Compare commits

..
Author SHA1 Message Date
Bart 671a00b1ac fix: Mask every credential the server echoes, logs or prints
An error reply echoes the request that caused it, and masking covers four
fields at the top level of an object only. A `secret` nested inside
`params`, where the JSON-RPC transport puts it, comes back in the clear,
as does every other credential field at any depth, and only two sites
mask at all. Collect the names in one list and mask recursively, so
nesting stops mattering and a new field is added once. The list covers
the six names only a reply carries, which is how `wallet_propose` and
`validation_create` wrote a live key to the log; `validation_key` is the
same seed as `validation_seed` in RFC1751 words.

A log is an echo that outlives the reply, so one `loggable()` helper
masks and truncates together and every site that writes a request or a
reply out uses it, the `[rpc_startup]` command and its result included,
and the command line client logs the reply it receives parsed and
masked where it wrote the raw body, a `validation_create` answer among
them, and caps a body it cannot parse at the same length. An
`[rpc_startup]` line that does not parse was echoed raw at fatal, the
one case masking cannot reach, and then run as whatever the parser had
left; it is now reported by position and parser message only, and
skipped. The `HTTP Reply` trace line in libxrpl, which cannot reach the
masker, now carries the status only; the body is logged beside it at
debug, masked when it carries a credential and otherwise as the string
already built for the wire, so a reply with no credential is serialized
once. No site logs an inbound request body uncapped, so the method name,
bounded by the request size limit, is the one thing a client chooses the
length of in the log. The request-duration line used to climb to warn
and error for a slow request with the request in it; the duration alone
still climbs, and the request stays at debug, so the duration line never
lifts text an anonymous client wrote to the default severity.

Three changes are visible to a caller. A credential in an echoed request
reads `<masked>` wherever it appears, nested inside `params` or a batch
entry too. The command line client masks `request_sent`, which carries
the `admin_password` it copies out of the config, so a failing
`./xrpld account_info rBogus` no longer prints a credential the operator
never typed. And a WebSocket frame that does not parse is answered with
its `size` rather than its body.
2026-10-14 10:14:02 +09:00
Bart 9096ec03a7 refactor: Declare the JSON-RPC and ripplerpc version constants
`ripplerpc`, which selects the reply envelope and accepts three values,
and `jsonrpc`, which names the JSON-RPC protocol version, are spelled as
literals at every call site, so neither field has one place stating what
it accepts. Declare `kRippleRpcVersion1/2/3` beside the `api_version`
constants in ApiVersion.h and `kJsonRpcVersion` in a new
protocol/JsonRpc.h, and use them at every production site that reads
a value: the one in RPCCall.cpp that reads the pair, and the three in
ServerHandler.cpp that default, compare and gate on `ripplerpc`. Every
test site spelling a value as a C++ expression follows. A literal inside
a JSON string fixture is left alone, since substituting there means
assembling the JSON by concatenation. The three `ripplerpc` constants
are declared as one set, so the header states every value the field
accepts, and each has a production user in ServerHandler.cpp.

The two fields keep separate constants and separate headers although
both spell "2.0" today. The specification fixes `jsonrpc` at that value
while `ripplerpc` accepts three, and the `ripplerpc` constants go when
support for API versions 1 and 2 goes, where JSON-RPC is a protocol this
server keeps speaking.

ApiVersion.h's header comment named five constants by unprefixed
spellings that no longer exist, and read as a complete map of the file's
version constants, which it stops being here. Two jtx helpers,
`hasEnvelope2` and `setEnvelope2` in TestHelpers.h, replace the
assertion pair and the request pair that every rewritten test site
repeated. No value changes, on the wire or in a test.
2026-10-14 10:14:02 +09:00
Bart 5fec493960 refactor: Let json::Value be compared and constructed from a string view
`json::Value` accepts `char const*`, `std::string` and
`json::StaticString`, so a caller holding a `std::string_view` has to
materialize a `std::string` whose characters are then copied a second
time into the value's own storage. Add the missing constructor, which
the `std::string` one delegates to, and an `operator==` that reads the
value's characters in place.

The comparison is constrained to `std::string_view` exactly rather than
taking a view by plain overload. A string literal converts equally well
to a view and to a Value, so a plain overload makes every
`value == "literal"` ambiguous, and a literal `0`, which converts to a
view through `char const*` as well as to a Value, with it.

No reply changes. The two spellings differ only for a view holding an
embedded NUL, which the Value comparison stops at. The `method: "batch"`
check in `ServerHandler.cpp` is the operator's first production user, so
that comparison stops building a `Value` from the literal on every
request.
2026-10-13 18:45:16 +09:00
Bart a6a4fff2aa refactor: Remove a publish loop nothing can enter
`pubProposedAccountTransaction` declares an `accountHistoryNotify` vector,
never inserts into it, and then tests it and iterates it. The vector is a
local, so the proof is the function itself: between the declaration and the
loop there are exactly two mentions of it, the condition and the loop, and
neither adds an element. Its sibling `pubAccountTransaction` fills its own
copy, which is what makes the empty one here read as live code.

The compiler corroborates it: with the loop gone the message becomes
`MultiApiJson const`, which is possible only because that loop was its sole
mutator. Nothing is lost with the assertion above the loop either. It held
that a `transJson` result carries no member named `account_history_tx_stream`.
No code writes one: outside the two assertions, the token appears in the
`subscribe` and `unsubscribe` request handlers only. The identical assertion
stays where the loop it guards is live.

No subscriber sees a difference. An account-history subscription is
registered in `subAccountHistory_` alone, so it was never in the map this
function reads, and it receives its transactions from
`pubAccountTransaction`. The same function's guard on three subscription maps
also goes: an earlier return leaves `subRTAccount_` non-empty, so the
condition cannot be false.
2026-10-13 18:45:15 +09:00
BartandBart c2478f509c refactor: Open the acquisition seams its tests need (#8081)
Co-authored-by: Bart <[email protected]>
2026-10-13 03:51:12 +00:00
Mayukha Vadari c908ed7839 fix: Reject malformed conditions in EscrowFinish preflight (#8523) 2026-10-12 20:48:55 +00:00
BartandBart fc57311c81 refactor: Expose a SHAMapAddNode verdict as counts (#8080)
Co-authored-by: Bart <[email protected]>
2026-10-12 20:02:36 +00:00
Mayukha Vadari 818de49264 refactor: Use DepositPreauthEntry everywhere (#8364) 2026-10-12 18:56:14 +00:00
dependabot[bot] 1318b1e58b chore: [DEPENDABOT] bump cxx from 1.0.202 to 1.0.203 in /crates in the rust-dependencies group (#8564)
Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-12 17:23:41 +00:00
Ayaz Salikhov 617c816ec8 chore: Fix readability-trailing-comma (#8545) 2026-10-12 13:57:24 +00:00
dependabot[bot] 34fc86f585 ci: [DEPENDABOT] bump the github-actions group across 1 directory with 2 updates (#8562)
Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-12 12:59:39 +00:00
Ayaz Salikhov e071f0a28d chore: Fix misc-const-correctness (#8546) 2026-10-12 11:44:06 +00:00
Ayaz Salikhov 8faa624ade chore: Update XRPLF/actions to use pip from python3.14 explicitly (#8560) 2026-10-12 10:06:06 +00:00
Ayaz Salikhov 6d6ab2d067 Merge remote-tracking branch 'upstream/release/3.4.x' into develop 2026-10-10 00:20:39 +01:00
Ayaz Salikhov 00e6407514 chore: Bump version to 3.4.1 and make pkg_release 2 2026-10-09 23:50:58 +01:00
Ayaz Salikhov 00c06edffb Merge remote-tracking branch 'upstream/release/3.4.x' into develop 2026-10-09 22:45:18 +01:00
Ayaz Salikhov de5053ae0d build: Reduce number of conan logs (#8548) 2026-10-09 16:33:41 +00:00
Ayaz Salikhov 1940ec5c2a chore: Fix readability-redundant-lambda-parameter-list (#8544) 2026-10-09 16:20:45 +00:00
Denis Angell 19c94c73f4 fix: Reject Batch inner txs with the wrong wrapper (fixBatchV1_2) 2026-10-09 16:04:36 +01:00
Bart cd005ff60d ci: Update Nexus packaging URL 2026-10-09 16:04:36 +01:00
Gregory Tsipenyuk 578224f2e6 fix: Assorted integer-arithmetic hardening in the payment engine and ledger helpers 2026-10-09 16:04:35 +01:00
Shawn Xie 3857ce21cd fix: Change mpt subscription msg type back to transaction (#8539) 2026-10-09 13:33:13 +00:00
Ayaz Salikhov aa490df46b chore: Update clang-tidy image to v23 (#8536) 2026-10-09 10:19:07 +00:00
88c1f1e7ac feat: Integrate Permissioned Domain & Credential Checks for Lending Protocol (#6517)
Signed-off-by: JCW <[email protected]>
Co-authored-by: Vito <[email protected]>
Co-authored-by: Ed Hennis <[email protected]>
2026-10-09 10:18:31 +00:00
Ayaz SalikhovandCopilot Autofix powered by AI ede8af8191 refactor: Group binaries in subdirectories (#8535)
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
2026-10-08 12:34:06 +00:00
Alex Kremer 3c24b605a1 chore: Split multiple-in-one into individual tests (#8025) 2026-10-08 09:57:38 +00:00
Alex Kremer d343b542f1 refactor: Migrate handlers to rpc-spec (B) (#8484) 2026-10-07 13:46:37 +00:00
Ayaz Salikhov 7acd719bf7 build: Use images with Clang 23 except for clang-tidy (#8530) 2026-10-07 13:08:20 +00:00
Ayaz Salikhov b4564d5301 chore: Update pre-commit hooks and image (#8528) 2026-10-07 10:59:37 +00:00
Shawn Xie 60195e6d37 fix: Fix MPT partial payment overflow (#8302) 2026-10-06 23:16:13 +00:00
Ayaz Salikhov 3d526d456e build: Use LLVM 23 (#8522) 2026-10-06 21:19:57 +00:00
Denis AngellandMayukha Vadari f05c9f7913 refactor: Extract escrow lock helpers and paychan test helpers (#7882)
Co-authored-by: Mayukha Vadari <[email protected]>
2026-10-06 19:58:52 +00:00
Harshit GuptaandMayukha Vadari c2a4bc3aa1 fix: Validate vetoed parameter type in feature RPC (#7583)
Co-authored-by: Mayukha Vadari <[email protected]>
2026-10-06 19:44:56 +00:00
Mayukha Vadari 718185e3b2 refactor: Use CheckEntry everywhere (#8349) 2026-10-06 19:26:35 +00:00
Ayaz Salikhov 1d7783bb86 build: Make conan retry with Conan Center's source backups (#8524) 2026-10-06 19:23:38 +00:00
Mayukha Vadari 9fd2c552f5 refactor: Use AmendmentsEntry everywhere (#8368) 2026-10-06 17:59:44 +00:00
Ayaz Salikhov 70b8fd301b chore: Update docker images; link Conan-built tools with a static runtime (#8520) 2026-10-06 16:47:35 +00:00
Mayukha Vadari e6564f553d refactor: Use NegativeUNLEntry everywhere (#8365) 2026-10-06 14:23:24 +00:00
Ayaz Salikhov ed96e60ce3 build: Make clang-tools custom in Nix, to match what's being built (#8521) 2026-10-06 13:59:12 +00:00
Alex Kremer 2ebd745a1b refactor: Migrate handlers to rpc-spec (A) (#8345) 2026-10-06 13:19:20 +00:00
Mayukha Vadari cfcbe45b60 test: Declare, not define, entry instantiations in SLEBase test (#8357) 2026-10-06 12:12:22 +00:00
yinyiqian1andBart 9cbf78ba99 test: Add more tests for granular permissions (#8459)
Co-authored-by: Bart <[email protected]>
2026-10-05 23:18:58 +00:00
Timur Yalymov b8d8738f81 fix: Enforce that MPT issuance flags are never cleared (#8152) 2026-10-05 23:17:36 +00:00
63c97e719f feat: Allow lending transactions in Batch (#8244)
Co-authored-by: Cursor <[email protected]>
Co-authored-by: Vito Tumas <[email protected]>
2026-10-05 23:17:26 +00:00
3ac26f23c7 feat: Add full support for all objects in ledger_entry (#6319)
Co-authored-by: Timur Yalymov <[email protected]>
Co-authored-by: Cursor <[email protected]>
Co-authored-by: Vito Tumas <[email protected]>
Co-authored-by: Ayaz Salikhov <[email protected]>
2026-10-05 23:17:14 +00:00
BartandBart ff9410bc56 build: Define XRPL_ASAN, XRPL_TSAN, and XRPL_UBSAN compile definitions (#8483)
Co-authored-by: Bart <[email protected]>
2026-10-05 23:15:08 +00:00
Mayukha Vadari 1798262d7a refactor: Use LedgerHashesEntry everywhere (#8369) 2026-10-05 18:15:02 +00:00
Mayukha Vadari cd633b9ac9 refactor: Use EscrowEntry everywhere (#8354) 2026-10-05 17:51:18 +00:00
Ayaz Salikhov 5c5f7d315a chore: Update nix flake file (#8479) 2026-10-05 16:58:41 +00:00
Mayukha Vadari 0f7493ce50 refactor: Use FeeSettingsEntry everywhere (#8370) 2026-10-05 16:56:41 +00:00
Harshit Gupta 40f61f828a fix: Add string type validation for channel_id and signature (#7582) 2026-10-05 16:55:14 +00:00
Mayukha Vadari 108277f4b7 test: Migrate three beast suites from beast::unit_test to gtest (#7993) 2026-10-05 15:28:05 +00:00
799 changed files with 32028 additions and 22640 deletions

No files matched your search

+11
View File
@@ -5,7 +5,10 @@ Checks: "-*,
-bugprone-exception-escape, -bugprone-exception-escape,
-bugprone-implicit-widening-of-multiplication-result, -bugprone-implicit-widening-of-multiplication-result,
-bugprone-narrowing-conversions, -bugprone-narrowing-conversions,
-bugprone-signed-bitwise,
-bugprone-std-exception-baseclass,
-bugprone-throwing-static-initialization, -bugprone-throwing-static-initialization,
-bugprone-unhandled-code-paths,
cppcoreguidelines-*, cppcoreguidelines-*,
-cppcoreguidelines-avoid-c-arrays, -cppcoreguidelines-avoid-c-arrays,
@@ -14,6 +17,7 @@ Checks: "-*,
-cppcoreguidelines-avoid-magic-numbers, -cppcoreguidelines-avoid-magic-numbers,
-cppcoreguidelines-avoid-non-const-global-variables, -cppcoreguidelines-avoid-non-const-global-variables,
-cppcoreguidelines-c-copy-assignment-signature, -cppcoreguidelines-c-copy-assignment-signature,
-cppcoreguidelines-explicit-constructor,
-cppcoreguidelines-interfaces-global-init, -cppcoreguidelines-interfaces-global-init,
-cppcoreguidelines-macro-usage, -cppcoreguidelines-macro-usage,
-cppcoreguidelines-missing-std-forward, -cppcoreguidelines-missing-std-forward,
@@ -32,6 +36,7 @@ Checks: "-*,
llvm-namespace-comment, llvm-namespace-comment,
misc-*, misc-*,
-misc-explicit-constructor,
-misc-multiple-inheritance, -misc-multiple-inheritance,
-misc-no-recursion, -misc-no-recursion,
-misc-non-private-member-variables-in-classes, -misc-non-private-member-variables-in-classes,
@@ -45,6 +50,8 @@ Checks: "-*,
-modernize-avoid-c-style-cast, -modernize-avoid-c-style-cast,
-modernize-return-braced-init-list, -modernize-return-braced-init-list,
-modernize-use-integer-sign-comparison, -modernize-use-integer-sign-comparison,
-modernize-use-string-view,
-modernize-use-structured-binding,
-modernize-use-trailing-return-type, -modernize-use-trailing-return-type,
performance-*, performance-*,
@@ -53,6 +60,7 @@ Checks: "-*,
-performance-noexcept-move-constructor, -performance-noexcept-move-constructor,
-performance-unnecessary-copy-initialization, -performance-unnecessary-copy-initialization,
-performance-unnecessary-value-param, -performance-unnecessary-value-param,
-performance-use-std-move,
readability-*, readability-*,
-readability-avoid-const-params-in-decls, -readability-avoid-const-params-in-decls,
@@ -65,7 +73,10 @@ Checks: "-*,
-readability-named-parameter, -readability-named-parameter,
-readability-qualified-auto, -readability-qualified-auto,
-readability-redundant-access-specifiers, -readability-redundant-access-specifiers,
-readability-redundant-nested-if,
-readability-redundant-qualified-alias,
-readability-static-accessed-through-instance, -readability-static-accessed-through-instance,
-readability-trivial-switch,
-readability-uppercase-literal-suffix -readability-uppercase-literal-suffix
" "
# --- # ---
+72
View File
@@ -108,3 +108,75 @@ endfunction()
function(patch_nix_binary target) function(patch_nix_binary target)
endfunction() endfunction()
function(rpcspec_generate_instantiations)
set(options)
set(oneValueArgs OUT_VAR VALUE_TYPE VIEW_HEADER INCLUDE_DIR)
set(multiValueArgs HANDLERS)
cmake_parse_arguments(
THIS_FUNCTION_PREFIX
"${options}"
"${oneValueArgs}"
"${multiValueArgs}"
${ARGN}
)
endfunction()
function(corrosion_import_crate)
set(options
ALL_FEATURES
NO_DEFAULT_FEATURES
NO_STD
NO_LINKER_OVERRIDE
NO_USES_TERMINAL
LOCKED
FROZEN
)
set(oneValueArgs MANIFEST_PATH PROFILE IMPORTED_CRATES)
set(multiValueArgs
CRATE_TYPES
CRATES
FEATURES
FLAGS
OVERRIDE_CRATE_TYPE
)
cmake_parse_arguments(
THIS_FUNCTION_PREFIX
"${options}"
"${oneValueArgs}"
"${multiValueArgs}"
${ARGN}
)
endfunction()
function(corrosion_set_env_vars target_name env_var)
endfunction()
function(corrosion_add_cxxbridge cxx_target)
set(options)
set(oneValueArgs CRATE)
set(multiValueArgs FILES)
cmake_parse_arguments(
THIS_FUNCTION_PREFIX
"${options}"
"${oneValueArgs}"
"${multiValueArgs}"
${ARGN}
)
endfunction()
function(_unlink_libgcc_s crate)
endfunction()
function(add_xrpl_crate name)
set(options)
set(oneValueArgs CRATE)
set(multiValueArgs FILES)
cmake_parse_arguments(
THIS_FUNCTION_PREFIX
"${options}"
"${oneValueArgs}"
"${multiValueArgs}"
${ARGN}
)
endfunction()
+22 -5
View File
@@ -15,9 +15,9 @@ inputs:
required: false required: false
default: "false" default: "false"
log_verbosity: log_verbosity:
description: "The logging verbosity." description: 'The logging verbosity ("quiet", "verbose"), or empty to use the Conan defaults.'
required: false required: false
default: "verbose" default: ""
sanitizers: sanitizers:
description: "The sanitizers to enable." description: "The sanitizers to enable."
required: false required: false
@@ -35,6 +35,16 @@ runs:
LOG_VERBOSITY: ${{ inputs.log_verbosity }} LOG_VERBOSITY: ${{ inputs.log_verbosity }}
SANITIZERS: ${{ inputs.sanitizers }} SANITIZERS: ${{ inputs.sanitizers }}
run: | run: |
# By default, leave the verbosity unset, so CMake configure output is
# shown, but compile commands and Boost's b2 debug output (~85k lines
# when "verbose") are not.
VERBOSITY_ARGS=()
if [[ -n "${LOG_VERBOSITY}" ]]; then
VERBOSITY_ARGS=(
--conf:all tools.build:verbosity="${LOG_VERBOSITY}"
--conf:all tools.compilation:verbosity="${LOG_VERBOSITY}"
)
fi
conan install \ conan install \
--profile:all ci \ --profile:all ci \
--build="${BUILD_OPTION}" \ --build="${BUILD_OPTION}" \
@@ -42,6 +52,13 @@ runs:
--options:host='&:xrpld=True' \ --options:host='&:xrpld=True' \
--settings:all build_type="${BUILD_TYPE}" \ --settings:all build_type="${BUILD_TYPE}" \
--conf:all tools.build:jobs=${BUILD_NPROC} \ --conf:all tools.build:jobs=${BUILD_NPROC} \
--conf:all tools.build:verbosity="${LOG_VERBOSITY}" \ "${VERBOSITY_ARGS[@]}" \
--conf:all tools.compilation:verbosity="${LOG_VERBOSITY}" \ --format=json \
. . >"${RUNNER_TEMP}/conan-graph.json"
# Tools that run during the build may only load glibc from the Nix store,
# as their package ID survives a GCC runtime update.
- name: Check build-context packages for Nix store dependencies (Linux)
if: ${{ runner.os == 'Linux' }}
shell: bash
run: ./bin/nix/check-build-context-runtime.sh "${RUNNER_TEMP}/conan-graph.json"
@@ -174,6 +174,7 @@ test.server > xrpl.basics
test.server > xrpl.config test.server > xrpl.config
test.server > xrpld.app test.server > xrpld.app
test.server > xrpld.core test.server > xrpld.core
test.server > xrpld.rpc
test.server > xrpl.json test.server > xrpl.json
test.server > xrpl.protocol test.server > xrpl.protocol
test.server > xrpl.server test.server > xrpl.server
+4 -4
View File
@@ -1,5 +1,5 @@
{ {
"image_tag": "sha-060957e", "image_tag": "sha-3d526d4",
"configs": { "configs": {
"ubuntu": [ "ubuntu": [
{ {
@@ -74,7 +74,7 @@
"extra_cmake_args": "-Dvalidator_keys=ON", "extra_cmake_args": "-Dvalidator_keys=ON",
"package": { "package": {
"type": "deb", "type": "deb",
"image": "ghcr.io/xrplf/xrpld/packaging-debian:sha-3a2d19f" "image": "ghcr.io/xrplf/xrpld/packaging-debian:sha-e6055dd"
} }
}, },
{ {
@@ -86,7 +86,7 @@
"extra_cmake_args": "-Dvalidator_keys=ON -Dassert=ON", "extra_cmake_args": "-Dvalidator_keys=ON -Dassert=ON",
"package": { "package": {
"type": "deb", "type": "deb",
"image": "ghcr.io/xrplf/xrpld/packaging-debian:sha-3a2d19f", "image": "ghcr.io/xrplf/xrpld/packaging-debian:sha-e6055dd",
"variant": "assert" "variant": "assert"
} }
} }
@@ -101,7 +101,7 @@
"extra_cmake_args": "-Dvalidator_keys=ON", "extra_cmake_args": "-Dvalidator_keys=ON",
"package": { "package": {
"type": "rpm", "type": "rpm",
"image": "ghcr.io/xrplf/xrpld/packaging-rhel:sha-3a2d19f" "image": "ghcr.io/xrplf/xrpld/packaging-rhel:sha-e6055dd"
} }
} }
] ]
+3 -4
View File
@@ -12,8 +12,7 @@ on:
- "!nix/docker/README.md" - "!nix/docker/README.md"
- "!nix/devshell.nix" - "!nix/devshell.nix"
- "!nix/check-tools/**" - "!nix/check-tools/**"
- "bin/default-loader-path.sh" - "bin/nix/default-loader-path.sh"
- "bin/install-sanitizer-libs.sh"
pull_request: pull_request:
paths: paths:
- ".github/workflows/build-nix-images.yml" - ".github/workflows/build-nix-images.yml"
@@ -25,8 +24,8 @@ on:
- "!nix/devshell.nix" - "!nix/devshell.nix"
- "!nix/check-tools/**" - "!nix/check-tools/**"
- "bin/check-tools.sh" - "bin/check-tools.sh"
- "bin/default-loader-path.sh" - "bin/nix/default-loader-path.sh"
- "bin/install-sanitizer-libs.sh" - "bin/install/sanitizer-libs.sh"
workflow_dispatch: workflow_dispatch:
concurrency: concurrency:
+2 -3
View File
@@ -5,13 +5,12 @@ on:
branches: branches:
- develop - develop
paths: paths:
- ".github/workflows/build-packaging-images.yml" - "bin/install/packaging-tools.sh"
- "bin/install-packaging-tools.sh"
- "package/images/packaging/**" - "package/images/packaging/**"
pull_request: pull_request:
paths: paths:
- ".github/workflows/build-packaging-images.yml" - ".github/workflows/build-packaging-images.yml"
- "bin/install-packaging-tools.sh" - "bin/install/packaging-tools.sh"
- "package/images/packaging/**" - "package/images/packaging/**"
workflow_dispatch: workflow_dispatch:
@@ -5,7 +5,6 @@ on:
branches: branches:
- develop - develop
paths: paths:
- ".github/workflows/build-pre-commit-image.yml"
- "bin/pre-commit/Dockerfile" - "bin/pre-commit/Dockerfile"
- "rust-toolchain.toml" - "rust-toolchain.toml"
pull_request: pull_request:
+2 -2
View File
@@ -34,7 +34,7 @@ permissions:
jobs: jobs:
audit: audit:
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-060957e container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-3d526d4
permissions: permissions:
contents: read contents: read
# Needed to open an issue on scheduled failures. # Needed to open an issue on scheduled failures.
@@ -66,7 +66,7 @@ jobs:
- name: Create issue - name: Create issue
if: ${{ steps.audit.outcome != 'success' && github.event_name == 'schedule' }} if: ${{ steps.audit.outcome != 'success' && github.event_name == 'schedule' }}
uses: XRPLF/actions/create-issue@2b8bc36af85b88bca0dd7bfac2e2dc05f94ad712 uses: XRPLF/actions/create-issue@b489c21d53928f7dab4874912fec40e4f6c9e85e
with: with:
title: "cargo audit found vulnerabilities" title: "cargo audit found vulnerabilities"
body_file: /tmp/cargo-audit-issue.md body_file: /tmp/cargo-audit-issue.md
+1 -1
View File
@@ -53,7 +53,7 @@ jobs:
- name: Create issue - name: Create issue
if: ${{ failure() && github.event_name == 'schedule' && github.repository == 'XRPLF/rippled' }} if: ${{ failure() && github.event_name == 'schedule' && github.repository == 'XRPLF/rippled' }}
uses: XRPLF/actions/create-issue@2b8bc36af85b88bca0dd7bfac2e2dc05f94ad712 uses: XRPLF/actions/create-issue@b489c21d53928f7dab4874912fec40e4f6c9e85e
with: with:
title: "Releases not merged back into develop" title: "Releases not merged back into develop"
body_file: ${{ env.ISSUE_FILE }} body_file: ${{ env.ISSUE_FILE }}
+2 -2
View File
@@ -79,7 +79,7 @@ jobs:
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Prepare runner - name: Prepare runner
uses: XRPLF/actions/prepare-runner@b3e255d74d785d053e4903da8ac90983cd7d9e82 uses: XRPLF/actions/prepare-runner@8e98d61f011fd2a67f3fde5f0f075662c099a527
with: with:
enable_ccache: false enable_ccache: false
@@ -108,7 +108,7 @@ jobs:
- name: Upload regenerated snapshot - name: Upload regenerated snapshot
if: failure() if: failure()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with: with:
name: check-tools-${{ runner.os }}-${{ runner.arch }} name: check-tools-${{ runner.os }}-${{ runner.arch }}
path: ${{ matrix.snapshot }} path: ${{ matrix.snapshot }}
+1 -2
View File
@@ -93,9 +93,8 @@ jobs:
.github/workflows/reusable-upload-recipe.yml .github/workflows/reusable-upload-recipe.yml
.clang-tidy .clang-tidy
.codecov.yml .codecov.yml
bin/check-nix-store-refs.sh
bin/check-tools.sh bin/check-tools.sh
bin/default-loader-path.sh bin/nix/**
cfg/** cfg/**
cmake/** cmake/**
conan/** conan/**
+1 -2
View File
@@ -31,9 +31,8 @@ on:
- ".github/workflows/reusable-upload-recipe.yml" - ".github/workflows/reusable-upload-recipe.yml"
- ".clang-tidy" - ".clang-tidy"
- ".codecov.yml" - ".codecov.yml"
- "bin/check-nix-store-refs.sh"
- "bin/check-tools.sh" - "bin/check-tools.sh"
- "bin/default-loader-path.sh" - "bin/nix/**"
- "cfg/**" - "cfg/**"
- "cmake/**" - "cmake/**"
- "conan/**" - "conan/**"
+2 -2
View File
@@ -14,7 +14,7 @@ on:
jobs: jobs:
# Call the workflow in the XRPLF/actions repo that runs the pre-commit hooks. # Call the workflow in the XRPLF/actions repo that runs the pre-commit hooks.
run-hooks: run-hooks:
uses: XRPLF/actions/.github/workflows/pre-commit.yml@279ec358f4a1be4088be3e024b07916fa97c75b6 uses: XRPLF/actions/.github/workflows/pre-commit.yml@d7f2acb47d9662e1e2f8b1f5feffa6d21cc3290a
with: with:
runs_on: ubuntu-latest runs_on: ubuntu-latest
container: '{ "image": "ghcr.io/xrplf/xrpld/pre-commit:sha-473fe44" }' container: '{ "image": "ghcr.io/xrplf/xrpld/pre-commit:sha-70b8fd3" }'
+2 -2
View File
@@ -41,13 +41,13 @@ env:
jobs: jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-060957e container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-3d526d4
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Prepare runner - name: Prepare runner
uses: XRPLF/actions/prepare-runner@b3e255d74d785d053e4903da8ac90983cd7d9e82 uses: XRPLF/actions/prepare-runner@8e98d61f011fd2a67f3fde5f0f075662c099a527
with: with:
enable_ccache: false enable_ccache: false
@@ -129,7 +129,7 @@ jobs:
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Prepare runner - name: Prepare runner
uses: XRPLF/actions/prepare-runner@b3e255d74d785d053e4903da8ac90983cd7d9e82 uses: XRPLF/actions/prepare-runner@8e98d61f011fd2a67f3fde5f0f075662c099a527
with: with:
enable_ccache: ${{ inputs.ccache_enabled }} enable_ccache: ${{ inputs.ccache_enabled }}
@@ -186,9 +186,6 @@ jobs:
with: with:
build_nproc: ${{ steps.nproc.outputs.nproc }} build_nproc: ${{ steps.nproc.outputs.nproc }}
build_type: ${{ inputs.build_type }} build_type: ${{ inputs.build_type }}
# Set the verbosity to "quiet" for Windows to avoid an excessive
# amount of logs. For other OSes, the "verbose" logs are more useful.
log_verbosity: ${{ runner.os == 'Windows' && 'quiet' || 'verbose' }}
sanitizers: ${{ inputs.sanitizers }} sanitizers: ${{ inputs.sanitizers }}
- name: Configure CMake - name: Configure CMake
@@ -257,20 +254,20 @@ jobs:
# cache included, since what it holds is what gets uploaded and reused. # cache included, since what it holds is what gets uploaded and reused.
- name: Check the build output for Nix store references (Nix toolchain) - name: Check the build output for Nix store references (Nix toolchain)
if: ${{ inputs.toolchain == 'nix' }} if: ${{ inputs.toolchain == 'nix' }}
run: ./bin/check-nix-store-refs.sh "${BUILD_DIR}" run: ./bin/nix/check-nix-store-refs.sh "${BUILD_DIR}"
- name: Check the Conan cache for Nix store references (Nix toolchain) - name: Check the Conan cache for Nix store references (Nix toolchain)
if: ${{ inputs.toolchain == 'nix' }} if: ${{ inputs.toolchain == 'nix' }}
run: ./bin/check-nix-store-refs.sh "${CONAN_HOME}" run: ./bin/nix/check-nix-store-refs.sh "${CONAN_HOME}"
# Only what PatchNixBinary.cmake retargets: the toolchain in the Linux # Only what PatchNixBinary.cmake retargets: the toolchain in the Linux
# images always references the store. Same condition it uses. # images always references the store. Same condition it uses.
- name: Check for Nix store references (Linux) - name: Check for Nix store references (Linux)
if: ${{ runner.os == 'Linux' && env.SANITIZERS_ENABLED == 'false' }} if: ${{ runner.os == 'Linux' && env.SANITIZERS_ENABLED == 'false' }}
run: | run: |
./bin/check-nix-store-refs.sh "${BUILD_DIR}/xrpld" ./bin/nix/check-nix-store-refs.sh "${BUILD_DIR}/xrpld"
./bin/check-nix-store-refs.sh "${BUILD_DIR}/xrpl_tests" ./bin/nix/check-nix-store-refs.sh "${BUILD_DIR}/xrpl_tests"
./bin/check-nix-store-refs.sh "${BUILD_DIR}/xrpld_tests" ./bin/nix/check-nix-store-refs.sh "${BUILD_DIR}/xrpld_tests"
- name: Show ccache statistics - name: Show ccache statistics
if: ${{ inputs.ccache_enabled }} if: ${{ inputs.ccache_enabled }}
@@ -283,7 +280,7 @@ jobs:
- name: Upload the binary (Linux) - name: Upload the binary (Linux)
if: ${{ env.PACKAGING_ARTIFACTS_ENABLED == 'true' && runner.os == 'Linux' }} if: ${{ env.PACKAGING_ARTIFACTS_ENABLED == 'true' && runner.os == 'Linux' }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with: with:
name: xrpld-${{ inputs.config_name }} name: xrpld-${{ inputs.config_name }}
path: ${{ env.BUILD_DIR }}/xrpld path: ${{ env.BUILD_DIR }}/xrpld
@@ -297,7 +294,7 @@ jobs:
- name: Upload the validator-keys binary - name: Upload the validator-keys binary
if: ${{ env.PACKAGING_ARTIFACTS_ENABLED == 'true' && env.VALIDATOR_KEYS_ENABLED == 'true' }} if: ${{ env.PACKAGING_ARTIFACTS_ENABLED == 'true' && env.VALIDATOR_KEYS_ENABLED == 'true' }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with: with:
name: validator-keys-${{ inputs.config_name }} name: validator-keys-${{ inputs.config_name }}
path: | path: |
@@ -308,7 +305,7 @@ jobs:
- name: Upload the test binary (Linux) - name: Upload the test binary (Linux)
if: ${{ github.event.repository.visibility == 'public' && runner.os == 'Linux' }} if: ${{ github.event.repository.visibility == 'public' && runner.os == 'Linux' }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with: with:
name: xrpl_tests-${{ inputs.config_name }} name: xrpl_tests-${{ inputs.config_name }}
path: ${{ env.BUILD_DIR }}/xrpl_tests path: ${{ env.BUILD_DIR }}/xrpl_tests
@@ -324,7 +321,7 @@ jobs:
- name: Upload server definitions - name: Upload server definitions
if: ${{ github.event.repository.visibility == 'public' && inputs.config_name == 'ubuntu-gcc-debug-amd64-coverage' }} if: ${{ github.event.repository.visibility == 'public' && inputs.config_name == 'ubuntu-gcc-debug-amd64-coverage' }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with: with:
name: server-definitions name: server-definitions
path: ${{ env.BUILD_DIR }}/server_definitions.json path: ${{ env.BUILD_DIR }}/server_definitions.json
+5 -6
View File
@@ -34,7 +34,7 @@ jobs:
needs: [determine-files] needs: [determine-files]
if: ${{ needs.determine-files.outputs.cpp_changed_files != '' || needs.determine-files.outputs.need_full_run == 'true' }} if: ${{ needs.determine-files.outputs.cpp_changed_files != '' || needs.determine-files.outputs.need_full_run == 'true' }}
runs-on: ["self-hosted", "Linux", "X64", "heavy"] runs-on: ["self-hosted", "Linux", "X64", "heavy"]
container: "ghcr.io/xrplf/xrpld/nix-debian:sha-060957e" container: "ghcr.io/xrplf/xrpld/nix-debian:sha-3d526d4"
permissions: permissions:
contents: read contents: read
issues: write issues: write
@@ -43,7 +43,7 @@ jobs:
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Prepare runner - name: Prepare runner
uses: XRPLF/actions/prepare-runner@b3e255d74d785d053e4903da8ac90983cd7d9e82 uses: XRPLF/actions/prepare-runner@8e98d61f011fd2a67f3fde5f0f075662c099a527
with: with:
enable_ccache: false enable_ccache: false
@@ -73,7 +73,6 @@ jobs:
with: with:
build_nproc: ${{ steps.nproc.outputs.nproc }} build_nproc: ${{ steps.nproc.outputs.nproc }}
build_type: ${{ env.BUILD_TYPE }} build_type: ${{ env.BUILD_TYPE }}
log_verbosity: verbose
- name: Configure CMake - name: Configure CMake
working-directory: ${{ env.BUILD_DIR }} working-directory: ${{ env.BUILD_DIR }}
@@ -110,7 +109,7 @@ jobs:
- name: Upload clang-tidy output - name: Upload clang-tidy output
if: ${{ github.event.repository.visibility == 'public' && steps.run_clang_tidy.outcome != 'success' }} if: ${{ github.event.repository.visibility == 'public' && steps.run_clang_tidy.outcome != 'success' }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with: with:
path: ${{ env.OUTPUT_FILE }} path: ${{ env.OUTPUT_FILE }}
archive: false archive: false
@@ -134,7 +133,7 @@ jobs:
- name: Upload clang-tidy diff output - name: Upload clang-tidy diff output
if: ${{ github.event.repository.visibility == 'public' && steps.files_changed.outcome != 'success' }} if: ${{ github.event.repository.visibility == 'public' && steps.files_changed.outcome != 'success' }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with: with:
path: ${{ env.DIFF_FILE }} path: ${{ env.DIFF_FILE }}
archive: false archive: false
@@ -186,7 +185,7 @@ jobs:
- name: Create issue - name: Create issue
if: ${{ steps.run_clang_tidy.outcome != 'success' && inputs.create_issue_on_failure }} if: ${{ steps.run_clang_tidy.outcome != 'success' && inputs.create_issue_on_failure }}
uses: XRPLF/actions/create-issue@2b8bc36af85b88bca0dd7bfac2e2dc05f94ad712 uses: XRPLF/actions/create-issue@b489c21d53928f7dab4874912fec40e4f6c9e85e
with: with:
title: "Clang-tidy check failed" title: "Clang-tidy check failed"
body_file: ${{ env.ISSUE_FILE }} body_file: ${{ env.ISSUE_FILE }}
@@ -44,7 +44,7 @@ jobs:
# Every package lands in one directory; the step below picks its own, # Every package lands in one directory; the step below picks its own,
# which keeps this independent of the artifact names. # which keeps this independent of the artifact names.
- name: Download package artifacts - name: Download package artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with: with:
pattern: "*-pkg" pattern: "*-pkg"
merge-multiple: true merge-multiple: true
+9 -9
View File
@@ -100,18 +100,18 @@ jobs:
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Prepare runner - name: Prepare runner
uses: XRPLF/actions/prepare-runner@b3e255d74d785d053e4903da8ac90983cd7d9e82 uses: XRPLF/actions/prepare-runner@8e98d61f011fd2a67f3fde5f0f075662c099a527
with: with:
enable_ccache: false enable_ccache: false
- name: Download pre-built xrpld binary - name: Download pre-built xrpld binary
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with: with:
name: ${{ matrix.xrpld_artifact_name }} name: ${{ matrix.xrpld_artifact_name }}
path: ${{ env.BUILD_DIR }} path: ${{ env.BUILD_DIR }}
- name: Download pre-built validator-keys binary - name: Download pre-built validator-keys binary
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with: with:
name: ${{ matrix.validator_keys_artifact_name }} name: ${{ matrix.validator_keys_artifact_name }}
path: ${{ env.BUILD_DIR }} path: ${{ env.BUILD_DIR }}
@@ -151,7 +151,7 @@ jobs:
# version starts with a digit and a longer name does not, so that one digit # version starts with a digit and a longer name does not, so that one digit
# is what tells 'xrpld-3.4.1-...' from 'xrpld-assert-3.4.1-...'. # is what tells 'xrpld-3.4.1-...' from 'xrpld-assert-3.4.1-...'.
- name: Upload package artifact - name: Upload package artifact
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with: with:
name: ${{ matrix.xrpld_artifact_name }}-pkg name: ${{ matrix.xrpld_artifact_name }}-pkg
path: | path: |
@@ -160,7 +160,7 @@ jobs:
if-no-files-found: error if-no-files-found: error
- name: Upload debug symbol artifact - name: Upload debug symbol artifact
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with: with:
name: ${{ matrix.xrpld_artifact_name }}-pkg-debug name: ${{ matrix.xrpld_artifact_name }}-pkg-debug
path: | path: |
@@ -225,13 +225,13 @@ jobs:
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Prepare runner - name: Prepare runner
uses: XRPLF/actions/prepare-runner@b3e255d74d785d053e4903da8ac90983cd7d9e82 uses: XRPLF/actions/prepare-runner@8e98d61f011fd2a67f3fde5f0f075662c099a527
with: with:
enable_ccache: false enable_ccache: false
# Both artifacts, so the debug symbols are published alongside the package. # Both artifacts, so the debug symbols are published alongside the package.
- name: Download package artifacts - name: Download package artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with: with:
pattern: ${{ matrix.xrpld_artifact_name }}-pkg* pattern: ${{ matrix.xrpld_artifact_name }}-pkg*
merge-multiple: true merge-multiple: true
@@ -287,7 +287,7 @@ jobs:
run: echo "PUSH=${PUSH}" | tee -a "${GITHUB_ENV}" run: echo "PUSH=${PUSH}" | tee -a "${GITHUB_ENV}"
- name: Download package artifacts - name: Download package artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with: with:
pattern: "*-pkg" pattern: "*-pkg"
merge-multiple: true merge-multiple: true
@@ -295,7 +295,7 @@ jobs:
- name: Download voidstar binary - name: Download voidstar binary
if: ${{ matrix.target == 'voidstar' }} if: ${{ matrix.target == 'voidstar' }}
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with: with:
name: xrpld-ubuntu-clang-debug-amd64-voidstar name: xrpld-ubuntu-clang-debug-amd64-voidstar
path: ${{ env.CONTEXT }} path: ${{ env.CONTEXT }}
+3 -3
View File
@@ -28,7 +28,7 @@ permissions:
jobs: jobs:
clippy: clippy:
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-060957e container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-3d526d4
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
@@ -41,7 +41,7 @@ jobs:
coverage: coverage:
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-060957e container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-3d526d4
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
@@ -70,7 +70,7 @@ jobs:
doc: doc:
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-060957e container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-3d526d4
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
+2 -2
View File
@@ -40,7 +40,7 @@ defaults:
jobs: jobs:
upload: upload:
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-060957e container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-3d526d4
env: env:
REMOTE_NAME: ${{ inputs.remote_name }} REMOTE_NAME: ${{ inputs.remote_name }}
CONAN_LOGIN_USERNAME_XRPLF: ${{ secrets.remote_username }} CONAN_LOGIN_USERNAME_XRPLF: ${{ secrets.remote_username }}
@@ -50,7 +50,7 @@ jobs:
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Prepare runner - name: Prepare runner
uses: XRPLF/actions/prepare-runner@b3e255d74d785d053e4903da8ac90983cd7d9e82 uses: XRPLF/actions/prepare-runner@8e98d61f011fd2a67f3fde5f0f075662c099a527
with: with:
enable_ccache: false enable_ccache: false
+2 -5
View File
@@ -68,7 +68,7 @@ jobs:
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Prepare runner - name: Prepare runner
uses: XRPLF/actions/prepare-runner@b3e255d74d785d053e4903da8ac90983cd7d9e82 uses: XRPLF/actions/prepare-runner@8e98d61f011fd2a67f3fde5f0f075662c099a527
with: with:
enable_ccache: false enable_ccache: false
@@ -108,14 +108,11 @@ jobs:
build_nproc: ${{ steps.nproc.outputs.nproc }} build_nproc: ${{ steps.nproc.outputs.nproc }}
build_type: ${{ matrix.build_type }} build_type: ${{ matrix.build_type }}
force_build: ${{ github.event_name == 'schedule' || github.event.inputs.force_source_build == 'true' }} force_build: ${{ github.event_name == 'schedule' || github.event.inputs.force_source_build == 'true' }}
# Set the verbosity to "quiet" for Windows to avoid an excessive
# amount of logs. For other OSes, the "verbose" logs are more useful.
log_verbosity: ${{ runner.os == 'Windows' && 'quiet' || 'verbose' }}
sanitizers: ${{ matrix.sanitizers }} sanitizers: ${{ matrix.sanitizers }}
- name: Check the Conan cache for Nix store references (Nix toolchain) - name: Check the Conan cache for Nix store references (Nix toolchain)
if: ${{ matrix.toolchain == 'nix' }} if: ${{ matrix.toolchain == 'nix' }}
run: ./bin/check-nix-store-refs.sh "${CONAN_HOME}" run: ./bin/nix/check-nix-store-refs.sh "${CONAN_HOME}"
- name: Log into Conan remote - name: Log into Conan remote
if: ${{ github.repository == 'XRPLF/rippled' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') }} if: ${{ github.repository == 'XRPLF/rippled' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') }}
+6 -5
View File
@@ -60,7 +60,7 @@ repos:
types_or: [c++, c] types_or: [c++, c]
- repo: https://github.com/pre-commit/mirrors-clang-format - repo: https://github.com/pre-commit/mirrors-clang-format
rev: e2b496dc2bd8340c2524cb9a2d2a943cde1bb6df # frozen: v23.1.1 rev: a9a8a861f30ed207ead7d5a3b7e8032283ba5da7 # frozen: v23.1.2
hooks: hooks:
- id: clang-format - id: clang-format
args: [--style=file] args: [--style=file]
@@ -82,9 +82,10 @@ repos:
files: ^crates/.*\.rs$ files: ^crates/.*\.rs$
- repo: https://github.com/BlankSpruce/gersemi-pre-commit - repo: https://github.com/BlankSpruce/gersemi-pre-commit
rev: f1c4833f8cf23c6d952673abc73525411a5719e8 # frozen: 0.29.1 rev: 28010ddd6016e1a0f7bd232acb6536ef996ae897 # frozen: 0.29.2
hooks: hooks:
- id: gersemi - id: gersemi
args: [-i, --warnings-as-errors]
- repo: https://github.com/rbubley/mirrors-prettier - repo: https://github.com/rbubley/mirrors-prettier
rev: ef4a397f916211b4a39ccf9d3d9cbb6562157251 # frozen: v3.9.9 rev: ef4a397f916211b4a39ccf9d3d9cbb6562157251 # frozen: v3.9.9
@@ -95,19 +96,19 @@ repos:
# Scoped to package/: the rest of the repo's Python has pre-existing findings, # Scoped to package/: the rest of the repo's Python has pre-existing findings,
# so widening these is its own change. # so widening these is its own change.
- repo: https://github.com/astral-sh/ruff-pre-commit - repo: https://github.com/astral-sh/ruff-pre-commit
rev: a56c0b927e6465d37cae3e97d35d4d18ab2b96cd # frozen: v0.16.9 rev: f12be1ebaa5351c1fc76472de98db2c3446c8253 # frozen: v0.16.10
hooks: hooks:
- id: ruff-check - id: ruff-check
args: [--fix] args: [--fix]
files: ^package/.*\.py$ files: ^package/.*\.py$
- repo: https://github.com/psf/black-pre-commit-mirror - repo: https://github.com/psf/black-pre-commit-mirror
rev: 4160603246a6b365d4a2af661c6d71b0a0f50478 # frozen: 26.5.1 rev: 96ae3e5802f3fe2d551e703e18f0a367d1a81ac2 # frozen: 26.10.0
hooks: hooks:
- id: black - id: black
- repo: https://github.com/pre-commit/mirrors-mypy - repo: https://github.com/pre-commit/mirrors-mypy
rev: 7ff8d35ae36a7d2b968f2f90b4c723e292e594ee # frozen: v2.3.1 rev: 2834ec6639549dd6796205c8f011dedcd587288b # frozen: v2.4.0
hooks: hooks:
- id: mypy - id: mypy
args: [--strict] args: [--strict]
+20 -1
View File
@@ -22,13 +22,31 @@ API version 2 is available in `xrpld` version 2.0.0 and later. See [API-VERSION-
This version is supported by all `xrpld` versions. For WebSocket and HTTP JSON-RPC requests, it is currently the default API version used when no `api_version` is specified. This version is supported by all `xrpld` versions. For WebSocket and HTTP JSON-RPC requests, it is currently the default API version used when no `api_version` is specified.
## Unreleased
### Bugfixes
- A request echoed back in an error reply now has every credential-bearing field masked: `admin_password`, `admin_user`, `passphrase`, `password`, `secret`, `seed`, `seed_hex`, `url_password`, `url_username` and `username`. Nesting no longer matters, so a credential inside `params` is masked too. The same masking is applied to every request and reply written to the log, and it covers six further names that only a reply carries: `master_key`, `master_seed`, `master_seed_hex`, `validation_key`, `validation_private_key` and `validation_seed`, which is how `wallet_propose` and `validation_create` used to write a live private key to the log. A request or reply written to the log is truncated at 10,000 characters. An `[rpc_startup]` line that does not parse is reported by its position in the section and the parser's message, never by its text, and no command runs for it.
- The command line client no longer prints a credential the operator did not type. A failing command echoes the request it built under `request_sent`, which carries the `admin_password` the client copies out of `[port_rpc]` in the config, so `./xrpld account_info rBogus` printed that password to stdout and into any captured output. `request_sent` is now masked. The `rpc` member beside it, which echoes the arguments as they were typed, is unchanged. The command line client also no longer writes an unparsed `json` or `ripple_path_find` argument to its trace log before parsing it, where a `secret` inside that argument could not be masked; it logs the parsed request instead, masked. The reply it receives is logged the same way, parsed and masked, where the raw body was written before, a `validation_create` answer included.
- A WebSocket frame that does not parse, or exceeds the request size limit, is answered `{"type": "error", "error": "jsonInvalid", "size": <bytes>}`. The frame's body is reported by size rather than echoed back in a `value` member, since a body that does not parse has no fields to mask. A client that read `value` gets `size` instead.
## XRP Ledger server version 3.5.0 ## XRP Ledger server version 3.5.0
Version 3.5.0 is not yet released. Version 3.5.0 is not yet released.
### Additions in 3.5.0 ### Additions in 3.5.0
- `subscribe`, `unsubscribe`: Added an optional `mpt_issuances` request field, an array of MPT issuance IDs (hex strings). Subscribers receive a message with `type` `mptTransaction` for each validated transaction whose metadata affects a subscribed issuance; the message has the same fields as the `transactions` stream. MPT issuance subscriptions count toward the per-connection subscription limit. An empty array, a non-array value, or an invalid ID returns `invalidParams`. ([#5671](https://github.com/XRPLF/rippled/pull/5671)) - `subscribe`, `unsubscribe`: Added an optional `mpt_issuances` request field, an array of MPT issuance IDs (hex strings). Subscribers receive the same `transaction` message as the `transactions` stream for each validated transaction whose metadata affects a subscribed issuance. MPT issuance subscriptions count toward the per-connection subscription limit. An empty array, a non-array value, or an invalid ID returns `invalidParams`. ([#5671](https://github.com/XRPLF/rippled/pull/5671))
- `ledger_entry`: Add full support for checks, NFT offers, payment channels, and signer lists. ([#6319](https://github.com/XRPLF/rippled/pull/6319))
### Bugfixes in 3.5.0
- `channel_authorize`: The `channel_id` field now returns an `invalidParams` error if the value is not a string. [#7582](https://github.com/XRPLF/rippled/pull/7582)
- `channel_verify`: The `channel_id` and `signature` fields now return an `invalidParams` error if the value is not a string. [#7582](https://github.com/XRPLF/rippled/pull/7582)
### Bugfixes in 3.5.0
- `feature`: The admin-only `vetoed` field now returns `invalidParams` unless its value is a boolean. [#7583](https://github.com/XRPLF/rippled/pull/7583)
## XRP Ledger server version 3.4.0 ## XRP Ledger server version 3.4.0
@@ -50,6 +68,7 @@ Version 3.4.0 is not yet released. These changes are available in the 3.4.0 beta
- `account_lines`: The `peer` field now returns an error if the value is not a string. [#7728](https://github.com/XRPLF/rippled/pull/7728) - `account_lines`: The `peer` field now returns an error if the value is not a string. [#7728](https://github.com/XRPLF/rippled/pull/7728)
- `ledger`: `delivered_amount` is now included in the metadata of successful `AccountDelete` transactions when transactions are expanded (`expand`, or admin-only `full`). Previously it was only added for `Payment` and `CheckCash`, which made `ledger` inconsistent with `tx` and `account_tx`. [#5706](https://github.com/XRPLF/rippled/pull/5706) - `ledger`: `delivered_amount` is now included in the metadata of successful `AccountDelete` transactions when transactions are expanded (`expand`, or admin-only `full`). Previously it was only added for `Payment` and `CheckCash`, which made `ledger` inconsistent with `tx` and `account_tx`. [#5706](https://github.com/XRPLF/rippled/pull/5706)
- `noripple_check`: The `transactions` field is no longer included in error responses; it is still returned (possibly as an empty array) whenever `transactions` is `true` and the request succeeds. A malformed `account` is now rejected before the ledger is looked up, so that error response no longer carries the `ledger_hash`, `ledger_index`, and `validated` fields ([#6303](https://github.com/XRPLF/rippled/pull/6303)). - `noripple_check`: The `transactions` field is no longer included in error responses; it is still returned (possibly as an empty array) whenever `transactions` is `true` and the request succeeds. A malformed `account` is now rejected before the ledger is looked up, so that error response no longer carries the `ledger_hash`, `ledger_index`, and `validated` fields ([#6303](https://github.com/XRPLF/rippled/pull/6303)).
- `transaction_entry`: An object or an array in `tx_hash` now returns `malformedRequest`, like any other value that is not a hex hash, instead of an `internal` error.
## XRP Ledger server version 3.3.0 ## XRP Ledger server version 3.3.0
+17 -6
View File
@@ -20,9 +20,11 @@
# development setups, but not in the macOS CI environment. They are checked # development setups, but not in the macOS CI environment. They are checked
# everywhere except when running in CI on macOS. # everywhere except when running in CI on macOS.
# #
# Tools that Nix also exposes under a version-suffixed name (`clang-tidy-22`, # Tools that Nix also exposes under a version-suffixed name
# `g++-15`, ...) are probed under both names: a suffixed name can break while # (`clang-tidy-<v>`, `g++-<v>`, ...) are probed under both names:
# the plain one still works (see mkVersionedToolLinks in nix/packages.nix). # a suffixed name can break while the plain one still works
# (see mkVersionedToolLinks in nix/packages.nix).
# The suffix is the major version of the plain `clang` / `gcc` on PATH.
# #
# Tools scoped to a single dev shell rather than to commonPackages are checked # Tools scoped to a single dev shell rather than to commonPackages are checked
# only in that shell, keyed off XRPL_DEVSHELL. # only in that shell, keyed off XRPL_DEVSHELL.
@@ -34,9 +36,16 @@
set -uo pipefail set -uo pipefail
# Version suffixes of the Nix tool links, tracking nix/packages.nix. # major_version <compiler>
gcc_version=15 # Major version of a compiler on PATH, or "unknown" when it isn't there.
llvm_version=22 major_version() {
local version
version="$("$1" -dumpversion 2>/dev/null)" || version=""
version="${version%%.*}"
printf '%s' "${version:-unknown}"
}
llvm_version="$(major_version clang)"
missing=() missing=()
checked=0 checked=0
@@ -112,6 +121,7 @@ if [ "${os}" = "linux" ] || [ "${os}" = "macos" ]; then
check ClangBuildAnalyzer check ClangBuildAnalyzer
check curl check curl
check file check file
check jq
check less check less
check make check make
# net-tools netstat reports "net-tools X.Y"; macOS ships BSD netstat with no # net-tools netstat reports "net-tools X.Y"; macOS ships BSD netstat with no
@@ -180,6 +190,7 @@ fi
if [ "${os}" = "linux" ]; then if [ "${os}" = "linux" ]; then
echo echo
echo "GCC toolchain:" echo "GCC toolchain:"
gcc_version="$(major_version gcc)"
check gcc check gcc
check "gcc-${gcc_version}" check "gcc-${gcc_version}"
check g++ check g++
File renamed without changes.
File renamed without changes.
+65
View File
@@ -0,0 +1,65 @@
#!/usr/bin/env bash
# Fail if a binary of a build-context Conan package loads anything from the Nix
# store other than glibc, or cannot resolve a library at all.
#
# Only binaries linked by the Nix toolchain are checked, i.e. those recording a
# store path as their interpreter or RUNPATH. Prebuilt upstream binaries (such
# as the ones the cmake package ships) use the system loader instead.
#
# Build-context packages provide the tools that run during the build (protoc,
# grpc_cpp_plugin, ...). Their package ID does not change when a Nix toolchain
# update moves the GCC runtime to a new store path, so a cached binary has to
# get by with the pinned glibc alone. See docs/build/nix.md.
#
# Usage: bin/nix/check-build-context-runtime.sh <graph.json>
# <graph.json> is the output of `conan install --format=json`.
set -euo pipefail
if [ "$#" -ne 1 ]; then
echo "usage: $0 <graph.json>" >&2
exit 2
fi
if [ "$(uname -s)" != "Linux" ]; then
echo "$0: Linux only" >&2
exit 2
fi
folders="$(jq -r '.graph.nodes[] | select(.context == "build" and .package_folder) | .package_folder' "$1" | sort -u)"
checked=0
failed=0
while IFS= read -r file; do
case "$(file -b "${file}")" in
ELF*) ;;
*) continue ;;
esac
[[ "$(readelf -ldW "${file}")" == */nix/store/* ]] || continue
checked=$((checked + 1))
# `ldd` lists the interpreter and every library as the loader resolves them.
if deps="$(ldd "${file}" 2>&1)"; then
bad="$(printf '%s\n' "${deps}" |
grep -E 'not found|/nix/store/' |
grep -vE '/nix/store/[^/]+-glibc-[^/]+/' || true)"
else
case "${deps}" in
*"not a dynamic executable"*) continue ;;
esac
bad="${deps}"
fi
if [ -n "${bad}" ]; then
failed=$((failed + 1))
echo "::error file=${file}::loads a library from the Nix store other than glibc"
echo "${file}"
echo "${bad}" | sed 's/^/ /'
fi
done < <(
# shellcheck disable=SC2086 # one folder per line, no spaces in Conan paths
[ -z "${folders}" ] || find ${folders} -type f \( -perm -u+x -o -name '*.so*' \)
)
echo "Build-context packages: checked ${checked} binaries, ${failed} failed."
[ "${failed}" -eq 0 ]
@@ -10,7 +10,7 @@
# alone; the scripts in a Conan cache are all git hook samples and autotools # alone; the scripts in a Conan cache are all git hook samples and autotools
# scratch, 36 false positives to 0 real. # scratch, 36 false positives to 0 real.
# #
# Usage: bin/check-nix-store-refs.sh <path> # Usage: bin/nix/check-nix-store-refs.sh <path>
set -euo pipefail set -euo pipefail
File renamed without changes.
+1 -1
View File
@@ -23,7 +23,7 @@ apt-get clean
rm -rf /var/lib/apt/lists/* rm -rf /var/lib/apt/lists/*
EOF EOF
ARG PRE_COMMIT_VERSION=4.6.0 ARG PRE_COMMIT_VERSION=4.6.2
RUN pip install --no-cache --break-system-packages \ RUN pip install --no-cache --break-system-packages \
pre-commit==${PRE_COMMIT_VERSION} pre-commit==${PRE_COMMIT_VERSION}
+20 -7
View File
@@ -26,8 +26,6 @@ import sys
import tempfile import tempfile
from pathlib import Path from pathlib import Path
CLANG_TIDY_VERSION = 22
# Extensions run-clang-tidy can analyse: `.cpp` translation units and, thanks to # Extensions run-clang-tidy can analyse: `.cpp` translation units and, thanks to
# the `verify_headers` build option, `.h`/`.hpp` headers (each has its own # the `verify_headers` build option, `.h`/`.hpp` headers (each has its own
# compile_commands.json entry). `.ipp` fragments have no entry and are skipped. # compile_commands.json entry). `.ipp` fragments have no entry and are skipped.
@@ -39,8 +37,21 @@ TIDY_EXTENSIONS = {".cpp", ".h", ".hpp"}
FILEPATH_RE = re.compile(r"^(\s*(?:-\s+)?FilePath:\s*)'((?:[^']|'')*)'\s*$") FILEPATH_RE = re.compile(r"^(\s*(?:-\s+)?FilePath:\s*)'((?:[^']|'')*)'\s*$")
def find_tool(name: str) -> str | None: def clang_tidy_major() -> str | None:
for candidate in (f"{name}-{CLANG_TIDY_VERSION}", name): """Major version of the `clang-tidy` on PATH, which run-clang-tidy invokes."""
if not (clang_tidy := shutil.which("clang-tidy")):
return None
output = subprocess.run(
[clang_tidy, "--version"], capture_output=True, text=True
).stdout
m = re.search(r"LLVM version (\d+)", output)
return m.group(1) if m else None
def find_tool(name: str, version: str | None) -> str | None:
"""Prefer `<name>-<version>`, so a host tool of another version can't win."""
candidates = ([f"{name}-{version}"] if version else []) + [name]
for candidate in candidates:
if path := shutil.which(candidate): if path := shutil.which(candidate):
return path return path
return None return None
@@ -103,8 +114,9 @@ def main():
if not files: if not files:
return 0 return 0
run_clang_tidy = find_tool("run-clang-tidy") version = clang_tidy_major()
clang_apply_replacements = find_tool("clang-apply-replacements") run_clang_tidy = find_tool("run-clang-tidy", version)
clang_apply_replacements = find_tool("clang-apply-replacements", version)
missing = [ missing = [
name name
for name, path in ( for name, path in (
@@ -114,9 +126,10 @@ def main():
if not path if not path
] ]
if missing: if missing:
tried = f" (tried the '-{version}' suffix too)" if version else ""
print( print(
f"clang-tidy check failed: TIDY is enabled but {' and '.join(missing)} " f"clang-tidy check failed: TIDY is enabled but {' and '.join(missing)} "
f"was not found in PATH (tried the '-{CLANG_TIDY_VERSION}' suffix too).", f"was not found in PATH{tried}.",
file=sys.stderr, file=sys.stderr,
) )
return 1 return 1
+2 -2
View File
@@ -17,7 +17,7 @@
(runtime libraries resolved through the rpath) are skipped too. (runtime libraries resolved through the rpath) are skipped too.
Everywhere else `patch_nix_binary` is a no-op. Everywhere else `patch_nix_binary` is a no-op.
The default loader is resolved by bin/default-loader-path.sh. The default loader is resolved by bin/nix/default-loader-path.sh.
#]===================================================================] #]===================================================================]
include_guard(GLOBAL) include_guard(GLOBAL)
@@ -25,7 +25,7 @@ include_guard(GLOBAL)
include(CompilationEnv) include(CompilationEnv)
# Resolves the system default ELF loader path for the current architecture. # Resolves the system default ELF loader path for the current architecture.
set(_loader_path_script "${CMAKE_SOURCE_DIR}/bin/default-loader-path.sh") set(_loader_path_script "${CMAKE_SOURCE_DIR}/bin/nix/default-loader-path.sh")
if( if(
is_linux is_linux
+9
View File
@@ -292,6 +292,14 @@ if(xrpld)
) )
target_sources(xrpld PRIVATE ${sources}) target_sources(xrpld PRIVATE ${sources})
rpcspec_generate_instantiations(
OUT_VAR rpcspec_instantiations
VALUE_TYPE "::json::Value"
VIEW_HEADER "xrpld/rpc/detail/JsonObjectView.hpp"
HANDLERS book_changes ledger transaction_entry
)
target_sources(xrpld PRIVATE ${rpcspec_instantiations})
if(tests) if(tests)
file( file(
GLOB_RECURSE sources GLOB_RECURSE sources
@@ -322,6 +330,7 @@ if(xrpld)
# antithesis_instrumentation.h, which is not exported as INTERFACE # antithesis_instrumentation.h, which is not exported as INTERFACE
target_include_directories( target_include_directories(
xrpld xrpld
SYSTEM
PRIVATE ${CMAKE_SOURCE_DIR}/external/antithesis-sdk PRIVATE ${CMAKE_SOURCE_DIR}/external/antithesis-sdk
) )
endif() endif()
+6 -1
View File
@@ -77,19 +77,24 @@ if(is_clang)
message(STATUS " Ignorelist: ${ignorelist_path}") message(STATUS " Ignorelist: ${ignorelist_path}")
endif() endif()
# Define SANITIZERS macro for BuildInfo.cpp # Define the SANITIZERS macro for BuildInfo.cpp, plus one of XRPL_ASAN,
# XRPL_TSAN and XRPL_UBSAN per active sanitizer, so that code can test for a
# specific one with #ifdef instead of parsing the dot-joined SANITIZERS string.
set(sanitizers_list) set(sanitizers_list)
if(SANITIZERS MATCHES "address") if(SANITIZERS MATCHES "address")
set(enable_asan ON) set(enable_asan ON)
list(APPEND sanitizers_list "ASAN") list(APPEND sanitizers_list "ASAN")
target_compile_definitions(common INTERFACE XRPL_ASAN)
endif() endif()
if(SANITIZERS MATCHES "thread") if(SANITIZERS MATCHES "thread")
set(enable_tsan ON) set(enable_tsan ON)
list(APPEND sanitizers_list "TSAN") list(APPEND sanitizers_list "TSAN")
target_compile_definitions(common INTERFACE XRPL_TSAN)
endif() endif()
if(SANITIZERS MATCHES "undefinedbehavior") if(SANITIZERS MATCHES "undefinedbehavior")
set(enable_ubsan ON) set(enable_ubsan ON)
list(APPEND sanitizers_list "UBSAN") list(APPEND sanitizers_list "UBSAN")
target_compile_definitions(common INTERFACE XRPL_UBSAN)
endif() endif()
if(sanitizers_list) if(sanitizers_list)
+6 -2
View File
@@ -3,7 +3,7 @@
"requires": [ "requires": [
"zlib/1.3.2#1cb806da49011867778ffb6ac7190fcb%1782392402.122708", "zlib/1.3.2#1cb806da49011867778ffb6ac7190fcb%1782392402.122708",
"xxhash/0.8.3#681d36a0a6111fc56e5e45ea182c19cc%1782392402.420688", "xxhash/0.8.3#681d36a0a6111fc56e5e45ea182c19cc%1782392402.420688",
"xrpl-rpc-spec/0.1.19#870b2d3abcfbbf13b61c2d3c69495060%1790348286.187549", "xrpl-rpc-spec/0.1.21#d536f87a2ae7d313452746cfa3ac4404%1790869005.122975",
"sqlite3/3.53.0#324ada52333108388a9a6108bfa96734%1782392403.185447", "sqlite3/3.53.0#324ada52333108388a9a6108bfa96734%1782392403.185447",
"soci/4.0.3#e726491a03468795453f7c83fc924a96%1782392402.679521", "soci/4.0.3#e726491a03468795453f7c83fc924a96%1782392402.679521",
"snappy/1.1.10#968fef506ff261592ec30c574d4a7809%1782307151.633168", "snappy/1.1.10#968fef506ff261592ec30c574d4a7809%1782307151.633168",
@@ -20,7 +20,7 @@
"libarchive/3.8.7#c446109bd1f1d8ba7936c94189bc50e6%1782392403.066892", "libarchive/3.8.7#c446109bd1f1d8ba7936c94189bc50e6%1782392403.066892",
"jemalloc/5.3.1#1fc58d55316041f10fbc1e8a2eae632a%1776700028.228", "jemalloc/5.3.1#1fc58d55316041f10fbc1e8a2eae632a%1776700028.228",
"gtest/1.17.0#5224b3b3ff3b4ce1133cbdd27d53ee7d%1782392402.791979", "gtest/1.17.0#5224b3b3ff3b4ce1133cbdd27d53ee7d%1782392402.791979",
"grpc/1.81.1#b87796a4269034856cbc1a2522db16eb%1788275071.530512", "grpc/1.81.1#aaa93ab6cda2f2baa6a84490582c8adf%1791284951.826256",
"fast_float/8.2.10#f6f28d6bb22112078e7dbda611caf681%1785888854.601666", "fast_float/8.2.10#f6f28d6bb22112078e7dbda611caf681%1785888854.601666",
"ed25519/2015.03#ae761bdc52730a843f0809bdf6c1b1f6%1782307148.15562", "ed25519/2015.03#ae761bdc52730a843f0809bdf6c1b1f6%1782307148.15562",
"date/3.0.4#862e11e80030356b53c2c38599ceb32b%1782392402.538492", "date/3.0.4#862e11e80030356b53c2c38599ceb32b%1782392402.538492",
@@ -34,11 +34,15 @@
"build_requires": [ "build_requires": [
"zlib/1.3.2#1cb806da49011867778ffb6ac7190fcb%1782392402.122708", "zlib/1.3.2#1cb806da49011867778ffb6ac7190fcb%1782392402.122708",
"strawberryperl/5.32.1.1#8d114504d172cfea8ea1662d09b6333e%1782395692.540639", "strawberryperl/5.32.1.1#8d114504d172cfea8ea1662d09b6333e%1782395692.540639",
"re2/20251105#8579cfd0bda4daf0683f9e3898f964b4%1782392402.431897",
"protobuf/6.33.5#ff253ead763bd8d9904a52979cd21e81%1782392410.233933", "protobuf/6.33.5#ff253ead763bd8d9904a52979cd21e81%1782392410.233933",
"openssl/3.6.3#f806de8933e3bf6f01016c6a888cee2e%1783945160.863288",
"nasm/2.16.01#31e26f2ee3c4346ecd347911bd126904%1782395690.33162", "nasm/2.16.01#31e26f2ee3c4346ecd347911bd126904%1782395690.33162",
"msys2/cci.latest#d22fe7b2808f5fd34d0a7923ace9c54f%1770657326.649", "msys2/cci.latest#d22fe7b2808f5fd34d0a7923ace9c54f%1770657326.649",
"m4/1.4.19#1727f439cf74e83826ec96d0b4904eee%1784541921.659", "m4/1.4.19#1727f439cf74e83826ec96d0b4904eee%1784541921.659",
"grpc/1.81.1#aaa93ab6cda2f2baa6a84490582c8adf%1791284951.826256",
"cmake/4.3.3#840cf00ea09777e05c2050a50a82c722%1782392418.696091", "cmake/4.3.3#840cf00ea09777e05c2050a50a82c722%1782392418.696091",
"c-ares/1.34.6#545240bb1c40e2cacd4362d6b8967650%1782392402.681654",
"b2/5.4.2#ffd6084a119587e70f11cd45d1a386e2%1782392402.624226", "b2/5.4.2#ffd6084a119587e70f11cd45d1a386e2%1782392402.624226",
"automake/1.16.5#b91b7c384c3deaa9d535be02da14d04f%1755524470.56", "automake/1.16.5#b91b7c384c3deaa9d535be02da14d04f%1755524470.56",
"autoconf/2.71#51077f068e61700d65bb05541ea1e4b0%1731054366.86", "autoconf/2.71#51077f068e61700d65bb05541ea1e4b0%1731054366.86",
+9 -1
View File
@@ -3,5 +3,13 @@
core:non_interactive=True core:non_interactive=True
core.download:parallel={{ os.cpu_count() }} core.download:parallel={{ os.cpu_count() }}
core.upload:parallel={{ os.cpu_count() }} core.upload:parallel={{ os.cpu_count() }}
tools.files.download:retry=5 # Fall back to Conan Center's source backups when a recipe's upstream URL is down
# (e.g. the GNU FTP mirrors), see
# https://github.com/conan-io/conan-center-index/issues/28147#issuecomment-3183544772
# The backups are only tried once every upstream URL has used up its retries,
# so keep the retries low.
core.sources:download_urls=["origin", "https://c3i.jfrog.io/artifactory/conan-center-backup-sources"]
tools.files.download:retry=1
tools.files.download:retry_wait=10 tools.files.download:retry_wait=10
# Fail fast on unreachable hosts (default connect timeout is 30s), keep the 60s read timeout.
core.net.http:timeout=(5, 60)
+31 -4
View File
@@ -29,9 +29,9 @@ os.version={{ min_macos_version }}
[conf] [conf]
{# The Boost recipe builds with b2, which doesn't use Conan's toolchain files. #} {# The Boost recipe builds with b2, which doesn't use Conan's toolchain files. #}
{# Instead it hand-rolls the compiler for user-config.jam, #} {# Instead it hand-rolls the compiler for user-config.jam, #}
{# and its fallback probes a version-suffixed binary (e.g. `g++-15`) before plain `g++`. #} {# and its fallback probes a version-suffixed binary (e.g. `g++-<major>`) before plain `g++`. #}
{# Inside the Nix shell the wrapper only provides `g++`/`gcc` (no `-15` suffix), #} {# Inside the Nix shell the wrapper only provides `g++`/`gcc` (no `-<major>` suffix), #}
{# so on a host that also has a system `g++-15` the probe escapes Nix #} {# so on a host that also has a system `g++-<major>` the probe escapes Nix #}
{# and picks the system compiler, which is mismatched with the Nix libraries #} {# and picks the system compiler, which is mismatched with the Nix libraries #}
{# and breaks the build (e.g. Boost.Stacktrace link checks fail). #} {# and breaks the build (e.g. Boost.Stacktrace link checks fail). #}
{# Pinning the executables here short-circuits that probe so Boost (and the rest of the toolchain) #} {# Pinning the executables here short-circuits that probe so Boost (and the rest of the toolchain) #}
@@ -49,8 +49,31 @@ tools.build:compiler_executables={'c':'{{ cc_exe }}','cpp':'{{ cxx_exe }}'}
user.package:cppstd_version=23 user.package:cppstd_version=23
tools.info.package_id:confs+=["user.package:cppstd_version"] tools.info.package_id:confs+=["user.package:cppstd_version"]
{% if os == "Macos" %} {% if os == "Linux" and context == "build" %}
{# Build-context executables (protoc, grpc_cpp_plugin, build tools) run during the build #}
{# and would otherwise load libstdc++/libgcc from a Nix store path #}
{# that might change with a Nix toolchain update. #}
{# --as-needed drops the ones they link but don't use, #}
{# such as libatomic for grpc_cpp_plugin on arm64. #}
{% set static_runtime_flags = ["-static-libstdc++", "-static-libgcc", "-Wl,--as-needed"] %}
tools.build:exelinkflags+={{ static_runtime_flags }}
tools.info.package_id:confs+=["tools.build:exelinkflags"]
{% endif %}
{% if os == "Linux" and context == "build" %}
{# b2 links itself with its own script, which ignores exelinkflags #}
{# and only takes CXXFLAGS when use_cxx_env is set (see [buildenv] below). #}
[options]
b2/*:use_cxx_env=True
{% endif %}
[buildenv] [buildenv]
{# gRPC emits thousands of compiler warnings that we cannot act on. #}
{# CMake picks up CXXFLAGS, and unlike tools.build:cxxflags, #}
{# this is not part of the package ID, so binaries stay shareable. #}
grpc/*:CXXFLAGS=-w
{% if os == "Macos" %}
{# os.version adds -mmacosx-version-min to compiler command lines, #} {# os.version adds -mmacosx-version-min to compiler command lines, #}
{# but Boost.Context's b2 assembly (.S) rule ignores it, #} {# but Boost.Context's b2 assembly (.S) rule ignores it, #}
{# so those objects keep the host SDK version and still warn at link time. #} {# so those objects keep the host SDK version and still warn at link time. #}
@@ -58,3 +81,7 @@ tools.info.package_id:confs+=["user.package:cppstd_version"]
{# Scoped to boost/* since it is the only gap. #} {# Scoped to boost/* since it is the only gap. #}
boost/*:MACOSX_DEPLOYMENT_TARGET={{ min_macos_version }} boost/*:MACOSX_DEPLOYMENT_TARGET={{ min_macos_version }}
{% endif %} {% endif %}
{% if os == "Linux" and context == "build" %}
b2/*:CXXFLAGS={{ static_runtime_flags | join(" ") }}
{% endif %}
+3
View File
@@ -5,6 +5,9 @@ include(default)
{% if not sanitizers %} {% if not sanitizers %}
{# Sanitizers not configured; no additional settings needed #} {# Sanitizers not configured; no additional settings needed #}
{% elif context == "build" %}
{# Build-context packages are tools we run, not code we test, #}
{# so don't instrument them #}
{% else %} {% else %}
{% if compiler == "msvc" %} {% if compiler == "msvc" %}
+8 -3
View File
@@ -40,7 +40,7 @@ class Xrpl(ConanFile):
"nudb/2.0.9", "nudb/2.0.9",
"openssl/3.6.3", "openssl/3.6.3",
"soci/4.0.3", "soci/4.0.3",
"xrpl-rpc-spec/0.1.19", "xrpl-rpc-spec/0.1.21",
"zlib/1.3.2", "zlib/1.3.2",
] ]
@@ -49,7 +49,8 @@ class Xrpl(ConanFile):
] ]
tool_requires = [ tool_requires = [
"protobuf/6.33.5", "grpc/<host_version>",
"protobuf/<host_version>",
] ]
default_options = { default_options = {
@@ -123,6 +124,10 @@ class Xrpl(ConanFile):
"xxhash/*:shared": False, "xxhash/*:shared": False,
} }
# default_options only reach the host context;
# give tool_requires (and their dependencies) the same dependency options.
default_build_options = {k: v for k, v in default_options.items() if "/" in k}
def set_version(self): def set_version(self):
self.version = self.version or DEV_VERSION self.version = self.version or DEV_VERSION
@@ -149,7 +154,7 @@ class Xrpl(ConanFile):
self.requires("xxhash/0.8.3", transitive_headers=True) self.requires("xxhash/0.8.3", transitive_headers=True)
exports_sources = ( exports_sources = (
"bin/default-loader-path.sh", "bin/nix/default-loader-path.sh",
"CMakeLists.txt", "CMakeLists.txt",
"cfg/*", "cfg/*",
"cmake/*", "cmake/*",
+5 -6
View File
@@ -80,13 +80,12 @@ function(add_xrpl_crate name)
# `cc` picks its runtime flag from `crt-static` alone, so it compiles a # `cc` picks its runtime flag from `crt-static` alone, so it compiles a
# crate's C++ with `-MT`; Debug needs `-MTd` (to match cmake/XrplCompiler.cmake). # crate's C++ with `-MT`; Debug needs `-MTd` (to match cmake/XrplCompiler.cmake).
if(is_msvc) if(is_msvc)
corrosion_set_env_vars( corrosion_set_env_vars(${ARG_CRATE} "$<$<CONFIG:Debug>:CXXFLAGS=-MTd>")
${ARG_CRATE}
"$<$<CONFIG:Debug>:CXXFLAGS=-MTd>"
)
endif() endif()
corrosion_add_cxxbridge(${name}_cxxbridge CRATE ${ARG_CRATE} FILES corrosion_add_cxxbridge(
${ARG_FILES} ${name}_cxxbridge
CRATE ${ARG_CRATE}
FILES ${ARG_FILES}
) )
# Generated cxxbridge headers don't exist at configure time; CMake 3.28+ # Generated cxxbridge headers don't exist at configure time; CMake 3.28+
# validates INTERFACE_SOURCES on consuming targets. Clear it to skip the # validates INTERFACE_SOURCES on consuming targets. Clear it to skip the
+10 -10
View File
@@ -57,9 +57,9 @@ dependencies = [
[[package]] [[package]]
name = "cxx" name = "cxx"
version = "1.0.202" version = "1.0.205"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13f6de320895f42e6e081abb5c7983bedcf0b6d0ff9323de0d33f620c8ac1199" checksum = "c8a02bfeba9074b2bbb39492c9b0908ec854f455a3cccdcde7a1de55e2315e40"
dependencies = [ dependencies = [
"cc", "cc",
"cxx-build", "cxx-build",
@@ -72,9 +72,9 @@ dependencies = [
[[package]] [[package]]
name = "cxx-build" name = "cxx-build"
version = "1.0.202" version = "1.0.205"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fde53ca86b9704a943fef0f1e1d836239a6aedca5de3c65fa9f97ec0bd46d39" checksum = "bbc2ac76997619d2d888b58ad79488f1c835de41ca4dd3dd7082acf4ecb0a50f"
dependencies = [ dependencies = [
"cc", "cc",
"codespan-reporting", "codespan-reporting",
@@ -87,9 +87,9 @@ dependencies = [
[[package]] [[package]]
name = "cxxbridge-cmd" name = "cxxbridge-cmd"
version = "1.0.202" version = "1.0.205"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07bae89236c811fd4d08ed3441759ac4ac98d752cbfd3de341315ba16ad20ec3" checksum = "54a486ed16a3f2a053fe7f5b98db4c1a59846a23e8cb9e49f9d1bd48830d51a2"
dependencies = [ dependencies = [
"clap", "clap",
"codespan-reporting", "codespan-reporting",
@@ -101,15 +101,15 @@ dependencies = [
[[package]] [[package]]
name = "cxxbridge-flags" name = "cxxbridge-flags"
version = "1.0.202" version = "1.0.205"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49045042e5fced01b80742aba5508de82aa4f13677ed3fa2b4cda709c40c5918" checksum = "c72569be94e2283764d334cd285980b747dbe221e27e315484eb6bcd93fa808a"
[[package]] [[package]]
name = "cxxbridge-macro" name = "cxxbridge-macro"
version = "1.0.202" version = "1.0.205"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b181252e2e3d3b5d183afbdc033a3958b445eb3e1a0ae65fc3d4f5259f5da6fd" checksum = "423e795284a7f7b3f843c956a5322c4bc497b60c2dd1a6339da10313cb18d575"
dependencies = [ dependencies = [
"indexmap", "indexmap",
"proc-macro2", "proc-macro2",
+9 -7
View File
@@ -10,14 +10,15 @@ This document explains how to set one up.
support it — see [compiler support for C++23][cpp23-support]. support it — see [compiler support for C++23][cpp23-support].
The versions currently tested in CI are: The versions currently tested in CI are:
| Compiler | Version | | Compiler | Version |
| ----------- | ------------------ | | ----------- | ------------------------------- |
| GCC | 15.2 | | GCC | `gccVersion` in [packages.nix] |
| Clang | 22 | | Clang | `llvmVersion` in [packages.nix] |
| Apple Clang | 21 | | Apple Clang | 21 |
| MSVC | Visual Studio 2026 | | MSVC | Visual Studio 2026 |
LLVM tools (`clang-tidy` and `clang-format`) are also pinned to version 22. LLVM tools (`clang-tidy` and `clang-format`)
come from the same LLVM release as Clang.
### Older compilers ### Older compilers
@@ -156,3 +157,4 @@ version out of the box — run it via `run-clang-tidy`. No separate installation
is needed. is needed.
[cpp23-support]: https://en.cppreference.com/w/cpp/compiler_support/23 [cpp23-support]: https://en.cppreference.com/w/cpp/compiler_support/23
[packages.nix]: ../../nix/packages.nix
+21 -9
View File
@@ -183,24 +183,36 @@ at link or run time.
> configuration CI covers, and no dependency binaries are published for it. > configuration CI covers, and no dependency binaries are published for it.
This is checked rather than assumed. This is checked rather than assumed.
[`bin/check-nix-store-refs.sh`](../../bin/check-nix-store-refs.sh) takes one file [`bin/nix/check-nix-store-refs.sh`](../../bin/nix/check-nix-store-refs.sh) takes one
or directory and fails if a binary under it resolves a store path at run time. file or directory and fails if a binary under it resolves a store path at run time.
CI runs it over the build output and the Conan cache, and again in the upload job CI runs it over the build output and the Conan cache, and again in the upload job
before anything is published. You can run it yourself: before anything is published. You can run it yourself:
```bash ```bash
bin/check-nix-store-refs.sh build bin/nix/check-nix-store-refs.sh build
bin/check-nix-store-refs.sh ~/.conan2-nix bin/nix/check-nix-store-refs.sh ~/.conan2-nix
``` ```
It works on Linux too, but asserts something narrower there: the toolchain always It works on Linux too, but asserts something narrower there: the toolchain always
writes the store into `PT_INTERP` and `RUNPATH`, and CI builds inside an image writes the store into `PT_INTERP` and `RUNPATH`. That is fine for the pinned
whose store is fixed for its lifetime, so that is fine. Only the binaries glibc, whose path does not move, but not for the GCC runtime, which moves with
[`PatchNixBinary.cmake`](../../cmake/PatchNixBinary.cmake) retargets to the every GCC update. So [`conan/profiles/default`](../../conan/profiles/default)
system loader have to be clean, and those are what CI checks: links build-context packages, whose executables run during the build, with
`-static-libstdc++ -static-libgcc -Wl,--as-needed`, and
[`conan/profiles/sanitizers`](../../conan/profiles/sanitizers) does not
instrument them. CI checks that they load nothing from the store but glibc, from
the graph `conan install --format=json` writes:
```bash ```bash
bin/check-nix-store-refs.sh build/xrpld bin/nix/check-build-context-runtime.sh graph.json
```
Only the binaries [`PatchNixBinary.cmake`](../../cmake/PatchNixBinary.cmake)
retargets to the system loader have to be fully clean, and those are what CI
checks:
```bash
bin/nix/check-nix-store-refs.sh build/xrpld
``` ```
### The libresolv stub ### The libresolv stub
+3 -3
View File
@@ -178,11 +178,11 @@ A binary stops starting after a `nix flake update`, or after
dyld[57271]: Library not loaded: /nix/store/…-libresolv-93/lib/libresolv.9.dylib dyld[57271]: Library not loaded: /nix/store/…-libresolv-93/lib/libresolv.9.dylib
``` ```
[`bin/check-nix-store-refs.sh`](../../bin/check-nix-store-refs.sh) finds the same [`bin/nix/check-nix-store-refs.sh`](../../bin/nix/check-nix-store-refs.sh) finds the
thing without having to run anything, and names the file: same thing without having to run anything, and names the file:
``` ```
$ bin/check-nix-store-refs.sh ~/.conan2-nix $ bin/nix/check-nix-store-refs.sh ~/.conan2-nix
::error file=/Users/you/.conan2-nix/p/b/c-area24ded30c388c/p/bin/adig::references the Nix store at run time ::error file=/Users/you/.conan2-nix/p/b/c-area24ded30c388c/p/bin/adig::references the Nix store at run time
/Users/you/.conan2-nix/p/b/c-area24ded30c388c/p/bin/adig /Users/you/.conan2-nix/p/b/c-area24ded30c388c/p/bin/adig
/nix/store/p4lp3xq4imd1qzqh08x8vcq2zfhi7rca-libresolv-93/lib/libresolv.9.dylib /nix/store/p4lp3xq4imd1qzqh08x8vcq2zfhi7rca-libresolv-93/lib/libresolv.9.dylib
+1 -1
View File
@@ -6,7 +6,7 @@ project(antithesis-sdk-cpp VERSION 0.4.4 LANGUAGES CXX)
add_library(antithesis-sdk-cpp INTERFACE antithesis_sdk.h) add_library(antithesis-sdk-cpp INTERFACE antithesis_sdk.h)
# Note, both sections below created by xrpld project # Note, both sections below created by xrpld project
target_include_directories(antithesis-sdk-cpp INTERFACE target_include_directories(antithesis-sdk-cpp SYSTEM INTERFACE
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}> $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
) )
Generated
+6 -6
View File
@@ -2,11 +2,11 @@
"nodes": { "nodes": {
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1781173989, "lastModified": 1791130267,
"narHash": "sha256-fnzKKPvS+oieI/pTzotA5tkoM47EB1NpaBcgk4R97hE=", "narHash": "sha256-1sjwcQMcgAbmiip/VivBSiK8p2bTkQGOvCuO7vnwfx4=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "8c91a71d13451abc40eb9dae8910f972f979852f", "rev": "9013764fcc0ea99fa16cf7aa7decf8a5c3889dd2",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -47,11 +47,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1784611586, "lastModified": 1791189933,
"narHash": "sha256-OfqgY+0hp/zseZB7uyH0U8kIDPS4scZZCyAurEplvG0=", "narHash": "sha256-Y8eN7ki0Urx4Ojf4w1xSpWg8uk/3lJqK+E0Oth77rH0=",
"owner": "oxalica", "owner": "oxalica",
"repo": "rust-overlay", "repo": "rust-overlay",
"rev": "14f58845249f3552a89b07772626b8d3c632fa86", "rev": "e60029353d0c48d216bc4b065168ccd4079c166f",
"type": "github" "type": "github"
}, },
"original": { "original": {
+1 -1
View File
@@ -34,7 +34,7 @@ lz4Compress(void const* in, std::size_t inSize, BufferFactory&& bf)
// data // data
auto compressed = bf(outCapacity); auto compressed = bf(outCapacity);
auto compressedSize = LZ4_compress_default( auto const compressedSize = LZ4_compress_default(
reinterpret_cast<char const*>(in), reinterpret_cast<char const*>(in),
reinterpret_cast<char*>(compressed), reinterpret_cast<char*>(compressed),
inSize, inSize,
+38 -30
View File
@@ -20,12 +20,14 @@ SharedIntrusive<T>::SharedIntrusive(T* p, TAdoptTag) noexcept : ptr_{p}
template <class T> template <class T>
SharedIntrusive<T>::SharedIntrusive(SharedIntrusive const& rhs) SharedIntrusive<T>::SharedIntrusive(SharedIntrusive const& rhs)
: ptr_{[&] { : ptr_{
auto p = rhs.unsafeGetRawPtr(); [&] {
if (p) auto p = rhs.unsafeGetRawPtr();
p->addStrongRef(); if (p)
return p; p->addStrongRef();
}()} return p;
}(),
}
{ {
} }
@@ -33,12 +35,14 @@ template <class T>
template <class TT> template <class TT>
requires std::convertible_to<TT*, T*> requires std::convertible_to<TT*, T*>
SharedIntrusive<T>::SharedIntrusive(SharedIntrusive<TT> const& rhs) SharedIntrusive<T>::SharedIntrusive(SharedIntrusive<TT> const& rhs)
: ptr_{[&] { : ptr_{
auto p = rhs.unsafeGetRawPtr(); [&] {
if (p) auto p = rhs.unsafeGetRawPtr();
p->addStrongRef(); if (p)
return p; p->addStrongRef();
}()} return p;
}(),
}
{ {
} }
@@ -140,12 +144,14 @@ SharedIntrusive<T>::~SharedIntrusive()
template <class T> template <class T>
template <class TT> template <class TT>
SharedIntrusive<T>::SharedIntrusive(StaticCastTagSharedIntrusive, SharedIntrusive<TT> const& rhs) SharedIntrusive<T>::SharedIntrusive(StaticCastTagSharedIntrusive, SharedIntrusive<TT> const& rhs)
: ptr_{[&] { : ptr_{
auto p = static_cast<T*>(rhs.unsafeGetRawPtr()); [&] {
if (p) auto p = static_cast<T*>(rhs.unsafeGetRawPtr());
p->addStrongRef(); if (p)
return p; p->addStrongRef();
}()} return p;
}(),
}
{ {
} }
@@ -159,12 +165,14 @@ SharedIntrusive<T>::SharedIntrusive(StaticCastTagSharedIntrusive, SharedIntrusiv
template <class T> template <class T>
template <class TT> template <class TT>
SharedIntrusive<T>::SharedIntrusive(DynamicCastTagSharedIntrusive, SharedIntrusive<TT> const& rhs) SharedIntrusive<T>::SharedIntrusive(DynamicCastTagSharedIntrusive, SharedIntrusive<TT> const& rhs)
: ptr_{[&] { : ptr_{
auto p = dynamic_cast<T*>(rhs.unsafeGetRawPtr()); [&] {
if (p) auto p = dynamic_cast<T*>(rhs.unsafeGetRawPtr());
p->addStrongRef(); if (p)
return p; p->addStrongRef();
}()} return p;
}(),
}
{ {
} }
@@ -260,7 +268,7 @@ SharedIntrusive<T>::unsafeReleaseAndStore(T* next)
return; return;
using enum ReleaseStrongRefAction; using enum ReleaseStrongRefAction;
auto action = prev->releaseStrongRef(); auto const action = prev->releaseStrongRef();
switch (action) switch (action)
{ {
case NoOp: case NoOp:
@@ -361,7 +369,7 @@ WeakIntrusive<T>::unsafeReleaseNoStore()
return; return;
using enum ReleaseWeakRefAction; using enum ReleaseWeakRefAction;
auto action = ptr_->releaseWeakRef(); auto const action = ptr_->releaseWeakRef();
switch (action) switch (action)
{ {
case NoOp: case NoOp:
@@ -580,7 +588,7 @@ SharedWeakUnion<T>::convertToStrong()
auto p = unsafeGetRawPtr(); auto p = unsafeGetRawPtr();
if (p && p->checkoutStrongRefFromWeak()) if (p && p->checkoutStrongRefFromWeak())
{ {
[[maybe_unused]] auto action = p->releaseWeakRef(); [[maybe_unused]] auto const action = p->releaseWeakRef();
XRPL_ASSERT( XRPL_ASSERT(
(action == ReleaseWeakRefAction::NoOp), (action == ReleaseWeakRefAction::NoOp),
"xrpl::SharedWeakUnion::convertToStrong : " "xrpl::SharedWeakUnion::convertToStrong : "
@@ -603,7 +611,7 @@ SharedWeakUnion<T>::convertToWeak()
return false; return false;
using enum ReleaseStrongRefAction; using enum ReleaseStrongRefAction;
auto action = p->addWeakReleaseStrongRef(); auto const action = p->addWeakReleaseStrongRef();
switch (action) switch (action)
{ {
case NoOp: case NoOp:
@@ -670,7 +678,7 @@ SharedWeakUnion<T>::unsafeReleaseNoStore()
if (isStrong()) if (isStrong())
{ {
using enum ReleaseStrongRefAction; using enum ReleaseStrongRefAction;
auto strongAction = p->releaseStrongRef(); auto const strongAction = p->releaseStrongRef();
switch (strongAction) switch (strongAction)
{ {
case NoOp: case NoOp:
@@ -688,7 +696,7 @@ SharedWeakUnion<T>::unsafeReleaseNoStore()
else else
{ {
using enum ReleaseWeakRefAction; using enum ReleaseWeakRefAction;
auto weakAction = p->releaseWeakRef(); auto const weakAction = p->releaseWeakRef();
switch (weakAction) switch (weakAction)
{ {
case NoOp: case NoOp:
+2 -2
View File
@@ -406,10 +406,10 @@ IntrusiveRefCounts::useCount() const noexcept
inline IntrusiveRefCounts::~IntrusiveRefCounts() noexcept inline IntrusiveRefCounts::~IntrusiveRefCounts() noexcept
{ {
#ifndef NDEBUG #ifndef NDEBUG
auto v = refCounts_.load(std::memory_order_acquire); auto const v = refCounts_.load(std::memory_order_acquire);
XRPL_ASSERT( XRPL_ASSERT(
(!(v & kValueMask)), "xrpl::IntrusiveRefCounts::~IntrusiveRefCounts : count must be zero"); (!(v & kValueMask)), "xrpl::IntrusiveRefCounts::~IntrusiveRefCounts : count must be zero");
auto t = v & kTagMask; auto const t = v & kTagMask;
XRPL_ASSERT((!t || t == kTagMask), "xrpl::IntrusiveRefCounts::~IntrusiveRefCounts : valid tag"); XRPL_ASSERT((!t || t == kTagMask), "xrpl::IntrusiveRefCounts::~IntrusiveRefCounts : valid tag");
#endif #endif
} }
+75
View File
@@ -3,9 +3,84 @@
#include <algorithm> #include <algorithm>
#include <cassert> #include <cassert>
#include <cstddef> #include <cstddef>
#include <cstdint>
#include <limits>
#include <optional>
namespace xrpl { namespace xrpl {
/**
* Add two signed 64-bit integers, returning std::nullopt when the exact
* mathematical sum is not representable in std::int64_t.
*/
[[nodiscard]] constexpr std::optional<std::int64_t>
checkedAdd(std::int64_t a, std::int64_t b) noexcept
{
using L = std::numeric_limits<std::int64_t>;
if ((b > 0 && a > L::max() - b) || (b < 0 && a < L::min() - b))
return std::nullopt;
return a + b;
}
/**
* Subtract two signed 64-bit integers, returning std::nullopt when the exact
* mathematical difference is not representable in std::int64_t.
*/
[[nodiscard]] constexpr std::optional<std::int64_t>
checkedSub(std::int64_t a, std::int64_t b) noexcept
{
using L = std::numeric_limits<std::int64_t>;
if ((b > 0 && a < L::min() + b) || (b < 0 && a > L::max() + b))
return std::nullopt;
return a - b;
}
static_assert(checkedAdd(0, 0) == 0);
static_assert(checkedAdd(1, -1) == 0);
static_assert(checkedAdd(-5, 2) == -3);
static_assert(!checkedAdd(std::numeric_limits<std::int64_t>::max(), 1).has_value());
static_assert(!checkedAdd(std::numeric_limits<std::int64_t>::min(), -1).has_value());
static_assert(
checkedAdd(std::numeric_limits<std::int64_t>::max() - 1, 1) ==
std::numeric_limits<std::int64_t>::max());
static_assert(
checkedAdd(
std::numeric_limits<std::int64_t>::min(),
std::numeric_limits<std::int64_t>::max()) == -1);
static_assert(
checkedAdd(
std::numeric_limits<std::int64_t>::max(),
std::numeric_limits<std::int64_t>::min()) == -1);
static_assert(
!checkedAdd(std::numeric_limits<std::int64_t>::max(), std::numeric_limits<std::int64_t>::max())
.has_value());
static_assert(
!checkedAdd(std::numeric_limits<std::int64_t>::min(), std::numeric_limits<std::int64_t>::min())
.has_value());
static_assert(checkedSub(0, 0) == 0);
static_assert(checkedSub(1, 1) == 0);
static_assert(checkedSub(-5, 2) == -7);
static_assert(checkedSub(-5, -2) == -3);
static_assert(!checkedSub(std::numeric_limits<std::int64_t>::min(), 1).has_value());
static_assert(!checkedSub(std::numeric_limits<std::int64_t>::max(), -1).has_value());
static_assert(
checkedSub(std::numeric_limits<std::int64_t>::min() + 1, 1) ==
std::numeric_limits<std::int64_t>::min());
static_assert(
checkedSub(-1, std::numeric_limits<std::int64_t>::max()) ==
std::numeric_limits<std::int64_t>::min());
static_assert(
!checkedSub(std::numeric_limits<std::int64_t>::max(), std::numeric_limits<std::int64_t>::min())
.has_value());
static_assert(
!checkedSub(std::numeric_limits<std::int64_t>::min(), std::numeric_limits<std::int64_t>::max())
.has_value());
/** /**
* Calculate one number divided by another number in percentage. * Calculate one number divided by another number in percentage.
* The result is rounded up to the next integer, and capped in the range [0,100] * The result is rounded up to the next integer, and capped in the range [0,100]
+1 -1
View File
@@ -340,7 +340,7 @@ public:
for (auto const& c : cfg) for (auto const& c : cfg)
{ {
auto& a = allocators_.emplace_back(c.extra_, c.alloc_, c.align_); auto const& a = allocators_.emplace_back(c.extra_, c.alloc_, c.align_);
if (a.size() > maxSize_) if (a.size() > maxSize_)
maxSize_ = a.size(); maxSize_ = a.size();
+1 -1
View File
@@ -36,7 +36,7 @@ template <typename T>
concept SomeChar = std::same_as<std::remove_cvref_t<T>, int8_t> || concept SomeChar = std::same_as<std::remove_cvref_t<T>, int8_t> ||
std::same_as<std::remove_cvref_t<T>, char> || std::same_as<std::remove_cvref_t<T>, uint8_t>; std::same_as<std::remove_cvref_t<T>, char> || std::same_as<std::remove_cvref_t<T>, uint8_t>;
inline constexpr std::array<std::optional<int>, 256> const kDigitLookupTable = []() { inline constexpr std::array<std::optional<int>, 256> const kDigitLookupTable = [] {
std::array<std::optional<int>, 256> t{}; std::array<std::optional<int>, 256> t{};
for (int i = 0; i < 10; ++i) for (int i = 0; i < 10; ++i)
+9 -9
View File
@@ -300,7 +300,7 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
// Remove from cache, if !valid, remove from map too. Returns true if removed from cache // Remove from cache, if !valid, remove from map too. Returns true if removed from cache
std::scoped_lock const lock(mutex_); std::scoped_lock const lock(mutex_);
auto cit = cache_.find(key); auto const cit = cache_.find(key);
if (cit == cache_.end()) if (cit == cache_.end())
return false; return false;
@@ -356,7 +356,7 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
std::scoped_lock const lock(mutex_); std::scoped_lock const lock(mutex_);
auto cit = cache_.find(key); auto const cit = cache_.find(key);
if (cit == cache_.end()) if (cit == cache_.end())
{ {
@@ -371,7 +371,7 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
Entry& entry = cit->second; Entry& entry = cit->second;
entry.touch(clock_.now()); entry.touch(clock_.now());
auto shouldReplaceCached = [&] { auto const shouldReplaceCached = [&] {
if constexpr (replaceCached) if constexpr (replaceCached)
{ {
return true; return true;
@@ -400,7 +400,7 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
return true; return true;
} }
auto cachedData = entry.lock(); auto const cachedData = entry.lock();
if (cachedData) if (cachedData)
{ {
@@ -563,7 +563,7 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
retrieve(key_type const& key, T& data) retrieve(key_type const& key, T& data)
{ {
// retrieve the value of the stored data // retrieve the value of the stored data
auto entry = fetch(key); auto const entry = fetch(key);
if (!entry) if (!entry)
return false; return false;
@@ -687,7 +687,7 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
return ret; return ret;
} }
auto sle = h(); auto const sle = h();
if (!sle) if (!sle)
return {}; return {};
@@ -713,7 +713,7 @@ inline SharedPointerType
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>:: TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::
initialFetch(key_type const& key, std::scoped_lock<MutexType> const& l) initialFetch(key_type const& key, std::scoped_lock<MutexType> const& l)
{ {
auto cit = cache_.find(key); auto const cit = cache_.find(key);
if (cit == cache_.end()) if (cit == cache_.end())
return {}; return {};
@@ -783,7 +783,7 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
std::atomic<int>& allRemovals, std::atomic<int>& allRemovals,
std::scoped_lock<std::recursive_mutex> const&) std::scoped_lock<std::recursive_mutex> const&)
{ {
return std::thread([&, this]() { return std::thread([&, this] {
int cacheRemovals = 0; int cacheRemovals = 0;
int mapRemovals = 0; int mapRemovals = 0;
@@ -863,7 +863,7 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
std::atomic<int>& allRemovals, std::atomic<int>& allRemovals,
std::scoped_lock<std::recursive_mutex> const&) std::scoped_lock<std::recursive_mutex> const&)
{ {
return std::thread([&, this]() { return std::thread([&, this] {
// NOLINTBEGIN https://github.com/XRPLF/rippled/issues/7056 // NOLINTBEGIN https://github.com/XRPLF/rippled/issues/7056
int cacheRemovals = 0; int cacheRemovals = 0;
int mapRemovals = 0; int mapRemovals = 0;
+3 -2
View File
@@ -195,7 +195,8 @@ private:
{ {
// Local lambda that converts a single hex char to four bits and // Local lambda that converts a single hex char to four bits and
// ORs those bits into a uint32_t. // ORs those bits into a uint32_t.
auto hexCharToUInt = [](char c, std::uint32_t shift, std::uint32_t& accum) -> ParseResult { auto const hexCharToUInt =
[](char c, std::uint32_t shift, std::uint32_t& accum) -> ParseResult {
std::uint32_t nibble = 0xFFu; std::uint32_t nibble = 0xFFu;
if (c < '0' || c > 'f') if (c < '0' || c > 'f')
return ParseResult::BadChar; return ParseResult::BadChar;
@@ -453,7 +454,7 @@ public:
{ {
for (int i = kWidth - 1; i >= 0; --i) for (int i = kWidth - 1; i >= 0; --i)
{ {
auto prev = data_[i]; auto const prev = data_[i];
data_[i] = boost::endian::native_to_big(boost::endian::big_to_native(data_[i]) - 1); data_[i] = boost::endian::native_to_big(boost::endian::big_to_native(data_[i]) - 1);
if (prev != 0) if (prev != 0)
@@ -17,7 +17,7 @@
namespace xrpl { namespace xrpl {
template <typename Key> template <typename Key>
static std::size_t std::size_t
extract(Key const& key) extract(Key const& key)
{ {
return key; return key;
@@ -365,7 +365,7 @@ public:
size() const size() const
{ {
std::size_t ret = 0; std::size_t ret = 0;
for (auto& p : map_) for (auto const& p : map_)
ret += p.size(); ret += p.size();
return ret; return ret;
} }
@@ -1604,7 +1604,7 @@ AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::erase(
beast::detail::AgedContainerIterator<IsConst, Iterator> pos) beast::detail::AgedContainerIterator<IsConst, Iterator> pos)
requires(!IsBoostReverseIterator<Iterator>::value) requires(!IsBoostReverseIterator<Iterator>::value)
{ {
unlinkAndDeleteElement(&*((pos++).iterator())); unlinkAndDeleteElement(&*(pos++).iterator());
return beast::detail::AgedContainerIterator<false, Iterator>(pos.iterator()); return beast::detail::AgedContainerIterator<false, Iterator>(pos.iterator());
} }
@@ -1617,7 +1617,7 @@ AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::erase(
requires(!IsBoostReverseIterator<Iterator>::value) requires(!IsBoostReverseIterator<Iterator>::value)
{ {
for (; first != last;) for (; first != last;)
unlinkAndDeleteElement(&*((first++).iterator())); unlinkAndDeleteElement(&*(first++).iterator());
return beast::detail::AgedContainerIterator<false, Iterator>(first.iterator()); return beast::detail::AgedContainerIterator<false, Iterator>(first.iterator());
} }
@@ -2404,7 +2404,7 @@ beast::detail::AgedContainerIterator<false, Iterator>
AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>::erase( AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>::erase(
beast::detail::AgedContainerIterator<IsConst, Iterator> pos) beast::detail::AgedContainerIterator<IsConst, Iterator> pos)
{ {
unlinkAndDeleteElement(&*((pos++).iterator())); unlinkAndDeleteElement(&*(pos++).iterator());
return beast::detail::AgedContainerIterator<false, Iterator>(pos.iterator()); return beast::detail::AgedContainerIterator<false, Iterator>(pos.iterator());
} }
@@ -2424,7 +2424,7 @@ AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>
beast::detail::AgedContainerIterator<IsConst, Iterator> last) beast::detail::AgedContainerIterator<IsConst, Iterator> last)
{ {
for (; first != last;) for (; first != last;)
unlinkAndDeleteElement(&*((first++).iterator())); unlinkAndDeleteElement(&*(first++).iterator());
return beast::detail::AgedContainerIterator<false, Iterator>(first.iterator()); return beast::detail::AgedContainerIterator<false, Iterator>(first.iterator());
} }
@@ -2536,7 +2536,7 @@ AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>
return false; return false;
for (auto iter(cbegin()), last(cend()), otherLast(other.cend()); iter != last; ++iter) for (auto iter(cbegin()), last(cend()), otherLast(other.cend()); iter != last; ++iter)
{ {
auto otherIter(other.find(extract(*iter))); auto const otherIter(other.find(extract(*iter)));
if (otherIter == otherLast) if (otherIter == otherLast)
return false; return false;
} }
+1 -1
View File
@@ -68,7 +68,7 @@ struct LexicalCast<Out, std::string_view>
if (first != last && *first == '+') if (first != last && *first == '+')
++first; ++first;
auto ret = std::from_chars(first, last, out); auto const ret = std::from_chars(first, last, out);
return ret.ec == std::errc() && ret.ptr == last; return ret.ec == std::errc() && ret.ptr == last;
} }
+1 -1
View File
@@ -390,7 +390,7 @@ void
hash_append(Hasher& h, boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept hash_append(Hasher& h, boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept
requires(IsContiguouslyHashable<Key, Hasher>::value) requires(IsContiguouslyHashable<Key, Hasher>::value)
{ {
h(&(v.begin()), v.size() * sizeof(Key)); h(&v.begin(), v.size() * sizeof(Key));
} }
// tuple // tuple
+1 -1
View File
@@ -8,7 +8,7 @@ namespace beast::insight {
class HookImpl : public std::enable_shared_from_this<HookImpl> class HookImpl : public std::enable_shared_from_this<HookImpl>
{ {
public: public:
using HandlerType = std::function<void(void)>; using HandlerType = std::function<void()>;
virtual ~HookImpl() = 0; virtual ~HookImpl() = 0;
}; };
+2 -2
View File
@@ -61,7 +61,7 @@ isMulticast(Address const& addr)
inline bool inline bool
isPrivate(Address const& addr) isPrivate(Address const& addr)
{ {
return (addr.is_v4()) ? isPrivate(addr.to_v4()) : isPrivate(addr.to_v6()); return addr.is_v4() ? isPrivate(addr.to_v4()) : isPrivate(addr.to_v6());
} }
/** /**
@@ -70,7 +70,7 @@ isPrivate(Address const& addr)
inline bool inline bool
isPublic(Address const& addr) isPublic(Address const& addr)
{ {
return (addr.is_v4()) ? isPublic(addr.to_v4()) : isPublic(addr.to_v6()); return addr.is_v4() ? isPublic(addr.to_v4()) : isPublic(addr.to_v6());
} }
} // namespace ip } // namespace ip
+1 -1
View File
@@ -83,7 +83,7 @@ trimRight(String const& s)
{ {
using std::begin; using std::begin;
using std::end; using std::end;
auto first(begin(s)); auto const first(begin(s));
auto last(end(s)); auto last(end(s));
last = trimRight(first, last); last = trimRight(first, last);
return {first, last}; return {first, last};
+1 -1
View File
@@ -34,7 +34,7 @@ typeName()
name += " volatile"; name += " volatile";
if (std::is_lvalue_reference_v<T>) if (std::is_lvalue_reference_v<T>)
{ {
name += "&"; name += '&';
} }
else if (std::is_rvalue_reference_v<T>) else if (std::is_rvalue_reference_v<T>)
{ {
+1 -1
View File
@@ -32,7 +32,7 @@ public:
Module, Module,
// Match nothing (used internally) // Match nothing (used internally)
None None,
}; };
private: private:
+1 -1
View File
@@ -20,7 +20,7 @@ namespace beast::unit_test {
namespace detail { namespace detail {
template <class String> template <class String>
static std::string std::string
makeReason(String const& reason, char const* file, int line) makeReason(String const& reason, char const* file, int line)
{ {
std::string s(reason); std::string s(reason);
+3 -3
View File
@@ -47,8 +47,8 @@ public:
template <class F, class... Args> template <class F, class... Args>
explicit Thread(Suite& s, F&& f, Args&&... args) : s_(&s) explicit Thread(Suite& s, F&& f, Args&&... args) : s_(&s)
{ {
std::function<void(void)> b = [f = std::forward<F>(f), std::function<void()> b = [f = std::forward<F>(f),
... args = std::forward<Args>(args)]() mutable { ... args = std::forward<Args>(args)] mutable {
std::invoke(f, args...); std::invoke(f, args...);
}; };
t_ = std::thread(&Thread::run, this, std::move(b)); t_ = std::thread(&Thread::run, this, std::move(b));
@@ -94,7 +94,7 @@ public:
private: private:
void void
run(std::function<void(void)> f) run(std::function<void()> f)
{ {
try try
{ {
+1 -1
View File
@@ -24,7 +24,7 @@ enum class Severity : std::uint8_t {
Fatal = 5, Fatal = 5,
Disabled = 6, Disabled = 6,
None = Disabled None = Disabled,
}; };
/** /**
+1 -1
View File
@@ -18,7 +18,7 @@ enum class Type : std::uint8_t {
PrefixSha256 = 1, PrefixSha256 = 1,
ThresholdSha256 = 2, ThresholdSha256 = 2,
RsaSha256 = 3, RsaSha256 = 3,
Ed25519Sha256 = 4 Ed25519Sha256 = 4,
}; };
class Condition class Condition
@@ -49,7 +49,7 @@ public:
using namespace der; using namespace der;
auto p = parsePreamble(s, ec); auto const p = parsePreamble(s, ec);
if (ec) if (ec)
return nullptr; return nullptr;
+1 -1
View File
@@ -21,7 +21,7 @@ enum class Error {
UnexpectedTag, UnexpectedTag,
LongTag, LongTag,
LargeSize, LargeSize,
PreimageTooLong PreimageTooLong,
}; };
std::error_code std::error_code
+1 -1
View File
@@ -396,7 +396,7 @@ inline bool
getIfExists<bool>(Section const& section, std::string const& name, bool& v) getIfExists<bool>(Section const& section, std::string const& name, bool& v)
{ {
int intVal = 0; int intVal = 0;
auto stat = getIfExists(section, name, intVal); auto const stat = getIfExists(section, name, intVal);
if (stat) if (stat)
v = bool(intVal); v = bool(intVal);
return stat; return stat;
+2 -2
View File
@@ -93,14 +93,14 @@ public:
void void
check(std::vector<TxID> accepted, Predicate&& pred) check(std::vector<TxID> accepted, Predicate&& pred)
{ {
auto acceptTxid = accepted.begin(); auto const acceptTxid = accepted.begin();
auto const ae = accepted.end(); auto const ae = accepted.end();
std::sort(acceptTxid, ae); std::sort(acceptTxid, ae);
// We want to remove all tracking entries for transactions that were // We want to remove all tracking entries for transactions that were
// accepted as well as those which match the predicate. // accepted as well as those which match the predicate.
auto i = removeIfIntersectOrMatch( auto const i = removeIfIntersectOrMatch(
tracker_.begin(), tracker_.begin(),
tracker_.end(), tracker_.end(),
accepted.begin(), accepted.begin(),
+10 -9
View File
@@ -779,7 +779,7 @@ Consensus<Adaptor>::peerProposalInternal(
{ {
// update current position // update current position
auto peerPosIt = currPeerPositions_.find(peerID); auto const peerPosIt = currPeerPositions_.find(peerID);
if (peerPosIt != currPeerPositions_.end()) if (peerPosIt != currPeerPositions_.end())
{ {
@@ -1110,7 +1110,7 @@ Consensus<Adaptor>::checkLedger(std::unique_ptr<std::stringstream> const& clog)
{ {
CLOG(clog) << "checkLedger. "; CLOG(clog) << "checkLedger. ";
auto netLgr = adaptor_.getPrevLedger(prevLedgerID_, previousLedger_, mode_.get()); auto const netLgr = adaptor_.getPrevLedger(prevLedgerID_, previousLedger_, mode_.get());
CLOG(clog) << "network ledgerid " << netLgr << ", " CLOG(clog) << "network ledgerid " << netLgr << ", "
<< "previous ledger " << prevLedgerID_ << ". "; << "previous ledger " << prevLedgerID_ << ". ";
@@ -1159,8 +1159,8 @@ Consensus<Adaptor>::phaseOpen(std::unique_ptr<std::stringstream> const& clog)
// it is shortly before ledger close time // it is shortly before ledger close time
bool const anyTransactions = adaptor_.hasOpenTransactions(); bool const anyTransactions = adaptor_.hasOpenTransactions();
auto proposersClosed = currPeerPositions_.size(); auto const proposersClosed = currPeerPositions_.size();
auto proposersValidated = adaptor_.proposersValidated(prevLedgerID_); auto const proposersValidated = adaptor_.proposersValidated(prevLedgerID_);
openTime_.tick(clock_.now()); openTime_.tick(clock_.now());
@@ -1669,7 +1669,7 @@ Consensus<Adaptor>::haveConsensus(std::unique_ptr<std::stringstream> const& clog
// CHECKME: should possibly count unacquired TX sets as disagreeing // CHECKME: should possibly count unacquired TX sets as disagreeing
int agree = 0, disagree = 0; int agree = 0, disagree = 0;
auto ourPosition = result_->position.position(); auto const ourPosition = result_->position.position();
// Count number of agreements/disagreements with our position // Count number of agreements/disagreements with our position
for (auto const& [nodeId, peerPos] : currPeerPositions_) for (auto const& [nodeId, peerPos] : currPeerPositions_)
@@ -1686,7 +1686,7 @@ Consensus<Adaptor>::haveConsensus(std::unique_ptr<std::stringstream> const& clog
++disagree; ++disagree;
} }
} }
auto currentFinished = adaptor_.proposersFinished(previousLedger_, prevLedgerID_); auto const currentFinished = adaptor_.proposersFinished(previousLedger_, prevLedgerID_);
JLOG(j_.debug()) << "Checking for TX consensus: agree=" << agree << ", disagree=" << disagree; JLOG(j_.debug()) << "Checking for TX consensus: agree=" << agree << ", disagree=" << disagree;
@@ -1812,7 +1812,7 @@ Consensus<Adaptor>::createDisputes(TxSetT const& o, std::unique_ptr<std::strings
<< ". "; << ". ";
JLOG(j_.debug()) << "createDisputes " << result_->txns.id() << " to " << o.id(); JLOG(j_.debug()) << "createDisputes " << result_->txns.id() << " to " << o.id();
auto differences = result_->txns.compare(o); auto const differences = result_->txns.compare(o);
int dc = 0; int dc = 0;
@@ -1826,7 +1826,7 @@ Consensus<Adaptor>::createDisputes(TxSetT const& o, std::unique_ptr<std::strings
"xrpl::Consensus::createDisputes : has disputed transactions"); "xrpl::Consensus::createDisputes : has disputed transactions");
TxT const tx = inThisSet ? result_->txns.find(txId) : o.find(txId); TxT const tx = inThisSet ? result_->txns.find(txId) : o.find(txId);
auto txID = tx.id(); auto const txID = tx.id();
if (result_->disputes.find(txID) != result_->disputes.end()) if (result_->disputes.find(txID) != result_->disputes.end())
continue; continue;
@@ -1837,7 +1837,8 @@ Consensus<Adaptor>::createDisputes(TxSetT const& o, std::unique_ptr<std::strings
tx, tx,
result_->txns.exists(txID), result_->txns.exists(txID),
std::max(prevProposers_, currPeerPositions_.size()), std::max(prevProposers_, currPeerPositions_.size()),
j_}; j_,
};
// Update all of the available peer's votes on the disputed transaction // Update all of the available peer's votes on the disputed transaction
for (auto const& [nodeId, peerPos] : currPeerPositions_) for (auto const& [nodeId, peerPos] : currPeerPositions_)
+16 -8
View File
@@ -145,18 +145,26 @@ struct ConsensusParms
std::map<AvalancheState, AvalancheCutoff> const avalancheCutoffs{ std::map<AvalancheState, AvalancheCutoff> const avalancheCutoffs{
// {state, {time, percent, nextState}}, // {state, {time, percent, nextState}},
// Initial state: 50% of nodes must vote yes // Initial state: 50% of nodes must vote yes
{AvalancheState::Init, {
{.consensusTime = 0, .consensusPct = 50, .next = AvalancheState::Mid}}, AvalancheState::Init,
{.consensusTime = 0, .consensusPct = 50, .next = AvalancheState::Mid},
},
// mid-consensus starts after 50% of the previous round time, and // mid-consensus starts after 50% of the previous round time, and
// requires 65% yes // requires 65% yes
{AvalancheState::Mid, {
{.consensusTime = 50, .consensusPct = 65, .next = AvalancheState::Late}}, AvalancheState::Mid,
{.consensusTime = 50, .consensusPct = 65, .next = AvalancheState::Late},
},
// late consensus starts after 85% time, and requires 70% yes // late consensus starts after 85% time, and requires 70% yes
{AvalancheState::Late, {
{.consensusTime = 85, .consensusPct = 70, .next = AvalancheState::Stuck}}, AvalancheState::Late,
{.consensusTime = 85, .consensusPct = 70, .next = AvalancheState::Stuck},
},
// we're stuck after 2x time, requires 95% yes votes // we're stuck after 2x time, requires 95% yes votes
{AvalancheState::Stuck, {
{.consensusTime = 200, .consensusPct = 95, .next = AvalancheState::Stuck}}, AvalancheState::Stuck,
{.consensusTime = 200, .consensusPct = 95, .next = AvalancheState::Stuck},
},
}; };
/** /**
+3 -3
View File
@@ -59,7 +59,7 @@ enum class ConsensusMode {
* if we entered the round observing, but is used to indicate we did * if we entered the round observing, but is used to indicate we did
* have the wrongLedger at some point. * have the wrongLedger at some point.
*/ */
SwitchedLedger SwitchedLedger,
}; };
inline std::string inline std::string
@@ -222,7 +222,7 @@ medianCloseOffset(ConsensusCloseTimes const& times)
// Accumulate weight in time order; the first bin to reach halfWeight is // Accumulate weight in time order; the first bin to reach halfWeight is
// the (lower) weighted median. Returns true once that bin is found. // the (lower) weighted median. Returns true once that bin is found.
auto step = [&](time_point t, std::int64_t w) { auto const step = [&](time_point t, std::int64_t w) {
XRPL_ASSERT(tally < halfWeight, "xrpl::medianCloseOffset::step : median not yet found"); XRPL_ASSERT(tally < halfWeight, "xrpl::medianCloseOffset::step : median not yet found");
tally += w; tally += w;
if (tally >= halfWeight) if (tally >= halfWeight)
@@ -267,7 +267,7 @@ enum class ConsensusState {
No, ///< We do not have consensus No, ///< We do not have consensus
MovedOn, ///< The network has consensus without us MovedOn, ///< The network has consensus without us
Expired, ///< Consensus time limit has hard-expired Expired, ///< Consensus time limit has hard-expired
Yes ///< We have consensus along with the network Yes, ///< We have consensus along with the network
}; };
/** /**
+1 -1
View File
@@ -266,7 +266,7 @@ template <class Tx, class NodeId>
void void
DisputedTx<Tx, NodeId>::unVote(NodeId const& peer) DisputedTx<Tx, NodeId>::unVote(NodeId const& peer)
{ {
auto it = votes_.find(peer); auto const it = votes_.find(peer);
if (it != votes_.end()) if (it != votes_.end())
{ {
+1 -1
View File
@@ -211,7 +211,7 @@ struct Node
void void
erase(Node const* child) erase(Node const* child)
{ {
auto it = std::ranges::find_if( auto const it = std::ranges::find_if(
children, [child](std::unique_ptr<Node> const& curr) { return curr.get() == child; }); children, [child](std::unique_ptr<Node> const& curr) { return curr.get() == child; });
XRPL_ASSERT(it != children.end(), "xrpl::Node::erase : valid input"); XRPL_ASSERT(it != children.end(), "xrpl::Node::erase : valid input");
std::swap(*it, children.back()); std::swap(*it, children.back());
+9 -9
View File
@@ -184,7 +184,7 @@ enum class ValStatus {
/** /**
* Multiple validations by a validator for different ledgers * Multiple validations by a validator for different ledgers
*/ */
Conflicting Conflicting,
}; };
inline std::string inline std::string
@@ -366,7 +366,7 @@ private:
removeTrie(std::scoped_lock<Mutex> const&, NodeID const& nodeID, Validation const& val) removeTrie(std::scoped_lock<Mutex> const&, NodeID const& nodeID, Validation const& val)
{ {
{ {
auto it = acquiring_.find(std::make_pair(val.seq(), val.ledgerID())); auto const it = acquiring_.find(std::make_pair(val.seq(), val.ledgerID()));
if (it != acquiring_.end()) if (it != acquiring_.end())
{ {
it->second.erase(nodeID); it->second.erase(nodeID);
@@ -375,7 +375,7 @@ private:
} }
} }
{ {
auto it = lastLedger_.find(nodeID); auto const it = lastLedger_.find(nodeID);
if (it != lastLedger_.end() && it->second.id() == val.ledgerID()) if (it != lastLedger_.end() && it->second.id() == val.ledgerID())
{ {
trie_.remove(it->second); trie_.remove(it->second);
@@ -443,7 +443,7 @@ private:
// Clear any prior acquiring ledger for this node // Clear any prior acquiring ledger for this node
if (prior) if (prior)
{ {
auto it = acquiring_.find(*prior); auto const it = acquiring_.find(*prior);
if (it != acquiring_.end()) if (it != acquiring_.end())
{ {
it->second.erase(nodeID); it->second.erase(nodeID);
@@ -455,7 +455,7 @@ private:
checkAcquired(lock); checkAcquired(lock);
std::pair<Seq, ID> const valPair{val.seq(), val.ledgerID()}; std::pair<Seq, ID> const valPair{val.seq(), val.ledgerID()};
auto it = acquiring_.find(valPair); auto const it = acquiring_.find(valPair);
if (it != acquiring_.end()) if (it != acquiring_.end())
{ {
it->second.insert(nodeID); it->second.insert(nodeID);
@@ -529,7 +529,7 @@ private:
} }
else else
{ {
auto cit = typename decltype(current_)::const_iterator{it}; auto const cit = typename decltype(current_)::const_iterator{it};
// contains a live record // contains a live record
f(cit->first, cit->second); f(cit->first, cit->second);
++it; ++it;
@@ -554,7 +554,7 @@ private:
void void
byLedger(std::scoped_lock<Mutex> const&, ID const& ledgerID, Pre&& pre, F&& f) byLedger(std::scoped_lock<Mutex> const&, ID const& ledgerID, Pre&& pre, F&& f)
{ {
auto it = byLedger_.find(ledgerID); auto const it = byLedger_.find(ledgerID);
if (it != byLedger_.end()) if (it != byLedger_.end())
{ {
// Update set time since it is being used // Update set time since it is being used
@@ -857,7 +857,7 @@ public:
if (!preferred) if (!preferred)
{ {
// fall back to majority over acquiring ledgers // fall back to majority over acquiring ledgers
auto it = std::ranges::max_element(acquiring_, [](auto const& a, auto const& b) { auto const it = std::ranges::max_element(acquiring_, [](auto const& a, auto const& b) {
std::pair<Seq, ID> const& aKey = a.first; std::pair<Seq, ID> const& aKey = a.first;
typename HashSet<NodeID>::size_type const& aSize = a.second.size(); typename HashSet<NodeID>::size_type const& aSize = a.second.size();
std::pair<Seq, ID> const& bKey = b.first; std::pair<Seq, ID> const& bKey = b.first;
@@ -937,7 +937,7 @@ public:
return (preferred->first >= minSeq) ? preferred->second : lcl.id(); return (preferred->first >= minSeq) ? preferred->second : lcl.id();
// Otherwise, rely on peer ledgers // Otherwise, rely on peer ledgers
auto it = std::ranges::max_element(peerCounts, [](auto const& a, auto const& b) { auto const it = std::ranges::max_element(peerCounts, [](auto const& a, auto const& b) {
// Prefer larger counts, then larger ids on ties // Prefer larger counts, then larger ids on ties
// (max_element expects this to return true if a < b) // (max_element expects this to return true if a < b)
return std::tie(a.second, a.first) < std::tie(b.second, b.first); return std::tie(a.second, a.first) < std::tie(b.second, b.first);
+1 -1
View File
@@ -156,7 +156,7 @@ public:
{ {
if (!allClosuresDoneCond_.wait_for(lock, wait, [this] { return closureCount_ == 0; })) if (!allClosuresDoneCond_.wait_for(lock, wait, [this] { return closureCount_ == 0; }))
{ {
if (auto stream = j.error()) if (auto const stream = j.error())
stream << name << " waiting for ClosureCounter::join()."; stream << name << " waiting for ClosureCounter::join().";
allClosuresDoneCond_.wait(lock, [this] { return closureCount_ == 0; }); allClosuresDoneCond_.wait(lock, [this] { return closureCount_ == 0; });
} }
+2 -2
View File
@@ -54,7 +54,7 @@ JobQueue::Coro::post()
} }
// sp keeps 'this' alive // sp keeps 'this' alive
if (jq_.addJob(type_, name_, [this, sp = shared_from_this()]() { resume(); })) if (jq_.addJob(type_, name_, [this, sp = shared_from_this()] { resume(); }))
{ {
return true; return true;
} }
@@ -130,7 +130,7 @@ inline void
JobQueue::Coro::join() JobQueue::Coro::join()
{ {
std::unique_lock<std::mutex> lk(mutexRun_); std::unique_lock<std::mutex> lk(mutexRun_);
cv_.wait(lk, [this]() { return !running_; }); cv_.wait(lk, [this] { return !running_; });
} }
} // namespace xrpl } // namespace xrpl
+1 -1
View File
@@ -37,7 +37,7 @@ enum class HashRouterFlags : std::uint16_t {
PRIVATE6 = 0x2000, PRIVATE6 = 0x2000,
// Used in apply.cpp // Used in apply.cpp
PRIVATE7 = 0x4000, PRIVATE7 = 0x4000,
PRIVATE8 = 0x8000 PRIVATE8 = 0x8000,
}; };
constexpr HashRouterFlags constexpr HashRouterFlags
+6 -6
View File
@@ -30,12 +30,12 @@ private:
using namespace std::chrono_literals; using namespace std::chrono_literals;
int const maxLimit = std::numeric_limits<int>::max(); int const maxLimit = std::numeric_limits<int>::max();
auto add = [this]( auto const add = [this](
JobType jt, JobType jt,
std::string name, std::string name,
int limit, int limit,
std::chrono::milliseconds avgLatency, std::chrono::milliseconds avgLatency,
std::chrono::milliseconds peakLatency) { std::chrono::milliseconds peakLatency) {
XRPL_ASSERT(!map.contains(jt), "xrpl::JobTypes::JobTypes::add : unique job type input"); XRPL_ASSERT(!map.contains(jt), "xrpl::JobTypes::JobTypes::add : unique job type input");
[[maybe_unused]] auto const inserted = [[maybe_unused]] auto const inserted =
+4 -3
View File
@@ -177,12 +177,13 @@ measureDurationAndLog(
std::chrono::duration<Rep, Period> maxDelay, std::chrono::duration<Rep, Period> maxDelay,
beast::Journal const& journal) beast::Journal const& journal)
{ {
auto startTime = std::chrono::high_resolution_clock::now(); auto const startTime = std::chrono::high_resolution_clock::now();
auto result = func(); auto result = func();
auto endTime = std::chrono::high_resolution_clock::now(); auto const endTime = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(endTime - startTime); auto const duration =
std::chrono::duration_cast<std::chrono::milliseconds>(endTime - startTime);
if (duration > maxDelay) if (duration > maxDelay)
{ {
JLOG(journal.warn()) << actionDescription << " took " << duration.count() << " ms"; JLOG(journal.warn()) << actionDescription << " took " << duration.count() << " ms";
+1 -1
View File
@@ -95,7 +95,7 @@ private:
ArraySeparator, ArraySeparator,
MemberSeparator, MemberSeparator,
Comment, Comment,
Error Error,
}; };
class Token class Token
+38 -1
View File
@@ -3,11 +3,13 @@
#include <xrpl/basics/Number.h> #include <xrpl/basics/Number.h>
#include <xrpl/json/json_forwards.h> #include <xrpl/json/json_forwards.h>
#include <concepts>
#include <cstring> #include <cstring>
#include <iterator> #include <iterator>
#include <limits> #include <limits>
#include <map> #include <map>
#include <string> #include <string>
#include <string_view>
#include <vector> #include <vector>
/** /**
@@ -26,7 +28,7 @@ enum class ValueType {
String, ///< UTF-8 string value String, ///< UTF-8 string value
Boolean, ///< bool value Boolean, ///< bool value
Array, ///< array value (ordered list) Array, ///< array value (ordered list)
Object ///< object value (collection of name/value pairs). Object, ///< object value (collection of name/value pairs).
}; };
/** /**
@@ -198,6 +200,15 @@ public:
*/ */
Value(StaticString const& value); Value(StaticString const& value);
Value(std::string const& value); Value(std::string const& value);
/**
* @brief Constructs a value from a string view.
*
* The characters are copied, so the view need not outlive the call and need
* not be NUL-terminated.
*
* @param value The characters to copy.
*/
Value(std::string_view value);
Value(bool value); Value(bool value);
Value(Value const& other); Value(Value const& other);
~Value(); ~Value();
@@ -472,6 +483,32 @@ toJson(xrpl::Number const& number)
bool bool
operator==(Value const&, Value const&); operator==(Value const&, Value const&);
/**
* Compares a value with a string view, reading the value's characters in place
* rather than building a Value from the view.
*
* Constrained to the exact type: a string literal converts equally well to a
* view and to a Value, so a plain overload makes `value == "literal"`
* ambiguous.
*
* @param x The value to compare.
* @param y The characters to compare it against.
* @return Whether `x` is a string whose characters up to its first NUL are
* exactly the characters of `y`.
*/
template <class T>
requires std::same_as<T, std::string_view>
bool
operator==(Value const& x, T y)
{
if (!x.isString())
return false;
// A string `Value` can hold a null pointer, which names no characters, so it equals no view.
char const* const s = x.asCString();
return s != nullptr && std::string_view{s} == y;
}
bool bool
operator<(Value const&, Value const&); operator<(Value const&, Value const&);
+1 -1
View File
@@ -165,7 +165,7 @@ public:
beast::Journal j) beast::Journal j)
{ {
// Ask implementation what to do // Ask implementation what to do
auto actions = doVoting( auto const actions = doVoting(
lastClosedLedger->rules(), lastClosedLedger->rules(),
lastClosedLedger->parentCloseTime(), lastClosedLedger->parentCloseTime(),
getEnabledAmendments(*lastClosedLedger), getEnabledAmendments(*lastClosedLedger),
+1 -1
View File
@@ -50,7 +50,7 @@ enum ApplyFlags : std::uint32_t {
// afterward, so signature-presence checks (e.g. Batch signer matching) // afterward, so signature-presence checks (e.g. Batch signer matching)
// are skipped at proposal-creation time (On-Chain Cosigner spec // are skipped at proposal-creation time (On-Chain Cosigner spec
// §5.3.1.2). // §5.3.1.2).
TapProposal = 0x2000 TapProposal = 0x2000,
}; };
constexpr ApplyFlags constexpr ApplyFlags
+2 -1
View File
@@ -20,7 +20,8 @@ constexpr std::chrono::seconds kLedgerPossibleTimeResolutions[] = {
std::chrono::seconds{30}, std::chrono::seconds{30},
std::chrono::seconds{60}, std::chrono::seconds{60},
std::chrono::seconds{90}, std::chrono::seconds{90},
std::chrono::seconds{120}}; std::chrono::seconds{120},
};
/** /**
* Initial resolution of ledger close time. * Initial resolution of ledger close time.
+2 -2
View File
@@ -35,7 +35,7 @@ public:
{ {
std::scoped_lock const lock(mutex_); std::scoped_lock const lock(mutex_);
auto it = map_.find(seq); auto const it = map_.find(seq);
if ((it == map_.end()) || it->second) if ((it == map_.end()) || it->second)
{ {
@@ -88,7 +88,7 @@ public:
std::unique_lock<std::mutex> lock(mutex_); std::unique_lock<std::mutex> lock(mutex_);
do do
{ {
auto it = map_.find(seq); auto const it = map_.find(seq);
if (it == map_.end()) if (it == map_.end())
{ {
+4 -5
View File
@@ -5,7 +5,6 @@
#include <xrpl/beast/utility/Journal.h> #include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h> #include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h> #include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/AccountRootEntry.h>
#include <xrpl/protocol/AccountID.h> #include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Asset.h> #include <xrpl/protocol/Asset.h>
#include <xrpl/protocol/Keylet.h> #include <xrpl/protocol/Keylet.h>
@@ -165,7 +164,7 @@ getCandidateLedger(LedgerIndex requested)
areCompatible( areCompatible(
ReadView const& validLedger, ReadView const& validLedger,
ReadView const& testLedger, ReadView const& testLedger,
beast::Journal::Stream& s, beast::Journal::Stream const& s,
char const* reason); char const* reason);
[[nodiscard]] bool [[nodiscard]] bool
@@ -173,7 +172,7 @@ areCompatible(
UInt256 const& validHash, UInt256 const& validHash,
LedgerIndex validIndex, LedgerIndex validIndex,
ReadView const& testLedger, ReadView const& testLedger,
beast::Journal::Stream& s, beast::Journal::Stream const& s,
char const* reason); char const* reason);
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@@ -186,7 +185,7 @@ areCompatible(
dirLink( dirLink(
ApplyView& view, ApplyView& view,
AccountID const& owner, AccountID const& owner,
SLE::pointer& object, SLE::pointer const& object,
SF_UINT64 const& node = sfOwnerNode); SF_UINT64 const& node = sfOwnerNode);
/** /**
@@ -212,7 +211,7 @@ canWithdraw(
ReadView const& view, ReadView const& view,
AccountID const& from, AccountID const& from,
AccountID const& to, AccountID const& to,
AccountRootEntryR const& toSle, SLE::ConstRef toSle,
STAmount const& amount, STAmount const& amount,
bool hasDestinationTag, bool hasDestinationTag,
std::optional<std::vector<UInt256>> const& credentialIDs = std::nullopt); std::optional<std::vector<UInt256>> const& credentialIDs = std::nullopt);
+8 -4
View File
@@ -30,13 +30,17 @@ public:
static constexpr size_t kInitialBufferSize = kilobytes(256); static constexpr size_t kInitialBufferSize = kilobytes(256);
RawStateTable() RawStateTable()
: monotonicResource_{std::make_unique<boost::container::pmr::monotonic_buffer_resource>( : monotonicResource_{
kInitialBufferSize)} std::make_unique<boost::container::pmr::monotonic_buffer_resource>(
kInitialBufferSize),
}
, items_{monotonicResource_.get()} {}; , items_{monotonicResource_.get()} {};
RawStateTable(RawStateTable const& rhs) RawStateTable(RawStateTable const& rhs)
: monotonicResource_{std::make_unique<boost::container::pmr::monotonic_buffer_resource>( : monotonicResource_{
kInitialBufferSize)} std::make_unique<boost::container::pmr::monotonic_buffer_resource>(
kInitialBufferSize),
}
, items_{rhs.items_, monotonicResource_.get()} , items_{rhs.items_, monotonicResource_.get()}
, dropsDestroyed_{rhs.dropsDestroyed_} {}; , dropsDestroyed_{rhs.dropsDestroyed_} {};
@@ -7,20 +7,9 @@
#include <xrpl/protocol/AccountID.h> #include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Indexes.h> #include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h> #include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/TER.h>
#include <xrpl/protocol/XRPAmount.h>
#include <cstdint>
#include <optional>
namespace xrpl { namespace xrpl {
struct Adjustment
{
std::int32_t ownerCountDelta = 0;
std::int32_t accountCountDelta = 0;
};
template <typename ViewT> template <typename ViewT>
class AccountRootEntry : public SLEBase<ViewT, ltACCOUNT_ROOT> class AccountRootEntry : public SLEBase<ViewT, ltACCOUNT_ROOT>
{ {
@@ -38,123 +27,6 @@ public:
: Base(keylet::account(id), view, j) : Base(keylet::account(id), view, j)
{ {
} }
/**
* Returns the account reserve, in drops.
*
* Actual owner count can be adjusted by delta in ownerCountAdj
* Actual reserve count can be adjusted by delta in accountCountAdj
* The reserve is calculated as:
* (ownerCount + "sponsoring object count" - "sponsored object count" + additionalOwnerCount) *
* increment + (1 if not sponsored account + sponsoringAccountCount) * "reserve base"
*
* @param adj Adjustment to the owner/account count (default: 0/0). Positive to add, negative
* to subtract.
* @return The account reserve amount in drops
*/
[[nodiscard]] XRPAmount
reserve(Adjustment adj = {}) const;
/**
* Return number of the objects which reserve is covered by the account (so called "owner
* count"). Actual owner count can be adjusted by delta in ownerCountAdj.
*
* @param ownerCountAdj Adjustment to the owner count (default: 0)
* @return The adjusted owner count
*/
[[nodiscard]] std::uint32_t
ownerCount(std::int32_t ownerCountAdj = 0) const;
/**
* Check if this account has sufficient reserve.
*
* @param ctx The apply-view context (view + tx)
* @param accBalance The account's balance
* @param sponsorSle The sponsor's ledger entry (if applicable)
* @param adj Adjustment to the owner/account count (default: 0/0). Positive to add, negative
* to subtract.
* @param insufReserveCode The transaction result code to return if the reserve is
* insufficient (default: tecINSUFFICIENT_RESERVE).
* @return Transaction result code
*/
[[nodiscard]] TER
checkReserve(
ApplyViewContext ctx,
XRPAmount accBalance,
std::optional<AccountRootEntry<ReadView>> const& sponsorSle,
Adjustment adj,
TER insufReserveCode = tecINSUFFICIENT_RESERVE) const;
/**
* Check if this account has sufficient reserve, deriving the sponsor internally.
*
* Equivalent to the overload above, but resolves the sponsor via
* getEffectiveTxReserveSponsor(ctx, *this) instead of taking it explicitly. Use this
* in the common case where the sponsor is simply the transaction's reserve
* sponsor for this account. Callers that must force the account's-own-reserve branch
* (passing a null sponsor) or supply a different sponsor should use the
* explicit overload above.
*
* @param ctx The apply-view context (view + tx)
* @param accBalance The account's balance
* @param adj Reserve adjustments (owner/account count deltas)
* @return Transaction result code
*/
[[nodiscard]] TER
checkReserve(ApplyViewContext ctx, XRPAmount accBalance, Adjustment adj) const;
/**
* Increase owner-count fields when the caller supplies the sponsor.
*
* This helper does not create a ledger object. It updates reserve accounting
* after the caller has created/updated an object.
* If sponsorSle is provided, this also adjusts the account's sponsored count
* and the sponsor's sponsoring count.
*
* @param sponsorSle The sponsor's ledger entry (if applicable)
* @param count Amount to add to the owner count
*/
void
increaseOwnerCount(std::optional<AccountRootEntry<ApplyView>>& sponsorSle, std::uint32_t count)
requires Base::kIsWritable;
/**
* Increase owner-count fields, deriving the tx reserve sponsor internally.
*
* Equivalent to the overload above, but resolves the sponsor via
* getEffectiveTxReserveSponsor(ctx, *this) instead of taking it explicitly. Use
* this when the sponsor is the transaction's reserve sponsor for this account
* (the common create path). Deletion paths, which derive the sponsor from an
* object's sfSponsor field, should keep using the explicit overload.
*
* @param ctx The apply-view context (view + tx)
* @param count Amount to add to the owner count
*/
void
increaseOwnerCount(ApplyViewContext ctx, std::uint32_t count)
requires Base::kIsWritable;
/**
* Decrease owner-count fields when the caller supplies the sponsor.
*
* This helper does not delete a ledger object. It updates reserve accounting
* after the caller has removed an owner-counted reserve, or for special
* owner-count changes whose sponsor cannot be derived from an object's
* sfSponsor field.
*
* @param sponsorSle The sponsor's ledger entry (if applicable)
* @param count Amount to remove from the owner count
*/
void
decreaseOwnerCount(std::optional<AccountRootEntry<ApplyView>>& sponsorSle, std::uint32_t count)
requires Base::kIsWritable;
private:
void
adjustOwnerCountSigned(
std::optional<AccountRootEntry<ApplyView>>& sponsorSle,
std::int32_t adjustment)
requires Base::kIsWritable;
}; };
using AccountRootEntryR = AccountRootEntry<ReadView>; using AccountRootEntryR = AccountRootEntry<ReadView>;
@@ -1,11 +1,17 @@
#pragma once #pragma once
#include <xrpl/basics/base_uint.h>
#include <xrpl/basics/chrono.h>
#include <xrpl/beast/utility/Journal.h> #include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h> #include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h> #include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/SLEBase.h> #include <xrpl/ledger/entries/SLEBase.h>
#include <xrpl/protocol/Indexes.h> #include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h> #include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/SField.h>
#include <map>
#include <set>
namespace xrpl { namespace xrpl {
@@ -25,6 +31,52 @@ public:
: Base(keylet::amendments(), view, j) : Base(keylet::amendments(), view, j)
{ {
} }
/**
* Returns the set of amendments this entry reports as enabled.
*
* @return the set of enabled amendments.
*/
[[nodiscard]] std::set<UInt256>
enabledAmendments() const
{
std::set<UInt256> amendments;
if (this->exists() && (*this)->isFieldPresent(sfAmendments))
{
auto const& v = (*this)->getFieldV256(sfAmendments);
amendments.insert_range(v);
}
return amendments;
}
/**
* Returns a map of amendments that have achieved majority, to the time
* majority was reached.
*
* @return a map of amendment to the time majority was reached.
*/
[[nodiscard]] std::map<UInt256, NetClock::time_point>
majorityAmendments() const
{
std::map<UInt256, NetClock::time_point> ret;
if (this->exists() && (*this)->isFieldPresent(sfMajorities))
{
using TimePoint = NetClock::time_point;
using Duration = TimePoint::duration;
auto const majorities = (*this)->getFieldArray(sfMajorities);
for (auto const& m : majorities)
{
ret[m.getFieldH256(sfAmendment)] = TimePoint(Duration(m.getFieldU32(sfCloseTime)));
}
}
return ret;
}
}; };
using AmendmentsEntryR = AmendmentsEntry<ReadView>; using AmendmentsEntryR = AmendmentsEntry<ReadView>;
@@ -1,11 +1,17 @@
#pragma once #pragma once
#include <xrpl/basics/base_uint.h>
#include <xrpl/beast/utility/Journal.h> #include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h> #include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h> #include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/SLEBase.h> #include <xrpl/ledger/entries/SLEBase.h>
#include <xrpl/protocol/Indexes.h> #include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h> #include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/STVector256.h>
#include <cstddef>
#include <optional>
namespace xrpl { namespace xrpl {
@@ -25,6 +31,31 @@ public:
: Base(keylet::skip(), view, j) : Base(keylet::skip(), view, j)
{ {
} }
/**
* Looks up a hash `diff` slots back from the most recent entry in the
* sfHashes vector (diff == 0 is the most recent entry).
*
* Callers decide which skip list entry to read and how to translate a
* target ledger sequence into `diff`; this only does the bounds check
* and vector indexing shared by both the recent (stride 1) and distant
* (stride 256) skip lists.
*
* @param diff how many slots back from the most recent hash to look up;
* 0 is the most recent hash.
* @return the hash at that slot, or std::nullopt if the entry does not
* exist or `diff` is out of range.
*/
[[nodiscard]] std::optional<UInt256>
hashAt(std::size_t diff) const
{
if (!this->exists())
return std::nullopt;
STVector256 const vec = (*this)->getFieldV256(sfHashes);
if (vec.size() > diff)
return vec[vec.size() - diff - 1];
return std::nullopt;
}
}; };
using LedgerHashesEntryR = LedgerHashesEntry<ReadView>; using LedgerHashesEntryR = LedgerHashesEntry<ReadView>;
+15 -17
View File
@@ -224,7 +224,7 @@ getAMMOfferStartWithTakerGets(
if (nTakerGetsConstraint < *nTakerGets) if (nTakerGetsConstraint < *nTakerGets)
nTakerGets = nTakerGetsConstraint; nTakerGets = nTakerGetsConstraint;
auto getAmounts = [&pool, &tfee](Number const& nTakerGetsProposed) { auto const getAmounts = [&pool, &tfee](Number const& nTakerGetsProposed) {
// Round downward to minimize the offer and to maximize the quality. // Round downward to minimize the offer and to maximize the quality.
// This has the most impact when takerGets is integral. // This has the most impact when takerGets is integral.
auto const takerGets = auto const takerGets =
@@ -292,7 +292,7 @@ getAMMOfferStartWithTakerPays(
if (nTakerPaysConstraint < *nTakerPays) if (nTakerPaysConstraint < *nTakerPays)
nTakerPays = nTakerPaysConstraint; nTakerPays = nTakerPaysConstraint;
auto getAmounts = [&pool, &tfee](Number const& nTakerPaysProposed) { auto const getAmounts = [&pool, &tfee](Number const& nTakerPaysProposed) {
// Round downward to minimize the offer and to maximize the quality. // Round downward to minimize the offer and to maximize the quality.
// This has the most impact when takerPays is integral. // This has the most impact when takerPays is integral.
auto const takerPays = auto const takerPays =
@@ -353,7 +353,7 @@ changeSpotPriceQuality(
} }
if (auto const nTakerPaysPropose = (-b + root2(res)) / (2 * a); nTakerPaysPropose > 0) if (auto const nTakerPaysPropose = (-b + root2(res)) / (2 * a); nTakerPaysPropose > 0)
{ {
auto const nTakerPays = [&]() { auto const nTakerPays = [&] {
// The fee might make the AMM offer quality less than CLOB // The fee might make the AMM offer quality less than CLOB
// quality. Therefore, AMM offer has to satisfy this constraint: // quality. Therefore, AMM offer has to satisfy this constraint:
// o / i >= q. Substituting o with swapAssetIn() gives: i <= O / // o / i >= q. Substituting o with swapAssetIn() gives: i <= O /
@@ -372,8 +372,8 @@ changeSpotPriceQuality(
auto const takerPays = auto const takerPays =
toAmount<TIn>(getAsset(pool.in), nTakerPays, Number::RoundingMode::Upward); toAmount<TIn>(getAsset(pool.in), nTakerPays, Number::RoundingMode::Upward);
// should not fail // should not fail
if (auto amounts = TAmounts<TIn, TOut>{takerPays, swapAssetIn(pool, takerPays, tfee)}; auto amounts = TAmounts<TIn, TOut>{takerPays, swapAssetIn(pool, takerPays, tfee)};
Quality{amounts} < quality && if (Quality{amounts} < quality &&
!withinRelativeDistance(Quality{amounts}, quality, Number(1, -7))) !withinRelativeDistance(Quality{amounts}, quality, Number(1, -7)))
{ {
JLOG(j.error()) << "changeSpotPriceQuality failed: " << to_string(pool.in) << " " JLOG(j.error()) << "changeSpotPriceQuality failed: " << to_string(pool.in) << " "
@@ -382,21 +382,19 @@ changeSpotPriceQuality(
<< " " << to_string(amounts.out); << " " << to_string(amounts.out);
Throw<std::runtime_error>("changeSpotPriceQuality failed"); Throw<std::runtime_error>("changeSpotPriceQuality failed");
} }
else
{ JLOG(j.trace()) << "changeSpotPriceQuality succeeded: " << to_string(pool.in) << " "
JLOG(j.trace()) << "changeSpotPriceQuality succeeded: " << to_string(pool.in) << " " << to_string(pool.out) << " "
<< to_string(pool.out) << " " << " " << quality << " " << tfee << " " << to_string(amounts.in) << " "
<< " " << quality << " " << tfee << " " << to_string(amounts.in) << to_string(amounts.out);
<< " " << to_string(amounts.out); return amounts;
return amounts;
}
} }
JLOG(j.trace()) << "changeSpotPriceQuality calc failed: " << to_string(pool.in) << " " JLOG(j.trace()) << "changeSpotPriceQuality calc failed: " << to_string(pool.in) << " "
<< to_string(pool.out) << " " << quality << " " << tfee; << to_string(pool.out) << " " << quality << " " << tfee;
return std::nullopt; return std::nullopt;
} }
auto amounts = [&]() { auto amounts = [&] {
bool const inIntegral = getAsset(pool.in).integral(); bool const inIntegral = getAsset(pool.in).integral();
bool const outIntegral = getAsset(pool.out).integral(); bool const outIntegral = getAsset(pool.out).integral();
@@ -872,8 +870,8 @@ deleteAMMAccount(Sandbox& view, Asset const& asset, Asset const& asset2, beast::
*/ */
void void
initializeFeeAuctionVote( initializeFeeAuctionVote(
ApplyView& view, ApplyView const& view,
SLE::pointer& ammSle, SLE::pointer const& ammSle,
AccountID const& account, AccountID const& account,
Asset const& lptAsset, Asset const& lptAsset,
std::uint16_t tfee); std::uint16_t tfee);
@@ -895,7 +893,7 @@ std::expected<bool, TER>
verifyAndAdjustLPTokenBalance( verifyAndAdjustLPTokenBalance(
Sandbox& sb, Sandbox& sb,
STAmount const& lpTokens, STAmount const& lpTokens,
SLE::pointer& ammSle, SLE::pointer const& ammSle,
AccountID const& account); AccountID const& account);
} // namespace xrpl } // namespace xrpl
+164 -60
View File
@@ -4,8 +4,8 @@
#include <xrpl/beast/utility/Journal.h> #include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h> #include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h> #include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/AccountRootEntry.h>
#include <xrpl/protocol/AccountID.h> #include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/Rate.h> #include <xrpl/protocol/Rate.h>
#include <xrpl/protocol/SField.h> #include <xrpl/protocol/SField.h>
#include <xrpl/protocol/STLedgerEntry.h> #include <xrpl/protocol/STLedgerEntry.h>
@@ -46,55 +46,30 @@ isGlobalFrozen(ReadView const& view, AccountID const& issuer);
[[nodiscard]] XRPAmount [[nodiscard]] XRPAmount
xrpLiquid(ReadView const& view, AccountID const& id, std::int32_t ownerCountAdj, beast::Journal j); xrpLiquid(ReadView const& view, AccountID const& id, std::int32_t ownerCountAdj, beast::Journal j);
namespace detail { struct Adjustment
{
std::int32_t ownerCountDelta = 0;
std::int32_t accountCountDelta = 0;
};
/** /**
* An owner count cannot be negative. If adjustment would cause a negative * Returns the account reserve, in drops.
* owner count, clamp the owner count at 0. Similarly for overflow. This
* adjustment allows the ownerCount to be adjusted up or down in multiple steps.
* If id != std::nullopt, then do error reporting.
* *
* Shared by AccountRootEntry::ownerCount() and the owner-count helpers. * Actual owner count can be adjusted by delta in ownerCountAdj
* Actual reserve count can be adjusted by delta in accountCountAdj
* The reserve is calculated as:
* (ownerCount + "sponsoring object count" - "sponsored object count" + additionalOwnerCount) *
* increment + (1 if not sponsored account + sponsoringAccountCount) * "reserve base"
* *
* @param currentOwnerCount The owner count before adjustment * @param view The ledger view to read from
* @param ownerCountAdj Positive to add to count, negative to reduce count * @param sle The ledger entry for the account
* @param id The account ID to use for error reporting, or std::nullopt to
* skip error reporting
* @param j Journal for logging * @param j Journal for logging
* @return The adjusted owner count * @param adj Adjustment to the owner/account count (default: 0/0). Positive to add, negative to
* subtract.
* @return The account reserve amount in drops
*/ */
std::uint32_t [[nodiscard]] XRPAmount
confineOwnerCount( accountReserve(ReadView const& view, SLE::ConstRef sle, beast::Journal j, Adjustment adj = {});
std::uint32_t currentOwnerCount,
std::int32_t ownerCountAdj,
std::optional<AccountID> const& id = std::nullopt,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()});
/**
* Clamps and writes an owner-count field of sle, then updates sle in view.
*
* Shared by AccountRootEntry and adjustLoanBrokerOwnerCount().
*
* @return The adjusted owner count
*/
std::uint32_t
adjustOwnerCountImpl(
ApplyView& view,
SLE::Ref sle,
SF_UINT32 const& sfield,
AccountID const& accID,
std::int32_t ownerCountAdj,
beast::Journal j);
/**
* Returns the number of account reserves funded by this account: 1 for itself
* (0 if sponsored by another account) plus the count of accounts it sponsors.
* Shared by AccountRootEntry::reserve() and xrpLiquid().
*/
std::uint32_t
accountCountImpl(AccountRootEntryR const& sle, std::int32_t accountCountAdj, beast::Journal j);
} // namespace detail
/** /**
* Convenience overload that accepts AccountID instead of SLE. * Convenience overload that accepts AccountID instead of SLE.
@@ -109,9 +84,114 @@ accountCountImpl(AccountRootEntryR const& sle, std::int32_t accountCountAdj, bea
[[nodiscard]] inline XRPAmount [[nodiscard]] inline XRPAmount
accountReserve(ReadView const& view, AccountID const& id, beast::Journal j, Adjustment adj = {}) accountReserve(ReadView const& view, AccountID const& id, beast::Journal j, Adjustment adj = {})
{ {
return AccountRootEntryR(id, view, j).reserve(adj); return accountReserve(view, view.read(keylet::account(id)), j, adj);
} }
/**
* Check if an account has sufficient reserve.
*
* @param view The ledger view to read from
* @param tx The transaction being processed
* @param accSle The account's ledger entry
* @param accBalance The account's balance
* @param sponsorSle The sponsor's ledger entry (if applicable)
* @param adj Adjustment to the owner/account count (default: 0/0). Positive to add, negative to
* subtract.
* @param j Journal for logging (default: null sink)
* @param insufReserveCode The transaction result code to return if the reserve is insufficient
* (default: tecINSUFFICIENT_RESERVE).
* @return Transaction result code
*/
[[nodiscard]] TER
checkReserve(
ApplyViewContext ctx,
SLE::ConstRef accSle,
XRPAmount accBalance,
SLE::ConstRef sponsorSle,
Adjustment adj,
beast::Journal j,
TER insufReserveCode = tecINSUFFICIENT_RESERVE);
/**
* Check if an account has sufficient reserve, deriving the sponsor internally.
*
* Equivalent to the overload above, but resolves the sponsor via
* getEffectiveTxReserveSponsor(ctx, accSle) instead of taking it explicitly. Use this
* in the common case where the sponsor is simply the transaction's reserve
* sponsor for accSle. Callers that must force the account's-own-reserve branch
* (passing a null sponsor) or supply a different sponsor should use the
* explicit overload above.
*
* @param ctx The apply-view context (view + tx)
* @param accSle The account's ledger entry
* @param accBalance The account's balance
* @param adj Reserve adjustments (owner/account count deltas)
* @param j Journal for logging (default: null sink)
* @return Transaction result code
*/
[[nodiscard]] TER
checkReserve(
ApplyViewContext ctx,
SLE::ConstRef accSle,
XRPAmount accBalance,
Adjustment adj,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()});
/**
* Return number of the objects which reserve is covered by the account(sle) (so called "owner
* count"). Actual owner count can be adjusted by delta in ownerCountAdj.
*
* @param sle The account's ledger entry
* @param j Journal for logging
* @param ownerCountAdj Adjustment to the owner count (default: 0)
* @return The adjusted owner count
*/
std::uint32_t
ownerCount(SLE::ConstRef sle, beast::Journal j, std::int32_t ownerCountAdj = 0);
/**
* Increase owner-count fields when the caller supplies the sponsor.
*
* This helper does not create a ledger object. It updates reserve accounting
* after the caller has created/updated an object.
* If sponsorSle is provided, this also adjusts the account's sponsored count
* and the sponsor's sponsoring count.
*
* @param view The apply view for making changes
* @param accountSle The account's ledger entry
* @param sponsorSle The sponsor's ledger entry (if applicable)
* @param count Amount to add to the owner count
* @param j Journal for logging
*/
void
increaseOwnerCount(
ApplyView& view,
SLE::Ref accountSle,
SLE::Ref sponsorSle,
std::uint32_t count,
beast::Journal j);
/**
* Increase owner-count fields, deriving the tx reserve sponsor internally.
*
* Equivalent to the overload above, but resolves the sponsor via
* getEffectiveTxReserveSponsor(ctx, accountSle) instead of taking it explicitly. Use
* this when the sponsor is the transaction's reserve sponsor for accountSle
* (the common create path). Deletion paths, which derive the sponsor from an
* object's sfSponsor field, should keep using the explicit overload.
*
* @param ctx The apply-view context (view + tx)
* @param accountSle The account's ledger entry
* @param count Amount to add to the owner count
* @param j Journal for logging
*/
void
increaseOwnerCount(
ApplyViewContext ctx,
SLE::Ref accountSle,
std::uint32_t count,
beast::Journal j);
/** /**
* Convenience overload that accepts AccountID instead of SLE references. * Convenience overload that accepts AccountID instead of SLE references.
* *
@@ -129,13 +209,36 @@ increaseOwnerCount(
std::uint32_t count, std::uint32_t count,
beast::Journal j) beast::Journal j)
{ {
AccountRootEntryW accountSle(account, view, j); increaseOwnerCount(
std::optional<AccountRootEntryW> sponsorSle; view,
if (sponsor) view.peek(keylet::account(account)),
sponsorSle.emplace(*sponsor, view); sponsor ? view.peek(keylet::account(*sponsor)) : SLE::pointer(),
accountSle.increaseOwnerCount(sponsorSle, count); count,
j);
} }
/**
* Decrease owner-count fields when the caller supplies the sponsor.
*
* This helper does not delete a ledger object. It updates reserve accounting
* after the caller has removed an owner-counted reserve, or for special
* owner-count changes whose sponsor cannot be derived from an object's
* sfSponsor field.
*
* @param view The apply view for making changes
* @param accountSle The account's ledger entry
* @param sponsorSle The sponsor's ledger entry (if applicable)
* @param count Amount to remove from the owner count
* @param j Journal for logging
*/
void
decreaseOwnerCount(
ApplyView& view,
SLE::Ref accountSle,
SLE::Ref sponsorSle,
std::uint32_t count,
beast::Journal j);
/** /**
* Convenience overload that accepts AccountID instead of SLE references. * Convenience overload that accepts AccountID instead of SLE references.
* *
@@ -153,11 +256,12 @@ decreaseOwnerCount(
std::uint32_t count, std::uint32_t count,
beast::Journal j) beast::Journal j)
{ {
AccountRootEntryW accountSle(account, view, j); decreaseOwnerCount(
std::optional<AccountRootEntryW> sponsorSle; view,
if (sponsor) view.peek(keylet::account(account)),
sponsorSle.emplace(*sponsor, view); sponsor ? view.peek(keylet::account(*sponsor)) : SLE::pointer(),
accountSle.decreaseOwnerCount(sponsorSle, count); count,
j);
} }
/** /**
@@ -177,7 +281,7 @@ decreaseOwnerCount(
void void
decreaseOwnerCountForObject( decreaseOwnerCountForObject(
ApplyView& view, ApplyView& view,
AccountRootEntryW& accountSle, SLE::Ref accountSle,
SLE::Ref objectSle, SLE::Ref objectSle,
std::uint32_t count, std::uint32_t count,
beast::Journal j); beast::Journal j);
@@ -199,7 +303,7 @@ decreaseOwnerCountForObject(
std::uint32_t count, std::uint32_t count,
beast::Journal j) beast::Journal j)
{ {
AccountRootEntryW accountSle(account, view); SLE::Ref accountSle = view.peek(keylet::account(account));
decreaseOwnerCountForObject(view, accountSle, objectSle, count, j); decreaseOwnerCountForObject(view, accountSle, objectSle, count, j);
} }
@@ -263,7 +367,7 @@ getPseudoAccountFields();
* - null pointer * - null pointer
*/ */
[[nodiscard]] bool [[nodiscard]] bool
isPseudoAccount(AccountRootEntryR const& sleAcct); isPseudoAccount(SLE::const_pointer sleAcct);
/** /**
* Convenience overload that reads the account from the view. * Convenience overload that reads the account from the view.
@@ -271,7 +375,7 @@ isPseudoAccount(AccountRootEntryR const& sleAcct);
[[nodiscard]] inline bool [[nodiscard]] inline bool
isPseudoAccount(ReadView const& view, AccountID const& accountId) isPseudoAccount(ReadView const& view, AccountID const& accountId)
{ {
return isPseudoAccount(AccountRootEntryR(accountId, view)); return isPseudoAccount(view.read(keylet::account(accountId)));
} }
/** /**
@@ -292,6 +396,6 @@ createPseudoAccount(ApplyView& view, UInt256 const& pseudoOwnerKey, SField const
* - If the SLE requires a destination tag, checks that there is a tag. * - If the SLE requires a destination tag, checks that there is a tag.
*/ */
[[nodiscard]] TER [[nodiscard]] TER
checkDestinationAndTag(AccountRootEntryR const& toSle, bool hasDestinationTag); checkDestinationAndTag(SLE::ConstRef toSle, bool hasDestinationTag);
} // namespace xrpl } // namespace xrpl
+314 -57
View File
@@ -2,9 +2,11 @@
#include <xrpl/basics/Log.h> #include <xrpl/basics/Log.h>
#include <xrpl/beast/utility/Journal.h> #include <xrpl/beast/utility/Journal.h>
#include <xrpl/beast/utility/Zero.h>
#include <xrpl/beast/utility/instrumentation.h> #include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/ledger/ApplyView.h> #include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/entries/AccountRootEntry.h> #include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/MPTokenHelpers.h> #include <xrpl/ledger/helpers/MPTokenHelpers.h>
#include <xrpl/ledger/helpers/RippleStateHelpers.h> #include <xrpl/ledger/helpers/RippleStateHelpers.h>
#include <xrpl/ledger/helpers/SponsorHelpers.h> #include <xrpl/ledger/helpers/SponsorHelpers.h>
@@ -27,31 +29,290 @@
namespace xrpl { namespace xrpl {
namespace detail {
/** /**
* Before fixCleanup3_2_0, EscrowCancel passes the escrow SLE as sleDest. * Validate that @p account may lock @p amount of a token for later delivery
* Return what the old reserve check returned for it, without adopting a * to @p dest.
* non-AccountRoot SLE into an AccountRootEntry: the tx reserve sponsor's
* error if the escrow owner submitted the tx, else tefINTERNAL.
* *
* @param ctx the apply view context for the escrow transaction. * The lock-side counterpart of escrowUnlockPreclaimHelper: every issuer
* @param sleDest the non-AccountRoot SLE that was passed as the destination. * control (locking opt-in, authorization, freeze/lock, transferability,
* @return the tx reserve sponsor's error code if the escrow owner submitted * spendable balance) that gates locking token value lives here, so any
* the tx, else tefINTERNAL. * transactor that locks funds applies the same rules. The signature is
* view-based rather than PreclaimContext-based so it can also run from
* doApply.
*/ */
template <ValidIssueType T>
TER
escrowLockPreclaimHelper(
ReadView const& view,
AccountID const& account,
AccountID const& dest,
STAmount const& amount,
beast::Journal j);
template <>
inline TER inline TER
escrowDestNotAccountResult(ApplyViewContext ctx, SLE::ConstRef sleDest) escrowLockPreclaimHelper<Issue>(
ReadView const& view,
AccountID const& account,
AccountID const& dest,
STAmount const& amount,
beast::Journal j)
{ {
if (sleDest->getAccountID(sfAccount) == ctx.tx[sfAccount]) auto const& issue = amount.get<Issue>();
{ auto const& issuer = amount.getIssuer();
if (auto const sponsor = getTxReserveSponsor(ctx); !sponsor) // If the issuer is the same as the account, return tecNO_PERMISSION
return sponsor.error(); // LCOV_EXCL_LINE if (issuer == account)
} return tecNO_PERMISSION;
return tefINTERNAL;
// If the lsfAllowTrustLineLocking is not enabled, return tecNO_PERMISSION
auto const sleIssuer = view.read(keylet::account(issuer));
if (!sleIssuer)
return tecNO_ISSUER;
if (!sleIssuer->isFlag(lsfAllowTrustLineLocking))
return tecNO_PERMISSION;
// If the account does not have a trustline to the issuer, return tecNO_LINE
auto const sleRippleState = view.read(keylet::trustLine(account, issuer, issue.currency));
if (!sleRippleState)
return tecNO_LINE;
STAmount const balance = (*sleRippleState)[sfBalance];
// If balance is positive, issuer must have higher address than account
if (balance > beast::kZero && issuer < account)
return tecNO_PERMISSION; // LCOV_EXCL_LINE
// If balance is negative, issuer must have lower address than account
if (balance < beast::kZero && issuer > account)
return tecNO_PERMISSION; // LCOV_EXCL_LINE
// If the issuer has requireAuth set, check if the account is authorized
if (auto const ter = requireAuth(view, issue, account); !isTesSuccess(ter))
return ter;
// If the issuer has requireAuth set, check if the destination is authorized
if (auto const ter = requireAuth(view, issue, dest); !isTesSuccess(ter))
return ter;
// If the issuer has frozen the account, return tecFROZEN
if (isFrozen(view, account, issue))
return tecFROZEN;
// If the issuer has frozen the destination, return tecFROZEN
if (isFrozen(view, dest, issue))
return tecFROZEN;
STAmount const spendableAmount =
accountHolds(view, account, issue.currency, issuer, FreezeHandling::IgnoreFreeze, j);
// If the balance is less than or equal to 0, return tecINSUFFICIENT_FUNDS
if (spendableAmount <= beast::kZero)
return tecINSUFFICIENT_FUNDS;
// If the spendable amount is less than the amount, return
// tecINSUFFICIENT_FUNDS
if (spendableAmount < amount)
return tecINSUFFICIENT_FUNDS;
// If the amount is not addable to the balance, return tecPRECISION_LOSS
if (!canAdd(spendableAmount, amount))
return tecPRECISION_LOSS;
return tesSUCCESS;
} }
} // namespace detail template <>
inline TER
escrowLockPreclaimHelper<MPTIssue>(
ReadView const& view,
AccountID const& account,
AccountID const& dest,
STAmount const& amount,
beast::Journal j)
{
AccountID const issuer = amount.getIssuer();
// If the issuer is the same as the account, return tecNO_PERMISSION
if (issuer == account)
return tecNO_PERMISSION;
// If the mpt does not exist, return tecOBJECT_NOT_FOUND
auto const issuanceKey = keylet::mptokenIssuance(amount.get<MPTIssue>().getMptID());
auto const sleIssuance = view.read(issuanceKey);
if (!sleIssuance)
return tecOBJECT_NOT_FOUND;
// If the lsfMPTCanEscrow is not enabled, return tecNO_PERMISSION
if (!sleIssuance->isFlag(lsfMPTCanEscrow))
return tecNO_PERMISSION;
// If the issuer is not the same as the issuer of the mpt, return
// tecNO_PERMISSION
if (sleIssuance->getAccountID(sfIssuer) != issuer)
return tecNO_PERMISSION; // LCOV_EXCL_LINE
// If the account does not have the mpt, return tecOBJECT_NOT_FOUND
if (!view.exists(keylet::mptoken(issuanceKey.key, account)))
return tecOBJECT_NOT_FOUND;
// If the issuer has requireAuth set, check if the account is
// authorized
auto const& mptIssue = amount.get<MPTIssue>();
if (auto const ter = requireAuth(view, mptIssue, account, AuthType::WeakAuth);
!isTesSuccess(ter))
return ter;
// If the issuer has requireAuth set, check if the destination is
// authorized
if (auto const ter = requireAuth(view, mptIssue, dest, AuthType::WeakAuth); !isTesSuccess(ter))
return ter;
// If the issuer has frozen the account, return tecLOCKED
if (isFrozen(view, account, *sleIssuance))
return tecLOCKED;
// If the issuer has frozen the destination, return tecLOCKED
if (isFrozen(view, dest, *sleIssuance))
return tecLOCKED;
// If the mpt cannot be transferred, return tecNO_AUTH
if (auto const ter = canTransfer(view, mptIssue, account, dest); !isTesSuccess(ter))
return ter;
STAmount const spendableAmount = accountHolds(
view,
account,
amount.get<MPTIssue>(),
FreezeHandling::IgnoreFreeze,
AuthHandling::IgnoreAuth,
j);
// If the balance is less than or equal to 0, return tecINSUFFICIENT_FUNDS
if (spendableAmount <= beast::kZero)
return tecINSUFFICIENT_FUNDS;
// If the spendable amount is less than the amount, return
// tecINSUFFICIENT_FUNDS
if (spendableAmount < amount)
return tecINSUFFICIENT_FUNDS;
return tesSUCCESS;
}
template <ValidIssueType T>
TER
escrowLockApplyHelper(
ApplyView& view,
AccountID const& issuer,
AccountID const& sender,
STAmount const& amount,
beast::Journal journal);
template <>
inline TER
escrowLockApplyHelper<Issue>(
ApplyView& view,
AccountID const& issuer,
AccountID const& sender,
STAmount const& amount,
beast::Journal journal)
{
// Defensive: Issuer cannot create an escrow
if (issuer == sender)
return tecINTERNAL; // LCOV_EXCL_LINE
auto const ter =
directSendNoFee(view, sender, issuer, amount, !amount.holds<MPTIssue>(), journal);
if (!isTesSuccess(ter))
return ter; // LCOV_EXCL_LINE
return tesSUCCESS;
}
template <>
inline TER
escrowLockApplyHelper<MPTIssue>(
ApplyView& view,
AccountID const& issuer,
AccountID const& sender,
STAmount const& amount,
beast::Journal journal)
{
// Defensive: Issuer cannot create an escrow
if (issuer == sender)
return tecINTERNAL; // LCOV_EXCL_LINE
auto const ter = lockEscrowMPT(view, sender, amount, journal);
if (!isTesSuccess(ter))
return ter; // LCOV_EXCL_LINE
return tesSUCCESS;
}
template <ValidIssueType T>
TER
escrowUnlockPreclaimHelper(
ReadView const& view,
AccountID const& account,
STAmount const& amount,
bool checkFreeze = true);
template <>
inline TER
escrowUnlockPreclaimHelper<Issue>(
ReadView const& view,
AccountID const& account,
STAmount const& amount,
bool checkFreeze)
{
AccountID const& issuer = amount.getIssuer();
// If the issuer is the same as the account, return tesSUCCESS
if (issuer == account)
return tesSUCCESS;
// If the issuer has requireAuth set, check if the destination is authorized
if (auto const ter = requireAuth(view, amount.get<Issue>(), account); !isTesSuccess(ter))
return ter;
// If the issuer has deep frozen the destination, return tecFROZEN
if (checkFreeze &&
isDeepFrozen(view, account, amount.get<Issue>().currency, amount.getIssuer()))
return tecFROZEN;
return tesSUCCESS;
}
template <>
inline TER
escrowUnlockPreclaimHelper<MPTIssue>(
ReadView const& view,
AccountID const& account,
STAmount const& amount,
bool checkFreeze)
{
AccountID const& issuer = amount.getIssuer();
// If the issuer is the same as the account, return tesSUCCESS
if (issuer == account)
return tesSUCCESS;
// If the mpt does not exist, return tecOBJECT_NOT_FOUND
auto const issuanceKey = keylet::mptokenIssuance(amount.get<MPTIssue>().getMptID());
auto const sleIssuance = view.read(issuanceKey);
if (!sleIssuance)
return tecOBJECT_NOT_FOUND;
// If the issuer has requireAuth set, check if the account is
// authorized
auto const& mptIssue = amount.get<MPTIssue>();
if (auto const ter = requireAuth(view, mptIssue, account, AuthType::WeakAuth);
!isTesSuccess(ter))
return ter;
// If the issuer has frozen the account, return tecLOCKED
if (checkFreeze && isFrozen(view, account, *sleIssuance))
return tecLOCKED;
return tesSUCCESS;
}
//------------------------------------------------------------------------------
template <ValidIssueType T> template <ValidIssueType T>
TER TER
@@ -81,9 +342,6 @@ escrowUnlockApplyHelper<Issue>(
bool createAsset, bool createAsset,
beast::Journal journal) beast::Journal journal)
{ {
auto const& issue = amount.get<Issue>();
Keylet const trustLineKey = keylet::trustLine(receiver, issue);
bool const recvLow = issuer > receiver;
bool const senderIssuer = issuer == sender; bool const senderIssuer = issuer == sender;
bool const receiverIssuer = issuer == receiver; bool const receiverIssuer = issuer == receiver;
@@ -93,20 +351,25 @@ escrowUnlockApplyHelper<Issue>(
if (receiverIssuer) if (receiverIssuer)
return tesSUCCESS; return tesSUCCESS;
auto const& issue = amount.get<Issue>();
Keylet const trustLineKey = keylet::trustLine(receiver, issue);
bool const recvLow = issuer > receiver;
if (!ctx.view.exists(trustLineKey) && createAsset) if (!ctx.view.exists(trustLineKey) && createAsset)
{ {
// Can the account cover the trust line's reserve? // Can the account cover the trust line's reserve?
if (sleDest->getType() != ltACCOUNT_ROOT) auto const sponsorSle = getEffectiveTxReserveSponsor(ctx, sleDest);
return detail::escrowDestNotAccountResult(ctx, sleDest);
auto const destSle = AccountRootEntryR(sleDest, ctx.view, journal);
auto sponsorSle = getEffectiveTxReserveSponsor(ctx, destSle);
if (!sponsorSle) if (!sponsorSle)
return sponsorSle.error(); // LCOV_EXCL_LINE return sponsorSle.error(); // LCOV_EXCL_LINE
auto& sponsor = *sponsorSle; if (auto const ret = checkReserve(
ctx,
if (auto const ret = destSle.checkReserve( sleDest,
ctx, xrpBalance, sponsor, {.ownerCountDelta = 1}, tecNO_LINE_INSUF_RESERVE); xrpBalance,
*sponsorSle,
{.ownerCountDelta = 1},
journal,
tecNO_LINE_INSUF_RESERVE);
!isTesSuccess(ret)) !isTesSuccess(ret))
{ {
JLOG(journal.trace()) << "Trust line does not exist. " JLOG(journal.trace()) << "Trust line does not exist. "
@@ -119,22 +382,22 @@ escrowUnlockApplyHelper<Issue>(
initialBalance.get<Issue>().account = noAccount(); initialBalance.get<Issue>().account = noAccount();
if (TER const ter = trustCreate( if (TER const ter = trustCreate(
ctx.view, // payment sandbox ctx.view, // payment sandbox
recvLow, // is dest low? recvLow, // is dest low?
issuer, // source issuer, // source
receiver, // destination receiver, // destination
trustLineKey.key, // ledger index trustLineKey.key, // ledger index
sleDest, // Account to add to sleDest, // Account to add to
false, // authorize account false, // authorize account
!sleDest->isFlag(lsfDefaultRipple), // !sleDest->isFlag(lsfDefaultRipple), //
false, // freeze trust line false, // freeze trust line
false, // deep freeze trust line false, // deep freeze trust line
initialBalance, // zero initial balance initialBalance, // zero initial balance
Issue(currency, receiver), // limit of zero Issue(currency, receiver), // limit of zero
0, // quality in 0, // quality in
0, // quality out 0, // quality out
sponsor ? sponsor->mutableRawSle() : SLE::pointer(), // sponsor *sponsorSle, // sponsor
journal); // journal journal); // journal
!isTesSuccess(ter)) !isTesSuccess(ter))
{ {
return ter; // LCOV_EXCL_LINE return ter; // LCOV_EXCL_LINE
@@ -229,29 +492,23 @@ escrowUnlockApplyHelper<MPTIssue>(
auto const mptKeylet = keylet::mptoken(issuanceKey.key, receiver); auto const mptKeylet = keylet::mptoken(issuanceKey.key, receiver);
if (!ctx.view.exists(mptKeylet) && createAsset && !receiverIssuer) if (!ctx.view.exists(mptKeylet) && createAsset && !receiverIssuer)
{ {
if (sleDest->getType() != ltACCOUNT_ROOT) auto const sponsorSle = getEffectiveTxReserveSponsor(ctx, sleDest);
return detail::escrowDestNotAccountResult(ctx, sleDest);
auto const destSle = AccountRootEntryR(sleDest, ctx.view, journal);
auto sponsorSle = getEffectiveTxReserveSponsor(ctx, destSle);
if (!sponsorSle) if (!sponsorSle)
return sponsorSle.error(); // LCOV_EXCL_LINE return sponsorSle.error(); // LCOV_EXCL_LINE
auto& sponsor = *sponsorSle; if (auto const ret = checkReserve(
ctx, sleDest, xrpBalance, *sponsorSle, {.ownerCountDelta = 1}, journal);
if (auto const ret = destSle.checkReserve(ctx, xrpBalance, sponsor, {.ownerCountDelta = 1});
!isTesSuccess(ret)) !isTesSuccess(ret))
return ret; return ret;
if (auto const ter = createMPToken( if (auto const ter = createMPToken(ctx.view, mptID, receiver, *sponsorSle, 0);
ctx.view, mptID, receiver, sponsor ? sponsor->mutableRawSle() : SLE::pointer(), 0);
!isTesSuccess(ter)) !isTesSuccess(ter))
{ {
return ter; // LCOV_EXCL_LINE return ter; // LCOV_EXCL_LINE
} }
// update owner count. // update owner count.
AccountRootEntryW receiverSle(receiver, ctx.view, journal); increaseOwnerCount(ctx.view, sleDest, *sponsorSle, 1, journal);
receiverSle.increaseOwnerCount(sponsor, 1);
} }
if (!ctx.view.exists(mptKeylet) && !receiverIssuer) if (!ctx.view.exists(mptKeylet) && !receiverIssuer)
+11 -12
View File
@@ -2,7 +2,6 @@
#include <xrpl/ledger/ApplyView.h> #include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h> #include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/AccountRootEntry.h>
#include <xrpl/protocol/AccountID.h> #include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/SField.h> #include <xrpl/protocol/SField.h>
#include <xrpl/protocol/STLedgerEntry.h> #include <xrpl/protocol/STLedgerEntry.h>
@@ -55,11 +54,11 @@ getTxReserveSponsorID(STTx const& tx);
* Return a mutable SLE for the transaction's reserve sponsor account. * Return a mutable SLE for the transaction's reserve sponsor account.
* *
* @param ctx The apply-view context (view + tx) * @param ctx The apply-view context (view + tx)
* @return The sponsor account entry, nullopt if the tx is not * @return The sponsor account SLE, a null pointer if the tx is not
* reserve-sponsored, or tecINTERNAL if the sponsor account cannot * reserve-sponsored, or tecINTERNAL if the sponsor account cannot
* be loaded (an already-checked invariant). * be loaded (an already-checked invariant).
*/ */
std::expected<std::optional<AccountRootEntryW>, TER> std::expected<SLE::pointer, TER>
getTxReserveSponsor(ApplyViewContext ctx); getTxReserveSponsor(ApplyViewContext ctx);
/** /**
@@ -67,29 +66,29 @@ getTxReserveSponsor(ApplyViewContext ctx);
* *
* @param view The ledger read view * @param view The ledger read view
* @param tx The transaction to inspect * @param tx The transaction to inspect
* @return The sponsor account entry, nullopt if the tx is not * @return The sponsor account SLE, a null pointer if the tx is not
* reserve-sponsored, or tecINTERNAL if the sponsor account cannot * reserve-sponsored, or tecINTERNAL if the sponsor account cannot
* be loaded (an already-checked invariant). * be loaded (an already-checked invariant).
*/ */
std::expected<std::optional<AccountRootEntryR>, TER> std::expected<SLE::const_pointer, TER>
getTxReserveSponsor(ReadView const& view, STTx const& tx); getTxReserveSponsor(ReadView const& view, STTx const& tx);
/** /**
* The transaction's reserve sponsor for the given account, if applicable. * The transaction's reserve sponsor for the given account, if applicable.
* *
* A reserve sponsor only covers the transaction submitter's own objects, so * A reserve sponsor only covers the transaction submitter's own objects, so
* this returns the tx reserve sponsor entry only when accountSle is the tx's * this returns the tx reserve sponsor SLE only when accountSle is the tx's own
* own (non-pseudo) account; otherwise it returns nullopt. This is * (non-pseudo) account; otherwise it returns a null sponsor pointer. This is
* the single source of truth for the "sponsor applies to tx.Account only" rule * the single source of truth for the "sponsor applies to tx.Account only" rule
* that the sponsor-deriving helper overloads in AccountRootHelpers rely on. * that the sponsor-deriving helper overloads in AccountRootHelpers rely on.
* *
* @param ctx The apply-view context (view + tx) * @param ctx The apply-view context (view + tx)
* @param accountSle The account whose sponsor is being resolved * @param accountSle The account whose sponsor is being resolved
* @return The sponsor entry (nullopt if unsponsored), or tecINTERNAL if the * @return The sponsor SLE (nullptr if unsponsored), or tecINTERNAL if the
* sponsor account cannot be loaded (an already-checked invariant) * sponsor account cannot be loaded (an already-checked invariant)
*/ */
[[nodiscard]] std::expected<std::optional<AccountRootEntryW>, TER> [[nodiscard]] std::expected<SLE::pointer, TER>
getEffectiveTxReserveSponsor(ApplyViewContext ctx, AccountRootEntryR const& accountSle); getEffectiveTxReserveSponsor(ApplyViewContext ctx, SLE::ConstRef accountSle);
/** /**
* Return the AccountID stored in the given sponsor field of a ledger entry, or nullopt if absent. * Return the AccountID stored in the given sponsor field of a ledger entry, or nullopt if absent.
@@ -106,9 +105,9 @@ getLedgerEntryReserveSponsorID(SLE::ConstRef sle, SF_ACCOUNT const& field = sfSp
* @param view The mutable apply view * @param view The mutable apply view
* @param sle The ledger entry whose sponsor field is inspected * @param sle The ledger entry whose sponsor field is inspected
* @param field The field that holds the sponsor AccountID (defaults to sfSponsor) * @param field The field that holds the sponsor AccountID (defaults to sfSponsor)
* @return The sponsor account entry, or nullopt if the entry is unsponsored. * @return The sponsor account SLE, or a null pointer if the entry is unsponsored.
*/ */
std::optional<AccountRootEntryW> SLE::pointer
getLedgerEntryReserveSponsor( getLedgerEntryReserveSponsor(
ApplyView& view, ApplyView& view,
SLE::ConstRef sle, SLE::ConstRef sle,
+1 -1
View File
@@ -103,7 +103,7 @@ public:
void void
asyncHandshake(HandshakeType type, Callback cbFunc) asyncHandshake(HandshakeType type, Callback cbFunc)
{ {
if ((type == SslSocket::client) || (secure_)) if ((type == SslSocket::client) || secure_)
{ {
// must be ssl // must be ssl
secure_ = true; secure_ = true;
Loaded 100 of 799 files, more files were not shown because too many files have changed in this diff. Show more