diff --git a/.clang-tidy b/.clang-tidy index 35427810a3..88dd6f4e57 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,161 +1,87 @@ --- Checks: "-*, - bugprone-argument-comment, - bugprone-assert-side-effect, - bugprone-bad-signal-to-kill-thread, - bugprone-bool-pointer-implicit-conversion, - bugprone-capturing-this-in-member-variable, - bugprone-casting-through-void, - bugprone-chained-comparison, - bugprone-compare-pointer-to-member-virtual-function, - bugprone-copy-constructor-init, - bugprone-crtp-constructor-accessibility, - bugprone-dangling-handle, - bugprone-derived-method-shadowing-base-method, - bugprone-dynamic-static-initializers, - bugprone-empty-catch, - bugprone-fold-init-type, - bugprone-forward-declaration-namespace, - bugprone-inaccurate-erase, - bugprone-inc-dec-in-conditions, - bugprone-incorrect-enable-if, - bugprone-incorrect-roundings, - bugprone-infinite-loop, - bugprone-integer-division, - bugprone-invalid-enum-default-initialization, - bugprone-lambda-function-name, - bugprone-macro-parentheses, - bugprone-macro-repeated-side-effects, - bugprone-misleading-setter-of-reference, - bugprone-misplaced-operator-in-strlen-in-alloc, - bugprone-misplaced-pointer-arithmetic-in-alloc, - bugprone-misplaced-widening-cast, - bugprone-move-forwarding-reference, - bugprone-multi-level-implicit-pointer-conversion, - bugprone-multiple-new-in-one-expression, - bugprone-multiple-statement-macro, - bugprone-no-escape, - bugprone-non-zero-enum-to-bool-conversion, - bugprone-optional-value-conversion, - bugprone-parent-virtual-call, - bugprone-pointer-arithmetic-on-polymorphic-object, - bugprone-posix-return, - bugprone-redundant-branch-condition, - bugprone-reserved-identifier, - bugprone-return-const-ref-from-parameter, - bugprone-shared-ptr-array-mismatch, - bugprone-signal-handler, - bugprone-signed-char-misuse, - bugprone-sizeof-container, - bugprone-sizeof-expression, - bugprone-spuriously-wake-up-functions, - bugprone-standalone-empty, - bugprone-string-constructor, - bugprone-string-integer-assignment, - bugprone-string-literal-with-embedded-nul, - bugprone-stringview-nullptr, - bugprone-suspicious-enum-usage, - bugprone-suspicious-include, - bugprone-suspicious-memory-comparison, - bugprone-suspicious-memset-usage, - bugprone-suspicious-missing-comma, - bugprone-suspicious-realloc-usage, - bugprone-suspicious-semicolon, - bugprone-suspicious-string-compare, - bugprone-suspicious-stringview-data-usage, - bugprone-swapped-arguments, - bugprone-switch-missing-default-case, - bugprone-terminating-continue, - bugprone-throw-keyword-missing, - bugprone-too-small-loop-variable, - bugprone-unchecked-optional-access, - bugprone-undefined-memory-manipulation, - bugprone-undelegated-constructor, - bugprone-unhandled-exception-at-new, - bugprone-unhandled-self-assignment, - bugprone-unique-ptr-array-mismatch, - bugprone-unsafe-functions, - bugprone-unused-local-non-trivial-variable, - bugprone-unused-raii, - bugprone-unused-return-value, - bugprone-use-after-move, - bugprone-virtual-near-miss, - cppcoreguidelines-init-variables, - cppcoreguidelines-misleading-capture-default-by-value, - cppcoreguidelines-no-suspend-with-lock, - cppcoreguidelines-pro-type-member-init, - cppcoreguidelines-pro-type-static-cast-downcast, - cppcoreguidelines-rvalue-reference-param-not-moved, - cppcoreguidelines-use-default-member-init, - cppcoreguidelines-use-enum-class, - cppcoreguidelines-virtual-class-destructor, - hicpp-ignored-remove-result, + bugprone-*, + -bugprone-easily-swappable-parameters, + -bugprone-exception-escape, + -bugprone-implicit-widening-of-multiplication-result, + -bugprone-narrowing-conversions, + -bugprone-throwing-static-initialization, + + cppcoreguidelines-*, + -cppcoreguidelines-avoid-c-arrays, + -cppcoreguidelines-avoid-const-or-ref-data-members, + -cppcoreguidelines-avoid-do-while, + -cppcoreguidelines-avoid-magic-numbers, + -cppcoreguidelines-avoid-non-const-global-variables, + -cppcoreguidelines-c-copy-assignment-signature, + -cppcoreguidelines-interfaces-global-init, + -cppcoreguidelines-macro-usage, + -cppcoreguidelines-missing-std-forward, + -cppcoreguidelines-narrowing-conversions, + -cppcoreguidelines-noexcept-move-operations, + -cppcoreguidelines-non-private-member-variables-in-classes, + -cppcoreguidelines-owning-memory, + -cppcoreguidelines-pro-bounds-array-to-pointer-decay, + -cppcoreguidelines-pro-bounds-avoid-unchecked-container-access, + -cppcoreguidelines-pro-bounds-constant-array-index, + -cppcoreguidelines-pro-bounds-pointer-arithmetic, + -cppcoreguidelines-pro-type-reinterpret-cast, + -cppcoreguidelines-pro-type-union-access, + -cppcoreguidelines-special-member-functions, + llvm-namespace-comment, - misc-const-correctness, - misc-definitions-in-headers, - misc-header-include-cycle, - misc-include-cleaner, - misc-misplaced-const, - misc-redundant-expression, - misc-static-assert, - misc-throw-by-value-catch-by-reference, - misc-unused-alias-decls, - misc-unused-using-decls, - modernize-concat-nested-namespaces, - modernize-deprecated-headers, - modernize-make-shared, - modernize-make-unique, - modernize-pass-by-value, - modernize-type-traits, - modernize-use-designated-initializers, - modernize-use-emplace, - modernize-use-equals-default, - modernize-use-equals-delete, - modernize-use-nodiscard, - modernize-use-override, - modernize-use-ranges, - modernize-use-scoped-lock, - modernize-use-starts-ends-with, - modernize-use-std-numbers, - modernize-use-using, - performance-faster-string-find, - performance-for-range-copy, - performance-implicit-conversion-in-loop, - performance-inefficient-vector-operation, - performance-move-const-arg, - performance-move-constructor-init, - performance-no-automatic-move, - performance-trivially-destructible, - readability-ambiguous-smartptr-reset-call, - readability-avoid-nested-conditional-operator, - readability-avoid-return-with-void-value, - readability-braces-around-statements, - readability-const-return-type, - readability-container-contains, - readability-container-size-empty, - readability-convert-member-functions-to-static, - readability-duplicate-include, - readability-else-after-return, - readability-enum-initial-value, - readability-identifier-naming, - readability-implicit-bool-conversion, - readability-inconsistent-ifelse-braces, - readability-make-member-function-const, - readability-math-missing-parentheses, - readability-misleading-indentation, - readability-non-const-parameter, - readability-redundant-casting, - readability-redundant-declaration, - readability-redundant-inline-specifier, - readability-redundant-member-init, - readability-redundant-parentheses, - readability-redundant-string-init, - readability-redundant-typename, - readability-reference-to-constructed-temporary, - readability-simplify-boolean-expr, - readability-static-definition-in-anonymous-namespace, - readability-suspicious-call-argument, - readability-use-std-min-max + + misc-*, + -misc-multiple-inheritance, + -misc-no-recursion, + -misc-non-private-member-variables-in-classes, + -misc-override-with-different-visibility, + -misc-unused-parameters, + -misc-use-anonymous-namespace, + -misc-use-internal-linkage, + + modernize-*, + -modernize-avoid-c-arrays, + -modernize-avoid-c-style-cast, + -modernize-return-braced-init-list, + -modernize-use-integer-sign-comparison, + -modernize-use-trailing-return-type, + + performance-*, + -performance-avoid-endl, + -performance-enum-size, + -performance-noexcept-move-constructor, + -performance-unnecessary-copy-initialization, + -performance-unnecessary-value-param, + + readability-*, + -readability-avoid-const-params-in-decls, + -readability-avoid-unconditional-preprocessor-if, + -readability-container-data-pointer, + -readability-delete-null-pointer, + -readability-function-cognitive-complexity, + -readability-function-size, + -readability-identifier-length, + -readability-inconsistent-declaration-parameter-name, + -readability-isolate-declaration, + -readability-magic-numbers, + -readability-misplaced-array-index, + -readability-named-parameter, + -readability-operators-representation, + -readability-qualified-auto, + -readability-redundant-access-specifiers, + -readability-redundant-control-flow, + -readability-redundant-function-ptr-dereference, + -readability-redundant-preprocessor, + -readability-redundant-smartptr-get, + -readability-redundant-string-cstr, + -readability-simplify-subscript-expr, + -readability-static-accessed-through-instance, + -readability-string-compare, + -readability-uniqueptr-delete-release, + -readability-uppercase-literal-suffix, + -readability-use-anyofallof, + -readability-use-concise-preprocessor-directives " # --- # bugprone-narrowing-conversions, # This will break a lot of code but we should enable it in the future because it can eliminate a lot of bugs @@ -168,7 +94,7 @@ CheckOptions: bugprone-unsafe-functions.ReportMoreUnsafeFunctions: true bugprone-unused-return-value.CheckedReturnTypes: ::std::error_code;::std::error_condition;::std::errc - misc-include-cleaner.IgnoreHeaders: ".*/(detail|impl)/.*;.*fwd\\.h(pp)?;time.h;stdlib.h;sqlite3.h;netinet/in\\.h;sys/resource\\.h;sys/sysinfo\\.h;linux/sysinfo\\.h;__chrono/.*;bits/.*;_abort\\.h;boost/uuid/uuid_hash.hpp;boost/beast/core/flat_buffer\\.hpp;boost/beast/http/field\\.hpp;boost/beast/http/dynamic_body\\.hpp;boost/beast/http/message\\.hpp;boost/beast/http/read\\.hpp;boost/beast/http/write\\.hpp;openssl/obj_mac\\.h" + misc-include-cleaner.IgnoreHeaders: ".*/(detail|impl)/.*;.*fwd\\.h(pp)?;time.h;stdlib.h;sqlite3.h;netinet/in\\.h;sys/resource\\.h;sys/sysinfo\\.h;linux/sysinfo\\.h;__chrono/.*;bits/.*;_abort\\.h;boost/.*;openssl/obj_mac\\.h" readability-braces-around-statements.ShortStatementLines: 2 readability-identifier-naming.MacroDefinitionCase: UPPER_CASE diff --git a/cspell.config.yaml b/.cspell.config.yaml similarity index 95% rename from cspell.config.yaml rename to .cspell.config.yaml index 8273df6c98..3c5191f5e1 100644 --- a/cspell.config.yaml +++ b/.cspell.config.yaml @@ -36,9 +36,7 @@ overrides: - /'[^']*'/g # single-quoted strings - /`[^`]*`/g # backtick strings suggestWords: - - xprl->xrpl - - xprld->xrpld # cspell: disable-line not sure what this problem is.... - - unsynched->unsynced # cspell: disable-line not sure what this problem is.... + - unsynched->unsynced - synched->synced - synch->sync words: @@ -60,6 +58,7 @@ words: - autobridging - bimap - bindir + - blindings - bookdir - Bougalis - Britto @@ -95,6 +94,7 @@ words: - daria - dcmake - dearmor + - decryptor - dedented - deleteme - demultiplexer @@ -106,6 +106,7 @@ words: - distro - doxyfile - dxrpl + - elgamal - enabled - enablerepo - endmacro @@ -119,6 +120,7 @@ words: - fmtdur - fsanitize - funclets + - Gamal - gcov - gcovr - ghead @@ -216,6 +218,7 @@ words: - partitioner - paychan - paychans + - Pedersen - permdex - perminute - permissioned @@ -239,6 +242,10 @@ words: - Raphson - rcflags - replayer + - rerandomize + - rerandomization + - rerandomized + - rerandomizes - rerere - retriable - RIPD @@ -255,6 +262,7 @@ words: - sahyadri - Satoshi - scons + - Schnorr - secp - sendq - seqit @@ -271,6 +279,8 @@ words: - sles - soci - socidb + - sponsee + - sponsees - SRPMS - sslws - statsd @@ -285,12 +295,14 @@ words: - stvar - stvector - stxchainattestations + - summands - superpeer - superpeers - takergets - takerpays - ters - TMEndpointv2 + - tparam - trixie - tx - txid @@ -318,6 +330,7 @@ words: - unserviced - unshareable - unshares + - unsponsored - unsquelch - unsquelched - unsquelching diff --git a/.envrc b/.envrc new file mode 100644 index 0000000000..3550a30f2d --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake diff --git a/.gersemi/definitions.cmake b/.gersemi/definitions.cmake index 58bc74c70a..aa63076c8b 100644 --- a/.gersemi/definitions.cmake +++ b/.gersemi/definitions.cmake @@ -48,6 +48,12 @@ endfunction() function(add_module parent name) endfunction() +function(verify_target_headers target headers_dir) +endfunction() + +function(_verify_add_headers target dir) +endfunction() + function(setup_protocol_autogen) endfunction() diff --git a/.github/actions/setup-conan/action.yml b/.github/actions/setup-conan/action.yml index 0dd22f0d92..e8a548cfce 100644 --- a/.github/actions/setup-conan/action.yml +++ b/.github/actions/setup-conan/action.yml @@ -9,7 +9,7 @@ inputs: remote_url: description: "The URL of the Conan endpoint to use." required: false - default: https://conan.ripplex.io + default: https://conan.xrplf.org/repository/conan/ runs: using: composite diff --git a/.github/scripts/levelization/results/loops.txt b/.github/scripts/levelization/results/loops.txt index fb449441e3..cf70468e32 100644 --- a/.github/scripts/levelization/results/loops.txt +++ b/.github/scripts/levelization/results/loops.txt @@ -1,9 +1,3 @@ -Loop: test.jtx test.toplevel - test.toplevel > test.jtx - -Loop: test.jtx test.unit_test - test.unit_test ~= test.jtx - Loop: xrpld.app xrpld.overlay xrpld.app > xrpld.overlay diff --git a/.github/scripts/levelization/results/ordering.txt b/.github/scripts/levelization/results/ordering.txt index 7b31042158..aee6f4c579 100644 --- a/.github/scripts/levelization/results/ordering.txt +++ b/.github/scripts/levelization/results/ordering.txt @@ -72,7 +72,6 @@ test.app > xrpl.server test.app > xrpl.shamap test.app > xrpl.tx test.basics > test.jtx -test.basics > test.unit_test test.basics > xrpl.basics test.basics > xrpl.core test.basics > xrpld.rpc @@ -105,9 +104,9 @@ test.csf > xrpl.basics test.csf > xrpld.consensus test.csf > xrpl.json test.csf > xrpl.ledger -test.csf > xrpl.protocol test.json > test.jtx test.json > xrpl.json +test.jtx > test.unit_test test.jtx > xrpl.basics test.jtx > xrpl.config test.jtx > xrpl.core @@ -162,9 +161,6 @@ test.protocol > test.unit_test test.protocol > xrpl.basics test.protocol > xrpl.json test.protocol > xrpl.protocol -test.resource > test.unit_test -test.resource > xrpl.basics -test.resource > xrpl.resource test.rpc > test.jtx test.rpc > xrpl.basics test.rpc > xrpl.config @@ -188,14 +184,6 @@ test.server > xrpld.core test.server > xrpl.json test.server > xrpl.protocol test.server > xrpl.server -test.shamap > test.unit_test -test.shamap > xrpl.basics -test.shamap > xrpl.config -test.shamap > xrpl.nodestore -test.shamap > xrpl.protocol -test.shamap > xrpl.shamap -test.toplevel > test.csf -test.toplevel > xrpl.json test.unit_test > xrpl.basics test.unit_test > xrpl.protocol tests.libxrpl > xrpl.basics @@ -207,6 +195,7 @@ tests.libxrpl > xrpl.net tests.libxrpl > xrpl.nodestore tests.libxrpl > xrpl.protocol tests.libxrpl > xrpl.protocol_autogen +tests.libxrpl > xrpl.resource tests.libxrpl > xrpl.server tests.libxrpl > xrpl.shamap tests.libxrpl > xrpl.tx @@ -218,11 +207,14 @@ xrpl.core > xrpl.json xrpl.core > xrpl.protocol xrpl.json > xrpl.basics xrpl.ledger > xrpl.basics +xrpl.ledger > xrpl.json +xrpl.ledger > xrpl.nodestore xrpl.ledger > xrpl.protocol xrpl.ledger > xrpl.shamap xrpl.net > xrpl.basics xrpl.nodestore > xrpl.basics xrpl.nodestore > xrpl.config +xrpl.nodestore > xrpl.json xrpl.nodestore > xrpl.protocol xrpl.protocol > xrpl.basics xrpl.protocol > xrpl.json @@ -240,7 +232,6 @@ xrpl.server > xrpl.json xrpl.server > xrpl.protocol xrpl.server > xrpl.rdb xrpl.server > xrpl.resource -xrpl.server > xrpl.shamap xrpl.shamap > xrpl.basics xrpl.shamap > xrpl.nodestore xrpl.shamap > xrpl.protocol @@ -295,8 +286,10 @@ xrpld.peerfinder > xrpl.rdb xrpld.perflog > xrpl.basics xrpld.perflog > xrpl.config xrpld.perflog > xrpl.core +xrpld.perflog > xrpld.app xrpld.perflog > xrpld.rpc xrpld.perflog > xrpl.json +xrpld.perflog > xrpl.nodestore xrpld.perflog > xrpl.protocol xrpld.rpc > xrpl.basics xrpld.rpc > xrpl.config @@ -314,5 +307,6 @@ xrpld.rpc > xrpl.shamap xrpld.rpc > xrpl.tx xrpld.shamap > xrpl.basics xrpld.shamap > xrpld.core +xrpld.shamap > xrpl.nodestore xrpld.shamap > xrpl.protocol xrpld.shamap > xrpl.shamap diff --git a/.github/scripts/strategy-matrix/macos.json b/.github/scripts/strategy-matrix/macos.json index 66d7a55a43..2d3cc75c7b 100644 --- a/.github/scripts/strategy-matrix/macos.json +++ b/.github/scripts/strategy-matrix/macos.json @@ -1,6 +1,6 @@ { "platform": "macos/arm64", - "runner": ["self-hosted", "macOS", "ARM64", "mac-runner-m1"], + "runner": ["self-hosted", "macOS", "ARM64", "macos-26-apple-clang-21"], "configs": [ { "build_type": "Release", diff --git a/.github/workflows/on-pr.yml b/.github/workflows/on-pr.yml index 0c9eeda712..19fb170b92 100644 --- a/.github/workflows/on-pr.yml +++ b/.github/workflows/on-pr.yml @@ -122,7 +122,6 @@ jobs: issues: write contents: read with: - check_only_changed: true create_issue_on_failure: false build-test: @@ -154,8 +153,8 @@ jobs: if: ${{ github.repository == 'XRPLF/rippled' && needs.should-run.outputs.go == 'true' && github.event_name == 'pull_request' && startsWith(github.event.pull_request.base.ref, 'release') }} uses: ./.github/workflows/reusable-upload-recipe.yml secrets: - remote_username: ${{ secrets.CONAN_REMOTE_USERNAME }} - remote_password: ${{ secrets.CONAN_REMOTE_PASSWORD }} + remote_username: ${{ secrets.NEXUS_REMOTE_USERNAME }} + remote_password: ${{ secrets.NEXUS_REMOTE_PASSWORD }} notify-clio: needs: upload-recipe diff --git a/.github/workflows/on-tag.yml b/.github/workflows/on-tag.yml index 42d5827cab..abedc13d69 100644 --- a/.github/workflows/on-tag.yml +++ b/.github/workflows/on-tag.yml @@ -20,8 +20,8 @@ jobs: if: ${{ github.repository == 'XRPLF/rippled' }} uses: ./.github/workflows/reusable-upload-recipe.yml secrets: - remote_username: ${{ secrets.CONAN_REMOTE_USERNAME }} - remote_password: ${{ secrets.CONAN_REMOTE_PASSWORD }} + remote_username: ${{ secrets.NEXUS_REMOTE_USERNAME }} + remote_password: ${{ secrets.NEXUS_REMOTE_PASSWORD }} build-test: if: ${{ github.repository == 'XRPLF/rippled' }} diff --git a/.github/workflows/on-trigger.yml b/.github/workflows/on-trigger.yml index 063cdbff7f..49a93d2746 100644 --- a/.github/workflows/on-trigger.yml +++ b/.github/workflows/on-trigger.yml @@ -72,7 +72,6 @@ jobs: issues: write contents: read with: - check_only_changed: false create_issue_on_failure: ${{ github.event_name == 'schedule' }} build-test: @@ -98,8 +97,8 @@ jobs: if: ${{ github.repository == 'XRPLF/rippled' && github.event_name == 'push' && github.ref == 'refs/heads/develop' }} uses: ./.github/workflows/reusable-upload-recipe.yml secrets: - remote_username: ${{ secrets.CONAN_REMOTE_USERNAME }} - remote_password: ${{ secrets.CONAN_REMOTE_PASSWORD }} + remote_username: ${{ secrets.NEXUS_REMOTE_USERNAME }} + remote_password: ${{ secrets.NEXUS_REMOTE_PASSWORD }} package: needs: build-test diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 0363534af5..1acd28208e 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -14,7 +14,7 @@ on: jobs: # Call the workflow in the XRPLF/actions repo that runs the pre-commit hooks. run-hooks: - uses: XRPLF/actions/.github/workflows/pre-commit.yml@e06d4138c9ec8dceeb7c818645faa38087ea9e3d + uses: XRPLF/actions/.github/workflows/pre-commit.yml@1bde119a1ab71305ba5d3716e7a82cea1c7bdede with: runs_on: ubuntu-latest container: '{ "image": "ghcr.io/xrplf/ci/tools-rippled-pre-commit:sha-41ec7c1" }' diff --git a/.github/workflows/publish-docs.yml b/.github/workflows/publish-docs.yml index cb7d4c5382..1ac8d61655 100644 --- a/.github/workflows/publish-docs.yml +++ b/.github/workflows/publish-docs.yml @@ -47,7 +47,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - name: Prepare runner - uses: XRPLF/actions/prepare-runner@c47daebb2f9db64ffbac71b47d68a661498d5ce8 + uses: XRPLF/actions/prepare-runner@64ec3cf3b152b4444638f470bbd6df7a7a30c81c with: enable_ccache: false diff --git a/.github/workflows/reusable-build-test-config.yml b/.github/workflows/reusable-build-test-config.yml index 4709878f49..a4bb5932ca 100644 --- a/.github/workflows/reusable-build-test-config.yml +++ b/.github/workflows/reusable-build-test-config.yml @@ -113,7 +113,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - name: Prepare runner - uses: XRPLF/actions/prepare-runner@c47daebb2f9db64ffbac71b47d68a661498d5ce8 + uses: XRPLF/actions/prepare-runner@64ec3cf3b152b4444638f470bbd6df7a7a30c81c with: enable_ccache: ${{ inputs.ccache_enabled }} diff --git a/.github/workflows/reusable-clang-tidy.yml b/.github/workflows/reusable-clang-tidy.yml index f36463a5d0..a6bbe669ce 100644 --- a/.github/workflows/reusable-clang-tidy.yml +++ b/.github/workflows/reusable-clang-tidy.yml @@ -3,10 +3,6 @@ name: Run clang-tidy on files on: workflow_call: inputs: - check_only_changed: - description: "Check only changed files in PR. If false, checks all files in the repository." - type: boolean - default: false create_issue_on_failure: description: "Whether to create an issue if the check failed" type: boolean @@ -29,15 +25,14 @@ env: jobs: determine-files: - if: ${{ inputs.check_only_changed }} permissions: contents: read - uses: XRPLF/actions/.github/workflows/determine-tidy-files.yml@c7045074aafe9fb92fa537aa4446f81fbfc17e8b + uses: XRPLF/actions/.github/workflows/determine-tidy-files.yml@d041ac9f1fa9f07a4ba335eb4c1c82233fb3fef6 run-clang-tidy: name: Run clang tidy needs: [determine-files] - if: ${{ always() && !cancelled() && (!inputs.check_only_changed || needs.determine-files.outputs.cpp_changed_files != '' || needs.determine-files.outputs.clang_tidy_config_changed == 'true') }} + if: ${{ needs.determine-files.outputs.cpp_changed_files != '' || needs.determine-files.outputs.need_full_run == 'true' }} runs-on: ["self-hosted", "Linux", "X64", "heavy"] container: "ghcr.io/xrplf/xrpld/nix-debian:sha-e29b523" permissions: @@ -48,7 +43,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - name: Prepare runner - uses: XRPLF/actions/prepare-runner@c47daebb2f9db64ffbac71b47d68a661498d5ce8 + uses: XRPLF/actions/prepare-runner@64ec3cf3b152b4444638f470bbd6df7a7a30c81c with: enable_ccache: false @@ -84,6 +79,7 @@ jobs: -Dtests=ON \ -Dwerr=ON \ -Dxrpld=ON \ + -Dverify_headers=ON \ .. # clang-tidy needs headers generated from proto files @@ -96,15 +92,15 @@ jobs: id: run_clang_tidy continue-on-error: true env: - TARGETS: ${{ (needs.determine-files.outputs.clang_tidy_config_changed != 'true' && inputs.check_only_changed) && needs.determine-files.outputs.cpp_changed_files || 'src tests' }} + TARGETS: ${{ needs.determine-files.outputs.need_full_run != 'true' && needs.determine-files.outputs.cpp_changed_files || 'include src tests' }} run: | set -o pipefail run-clang-tidy -j ${{ steps.nproc.outputs.nproc }} -p "${BUILD_DIR}" -quiet -fix -allow-no-checks ${TARGETS} 2>&1 | tee "${OUTPUT_FILE}" - - name: Print errors + - name: Print filtered clang-tidy errors if: ${{ steps.run_clang_tidy.outcome != 'success' }} run: | - sed '/error\||/!d' "${OUTPUT_FILE}" + bin/filter-clang-tidy.py "${OUTPUT_FILE}" - name: Upload clang-tidy output if: ${{ github.event.repository.visibility == 'public' && steps.run_clang_tidy.outcome != 'success' }} @@ -148,12 +144,12 @@ jobs: \`\`\` EOF - - name: Append clang-tidy output to issue body (filter for errors and warnings) + - name: Append filtered clang-tidy output to issue body if: ${{ steps.run_clang_tidy.outcome != 'success' }} run: | if [ -f "${OUTPUT_FILE}" ]; then - # Extract lines containing 'error:', 'warning:', or 'note:' - grep -E '(error:|warning:|note:)' "${OUTPUT_FILE}" >"${FILTERED_OUTPUT_FILE}" || true + # Filter to the unique errors with their source context. + bin/filter-clang-tidy.py "${OUTPUT_FILE}" >"${FILTERED_OUTPUT_FILE}" || true # If filtered output is empty, use original (might be a different error format) if [ ! -s "${FILTERED_OUTPUT_FILE}" ]; then diff --git a/.github/workflows/reusable-package.yml b/.github/workflows/reusable-package.yml index 249e807592..6feecbfb75 100644 --- a/.github/workflows/reusable-package.yml +++ b/.github/workflows/reusable-package.yml @@ -30,7 +30,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - name: Set up Python - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 with: python-version: "3.13" diff --git a/.github/workflows/reusable-strategy-matrix.yml b/.github/workflows/reusable-strategy-matrix.yml index c1a1c1a78b..690aa3d423 100644 --- a/.github/workflows/reusable-strategy-matrix.yml +++ b/.github/workflows/reusable-strategy-matrix.yml @@ -26,7 +26,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - name: Set up Python - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 with: python-version: "3.13" diff --git a/.github/workflows/reusable-upload-recipe.yml b/.github/workflows/reusable-upload-recipe.yml index a18f76796a..feeee0a621 100644 --- a/.github/workflows/reusable-upload-recipe.yml +++ b/.github/workflows/reusable-upload-recipe.yml @@ -14,7 +14,7 @@ on: description: "The URL of the Conan endpoint to use." required: false type: string - default: https://conan.ripplex.io + default: https://conan.xrplf.org/repository/conan/ secrets: remote_username: @@ -41,6 +41,10 @@ jobs: upload: runs-on: ubuntu-latest container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-e29b523 + env: + REMOTE_NAME: ${{ inputs.remote_name }} + CONAN_LOGIN_USERNAME_XRPLF: ${{ secrets.remote_username }} + CONAN_PASSWORD_XRPLF: ${{ secrets.remote_password }} steps: - name: Checkout repository uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 @@ -56,15 +60,9 @@ jobs: remote_url: ${{ inputs.remote_url }} - name: Log into Conan remote - env: - REMOTE_NAME: ${{ inputs.remote_name }} - REMOTE_USERNAME: ${{ secrets.remote_username }} - REMOTE_PASSWORD: ${{ secrets.remote_password }} - run: conan remote login "${REMOTE_NAME}" "${REMOTE_USERNAME}" --password "${REMOTE_PASSWORD}" + run: conan remote login "${REMOTE_NAME}" "${CONAN_LOGIN_USERNAME_XRPLF}" --password "${CONAN_PASSWORD_XRPLF}" - name: Upload Conan recipe (version) - env: - REMOTE_NAME: ${{ inputs.remote_name }} run: | conan export . --version=${{ steps.version.outputs.version }} conan upload --confirm --check --remote="${REMOTE_NAME}" xrpl/${{ steps.version.outputs.version }} @@ -73,8 +71,6 @@ jobs: # 'develop' branch, see on-trigger.yml. - name: Upload Conan recipe (develop) if: ${{ github.event_name == 'push' }} - env: - REMOTE_NAME: ${{ inputs.remote_name }} run: | conan export . --version=develop conan upload --confirm --check --remote="${REMOTE_NAME}" xrpl/develop @@ -83,8 +79,6 @@ jobs: # one of the 'release' branches, see on-pr.yml. - name: Upload Conan recipe (rc) if: ${{ github.event_name == 'pull_request' }} - env: - REMOTE_NAME: ${{ inputs.remote_name }} run: | conan export . --version=rc conan upload --confirm --check --remote="${REMOTE_NAME}" xrpl/rc @@ -93,8 +87,6 @@ jobs: # release, see on-tag.yml. - name: Upload Conan recipe (release) if: ${{ startsWith(github.ref, 'refs/tags/') }} - env: - REMOTE_NAME: ${{ inputs.remote_name }} run: | conan export . --version=release conan upload --confirm --check --remote="${REMOTE_NAME}" xrpl/release diff --git a/.github/workflows/upload-conan-deps.yml b/.github/workflows/upload-conan-deps.yml index 5d3712cf9e..22ad36d98f 100644 --- a/.github/workflows/upload-conan-deps.yml +++ b/.github/workflows/upload-conan-deps.yml @@ -34,7 +34,7 @@ on: env: CONAN_REMOTE_NAME: xrplf - CONAN_REMOTE_URL: https://conan.ripplex.io + CONAN_REMOTE_URL: https://conan.xrplf.org/repository/conan/ NPROC_SUBTRACT: 2 concurrency: @@ -68,7 +68,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - name: Prepare runner - uses: XRPLF/actions/prepare-runner@c47daebb2f9db64ffbac71b47d68a661498d5ce8 + uses: XRPLF/actions/prepare-runner@64ec3cf3b152b4444638f470bbd6df7a7a30c81c with: enable_ccache: false @@ -108,10 +108,12 @@ jobs: - name: Log into Conan remote if: ${{ github.repository == 'XRPLF/rippled' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') }} - run: conan remote login "${CONAN_REMOTE_NAME}" "${{ secrets.CONAN_REMOTE_USERNAME }}" --password "${{ secrets.CONAN_REMOTE_PASSWORD }}" + run: conan remote login "${CONAN_REMOTE_NAME}" "${{ secrets.NEXUS_REMOTE_USERNAME }}" --password "${{ secrets.NEXUS_REMOTE_PASSWORD }}" - name: Upload Conan packages if: ${{ github.repository == 'XRPLF/rippled' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') }} env: FORCE_OPTION: ${{ github.event.inputs.force_upload == 'true' && '--force' || '' }} + CONAN_LOGIN_USERNAME_XRPLF: ${{ secrets.NEXUS_REMOTE_USERNAME }} + CONAN_PASSWORD_XRPLF: ${{ secrets.NEXUS_REMOTE_PASSWORD }} run: conan upload "*" --remote="${CONAN_REMOTE_NAME}" --confirm ${FORCE_OPTION} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4cbf4c1dd0..d3bf0209fb 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -28,8 +28,10 @@ repos: entry: ./bin/pre-commit/clang_tidy_check.py language: python types_or: [c++, c] - exclude: ^include/xrpl/protocol_autogen - pass_filenames: false # script determines the staged files itself + # .ipp fragments are included by their owning header rather than compiled + # as standalone translation units, so they have no compile_commands.json + # entry to lint (verify_headers checks them transitively). + exclude: '^include/xrpl/protocol_autogen|\.ipp$' - id: fix-include-style name: fix include style entry: ./bin/pre-commit/fix_include_style.py @@ -41,6 +43,11 @@ repos: language: python entry: ./bin/pre-commit/fix_pragma_once.py files: \.(h|hpp)$ + - id: check-doxygen-style + name: check Doxygen comment style + entry: ./bin/pre-commit/check_doxygen_style.py + language: python + types_or: [c++, c] - repo: https://github.com/pre-commit/mirrors-clang-format rev: dd18dad857d6133e90bbe478f4f2f22ec0030269 # frozen: v22.1.5 @@ -51,12 +58,12 @@ repos: exclude: ^include/xrpl/protocol_autogen/(transactions|ledger_entries)/ - repo: https://github.com/BlankSpruce/gersemi-pre-commit - rev: faadd6a9d852369ca94f4d15b2404c967ba8cb01 # frozen: 0.27.6 + rev: e98930bdc210d3387007f9252d8c1694ea7e410f # frozen: 0.27.7 hooks: - id: gersemi - repo: https://github.com/rbubley/mirrors-prettier - rev: 515f543f5718ebfd6ce22e16708bb32c68ff96e1 # frozen: v3.8.3 + rev: 39e2973981e6d2f9b6c543b0086a2d2393abdc89 # frozen: v3.9.4 hooks: - id: prettier args: [--end-of-line=auto] @@ -86,22 +93,21 @@ repos: files: \.md$ - repo: https://github.com/streetsidesoftware/cspell-cli - rev: 4643f154907327ee0a2c7038f0296e0dd77d9776 # frozen: v10.0.0 + rev: ea11f9efc0bec520073405bc30552da887ba71bc # frozen: v10.0.1 hooks: - - id: cspell # Spell check changed files + - id: cspell + name: check changed files spelling exclude: | (?x)^( - .config/cspell.config.yaml| + \.cspell\.config\.yaml| include/xrpl/protocol_autogen/(transactions|ledger_entries)/.* )$ - - id: cspell # Spell check the commit message + - id: cspell name: check commit message spelling args: - --no-must-find-files - --no-progress - --no-summary - - --files - - .git/COMMIT_EDITMSG stages: [commit-msg] - repo: local diff --git a/BUILD.md b/BUILD.md index 2ac24f2c5d..a15c94edc9 100644 --- a/BUILD.md +++ b/BUILD.md @@ -25,7 +25,7 @@ You can verify that the required tools are installed and runnable with: | ----------- | --------------- | | GCC | 15.2 | | Clang | 22 | -| Apple Clang | 17 | +| Apple Clang | 21 | | MSVC | 19.44[^windows] | ## Operating Systems @@ -101,7 +101,7 @@ More information on customizing Conan can be found in the [Advanced Conan config Run the following command to add the `xrplf` remote, which hosts some of our dependencies: ```bash -conan remote add --index 0 --force xrplf https://conan.ripplex.io +conan remote add --index 0 --force xrplf https://conan.xrplf.org/repository/conan/ ``` ### Set Up Ccache @@ -317,21 +317,41 @@ See [Sanitizers docs](./docs/build/sanitizers.md) for more details. ## Options -| Option | Default Value | Description | -| ---------- | ------------- | -------------------------------------------------------------- | -| `assert` | OFF | Force enabling assertions. | -| `coverage` | OFF | Prepare the coverage report. | -| `tests` | OFF | Build tests. | -| `unity` | OFF | Configure a unity build. | -| `xrpld` | OFF | Build the xrpld application, and not just the libxrpl library. | -| `werr` | OFF | Treat compilation warnings as errors | -| `wextra` | OFF | Enable additional compilation warnings | +| Option | Default Value | Description | +| ---------------- | ------------- | ----------------------------------------------------------------------------- | +| `assert` | OFF | Force enabling assertions. | +| `coverage` | OFF | Prepare the coverage report. | +| `tests` | OFF | Build tests. | +| `unity` | OFF | Configure a unity build. | +| `verify_headers` | ON | Make the `verify-headers` target available to compile each header on its own. | +| `xrpld` | OFF | Build the xrpld application, and not just the libxrpl library. | +| `werr` | OFF | Treat compilation warnings as errors | +| `wextra` | OFF | Enable additional compilation warnings | [Unity builds][unity-build] may be faster for the first build (at the cost of much more memory) since they concatenate sources into fewer translation units. Non-unity builds may be faster for incremental builds, and can be helpful for detecting `#include` omissions. +### Verifying headers + +The regular build only compiles `.cpp` files, so a header is only ever checked +through whatever translation unit happens to include it. A header that forgets +an `#include` is not caught as long as every `.cpp` that uses it includes its +missing dependency first. The `verify_headers` option (ON by default) adds a +`verify-headers` target that compiles every header on its own, which fails if a +header is not self-contained: + +```bash +cmake --build . --target verify-headers +``` + +The per-header objects are excluded from the `all` target, so a normal build +never compiles them; they are built only through `verify-headers`. The generated +translation units do appear in `compile_commands.json`, so clang-tidy (and +clangd and IDEs) can lint each header on its own. Pass `-Dverify_headers=OFF` to +omit them entirely. + ## Troubleshooting ### Conan diff --git a/CMakeLists.txt b/CMakeLists.txt index bdc62442b3..1e8befcc8f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -90,6 +90,7 @@ find_package(ed25519 REQUIRED) find_package(gRPC REQUIRED) find_package(LibArchive REQUIRED) find_package(lz4 REQUIRED) +find_package(mpt-crypto REQUIRED) find_package(nudb REQUIRED) find_package(OpenSSL REQUIRED) find_package(secp256k1 REQUIRED) @@ -102,6 +103,7 @@ target_link_libraries( INTERFACE ed25519::ed25519 lz4::lz4 + mpt-crypto::mpt-crypto OpenSSL::Crypto OpenSSL::SSL secp256k1::secp256k1 diff --git a/bin/filter-clang-tidy.py b/bin/filter-clang-tidy.py new file mode 100755 index 0000000000..204a4e36f3 --- /dev/null +++ b/bin/filter-clang-tidy.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python3 + +""" +Reduce run-clang-tidy output to its unique errors. + +It does two things: + + 1. Filters the raw output down to diagnostics and their source-context lines + (the indented " 103 | ..." / " | ^" lines clang-tidy prints), + matching the "path:line:col: error:" diagnostic shape. + + 2. Deduplicates. The same diagnostic in a header is reported once per + translation unit that includes it, so identical error blocks are collapsed + to their first occurrence. + +An "error block" is an "error:" line together with the indented context lines +and any "note:" lines that follow it (up to the next "error:" line). Blocks are +compared as a whole, so an error stays attached to its own context, and +first-occurrence order is preserved. + +The deduplicated output goes to stdout; a summary of unique error counts per +check is printed to stderr. + +Usage: + bin/filter-clang-tidy.py [INPUT_FILE] # read from file, or + run-clang-tidy ... | bin/filter-clang-tidy.py # read from stdin +""" + +import re +import sys +from collections import Counter + +# A clang-tidy diagnostic line looks like "path:line:col: error: msg [check]". +# Matching on that shape (rather than a loose "error" substring) avoids treating +# progress lines whose paths contain "error" as diagnostics, e.g. +# [284/850][0.7s] /nix/.../clang-tidy ... src/.../error.cpp +DIAG_RE = re.compile(r":\d+:\d+: (?:error|warning|note):") +ERROR_RE = re.compile(r":\d+:\d+: error:") +CHECK_RE = re.compile(r" error: .*\[([^\],]+)") + + +def filter_and_dedup(lines: list[str]) -> list[str]: + """Keep diagnostics with their context, then drop duplicate error blocks.""" + blocks: list[str] = [] + seen: set[str] = set() + current: list[str] = [] + + def flush() -> None: + if not current: + return + block = "".join(current) + if block not in seen: + seen.add(block) + blocks.append(block) + + for line in lines: + # Keep only diagnostics and their indented source-context lines; drop + # progress/status output and blank lines. + if not (DIAG_RE.search(line) or line[:1] in (" ", "\t")): + continue + # An "error:" line starts a new block; its context and any following + # "note:" lines (and their context) belong to it. + if ERROR_RE.search(line): + flush() + current = [] + current.append(line) + flush() + + return blocks + + +def summarize(blocks: list[str]) -> Counter[str]: + """Count unique errors per check name (e.g. "bugprone-branch-clone").""" + counts: Counter[str] = Counter() + for block in blocks: + # The error line is the first line of the block. + match = CHECK_RE.search(block.splitlines()[0]) + if match: + counts[match.group(1)] += 1 + return counts + + +def main() -> int: + if len(sys.argv) > 1 and sys.argv[1] != "-": + with open(sys.argv[1], encoding="utf-8") as f: + lines = f.readlines() + else: + lines = sys.stdin.readlines() + + blocks = filter_and_dedup(lines) + # Blank line between blocks so distinct errors are easy to tell apart. + sys.stdout.write("\n".join(blocks)) + + print("\nUnique errors per check:", file=sys.stderr) + for check, count in summarize(blocks).most_common(): + print(f"{count:>4} {check}", file=sys.stderr) + + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/bin/pre-commit/check_doxygen_style.py b/bin/pre-commit/check_doxygen_style.py new file mode 100755 index 0000000000..6a9af9399f --- /dev/null +++ b/bin/pre-commit/check_doxygen_style.py @@ -0,0 +1,440 @@ +#!/usr/bin/env python3 +""" +Check C++ Doxygen comment style. + +Enforces the house convention for documentation comments: + + * Use ``/** ... */`` blocks, not ``///``, ``//!`` or ``/*! ... */``; a plain + ``/* ... */`` that contains Doxygen commands is a doc comment missing its + second star. Trailing member-after comments use ``///<`` (not ``//!<``, + ``/*!< ... */`` or ``/**< ... */`` -- the block forms get reflowed and + mis-attached by clang-format on packed enum values, the line form does not). + * ``/**`` sits alone on its line; the closing ``*/`` sits alone on its line. + * Every content line is prefixed with `` * `` (no bare-indented continuation). + * The first content line is flush (not over-indented). + * Doxygen commands use the ``@cmd`` form, not ``\\cmd``. + * Use ``@return`` / ``@throws`` rather than prose ``Returns:`` / ``Throws:``. + * A plain ``//`` comment carrying a block-level ``@command`` (``@param``, + ``@return``, ``@see``, ...) is documentation and must be a ``/** ... */`` + block (Doxygen ignores ``//``). + * Use canonical command spellings: ``@return`` (not ``@returns``), + ``@throws`` (not ``@throw``), ``@see`` (not ``@sa``). + * Order block tags ``@tparam`` -> ``@param`` -> ``@return``. (Whether + ``@param`` order matches the signature is not checked here -- too fragile to + parse; Doxygen's WARN_IF_DOC_ERROR covers name mismatches.) + * One-liners are expanded to three lines, EXCEPT bare markers ``@{`` / ``@}`` + / ``@cond [label]`` / ``@endcond`` / ``@file [name]`` which stay on one line. + +Left intentionally alone (recognized, valid Doxygen that is not this style's +concern): + + * ``///<`` trailing "member-after" comments (the house form). + * Divider lines made only of slashes (``//////////``). + * Plain ``/* ... */`` (non-Doxygen) comments. + +Usage: + check_doxygen_style.py [FILE ...] # explicit files + check_doxygen_style.py # default: src/ and include/ trees + +Exit status is non-zero if any violation is found. +""" + +import argparse +import re +import sys +from collections.abc import Iterable, Iterator +from dataclasses import dataclass +from enum import Enum +from pathlib import Path + + +class Category(Enum): + """A kind of style violation: a printed ``label`` and its ``description``. + + The description is the default message; a few categories whose wording + depends on the offending text (see ``Finding.detail``) override it. + """ + + def __init__(self, label: str, description: str) -> None: + self.label = label + self.description = description + + BACKSLASH_COMMAND = ("backslash-command", "use the @cmd form, not \\cmd") + WRONG_COMMAND = ("wrong-command", "use the canonical command spelling") + TRIPLE_SLASH = ("triple-slash", "use a /** ... */ block instead of ///") + QT_MEMBER = ("qt-member", "use ///< instead of //!<") + QT_LINE = ("qt-line", "use a /** ... */ block instead of //!") + BLOCK_MEMBER = ("block-member", "use ///< instead of /**<") + QT_BLOCK_MEMBER = ("qt-block-member", "use ///< instead of /*!<") + DOC_IN_LINE_COMMENT = ( + "doc-in-line-comment", + "use a /** ... */ block for documentation, not //", + ) + QT_COMMENT = ("qt-comment", "use /** instead of /*!") + SINGLE_LINE_BLOCK = ( + "single-line-block", + "expand one-line /** ... */ to a multi-line block " + "(markers @{ @} @cond @endcond @file may stay)", + ) + TEXT_ON_OPENER = ("text-on-opener", "move text off the /** opener line") + BARE_CONTINUATION = ("bare-continuation", 'prefix continuation lines with " * "') + OVER_INDENTED = ("over-indented", "first content line is over-indented") + OVER_INDENTED_TAG = ( + "over-indented-tag", + 'Doxygen tag over-indented; use a single space after "*"', + ) + COMBINED_MARKER = ( + "combined-marker", + "scope marker @{ / @} should be its own single-line /** @{ */ block", + ) + PROSE_LABEL = ("prose-label", "use a Doxygen tag instead of a prose label") + CONTENT_ON_CLOSER = ("content-on-closer", "move content off the closing */ line") + PLAIN_BLOCK_DOC = ( + "plain-block-doc", + "documentation comment must open with /** not /*", + ) + TAG_ORDER = ( + "tag-order", + "block tags out of order; expected @tparam, then @param, then @return", + ) + + +@dataclass(frozen=True) +class Finding: + """A single style violation at a 1-based line number. + + ``detail`` overrides the category's default description when the message + depends on the offending text (e.g. which command was misspelled). + """ + + line: int + category: Category + detail: str | None = None + + @property + def message(self) -> str: + return self.detail if self.detail is not None else self.category.description + + +DEFAULT_ROOTS = ("src", "include") +EXTS = {".h", ".hpp", ".cpp", ".ipp", ".cxx", ".cc"} + +# Every Doxygen command we recognize when written with a backslash (\cmd). +_ALL_COMMANDS = ( + "brief|param|tparam|return|returns|retval|note|warning|pre|post|see|sa|ref|" + "throw|throws|exception|deprecated|details|code|endcode|verbatim|endverbatim|" + "li|arg|c|internal|since|todo|attention|remark|remarks|ingroup|defgroup" +) +# Block-level tags whose over-indentation we flag inside a block body. +_BLOCK_TAGS = ( + "param|tparam|returns?|retval|brief|throws?|note|warning|" + "pre|post|see|sa|details|deprecated" +) +# Tags that, appearing anywhere in a comment, mark it as documentation. +_ANY_DOC_TAGS = ( + "param|tparam|returns?|retval|brief|throws?|note|warning|pre|post|see|sa" +) +# Tags that make a plain // comment a mis-styled doc comment. +_LINE_DOC_TAGS = "brief|param|tparam|returns?|retval|throws?|note|see|pre|post" + +# \cmd that should be @cmd. +RE_BACKSLASH_CMD = re.compile(r"\\(" + _ALL_COMMANDS + r")\b") +# Bare markers that may legitimately stay on a single line. +RE_MARKER = re.compile(r"^@(\{|\}|cond(\s.*)?|endcond|file(\s.*)?)$") +# Prose section labels that should be Doxygen tags. +RE_PROSE_LABEL = re.compile(r"^\*\s(Returns|Throws|Exceptions):\s*$") +# An over-indented block tag: "*" followed by 2+ spaces then the tag. +RE_OVERINDENTED_TAG = re.compile(r"^\*\s{2,}@(" + _BLOCK_TAGS + r")\b") +# Any documentation tag (used to spot a doc comment hiding in a plain /* */). +RE_ANY_DOC_TAG = re.compile(r"@(" + _ANY_DOC_TAGS + r")\b") +# A documentation tag inside a // comment. +RE_LINE_DOC_TAG = re.compile(r"@(" + _LINE_DOC_TAGS + r")\b") +# Order-relevant tags, for the @tparam -> @param -> @return ordering check. +RE_ORDER_TAG = re.compile(r"^\*\s*@(param|tparam|returns?|retval)\b") +# First content line indented by 2+ spaces after the "*". +RE_FIRST_OVERINDENT = re.compile(r"^\s*\*\s{2,}\S") +# A scope marker @{ / @} sharing a comment with other text. +RE_COMBINED_MARKER = re.compile(r"^\*\s*@[{}]\s*$") + +# Non-canonical command spellings -> the house spelling (bare command names). +# Used both to flag a wrong @form and to suggest the right @form for a \wrong. +CANONICAL_COMMAND = {"returns": "return", "throw": "throws", "sa": "see"} +WRONG_SPELLINGS = [ + (re.compile(rf"@{wrong}\b"), f"@{right}") + for wrong, right in CANONICAL_COMMAND.items() +] + +# Order block tags should appear in; a body out of this order is a violation. +EXPECTED_TAG_ORDER = ("tparam", "param", "return") + + +def is_doxy_open(stripped: str) -> bool: + """True for a line-start Doxygen block opener we should normalize.""" + if stripped.startswith("/*!"): # Qt-style Doxygen + return not stripped.startswith("/*!<") # member-after, leave inline + return ( + stripped.startswith("/**") + and not stripped.startswith("/***") + and not stripped.startswith("/**/") + and not stripped.startswith("/**<") + ) + + +def _flag_commands(raw_line: str, stripped: str, index: int) -> list[Finding]: + """Flag \\cmd and misspelled @cmd on a comment line (opener, body, or closer).""" + if not stripped.startswith(("*", "//", "/*")): + return [] + findings: list[Finding] = [] + backslash = RE_BACKSLASH_CMD.search(raw_line) + if backslash: + command = backslash.group(1) + canonical = CANONICAL_COMMAND.get(command, command) + findings.append( + Finding( + index + 1, + Category.BACKSLASH_COMMAND, + f"use @{canonical} instead of \\{command}", + ) + ) + for pattern, replacement in WRONG_SPELLINGS: + wrong = pattern.search(raw_line) + if wrong: + findings.append( + Finding( + index + 1, + Category.WRONG_COMMAND, + f"use {replacement} instead of {wrong.group(0)}", + ) + ) + return findings + + +def _flag_line_comment(raw_line: str, stripped: str, index: int) -> Finding | None: + """Return the finding for a single-line comment form (///, //!, /**<, ...), else None.""" + if stripped.startswith("///") and not stripped.startswith(("////", "///<")): + return Finding(index + 1, Category.TRIPLE_SLASH) + if "//!<" in raw_line: + return Finding(index + 1, Category.QT_MEMBER) + if stripped.startswith("//!"): + return Finding(index + 1, Category.QT_LINE) + if "/**<" in raw_line: + return Finding(index + 1, Category.BLOCK_MEMBER) + if "/*!<" in raw_line: + return Finding(index + 1, Category.QT_BLOCK_MEMBER) + if stripped.startswith("//") and RE_LINE_DOC_TAG.search(stripped): + return Finding(index + 1, Category.DOC_IN_LINE_COMMENT) + return None + + +def _flag_single_line_block(stripped: str, line_no: int, is_qt: bool) -> list[Finding]: + """Findings for a whole /** ... */ or /*! ... */ block on one line.""" + inner = re.sub(r"^/\*[*!]", "", stripped) + inner = re.sub(r"\*/\s*$", "", inner).strip() + findings: list[Finding] = [] + if is_qt: + findings.append(Finding(line_no, Category.QT_COMMENT)) + if inner and not RE_MARKER.match(inner): + findings.append(Finding(line_no, Category.SINGLE_LINE_BLOCK)) + return findings + + +def _canonical_order_tag(body: str) -> str | None: + """The order-relevant tag (tparam/param/return) a body line opens with, if any.""" + match = RE_ORDER_TAG.match(body) + if match is None: + return None + command = match.group(1) + return "return" if command in ("return", "returns", "retval") else command + + +def _flag_body_line( + body_line: str, line_no: int, is_first_content: bool +) -> list[Finding]: + """Findings for one interior line of a multi-line block.""" + body = body_line.strip() + findings: list[Finding] = [] + if body and not body.startswith("*"): + findings.append(Finding(line_no, Category.BARE_CONTINUATION)) + if body.startswith("*"): + if is_first_content and RE_FIRST_OVERINDENT.match(body_line): + findings.append(Finding(line_no, Category.OVER_INDENTED)) + if RE_OVERINDENTED_TAG.match(body): + findings.append(Finding(line_no, Category.OVER_INDENTED_TAG)) + if RE_COMBINED_MARKER.match(body): + findings.append(Finding(line_no, Category.COMBINED_MARKER)) + label = RE_PROSE_LABEL.match(body) + if label: + suggested_tag = "@return" if label.group(1) == "Returns" else "@throws" + findings.append( + Finding( + line_no, + Category.PROSE_LABEL, + f'use {suggested_tag} instead of prose "{label.group(1)}:"', + ) + ) + return findings + + +def _flag_closer(closer_line: str, line_no: int) -> list[Finding]: + """Findings for content sharing the closing */ line.""" + before = closer_line[: closer_line.index("*/")].strip() + if before and before != "*": + return [Finding(line_no, Category.CONTENT_ON_CLOSER)] + return [] + + +def _flag_tag_order(first_tag_line: dict[str, int]) -> list[Finding]: + """One finding if the present block tags are not in EXPECTED_TAG_ORDER.""" + tag_lines = [ + first_tag_line[tag] for tag in EXPECTED_TAG_ORDER if tag in first_tag_line + ] + if tag_lines != sorted(tag_lines): + return [Finding(min(tag_lines), Category.TAG_ORDER)] + return [] + + +def _flag_doxy_block(lines: list[str], start: int) -> tuple[int, list[Finding]]: + """Handle a /** or /*! block opening at ``start``; return (next index, findings).""" + raw_line = lines[start] + stripped = raw_line.lstrip() + open_pos = raw_line.index("/*") + is_qt = stripped.startswith("/*!") + + # A whole block on one line: /** ... */. + if "*/" in raw_line[open_pos + 2 :]: + return start + 1, _flag_single_line_block(stripped, start + 1, is_qt) + + # Multi-line block: opener, then scan the body to the closer. + findings: list[Finding] = [] + if is_qt: + findings.append(Finding(start + 1, Category.QT_COMMENT)) + if raw_line[open_pos + 3 :].strip(): + findings.append(Finding(start + 1, Category.TEXT_ON_OPENER)) + + line_count = len(lines) + cursor = start + 1 + is_first_content = True + first_tag_line: dict[str, int] = {} # canonical tag -> 1-based first line + while cursor < line_count and "*/" not in lines[cursor]: + body_line = lines[cursor] + body = body_line.strip() + findings.extend(_flag_commands(body_line, body, cursor)) + tag = _canonical_order_tag(body) + if tag is not None: + first_tag_line.setdefault(tag, cursor + 1) + findings.extend(_flag_body_line(body_line, cursor + 1, is_first_content)) + if body.startswith("*"): + is_first_content = False + cursor += 1 + + if cursor < line_count: + closer_line = lines[cursor] + findings.extend(_flag_commands(closer_line, closer_line.strip(), cursor)) + findings.extend(_flag_closer(closer_line, cursor + 1)) + findings.extend(_flag_tag_order(first_tag_line)) + + return cursor + 1, findings + + +def _flag_plain_block(lines: list[str], start: int) -> tuple[int, list[Finding]]: + """Handle a line-start plain /* ... */ block; return (next index, findings). + + Only flagged when it hides a documentation command (a missing second star). + """ + line_count = len(lines) + cursor = start + while cursor < line_count and "*/" not in lines[cursor]: + cursor += 1 + findings: list[Finding] = [] + # The opener (start) is command-checked by check_file; check the rest here. + for i in range(start + 1, min(cursor + 1, line_count)): + findings.extend(_flag_commands(lines[i], lines[i].strip(), i)) + block_text = "\n".join( + lines[start : cursor + 1] if cursor < line_count else lines[start:] + ) + if RE_ANY_DOC_TAG.search(block_text): + findings.append(Finding(start + 1, Category.PLAIN_BLOCK_DOC)) + next_index = cursor + 1 if cursor < line_count else line_count + return next_index, findings + + +def check_source(text: str) -> list[Finding]: + """Return all style violations found in the given source text.""" + lines = text.split("\n") + findings: list[Finding] = [] + line_count = len(lines) + index = 0 + in_plain_block = False # inside a mid-line, non-Doxygen /* ... */ + while index < line_count: + raw_line = lines[index] + stripped = raw_line.lstrip() + + # Skip the interior of a plain block opened on an earlier line. + if in_plain_block: + in_plain_block = "*/" not in raw_line + index += 1 + continue + + findings.extend(_flag_commands(raw_line, stripped, index)) + + line_finding = _flag_line_comment(raw_line, stripped, index) + if line_finding is not None: + findings.append(line_finding) + index += 1 + elif is_doxy_open(stripped): + index, block_findings = _flag_doxy_block(lines, index) + findings.extend(block_findings) + elif stripped.startswith("/*"): + index, block_findings = _flag_plain_block(lines, index) + findings.extend(block_findings) + else: + # A /* that opens mid-line without closing starts a plain block. + if "/*" in raw_line and not stripped.startswith("//"): + if "*/" not in raw_line[raw_line.index("/*") + 2 :]: + in_plain_block = True + index += 1 + return findings + + +def check_file(path: Path) -> list[Finding]: + """Return all style violations found in one file.""" + return check_source(path.read_text(encoding="utf-8")) + + +def iter_files(paths: Iterable[str]) -> Iterator[Path]: + """Yield every C++ source file among the given files and directories.""" + for raw_path in paths: + path = Path(raw_path) + if path.is_dir(): + for candidate in path.rglob("*"): + if candidate.is_file() and candidate.suffix in EXTS: + yield candidate + elif path.suffix in EXTS: + yield path + + +def main() -> int: + parser = argparse.ArgumentParser(description="Check Doxygen comment style.") + parser.add_argument( + "files", nargs="*", help="files or directories (default: src/ include/)" + ) + parser.add_argument( + "-q", "--quiet", action="store_true", help="only print the summary count" + ) + args = parser.parse_args() + roots = args.files or [root for root in DEFAULT_ROOTS if Path(root).is_dir()] + + total = 0 + for path in sorted(set(iter_files(roots)), key=str): + for finding in check_file(path): + total += 1 + if not args.quiet: + print( + f"{path}:{finding.line}: {finding.category.label}: {finding.message}" + ) + print(f"\n{total} doxygen-style violation(s)", file=sys.stderr) + return 1 if total else 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/bin/pre-commit/clang_tidy_check.py b/bin/pre-commit/clang_tidy_check.py index f134660671..5b5792b405 100755 --- a/bin/pre-commit/clang_tidy_check.py +++ b/bin/pre-commit/clang_tidy_check.py @@ -1,24 +1,27 @@ #!/usr/bin/env python3 -"""Pre-commit hook that runs clang-tidy on changed files using run-clang-tidy.""" +"""Pre-commit hook that runs clang-tidy on changed files using run-clang-tidy. + +The set of files is chosen by pre-commit (see .pre-commit-config.yaml), which +filters to C/C++ sources and excludes `.ipp` fragments. Headers are linted +directly: the `verify_headers` build option (ON by default) compiles every +`.h`/`.hpp` on its own, so each header is the main file of its own +compile_commands.json entry and run-clang-tidy can analyse it just like a +`.cpp`. +""" from __future__ import annotations -import json import os -import re import shutil import subprocess import sys -from collections import defaultdict from pathlib import Path -HEADER_EXTENSIONS = {".h", ".hpp", ".ipp"} -SOURCE_EXTENSIONS = {".cpp"} -INCLUDE_RE = re.compile(r"^\s*#\s*include\s*[<\"]([^>\"]+)[>\"]") +CLANG_TIDY_VERSION = 22 def find_run_clang_tidy() -> str | None: - for candidate in ("run-clang-tidy-21", "run-clang-tidy"): + for candidate in (f"run-clang-tidy-{CLANG_TIDY_VERSION}", "run-clang-tidy"): if path := shutil.which(candidate): return path return None @@ -32,142 +35,23 @@ def find_build_dir(repo_root: Path) -> Path | None: return None -def build_include_graph(build_dir: Path, repo_root: Path) -> tuple[dict, set]: - """ - Scan all files reachable from compile_commands.json and build an inverted include graph. - - Returns: - inverted: header_path -> set of files that include it - source_files: set of all TU paths from compile_commands.json - """ - with open(build_dir / "compile_commands.json") as f: - db = json.load(f) - - source_files = {Path(e["file"]).resolve() for e in db} - include_roots = [repo_root / "include", repo_root / "src"] - inverted: dict[Path, set[Path]] = defaultdict(set) - - to_scan: set[Path] = set(source_files) - scanned: set[Path] = set() - - while to_scan: - file = to_scan.pop() - if file in scanned or not file.exists(): - continue - scanned.add(file) - - content = file.read_text() - - for line in content.splitlines(): - m = INCLUDE_RE.match(line) - if not m: - continue - for root in include_roots: - candidate = (root / m.group(1)).resolve() - if candidate.exists(): - inverted[candidate].add(file) - if candidate not in scanned: - to_scan.add(candidate) - break - - return inverted, source_files - - -def find_tus_for_headers( - headers: list[Path], - inverted: dict[Path, set[Path]], - source_files: set[Path], -) -> set[Path]: - """ - For each header, pick one TU that transitively includes it. - Prefers a TU whose stem matches the header's stem, otherwise picks the first found. - """ - result: set[Path] = set() - - for header in headers: - preferred: Path | None = None - visited: set[Path] = {header} - stack: list[Path] = [header] - - while stack: - h = stack.pop() - for inc in inverted.get(h, ()): - if inc in source_files: - if inc.stem == header.stem: - preferred = inc - break - if preferred is None: - preferred = inc - if inc not in visited: - visited.add(inc) - stack.append(inc) - if preferred is not None and preferred.stem == header.stem: - break - - if preferred is not None: - result.add(preferred) - - return result - - -def resolve_files( - input_files: list[str], build_dir: Path, repo_root: Path -) -> list[str]: - """ - Split input into source files and headers. Source files are passed through; - headers are resolved to the TUs that transitively include them. - """ - sources: list[Path] = [] - headers: list[Path] = [] - - for f in input_files: - p = Path(f).resolve() - if p.suffix in SOURCE_EXTENSIONS: - sources.append(p) - elif p.suffix in HEADER_EXTENSIONS: - headers.append(p) - - if not headers: - return [str(p) for p in sources] - - print( - f"Resolving {len(headers)} header(s) to compilation units...", file=sys.stderr - ) - inverted, source_files = build_include_graph(build_dir, repo_root) - tus = find_tus_for_headers(headers, inverted, source_files) - - if not tus: - print( - "Warning: no compilation units found that include the modified headers; " - "skipping clang-tidy for headers.", - file=sys.stderr, - ) - - return sorted({str(p) for p in (*sources, *tus)}) - - -def staged_files(repo_root: Path) -> list[str]: - result = subprocess.run( - ["git", "diff", "--staged", "--name-only", "--diff-filter=d"], - capture_output=True, - text=True, - cwd=repo_root, - ) - if result.returncode != 0: - print( - "clang-tidy check failed: 'git diff --staged' command failed.", - file=sys.stderr, - ) - if result.stderr: - print(result.stderr, file=sys.stderr) - sys.exit(result.returncode or 1) - return [str(repo_root / p) for p in result.stdout.splitlines() if p] - - def main(): if not os.environ.get("TIDY"): return 0 + files = sys.argv[1:] + if not files: + return 0 + + run_clang_tidy = find_run_clang_tidy() + if not run_clang_tidy: + print( + f"clang-tidy check failed: TIDY is enabled but neither " + f"'run-clang-tidy-{CLANG_TIDY_VERSION}' nor 'run-clang-tidy' was found in PATH.", + file=sys.stderr, + ) + return 1 + repo_root = Path( subprocess.check_output( ["git", "rev-parse", "--show-toplevel"], @@ -175,19 +59,6 @@ def main(): text=True, ).strip() ) - files = staged_files(repo_root) - if not files: - return 0 - - run_clang_tidy = find_run_clang_tidy() - if not run_clang_tidy: - print( - "clang-tidy check failed: TIDY is enabled but neither " - "'run-clang-tidy-21' nor 'run-clang-tidy' was found in PATH.", - file=sys.stderr, - ) - return 1 - build_dir = find_build_dir(repo_root) if not build_dir: print( @@ -197,13 +68,9 @@ def main(): ) return 1 - tidy_files = resolve_files(files, build_dir, repo_root) - if not tidy_files: - return 0 - result = subprocess.run( [run_clang_tidy, "-quiet", "-p", str(build_dir), "-fix", "-allow-no-checks"] - + tidy_files + + files ) return result.returncode diff --git a/bin/pre-commit/test_check_doxygen_style.py b/bin/pre-commit/test_check_doxygen_style.py new file mode 100755 index 0000000000..861414f46d --- /dev/null +++ b/bin/pre-commit/test_check_doxygen_style.py @@ -0,0 +1,406 @@ +#!/usr/bin/env python3 +""" +Tests for check_doxygen_style.py. + +Run directly (no test framework needed): + ./bin/pre-commit/test_check_doxygen_style.py +or under pytest: + pytest bin/pre-commit/test_check_doxygen_style.py +""" + +import sys +import textwrap + +from check_doxygen_style import Finding, check_source + + +def findings_for(text: str) -> list[Finding]: + """Return the style violations for the given source text. + + The text is dedented and its leading newline stripped, so fixtures can be + written as indented triple-quoted here-docs while keeping honest 1-based + line numbers. + """ + text = textwrap.dedent(text).lstrip("\n") + return check_source(text) + + +def labels_for(text: str) -> list[str]: + return [f.category.label for f in findings_for(text)] + + +def messages_for(text: str) -> list[str]: + return [f.message for f in findings_for(text)] + + +# --- well-formed input produces nothing ------------------------------------- + + +def test_clean_block_ok() -> None: + code = """ + /** + * Brief. + * + * @tparam T a type + * @param x the x + * @return the result + */ + """ + assert findings_for(code) == [] + + +def test_blank_lines_inside_block_ok() -> None: + code = """ + /** + * a + * + * b + */ + """ + assert findings_for(code) == [] + + +def test_member_and_divider_allowed() -> None: + assert findings_for("int x; ///< ok member\n") == [] + assert findings_for("//////////\n") == [] + assert findings_for("//// text\n") == [] + + +# --- line-comment forms ------------------------------------------------------ + + +def test_triple_slash() -> None: + code = "/// doc\n" + assert labels_for(code) == ["triple-slash"] + + +def test_qt_line() -> None: + code = "//! doc\n" + assert labels_for(code) == ["qt-line"] + + +def test_qt_member() -> None: + code = "int x; //!< doc\n" + assert labels_for(code) == ["qt-member"] + + +def test_block_member() -> None: + code = "int x; /**< doc */\n" + assert labels_for(code) == ["block-member"] + + +def test_qt_block_member() -> None: + code = "int x; /*!< doc */\n" + assert labels_for(code) == ["qt-block-member"] + + +def test_doc_in_line_comment() -> None: + code = "// @param x\n" + assert labels_for(code) == ["doc-in-line-comment"] + + +# --- block forms ------------------------------------------------------------- + + +def test_qt_comment() -> None: + code = """ + /*! + * brief + */ + """ + assert labels_for(code) == ["qt-comment"] + + +def test_qt_comment_single_line() -> None: + # /*! ... */ on one line -> qt-comment (plus single-line-block) + code = "/*! brief */\n" + assert labels_for(code) == ["qt-comment", "single-line-block"] + + +def test_single_line_block() -> None: + code = "/** brief */\n" + assert labels_for(code) == ["single-line-block"] + + +def test_single_line_markers_allowed() -> None: + for marker in ("@{", "@}", "@cond LABEL", "@endcond", "@file foo.h"): + code = f"/** {marker} */\n" + assert findings_for(code) == [], marker + + +def test_text_on_opener() -> None: + code = """ + /** text here + * more + */ + """ + assert labels_for(code) == ["text-on-opener"] + + +def test_bare_continuation() -> None: + code = """ + /** + * a + bare line + */ + """ + assert labels_for(code) == ["bare-continuation"] + + +def test_over_indented_first_line() -> None: + code = """ + /** + * over + */ + """ + assert labels_for(code) == ["over-indented"] + + +def test_over_indented_tag() -> None: + # a flush first line consumes "first content", isolating the tag check + code = """ + /** + * brief + * @param x + */ + """ + assert labels_for(code) == ["over-indented-tag"] + + +def test_combined_marker() -> None: + code = """ + /** + * @{ + */ + """ + assert labels_for(code) == ["combined-marker"] + + +def test_prose_label() -> None: + for word in ("Returns", "Throws", "Exceptions"): + code = f""" + /** + * {word}: + */ + """ + assert labels_for(code) == ["prose-label"], word + + +def test_content_on_closer() -> None: + code = """ + /** + * a + * b */ + """ + assert labels_for(code) == ["content-on-closer"] + + +def test_plain_block_doc() -> None: + assert labels_for("/* @param x */\n") == ["plain-block-doc"] + assert findings_for("/* just an ordinary note */\n") == [] + + +def test_tag_order() -> None: + out_of_order = """ + /** + * @param x + * @tparam T + */ + """ + assert labels_for(out_of_order) == ["tag-order"] + + correct = """ + /** + * @tparam T + * @param x + * @return r + */ + """ + assert findings_for(correct) == [] + + single = """ + /** + * @param x + */ + """ + assert findings_for(single) == [] # single tag: never out of order + + +# --- command spelling (must work on body/closer lines, not just the opener) -- + + +def test_backslash_command_on_body_line() -> None: + code = r""" + /** + * \brief x + */ + """ + assert labels_for(code) == ["backslash-command"] + + +def test_backslash_command_suggests_canonical_spelling() -> None: + # a backslash + non-canonical spelling is fixed in one pass, not two: + # \sa -> @see (not @sa), \returns -> @return (not @returns) + sa = r""" + /** + * \sa other + */ + """ + assert messages_for(sa) == [r"use @see instead of \sa"] + + returns = r""" + /** + * \returns x + */ + """ + assert messages_for(returns) == [r"use @return instead of \returns"] + + +def test_wrong_command_on_body_line() -> None: + code = """ + /** + * @returns x + */ + """ + assert labels_for(code) == ["wrong-command"] + + +def test_body_line_commands_regression() -> None: + # regression: these live on body lines of a multi-line block + code = r""" + /** + * @returns bad + * @throw ex + * @sa other + * \param y + */ + """ + assert labels_for(code) == [ + "wrong-command", + "wrong-command", + "wrong-command", + "backslash-command", + ] + + +def test_command_on_closer_line() -> None: + code = """ + /** + * a + * @sa b */ + """ + assert labels_for(code) == ["wrong-command", "content-on-closer"] + + +def test_no_double_count_across_opener_body_closer() -> None: + code = """ + /** @returns opener + * @throw body + * @sa closer */ + """ + assert labels_for(code).count("wrong-command") == 3 + + +def test_code_with_word_allowed() -> None: + # @code{.cpp} is valid Doxygen and must not be flagged + code = """ + /** + * @code{.cpp} + * int x; + * @endcode + */ + """ + assert findings_for(code) == [] + + +# --- rendered message text --------------------------------------------------- + + +def test_message_uses_category_description() -> None: + # a static category renders its default description + code = "/// doc\n" + assert messages_for(code) == ["use a /** ... */ block instead of ///"] + + +def test_message_detail_overrides() -> None: + # dynamic categories render the offending text via Finding.detail + backslash = r""" + /** + * \param y + */ + """ + assert messages_for(backslash) == [r"use @param instead of \param"] + + wrong = """ + /** + * @returns x + */ + """ + assert messages_for(wrong) == ["use @return instead of @returns"] + + prose = """ + /** + * Throws: + */ + """ + assert messages_for(prose) == ['use @throws instead of prose "Throws:"'] + + +# --- robustness -------------------------------------------------------------- + + +def test_empty_file_no_crash() -> None: + assert findings_for("") == [] + + +def test_mid_line_plain_block_skipped() -> None: + # a /* opened mid-line (after code) and spanning lines is skipped, so its + # comment-like contents are not analyzed + code = """ + int x = 0; /* note: @returns is not a real tag here + * @param also not real + */ + int y = 0; + """ + assert findings_for(code) == [] + + +def test_unclosed_block_scanned_to_eof() -> None: + # an unterminated /** block is still scanned to EOF (no crash, body checked) + code = """ + /** + * @returns x + """ + assert labels_for(code) == ["wrong-command"] + + +def test_banner_and_empty_comment_not_flagged() -> None: + code = """ + /*** + * banner + ***/ + """ + assert findings_for(code) == [] + assert findings_for("/**/\n") == [] + + +def main() -> int: + tests = sorted( + (name, fn) + for name, fn in globals().items() + if name.startswith("test_") and callable(fn) + ) + failed = 0 + for name, fn in tests: + try: + fn() + print(f"PASS {name}") + except AssertionError as exc: + failed += 1 + print(f"FAIL {name}: {exc!r}") + print(f"\n{len(tests) - failed}/{len(tests)} passed") + return 1 if failed else 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/cmake/XrplCore.cmake b/cmake/XrplCore.cmake index 4d4a800d9a..3e49267715 100644 --- a/cmake/XrplCore.cmake +++ b/cmake/XrplCore.cmake @@ -293,4 +293,13 @@ if(xrpld) PRIVATE ${CMAKE_SOURCE_DIR}/external/antithesis-sdk ) endif() + + # The xrpld headers are not built with add_module, so verify them against + # the executable's own compile environment. + if(verify_headers) + verify_target_headers(xrpld "${CMAKE_CURRENT_SOURCE_DIR}/src/xrpld") + if(tests) + verify_target_headers(xrpld "${CMAKE_CURRENT_SOURCE_DIR}/src/test") + endif() + endif() endif() diff --git a/cmake/XrplSettings.cmake b/cmake/XrplSettings.cmake index 44a727a994..757a596096 100644 --- a/cmake/XrplSettings.cmake +++ b/cmake/XrplSettings.cmake @@ -30,6 +30,23 @@ if(tests) endif() endif() +# Enabled by default so every header is compiled on its own as the main file of +# its own compile_commands.json entry - this is what lets clang-tidy (and clangd +# and IDEs) analyse a header's own includes directly. The per-header objects are +# EXCLUDE_FROM_ALL (see cmake/verify_headers.cmake) and the aggregate target +# below is not part of `all`, so a normal `cmake --build` never compiles them. +option( + verify_headers + "Compile every header on its own to verify it is self-contained." + ON +) +if(verify_headers) + # Aggregate target that builds every per-module header-verification library + # created by add_module (see cmake/verify_headers.cmake). Build it with: + # cmake --build . --target verify-headers + add_custom_target(verify-headers) +endif() + option(unity "Creates a build using UNITY support in cmake." OFF) if(unity) if(NOT is_ci) diff --git a/cmake/add_module.cmake b/cmake/add_module.cmake index 316d6c627b..b72d1077bb 100644 --- a/cmake/add_module.cmake +++ b/cmake/add_module.cmake @@ -1,4 +1,5 @@ include(isolate_headers) +include(verify_headers) # Create an OBJECT library target named # @@ -37,4 +38,20 @@ function(add_module parent name) "${CMAKE_CURRENT_SOURCE_DIR}/src/lib${parent}/${name}" PRIVATE ) + # protocol_autogen contains generated headers that are deliberately exempt + # from clang-tidy (see ExcludeHeaderFilterRegex in .clang-tidy), so we do not + # verify them either. + if( + verify_headers + AND NOT "${parent}/${name}" STREQUAL "xrpl/protocol_autogen" + ) + verify_target_headers( + ${target} + "${CMAKE_CURRENT_SOURCE_DIR}/include/${parent}/${name}" + ) + verify_target_headers( + ${target} + "${CMAKE_CURRENT_SOURCE_DIR}/src/lib${parent}/${name}" + ) + endif() endfunction() diff --git a/cmake/scripts/codegen/templates/LedgerEntry.h.mako b/cmake/scripts/codegen/templates/LedgerEntry.h.mako index 63f5f39ef9..c799903b21 100644 --- a/cmake/scripts/codegen/templates/LedgerEntry.h.mako +++ b/cmake/scripts/codegen/templates/LedgerEntry.h.mako @@ -177,7 +177,9 @@ ${field['typeData']['setter_type']} ${field['paramName']}${',' if i < len(requir object_ = *sle; } - /** @brief Ledger entry-specific field setters */ + /** + * @brief Ledger entry-specific field setters + */ % for field in fields: /** diff --git a/cmake/scripts/codegen/templates/Transaction.h.mako b/cmake/scripts/codegen/templates/Transaction.h.mako index d3b303d9d6..49e2e4a5cd 100644 --- a/cmake/scripts/codegen/templates/Transaction.h.mako +++ b/cmake/scripts/codegen/templates/Transaction.h.mako @@ -185,7 +185,9 @@ public: object_ = *tx; } - /** @brief Transaction-specific field setters */ + /** + * @brief Transaction-specific field setters + */ % for field in fields: /** diff --git a/cmake/verify_headers.cmake b/cmake/verify_headers.cmake new file mode 100644 index 0000000000..2c36869441 --- /dev/null +++ b/cmake/verify_headers.cmake @@ -0,0 +1,84 @@ +# Our normal build only ever compiles `.cpp` files, so a header is only ever +# checked through whatever translation unit happens to include it. A header that +# is missing an `#include` is never caught as long as every `.cpp` that uses it +# includes its missing dependency first. To check a header on its own we compile +# it directly as a translation unit. +# +# Compiling the header itself - rather than a `.cpp` wrapper that includes it - +# gives two checks at once: +# * the compiler fails if the header is not self-contained, i.e. it uses a +# declaration that is not available (directly or transitively); and +# * the header is the *main file* of its `compile_commands.json` entry, so +# clang-tidy's misc-include-cleaner analyses (and can --fix) the header's own +# includes - flagging a dependency that is only available transitively, which +# a plain compile cannot catch. A wrapper would be the main file instead, and +# include-cleaner never looks inside the headers a main file includes. +# +# The objects are never linked anywhere; we build them only for these checks. + +# Verify that the headers under headers_dir compile on their own, using the +# compile environment of an existing target so each header is compiled exactly as +# that target compiles it. This works for both add_module libraries and the xrpld +# and test binaries: a library's isolated public and private include directories +# and a binary's `-I src` both live in its INCLUDE_DIRECTORIES, and the modules or +# libraries it links live in its LINK_LIBRARIES. We copy those usage requirements +# through generator expressions (rather than linking ${target}, which is +# impossible for an executable), evaluated at generation time so they capture +# requirements the caller adds after this runs. The verify library is created +# once; call this repeatedly to add more header directories. +# +# verify_target_headers(target headers_dir) +function(verify_target_headers target headers_dir) + set(verify ${target}.verify) + if(NOT TARGET ${verify}) + add_library(${verify} OBJECT EXCLUDE_FROM_ALL) + # A unity build would concatenate the headers into a single translation + # unit, where a header missing an include could be satisfied by one that + # precedes it in the blob - exactly the bug we want to catch. + set_target_properties(${verify} PROPERTIES UNITY_BUILD OFF) + target_include_directories( + ${verify} + PRIVATE $ + ) + target_compile_definitions( + ${verify} + PRIVATE $ + ) + target_compile_options( + ${verify} + PRIVATE $ + ) + target_link_libraries( + ${verify} + PRIVATE $ + ) + add_dependencies(verify-headers ${verify}) + endif() + _verify_add_headers(${verify} "${headers_dir}") +endfunction() + +# Add every .h/.hpp under dir to target as a directly-compiled C++ translation +# unit. .ipp files are inline-implementation fragments included by their owning +# header (often after a class declaration), so they are not self-contained on +# their own and are verified transitively when that header is verified. +function(_verify_add_headers target dir) + file(GLOB_RECURSE headers CONFIGURE_DEPENDS "${dir}/*.h" "${dir}/*.hpp") + if(NOT headers) + return() + endif() + # `-xc++` forces the header to be compiled as a C++ translation unit; a lone + # `.h` is otherwise treated as a header to precompile. `#pragma once` is + # harmless (and warns) when the header is the main file, so silence it. + # Compiled on its own, a header legitimately defines constants and static or + # template functions that nothing in this single translation unit uses (they + # exist for the files that include it), so the resulting unused-entity + # warnings are expected and must not fail the build under -Werror. + set_source_files_properties( + ${headers} + PROPERTIES + LANGUAGE CXX + COMPILE_OPTIONS + "-xc++;-Wno-pragma-once-outside-header;-Wno-unused-const-variable;-Wno-unused-function" + ) + target_sources(${target} PRIVATE ${headers}) +endfunction() diff --git a/conan.lock b/conan.lock index d80a6d0c57..b6ddfa4e58 100644 --- a/conan.lock +++ b/conan.lock @@ -1,43 +1,44 @@ { "version": "0.5", "requires": [ - "zlib/1.3.2#1cb806da49011867778ffb6ac7190fcb%1778091116.056", - "xxhash/0.8.3#681d36a0a6111fc56e5e45ea182c19cc%1765850149.987", - "sqlite3/3.53.0#324ada52333108388a9a6108bfa96734%1778091117.311", - "soci/4.0.3#fe32b9ad5eb47e79ab9e45a68f363945%1774450067.231", - "snappy/1.1.10#968fef506ff261592ec30c574d4a7809%1765850147.878", - "secp256k1/0.7.1#481881709eb0bdd0185a12b912bbe8ad%1770910500.329", - "rocksdb/10.5.1#4a197eca381a3e5ae8adf8cffa5aacd0%1765850186.86", - "re2/20251105#8579cfd0bda4daf0683f9e3898f964b4%1774398111.888", - "protobuf/6.33.5#d96d52ba5baaaa532f47bda866ad87a5%1774467363.12", - "openssl/3.6.2#4789bbf131b77d0515d15e094c8f697f%1778071755.506", - "nudb/2.0.9#11149c73f8f2baff9a0198fe25971fc7%1775040983.408", - "lz4/1.10.0#59fc63cac7f10fbe8e05c7e62c2f3504%1765850143.914", - "libiconv/1.17#1e65319e945f2d31941a9d28cc13c058%1765842973.492", - "libbacktrace/cci.20210118#a7691bfccd8caaf66309df196790a5a1%1765842973.03", - "libarchive/3.8.7#c446109bd1f1d8ba7936c94189bc50e6%1778091117.848", + "zlib/1.3.2#1cb806da49011867778ffb6ac7190fcb%1782392402.122708", + "xxhash/0.8.3#681d36a0a6111fc56e5e45ea182c19cc%1782392402.420688", + "sqlite3/3.53.0#324ada52333108388a9a6108bfa96734%1782392403.185447", + "soci/4.0.3#e726491a03468795453f7c83fc924a96%1782392402.679521", + "snappy/1.1.10#968fef506ff261592ec30c574d4a7809%1782307151.633168", + "secp256k1/0.7.1#b1f450b7f78a36fff75bb6934a356f3a%1782338841.3729", + "rocksdb/10.5.1#4a197eca381a3e5ae8adf8cffa5aacd0%1782392413.075713", + "re2/20251105#8579cfd0bda4daf0683f9e3898f964b4%1782392402.431897", + "protobuf/6.33.5#ff253ead763bd8d9904a52979cd21e81%1782392410.233933", + "openssl/3.6.3#1163d4ddc603907084d08a6a0c6e580f%1782307150.583886", + "nudb/2.0.9#11149c73f8f2baff9a0198fe25971fc7%1782392402.297166", + "mpt-crypto/0.4.0-rc2#a580f2f9ad0e795de696aa62d54fb9af%1782425834.488828", + "lz4/1.10.0#982d9b673900f665a1da109e09c17cab%1782392402.164188", + "libiconv/1.17#9923bc6dc6f106646d6967e0039a5ada%1782392792.775744", + "libbacktrace/cci.20210118#a7691bfccd8caaf66309df196790a5a1%1782392402.420732", + "libarchive/3.8.7#c446109bd1f1d8ba7936c94189bc50e6%1782392403.066892", "jemalloc/5.3.1#1fc58d55316041f10fbc1e8a2eae632a%1776700028.228", - "gtest/1.17.0#5224b3b3ff3b4ce1133cbdd27d53ee7d%1768312129.152", - "grpc/1.81.0#2fb144aeb47e7f35c6ebb0e5f35bed31%1781620605.685", - "ed25519/2015.03#ae761bdc52730a843f0809bdf6c1b1f6%1765850143.772", - "date/3.0.4#862e11e80030356b53c2c38599ceb32b%1765850143.772", - "c-ares/1.34.6#545240bb1c40e2cacd4362d6b8967650%1774439234.681", - "bzip2/1.0.8#c470882369c2d95c5c77e970c0c7e321%1765850143.837", - "boost/1.91.0#ea540ca2133d831b560036aa24dece3c%1778091165.282", - "abseil/20250127.0#bb0baf1f362bc4a725a24eddd419b8f7%1774365460.196" + "gtest/1.17.0#5224b3b3ff3b4ce1133cbdd27d53ee7d%1782392402.791979", + "grpc/1.81.1#5217e6ef0544c42b46f4af35d5e7f649%1782307148.845616", + "ed25519/2015.03#ae761bdc52730a843f0809bdf6c1b1f6%1782307148.15562", + "date/3.0.4#862e11e80030356b53c2c38599ceb32b%1782392402.538492", + "c-ares/1.34.6#545240bb1c40e2cacd4362d6b8967650%1782392402.681654", + "bzip2/1.0.8#c470882369c2d95c5c77e970c0c7e321%1782392402.296732", + "boost/1.91.0#ea540ca2133d831b560036aa24dece3c%1782392419.475605", + "abseil/20250127.0#bb0baf1f362bc4a725a24eddd419b8f7%1782307147.395833" ], "build_requires": [ - "zlib/1.3.2#1cb806da49011867778ffb6ac7190fcb%1778091116.056", - "strawberryperl/5.32.1.1#8d114504d172cfea8ea1662d09b6333e%1774447376.964", - "protobuf/6.33.5#d96d52ba5baaaa532f47bda866ad87a5%1774467363.12", - "nasm/2.16.01#31e26f2ee3c4346ecd347911bd126904%1765850144.707", + "zlib/1.3.2#1cb806da49011867778ffb6ac7190fcb%1782392402.122708", + "strawberryperl/5.32.1.1#8d114504d172cfea8ea1662d09b6333e%1782395692.540639", + "protobuf/6.33.5#ff253ead763bd8d9904a52979cd21e81%1782392410.233933", + "nasm/2.16.01#31e26f2ee3c4346ecd347911bd126904%1782395690.33162", "msys2/cci.latest#d22fe7b2808f5fd34d0a7923ace9c54f%1770657326.649", - "m4/1.4.19#4523e4347b55cd26ae918bd5770cab9a%1778062762.471", - "cmake/4.3.0#b939a42e98f593fb34d3a8c5cc860359%1774439249.183", - "b2/5.4.2#ffd6084a119587e70f11cd45d1a386e2%1774439233.447", + "m4/1.4.19#34c4bbc3eeebe98ca6edf2f52d602e7d%1777282960.259", + "cmake/4.3.3#840cf00ea09777e05c2050a50a82c722%1782392418.696091", + "b2/5.4.2#ffd6084a119587e70f11cd45d1a386e2%1782392402.624226", "automake/1.16.5#b91b7c384c3deaa9d535be02da14d04f%1755524470.56", "autoconf/2.71#51077f068e61700d65bb05541ea1e4b0%1731054366.86", - "abseil/20250127.0#bb0baf1f362bc4a725a24eddd419b8f7%1774365460.196" + "abseil/20250127.0#bb0baf1f362bc4a725a24eddd419b8f7%1782307147.395833" ], "python_requires": [], "overrides": { @@ -57,7 +58,7 @@ "boost/1.91.0" ], "lz4/[>=1.9.4 <2]": [ - "lz4/1.10.0#59fc63cac7f10fbe8e05c7e62c2f3504" + "lz4/1.10.0#982d9b673900f665a1da109e09c17cab" ] }, "config_requires": [] diff --git a/conan/lockfile/regenerate.sh b/conan/lockfile/regenerate.sh index 1aa47628f0..98ee6f7c99 100755 --- a/conan/lockfile/regenerate.sh +++ b/conan/lockfile/regenerate.sh @@ -14,7 +14,7 @@ export CONAN_HOME="$TEMP_DIR" # Ensure that the xrplf remote is the first to be consulted, so any recipes we # patched are used. We also add it there to not created huge diff when the # official Conan Center Index is updated. -conan remote add --force --index 0 xrplf https://conan.ripplex.io +conan remote add --force --index 0 xrplf https://conan.xrplf.org/repository/conan/ # Delete any existing lockfile. rm -f conan.lock diff --git a/conan/profiles/default b/conan/profiles/default index e0a88ebca1..ae6e23c3c3 100644 --- a/conan/profiles/default +++ b/conan/profiles/default @@ -10,16 +10,18 @@ os={{ os }} arch={{ arch }} build_type=Debug -compiler={{compiler}} +compiler={{ compiler }} compiler.version={{ compiler_version }} compiler.cppstd=23 {% if os == "Windows" %} compiler.runtime=static {% else %} -compiler.libcxx={{detect_api.detect_libcxx(compiler, version, compiler_exe)}} +compiler.libcxx={{ detect_api.detect_libcxx(compiler, version, compiler_exe) }} {% endif %} [conf] -{% if compiler == "gcc" and compiler_version < 13 %} -tools.build:cxxflags+=['-Wno-restrict'] -{% endif %} +{# By default, Conan tries to reuse binaries built with different cppstd versions. #} +{# We want to avoid that to improve reproduceability, so we add the cppstd version to the package ID. #} +{# More info: https://docs.conan.io/2/reference/extensions/binary_compatibility.html #} +user.package:cppstd_version=23 +tools.info.package_id:confs+=["user.package:cppstd_version"] diff --git a/conan/profiles/sanitizers b/conan/profiles/sanitizers index 083807ea9e..09e6aef02b 100644 --- a/conan/profiles/sanitizers +++ b/conan/profiles/sanitizers @@ -87,15 +87,15 @@ include(default) {% endif %} [conf] -tools.build:defines+={{defines}} -tools.build:cxxflags+={{sanitizer_compiler_flags}} -tools.build:sharedlinkflags+={{sanitizer_linker_flags}} -tools.build:exelinkflags+={{sanitizer_linker_flags}} +tools.build:defines+={{ defines }} +tools.build:cxxflags+={{ sanitizer_compiler_flags }} +tools.build:sharedlinkflags+={{ sanitizer_linker_flags }} +tools.build:exelinkflags+={{ sanitizer_linker_flags }} tools.info.package_id:confs+=["tools.build:cxxflags", "tools.build:exelinkflags", "tools.build:sharedlinkflags", "tools.build:defines"] # &: means "apply only to the consumer/root package" -&:tools.cmake.cmaketoolchain:extra_variables={"SANITIZERS": "{{sanitizers}}", "SANITIZERS_COMPILER_FLAGS": "{{sanitizer_compiler_flags | join(' ')}}", "SANITIZERS_LINKER_FLAGS": "{{sanitizer_linker_flags | join(' ')}}"} +&:tools.cmake.cmaketoolchain:extra_variables={"SANITIZERS": "{{ sanitizers }}", "SANITIZERS_COMPILER_FLAGS": "{{ sanitizer_compiler_flags | join(' ') }}", "SANITIZERS_LINKER_FLAGS": "{{ sanitizer_linker_flags | join(' ') }}"} [options] {% if enable_asan %} diff --git a/conanfile.py b/conanfile.py index 5b78dc22e3..db12dcb585 100644 --- a/conanfile.py +++ b/conanfile.py @@ -28,11 +28,10 @@ class Xrpl(ConanFile): requires = [ "ed25519/2015.03", - "grpc/1.81.0", + "grpc/1.81.1", "libarchive/3.8.7", "nudb/2.0.9", - "openssl/3.6.2", - "secp256k1/0.7.1", + "openssl/3.6.3", "soci/4.0.3", "zlib/1.3.2", ] @@ -132,13 +131,15 @@ class Xrpl(ConanFile): def requirements(self): self.requires("boost/1.91.0", force=True, transitive_headers=True) self.requires("date/3.0.4", transitive_headers=True) - self.requires("lz4/1.10.0", force=True) - self.requires("protobuf/6.33.5", force=True) - self.requires("sqlite3/3.53.0", force=True) if self.options.jemalloc: self.requires("jemalloc/5.3.1") + self.requires("lz4/1.10.0", force=True) + self.requires("mpt-crypto/0.4.0-rc2", transitive_headers=True) + self.requires("protobuf/6.33.5", force=True) if self.options.rocksdb: self.requires("rocksdb/10.5.1") + self.requires("secp256k1/0.7.1", transitive_headers=True) + self.requires("sqlite3/3.53.0", force=True) self.requires("xxhash/0.8.3", transitive_headers=True) exports_sources = ( @@ -208,6 +209,7 @@ class Xrpl(ConanFile): "grpc::grpc++", "libarchive::libarchive", "lz4::lz4", + "mpt-crypto::mpt-crypto", "nudb::nudb", "openssl::crypto", "protobuf::libprotobuf", diff --git a/docs/0001-negative-unl/README.md b/docs/0001-negative-unl/README.md index dd5f9af2ae..0bc65cd860 100644 --- a/docs/0001-negative-unl/README.md +++ b/docs/0001-negative-unl/README.md @@ -288,7 +288,7 @@ components with non-trivial changes are colored green. validated. ![Sequence diagram](./negativeUNL_highLevel_sequence.png?raw=true "Negative UNL - Changes") +Changes") ## Roads Not Taken diff --git a/docs/build/advanced_conan.md b/docs/build/advanced_conan.md index aae17e385a..26b88ef186 100644 --- a/docs/build/advanced_conan.md +++ b/docs/build/advanced_conan.md @@ -34,7 +34,7 @@ higher index than the default Conan Center remote, so it is consulted first. You can do this by running: ```bash -conan remote add --index 0 --force xrplf https://conan.ripplex.io +conan remote add --index 0 --force xrplf https://conan.xrplf.org/repository/conan/ ``` Alternatively, you can pull our recipes from the repository and export them locally: diff --git a/docs/build/environment.md b/docs/build/environment.md index 2cca608567..e639ed2d5f 100644 --- a/docs/build/environment.md +++ b/docs/build/environment.md @@ -33,9 +33,10 @@ with a single command and without installing anything system-wide: nix --experimental-features 'nix-command flakes' develop ``` -On **Linux**, Nix also provides the compiler (GCC). On **macOS**, the shell uses -your **system-wide Apple Clang** as the compiler, so you still need to manage -its version (see below). +On **Linux**, Nix also provides the compiler (GCC); on **macOS**, it provides +Clang. If you instead opt to use your system-wide Apple Clang (via +`nix develop .#apple-clang`), you need to manage its version yourself (see +below). See [Using the Nix development shell](./nix.md) for installation and usage details, including how to select a different compiler. @@ -48,10 +49,10 @@ details, including how to select a different compiler. ### macOS: managing the Apple Clang version -Because the Nix shell uses the system-wide Apple Clang on macOS, the compiler -version is whatever your installed Xcode (or Command Line Tools) provides. The -following command should return a version greater than or equal to the -[minimum required](#tested-compiler-versions): +If you use your system-wide Apple Clang on macOS (via `nix develop .#apple-clang`), +the compiler version is whatever your installed Xcode (or Command Line Tools) +provides. The following command should return a version greater than or equal to +the [minimum required](#tested-compiler-versions): ```bash clang --version diff --git a/docs/build/nix.md b/docs/build/nix.md index 2ae483aefe..d6e53a254a 100644 --- a/docs/build/nix.md +++ b/docs/build/nix.md @@ -9,7 +9,7 @@ This guide explains how to use Nix to set up a reproducible development environm - **Reproducible environment**: Everyone gets the same versions of tools and compilers - **Matches CI**: The Linux CI runs in Docker images built from this exact Nix environment - **No system pollution**: Dependencies are isolated and don't affect your system packages -- **Multiple compiler versions**: Easily switch between different GCC and Clang versions +- **Consistent compilers**: The GCC and Clang shells use the same versions as CI - **Quick setup**: Get started with a single command - **Works on Linux and macOS**: Consistent experience across platforms @@ -31,8 +31,8 @@ This will: - Download and set up all required development tools (CMake, Ninja, Conan, etc.) - Configure the appropriate compiler for your platform: - - **Linux**: GCC 15.2 (provided by Nix) - - **macOS**: Apple Clang (your system compiler) + - **Linux**: GCC (provided by Nix) + - **macOS**: Clang (provided by Nix) The first time you run this command, it will take a few minutes to download and build the environment. Subsequent runs will be much faster. @@ -40,12 +40,12 @@ The first time you run this command, it will take a few minutes to download and - **Linux**: `nix develop` gives you a shell with all the tooling necessary to develop xrpld and with GCC 15.2 (also provided by Nix). There are no caveats. -- **macOS**: `nix develop` gives you a full environment too. The compiler is - your system-wide Apple Clang, while every other tool — including Conan — is - provided by Nix. Conan has no binary in the Nix cache for macOS, so it is - built from source the first time you enter the shell, which makes the initial - setup slower (this is handled automatically; see - [`nix/devshell.nix`](../../nix/devshell.nix)). +- **macOS**: `nix develop` gives you a full environment too, with Clang (and + every other tool, including Conan) provided by Nix. To use your system-wide + Apple Clang instead, enter `nix develop .#apple-clang`. Conan has no binary in + the Nix cache for macOS, so it is built from source the first time you enter + the shell, which makes the initial setup slower (this is handled + automatically; see [`nix/devshell.nix`](../../nix/devshell.nix)). > [!TIP] > To avoid typing `--experimental-features 'nix-command flakes'` every time, you can permanently enable flakes by creating `~/.config/nix/nix.conf`: @@ -62,7 +62,9 @@ The first time you run this command, it will take a few minutes to download and ### Choosing a different compiler -A compiler can be chosen by providing its name with the `.#` prefix, e.g. `nix develop .#gcc15`. +A compiler can be chosen by providing its name with the `.#` prefix, e.g. `nix develop .#clang`. +The `.#gcc` and `.#clang` shells provide the same GCC and Clang versions used in CI +(pinned in [`nix/packages.nix`](../../nix/packages.nix)). Use `nix flake show` to see all the available development shells. Use `nix develop .#no-compiler` to use the compiler from your system. @@ -70,11 +72,11 @@ Use `nix develop .#no-compiler` to use the compiler from your system. ### Example Usage ```bash -# Use GCC 14 -nix develop .#gcc14 +# Use GCC (same version as CI) +nix develop .#gcc -# Use Clang 19 -nix develop .#clang19 +# Use Clang (same version as CI) +nix develop .#clang # Use default for your platform nix develop @@ -112,7 +114,15 @@ Once inside the Nix development shell, follow the standard [build instructions]( [direnv](https://direnv.net/) or [nix-direnv](https://github.com/nix-community/nix-direnv) can automatically activate the Nix development shell when you enter the repository directory. -This is also the most robust way to use the environment from **any shell** (bash, zsh, fish, …): direnv stays in your current shell and loads the environment _after_ your shell's startup files have run, so the Nix-provided tools take precedence over anything your shell configuration adds to `$PATH`. To use it, install direnv for your shell, then add an `.envrc` containing `use flake` at the repository root and run `direnv allow`. +This is also the most robust way to use the environment from **any shell** (bash, zsh, fish, …): direnv stays in your current shell and loads the environment _after_ your shell's startup files have run, so the Nix-provided tools take precedence over anything your shell configuration adds to `$PATH`. + +The repository already ships an `.envrc` at its root that activates the Nix flake development shell, so you don't need to create one. To use it: + +1. [Install direnv](https://direnv.net/docs/installation.html) and [hook it into your shell](https://direnv.net/docs/hook.html) (bash, zsh, fish, …). Installing [nix-direnv](https://github.com/nix-community/nix-direnv) as well is recommended: it caches the shell so that activation is near-instant after the first run. +2. Run `direnv allow` once in the repository root. direnv will then load (and reload) the Nix development shell automatically whenever you enter the directory. + +> [!NOTE] +> direnv only caches the `.direnv` directory (already listed in `.gitignore`); no other repository files are affected. ## Conan and Prebuilt Packages diff --git a/include/xrpl/basics/Archive.h b/include/xrpl/basics/Archive.h index 58e12bbb71..66d6a019af 100644 --- a/include/xrpl/basics/Archive.h +++ b/include/xrpl/basics/Archive.h @@ -4,13 +4,14 @@ namespace xrpl { -/** Extract a tar archive compressed with lz4 - - @param src the path of the archive to be extracted - @param dst the directory to extract to - - @throws runtime_error -*/ +/** + * Extract a tar archive compressed with lz4 + * + * @param src the path of the archive to be extracted + * @param dst the directory to extract to + * + * @throws runtime_error + */ void extractTarLz4(boost::filesystem::path const& src, boost::filesystem::path const& dst); diff --git a/include/xrpl/basics/Blob.h b/include/xrpl/basics/Blob.h index ee0d6cf3b5..bfb8e5a697 100644 --- a/include/xrpl/basics/Blob.h +++ b/include/xrpl/basics/Blob.h @@ -4,9 +4,10 @@ namespace xrpl { -/** Storage for linear binary data. - Blocks of binary data appear often in various idioms and structures. -*/ +/** + * Storage for linear binary data. + * Blocks of binary data appear often in various idioms and structures. + */ using Blob = std::vector; } // namespace xrpl diff --git a/include/xrpl/basics/Buffer.h b/include/xrpl/basics/Buffer.h index 59968a4fa4..05af6c409a 100644 --- a/include/xrpl/basics/Buffer.h +++ b/include/xrpl/basics/Buffer.h @@ -6,12 +6,14 @@ #include #include #include +#include namespace xrpl { -/** Like std::vector but better. - Meets the requirements of BufferFactory. -*/ +/** + * Like std::vector but better. + * Meets the requirements of BufferFactory. + */ class Buffer { private: @@ -23,30 +25,37 @@ public: Buffer() = default; - /** Create an uninitialized buffer with the given size. */ + /** + * Create an uninitialized buffer with the given size. + */ explicit Buffer(std::size_t size) : p_((size != 0u) ? new std::uint8_t[size] : nullptr), size_(size) { } - /** Create a buffer as a copy of existing memory. - - @param data a pointer to the existing memory. If - size is non-zero, it must not be null. - @param size size of the existing memory block. - */ + /** + * Create a buffer as a copy of existing memory. + * + * @param data a pointer to the existing memory. If + * size is non-zero, it must not be null. + * @param size size of the existing memory block. + */ Buffer(void const* data, std::size_t size) : Buffer(size) { if (size != 0u) std::memcpy(p_.get(), data, size); } - /** Copy-construct */ + /** + * Copy-construct + */ Buffer(Buffer const& other) : Buffer(other.p_.get(), other.size_) { } - /** Copy assign */ + /** + * Copy assign + */ Buffer& operator=(Buffer const& other) { @@ -58,17 +67,19 @@ public: return *this; } - /** Move-construct. - The other buffer is reset. - */ + /** + * Move-construct. + * The other buffer is reset. + */ Buffer(Buffer&& other) noexcept : p_(std::move(other.p_)), size_(other.size_) { other.size_ = 0; } - /** Move-assign. - The other buffer is reset. - */ + /** + * Move-assign. + * The other buffer is reset. + */ Buffer& operator=(Buffer&& other) noexcept { @@ -81,12 +92,16 @@ public: return *this; } - /** Construct from a slice */ + /** + * Construct from a slice + */ explicit Buffer(Slice s) : Buffer(s.data(), s.size()) { } - /** Assign from slice */ + /** + * Assign from slice + */ Buffer& operator=(Slice s) { @@ -100,7 +115,9 @@ public: return *this; } - /** Returns the number of bytes in the buffer. */ + /** + * Returns the number of bytes in the buffer. + */ [[nodiscard]] std::size_t size() const noexcept { @@ -120,10 +137,11 @@ public: return Slice{p_.get(), size_}; } - /** Return a pointer to beginning of the storage. - @note The return type is guaranteed to be a pointer - to a single byte, to facilitate pointer arithmetic. - */ + /** + * Return a pointer to beginning of the storage. + * @note The return type is guaranteed to be a pointer + * to a single byte, to facilitate pointer arithmetic. + */ /** @{ */ [[nodiscard]] std::uint8_t const* data() const noexcept @@ -138,9 +156,10 @@ public: } /** @} */ - /** Reset the buffer. - All memory is deallocated. The resulting size is 0. - */ + /** + * Reset the buffer. + * All memory is deallocated. The resulting size is 0. + */ void clear() noexcept { @@ -148,9 +167,10 @@ public: size_ = 0; } - /** Reallocate the storage. - Existing data, if any, is discarded. - */ + /** + * Reallocate the storage. + * Existing data, if any, is discarded. + */ std::uint8_t* alloc(std::size_t n) { diff --git a/include/xrpl/basics/CompressionAlgorithms.h b/include/xrpl/basics/CompressionAlgorithms.h index e24c490337..316acb14ac 100644 --- a/include/xrpl/basics/CompressionAlgorithms.h +++ b/include/xrpl/basics/CompressionAlgorithms.h @@ -5,13 +5,15 @@ #include #include +#include #include #include #include namespace xrpl::compression_algorithms { -/** LZ4 block compression. +/** + * LZ4 block compression. * @tparam BufferFactory Callable object or lambda. * Takes the requested buffer size and returns allocated buffer pointer. * @param in Data to compress @@ -79,7 +81,8 @@ lz4Decompress( return decompressedSize; } -/** LZ4 block decompression. +/** + * LZ4 block decompression. * @tparam InputStream ZeroCopyInputStream * @param in Input source stream * @param inSize Size of compressed data diff --git a/include/xrpl/basics/CountedObject.h b/include/xrpl/basics/CountedObject.h index 275894673e..bb7b0d8877 100644 --- a/include/xrpl/basics/CountedObject.h +++ b/include/xrpl/basics/CountedObject.h @@ -9,7 +9,9 @@ namespace xrpl { -/** Manages all counted object types. */ +/** + * Manages all counted object types. + */ class CountedObjects { public: @@ -23,10 +25,11 @@ public: getCounts(int minimumThreshold) const; public: - /** Implementation for @ref CountedObject. - - @internal - */ + /** + * Implementation for @ref CountedObject. + * + * @internal + */ class Counter { public: @@ -94,13 +97,14 @@ private: //------------------------------------------------------------------------------ -/** Tracks the number of instances of an object. - - Derived classes have their instances counted automatically. This is used - for reporting purposes. - - @ingroup basics -*/ +/** + * Tracks the number of instances of an object. + * + * Derived classes have their instances counted automatically. This is used + * for reporting purposes. + * + * @ingroup basics + */ template class CountedObject { diff --git a/include/xrpl/basics/DecayingSample.h b/include/xrpl/basics/DecayingSample.h index 910c8f9e14..1b05770734 100644 --- a/include/xrpl/basics/DecayingSample.h +++ b/include/xrpl/basics/DecayingSample.h @@ -2,12 +2,14 @@ #include #include +#include namespace xrpl { -/** Sampling function using exponential decay to provide a continuous value. - @tparam The number of seconds in the decay window. -*/ +/** + * Sampling function using exponential decay to provide a continuous value. + * @tparam The number of seconds in the decay window. + */ template class DecayingSample { @@ -18,15 +20,16 @@ public: DecayingSample() = delete; /** - @param now Start time of DecayingSample. - */ + * @param now Start time of DecayingSample. + */ explicit DecayingSample(time_point now) : value_(value_type()), when_(now) { } - /** Add a new sample. - The value is first aged according to the specified time. - */ + /** + * Add a new sample. + * The value is first aged according to the specified time. + */ value_type add(value_type value, time_point now) { @@ -35,9 +38,10 @@ public: return value_ / Window; } - /** Retrieve the current value in normalized units. - The samples are first aged according to the specified time. - */ + /** + * Retrieve the current value in normalized units. + * The samples are first aged according to the specified time. + */ value_type value(time_point now) { @@ -86,9 +90,10 @@ private: //------------------------------------------------------------------------------ -/** Sampling function using exponential decay to provide a continuous value. - @tparam HalfLife The half life of a sample, in seconds. -*/ +/** + * Sampling function using exponential decay to provide a continuous value. + * @tparam HalfLife The half life of a sample, in seconds. + */ template class DecayWindow { diff --git a/include/xrpl/basics/FileUtilities.h b/include/xrpl/basics/FileUtilities.h index 8cf7e4893f..c7a427b8a9 100644 --- a/include/xrpl/basics/FileUtilities.h +++ b/include/xrpl/basics/FileUtilities.h @@ -3,7 +3,9 @@ #include #include +#include #include +#include namespace xrpl { diff --git a/include/xrpl/basics/IntrusivePointer.h b/include/xrpl/basics/IntrusivePointer.h index d66c340d3f..59853ad4d0 100644 --- a/include/xrpl/basics/IntrusivePointer.h +++ b/include/xrpl/basics/IntrusivePointer.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include @@ -9,33 +10,37 @@ namespace xrpl { //------------------------------------------------------------------------------ -/** Tag to create an intrusive pointer from another intrusive pointer by using a - static cast. This is useful to create an intrusive pointer to a derived - class from an intrusive pointer to a base class. -*/ +/** + * Tag to create an intrusive pointer from another intrusive pointer by using a + * static cast. This is useful to create an intrusive pointer to a derived + * class from an intrusive pointer to a base class. + */ struct StaticCastTagSharedIntrusive { }; -/** Tag to create an intrusive pointer from another intrusive pointer by using a - dynamic cast. This is useful to create an intrusive pointer to a derived - class from an intrusive pointer to a base class. If the cast fails an empty - (null) intrusive pointer is created. -*/ +/** + * Tag to create an intrusive pointer from another intrusive pointer by using a + * dynamic cast. This is useful to create an intrusive pointer to a derived + * class from an intrusive pointer to a base class. If the cast fails an empty + * (null) intrusive pointer is created. + */ struct DynamicCastTagSharedIntrusive { }; -/** When creating or adopting a raw pointer, controls whether the strong count - is incremented or not. Use this tag to increment the strong count. -*/ +/** + * When creating or adopting a raw pointer, controls whether the strong count + * is incremented or not. Use this tag to increment the strong count. + */ struct SharedIntrusiveAdoptIncrementStrongTag { }; -/** When creating or adopting a raw pointer, controls whether the strong count - is incremented or not. Use this tag to leave the strong count unchanged. -*/ +/** + * When creating or adopting a raw pointer, controls whether the strong count + * is incremented or not. Use this tag to leave the strong count unchanged. + */ struct SharedIntrusiveAdoptNoIncrementTag { }; @@ -49,20 +54,21 @@ concept CAdoptTag = std::is_same_v || //------------------------------------------------------------------------------ -/** A shared intrusive pointer class that supports weak pointers. - - This is meant to be used for SHAMapInnerNodes, but may be useful for other - cases. Since the reference counts are stored on the pointee, the pointee is - not destroyed until both the strong _and_ weak pointer counts go to zero. - When the strong pointer count goes to zero, the "partialDestructor" is - called. This can be used to destroy as much of the object as possible while - still retaining the reference counts. For example, for SHAMapInnerNodes the - children may be reset in that function. Note that std::shared_pointer WILL - run the destructor when the strong count reaches zero, but may not free the - memory used by the object until the weak count reaches zero. In xrpld, we - typically allocate shared pointers with the `make_shared` function. When - that is used, the memory is not reclaimed until the weak count reaches zero. -*/ +/** + * A shared intrusive pointer class that supports weak pointers. + * + * This is meant to be used for SHAMapInnerNodes, but may be useful for other + * cases. Since the reference counts are stored on the pointee, the pointee is + * not destroyed until both the strong _and_ weak pointer counts go to zero. + * When the strong pointer count goes to zero, the "partialDestructor" is + * called. This can be used to destroy as much of the object as possible while + * still retaining the reference counts. For example, for SHAMapInnerNodes the + * children may be reset in that function. Note that std::shared_pointer WILL + * run the destructor when the strong count reaches zero, but may not free the + * memory used by the object until the weak count reaches zero. In xrpld, we + * typically allocate shared pointers with the `make_shared` function. When + * that is used, the memory is not reclaimed until the weak count reaches zero. + */ template class SharedIntrusive { @@ -110,8 +116,9 @@ public: operator=( SharedIntrusive&& rhs); // NOLINT(cppcoreguidelines-rvalue-reference-param-not-moved) - /** Adopt the raw pointer. The strong reference may or may not be - incremented, depending on the TAdoptTag + /** + * Adopt the raw pointer. The strong reference may or may not be + * incremented, depending on the TAdoptTag */ template void @@ -119,27 +126,31 @@ public: ~SharedIntrusive(); - /** Create a new SharedIntrusive by statically casting the pointer - controlled by the rhs param. - */ + /** + * Create a new SharedIntrusive by statically casting the pointer + * controlled by the rhs param. + */ template SharedIntrusive(StaticCastTagSharedIntrusive, SharedIntrusive const& rhs); - /** Create a new SharedIntrusive by statically casting the pointer - controlled by the rhs param. - */ + /** + * Create a new SharedIntrusive by statically casting the pointer + * controlled by the rhs param. + */ template SharedIntrusive(StaticCastTagSharedIntrusive, SharedIntrusive&& rhs); - /** Create a new SharedIntrusive by dynamically casting the pointer - controlled by the rhs param. - */ + /** + * Create a new SharedIntrusive by dynamically casting the pointer + * controlled by the rhs param. + */ template SharedIntrusive(DynamicCastTagSharedIntrusive, SharedIntrusive const& rhs); - /** Create a new SharedIntrusive by dynamically casting the pointer - controlled by the rhs param. - */ + /** + * Create a new SharedIntrusive by dynamically casting the pointer + * controlled by the rhs param. + */ template SharedIntrusive(DynamicCastTagSharedIntrusive, SharedIntrusive&& rhs); @@ -152,17 +163,22 @@ public: explicit operator bool() const noexcept; - /** Set the pointer to null, decrement the strong count, and run the - appropriate release action. - */ + /** + * Set the pointer to null, decrement the strong count, and run the + * appropriate release action. + */ void reset(); - /** Get the raw pointer */ + /** + * Get the raw pointer + */ [[nodiscard]] T* get() const; - /** Return the strong count */ + /** + * Return the strong count + */ [[nodiscard]] std::size_t useCount() const; @@ -180,43 +196,51 @@ public: friend class WeakIntrusive; private: - /** Return the raw pointer held by this object. */ + /** + * Return the raw pointer held by this object. + */ [[nodiscard]] T* unsafeGetRawPtr() const; - /** Exchange the current raw pointer held by this object with the given - pointer. Decrement the strong count of the raw pointer previously held - by this object and run the appropriate release action. + /** + * Exchange the current raw pointer held by this object with the given + * pointer. Decrement the strong count of the raw pointer previously held + * by this object and run the appropriate release action. */ void unsafeReleaseAndStore(T* next); - /** Set the raw pointer directly. This is wrapped in a function so the class - can support both atomic and non-atomic pointers in a future patch. + /** + * Set the raw pointer directly. This is wrapped in a function so the class + * can support both atomic and non-atomic pointers in a future patch. */ void unsafeSetRawPtr(T* p); - /** Exchange the raw pointer directly. - This sets the raw pointer to the given value and returns the previous - value. This is wrapped in a function so the class can support both - atomic and non-atomic pointers in a future patch. + /** + * Exchange the raw pointer directly. + * This sets the raw pointer to the given value and returns the previous + * value. This is wrapped in a function so the class can support both + * atomic and non-atomic pointers in a future patch. */ T* unsafeExchange(T* p); - /** pointer to the type with an intrusive count */ + /** + * pointer to the type with an intrusive count + */ T* ptr_{nullptr}; }; //------------------------------------------------------------------------------ -/** A weak intrusive pointer class for the SharedIntrusive pointer class. - -Note that this weak pointer class asks differently from normal weak pointer -classes. When the strong pointer count goes to zero, the "partialDestructor" -is called. See the comment on SharedIntrusive for a fuller explanation. -*/ +/** + * A weak intrusive pointer class for the SharedIntrusive pointer class. + * + * Note that this weak pointer class asks differently from normal weak pointer + * classes. When the strong pointer count goes to zero, the "partialDestructor" + * is called. See the comment on SharedIntrusive for a fuller explanation. + */ template class WeakIntrusive { @@ -246,54 +270,62 @@ public: WeakIntrusive& operator=(SharedIntrusive const& rhs); - /** Adopt the raw pointer and increment the weak count. */ + /** + * Adopt the raw pointer and increment the weak count. + */ void adopt(T* ptr); ~WeakIntrusive(); - /** Get a strong pointer from the weak pointer, if possible. This will - only return a seated pointer if the strong count on the raw pointer - is non-zero before locking. + /** + * Get a strong pointer from the weak pointer, if possible. This will + * only return a seated pointer if the strong count on the raw pointer + * is non-zero before locking. */ SharedIntrusive lock() const; - /** Return true if the strong count is zero. */ + /** + * Return true if the strong count is zero. + */ [[nodiscard]] bool expired() const; - /** Set the pointer to null and decrement the weak count. - - Note: This may run the destructor if the strong count is zero. - */ + /** + * Set the pointer to null and decrement the weak count. + * + * Note: This may run the destructor if the strong count is zero. + */ void reset(); private: T* ptr_ = nullptr; - /** Decrement the weak count. This does _not_ set the raw pointer to - null. - - Note: This may run the destructor if the strong count is zero. - */ + /** + * Decrement the weak count. This does _not_ set the raw pointer to + * null. + * + * Note: This may run the destructor if the strong count is zero. + */ void unsafeReleaseNoStore(); }; //------------------------------------------------------------------------------ -/** A combination of a strong and a weak intrusive pointer stored in the - space of a single pointer. - - This class is similar to a `std::variant` - with some optimizations. In particular, it uses a low-order bit to - determine if the raw pointer represents a strong pointer or a weak - pointer. It can also be quickly switched between its strong pointer and - weak pointer representations. This class is useful for storing intrusive - pointers in tagged caches. - */ +/** + * A combination of a strong and a weak intrusive pointer stored in the + * space of a single pointer. + * + * This class is similar to a `std::variant` + * with some optimizations. In particular, it uses a low-order bit to + * determine if the raw pointer represents a strong pointer or a weak + * pointer. It can also be quickly switched between its strong pointer and + * weak pointer representations. This class is useful for storing intrusive + * pointers in tagged caches. + */ template class SharedWeakUnion @@ -335,69 +367,83 @@ public: ~SharedWeakUnion(); - /** Return a strong pointer if this is already a strong pointer (i.e. - don't lock the weak pointer. Use the `lock` method if that's what's - needed) + /** + * Return a strong pointer if this is already a strong pointer (i.e. + * don't lock the weak pointer. Use the `lock` method if that's what's + * needed) */ [[nodiscard]] SharedIntrusive getStrong() const; - /** Return true if this is a strong pointer and the strong pointer is - seated. + /** + * Return true if this is a strong pointer and the strong pointer is + * seated. */ explicit operator bool() const noexcept; - /** Set the pointer to null, decrement the appropriate ref count, and - run the appropriate release action. + /** + * Set the pointer to null, decrement the appropriate ref count, and + * run the appropriate release action. */ void reset(); - /** If this is a strong pointer, return the raw pointer. Otherwise - return null. + /** + * If this is a strong pointer, return the raw pointer. Otherwise + * return null. */ [[nodiscard]] T* get() const; - /** If this is a strong pointer, return the strong count. Otherwise + /** + * If this is a strong pointer, return the strong count. Otherwise * return 0 */ [[nodiscard]] std::size_t useCount() const; - /** Return true if there is a non-zero strong count. */ + /** + * Return true if there is a non-zero strong count. + */ [[nodiscard]] bool expired() const; - /** If this is a strong pointer, return the strong pointer. Otherwise - attempt to lock the weak pointer. + /** + * If this is a strong pointer, return the strong pointer. Otherwise + * attempt to lock the weak pointer. */ [[nodiscard]] SharedIntrusive lock() const; - /** Return true is this represents a strong pointer. */ + /** + * Return true is this represents a strong pointer. + */ [[nodiscard]] bool isStrong() const; - /** Return true is this represents a weak pointer. */ + /** + * Return true is this represents a weak pointer. + */ [[nodiscard]] bool isWeak() const; - /** If this is a weak pointer, attempt to convert it to a strong - pointer. - - @return true if successfully converted to a strong pointer (or was - already a strong pointer). Otherwise false. - */ + /** + * If this is a weak pointer, attempt to convert it to a strong + * pointer. + * + * @return true if successfully converted to a strong pointer (or was + * already a strong pointer). Otherwise false. + */ bool convertToStrong(); - /** If this is a strong pointer, attempt to convert it to a weak - pointer. - - @return false if the pointer is null. Otherwise return true. - */ + /** + * If this is a strong pointer, attempt to convert it to a weak + * pointer. + * + * @return false if the pointer is null. Otherwise return true. + */ bool convertToWeak(); @@ -410,23 +456,27 @@ private: static constexpr std::uintptr_t kPtrMask = ~kTagMask; private: - /** Return the raw pointer held by this object. + /** + * Return the raw pointer held by this object. */ [[nodiscard]] T* unsafeGetRawPtr() const; enum class RefStrength { Strong, Weak }; - /** Set the raw pointer and tag bit directly. + /** + * Set the raw pointer and tag bit directly. */ void unsafeSetRawPtr(T* p, RefStrength rs); - /** Set the raw pointer and tag bit to all zeros (strong null pointer). + /** + * Set the raw pointer and tag bit to all zeros (strong null pointer). */ void unsafeSetRawPtr(std::nullptr_t); - /** Decrement the appropriate ref count, and run the appropriate release - action. Note: this does _not_ set the raw pointer to null. + /** + * Decrement the appropriate ref count, and run the appropriate release + * action. Note: this does _not_ set the raw pointer to null. */ void unsafeReleaseNoStore(); @@ -434,12 +484,13 @@ private: //------------------------------------------------------------------------------ -/** Create a shared intrusive pointer. - - Note: unlike std::shared_ptr, where there is an advantage of allocating - the pointer and control block together, there is no benefit for intrusive - pointers. -*/ +/** + * Create a shared intrusive pointer. + * + * Note: unlike std::shared_ptr, where there is an advantage of allocating + * the pointer and control block together, there is no benefit for intrusive + * pointers. + */ template SharedIntrusive makeSharedIntrusive(Args&&... args) diff --git a/include/xrpl/basics/IntrusivePointer.ipp b/include/xrpl/basics/IntrusivePointer.ipp index 8344a3e613..67d43b05d6 100644 --- a/include/xrpl/basics/IntrusivePointer.ipp +++ b/include/xrpl/basics/IntrusivePointer.ipp @@ -641,6 +641,9 @@ template T* SharedWeakUnion::unsafeGetRawPtr() const { + // tp_ packs a raw pointer together with a strength bit; recovering the + // pointer inherently requires an integer-to-pointer cast. + // NOLINTNEXTLINE(performance-no-int-to-ptr) return reinterpret_cast(tp_ & kPtrMask); } diff --git a/include/xrpl/basics/IntrusiveRefCounts.h b/include/xrpl/basics/IntrusiveRefCounts.h index 0b00f1d5b1..caa06ed786 100644 --- a/include/xrpl/basics/IntrusiveRefCounts.h +++ b/include/xrpl/basics/IntrusiveRefCounts.h @@ -3,39 +3,43 @@ #include #include +#include #include namespace xrpl { -/** Action to perform when releasing a strong pointer. - - noop: Do nothing. For example, a `noop` action will occur when a count is - decremented to a non-zero value. - - partialDestroy: Run the `partialDestructor`. This action will happen when a - strong count is decremented to zero and the weak count is non-zero. - - destroy: Run the destructor. This action will occur when either the strong - count or weak count is decremented and the other count is also zero. +/** + * Action to perform when releasing a strong pointer. + * + * noop: Do nothing. For example, a `noop` action will occur when a count is + * decremented to a non-zero value. + * + * partialDestroy: Run the `partialDestructor`. This action will happen when a + * strong count is decremented to zero and the weak count is non-zero. + * + * destroy: Run the destructor. This action will occur when either the strong + * count or weak count is decremented and the other count is also zero. */ enum class ReleaseStrongRefAction { NoOp, PartialDestroy, Destroy }; -/** Action to perform when releasing a weak pointer. - - noop: Do nothing. For example, a `noop` action will occur when a count is - decremented to a non-zero value. - - destroy: Run the destructor. This action will occur when either the strong - count or weak count is decremented and the other count is also zero. +/** + * Action to perform when releasing a weak pointer. + * + * noop: Do nothing. For example, a `noop` action will occur when a count is + * decremented to a non-zero value. + * + * destroy: Run the destructor. This action will occur when either the strong + * count or weak count is decremented and the other count is also zero. */ enum class ReleaseWeakRefAction { NoOp, Destroy }; -/** Implement the strong count, weak count, and bit flags for an intrusive - pointer. - - A class can satisfy the requirements of an xrpl::IntrusivePointer by - inheriting from this class. - */ +/** + * Implement the strong count, weak count, and bit flags for an intrusive + * pointer. + * + * A class can satisfy the requirements of an xrpl::IntrusivePointer by + * inheriting from this class. + */ struct IntrusiveRefCounts { virtual ~IntrusiveRefCounts() noexcept; @@ -104,109 +108,123 @@ private: static constexpr size_t kFieldTypeBits = sizeof(FieldType) * 8; static constexpr FieldType kOne = 1; - /** `refCounts` consists of four fields that are treated atomically: - - 1. Strong count. This is a count of the number of shared pointers that - hold a reference to this object. When the strong counts goes to zero, - if the weak count is zero, the destructor is run. If the weak count is - non-zero when the strong count goes to zero then the partialDestructor - is run. - - 2. Weak count. This is a count of the number of weak pointer that hold - a reference to this object. When the weak count goes to zero and the - strong count is also zero, then the destructor is run. - - 3. Partial destroy started bit. This bit is set if the - `partialDestructor` function has been started (or is about to be - started). This is used to prevent the destructor from running - concurrently with the partial destructor. This can easily happen when - the last strong pointer release its reference in one thread and starts - the partialDestructor, while in another thread the last weak pointer - goes out of scope and starts the destructor while the partialDestructor - is still running. Both a start and finished bit is needed to handle a - corner-case where the last strong pointer goes out of scope, then then - last `weakPointer` goes out of scope, but this happens before the - `partialDestructor` bit is set. It would be possible to use a single - bit if it could also be set atomically when the strong count goes to - zero and the weak count is non-zero, but that would add complexity (and - likely slow down common cases as well). - - 4. Partial destroy finished bit. This bit is set when the - `partialDestructor` has finished running. See (3) above for more - information. - - */ + /** + * `refCounts` consists of four fields that are treated atomically: + * + * 1. Strong count. This is a count of the number of shared pointers that + * hold a reference to this object. When the strong counts goes to zero, + * if the weak count is zero, the destructor is run. If the weak count is + * non-zero when the strong count goes to zero then the partialDestructor + * is run. + * + * 2. Weak count. This is a count of the number of weak pointer that hold + * a reference to this object. When the weak count goes to zero and the + * strong count is also zero, then the destructor is run. + * + * 3. Partial destroy started bit. This bit is set if the + * `partialDestructor` function has been started (or is about to be + * started). This is used to prevent the destructor from running + * concurrently with the partial destructor. This can easily happen when + * the last strong pointer release its reference in one thread and starts + * the partialDestructor, while in another thread the last weak pointer + * goes out of scope and starts the destructor while the partialDestructor + * is still running. Both a start and finished bit is needed to handle a + * corner-case where the last strong pointer goes out of scope, then then + * last `weakPointer` goes out of scope, but this happens before the + * `partialDestructor` bit is set. It would be possible to use a single + * bit if it could also be set atomically when the strong count goes to + * zero and the weak count is non-zero, but that would add complexity (and + * likely slow down common cases as well). + * + * 4. Partial destroy finished bit. This bit is set when the + * `partialDestructor` has finished running. See (3) above for more + * information. + */ mutable std::atomic refCounts_{kStrongDelta}; - /** Amount to change the strong count when adding or releasing a reference - - Note: The strong count is stored in the low `StrongCountNumBits` bits - of refCounts - */ + /** + * Amount to change the strong count when adding or releasing a reference + * + * Note: The strong count is stored in the low `StrongCountNumBits` bits + * of refCounts + */ static constexpr FieldType kStrongDelta = 1; - /** Amount to change the weak count when adding or releasing a reference - - Note: The weak count is stored in the high `WeakCountNumBits` bits of - refCounts - */ + /** + * Amount to change the weak count when adding or releasing a reference + * + * Note: The weak count is stored in the high `WeakCountNumBits` bits of + * refCounts + */ static constexpr FieldType kWeakDelta = (kOne << kStrongCountNumBits); - /** Flag that is set when the partialDestroy function has started running - (or is about to start running). - - See description of the `refCounts` field for a fuller description of - this field. - */ + /** + * Flag that is set when the partialDestroy function has started running + * (or is about to start running). + * + * See description of the `refCounts` field for a fuller description of + * this field. + */ static constexpr FieldType kPartialDestroyStartedMask = (kOne << (kFieldTypeBits - 1)); - /** Flag that is set when the partialDestroy function has finished running - - See description of the `refCounts` field for a fuller description of - this field. - */ + /** + * Flag that is set when the partialDestroy function has finished running + * + * See description of the `refCounts` field for a fuller description of + * this field. + */ static constexpr FieldType kPartialDestroyFinishedMask = (kOne << (kFieldTypeBits - 2)); - /** Mask that will zero out all the `count` bits and leave the tag bits - unchanged. - */ + /** + * Mask that will zero out all the `count` bits and leave the tag bits + * unchanged. + */ static constexpr FieldType kTagMask = kPartialDestroyStartedMask | kPartialDestroyFinishedMask; - /** Mask that will zero out the `tag` bits and leave the count bits - unchanged. - */ + /** + * Mask that will zero out the `tag` bits and leave the count bits + * unchanged. + */ static constexpr FieldType kValueMask = ~kTagMask; - /** Mask that will zero out everything except the strong count. + /** + * Mask that will zero out everything except the strong count. */ static constexpr FieldType kStrongMask = ((kOne << kStrongCountNumBits) - 1) & kValueMask; - /** Mask that will zero out everything except the weak count. + /** + * Mask that will zero out everything except the weak count. */ static constexpr FieldType kWeakMask = (((kOne << kWeakCountNumBits) - 1) << kStrongCountNumBits) & kValueMask; - /** Unpack the count and tag fields from the packed atomic integer form. */ + /** + * Unpack the count and tag fields from the packed atomic integer form. + */ struct RefCountPair { CountType strong; CountType weak; - /** The `partialDestroyStartedBit` is set to on when the partial - destroy function is started. It is not a boolean; it is a uint32 - with all bits zero with the possible exception of the - `partialDestroyStartedMask` bit. This is done so it can be directly - masked into the `combinedValue`. + /** + * The `partialDestroyStartedBit` is set to on when the partial + * destroy function is started. It is not a boolean; it is a uint32 + * with all bits zero with the possible exception of the + * `partialDestroyStartedMask` bit. This is done so it can be directly + * masked into the `combinedValue`. */ FieldType partialDestroyStartedBit{0}; - /** The `partialDestroyFinishedBit` is set to on when the partial - destroy function has finished. + /** + * The `partialDestroyFinishedBit` is set to on when the partial + * destroy function has finished. */ FieldType partialDestroyFinishedBit{0}; RefCountPair(FieldType v) noexcept; RefCountPair(CountType s, CountType w) noexcept; - /** Convert back to the packed integer form. */ + /** + * Convert back to the packed integer form. + */ [[nodiscard]] FieldType combinedValue() const noexcept; @@ -214,9 +232,10 @@ private: static_cast((kOne << kStrongCountNumBits) - 1); static constexpr CountType kMaxWeakValue = static_cast((kOne << kWeakCountNumBits) - 1); - /** Put an extra margin to detect when running up against limits. - This is only used in debug code, and is useful if we reduce the - number of bits in the strong and weak counts (to 16 and 14 bits). + /** + * Put an extra margin to detect when running up against limits. + * This is only used in debug code, and is useful if we reduce the + * number of bits in the strong and weak counts (to 16 and 14 bits). */ static constexpr CountType kCheckStrongMaxValue = kMaxStrongValue - 32; static constexpr CountType kCheckWeakMaxValue = kMaxWeakValue - 32; diff --git a/include/xrpl/basics/LocalValue.h b/include/xrpl/basics/LocalValue.h index 1c2a657a18..c5e544a343 100644 --- a/include/xrpl/basics/LocalValue.h +++ b/include/xrpl/basics/LocalValue.h @@ -70,11 +70,15 @@ public: { } - /** Stores instance of T specific to the calling coroutine or thread. */ + /** + * Stores instance of T specific to the calling coroutine or thread. + */ T& operator*(); - /** Stores instance of T specific to the calling coroutine or thread. */ + /** + * Stores instance of T specific to the calling coroutine or thread. + */ T* operator->() { diff --git a/include/xrpl/basics/Log.h b/include/xrpl/basics/Log.h index 0699cdd3d9..945dc1b4ec 100644 --- a/include/xrpl/basics/Log.h +++ b/include/xrpl/basics/Log.h @@ -1,6 +1,5 @@ #pragma once -#include #include #include @@ -11,11 +10,15 @@ #include #include #include +#include #include +#include namespace xrpl { -/** Manages partitions for logging. */ +/** + * Manages partitions for logging. + */ class Logs { private: @@ -39,69 +42,81 @@ private: writeAlways(beast::Severity level, std::string const& text) override; }; - /** Manages a system file containing logged output. - The system file remains open during program execution. Interfaces - are provided for interoperating with standard log management - tools like logrotate(8): - http://linuxcommand.org/man_pages/logrotate8.html - @note None of the listed interfaces are thread-safe. - */ + /** + * Manages a system file containing logged output. + * The system file remains open during program execution. Interfaces + * are provided for interoperating with standard log management + * tools like logrotate(8): + * http://linuxcommand.org/man_pages/logrotate8.html + * @note None of the listed interfaces are thread-safe. + */ class File { public: - /** Construct with no associated system file. - A system file may be associated later with @ref open. - @see open - */ + /** + * Construct with no associated system file. + * A system file may be associated later with @ref open. + * @see open + */ File(); - /** Destroy the object. - If a system file is associated, it will be flushed and closed. - */ + /** + * Destroy the object. + * If a system file is associated, it will be flushed and closed. + */ ~File() = default; - /** Determine if a system file is associated with the log. - @return `true` if a system file is associated and opened for - writing. - */ + /** + * Determine if a system file is associated with the log. + * @return `true` if a system file is associated and opened for + * writing. + */ [[nodiscard]] bool isOpen() const noexcept; - /** Associate a system file with the log. - If the file does not exist an attempt is made to create it - and open it for writing. If the file already exists an attempt is - made to open it for appending. - If a system file is already associated with the log, it is closed - first. - @return `true` if the file was opened. - */ + /** + * Associate a system file with the log. + * If the file does not exist an attempt is made to create it + * and open it for writing. If the file already exists an attempt is + * made to open it for appending. + * If a system file is already associated with the log, it is closed + * first. + * @return `true` if the file was opened. + */ bool open(boost::filesystem::path const& path); - /** Close and re-open the system file associated with the log - This assists in interoperating with external log management tools. - @return `true` if the file was opened. - */ + /** + * Close and re-open the system file associated with the log + * This assists in interoperating with external log management tools. + * @return `true` if the file was opened. + */ bool closeAndReopen(); - /** Close the system file if it is open. */ + /** + * Close the system file if it is open. + */ void close(); - /** write to the log file. - Does nothing if there is no associated system file. - */ + /** + * write to the log file. + * Does nothing if there is no associated system file. + */ void write(char const* text); - /** write to the log file and append an end of line marker. - Does nothing if there is no associated system file. - */ + /** + * write to the log file and append an end of line marker. + * Does nothing if there is no associated system file. + */ void writeln(char const* text); - /** Write to the log file using std::string. */ + /** + * Write to the log file using std::string. + */ /** @{ */ void write(std::string const& str) @@ -222,19 +237,21 @@ private: //------------------------------------------------------------------------------ // Debug logging: -/** Set the sink for the debug journal. - - @param sink unique_ptr to new debug Sink. - @return unique_ptr to the previous Sink. nullptr if there was no Sink. -*/ +/** + * Set the sink for the debug journal. + * + * @param sink unique_ptr to new debug Sink. + * @return unique_ptr to the previous Sink. nullptr if there was no Sink. + */ std::unique_ptr setDebugLogSink(std::unique_ptr sink); -/** Returns a debug journal. - The journal may drain to a null sink, so its output - may never be seen. Never use it for critical - information. -*/ +/** + * Returns a debug journal. + * The journal may drain to a null sink, so its output + * may never be seen. Never use it for critical + * information. + */ beast::Journal debugLog(); diff --git a/include/xrpl/basics/MathUtilities.h b/include/xrpl/basics/MathUtilities.h index 4552b335e1..78f5c76988 100644 --- a/include/xrpl/basics/MathUtilities.h +++ b/include/xrpl/basics/MathUtilities.h @@ -6,7 +6,8 @@ namespace xrpl { -/** 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] * E.g. calculatePercent(1, 100) = 1 because 1/100 = 0.010000 * calculatePercent(1, 99) = 2 because 1/99 = 0.010101 @@ -19,7 +20,7 @@ namespace xrpl { * @return the percentage, in [0, 100] * * @note total cannot be zero. - * */ + */ constexpr std::size_t calculatePercent(std::size_t count, std::size_t total) { diff --git a/include/xrpl/basics/Number.h b/include/xrpl/basics/Number.h index cee0c45355..0026e7f006 100644 --- a/include/xrpl/basics/Number.h +++ b/include/xrpl/basics/Number.h @@ -2,7 +2,9 @@ #include +#include #include +#include #include #include #include @@ -11,7 +13,8 @@ #include #include #include -#include +#include +#include namespace xrpl { @@ -44,46 +47,54 @@ isPowerOfTen(T value) namespace detail { -/** Builds a table of the powers of 10 +/** + * Builds a table of the powers of 10 * * This function is marked consteval, so it can only be run in * a constexpr context. This assures that it is and can only be run at * compile time. Doing it at runtime would be pretty wasteful and * inefficient. */ -constexpr std::size_t kInt64Digits = 20; -consteval std::array +constexpr std::size_t kUint64Digits = 20; +[[maybe_unused]] constexpr std::size_t kUint128Digits = 39; + +template +consteval std::array buildPowersOfTen() { - std::array result{}; + std::array result{}; - std::uint64_t power = 1; + T power = 1; std::size_t exponent = 0; // end the loop early so it doesn't overflow; for (; exponent < result.size() - 1; ++exponent, power *= 10) { result[exponent] = power; - if (power > std::numeric_limits::max() / 10) + if (power > std::numeric_limits::max() / 10) throw std::logic_error("Power of 10 table is too big"); } result[exponent] = power; - if (power < std::numeric_limits::max() / 10) - throw std::logic_error("Power of 10 table is not big enough for the uint64_t type"); + if (power < std::numeric_limits::max() / 10) + throw std::logic_error("Power of 10 table is not big enough for the given type"); return result; } } // namespace detail -constexpr std::array kPowerOfTen = detail::buildPowersOfTen(); +template +constexpr std::array kPowerOfTenImpl = detail::buildPowersOfTen(); + +constexpr auto kPowerOfTen = kPowerOfTenImpl; static_assert(kPowerOfTen[0] == 1); static_assert(kPowerOfTen[1] == 10); static_assert(kPowerOfTen[10] == 10'000'000'000); static_assert( - isPowerOfTen(kPowerOfTen.back()) && *logTen(kPowerOfTen.back()) == detail::kInt64Digits - 1); + isPowerOfTen(kPowerOfTen.back()) && *logTen(kPowerOfTen.back()) == detail::kUint64Digits - 1); -/** MantissaRange defines a range for the mantissa of a normalized Number. +/** + * MantissaRange defines a range for the mantissa of a normalized Number. * * The mantissa is in the range [min, max], where * * min is a power of 10, and @@ -120,17 +131,37 @@ struct MantissaRange final { using rep = std::uint64_t; + // NOLINTBEGIN(readability-enum-initial-value) + // The values don't matter, except for Large enum class MantissaScale { + // Small can be removed when either featureSingleAssetVault or featureLendingProtocol are + // retired Small, // LargeLegacy can be removed when fixCleanup3_2_0 is retired LargeLegacy, - Large, + // Large320 can be removed when fixCleanup3_3_0 is retired + Large320, + // If Large330 is ever the only remaining "Large*" entry, it can be renamed to just "Large". + Large330, + // Large is a de-facto alias for "the latest", and is only here for backward compatibility + // in the extremely unlikely case that a downstream project made use of it. Note that + // because the behavior changed, this may still be a breaking change. + Large = Large330, }; + // NOLINTEND(readability-enum-initial-value) - // This entire enum can be removed when fixCleanup3_2_0 is retired - enum class CuspRoundingFix : bool { - Disabled = false, - Enabled = true, + // This entire enum can be removed when the last relevant amendment is retired + enum class CuspRoundingFix : std::uint8_t { + // Disabled can be removed when fixCleanup3_2_0 is retired + Disabled = 0, + // Enabled320 can be removed when fixCleanup3_3_0 is retired + Enabled320 = 1, + // If we ever get to the point that there's only one entry, remove the entire enum + Enabled330 = 2, + // Enabled is a de-facto alias for "the latest", and is only here for backward compatibility + // in the extremely unlikely case that a downstream project made use of it. Note that + // because the behavior changed, this may still be a breaking change. + Enabled = Enabled330, }; explicit constexpr MantissaRange(MantissaScale sc) : scale(sc) @@ -141,13 +172,27 @@ struct MantissaRange final int const log{getExponent(scale)}; rep const min{getMin(scale, log)}; rep const max{(min * 10) - 1}; - CuspRoundingFix const cuspRoundingFixEnabled{isCuspFixEnabled(scale)}; - - static MantissaRange const& - getMantissaRange(MantissaScale scale); + CuspRoundingFix const cuspRoundingFix{isCuspFixEnabled(scale)}; static std::set const& - getAllScales(); + getAllScales() + { + static std::set const kScales = { + MantissaRange::MantissaScale::Small, + MantissaRange::MantissaScale::LargeLegacy, + MantissaRange::MantissaScale::Large320, + MantissaRange::MantissaScale::Large330, + }; + return kScales; + } + + class Access + { + static constexpr MantissaRange const& + mantissaRange(MantissaScale scale); + + friend Number; + }; private: static constexpr int @@ -158,7 +203,8 @@ private: case MantissaScale::Small: return 15; case MantissaScale::LargeLegacy: - case MantissaScale::Large: + case MantissaScale::Large320: + case MantissaScale::Large330: return 18; // LCOV_EXCL_START default: @@ -187,24 +233,24 @@ private: case MantissaScale::Small: case MantissaScale::LargeLegacy: return CuspRoundingFix::Disabled; - case MantissaScale::Large: - return CuspRoundingFix::Enabled; + case MantissaScale::Large320: + return CuspRoundingFix::Enabled320; + case MantissaScale::Large330: + return CuspRoundingFix::Enabled330; default: // If called in a constexpr context, this throw assures that the build fails if an // invalid scale is used. throw std::runtime_error("Unknown mantissa scale"); // LCOV_EXCL_LINE } } - - static std::unordered_map const& - getRanges(); }; // Like std::integral, but only 64-bit integral types. template concept Integral64 = std::is_same_v || std::is_same_v; -/** Number is a floating point type that can represent a wide range of values. +/** + * Number is a floating point type that can represent a wide range of values. * * It can represent all values that can be represented by an STAmount - * regardless of asset type - XRPAmount, MPTAmount, and IOUAmount, with at least @@ -300,7 +346,6 @@ concept Integral64 = std::is_same_v || std::is_same_v kRange; + class Guard; + void normalize(MantissaRange const& range); - /** Normalize Number components to an arbitrary range. + // Guard has the fields that we need, as well as MantissaRange, so if we have a guard, use that + void + normalize(Guard const& guard); + + /** + * Normalize Number components to an arbitrary range. * * min/maxMantissa are parameters because this function is used by both * normalize(), which reads from kRange, and by normalizeToRange, @@ -567,7 +624,7 @@ private: int& exponent, internalrep const& minMantissa, internalrep const& maxMantissa, - MantissaRange::CuspRoundingFix cuspRoundingFixEnabled); + MantissaRange::CuspRoundingFix cuspRoundingFix); template friend void @@ -577,7 +634,7 @@ private: int& exponent, MantissaRange::rep const& minMantissa, MantissaRange::rep const& maxMantissa, - MantissaRange::CuspRoundingFix cuspRoundingFixEnabled, + MantissaRange::CuspRoundingFix cuspRoundingFix, bool dropped); [[nodiscard]] bool @@ -595,8 +652,6 @@ private: // UB, and can vary across compilers. static internalrep externalToInternal(rep mantissa); - - class Guard; }; constexpr Number::Number(bool negative, internalrep mantissa, int exponent, Unchecked) noexcept @@ -631,7 +686,8 @@ inline Number::Number(rep mantissa) : Number{mantissa, 0} { } -/** Returns the mantissa of the external view of the Number. +/** + * Returns the mantissa of the external view of the Number. * * Please see the "---- External Interface ----" section of the class * documentation for an explanation of why the internal value may be modified. @@ -652,7 +708,8 @@ Number::mantissa() const noexcept return sign * static_cast(m); } -/** Returns the exponent of the external view of the Number. +/** + * Returns the exponent of the external view of the Number. * * Please see the "---- External Interface ----" section of the class * documentation for an explanation of why the internal value may be modified. @@ -858,21 +915,11 @@ squelch(Number const& x, Number const& limit) noexcept return x; } -inline std::string -to_string(MantissaRange::MantissaScale const& scale) -{ - switch (scale) - { - case MantissaRange::MantissaScale::Small: - return "small"; - case MantissaRange::MantissaScale::LargeLegacy: - return "largeLegacy"; - case MantissaRange::MantissaScale::Large: - return "large"; - default: - throw std::runtime_error("Bad scale"); - } -} +std::string +to_string(MantissaRange::MantissaScale const& scale); + +std::string +to_string(Number::RoundingMode const& round); class SaveNumberRoundMode { @@ -911,10 +958,10 @@ public: operator=(NumberRoundModeGuard const&) = delete; }; -/** Sets the new scale and restores the old scale when it leaves scope. +/** + * Sets the new scale and restores the old scale when it leaves scope. * * If you think you need to use this class outside of unit tests, no you don't. - * */ class NumberMantissaScaleGuard { diff --git a/include/xrpl/basics/RangeSet.h b/include/xrpl/basics/RangeSet.h index e1cee8b6c4..3de882979e 100644 --- a/include/xrpl/basics/RangeSet.h +++ b/include/xrpl/basics/RangeSet.h @@ -6,29 +6,32 @@ #include #include +#include #include #include #include namespace xrpl { -/** A closed interval over the domain T. - - For an instance ClosedInterval c, this represents the closed interval - (c.first(), c.last()). A single element interval has c.first() == c.last(). - - This is simply a type-alias for boost interval container library interval - set, so users should consult that documentation for available supporting - member and free functions. -*/ +/** + * A closed interval over the domain T. + * + * For an instance ClosedInterval c, this represents the closed interval + * (c.first(), c.last()). A single element interval has c.first() == c.last(). + * + * This is simply a type-alias for boost interval container library interval + * set, so users should consult that documentation for available supporting + * member and free functions. + */ template using ClosedInterval = boost::icl::closed_interval; -/** Create a closed range interval - - Helper function to create a closed range interval without having to qualify - the template argument. -*/ +/** + * Create a closed range interval + * + * Helper function to create a closed range interval without having to qualify + * the template argument. + */ template ClosedInterval range(T low, T high) @@ -36,28 +39,30 @@ range(T low, T high) return ClosedInterval(low, high); } -/** A set of closed intervals over the domain T. - - Represents a set of values of the domain T using the minimum number - of disjoint ClosedInterval. This is useful to represent ranges of - T where a few instances are missing, e.g. the set 1-5,8-9,11-14. - - This is simply a type-alias for boost interval container library interval - set, so users should consult that documentation for available supporting - member and free functions. -*/ +/** + * A set of closed intervals over the domain T. + * + * Represents a set of values of the domain T using the minimum number + * of disjoint ClosedInterval. This is useful to represent ranges of + * T where a few instances are missing, e.g. the set 1-5,8-9,11-14. + * + * This is simply a type-alias for boost interval container library interval + * set, so users should consult that documentation for available supporting + * member and free functions. + */ template using RangeSet = boost::icl::interval_set>; -/** Convert a ClosedInterval to a styled string - - The styled string is - "c.first()-c.last()" if c.first() != c.last() - "c.first()" if c.first() == c.last() - - @param ci The closed interval to convert - @return The style string -*/ +/** + * Convert a ClosedInterval to a styled string + * + * The styled string is + * "c.first()-c.last()" if c.first() != c.last() + * "c.first()" if c.first() == c.last() + * + * @param ci The closed interval to convert + * @return The style string + */ template std::string to_string(ClosedInterval const& ci) @@ -67,14 +72,15 @@ to_string(ClosedInterval const& ci) return std::to_string(ci.first()) + "-" + std::to_string(ci.last()); } -/** Convert the given RangeSet to a styled string. - - The styled string representation is the set of disjoint intervals joined - by commas. The string "empty" is returned if the set is empty. - - @param rs The rangeset to convert - @return The styled string -*/ +/** + * Convert the given RangeSet to a styled string. + * + * The styled string representation is the set of disjoint intervals joined + * by commas. The string "empty" is returned if the set is empty. + * + * @param rs The rangeset to convert + * @return The styled string + */ template std::string to_string(RangeSet const& rs) @@ -90,15 +96,16 @@ to_string(RangeSet const& rs) return s; } -/** Convert the given styled string to a RangeSet. - - The styled string representation is the set - of disjoint intervals joined by commas. - - @param rs The set to be populated - @param s The styled string to convert - @return True on successfully converting styled string -*/ +/** + * Convert the given styled string to a RangeSet. + * + * The styled string representation is the set + * of disjoint intervals joined by commas. + * + * @param rs The set to be populated + * @param s The styled string to convert + * @return True on successfully converting styled string + */ template [[nodiscard]] bool fromString(RangeSet& rs, std::string const& s) @@ -160,14 +167,15 @@ fromString(RangeSet& rs, std::string const& s) return result; } -/** Find the largest value not in the set that is less than a given value. - - @param rs The set of interest - @param t The value that must be larger than the result - @param minVal (Default is 0) The smallest allowed value - @return The largest v such that minV <= v < t and !contains(rs, v) or - std::nullopt if no such v exists. -*/ +/** + * Find the largest value not in the set that is less than a given value. + * + * @param rs The set of interest + * @param t The value that must be larger than the result + * @param minVal (Default is 0) The smallest allowed value + * @return The largest v such that minV <= v < t and !contains(rs, v) or + * std::nullopt if no such v exists. + */ template std::optional prevMissing(RangeSet const& rs, T t, T minVal = 0) diff --git a/include/xrpl/basics/Resolver.h b/include/xrpl/basics/Resolver.h index 3b6a950247..239eb9630e 100644 --- a/include/xrpl/basics/Resolver.h +++ b/include/xrpl/basics/Resolver.h @@ -3,6 +3,7 @@ #include #include +#include #include namespace xrpl { @@ -14,22 +15,29 @@ public: virtual ~Resolver() = 0; - /** Issue an asynchronous stop request. */ + /** + * Issue an asynchronous stop request. + */ virtual void stopAsync() = 0; - /** Issue a synchronous stop request. */ + /** + * Issue a synchronous stop request. + */ virtual void stop() = 0; - /** Issue a synchronous start request. */ + /** + * Issue a synchronous start request. + */ virtual void start() = 0; - /** resolve all hostnames on the list - @param names the names to be resolved - @param handler the handler to call - */ + /** + * resolve all hostnames on the list + * @param names the names to be resolved + * @param handler the handler to call + */ /** @{ */ template void diff --git a/include/xrpl/basics/ResolverAsio.h b/include/xrpl/basics/ResolverAsio.h index 2764777327..0b78b9747c 100644 --- a/include/xrpl/basics/ResolverAsio.h +++ b/include/xrpl/basics/ResolverAsio.h @@ -5,6 +5,8 @@ #include +#include + namespace xrpl { class ResolverAsio : public Resolver diff --git a/include/xrpl/basics/SHAMapHash.h b/include/xrpl/basics/SHAMapHash.h index 76d9d4fa3d..3c3d525022 100644 --- a/include/xrpl/basics/SHAMapHash.h +++ b/include/xrpl/basics/SHAMapHash.h @@ -3,7 +3,9 @@ #include #include +#include #include +#include namespace xrpl { diff --git a/include/xrpl/basics/SharedWeakCachePointer.h b/include/xrpl/basics/SharedWeakCachePointer.h index c2c3239eea..1b78af2fae 100644 --- a/include/xrpl/basics/SharedWeakCachePointer.h +++ b/include/xrpl/basics/SharedWeakCachePointer.h @@ -1,17 +1,20 @@ #pragma once +#include +#include #include #include namespace xrpl { -/** A combination of a std::shared_ptr and a std::weak_pointer. - - -This class is a wrapper to a `std::variant` -This class is useful for storing intrusive pointers in tagged caches using less -memory than storing both pointers directly. -*/ +/** + * A combination of a std::shared_ptr and a std::weak_pointer. + * + * + * This class is a wrapper to a `std::variant` + * This class is useful for storing intrusive pointers in tagged caches using less + * memory than storing both pointers directly. + */ template class SharedWeakCachePointer @@ -46,65 +49,79 @@ public: ~SharedWeakCachePointer(); - /** Return a strong pointer if this is already a strong pointer (i.e. don't - lock the weak pointer. Use the `lock` method if that's what's needed) + /** + * Return a strong pointer if this is already a strong pointer (i.e. don't + * lock the weak pointer. Use the `lock` method if that's what's needed) */ [[nodiscard]] std::shared_ptr const& getStrong() const; - /** Return true if this is a strong pointer and the strong pointer is - seated. + /** + * Return true if this is a strong pointer and the strong pointer is + * seated. */ explicit operator bool() const noexcept; - /** Set the pointer to null, decrement the appropriate ref count, and run - the appropriate release action. + /** + * Set the pointer to null, decrement the appropriate ref count, and run + * the appropriate release action. */ void reset(); - /** If this is a strong pointer, return the raw pointer. Otherwise return - null. + /** + * If this is a strong pointer, return the raw pointer. Otherwise return + * null. */ [[nodiscard]] T* get() const; - /** If this is a strong pointer, return the strong count. Otherwise return 0 + /** + * If this is a strong pointer, return the strong count. Otherwise return 0 */ [[nodiscard]] std::size_t useCount() const; - /** Return true if there is a non-zero strong count. */ + /** + * Return true if there is a non-zero strong count. + */ [[nodiscard]] bool expired() const; - /** If this is a strong pointer, return the strong pointer. Otherwise - attempt to lock the weak pointer. + /** + * If this is a strong pointer, return the strong pointer. Otherwise + * attempt to lock the weak pointer. */ [[nodiscard]] std::shared_ptr lock() const; - /** Return true is this represents a strong pointer. */ + /** + * Return true is this represents a strong pointer. + */ [[nodiscard]] bool isStrong() const; - /** Return true is this represents a weak pointer. */ + /** + * Return true is this represents a weak pointer. + */ [[nodiscard]] bool isWeak() const; - /** If this is a weak pointer, attempt to convert it to a strong pointer. - - @return true if successfully converted to a strong pointer (or was - already a strong pointer). Otherwise false. - */ + /** + * If this is a weak pointer, attempt to convert it to a strong pointer. + * + * @return true if successfully converted to a strong pointer (or was + * already a strong pointer). Otherwise false. + */ bool convertToStrong(); - /** If this is a strong pointer, attempt to convert it to a weak pointer. - - @return false if the pointer is null. Otherwise return true. - */ + /** + * If this is a strong pointer, attempt to convert it to a weak pointer. + * + * @return false if the pointer is null. Otherwise return true. + */ bool convertToWeak(); diff --git a/include/xrpl/basics/SlabAllocator.h b/include/xrpl/basics/SlabAllocator.h index 0172b1ade2..7b6e88e8bc 100644 --- a/include/xrpl/basics/SlabAllocator.h +++ b/include/xrpl/basics/SlabAllocator.h @@ -15,6 +15,7 @@ #include #include #include +#include #include #if BOOST_OS_LINUX @@ -32,7 +33,9 @@ class SlabAllocator static_assert(alignof(Type) == 8 || alignof(Type) == 4); - /** A block of memory that is owned by a slab allocator */ + /** + * A block of memory that is owned by a slab allocator + */ struct SlabBlock { // A mutex to protect the freelist for this block: @@ -79,7 +82,9 @@ class SlabAllocator SlabBlock& operator=(SlabBlock&& other) = delete; - /** Determines whether the given pointer belongs to this allocator */ + /** + * Determines whether the given pointer belongs to this allocator + */ bool own(std::uint8_t const* pIn) const noexcept { @@ -106,14 +111,15 @@ class SlabAllocator return ret; } - /** Return an item to this allocator's freelist. - - @param ptr The pointer to the chunk of memory being deallocated. - - @note This is a dangerous, private interface; the item being - returned should belong to this allocator. Debug builds - will check and assert if this is not the case. Release - builds will not. + /** + * Return an item to this allocator's freelist. + * + * @param ptr The pointer to the chunk of memory being deallocated. + * + * @note This is a dangerous, private interface; the item being + * returned should belong to this allocator. Debug builds + * will check and assert if this is not the case. Release + * builds will not. */ void deallocate(std::uint8_t* ptr) noexcept @@ -144,13 +150,14 @@ private: std::size_t const slabSize_; public: - /** Constructs a slab allocator able to allocate objects of a fixed size - - @param count the number of items the slab allocator can allocate; note - that a count of 0 is valid and means that the allocator - is, effectively, disabled. This can be very useful in some - contexts (e.g. when minimal memory usage is needed) and - allows for graceful failure. + /** + * Constructs a slab allocator able to allocate objects of a fixed size + * + * @param count the number of items the slab allocator can allocate; note + * that a count of 0 is valid and means that the allocator + * is, effectively, disabled. This can be very useful in some + * contexts (e.g. when minimal memory usage is needed) and + * allows for graceful failure. */ constexpr explicit SlabAllocator( std::size_t extra, @@ -178,17 +185,20 @@ public: // shutdown process up could make this possible. ~SlabAllocator() = default; - /** Returns the size of the memory block this allocator returns. */ + /** + * Returns the size of the memory block this allocator returns. + */ [[nodiscard]] constexpr std::size_t size() const noexcept { return itemSize_; } - /** Returns a suitably aligned pointer, if one is available. - - @return a pointer to a block of memory from the allocator, or - nullptr if the allocator can't satisfy this request. + /** + * Returns a suitably aligned pointer, if one is available. + * + * @return a pointer to a block of memory from the allocator, or + * nullptr if the allocator can't satisfy this request. */ std::uint8_t* allocate() noexcept @@ -249,12 +259,13 @@ public: return slab->allocate(); } - /** Returns the memory block to the allocator. - - @param ptr A pointer to a memory block. - @param size If non-zero, a hint as to the size of the block. - @return true if this memory block belonged to the allocator and has - been released; false otherwise. + /** + * Returns the memory block to the allocator. + * + * @param ptr A pointer to a memory block. + * @param size If non-zero, a hint as to the size of the block. + * @return true if this memory block belonged to the allocator and has + * been released; false otherwise. */ bool deallocate(std::uint8_t* ptr) noexcept @@ -277,7 +288,9 @@ public: } }; -/** A collection of slab allocators of various sizes for a given type. */ +/** + * A collection of slab allocators of various sizes for a given type. + */ template class SlabAllocatorSet { @@ -344,13 +357,14 @@ public: ~SlabAllocatorSet() = default; - /** Returns a suitably aligned pointer, if one is available. - - @param extra The number of extra bytes, above and beyond the size of - the object, that should be returned by the allocator. - - @return a pointer to a block of memory, or nullptr if the allocator - can't satisfy this request. + /** + * Returns a suitably aligned pointer, if one is available. + * + * @param extra The number of extra bytes, above and beyond the size of + * the object, that should be returned by the allocator. + * + * @return a pointer to a block of memory, or nullptr if the allocator + * can't satisfy this request. */ std::uint8_t* allocate(std::size_t extra) noexcept @@ -367,12 +381,13 @@ public: return nullptr; } - /** Returns the memory block to the allocator. - - @param ptr A pointer to a memory block. - - @return true if this memory block belonged to one of the allocators - in this set and has been released; false otherwise. + /** + * Returns the memory block to the allocator. + * + * @param ptr A pointer to a memory block. + * + * @return true if this memory block belonged to one of the allocators + * in this set and has been released; false otherwise. */ bool deallocate(std::uint8_t* ptr) noexcept diff --git a/include/xrpl/basics/Slice.h b/include/xrpl/basics/Slice.h index 948d012958..36e7615c3a 100644 --- a/include/xrpl/basics/Slice.h +++ b/include/xrpl/basics/Slice.h @@ -16,12 +16,13 @@ namespace xrpl { -/** An immutable linear range of bytes. - - A fully constructed Slice is guaranteed to be in a valid state. - A Slice is lightweight and copyable, it retains no ownership - of the underlying memory. -*/ +/** + * An immutable linear range of bytes. + * + * A fully constructed Slice is guaranteed to be in a valid state. + * A Slice is lightweight and copyable, it retains no ownership + * of the underlying memory. + */ class Slice { private: @@ -32,30 +33,37 @@ public: using value_type = std::uint8_t; using const_iterator = value_type const*; - /** Default constructed Slice has length 0. */ + /** + * Default constructed Slice has length 0. + */ Slice() noexcept = default; Slice(Slice const&) noexcept = default; Slice& operator=(Slice const&) noexcept = default; - /** Create a slice pointing to existing memory. */ + /** + * Create a slice pointing to existing memory. + */ Slice(void const* data, std::size_t size) noexcept : data_(reinterpret_cast(data)), size_(size) { } - /** Return `true` if the byte range is empty. */ + /** + * Return `true` if the byte range is empty. + */ [[nodiscard]] bool empty() const noexcept { return size_ == 0; } - /** Returns the number of bytes in the storage. - - This may be zero for an empty range. - */ + /** + * Returns the number of bytes in the storage. + * + * This may be zero for an empty range. + */ /** @{ */ [[nodiscard]] std::size_t size() const noexcept @@ -70,17 +78,20 @@ public: } /** @} */ - /** Return a pointer to beginning of the storage. - @note The return type is guaranteed to be a pointer - to a single byte, to facilitate pointer arithmetic. - */ + /** + * Return a pointer to beginning of the storage. + * @note The return type is guaranteed to be a pointer + * to a single byte, to facilitate pointer arithmetic. + */ [[nodiscard]] std::uint8_t const* data() const noexcept { return data_; } - /** Access raw bytes. */ + /** + * Access raw bytes. + */ std::uint8_t operator[](std::size_t i) const noexcept { @@ -88,7 +99,9 @@ public: return data_[i]; } - /** Advance the buffer. */ + /** + * Advance the buffer. + */ /** @{ */ Slice& operator+=(std::size_t n) @@ -108,7 +121,9 @@ public: } /** @} */ - /** Shrinks the slice by moving its start forward by n characters. */ + /** + * Shrinks the slice by moving its start forward by n characters. + */ void removePrefix(std::size_t n) { @@ -116,7 +131,9 @@ public: size_ -= n; } - /** Shrinks the slice by moving its end backward by n characters. */ + /** + * Shrinks the slice by moving its end backward by n characters. + */ void removeSuffix(std::size_t n) { @@ -147,16 +164,17 @@ public: return data_ + size_; } - /** Return a "sub slice" of given length starting at the given position - - Note that the subslice encompasses the range [pos, pos + rCount), - where rCount is the smaller of count and size() - pos. - - @param pos position of the first character - @count requested length - - @returns The requested subslice, if the request is valid. - @throws std::out_of_range if pos > size() + /** + * Return a "sub slice" of given length starting at the given position + * + * Note that the subslice encompasses the range [pos, pos + rCount), + * where rCount is the smaller of count and size() - pos. + * + * @param pos position of the first character + * @count requested length + * + * @return The requested subslice, if the request is valid. + * @throws std::out_of_range if pos > size() */ [[nodiscard]] Slice substr(std::size_t pos, std::size_t count = std::numeric_limits::max()) const @@ -211,15 +229,17 @@ operator<<(Stream& s, Slice const& v) } template -std::enable_if_t || std::is_same_v, Slice> +Slice makeSlice(std::array const& a) + requires(std::is_same_v || std::is_same_v) { return Slice(a.data(), a.size()); } template -std::enable_if_t || std::is_same_v, Slice> +Slice makeSlice(std::vector const& v) + requires(std::is_same_v || std::is_same_v) { return Slice(v.data(), v.size()); } diff --git a/include/xrpl/basics/StringUtilities.h b/include/xrpl/basics/StringUtilities.h index 1d3434b7ed..2b360d2fda 100644 --- a/include/xrpl/basics/StringUtilities.h +++ b/include/xrpl/basics/StringUtilities.h @@ -1,30 +1,32 @@ #pragma once #include -#include #include #include #include #include +#include #include #include #include #include #include +#include namespace xrpl { -/** Format arbitrary binary data as an SQLite "blob literal". - - In SQLite, blob literals must be encoded when used in a query. Per - https://sqlite.org/lang_expr.html#literal_values_constants_ they are - encoded as string literals containing hexadecimal data and preceded - by a single 'X' character. - - @param blob An arbitrary blob of binary data - @return The input, encoded as a blob literal. +/** + * Format arbitrary binary data as an SQLite "blob literal". + * + * In SQLite, blob literals must be encoded when used in a query. Per + * https://sqlite.org/lang_expr.html#literal_values_constants_ they are + * encoded as string literals containing hexadecimal data and preceded + * by a single 'X' character. + * + * @param blob An arbitrary blob of binary data + * @return The input, encoded as a blob literal. */ std::string sqlBlobLiteral(Blob const& blob); @@ -129,11 +131,12 @@ trimWhitespace(std::string str); std::optional toUInt64(std::string const& s); -/** Determines if the given string looks like a TOML-file hosting domain. - - Do not use this function to determine if a particular string is a valid - domain, as this function may reject domains that are otherwise valid and - doesn't check whether the TLD is valid. +/** + * Determines if the given string looks like a TOML-file hosting domain. + * + * Do not use this function to determine if a particular string is a valid + * domain, as this function may reject domains that are otherwise valid and + * doesn't check whether the TLD is valid. */ bool isProperlyFormedTomlDomain(std::string_view domain); diff --git a/include/xrpl/basics/TaggedCache.h b/include/xrpl/basics/TaggedCache.h index 973fcd828a..7bb2cb552b 100644 --- a/include/xrpl/basics/TaggedCache.h +++ b/include/xrpl/basics/TaggedCache.h @@ -1,17 +1,24 @@ #pragma once -#include -#include -#include +#include +#include // IWYU pragma: keep #include #include #include -#include +#include +#include +#include +#include +#include #include +#include #include +#include #include +#include #include +#include #include #include #include @@ -34,18 +41,19 @@ struct ReplaceDynamically; } // namespace detail -/** Map/cache combination. - This class implements a cache and a map. The cache keeps objects alive - in the map. The map allows multiple code paths that reference objects - with the same tag to get the same actual object. - - So long as data is in the cache, it will stay in memory. - If it stays in memory even after it is ejected from the cache, - the map will track it. - - @note Callers must not modify data objects that are stored in the cache - unless they hold their own lock over all cache operations. -*/ +/** + * Map/cache combination. + * This class implements a cache and a map. The cache keeps objects alive + * in the map. The map allows multiple code paths that reference objects + * with the same tag to get the same actual object. + * + * So long as data is in the cache, it will stay in memory. + * If it stays in memory even after it is ejected from the cache, + * the map will track it. + * + * @note Callers must not modify data objects that are stored in the cache + * unless they hold their own lock over all cache operations. + */ template < class Key, class T, @@ -75,11 +83,15 @@ public: beast::insight::Collector::ptr const& collector = beast::insight::NullCollector::make()); public: - /** Return the clock associated with the cache. */ + /** + * Return the clock associated with the cache. + */ clock_type& clock(); - /** Returns the number of items in the container. */ + /** + * Returns the number of items in the container. + */ std::size_t size() const; @@ -98,9 +110,10 @@ public: void reset(); - /** Refresh the last access time on a key if present. - @return `true` If the key was found. - */ + /** + * Refresh the last access time on a key if present. + * @return `true` If the key was found. + */ template bool touchIfExists(KeyComparable const& key); @@ -123,14 +136,15 @@ private: SharedPointerType const&, SharedPointerType&>; - /** Shared implementation of the canonicalize family. - - `policy` selects how a collision is resolved when `key` already exists: - detail::ReplaceCached, detail::ReplaceClient or - detail::ReplaceDynamically. For ReplaceDynamically `replaceCallback` is - invoked with the existing strong pointer and returns whether to replace - the cached value with `data`; for the tag policies it is unused. - */ + /** + * Shared implementation of the canonicalize family. + * + * `policy` selects how a collision is resolved when `key` already exists: + * detail::ReplaceCached, detail::ReplaceClient or + * detail::ReplaceDynamically. For ReplaceDynamically `replaceCallback` is + * invoked with the existing strong pointer and returns whether to replace + * the cached value with `data`; for the tag policies it is unused. + */ template bool canonicalizeImpl( @@ -140,76 +154,82 @@ private: Callback&& replaceCallback = nullptr); public: - /** Replace aliased objects with originals. - - Due to concurrency it is possible for two separate objects with - the same content and referring to the same unique "thing" to exist. - This routine eliminates the duplicate and performs a replacement - on the callers shared pointer if needed. - - `replaceCallback` is a callable taking the existing strong pointer and - returning whether to replace the cached value with `data` (true) or to - keep the cached value and write it back into `data` (false). Because the - write-back case mutates `data`, `data` must be writable. - - @param key The key corresponding to the object - @param data A shared pointer to the data corresponding to the object. - @param replaceCallback A callable (existing strong pointer -> bool). - - @return `true` if an existing live entry was found and used; `false` if a new entry was - inserted or an expired tracked entry was re-cached. - **/ + /** + * Replace aliased objects with originals. + * + * Due to concurrency it is possible for two separate objects with + * the same content and referring to the same unique "thing" to exist. + * This routine eliminates the duplicate and performs a replacement + * on the callers shared pointer if needed. + * + * `replaceCallback` is a callable taking the existing strong pointer and + * returning whether to replace the cached value with `data` (true) or to + * keep the cached value and write it back into `data` (false). Because the + * write-back case mutates `data`, `data` must be writable. + * + * @param key The key corresponding to the object + * @param data A shared pointer to the data corresponding to the object. + * @param replaceCallback A callable (existing strong pointer -> bool). + * + * @return `true` if an existing live entry was found and used; `false` if a new entry was + * inserted or an expired tracked entry was re-cached. + */ template bool canonicalize(key_type const& key, SharedPointerType& data, Callback&& replaceCallback); - /** Insert/update the canonical entry for `key`, always replacing the - cached value with `data`. - - If an entry already exists for `key`, the cached value is unconditionally - replaced with `data`; otherwise `data` is inserted. `data` is never - written back, so it may be const. - - @param key The key corresponding to the object. - @param data A shared pointer to the data corresponding to the object. - - @return `true` if an existing live entry was found and used; `false` if a new entry was - inserted or an expired tracked entry was re-cached. - **/ + /** + * Insert/update the canonical entry for `key`, always replacing the + * cached value with `data`. + * + * If an entry already exists for `key`, the cached value is unconditionally + * replaced with `data`; otherwise `data` is inserted. `data` is never + * written back, so it may be const. + * + * @param key The key corresponding to the object. + * @param data A shared pointer to the data corresponding to the object. + * + * @return `true` if an existing live entry was found and used; `false` if a new entry was + * inserted or an expired tracked entry was re-cached. + */ bool canonicalizeReplaceCache(key_type const& key, SharedPointerType const& data); - /** Insert the canonical entry for `key`, keeping any existing cached value. - - If an entry already exists for `key`, the cached value is kept and - written back into `data` so the caller ends up with the canonical - object; otherwise `data` is inserted. Because `data` may be overwritten - it must be writable. - - @param key The key corresponding to the object. - @param data A shared pointer to the data corresponding to the object; - updated to the canonical value when one already exists. - - @return `true` if an existing live entry was found and used; `false` if a new entry was - inserted or an expired tracked entry was re-cached. - **/ + /** + * Insert the canonical entry for `key`, keeping any existing cached value. + * + * If an entry already exists for `key`, the cached value is kept and + * written back into `data` so the caller ends up with the canonical + * object; otherwise `data` is inserted. Because `data` may be overwritten + * it must be writable. + * + * @param key The key corresponding to the object. + * @param data A shared pointer to the data corresponding to the object; + * updated to the canonical value when one already exists. + * + * @return `true` if an existing live entry was found and used; `false` if a new entry was + * inserted or an expired tracked entry was re-cached. + */ bool canonicalizeReplaceClient(key_type const& key, SharedPointerType& data); SharedPointerType fetch(key_type const& key); - /** Insert the element into the container. - If the key already exists, nothing happens. - @return `true` If the element was inserted - */ + /** + * Insert the element into the container. + * If the key already exists, nothing happens. + * @return `true` If the element was inserted + */ template auto - insert(key_type const& key, T const& value) -> std::enable_if_t; + insert(key_type const& key, T const& value) -> ReturnType + requires(!IsKeyCache); template auto - insert(key_type const& key) -> std::enable_if_t; + insert(key_type const& key) -> ReturnType + requires IsKeyCache; // VFALCO NOTE It looks like this returns a copy of the data in // the output parameter 'data'. This could be expensive. @@ -226,15 +246,18 @@ public: getKeys() const; // CachedSLEs functions. - /** Returns the fraction of cache hits. */ + /** + * Returns the fraction of cache hits. + */ double rate() const; - /** Fetch an item from the cache. - If the digest was not found, Handler - will be called with this signature: - SLE::const_pointer(void) - */ + /** + * Fetch an item from the cache. + * If the digest was not found, Handler + * will be called with this signature: + * SLE::const_pointer(void) + */ template SharedPointerType fetch(key_type const& digest, Handler const& h); diff --git a/include/xrpl/basics/TaggedCache.ipp b/include/xrpl/basics/TaggedCache.ipp index 7e812ce4c7..b79561c71a 100644 --- a/include/xrpl/basics/TaggedCache.ipp +++ b/include/xrpl/basics/TaggedCache.ipp @@ -1,6 +1,7 @@ #pragma once #include +#include // IWYU pragma: keep #include namespace xrpl { @@ -56,7 +57,10 @@ inline TaggedCache< beast::insight::Collector::ptr const& collector) : journal_(journal) , clock_(clock) - , stats_(name, std::bind(&TaggedCache::collectMetrics, this), collector) + , stats_( + name, + [this] { collectMetrics(); }, + collector) , name_(name) , targetSize_(size) , targetAge_(expiration) @@ -499,7 +503,8 @@ template < template inline auto TaggedCache:: - insert(key_type const& key, T const& value) -> std::enable_if_t + insert(key_type const& key, T const& value) -> ReturnType + requires(!IsKeyCache) { static_assert( std::is_same_v, SharedPointerType> || @@ -529,7 +534,8 @@ template < template inline auto TaggedCache:: - insert(key_type const& key) -> std::enable_if_t + insert(key_type const& key) -> ReturnType + requires IsKeyCache { std::scoped_lock const lock(mutex_); clock_type::time_point const now(clock_.now()); diff --git a/include/xrpl/basics/ToString.h b/include/xrpl/basics/ToString.h index 7764c1e3e3..a54db8a8ce 100644 --- a/include/xrpl/basics/ToString.h +++ b/include/xrpl/basics/ToString.h @@ -5,15 +5,17 @@ namespace xrpl { -/** to_string() generalizes std::to_string to handle bools, chars, and strings. - - It's also possible to provide implementation of to_string for a class - which needs a string implementation. +/** + * to_string() generalizes std::to_string to handle bools, chars, and strings. + * + * It's also possible to provide implementation of to_string for a class + * which needs a string implementation. */ template -std::enable_if_t, std::string> +std::string to_string(T t) // NOLINT(readability-identifier-naming) + requires(std::is_arithmetic_v) { return std::to_string(t); } diff --git a/include/xrpl/basics/UnorderedContainers.h b/include/xrpl/basics/UnorderedContainers.h index 5a417d5045..e0700c4055 100644 --- a/include/xrpl/basics/UnorderedContainers.h +++ b/include/xrpl/basics/UnorderedContainers.h @@ -2,12 +2,14 @@ #include #include -#include #include #include +#include +#include #include #include +#include /** * Use hash_* containers for keys that do not need a cryptographically secure diff --git a/include/xrpl/basics/UptimeClock.h b/include/xrpl/basics/UptimeClock.h index 502aae7c25..b375de4497 100644 --- a/include/xrpl/basics/UptimeClock.h +++ b/include/xrpl/basics/UptimeClock.h @@ -7,12 +7,13 @@ namespace xrpl { -/** Tracks program uptime to seconds precision. - - The timer caches the current time as a performance optimization. - This allows clients to query the current time thousands of times - per second. -*/ +/** + * Tracks program uptime to seconds precision. + * + * The timer caches the current time as a performance optimization. + * This allows clients to query the current time thousands of times + * per second. + */ class UptimeClock { diff --git a/include/xrpl/basics/base64.h b/include/xrpl/basics/base64.h index 660958ce14..24fd660e65 100644 --- a/include/xrpl/basics/base64.h +++ b/include/xrpl/basics/base64.h @@ -34,6 +34,7 @@ #pragma once +#include #include #include #include diff --git a/include/xrpl/basics/base_uint.h b/include/xrpl/basics/base_uint.h index 93520ff699..96cfa343e3 100644 --- a/include/xrpl/basics/base_uint.h +++ b/include/xrpl/basics/base_uint.h @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -18,8 +19,17 @@ #include #include +#include +#include +#include #include #include +#include +#include +#include +#include +#include +#include #include namespace xrpl { @@ -53,18 +63,19 @@ struct AlwaysFalseT : std::bool_constant } // namespace detail -/** Integers of any length that is a multiple of 32-bits - - @note This class stores its values internally in big-endian - form and that internal representation is part of the - binary protocol of the XRP Ledger and cannot be changed - arbitrarily without causing breakage. - - @tparam Bits The number of bits this integer should have; must - be at least 64 and a multiple of 32. - @tparam Tag An arbitrary type that functions as a tag and allows - the instantiation of "distinct" types that the same - number of bits. +/** + * Integers of any length that is a multiple of 32-bits + * + * @note This class stores its values internally in big-endian + * form and that internal representation is part of the + * binary protocol of the XRP Ledger and cannot be changed + * arbitrarily without causing breakage. + * + * @tparam Bits The number of bits this integer should have; must + * be at least 64 and a multiple of 32. + * @tparam Tag An arbitrary type that functions as a tag and allows + * the instantiation of "distinct" types that the same + * number of bits. */ template class BaseUInt @@ -87,7 +98,7 @@ public: // static constexpr std::size_t kBytes = Bits / 8; - static_assert(sizeof(data_) == kBytes, ""); + static_assert(sizeof(data_) == kBytes); using size_type = std::size_t; using difference_type = std::ptrdiff_t; @@ -144,21 +155,23 @@ public: return data() + kBytes; } - /** Value hashing function. - The seed prevents crafted inputs from causing degenerate parent - containers. - */ + /** + * Value hashing function. + * The seed prevents crafted inputs from causing degenerate parent + * containers. + */ using hasher = HardenedHash<>; //-------------------------------------------------------------------------- private: - /** Construct from a raw pointer. - The buffer pointed to by `data` must be at least Bits/8 bytes. - - @note the structure is used to disambiguate this from the std::uint64_t - constructor: something like base_uint(0) is ambiguous. - */ + /** + * Construct from a raw pointer. + * The buffer pointed to by `data` must be at least Bits/8 bytes. + * + * @note the structure is used to disambiguate this from the std::uint64_t + * constructor: something like base_uint(0) is ambiguous. + */ // NIKB TODO Remove the need for this constructor. struct VoidHelper { @@ -270,12 +283,11 @@ public: { } - template < - class Container, - class = std::enable_if_t< - detail::IsContiguousContainer::value && - std::is_trivially_copyable_v>> + template explicit BaseUInt(Container const& c) + requires( + detail::IsContiguousContainer::value && + std::is_trivially_copyable_v) { // Use AlwaysFalseT so the static_assert condition is dependent // and only triggers when this constructor template is instantiated. @@ -285,13 +297,12 @@ public: "Use base_uint::fromRaw instead."); } - template < - class Container, - class = std::enable_if_t< - detail::IsContiguousContainer::value && - std::is_trivially_copyable_v>> + template static BaseUInt fromRaw(Container const& c) + requires( + detail::IsContiguousContainer::value && + std::is_trivially_copyable_v) { BaseUInt result; XRPL_ASSERT( @@ -302,11 +313,11 @@ public: } template - std::enable_if_t< - detail::IsContiguousContainer::value && - std::is_trivially_copyable_v, - BaseUInt&> + BaseUInt& operator=(Container const& c) + requires( + detail::IsContiguousContainer::value && + std::is_trivially_copyable_v) { XRPL_ASSERT( c.size() * sizeof(typename Container::value_type) == size(), @@ -495,13 +506,14 @@ public: h(a.data_.data(), sizeof(a.data_)); } - /** Parse a hex string into a base_uint - - The input must be precisely `2 * bytes` hexadecimal characters - long, with one exception: the value '0'. - - @param sv A null-terminated string of hexadecimal characters - @return true if the input was parsed properly; false otherwise. + /** + * Parse a hex string into a base_uint + * + * The input must be precisely `2 * bytes` hexadecimal characters + * long, with one exception: the value '0'. + * + * @param sv A null-terminated string of hexadecimal characters + * @return true if the input was parsed properly; false otherwise. */ [[nodiscard]] constexpr bool parseHex(std::string_view sv) @@ -587,7 +599,7 @@ template [[nodiscard]] constexpr bool operator==(BaseUInt const& lhs, BaseUInt const& rhs) { - return (lhs <=> rhs) == 0; + return (lhs <=> rhs) == 0; // NOLINT(modernize-use-nullptr) } //------------------------------------------------------------------------------ diff --git a/include/xrpl/basics/chrono.h b/include/xrpl/basics/chrono.h index 5d6de06248..b855318524 100644 --- a/include/xrpl/basics/chrono.h +++ b/include/xrpl/basics/chrono.h @@ -10,6 +10,7 @@ #include #include #include +#include namespace xrpl { @@ -20,15 +21,16 @@ using days = using weeks = std::chrono::duration>>; -/** Clock for measuring the network time. - - The epoch is January 1, 2000 - - epoch_offset - = date(2000-01-01) - date(1970-0-01) - = days(10957) - = seconds(946684800) -*/ +/** + * Clock for measuring the network time. + * + * The epoch is January 1, 2000 + * + * epoch_offset + * = date(2000-01-01) - date(1970-0-01) + * = days(10957) + * = seconds(946684800) + */ static constexpr std::chrono::seconds kEpochOffset = date::sys_days{date::year{2000} / 1 / 1} - date::sys_days{date::year{1970} / 1 / 1}; @@ -80,16 +82,21 @@ toStringIso(NetClock::time_point tp) return toStringIso(date::sys_time{tp.time_since_epoch() + kEpochOffset}); } -/** A clock for measuring elapsed time. - - The epoch is unspecified. -*/ +/** + * A clock for measuring elapsed time. + * + * The epoch is unspecified. + */ using Stopwatch = beast::AbstractClock; -/** A manual Stopwatch for unit tests. */ +/** + * A manual Stopwatch for unit tests. + */ using TestStopwatch = beast::ManualClock; -/** Returns an instance of a wall clock. */ +/** + * Returns an instance of a wall clock. + */ inline Stopwatch& stopwatch() { diff --git a/include/xrpl/basics/comparators.h b/include/xrpl/basics/comparators.h deleted file mode 100644 index 0e21d38d6b..0000000000 --- a/include/xrpl/basics/comparators.h +++ /dev/null @@ -1,54 +0,0 @@ -#pragma once - -#include - -namespace xrpl { - -#ifdef _MSC_VER - -/* - * MSVC 2019 version 16.9.0 added [[nodiscard]] to the std comparison - * operator() functions. boost::bimap checks that the comparator is a - * BinaryFunction, in part by calling the function and ignoring the value. - * These two things don't play well together. These wrapper classes simply - * strip [[nodiscard]] from operator() for use in boost::bimap. - * - * See also: - * https://www.boost.org/doc/libs/1_75_0/libs/bimap/doc/html/boost_bimap/the_tutorial/controlling_collection_types.html - */ - -template -struct less -{ - using result_type = bool; - - constexpr bool - operator()(T const& left, T const& right) const - { - return std::less()(left, right); - } -}; - -template -struct equal_to -{ - using result_type = bool; - - constexpr bool - operator()(T const& left, T const& right) const - { - return std::equal_to()(left, right); - } -}; - -#else - -template -using less = std::less; - -template -using equal_to = std::equal_to; - -#endif - -} // namespace xrpl diff --git a/include/xrpl/basics/contract.h b/include/xrpl/basics/contract.h index 0e90687de3..6588cb5d1a 100644 --- a/include/xrpl/basics/contract.h +++ b/include/xrpl/basics/contract.h @@ -15,20 +15,23 @@ namespace xrpl { preconditions, postconditions, and invariants. */ -/** Generates and logs a call stack */ +/** + * Generates and logs a call stack + */ void logThrow(std::string const& title); -/** Rethrow the exception currently being handled. - - When called from within a catch block, it will pass - control to the next matching exception handler, if any. - Otherwise, std::terminate will be called. - - ASAN can't handle sudden jumps in control flow very well. This - function is marked as XRPL_NO_SANITIZE_ADDRESS to prevent it from - triggering false positives, since it throws. -*/ +/** + * Rethrow the exception currently being handled. + * + * When called from within a catch block, it will pass + * control to the next matching exception handler, if any. + * Otherwise, std::terminate will be called. + * + * ASAN can't handle sudden jumps in control flow very well. This + * function is marked as XRPL_NO_SANITIZE_ADDRESS to prevent it from + * triggering false positives, since it throws. + */ [[noreturn]] XRPL_NO_SANITIZE_ADDRESS inline void rethrow() { @@ -56,7 +59,9 @@ Throw(Args&&... args) throw std::move(e); } -/** Called when faulty logic causes a broken invariant. */ +/** + * Called when faulty logic causes a broken invariant. + */ [[noreturn]] void logicError(std::string const& how) noexcept; diff --git a/include/xrpl/basics/hardened_hash.h b/include/xrpl/basics/hardened_hash.h index b8ea1e0f3f..6b8277a560 100644 --- a/include/xrpl/basics/hardened_hash.h +++ b/include/xrpl/basics/hardened_hash.h @@ -1,6 +1,5 @@ #pragma once -#include #include #include @@ -40,33 +39,33 @@ makeSeedPair() noexcept /** * Seed functor once per construction - - A std compatible hash adapter that resists adversarial inputs. - For this to work, T must implement in its own namespace: - - @code - - template - void - hash_append (Hasher& h, T const& t) noexcept - { - // hash_append each base and member that should - // participate in forming the hash - using beast::hash_append; - hash_append (h, static_cast(t)); - hash_append (h, static_cast(t)); - // ... - hash_append (h, t.member1); - hash_append (h, t.member2); - // ... - } - - @endcode - - Do not use any version of Murmur or CityHash for the Hasher - template parameter (the hashing algorithm). For details - see https://131002.net/siphash/#at -*/ + * + * A std compatible hash adapter that resists adversarial inputs. + * For this to work, T must implement in its own namespace: + * + * @code + * + * template + * void + * hash_append (Hasher& h, T const& t) noexcept + * { + * // hash_append each base and member that should + * // participate in forming the hash + * using beast::hash_append; + * hash_append (h, static_cast(t)); + * hash_append (h, static_cast(t)); + * // ... + * hash_append (h, t.member1); + * hash_append (h, t.member2); + * // ... + * } + * + * @endcode + * + * Do not use any version of Murmur or CityHash for the Hasher + * template parameter (the hashing algorithm). For details + * see https://131002.net/siphash/#at + */ template class HardenedHash diff --git a/include/xrpl/basics/join.h b/include/xrpl/basics/join.h index c214212473..492e4f3122 100644 --- a/include/xrpl/basics/join.h +++ b/include/xrpl/basics/join.h @@ -1,7 +1,9 @@ #pragma once +#include #include #include +#include namespace xrpl { diff --git a/include/xrpl/basics/make_SSLContext.h b/include/xrpl/basics/make_SSLContext.h index 46f6a15e84..c8ada176f9 100644 --- a/include/xrpl/basics/make_SSLContext.h +++ b/include/xrpl/basics/make_SSLContext.h @@ -2,15 +2,20 @@ #include +#include #include namespace xrpl { -/** Create a self-signed SSL context that allows anonymous Diffie Hellman. */ +/** + * Create a self-signed SSL context that allows anonymous Diffie Hellman. + */ std::shared_ptr makeSslContext(std::string const& cipherList); -/** Create an authenticated SSL context using the specified files. */ +/** + * Create an authenticated SSL context using the specified files. + */ std::shared_ptr makeSslContextAuthed( std::string const& keyFile, diff --git a/include/xrpl/basics/mulDiv.h b/include/xrpl/basics/mulDiv.h index 9076da62f2..38fa57294b 100644 --- a/include/xrpl/basics/mulDiv.h +++ b/include/xrpl/basics/mulDiv.h @@ -7,16 +7,16 @@ namespace xrpl { constexpr auto kMuldivMax = std::numeric_limits::max(); -/** Return value*mul/div accurately. - Computes the result of the multiplication and division in - a single step, avoiding overflow and retaining precision. - Throws: - None - Returns: - `std::optional`: - `std::nullopt` if the calculation overflows. Otherwise, `value * mul - / div`. -*/ +/** + * Return value*mul/div accurately. + * + * Computes the result of the multiplication and division in + * a single step, avoiding overflow and retaining precision. + * + * @throws None + * @return `std::nullopt` if the calculation overflows. Otherwise, + * `value * mul / div`. + */ std::optional mulDiv(std::uint64_t value, std::uint64_t mul, std::uint64_t div); diff --git a/include/xrpl/basics/partitioned_unordered_map.h b/include/xrpl/basics/partitioned_unordered_map.h index c51cedf2dd..e78043e252 100644 --- a/include/xrpl/basics/partitioned_unordered_map.h +++ b/include/xrpl/basics/partitioned_unordered_map.h @@ -3,7 +3,10 @@ #include #include +#include #include +#include +#include #include #include #include @@ -135,11 +138,8 @@ public: { } - ConstIterator(Iterator const& orig) + ConstIterator(Iterator const& orig) : map(orig.map), ait(orig.ait), mit(orig.mit) { - map = orig.map; - ait = orig.ait; - mit = orig.mit; } const_reference @@ -228,11 +228,11 @@ private: public: PartitionedUnorderedMap(std::optional partitions = std::nullopt) - { // Set partitions to the number of hardware threads if the parameter // is either empty or set to 0. - partitions_ = - partitions && (*partitions != 0u) ? *partitions : std::thread::hardware_concurrency(); + : partitions_( + partitions && (*partitions != 0u) ? *partitions : std::thread::hardware_concurrency()) + { map_.resize(partitions_); XRPL_ASSERT( partitions_, diff --git a/include/xrpl/basics/random.h b/include/xrpl/basics/random.h index 0b298e12d9..7aeb7d6145 100644 --- a/include/xrpl/basics/random.h +++ b/include/xrpl/basics/random.h @@ -3,7 +3,6 @@ #include #include -#include #include #include #include @@ -34,16 +33,17 @@ template using is_engine = std::is_invocable_r; } // namespace detail -/** Return the default random engine. - - This engine is guaranteed to be deterministic, but by - default will be randomly seeded. It is NOT cryptographically - secure and MUST NOT be used to generate randomness that - will be used for keys, secure cookies, IVs, padding, etc. - - Each thread gets its own instance of the engine which - will be randomly seeded. -*/ +/** + * Return the default random engine. + * + * This engine is guaranteed to be deterministic, but by + * default will be randomly seeded. It is NOT cryptographically + * secure and MUST NOT be used to generate randomness that + * will be used for keys, secure cookies, IVs, padding, etc. + * + * Each thread gets its own instance of the engine which + * will be randomly seeded. + */ inline beast::xor_shift_engine& defaultPrng() { @@ -71,29 +71,31 @@ defaultPrng() return kEngine; } -/** Return a uniformly distributed random integer. - - @param min The smallest value to return. If not specified - the value defaults to 0. - @param max The largest value to return. If not specified - the value defaults to the largest value that - can be represented. - - The randomness is generated by the specified engine (or - the default engine if one is not specified). The result - is cryptographically secure only when the engine passed - into the function is cryptographically secure. - - @note The range is always a closed interval, so calling - rand_int(-5, 15) can return any integer in the - closed interval [-5, 15]; similarly, calling - rand_int(7) can return any integer in the closed - interval [0, 7]. -*/ +/** + * Return a uniformly distributed random integer. + * + * @param min The smallest value to return. If not specified + * the value defaults to 0. + * @param max The largest value to return. If not specified + * the value defaults to the largest value that + * can be represented. + * + * The randomness is generated by the specified engine (or + * the default engine if one is not specified). The result + * is cryptographically secure only when the engine passed + * into the function is cryptographically secure. + * + * @note The range is always a closed interval, so calling + * rand_int(-5, 15) can return any integer in the + * closed interval [-5, 15]; similarly, calling + * rand_int(7) can return any integer in the closed + * interval [0, 7]. + */ /** @{ */ template -std::enable_if_t && detail::is_engine::value, Integral> +Integral randInt(Engine& engine, Integral min, Integral max) + requires(std::is_integral_v && detail::is_engine::value) { XRPL_ASSERT(max > min, "xrpl::randInt : max over min inputs"); @@ -104,63 +106,73 @@ randInt(Engine& engine, Integral min, Integral max) } template -std::enable_if_t, Integral> +Integral randInt(Integral min, Integral max) + requires(std::is_integral_v) { return randInt(defaultPrng(), min, max); } template -std::enable_if_t && detail::is_engine::value, Integral> +Integral randInt(Engine& engine, Integral max) + requires(std::is_integral_v && detail::is_engine::value) { return randInt(engine, Integral(0), max); } template -std::enable_if_t, Integral> +Integral randInt(Integral max) + requires(std::is_integral_v) { return randInt(defaultPrng(), max); } template -std::enable_if_t && detail::is_engine::value, Integral> +Integral randInt(Engine& engine) + requires(std::is_integral_v && detail::is_engine::value) { return randInt(engine, std::numeric_limits::max()); } template -std::enable_if_t, Integral> +Integral randInt() + requires(std::is_integral_v) { return randInt(defaultPrng(), std::numeric_limits::max()); } /** @} */ -/** Return a random byte */ +/** + * Return a random byte + */ /** @{ */ template -std::enable_if_t< - (std::is_same_v || std::is_same_v) && - detail::is_engine::value, - Byte> +Byte randByte(Engine& engine) + requires( + (std::is_same_v || std::is_same_v) && + detail::is_engine::value) { return static_cast(randInt( engine, std::numeric_limits::min(), std::numeric_limits::max())); } template -std::enable_if_t<(std::is_same_v || std::is_same_v), Byte> +Byte randByte() + requires(std::is_same_v || std::is_same_v) { return randByte(defaultPrng()); } /** @} */ -/** Return a random boolean value */ +/** + * Return a random boolean value + */ /** @{ */ template inline bool diff --git a/include/xrpl/basics/safe_cast.h b/include/xrpl/basics/safe_cast.h index f71edc47ad..7f2b93a7eb 100644 --- a/include/xrpl/basics/safe_cast.h +++ b/include/xrpl/basics/safe_cast.h @@ -1,6 +1,6 @@ #pragma once -#include +#include // IWYU pragma: keep #include @@ -17,8 +17,9 @@ concept SafeToCast = (std::is_integral_v && std::is_integral_v) && : sizeof(Dest) >= sizeof(Src)); template -constexpr std::enable_if_t && std::is_integral_v, Dest> +constexpr Dest safeCast(Src s) noexcept + requires(std::is_integral_v && std::is_integral_v) { static_assert( std::is_signed_v || std::is_unsigned_v, "Cannot cast signed to unsigned"); @@ -30,15 +31,17 @@ safeCast(Src s) noexcept } template -constexpr std::enable_if_t && std::is_integral_v, Dest> +constexpr Dest safeCast(Src s) noexcept + requires(std::is_enum_v && std::is_integral_v) { return static_cast(safeCast>(s)); } template -constexpr std::enable_if_t && std::is_enum_v, Dest> +constexpr Dest safeCast(Src s) noexcept + requires(std::is_integral_v && std::is_enum_v) { return safeCast(static_cast>(s)); } @@ -48,8 +51,9 @@ safeCast(Src s) noexcept // underlying types become safe, it can be converted to a safe_cast. template -constexpr std::enable_if_t && std::is_integral_v, Dest> +constexpr Dest unsafeCast(Src s) noexcept + requires(std::is_integral_v && std::is_integral_v) { static_assert( !SafeToCast, @@ -59,15 +63,17 @@ unsafeCast(Src s) noexcept } template -constexpr std::enable_if_t && std::is_integral_v, Dest> +constexpr Dest unsafeCast(Src s) noexcept + requires(std::is_enum_v && std::is_integral_v) { return static_cast(unsafeCast>(s)); } template -constexpr std::enable_if_t && std::is_enum_v, Dest> +constexpr Dest unsafeCast(Src s) noexcept + requires(std::is_integral_v && std::is_enum_v) { return unsafeCast(static_cast>(s)); } diff --git a/include/xrpl/basics/scope.h b/include/xrpl/basics/scope.h index cfd21e6e30..5821e1dacc 100644 --- a/include/xrpl/basics/scope.h +++ b/include/xrpl/basics/scope.h @@ -46,11 +46,9 @@ public: operator=(ScopeExit&&) = delete; template - explicit ScopeExit( - EFP&& f, - std::enable_if_t< - !std::is_same_v, ScopeExit> && - std::is_constructible_v>* = 0) noexcept + explicit ScopeExit(EFP&& f) noexcept + requires( + !std::is_same_v, ScopeExit> && std::is_constructible_v) : exitFunction_{std::forward(f)} { static_assert(std::is_nothrow_constructible_v(f))>); @@ -93,11 +91,9 @@ public: operator=(ScopeFail&&) = delete; template - explicit ScopeFail( - EFP&& f, - std::enable_if_t< - !std::is_same_v, ScopeFail> && - std::is_constructible_v>* = 0) noexcept + explicit ScopeFail(EFP&& f) noexcept + requires( + !std::is_same_v, ScopeFail> && std::is_constructible_v) : exitFunction_{std::forward(f)} { static_assert(std::is_nothrow_constructible_v(f))>); @@ -140,12 +136,11 @@ public: operator=(ScopeSuccess&&) = delete; template - explicit ScopeSuccess( - EFP&& f, - std::enable_if_t< + explicit ScopeSuccess(EFP&& f) noexcept( + std::is_nothrow_constructible_v || std::is_nothrow_constructible_v) + requires( !std::is_same_v, ScopeSuccess> && - std::is_constructible_v>* = - 0) noexcept(std::is_nothrow_constructible_v || std::is_nothrow_constructible_v) + std::is_constructible_v) : exitFunction_{std::forward(f)} { } @@ -161,41 +156,41 @@ template ScopeSuccess(EF) -> ScopeSuccess; /** - Automatically unlocks and re-locks a unique_lock object. - - This is the reverse of a std::unique_lock object - instead of locking the - mutex for the lifetime of this object, it unlocks it. - - Make sure you don't try to unlock mutexes that aren't actually locked! - - This is essentially a less-versatile boost::reverse_lock. - - e.g. @code - - std::mutex mut; - - for (;;) - { - std::unique_lock myScopedLock{mut}; - // mut is now locked - - ... do some stuff with it locked .. - - while (xyz) - { - ... do some stuff with it locked .. - - scope_unlock unlocker{myScopedLock}; - - // mut is now unlocked for the remainder of this block, - // and re-locked at the end. - - ...do some stuff with it unlocked ... - } // mut gets locked here. - - } // mut gets unlocked here - @endcode -*/ + * Automatically unlocks and re-locks a unique_lock object. + * + * This is the reverse of a std::unique_lock object - instead of locking the + * mutex for the lifetime of this object, it unlocks it. + * + * Make sure you don't try to unlock mutexes that aren't actually locked! + * + * This is essentially a less-versatile boost::reverse_lock. + * + * e.g. @code + * + * std::mutex mut; + * + * for (;;) + * { + * std::unique_lock myScopedLock{mut}; + * // mut is now locked + * + * ... do some stuff with it locked .. + * + * while (xyz) + * { + * ... do some stuff with it locked .. + * + * scope_unlock unlocker{myScopedLock}; + * + * // mut is now unlocked for the remainder of this block, + * // and re-locked at the end. + * + * ...do some stuff with it unlocked ... + * } // mut gets locked here. + * + * } // mut gets unlocked here + * @endcode + */ template class ScopeUnlock diff --git a/include/xrpl/basics/spinlock.h b/include/xrpl/basics/spinlock.h index 2cc00efdef..87611f20ba 100644 --- a/include/xrpl/basics/spinlock.h +++ b/include/xrpl/basics/spinlock.h @@ -15,15 +15,16 @@ namespace xrpl { namespace detail { -/** Inform the processor that we are in a tight spin-wait loop. - - Spinlocks caught in tight loops can result in the processor's pipeline - filling up with comparison operations, resulting in a misprediction at - the time the lock is finally acquired, necessitating pipeline flushing - which is ridiculously expensive and results in very high latency. - - This function instructs the processor to "pause" for some architecture - specific amount of time, to prevent this. +/** + * Inform the processor that we are in a tight spin-wait loop. + * + * Spinlocks caught in tight loops can result in the processor's pipeline + * filling up with comparison operations, resulting in a misprediction at + * the time the lock is finally acquired, necessitating pipeline flushing + * which is ridiculously expensive and results in very high latency. + * + * This function instructs the processor to "pause" for some architecture + * specific amount of time, to prevent this. */ inline void spinPause() noexcept @@ -38,37 +39,39 @@ spinPause() noexcept } // namespace detail /** @{ */ -/** Classes to handle arrays of spinlocks packed into a single atomic integer: - - Packed spinlocks allow for tremendously space-efficient lock-sharding - but they come at a cost. - - First, the implementation is necessarily low-level and uses advanced - features like memory ordering and highly platform-specific tricks to - maximize performance. This imposes a significant and ongoing cost to - developers. - - Second, and perhaps most important, is that the packing of multiple - locks into a single integer which, albeit space-efficient, also has - performance implications stemming from data dependencies, increased - cache-coherency traffic between processors and heavier loads on the - processor's load/store units. - - To be sure, these locks can have advantages but they are definitely - not general purpose locks and should not be thought of or used that - way. The use cases for them are likely few and far between; without - a compelling reason to use them, backed by profiling data, it might - be best to use one of the standard locking primitives instead. Note - that in most common platforms, `std::mutex` is so heavily optimized - that it can, usually, outperform spinlocks. - - @tparam T An unsigned integral type (e.g. std::uint16_t) +/** + * Classes to handle arrays of spinlocks packed into a single atomic integer: + * + * Packed spinlocks allow for tremendously space-efficient lock-sharding + * but they come at a cost. + * + * First, the implementation is necessarily low-level and uses advanced + * features like memory ordering and highly platform-specific tricks to + * maximize performance. This imposes a significant and ongoing cost to + * developers. + * + * Second, and perhaps most important, is that the packing of multiple + * locks into a single integer which, albeit space-efficient, also has + * performance implications stemming from data dependencies, increased + * cache-coherency traffic between processors and heavier loads on the + * processor's load/store units. + * + * To be sure, these locks can have advantages but they are definitely + * not general purpose locks and should not be thought of or used that + * way. The use cases for them are likely few and far between; without + * a compelling reason to use them, backed by profiling data, it might + * be best to use one of the standard locking primitives instead. Note + * that in most common platforms, `std::mutex` is so heavily optimized + * that it can, usually, outperform spinlocks. + * + * @tparam T An unsigned integral type (e.g. std::uint16_t) */ -/** A class that grabs a single packed spinlock from an atomic integer. - - This class meets the requirements of Lockable: - https://en.cppreference.com/w/cpp/named_req/Lockable +/** + * A class that grabs a single packed spinlock from an atomic integer. + * + * This class meets the requirements of Lockable: + * https://en.cppreference.com/w/cpp/named_req/Lockable */ template class PackedSpinlock @@ -91,13 +94,14 @@ public: PackedSpinlock& operator=(PackedSpinlock const&) = delete; - /** A single spinlock packed inside the specified atomic - - @param lock The atomic integer inside which the spinlock is packed. - @param index The index of the spinlock this object acquires. - - @note For performance reasons, you should strive to have `lock` be - on a cacheline by itself. + /** + * A single spinlock packed inside the specified atomic + * + * @param lock The atomic integer inside which the spinlock is packed. + * @param index The index of the spinlock this object acquires. + * + * @note For performance reasons, you should strive to have `lock` be + * on a cacheline by itself. */ PackedSpinlock(std::atomic& lock, int index) : bits_(lock), mask_(static_cast(1) << index) { @@ -133,17 +137,18 @@ public: } }; -/** A spinlock implemented on top of an atomic integer. - - @note Using `packed_spinlock` and `spinlock` against the same underlying - atomic integer can result in `spinlock` not being able to actually - acquire the lock during periods of high contention, because of how - the two locks operate: `spinlock` will spin trying to grab all the - bits at once, whereas any given `packed_spinlock` will only try to - grab one bit at a time. Caveat emptor. - - This class meets the requirements of Lockable: - https://en.cppreference.com/w/cpp/named_req/Lockable +/** + * A spinlock implemented on top of an atomic integer. + * + * @note Using `packed_spinlock` and `spinlock` against the same underlying + * atomic integer can result in `spinlock` not being able to actually + * acquire the lock during periods of high contention, because of how + * the two locks operate: `spinlock` will spin trying to grab all the + * bits at once, whereas any given `packed_spinlock` will only try to + * grab one bit at a time. Caveat emptor. + * + * This class meets the requirements of Lockable: + * https://en.cppreference.com/w/cpp/named_req/Lockable */ template class Spinlock @@ -159,12 +164,13 @@ public: Spinlock& operator=(Spinlock const&) = delete; - /** Grabs the - - @param lock The atomic integer to spin against. - - @note For performance reasons, you should strive to have `lock` be - on a cacheline by itself. + /** + * Grabs the + * + * @param lock The atomic integer to spin against. + * + * @note For performance reasons, you should strive to have `lock` be + * on a cacheline by itself. */ Spinlock(std::atomic& lock) : lock_(lock) { diff --git a/include/xrpl/basics/strHex.h b/include/xrpl/basics/strHex.h index 9cae234f06..1366515bd3 100644 --- a/include/xrpl/basics/strHex.h +++ b/include/xrpl/basics/strHex.h @@ -3,6 +3,9 @@ #include #include +#include +#include + namespace xrpl { template diff --git a/include/xrpl/basics/tagged_integer.h b/include/xrpl/basics/tagged_integer.h index ddcde479f3..2edb314a16 100644 --- a/include/xrpl/basics/tagged_integer.h +++ b/include/xrpl/basics/tagged_integer.h @@ -7,21 +7,23 @@ #include #include +#include #include namespace xrpl { -/** A type-safe wrap around standard integral types - - The tag is used to implement type safety, catching mismatched types at - compile time. Multiple instantiations wrapping the same underlying integral - type are distinct types (distinguished by tag) and will not interoperate. A - tagged_integer supports all the usual assignment, arithmetic, comparison and - shifting operations defined for the underlying type - - The tag is not meant as a unit, which would require restricting the set of - allowed arithmetic operations. -*/ +/** + * A type-safe wrap around standard integral types + * + * The tag is used to implement type safety, catching mismatched types at + * compile time. Multiple instantiations wrapping the same underlying integral + * type are distinct types (distinguished by tag) and will not interoperate. A + * tagged_integer supports all the usual assignment, arithmetic, comparison and + * shifting operations defined for the underlying type + * + * The tag is not meant as a unit, which would require restricting the set of + * allowed arithmetic operations. + */ template class TaggedInteger : boost::totally_ordered< TaggedInteger, @@ -42,10 +44,10 @@ public: TaggedInteger() = default; - template < - class OtherInt, - class = std::enable_if_t && sizeof(OtherInt) <= sizeof(Int)>> - explicit constexpr TaggedInteger(OtherInt value) noexcept : value_(value) + template + explicit constexpr TaggedInteger(OtherInt value) noexcept + requires(std::is_integral_v && sizeof(OtherInt) <= sizeof(Int)) + : value_(value) { static_assert(sizeof(TaggedInteger) == sizeof(Int), "tagged_integer is adding padding"); } diff --git a/include/xrpl/beast/asio/io_latency_probe.h b/include/xrpl/beast/asio/io_latency_probe.h index 5e1b098dcb..d87bdafe45 100644 --- a/include/xrpl/beast/asio/io_latency_probe.h +++ b/include/xrpl/beast/asio/io_latency_probe.h @@ -8,12 +8,15 @@ #include #include +#include #include #include namespace beast { -/** Measures handler latency on an io_context queue. */ +/** + * Measures handler latency on an io_context queue. + */ template class IOLatencyProbe { @@ -41,7 +44,9 @@ public: cancel(lock, true); } - /** Return the io_context associated with the latency probe. */ + /** + * Return the io_context associated with the latency probe. + */ /** @{ */ boost::asio::io_context& getIoContext() @@ -56,9 +61,10 @@ public: } /** @} */ - /** Cancel all pending i/o. - Any handlers which have already been queued will still be called. - */ + /** + * Cancel all pending i/o. + * Any handlers which have already been queued will still be called. + */ /** @{ */ void cancel() @@ -75,10 +81,11 @@ public: } /** @} */ - /** Measure one sample of i/o latency. - Handler will be called with this signature: - void Handler (Duration d); - */ + /** + * Measure one sample of i/o latency. + * Handler will be called with this signature: + * void Handler (Duration d); + */ template void sampleOne(Handler&& handler) @@ -90,10 +97,11 @@ public: ios_, SampleOp(std::forward(handler), Clock::now(), false, this)); } - /** Initiate continuous i/o latency sampling. - Handler will be called with this signature: - void Handler (std::chrono::milliseconds); - */ + /** + * Initiate continuous i/o latency sampling. + * Handler will be called with this signature: + * void Handler (std::chrono::milliseconds); + */ template void sample(Handler&& handler) diff --git a/include/xrpl/beast/clock/abstract_clock.h b/include/xrpl/beast/clock/abstract_clock.h index 15d785d138..6e23700730 100644 --- a/include/xrpl/beast/clock/abstract_clock.h +++ b/include/xrpl/beast/clock/abstract_clock.h @@ -2,34 +2,35 @@ namespace beast { -/** Abstract interface to a clock. - - This makes now() a member function instead of a static member, so - an instance of the class can be dependency injected, facilitating - unit tests where time may be controlled. - - An abstract_clock inherits all the nested types of the Clock - template parameter. - - Example: - - @code - - struct Implementation - { - using clock_type = abstract_clock ; - clock_type& clock_; - explicit Implementation (clock_type& clock) - : clock_(clock) - { - } - }; - - @endcode - - @tparam Clock A type meeting these requirements: - http://en.cppreference.com/w/cpp/concept/Clock -*/ +/** + * Abstract interface to a clock. + * + * This makes now() a member function instead of a static member, so + * an instance of the class can be dependency injected, facilitating + * unit tests where time may be controlled. + * + * An abstract_clock inherits all the nested types of the Clock + * template parameter. + * + * Example: + * + * @code + * + * struct Implementation + * { + * using clock_type = abstract_clock ; + * clock_type& clock_; + * explicit Implementation (clock_type& clock) + * : clock_(clock) + * { + * } + * }; + * + * @endcode + * + * @tparam Clock A type meeting these requirements: + * http://en.cppreference.com/w/cpp/concept/Clock + */ template class AbstractClock { @@ -46,7 +47,9 @@ public: AbstractClock() = default; AbstractClock(AbstractClock const&) = default; - /** Returns the current time. */ + /** + * Returns the current time. + */ [[nodiscard]] virtual time_point now() const = 0; }; @@ -74,11 +77,12 @@ struct AbstractClockWrapper : public AbstractClock //------------------------------------------------------------------------------ -/** Returns a global instance of an abstract clock. - @tparam Facade A type meeting these requirements: - http://en.cppreference.com/w/cpp/concept/Clock - @tparam Clock The actual concrete clock to use. -*/ +/** + * Returns a global instance of an abstract clock. + * @tparam Facade A type meeting these requirements: + * http://en.cppreference.com/w/cpp/concept/Clock + * @tparam Clock The actual concrete clock to use. + */ template AbstractClock& getAbstractClock() diff --git a/include/xrpl/beast/clock/basic_seconds_clock.h b/include/xrpl/beast/clock/basic_seconds_clock.h index 5a267e9458..dce521d0b8 100644 --- a/include/xrpl/beast/clock/basic_seconds_clock.h +++ b/include/xrpl/beast/clock/basic_seconds_clock.h @@ -4,15 +4,16 @@ namespace beast { -/** A clock whose minimum resolution is one second. - - The purpose of this class is to optimize the performance of the now() - member function call. It uses a dedicated thread that wakes up at least - once per second to sample the requested trivial clock. - - @tparam Clock A type meeting these requirements: - http://en.cppreference.com/w/cpp/concept/Clock -*/ +/** + * A clock whose minimum resolution is one second. + * + * The purpose of this class is to optimize the performance of the now() + * member function call. It uses a dedicated thread that wakes up at least + * once per second to sample the requested trivial clock. + * + * @tparam Clock A type meeting these requirements: + * http://en.cppreference.com/w/cpp/concept/Clock + */ class BasicSecondsClock { public: diff --git a/include/xrpl/beast/clock/manual_clock.h b/include/xrpl/beast/clock/manual_clock.h index 8b3e4e63c6..4dc9553644 100644 --- a/include/xrpl/beast/clock/manual_clock.h +++ b/include/xrpl/beast/clock/manual_clock.h @@ -7,15 +7,16 @@ namespace beast { -/** Manual clock implementation. - - This concrete class implements the @ref abstract_clock interface and - allows the time to be advanced manually, mainly for the purpose of - providing a clock in unit tests. - - @tparam Clock A type meeting these requirements: - http://en.cppreference.com/w/cpp/concept/Clock -*/ +/** + * Manual clock implementation. + * + * This concrete class implements the @ref abstract_clock interface and + * allows the time to be advanced manually, mainly for the purpose of + * providing a clock in unit tests. + * + * @tparam Clock A type meeting these requirements: + * http://en.cppreference.com/w/cpp/concept/Clock + */ template class ManualClock : public AbstractClock { @@ -38,7 +39,9 @@ public: return now_; } - /** Set the current time of the manual clock. */ + /** + * Set the current time of the manual clock. + */ void set(time_point const& when) { @@ -48,7 +51,9 @@ public: now_ = when; } - /** Convenience for setting the time in seconds from epoch. */ + /** + * Convenience for setting the time in seconds from epoch. + */ template void set(Integer secondsFromEpoch) @@ -56,7 +61,9 @@ public: set(time_point(duration(std::chrono::seconds(secondsFromEpoch)))); } - /** Advance the clock by a duration. */ + /** + * Advance the clock by a duration. + */ template void advance(std::chrono::duration const& elapsed) @@ -67,7 +74,9 @@ public: now_ += elapsed; } - /** Convenience for advancing the clock by one second. */ + /** + * Convenience for advancing the clock by one second. + */ ManualClock& operator++() { diff --git a/include/xrpl/beast/container/aged_container_utility.h b/include/xrpl/beast/container/aged_container_utility.h index 879672e9cf..da3e4e0500 100644 --- a/include/xrpl/beast/container/aged_container_utility.h +++ b/include/xrpl/beast/container/aged_container_utility.h @@ -3,14 +3,17 @@ #include #include -#include +#include namespace beast { -/** Expire aged container items past the specified age. */ +/** + * Expire aged container items past the specified age. + */ template -std::enable_if_t::value, std::size_t> +std::size_t expire(AgedContainer& c, std::chrono::duration const& age) + requires(IsAgedContainer::value) { std::size_t n(0); auto const expired(c.clock().now() - age); diff --git a/include/xrpl/beast/container/aged_map.h b/include/xrpl/beast/container/aged_map.h index c1f6943451..20daab70a4 100644 --- a/include/xrpl/beast/container/aged_map.h +++ b/include/xrpl/beast/container/aged_map.h @@ -5,6 +5,7 @@ #include #include #include +#include namespace beast { diff --git a/include/xrpl/beast/container/aged_multimap.h b/include/xrpl/beast/container/aged_multimap.h index 65efd1bbf9..f6133ced1c 100644 --- a/include/xrpl/beast/container/aged_multimap.h +++ b/include/xrpl/beast/container/aged_multimap.h @@ -5,6 +5,7 @@ #include #include #include +#include namespace beast { diff --git a/include/xrpl/beast/container/aged_unordered_map.h b/include/xrpl/beast/container/aged_unordered_map.h index a2189e2409..d6ea6e97bd 100644 --- a/include/xrpl/beast/container/aged_unordered_map.h +++ b/include/xrpl/beast/container/aged_unordered_map.h @@ -5,6 +5,7 @@ #include #include #include +#include namespace beast { diff --git a/include/xrpl/beast/container/aged_unordered_multimap.h b/include/xrpl/beast/container/aged_unordered_multimap.h index f1348ed39f..3b72be98b7 100644 --- a/include/xrpl/beast/container/aged_unordered_multimap.h +++ b/include/xrpl/beast/container/aged_unordered_multimap.h @@ -5,6 +5,7 @@ #include #include #include +#include namespace beast { diff --git a/include/xrpl/beast/container/detail/aged_container_iterator.h b/include/xrpl/beast/container/detail/aged_container_iterator.h index 02fb3927dd..d6c061bb86 100644 --- a/include/xrpl/beast/container/detail/aged_container_iterator.h +++ b/include/xrpl/beast/container/detail/aged_container_iterator.h @@ -30,20 +30,19 @@ public: // Disable constructing a const_iterator from a non-const_iterator. // Converting between reverse and non-reverse iterators should be explicit. - template < - bool OtherIsConst, - class OtherIterator, - class = std::enable_if_t< - (!OtherIsConst || IsConst) && - !static_cast(std::is_same_v)>> + template explicit AgedContainerIterator(AgedContainerIterator const& other) + requires( + (!OtherIsConst || IsConst) && + !static_cast(std::is_same_v)) : iter_(other.iter_) { } // Disable constructing a const_iterator from a non-const_iterator. - template > + template AgedContainerIterator(AgedContainerIterator const& other) + requires(!OtherIsConst || IsConst) : iter_(other.iter_) { } @@ -52,7 +51,8 @@ public: template auto operator=(AgedContainerIterator const& other) - -> std::enable_if_t + -> AgedContainerIterator& + requires(!OtherIsConst || IsConst) { iter_ = other.iter_; return *this; diff --git a/include/xrpl/beast/container/detail/aged_ordered_container.h b/include/xrpl/beast/container/detail/aged_ordered_container.h index 4cb2246a22..5b60ef7e6d 100644 --- a/include/xrpl/beast/container/detail/aged_ordered_container.h +++ b/include/xrpl/beast/container/detail/aged_ordered_container.h @@ -11,9 +11,14 @@ #include #include +#include +#include +#include #include #include #include +#include +#include #include #include @@ -34,22 +39,23 @@ struct IsBoostReverseIterator> : std::tru explicit IsBoostReverseIterator() = default; }; -/** Associative container where each element is also indexed by time. - - This container mirrors the interface of the standard library ordered - associative containers, with the addition that each element is associated - with a `when` `time_point` which is obtained from the value of the clock's - `now`. The function `touch` updates the time for an element to the current - time as reported by the clock. - - An extra set of iterator types and member functions are provided in the - `chronological` memberspace that allow traversal in temporal or reverse - temporal order. This container is useful as a building block for caches - whose items expire after a certain amount of time. The chronological - iterators allow for fully customizable expiration strategies. - - @see aged_set, aged_multiset, aged_map, aged_multimap -*/ +/** + * Associative container where each element is also indexed by time. + * + * This container mirrors the interface of the standard library ordered + * associative containers, with the addition that each element is associated + * with a `when` `time_point` which is obtained from the value of the clock's + * `now`. The function `touch` updates the time for an element to the current + * time as reported by the clock. + * + * An extra set of iterator types and member functions are provided in the + * `chronological` memberspace that allow traversal in temporal or reverse + * temporal order. This container is useful as a building block for caches + * whose items expire after a certain amount of time. The chronological + * iterators allow for fully customizable expiration strategies. + * + * @see aged_set, aged_multiset, aged_map, aged_multimap + */ template < bool IsMulti, bool IsMap, @@ -106,10 +112,9 @@ private: { } - template < - class... Args, - class = std::enable_if_t>> + template Element(time_point const& when, Args&&... args) + requires(std::is_constructible_v) : value(std::forward(args)...), when(when) { } @@ -355,6 +360,7 @@ private: deleteElement(Element const* p) { ElementAllocatorTraits::destroy(config_.alloc(), p); + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast) ElementAllocatorTraits::deallocate(config_.alloc(), const_cast(p), 1); } @@ -603,35 +609,25 @@ public: // //-------------------------------------------------------------------------- - template < - class K, - bool MaybeMulti = IsMulti, - bool MaybeMap = IsMap, - class = std::enable_if_t> + template std::conditional_t& - at(K const& k); + at(K const& k) + requires(MaybeMap && !MaybeMulti); - template < - class K, - bool MaybeMulti = IsMulti, - bool MaybeMap = IsMap, - class = std::enable_if_t> + template std::conditional::type const& - at(K const& k) const; + at(K const& k) const + requires(MaybeMap && !MaybeMulti); - template < - bool MaybeMulti = IsMulti, - bool MaybeMap = IsMap, - class = std::enable_if_t> + template std::conditional_t& - operator[](Key const& key); + operator[](Key const& key) + requires(MaybeMap && !MaybeMulti); - template < - bool MaybeMulti = IsMulti, - bool MaybeMap = IsMap, - class = std::enable_if_t> + template std::conditional_t& - operator[](Key&& key); + operator[](Key&& key) + requires(MaybeMap && !MaybeMulti); //-------------------------------------------------------------------------- // @@ -765,35 +761,40 @@ public: // map, set template auto - insert(value_type const& value) -> std::enable_if_t>; + insert(value_type const& value) -> std::pair + requires(!MaybeMulti); // multimap, multiset template auto - insert(value_type const& value) -> std::enable_if_t; + insert(value_type const& value) -> iterator + requires MaybeMulti; // set template auto - insert(value_type&& value) - -> std::enable_if_t>; + insert(value_type&& value) -> std::pair + requires(!MaybeMulti && !MaybeMap); // multiset template auto - insert(value_type&& value) -> std::enable_if_t; + insert(value_type&& value) -> iterator + requires(MaybeMulti && !MaybeMap); //--- // map, set template auto - insert(const_iterator hint, value_type const& value) -> std::enable_if_t; + insert(const_iterator hint, value_type const& value) -> iterator + requires(!MaybeMulti); // multimap, multiset template - std::enable_if_t + iterator insert(const_iterator /*hint*/, value_type const& value) + requires MaybeMulti { // VFALCO TODO Figure out how to utilize 'hint' return insert(value); @@ -802,12 +803,14 @@ public: // map, set template auto - insert(const_iterator hint, value_type&& value) -> std::enable_if_t; + insert(const_iterator hint, value_type&& value) -> iterator + requires(!MaybeMulti); // multimap, multiset template - std::enable_if_t + iterator insert(const_iterator /*hint*/, value_type&& value) + requires MaybeMulti { // VFALCO TODO Figure out how to utilize 'hint' return insert(std::move(value)); @@ -815,20 +818,18 @@ public: // map, multimap template - std::enable_if_t< - MaybeMap && std::is_constructible_v, - std::conditional_t>> + std::conditional_t> insert(P&& value) + requires(MaybeMap && std::is_constructible_v) { return emplace(std::forward

(value)); } // map, multimap template - std::enable_if_t< - MaybeMap && std::is_constructible_v, - std::conditional_t>> + std::conditional_t> insert(const_iterator hint, P&& value) + requires(MaybeMap && std::is_constructible_v) { return emplaceHint(hint, std::forward

(value)); } @@ -850,46 +851,45 @@ public: // map, set template auto - emplace(Args&&... args) -> std::enable_if_t>; + emplace(Args&&... args) -> std::pair + requires(!MaybeMulti); // multiset, multimap template auto - emplace(Args&&... args) -> std::enable_if_t; + emplace(Args&&... args) -> iterator + requires MaybeMulti; // map, set template auto - emplaceHint(const_iterator hint, Args&&... args) - -> std::enable_if_t>; + emplaceHint(const_iterator hint, Args&&... args) -> std::pair + requires(!MaybeMulti); // multiset, multimap template - std::enable_if_t + iterator emplaceHint(const_iterator /*hint*/, Args&&... args) + requires MaybeMulti { // VFALCO TODO Figure out how to utilize 'hint' return emplace(std::forward(args)...); } - // enable_if prevents erase (reverse_iterator pos) from compiling - template < - bool IsConst, - class Iterator, - class = std::enable_if_t::value>> + // The constraint prevents erase (reverse_iterator pos) from compiling + template beast::detail::AgedContainerIterator - erase(beast::detail::AgedContainerIterator pos); + erase(beast::detail::AgedContainerIterator pos) + requires(!IsBoostReverseIterator::value); - // enable_if prevents erase (reverse_iterator first, reverse_iterator last) + // The constraint prevents erase (reverse_iterator first, reverse_iterator last) // from compiling - template < - bool IsConst, - class Iterator, - class = std::enable_if_t::value>> + template beast::detail::AgedContainerIterator erase( beast::detail::AgedContainerIterator first, - beast::detail::AgedContainerIterator last); + beast::detail::AgedContainerIterator last) + requires(!IsBoostReverseIterator::value); template auto @@ -900,13 +900,11 @@ public: //-------------------------------------------------------------------------- - // enable_if prevents touch (reverse_iterator pos) from compiling - template < - bool IsConst, - class Iterator, - class = std::enable_if_t::value>> + // The constraint prevents touch (reverse_iterator pos) from compiling + template void touch(beast::detail::AgedContainerIterator pos) + requires(!IsBoostReverseIterator::value) { touch(pos, clock().now()); } @@ -1137,25 +1135,25 @@ public: } private: - // enable_if prevents erase (reverse_iterator pos, now) from compiling - template < - bool IsConst, - class Iterator, - class = std::enable_if_t::value>> + // The constraint prevents erase (reverse_iterator pos, now) from compiling + template void touch( beast::detail::AgedContainerIterator pos, - clock_type::time_point const& now); + clock_type::time_point const& now) + requires(!IsBoostReverseIterator::value); template < bool MaybePropagate = std::allocator_traits::propagate_on_container_swap::value> - std::enable_if_t - swapData(AgedOrderedContainer& other) noexcept; + void + swapData(AgedOrderedContainer& other) noexcept + requires MaybePropagate; template < bool MaybePropagate = std::allocator_traits::propagate_on_container_swap::value> - std::enable_if_t - swapData(AgedOrderedContainer& other) noexcept; + void + swapData(AgedOrderedContainer& other) noexcept + requires(!MaybePropagate); private: ConfigT config_; @@ -1247,12 +1245,7 @@ AgedOrderedContainer::AgedOrd template AgedOrderedContainer::AgedOrderedContainer( AgedOrderedContainer const& other) - : config_(other.config_) -#if BOOST_VERSION >= 108000 - , cont_(other.cont_.get_comp()) -#else - , cont_(other.cont_.comp()) -#endif + : config_(other.config_), cont_(other.cont_.get_comp()) { insert(other.cbegin(), other.cend()); } @@ -1261,12 +1254,7 @@ template ::AgedOrderedContainer( AgedOrderedContainer const& other, Allocator const& alloc) - : config_(other.config_, alloc) -#if BOOST_VERSION >= 108000 - , cont_(other.cont_.get_comp()) -#else - , cont_(other.cont_.comp()) -#endif + : config_(other.config_, alloc), cont_(other.cont_.get_comp()) { insert(other.cbegin(), other.cend()); } @@ -1283,13 +1271,7 @@ template ::AgedOrderedContainer( AgedOrderedContainer&& other, // NOLINT(cppcoreguidelines-rvalue-reference-param-not-moved) Allocator const& alloc) - : config_(std::move(other.config_), alloc) -#if BOOST_VERSION >= 108000 - , cont_(std::move(other.cont_.get_comp())) -#else - , cont_(std::move(other.cont_.comp())) -#endif - + : config_(std::move(other.config_), alloc), cont_(std::move(other.cont_.get_comp())) { insert(other.cbegin(), other.cend()); other.clear(); @@ -1380,9 +1362,10 @@ AgedOrderedContainer::operato //------------------------------------------------------------------------------ template -template +template std::conditional_t& AgedOrderedContainer::at(K const& k) + requires(MaybeMap && !MaybeMulti) { auto const iter(cont_.find(k, std::cref(config_.keyCompare()))); if (iter == cont_.end()) @@ -1391,9 +1374,10 @@ AgedOrderedContainer::at(K co } template -template +template std::conditional::type const& AgedOrderedContainer::at(K const& k) const + requires(MaybeMap && !MaybeMulti) { auto const iter(cont_.find(k, std::cref(config_.keyCompare()))); if (iter == cont_.end()) @@ -1402,9 +1386,10 @@ AgedOrderedContainer::at(K co } template -template +template std::conditional_t& AgedOrderedContainer::operator[](Key const& key) + requires(MaybeMap && !MaybeMulti) { typename cont_type::insert_commit_data d; auto const result(cont_.insert_check(key, std::cref(config_.keyCompare()), d)); @@ -1420,9 +1405,10 @@ AgedOrderedContainer::operato } template -template +template std::conditional_t& AgedOrderedContainer::operator[](Key&& key) + requires(MaybeMap && !MaybeMulti) { typename cont_type::insert_commit_data d; auto const result(cont_.insert_check(key, std::cref(config_.keyCompare()), d)); @@ -1456,7 +1442,8 @@ template auto AgedOrderedContainer::insert( - value_type const& value) -> std::enable_if_t> + value_type const& value) -> std::pair + requires(!MaybeMulti) { typename cont_type::insert_commit_data d; auto const result(cont_.insert_check(extract(value), std::cref(config_.keyCompare()), d)); @@ -1475,7 +1462,8 @@ template auto AgedOrderedContainer::insert( - value_type const& value) -> std::enable_if_t + value_type const& value) -> iterator + requires MaybeMulti { auto const before(cont_.upper_bound(extract(value), std::cref(config_.keyCompare()))); Element* const p(newElement(value)); @@ -1489,7 +1477,8 @@ template auto AgedOrderedContainer::insert(value_type&& value) - -> std::enable_if_t> + -> std::pair + requires(!MaybeMulti && !MaybeMap) { typename cont_type::insert_commit_data d; auto const result(cont_.insert_check(extract(value), std::cref(config_.keyCompare()), d)); @@ -1508,7 +1497,8 @@ template auto AgedOrderedContainer::insert(value_type&& value) - -> std::enable_if_t + -> iterator + requires(MaybeMulti && !MaybeMap) { auto const before(cont_.upper_bound(extract(value), std::cref(config_.keyCompare()))); Element* const p(newElement(std::move(value))); @@ -1525,7 +1515,8 @@ template auto AgedOrderedContainer::insert( const_iterator hint, - value_type const& value) -> std::enable_if_t + value_type const& value) -> iterator + requires(!MaybeMulti) { typename cont_type::insert_commit_data d; auto const result( @@ -1546,7 +1537,8 @@ template auto AgedOrderedContainer::insert( const_iterator hint, - value_type&& value) -> std::enable_if_t + value_type&& value) -> iterator + requires(!MaybeMulti) { typename cont_type::insert_commit_data d; auto const result( @@ -1566,7 +1558,8 @@ template auto AgedOrderedContainer::emplace(Args&&... args) - -> std::enable_if_t> + -> std::pair + requires(!MaybeMulti) { // VFALCO NOTE Its unfortunate that we need to // construct element here @@ -1588,7 +1581,8 @@ template auto AgedOrderedContainer::emplace(Args&&... args) - -> std::enable_if_t + -> iterator + requires MaybeMulti { Element* const p(newElement(std::forward(args)...)); auto const before(cont_.upper_bound(extract(p->value), std::cref(config_.keyCompare()))); @@ -1603,7 +1597,8 @@ template auto AgedOrderedContainer::emplaceHint( const_iterator hint, - Args&&... args) -> std::enable_if_t> + Args&&... args) -> std::pair + requires(!MaybeMulti) { // VFALCO NOTE Its unfortunate that we need to // construct element here @@ -1622,21 +1617,23 @@ AgedOrderedContainer::emplace } template -template +template beast::detail::AgedContainerIterator AgedOrderedContainer::erase( beast::detail::AgedContainerIterator pos) + requires(!IsBoostReverseIterator::value) { unlinkAndDeleteElement(&*((pos++).iterator())); return beast::detail::AgedContainerIterator(pos.iterator()); } template -template +template beast::detail::AgedContainerIterator AgedOrderedContainer::erase( beast::detail::AgedContainerIterator first, beast::detail::AgedContainerIterator last) + requires(!IsBoostReverseIterator::value) { for (; first != last;) unlinkAndDeleteElement(&*((first++).iterator())); @@ -1739,11 +1736,12 @@ AgedOrderedContainer::operato //------------------------------------------------------------------------------ template -template +template void AgedOrderedContainer::touch( beast::detail::AgedContainerIterator pos, clock_type::time_point const& now) + requires(!IsBoostReverseIterator::value) { auto& e(*pos.iterator()); e.when = now; @@ -1753,9 +1751,10 @@ AgedOrderedContainer::touch( template template -std::enable_if_t +void AgedOrderedContainer::swapData( AgedOrderedContainer& other) noexcept + requires MaybePropagate { std::swap(config_.keyCompare(), other.config_.keyCompare()); std::swap(config_.alloc(), other.config_.alloc()); @@ -1764,9 +1763,10 @@ AgedOrderedContainer::swapDat template template -std::enable_if_t +void AgedOrderedContainer::swapData( AgedOrderedContainer& other) noexcept + requires(!MaybePropagate) { std::swap(config_.keyCompare(), other.config_.keyCompare()); std::swap(config_.clock, other.config_.clock); @@ -1796,7 +1796,9 @@ swap( lhs.swap(rhs); } -/** Expire aged container items past the specified age. */ +/** + * Expire aged container items past the specified age. + */ template < bool IsMulti, bool IsMap, diff --git a/include/xrpl/beast/container/detail/aged_unordered_container.h b/include/xrpl/beast/container/detail/aged_unordered_container.h index 3bad12d9e5..db10e8cc23 100644 --- a/include/xrpl/beast/container/detail/aged_unordered_container.h +++ b/include/xrpl/beast/container/detail/aged_unordered_container.h @@ -10,13 +10,19 @@ #include #include +#include #include +#include +#include #include #include #include #include +#include +#include #include #include +#include /* @@ -37,23 +43,24 @@ TODO namespace beast { namespace detail { -/** Associative container where each element is also indexed by time. - - This container mirrors the interface of the standard library unordered - associative containers, with the addition that each element is associated - with a `when` `time_point` which is obtained from the value of the clock's - `now`. The function `touch` updates the time for an element to the current - time as reported by the clock. - - An extra set of iterator types and member functions are provided in the - `chronological` memberspace that allow traversal in temporal or reverse - temporal order. This container is useful as a building block for caches - whose items expire after a certain amount of time. The chronological - iterators allow for fully customizable expiration strategies. - - @see aged_unordered_set, aged_unordered_multiset - @see aged_unordered_map, aged_unordered_multimap -*/ +/** + * Associative container where each element is also indexed by time. + * + * This container mirrors the interface of the standard library unordered + * associative containers, with the addition that each element is associated + * with a `when` `time_point` which is obtained from the value of the clock's + * `now`. The function `touch` updates the time for an element to the current + * time as reported by the clock. + * + * An extra set of iterator types and member functions are provided in the + * `chronological` memberspace that allow traversal in temporal or reverse + * temporal order. This container is useful as a building block for caches + * whose items expire after a certain amount of time. The chronological + * iterators allow for fully customizable expiration strategies. + * + * @see aged_unordered_set, aged_unordered_multiset + * @see aged_unordered_map, aged_unordered_multimap + */ template < bool IsMulti, bool IsMap, @@ -111,10 +118,9 @@ private: { } - template < - class... Args, - class = std::enable_if_t>> + template Element(time_point const& when, Args&&... args) + requires(std::is_constructible_v) : value(std::forward(args)...), when(when) { } @@ -523,6 +529,7 @@ private: deleteElement(Element const* p) { ElementAllocatorTraits::destroy(config_.alloc(), p); + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast) ElementAllocatorTraits::deallocate(config_.alloc(), const_cast(p), 1); } @@ -835,35 +842,25 @@ public: // //-------------------------------------------------------------------------- - template < - class K, - bool MaybeMulti = IsMulti, - bool MaybeMap = IsMap, - class = std::enable_if_t> + template std::conditional_t& - at(K const& k); + at(K const& k) + requires(MaybeMap && !MaybeMulti); - template < - class K, - bool MaybeMulti = IsMulti, - bool MaybeMap = IsMap, - class = std::enable_if_t> + template std::conditional::type const& - at(K const& k) const; + at(K const& k) const + requires(MaybeMap && !MaybeMulti); - template < - bool MaybeMulti = IsMulti, - bool MaybeMap = IsMap, - class = std::enable_if_t> + template std::conditional_t& - operator[](Key const& key); + operator[](Key const& key) + requires(MaybeMap && !MaybeMulti); - template < - bool MaybeMulti = IsMulti, - bool MaybeMap = IsMap, - class = std::enable_if_t> + template std::conditional_t& - operator[](Key&& key); + operator[](Key&& key) + requires(MaybeMap && !MaybeMulti); //-------------------------------------------------------------------------- // @@ -961,28 +958,32 @@ public: // map, set template auto - insert(value_type const& value) -> std::enable_if_t>; + insert(value_type const& value) -> std::pair + requires(!MaybeMulti); // multimap, multiset template auto - insert(value_type const& value) -> std::enable_if_t; + insert(value_type const& value) -> iterator + requires MaybeMulti; // map, set template auto - insert(value_type&& value) - -> std::enable_if_t>; + insert(value_type&& value) -> std::pair + requires(!MaybeMulti && !MaybeMap); // multimap, multiset template auto - insert(value_type&& value) -> std::enable_if_t; + insert(value_type&& value) -> iterator + requires(MaybeMulti && !MaybeMap); // map, set template - std::enable_if_t + iterator insert(const_iterator /*hint*/, value_type const& value) + requires(!MaybeMulti) { // Hint is ignored but we provide the interface so // callers may use ordered and unordered interchangeably. @@ -991,8 +992,9 @@ public: // multimap, multiset template - std::enable_if_t + iterator insert(const_iterator /*hint*/, value_type const& value) + requires MaybeMulti { // VFALCO TODO The hint could be used to let // the client order equal ranges @@ -1001,8 +1003,9 @@ public: // map, set template - std::enable_if_t + iterator insert(const_iterator /*hint*/, value_type&& value) + requires(!MaybeMulti) { // Hint is ignored but we provide the interface so // callers may use ordered and unordered interchangeably. @@ -1011,8 +1014,9 @@ public: // multimap, multiset template - std::enable_if_t + iterator insert(const_iterator /*hint*/, value_type&& value) + requires MaybeMulti { // VFALCO TODO The hint could be used to let // the client order equal ranges @@ -1021,20 +1025,18 @@ public: // map, multimap template - std::enable_if_t< - MaybeMap && std::is_constructible_v, - std::conditional_t>> + std::conditional_t> insert(P&& value) + requires(MaybeMap && std::is_constructible_v) { return emplace(std::forward

(value)); } // map, multimap template - std::enable_if_t< - MaybeMap && std::is_constructible_v, - std::conditional_t>> + std::conditional_t> insert(const_iterator hint, P&& value) + requires(MaybeMap && std::is_constructible_v) { return emplaceHint(hint, std::forward

(value)); } @@ -1055,23 +1057,26 @@ public: // set, map template auto - emplace(Args&&... args) -> std::enable_if_t>; + emplace(Args&&... args) -> std::pair + requires(!MaybeMulti); // multiset, multimap template auto - emplace(Args&&... args) -> std::enable_if_t; + emplace(Args&&... args) -> iterator + requires MaybeMulti; // set, map template auto - emplaceHint(const_iterator /*hint*/, Args&&... args) - -> std::enable_if_t>; + emplaceHint(const_iterator /*hint*/, Args&&... args) -> std::pair + requires(!MaybeMulti); // multiset, multimap template - std::enable_if_t + iterator emplaceHint(const_iterator /*hint*/, Args&&... args) + requires MaybeMulti { // VFALCO TODO The hint could be used for multi, to let // the client order equal ranges @@ -1302,7 +1307,7 @@ public: class OtherHash, class OtherAllocator, bool MaybeMulti = IsMulti> - std::enable_if_t + bool operator==(AgedUnorderedContainer< false, OtherIsMap, @@ -1311,7 +1316,8 @@ public: OtherDuration, OtherHash, KeyEqual, - OtherAllocator> const& other) const; + OtherAllocator> const& other) const + requires(!MaybeMulti); template < bool OtherIsMap, @@ -1321,7 +1327,7 @@ public: class OtherHash, class OtherAllocator, bool MaybeMulti = IsMulti> - std::enable_if_t + bool operator==(AgedUnorderedContainer< true, OtherIsMap, @@ -1330,7 +1336,8 @@ public: OtherDuration, OtherHash, KeyEqual, - OtherAllocator> const& other) const; + OtherAllocator> const& other) const + requires MaybeMulti; template < bool OtherIsMulti, @@ -1375,13 +1382,14 @@ private: // map, set template auto - insertUnchecked(value_type const& value) - -> std::enable_if_t>; + insertUnchecked(value_type const& value) -> std::pair + requires(!MaybeMulti); // multimap, multiset template auto - insertUnchecked(value_type const& value) -> std::enable_if_t; + insertUnchecked(value_type const& value) -> iterator + requires MaybeMulti; template void @@ -1422,8 +1430,9 @@ private: template < bool MaybePropagate = std::allocator_traits::propagate_on_container_swap::value> - std::enable_if_t + void swapData(AgedUnorderedContainer& other) noexcept + requires MaybePropagate { std::swap(config_.hashFunction(), other.config_.hashFunction()); std::swap(config_.keyEq(), other.config_.keyEq()); @@ -1433,8 +1442,9 @@ private: template < bool MaybePropagate = std::allocator_traits::propagate_on_container_swap::value> - std::enable_if_t + void swapData(AgedUnorderedContainer& other) noexcept + requires(!MaybePropagate) { std::swap(config_.hashFunction(), other.config_.hashFunction()); std::swap(config_.keyEq(), other.config_.keyEq()); @@ -2088,9 +2098,10 @@ template < class Hash, class KeyEqual, class Allocator> -template +template std::conditional_t& AgedUnorderedContainer::at(K const& k) + requires(MaybeMap && !MaybeMulti) { auto const iter( cont_.find(k, std::cref(config_.hashFunction()), std::cref(config_.keyValueEqual()))); @@ -2108,10 +2119,11 @@ template < class Hash, class KeyEqual, class Allocator> -template +template std::conditional::type const& AgedUnorderedContainer::at( K const& k) const + requires(MaybeMap && !MaybeMulti) { auto const iter( cont_.find(k, std::cref(config_.hashFunction()), std::cref(config_.keyValueEqual()))); @@ -2129,10 +2141,11 @@ template < class Hash, class KeyEqual, class Allocator> -template +template std::conditional_t& AgedUnorderedContainer::operator[]( Key const& key) + requires(MaybeMap && !MaybeMulti) { maybeRehash(1); typename cont_type::insert_commit_data d; @@ -2158,10 +2171,11 @@ template < class Hash, class KeyEqual, class Allocator> -template +template std::conditional_t& AgedUnorderedContainer::operator[]( Key&& key) + requires(MaybeMap && !MaybeMulti) { maybeRehash(1); typename cont_type::insert_commit_data d; @@ -2214,7 +2228,8 @@ template < template auto AgedUnorderedContainer::insert( - value_type const& value) -> std::enable_if_t> + value_type const& value) -> std::pair + requires(!MaybeMulti) { maybeRehash(1); typename cont_type::insert_commit_data d; @@ -2243,7 +2258,8 @@ template < template auto AgedUnorderedContainer::insert( - value_type const& value) -> std::enable_if_t + value_type const& value) -> iterator + requires MaybeMulti { maybeRehash(1); Element* const p(newElement(value)); @@ -2265,7 +2281,8 @@ template < template auto AgedUnorderedContainer::insert( - value_type&& value) -> std::enable_if_t> + value_type&& value) -> std::pair + requires(!MaybeMulti && !MaybeMap) { maybeRehash(1); typename cont_type::insert_commit_data d; @@ -2294,7 +2311,8 @@ template < template auto AgedUnorderedContainer::insert( - value_type&& value) -> std::enable_if_t + value_type&& value) -> iterator + requires(MaybeMulti && !MaybeMap) { maybeRehash(1); Element* const p(newElement(std::move(value))); @@ -2303,7 +2321,6 @@ AgedUnorderedContainer return iterator(iter); } -#if 1 // Use insert() instead of insert_check() insert_commit() // set, map template < bool IsMulti, @@ -2317,7 +2334,8 @@ template < template auto AgedUnorderedContainer::emplace( - Args&&... args) -> std::enable_if_t> + Args&&... args) -> std::pair + requires(!MaybeMulti) { maybeRehash(1); // VFALCO NOTE Its unfortunate that we need to @@ -2332,42 +2350,6 @@ AgedUnorderedContainer deleteElement(p); return std::make_pair(iterator(result.first), false); } -#else // As original, use insert_check() / insert_commit () pair. -// set, map -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> -template -auto -AgedUnorderedContainer::emplace( - Args&&... args) -> typename std::enable_if>::type -{ - maybe_rehash(1); - // VFALCO NOTE Its unfortunate that we need to - // construct element here - element* const p(new_element(std::forward(args)...)); - typename cont_type::insert_commit_data d; - auto const result(m_cont.insert_check( - extract(p->value), - std::cref(m_config.hashFunction()), - std::cref(m_config.keyValueEqual()), - d)); - if (result.second) - { - auto const iter(m_cont.insert_commit(*p, d)); - chronological.list.push_back(*p); - return std::make_pair(iterator(iter), true); - } - delete_element(p); - return std::make_pair(iterator(result.first), false); -} -#endif // 0 // multiset, multimap template < @@ -2382,7 +2364,8 @@ template < template auto AgedUnorderedContainer::emplace( - Args&&... args) -> std::enable_if_t + Args&&... args) -> iterator + requires MaybeMulti { maybeRehash(1); Element* const p(newElement(std::forward(args)...)); @@ -2405,7 +2388,8 @@ template auto AgedUnorderedContainer::emplaceHint( const_iterator /*hint*/, - Args&&... args) -> std::enable_if_t> + Args&&... args) -> std::pair + requires(!MaybeMulti) { maybeRehash(1); // VFALCO NOTE Its unfortunate that we need to @@ -2556,7 +2540,7 @@ template < class OtherHash, class OtherAllocator, bool MaybeMulti> -std::enable_if_t +bool AgedUnorderedContainer::operator==( AgedUnorderedContainer< false, @@ -2567,6 +2551,7 @@ AgedUnorderedContainer OtherHash, KeyEqual, OtherAllocator> const& other) const + requires(!MaybeMulti) { if (size() != other.size()) return false; @@ -2596,7 +2581,7 @@ template < class OtherHash, class OtherAllocator, bool MaybeMulti> -std::enable_if_t +bool AgedUnorderedContainer::operator==( AgedUnorderedContainer< true, @@ -2607,6 +2592,7 @@ AgedUnorderedContainer OtherHash, KeyEqual, OtherAllocator> const& other) const + requires MaybeMulti { if (size() != other.size()) return false; @@ -2643,7 +2629,8 @@ template < template auto AgedUnorderedContainer::insertUnchecked( - value_type const& value) -> std::enable_if_t> + value_type const& value) -> std::pair + requires(!MaybeMulti) { typename cont_type::insert_commit_data d; auto const result(cont_.insert_check( @@ -2671,7 +2658,8 @@ template < template auto AgedUnorderedContainer::insertUnchecked( - value_type const& value) -> std::enable_if_t + value_type const& value) -> iterator + requires MaybeMulti { Element* const p(newElement(value)); chronological.list_.push_back(*p); @@ -2722,7 +2710,9 @@ swap( lhs.swap(rhs); } -/** Expire aged container items past the specified age. */ +/** + * Expire aged container items past the specified age. + */ template < bool IsMulti, bool IsMap, diff --git a/include/xrpl/beast/core/CurrentThreadName.h b/include/xrpl/beast/core/CurrentThreadName.h index 6175d99b16..d1f14a6f80 100644 --- a/include/xrpl/beast/core/CurrentThreadName.h +++ b/include/xrpl/beast/core/CurrentThreadName.h @@ -6,14 +6,16 @@ #include +#include #include #include namespace beast { -/** Changes the name of the caller thread. - Different OSes may place different length or content limits on this name. -*/ +/** + * Changes the name of the caller thread. + * Different OSes may place different length or content limits on this name. + */ void setCurrentThreadName(std::string_view newThreadName); @@ -23,13 +25,14 @@ setCurrentThreadName(std::string_view newThreadName); // Maximum number of characters is therefore 15. constexpr std::size_t kMaxThreadNameLength = 15; -/** Sets the name of the caller thread with compile-time size checking. - @tparam N The size of the string literal including null terminator - @param newThreadName A string literal to set as the thread name - - This template overload enforces that thread names are at most 16 characters - (including null terminator) at compile time, matching Linux's limit. -*/ +/** + * Sets the name of the caller thread with compile-time size checking. + * @tparam N The size of the string literal including null terminator + * @param newThreadName A string literal to set as the thread name + * + * This template overload enforces that thread names are at most 16 characters + * (including null terminator) at compile time, matching Linux's limit. + */ template void setCurrentThreadName(char const (&newThreadName)[N]) @@ -40,14 +43,15 @@ setCurrentThreadName(char const (&newThreadName)[N]) } #endif -/** Returns the name of the caller thread. - - The name returned is the name as set by a call to setCurrentThreadName(). - If the thread name is set by an external force, then that name change - will not be reported. - - If no name has ever been set, then the empty string is returned. -*/ +/** + * Returns the name of the caller thread. + * + * The name returned is the name as set by a call to setCurrentThreadName(). + * If the thread name is set by an external force, then that name change + * will not be reported. + * + * If no name has ever been set, then the empty string is returned. + */ std::string getCurrentThreadName(); diff --git a/include/xrpl/beast/core/LexicalCast.h b/include/xrpl/beast/core/LexicalCast.h index 18e63c9c10..7cf21892bd 100644 --- a/include/xrpl/beast/core/LexicalCast.h +++ b/include/xrpl/beast/core/LexicalCast.h @@ -5,11 +5,12 @@ #include #include -#include +#include #include -#include #include #include +#include +#include #include #include @@ -28,16 +29,18 @@ struct LexicalCast explicit LexicalCast() = default; template - std::enable_if_t, bool> + bool operator()(std::string& out, Arithmetic in) + requires(std::is_arithmetic_v) { out = std::to_string(in); return true; } template - std::enable_if_t, bool> + bool operator()(std::string& out, Enumeration in) + requires(std::is_enum_v) { out = std::to_string(static_cast>(in)); return true; @@ -55,8 +58,9 @@ struct LexicalCast "beast::LexicalCast can only be used with integral types"); template - std::enable_if_t && !std::is_same_v, bool> + bool operator()(Integral& out, std::string_view in) const + requires(std::is_integral_v && !std::is_same_v) { auto first = in.data(); auto last = in.data() + in.size(); @@ -159,17 +163,19 @@ struct LexicalCast //------------------------------------------------------------------------------ -/** Thrown when a conversion is not possible with LexicalCast. - Only used in the throw variants of lexicalCast. -*/ +/** + * Thrown when a conversion is not possible with LexicalCast. + * Only used in the throw variants of lexicalCast. + */ struct BadLexicalCast : public std::bad_cast { explicit BadLexicalCast() = default; }; -/** Intelligently convert from one type to another. - @return `false` if there was a parsing or range error -*/ +/** + * Intelligently convert from one type to another. + * @return `false` if there was a parsing or range error + */ template bool lexicalCastChecked(Out& out, In in) @@ -177,12 +183,13 @@ lexicalCastChecked(Out& out, In in) return detail::LexicalCast()(out, in); } -/** Convert from one type to another, throw on error - - An exception of type BadLexicalCast is thrown if the conversion fails. - - @return The new type. -*/ +/** + * Convert from one type to another, throw on error + * + * An exception of type BadLexicalCast is thrown if the conversion fails. + * + * @return The new type. + */ template Out lexicalCastThrow(In in) @@ -193,11 +200,12 @@ lexicalCastThrow(In in) throw BadLexicalCast(); } -/** Convert from one type to another. - - @param defaultValue The value returned if parsing fails - @return The new type. -*/ +/** + * Convert from one type to another. + * + * @param defaultValue The value returned if parsing fails + * @return The new type. + */ template Out lexicalCast(In in, Out defaultValue = Out()) diff --git a/include/xrpl/beast/core/List.h b/include/xrpl/beast/core/List.h index 1c3827ae1c..b9b6829d31 100644 --- a/include/xrpl/beast/core/List.h +++ b/include/xrpl/beast/core/List.h @@ -1,6 +1,8 @@ #pragma once +#include #include +#include namespace beast { @@ -9,7 +11,9 @@ class List; namespace detail { -/** Copy `const` attribute from T to U if present. */ +/** + * Copy `const` attribute from T to U if present. + */ /** @{ */ template struct CopyConst @@ -151,110 +155,111 @@ private: } // namespace detail -/** Intrusive doubly linked list. - - This intrusive List is a container similar in operation to std::list in the - Standard Template Library (STL). Like all @ref intrusive containers, List - requires you to first derive your class from List<>::Node: - - @code - - struct Object : List ::Node - { - explicit Object (int value) : value_ (value) - { - } - - int value_; - }; - - @endcode - - Now we define the list, and add a couple of items. - - @code - - List list; - - list.push_back (* (new Object (1))); - list.push_back (* (new Object (2))); - - @endcode - - For compatibility with the standard containers, push_back() expects a - reference to the object. Unlike the standard container, however, push_back() - places the actual object in the list and not a copy-constructed duplicate. - - Iterating over the list follows the same idiom as the STL: - - @code - - for (List ::iterator iter = list.begin(); iter != list.end; ++iter) - std::cout << iter->value_; - - @endcode - - You can even use BOOST_FOREACH, or range based for loops: - - @code - - BOOST_FOREACH (Object& object, list) // boost only - std::cout << object.value_; - - for (Object& object : list) // C++11 only - std::cout << object.value_; - - @endcode - - Because List is mostly STL compliant, it can be passed into STL algorithms: - e.g. `std::for_each()` or `std::find_first_of()`. - - In general, objects placed into a List should be dynamically allocated - although this cannot be enforced at compile time. Since the caller provides - the storage for the object, the caller is also responsible for deleting the - object. An object still exists after being removed from a List, until the - caller deletes it. This means an element can be moved from one List to - another with practically no overhead. - - Unlike the standard containers, an object may only exist in one list at a - time, unless special preparations are made. The Tag template parameter is - used to distinguish between different list types for the same object, - allowing the object to exist in more than one list simultaneously. - - For example, consider an actor system where a global list of actors is - maintained, so that they can each be periodically receive processing - time. We wish to also maintain a list of the subset of actors that require - a domain-dependent update. To achieve this, we declare two tags, the - associated list types, and the list element thusly: - - @code - - struct Actor; // Forward declaration required - - struct ProcessTag { }; - struct UpdateTag { }; - - using ProcessList = List ; - using UpdateList = List ; - - // Derive from both node types so we can be in each list at once. - // - struct Actor : ProcessList::Node, UpdateList::Node - { - bool process (); // returns true if we need an update - void update (); - }; - - @endcode - - @tparam T The base type of element which the list will store - pointers to. - - @tparam Tag An optional unique type name used to distinguish lists and - nodes, when the object can exist in multiple lists simultaneously. - - @ingroup beast_core intrusive -*/ +/** + * Intrusive doubly linked list. + * + * This intrusive List is a container similar in operation to std::list in the + * Standard Template Library (STL). Like all @ref intrusive containers, List + * requires you to first derive your class from List<>::Node: + * + * @code + * + * struct Object : List ::Node + * { + * explicit Object (int value) : value_ (value) + * { + * } + * + * int value_; + * }; + * + * @endcode + * + * Now we define the list, and add a couple of items. + * + * @code + * + * List list; + * + * list.push_back (* (new Object (1))); + * list.push_back (* (new Object (2))); + * + * @endcode + * + * For compatibility with the standard containers, push_back() expects a + * reference to the object. Unlike the standard container, however, push_back() + * places the actual object in the list and not a copy-constructed duplicate. + * + * Iterating over the list follows the same idiom as the STL: + * + * @code + * + * for (List ::iterator iter = list.begin(); iter != list.end; ++iter) + * std::cout << iter->value_; + * + * @endcode + * + * You can even use BOOST_FOREACH, or range based for loops: + * + * @code + * + * BOOST_FOREACH (Object& object, list) // boost only + * std::cout << object.value_; + * + * for (Object& object : list) // C++11 only + * std::cout << object.value_; + * + * @endcode + * + * Because List is mostly STL compliant, it can be passed into STL algorithms: + * e.g. `std::for_each()` or `std::find_first_of()`. + * + * In general, objects placed into a List should be dynamically allocated + * although this cannot be enforced at compile time. Since the caller provides + * the storage for the object, the caller is also responsible for deleting the + * object. An object still exists after being removed from a List, until the + * caller deletes it. This means an element can be moved from one List to + * another with practically no overhead. + * + * Unlike the standard containers, an object may only exist in one list at a + * time, unless special preparations are made. The Tag template parameter is + * used to distinguish between different list types for the same object, + * allowing the object to exist in more than one list simultaneously. + * + * For example, consider an actor system where a global list of actors is + * maintained, so that they can each be periodically receive processing + * time. We wish to also maintain a list of the subset of actors that require + * a domain-dependent update. To achieve this, we declare two tags, the + * associated list types, and the list element thusly: + * + * @code + * + * struct Actor; // Forward declaration required + * + * struct ProcessTag { }; + * struct UpdateTag { }; + * + * using ProcessList = List ; + * using UpdateList = List ; + * + * // Derive from both node types so we can be in each list at once. + * // + * struct Actor : ProcessList::Node, UpdateList::Node + * { + * bool process (); // returns true if we need an update + * void update (); + * }; + * + * @endcode + * + * @tparam T The base type of element which the list will store + * pointers to. + * + * @tparam Tag An optional unique type name used to distinguish lists and + * nodes, when the object can exist in multiple lists simultaneously. + * + * @ingroup beast_core intrusive + */ template class List { @@ -272,7 +277,9 @@ public: using iterator = detail::ListIterator; using const_iterator = detail::ListIterator; - /** Create an empty list. */ + /** + * Create an empty list. + */ List() { head_.prev_ = nullptr; // identifies the head @@ -284,119 +291,133 @@ public: List& operator=(List const&) = delete; - /** Determine if the list is empty. - @return `true` if the list is empty. - */ + /** + * Determine if the list is empty. + * @return `true` if the list is empty. + */ [[nodiscard]] bool empty() const noexcept { return size() == 0; } - /** Returns the number of elements in the list. */ + /** + * Returns the number of elements in the list. + */ [[nodiscard]] size_type size() const noexcept { return size_; } - /** Obtain a reference to the first element. - @invariant The list may not be empty. - @return A reference to the first element. - */ + /** + * Obtain a reference to the first element. + * @invariant The list may not be empty. + * @return A reference to the first element. + */ reference front() noexcept { return element_from(head_.next_); } - /** Obtain a const reference to the first element. - @invariant The list may not be empty. - @return A const reference to the first element. - */ + /** + * Obtain a const reference to the first element. + * @invariant The list may not be empty. + * @return A const reference to the first element. + */ [[nodiscard]] const_reference front() const noexcept { return element_from(head_.next_); } - /** Obtain a reference to the last element. - @invariant The list may not be empty. - @return A reference to the last element. - */ + /** + * Obtain a reference to the last element. + * @invariant The list may not be empty. + * @return A reference to the last element. + */ reference back() noexcept { return element_from(tail_.prev_); } - /** Obtain a const reference to the last element. - @invariant The list may not be empty. - @return A const reference to the last element. - */ + /** + * Obtain a const reference to the last element. + * @invariant The list may not be empty. + * @return A const reference to the last element. + */ [[nodiscard]] const_reference back() const noexcept { return element_from(tail_.prev_); } - /** Obtain an iterator to the beginning of the list. - @return An iterator pointing to the beginning of the list. - */ + /** + * Obtain an iterator to the beginning of the list. + * @return An iterator pointing to the beginning of the list. + */ iterator begin() noexcept { return iterator(head_.next_); } - /** Obtain a const iterator to the beginning of the list. - @return A const iterator pointing to the beginning of the list. - */ + /** + * Obtain a const iterator to the beginning of the list. + * @return A const iterator pointing to the beginning of the list. + */ [[nodiscard]] const_iterator begin() const noexcept { return const_iterator(head_.next_); } - /** Obtain a const iterator to the beginning of the list. - @return A const iterator pointing to the beginning of the list. - */ + /** + * Obtain a const iterator to the beginning of the list. + * @return A const iterator pointing to the beginning of the list. + */ [[nodiscard]] const_iterator cbegin() const noexcept { return const_iterator(head_.next_); } - /** Obtain a iterator to the end of the list. - @return An iterator pointing to the end of the list. - */ + /** + * Obtain a iterator to the end of the list. + * @return An iterator pointing to the end of the list. + */ iterator end() noexcept { return iterator(&tail_); } - /** Obtain a const iterator to the end of the list. - @return A constiterator pointing to the end of the list. - */ + /** + * Obtain a const iterator to the end of the list. + * @return A constiterator pointing to the end of the list. + */ [[nodiscard]] const_iterator end() const noexcept { return const_iterator(&tail_); } - /** Obtain a const iterator to the end of the list - @return A constiterator pointing to the end of the list. - */ + /** + * Obtain a const iterator to the end of the list + * @return A constiterator pointing to the end of the list. + */ [[nodiscard]] const_iterator cend() const noexcept { return const_iterator(&tail_); } - /** Clear the list. - @note This does not free the elements. - */ + /** + * Clear the list. + * @note This does not free the elements. + */ void clear() noexcept { @@ -405,12 +426,13 @@ public: size_ = 0; } - /** Insert an element. - @invariant The element must not already be in the list. - @param pos The location to insert after. - @param element The element to insert. - @return An iterator pointing to the newly inserted element. - */ + /** + * Insert an element. + * @invariant The element must not already be in the list. + * @param pos The location to insert after. + * @param element The element to insert. + * @return An iterator pointing to the newly inserted element. + */ iterator insert(iterator pos, T& element) noexcept { @@ -423,11 +445,12 @@ public: return iterator(node); } - /** Insert another list into this one. - The other list is cleared. - @param pos The location to insert after. - @param other The list to insert. - */ + /** + * Insert another list into this one. + * The other list is cleared. + * @param pos The location to insert after. + * @param other The list to insert. + */ void insert(iterator pos, List& other) noexcept { @@ -443,11 +466,12 @@ public: } } - /** Remove an element. - @invariant The element must exist in the list. - @param pos An iterator pointing to the element to remove. - @return An iterator pointing to the next element after the one removed. - */ + /** + * Remove an element. + * @invariant The element must exist in the list. + * @param pos An iterator pointing to the element to remove. + * @return An iterator pointing to the next element after the one removed. + */ iterator erase(iterator pos) noexcept { @@ -459,20 +483,22 @@ public: return pos; } - /** Insert an element at the beginning of the list. - @invariant The element must not exist in the list. - @param element The element to insert. - */ + /** + * Insert an element at the beginning of the list. + * @invariant The element must not exist in the list. + * @param element The element to insert. + */ iterator pushFront(T& element) noexcept { return insert(begin(), element); } - /** Remove the element at the beginning of the list. - @invariant The list must not be empty. - @return A reference to the popped element. - */ + /** + * Remove the element at the beginning of the list. + * @invariant The list must not be empty. + * @return A reference to the popped element. + */ T& popFront() noexcept { @@ -481,20 +507,22 @@ public: return element; } - /** Append an element at the end of the list. - @invariant The element must not exist in the list. - @param element The element to append. - */ + /** + * Append an element at the end of the list. + * @invariant The element must not exist in the list. + * @param element The element to append. + */ iterator pushBack(T& element) noexcept { return insert(end(), element); } - /** Remove the element at the end of the list. - @invariant The list must not be empty. - @return A reference to the popped element. - */ + /** + * Remove the element at the end of the list. + * @invariant The list must not be empty. + * @return A reference to the popped element. + */ T& popBack() noexcept { @@ -503,7 +531,9 @@ public: return element; } - /** Swap contents with another list. */ + /** + * Swap contents with another list. + */ void swap(List& other) noexcept { @@ -513,42 +543,46 @@ public: append(temp); } - /** Insert another list at the beginning of this list. - The other list is cleared. - @param list The other list to insert. - */ + /** + * Insert another list at the beginning of this list. + * The other list is cleared. + * @param list The other list to insert. + */ iterator prepend(List& list) noexcept { return insert(begin(), list); } - /** Append another list at the end of this list. - The other list is cleared. - @param list the other list to append. - */ + /** + * Append another list at the end of this list. + * The other list is cleared. + * @param list the other list to append. + */ iterator append(List& list) noexcept { return insert(end(), list); } - /** Obtain an iterator from an element. - @invariant The element must exist in the list. - @param element The element to obtain an iterator for. - @return An iterator to the element. - */ + /** + * Obtain an iterator from an element. + * @invariant The element must exist in the list. + * @param element The element to obtain an iterator for. + * @return An iterator to the element. + */ iterator iteratorTo(T& element) const noexcept { return iterator(static_cast(&element)); } - /** Obtain a const iterator from an element. - @invariant The element must exist in the list. - @param element The element to obtain an iterator for. - @return A const iterator to the element. - */ + /** + * Obtain a const iterator from an element. + * @invariant The element must exist in the list. + * @param element The element to obtain an iterator for. + * @return A const iterator to the element. + */ [[nodiscard]] const_iterator constIteratorTo(T const& element) const noexcept { diff --git a/include/xrpl/beast/core/LockFreeStack.h b/include/xrpl/beast/core/LockFreeStack.h index d4ad45cf5c..849edc8fce 100644 --- a/include/xrpl/beast/core/LockFreeStack.h +++ b/include/xrpl/beast/core/LockFreeStack.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -40,7 +41,7 @@ public: operator=(NodePtr node) { node_ = node; - return static_cast(*this); + return *this; } LockFreeStackIterator& @@ -58,7 +59,7 @@ public: return result; } - NodePtr + [[nodiscard]] NodePtr node() const { return node_; @@ -102,18 +103,19 @@ operator!=( //------------------------------------------------------------------------------ -/** Multiple Producer, Multiple Consumer (MPMC) intrusive stack. - - This stack is implemented using the same intrusive interface as List. - All mutations are lock-free. - - The caller is responsible for preventing the "ABA" problem: - http://en.wikipedia.org/wiki/ABA_problem - - @param Tag A type name used to distinguish lists and nodes, for - putting objects in multiple lists. If this parameter is - omitted, the default tag is used. -*/ +/** + * Multiple Producer, Multiple Consumer (MPMC) intrusive stack. + * + * This stack is implemented using the same intrusive interface as List. + * All mutations are lock-free. + * + * The caller is responsible for preventing the "ABA" problem: + * http://en.wikipedia.org/wiki/ABA_problem + * + * @param Tag A type name used to distinguish lists and nodes, for + * putting objects in multiple lists. If this parameter is + * omitted, the default tag is used. + */ template class LockFreeStack { @@ -161,24 +163,27 @@ public: LockFreeStack& operator=(LockFreeStack const&) = delete; - /** Returns true if the stack is empty. */ + /** + * Returns true if the stack is empty. + */ [[nodiscard]] bool empty() const { return head_.load() == &end_; } - /** Push a node onto the stack. - The caller is responsible for preventing the ABA problem. - This operation is lock-free. - Thread safety: - Safe to call from any thread. - - @param node The node to push. - - @return `true` if the stack was previously empty. If multiple threads - are attempting to push, only one will receive `true`. - */ + /** + * Push a node onto the stack. + * The caller is responsible for preventing the ABA problem. + * This operation is lock-free. + * Thread safety: + * Safe to call from any thread. + * + * @param node The node to push. + * + * @return `true` if the stack was previously empty. If multiple threads + * are attempting to push, only one will receive `true`. + */ // VFALCO NOTE Fix this, shouldn't it be a reference like intrusive list? bool pushFront(Node* node) @@ -194,15 +199,16 @@ public: return first; } - /** Pop an element off the stack. - The caller is responsible for preventing the ABA problem. - This operation is lock-free. - Thread safety: - Safe to call from any thread. - - @return The element that was popped, or `nullptr` if the stack - was empty. - */ + /** + * Pop an element off the stack. + * The caller is responsible for preventing the ABA problem. + * This operation is lock-free. + * Thread safety: + * Safe to call from any thread. + * + * @return The element that was popped, or `nullptr` if the stack + * was empty. + */ Element* popFront() { @@ -218,12 +224,13 @@ public: return static_cast(node); } - /** Return a forward iterator to the beginning or end of the stack. - Undefined behavior results if push_front or pop_front is called - while an iteration is in progress. - Thread safety: - Caller is responsible for synchronization. - */ + /** + * Return a forward iterator to the beginning or end of the stack. + * Undefined behavior results if push_front or pop_front is called + * while an iteration is in progress. + * Thread safety: + * Caller is responsible for synchronization. + */ /** @{ */ iterator begin() diff --git a/include/xrpl/beast/core/SemanticVersion.h b/include/xrpl/beast/core/SemanticVersion.h index 826a43d3f8..338942c252 100644 --- a/include/xrpl/beast/core/SemanticVersion.h +++ b/include/xrpl/beast/core/SemanticVersion.h @@ -6,13 +6,14 @@ namespace beast { -/** A Semantic Version number. - - Identifies the build of a particular version of software using - the Semantic Versioning Specification described here: - - http://semver.org/ -*/ +/** + * A Semantic Version number. + * + * Identifies the build of a particular version of software using + * the Semantic Versioning Specification described here: + * + * http://semver.org/ + */ class SemanticVersion { public: @@ -29,14 +30,17 @@ public: SemanticVersion(std::string_view version); - /** Parse a semantic version string. - The parsing is as strict as possible. - @return `true` if the string was parsed. - */ + /** + * Parse a semantic version string. + * The parsing is as strict as possible. + * @return `true` if the string was parsed. + */ bool parse(std::string_view input); - /** Produce a string from semantic version components. */ + /** + * Produce a string from semantic version components. + */ [[nodiscard]] std::string print() const; @@ -52,9 +56,10 @@ public: } }; -/** Compare two SemanticVersions against each other. - The comparison follows the rules as per the specification. -*/ +/** + * Compare two SemanticVersions against each other. + * The comparison follows the rules as per the specification. + */ int compare(SemanticVersion const& lhs, SemanticVersion const& rhs); diff --git a/include/xrpl/beast/hash/hash_append.h b/include/xrpl/beast/hash/hash_append.h index 83cff4bdea..c5374f95e5 100644 --- a/include/xrpl/beast/hash/hash_append.h +++ b/include/xrpl/beast/hash/hash_append.h @@ -5,8 +5,8 @@ #include #include +#include #include -#include #include #include #include @@ -26,7 +26,7 @@ template inline void reverseBytes(T& t) { - unsigned char* bytes = + auto* bytes = static_cast(std::memmove(std::addressof(t), std::addressof(t), sizeof(T))); for (unsigned i = 0; i < sizeof(T) / 2; ++i) std::swap(bytes[i], bytes[sizeof(T) - 1 - i]); @@ -135,19 +135,20 @@ struct IsUniquelyRepresented> explicit IsUniquelyRepresented() = default; }; -/** Metafunction returning `true` if the type can be hashed in one call. - - For `IsContiguouslyHashable::value` to be true, then for every - combination of possible values of `T` held in `x` and `y`, - if `x == y`, then it must be true that `memcmp(&x, &y, sizeof(T))` - return 0; i.e. that `x` and `y` are represented by the same bit pattern. - - For example: A two's complement `int` should be contiguously hashable. - Every bit pattern produces a unique value that does not compare equal to - any other bit pattern's value. A IEEE floating point should not be - contiguously hashable because -0. and 0. have different bit patterns, - though they compare equal. -*/ +/** + * Metafunction returning `true` if the type can be hashed in one call. + * + * For `IsContiguouslyHashable::value` to be true, then for every + * combination of possible values of `T` held in `x` and `y`, + * if `x == y`, then it must be true that `memcmp(&x, &y, sizeof(T))` + * return 0; i.e. that `x` and `y` are represented by the same bit pattern. + * + * For example: A two's complement `int` should be contiguously hashable. + * Every bit pattern produces a unique value that does not compare equal to + * any other bit pattern's value. A IEEE floating point should not be + * contiguously hashable because -0. and 0. have different bit patterns, + * though they compare equal. + */ /** @{ */ template struct IsContiguouslyHashable @@ -172,54 +173,58 @@ struct IsContiguouslyHashable //------------------------------------------------------------------------------ -/** Logically concatenate input data to a `Hasher`. - - Hasher requirements: - - `X` is the type `Hasher` - `h` is a value of type `x` - `p` is a value convertible to `void const*` - `n` is a value of type `std::size_t`, greater than zero - - Expression: - `h.append (p, n);` - Throws: - Never - Effect: - Adds the input data to the hasher state. - - Expression: - `static_cast(j)` - Throws: - Never - Effect: - Returns the resulting hash of all the input data. -*/ +/** + * Logically concatenate input data to a `Hasher`. + * + * Hasher requirements: + * + * `X` is the type `Hasher` + * `h` is a value of type `x` + * `p` is a value convertible to `void const*` + * `n` is a value of type `std::size_t`, greater than zero + * + * Expression: + * `h.append (p, n);` + * Throws: + * Never + * Effect: + * Adds the input data to the hasher state. + * + * Expression: + * `static_cast(j)` + * Throws: + * Never + * Effect: + * Returns the resulting hash of all the input data. + */ /** @{ */ // scalars template -inline std::enable_if_t::value> +inline void hash_append(Hasher& h, T const& t) noexcept + requires(IsContiguouslyHashable::value) { // NOLINTNEXTLINE(bugprone-sizeof-expression) h(static_cast(std::addressof(t)), sizeof(t)); } template -inline std::enable_if_t< - !IsContiguouslyHashable::value && - (std::is_integral_v || std::is_pointer_v || std::is_enum_v)> +inline void hash_append(Hasher& h, T t) noexcept + requires( + !IsContiguouslyHashable::value && + (std::is_integral_v || std::is_pointer_v || std::is_enum_v)) { detail::reverseBytes(t); h(std::addressof(t), sizeof(t)); } template -inline std::enable_if_t> +inline void hash_append(Hasher& h, T t) noexcept + requires(std::is_floating_point_v) { if (t == 0) t = 0; @@ -239,36 +244,44 @@ hash_append(Hasher& h, std::nullptr_t) noexcept // Forward declarations for ADL purposes template -std::enable_if_t::value> -hash_append(Hasher& h, T (&a)[N]) noexcept; +void +hash_append(Hasher& h, T (&a)[N]) noexcept + requires(!IsContiguouslyHashable::value); template -std::enable_if_t::value> -hash_append(Hasher& h, std::basic_string const& s) noexcept; +void +hash_append(Hasher& h, std::basic_string const& s) noexcept + requires(!IsContiguouslyHashable::value); template -std::enable_if_t::value> -hash_append(Hasher& h, std::basic_string const& s) noexcept; +void +hash_append(Hasher& h, std::basic_string const& s) noexcept + requires(IsContiguouslyHashable::value); template -std::enable_if_t, Hasher>::value> -hash_append(Hasher& h, std::pair const& p) noexcept; +void +hash_append(Hasher& h, std::pair const& p) noexcept + requires(!IsContiguouslyHashable, Hasher>::value); template -std::enable_if_t::value> -hash_append(Hasher& h, std::vector const& v) noexcept; +void +hash_append(Hasher& h, std::vector const& v) noexcept + requires(!IsContiguouslyHashable::value); template -std::enable_if_t::value> -hash_append(Hasher& h, std::vector const& v) noexcept; +void +hash_append(Hasher& h, std::vector const& v) noexcept + requires(IsContiguouslyHashable::value); template -std::enable_if_t, Hasher>::value> -hash_append(Hasher& h, std::array const& a) noexcept; +void +hash_append(Hasher& h, std::array const& a) noexcept + requires(!IsContiguouslyHashable, Hasher>::value); template -std::enable_if_t, Hasher>::value> -hash_append(Hasher& h, std::tuple const& t) noexcept; +void +hash_append(Hasher& h, std::tuple const& t) noexcept + requires(!IsContiguouslyHashable, Hasher>::value); template void @@ -279,11 +292,13 @@ void hash_append(Hasher& h, std::unordered_set const& s); template -std::enable_if_t::value> -hash_append(Hasher& h, boost::container::flat_set const& v) noexcept; +void +hash_append(Hasher& h, boost::container::flat_set const& v) noexcept + requires(!IsContiguouslyHashable::value); template -std::enable_if_t::value> -hash_append(Hasher& h, boost::container::flat_set const& v) noexcept; +void +hash_append(Hasher& h, boost::container::flat_set const& v) noexcept + requires(IsContiguouslyHashable::value); template void hash_append(Hasher& h, T0 const& t0, T1 const& t1, T const&... t) noexcept; @@ -291,8 +306,9 @@ hash_append(Hasher& h, T0 const& t0, T1 const& t1, T const&... t) noexcept; // c-array template -std::enable_if_t::value> +void hash_append(Hasher& h, T (&a)[N]) noexcept + requires(!IsContiguouslyHashable::value) { for (auto const& t : a) hash_append(h, t); @@ -301,8 +317,9 @@ hash_append(Hasher& h, T (&a)[N]) noexcept // basic_string template -inline std::enable_if_t::value> +inline void hash_append(Hasher& h, std::basic_string const& s) noexcept + requires(!IsContiguouslyHashable::value) { for (auto c : s) hash_append(h, c); @@ -310,8 +327,9 @@ hash_append(Hasher& h, std::basic_string const& s) noexcep } template -inline std::enable_if_t::value> +inline void hash_append(Hasher& h, std::basic_string const& s) noexcept + requires(IsContiguouslyHashable::value) { h(s.data(), s.size() * sizeof(CharT)); hash_append(h, s.size()); @@ -320,8 +338,9 @@ hash_append(Hasher& h, std::basic_string const& s) noexcep // pair template -inline std::enable_if_t, Hasher>::value> +inline void hash_append(Hasher& h, std::pair const& p) noexcept + requires(!IsContiguouslyHashable, Hasher>::value) { hash_append(h, p.first, p.second); } @@ -329,8 +348,9 @@ hash_append(Hasher& h, std::pair const& p) noexcept // vector template -inline std::enable_if_t::value> +inline void hash_append(Hasher& h, std::vector const& v) noexcept + requires(!IsContiguouslyHashable::value) { for (auto const& t : v) hash_append(h, t); @@ -338,8 +358,9 @@ hash_append(Hasher& h, std::vector const& v) noexcept } template -inline std::enable_if_t::value> +inline void hash_append(Hasher& h, std::vector const& v) noexcept + requires(IsContiguouslyHashable::value) { h(v.data(), v.size() * sizeof(T)); hash_append(h, v.size()); @@ -348,57 +369,37 @@ hash_append(Hasher& h, std::vector const& v) noexcept // array template -std::enable_if_t, Hasher>::value> +void hash_append(Hasher& h, std::array const& a) noexcept + requires(!IsContiguouslyHashable, Hasher>::value) { for (auto const& t : a) hash_append(h, t); } template -std::enable_if_t::value> +void hash_append(Hasher& h, boost::container::flat_set const& v) noexcept + requires(!IsContiguouslyHashable::value) { for (auto const& t : v) hash_append(h, t); } template -std::enable_if_t::value> +void hash_append(Hasher& h, boost::container::flat_set const& v) noexcept + requires(IsContiguouslyHashable::value) { h(&(v.begin()), v.size() * sizeof(Key)); } // tuple -namespace detail { - -inline void -forEachItem(...) noexcept -{ -} - -template -inline int -hashOne(Hasher& h, T const& t) noexcept -{ - hash_append(h, t); - return 0; -} - -template -inline void -tuple_hash(Hasher& h, std::tuple const& t, std::index_sequence) noexcept -{ - for_each_item(hash_one(h, std::get(t))...); -} - -} // namespace detail - template -inline std::enable_if_t, Hasher>::value> +inline void hash_append(Hasher& h, std::tuple const& t) noexcept + requires(!IsContiguouslyHashable, Hasher>::value) { - detail::tuple_hash(h, t, std::index_sequence_for{}); + std::apply([&h](auto const&... item) { (hash_append(h, item), ...); }, t); } // shared_ptr diff --git a/include/xrpl/beast/hash/xxhasher.h b/include/xrpl/beast/hash/xxhasher.h index 978bbc6917..73dbb8e8ab 100644 --- a/include/xrpl/beast/hash/xxhasher.h +++ b/include/xrpl/beast/hash/xxhasher.h @@ -124,14 +124,18 @@ public: } } - template >* = nullptr> - explicit Xxhasher(Seed seed) : seed_(seed) + template + explicit Xxhasher(Seed seed) + requires(std::is_unsigned_v) + : seed_(seed) { resetBuffers(); } - template >* = nullptr> - Xxhasher(Seed seed, Seed) : seed_(seed) + template + Xxhasher(Seed seed, Seed) + requires(std::is_unsigned_v) + : seed_(seed) { resetBuffers(); } diff --git a/include/xrpl/beast/insight/Collector.h b/include/xrpl/beast/insight/Collector.h index 2e73d60400..9da2a8bb74 100644 --- a/include/xrpl/beast/insight/Collector.h +++ b/include/xrpl/beast/insight/Collector.h @@ -4,22 +4,25 @@ #include #include #include +#include #include +#include #include namespace beast::insight { -/** Interface for a manager that allows collection of metrics. - - To export metrics from a class, pass and save a shared_ptr to this - interface in the class constructor. Create the metric objects - as desired (counters, events, gauges, meters, and an optional hook) - using the interface. - - @see Counter, Event, Gauge, Hook, Meter - @see NullCollector, StatsDCollector -*/ +/** + * Interface for a manager that allows collection of metrics. + * + * To export metrics from a class, pass and save a shared_ptr to this + * interface in the class constructor. Create the metric objects + * as desired (counters, events, gauges, meters, and an optional hook) + * using the interface. + * + * @see Counter, Event, Gauge, Hook, Meter + * @see NullCollector, StatsDCollector + */ class Collector { public: @@ -27,18 +30,19 @@ public: virtual ~Collector() = 0; - /** Create a hook. - - A hook is called at each collection interval, on an implementation - defined thread. This is a convenience facility for gathering metrics - in the polling style. The typical usage is to update all the metrics - of interest in the handler. - - Handler will be called with this signature: - void handler (void) - - @see Hook - */ + /** + * Create a hook. + * + * A hook is called at each collection interval, on an implementation + * defined thread. This is a convenience facility for gathering metrics + * in the polling style. The typical usage is to update all the metrics + * of interest in the handler. + * + * Handler will be called with this signature: + * void handler (void) + * + * @see Hook + */ /** @{ */ template Hook @@ -51,9 +55,10 @@ public: makeHook(HookImpl::HandlerType const& handler) = 0; /** @} */ - /** Create a counter with the specified name. - @see Counter - */ + /** + * Create a counter with the specified name. + * @see Counter + */ /** @{ */ virtual Counter makeCounter(std::string const& name) = 0; @@ -67,9 +72,10 @@ public: } /** @} */ - /** Create an event with the specified name. - @see Event - */ + /** + * Create an event with the specified name. + * @see Event + */ /** @{ */ virtual Event makeEvent(std::string const& name) = 0; @@ -83,9 +89,10 @@ public: } /** @} */ - /** Create a gauge with the specified name. - @see Gauge - */ + /** + * Create a gauge with the specified name. + * @see Gauge + */ /** @{ */ virtual Gauge makeGauge(std::string const& name) = 0; @@ -99,9 +106,10 @@ public: } /** @} */ - /** Create a meter with the specified name. - @see Meter - */ + /** + * Create a meter with the specified name. + * @see Meter + */ /** @{ */ virtual Meter makeMeter(std::string const& name) = 0; diff --git a/include/xrpl/beast/insight/Counter.h b/include/xrpl/beast/insight/Counter.h index 482808b2c7..875fadf33a 100644 --- a/include/xrpl/beast/insight/Counter.h +++ b/include/xrpl/beast/insight/Counter.h @@ -7,34 +7,39 @@ namespace beast::insight { -/** A metric for measuring an integral value. - - A counter is a gauge calculated at the server. The owner of the counter - may increment and decrement the value by an amount. - - This is a lightweight reference wrapper which is cheap to copy and assign. - When the last reference goes away, the metric is no longer collected. -*/ +/** + * A metric for measuring an integral value. + * + * A counter is a gauge calculated at the server. The owner of the counter + * may increment and decrement the value by an amount. + * + * This is a lightweight reference wrapper which is cheap to copy and assign. + * When the last reference goes away, the metric is no longer collected. + */ class Counter final { public: using value_type = CounterImpl::value_type; - /** Create a null metric. - A null metric reports no information. - */ + /** + * Create a null metric. + * A null metric reports no information. + */ Counter() = default; - /** Create the metric reference the specified implementation. - Normally this won't be called directly. Instead, call the appropriate - factory function in the Collector interface. - @see Collector. - */ + /** + * Create the metric reference the specified implementation. + * Normally this won't be called directly. Instead, call the appropriate + * factory function in the Collector interface. + * @see Collector. + */ explicit Counter(std::shared_ptr impl) : impl_(std::move(impl)) { } - /** Increment the counter. */ + /** + * Increment the counter. + */ /** @{ */ void increment(value_type amount) const diff --git a/include/xrpl/beast/insight/Event.h b/include/xrpl/beast/insight/Event.h index afccf9baba..c3ff1a8877 100644 --- a/include/xrpl/beast/insight/Event.h +++ b/include/xrpl/beast/insight/Event.h @@ -8,35 +8,40 @@ namespace beast::insight { -/** A metric for reporting event timing. - - An event is an operation that has an associated millisecond time, or - other integral value. Because events happen at a specific moment, the - metric only supports a push-style interface. - - This is a lightweight reference wrapper which is cheap to copy and assign. - When the last reference goes away, the metric is no longer collected. -*/ +/** + * A metric for reporting event timing. + * + * An event is an operation that has an associated millisecond time, or + * other integral value. Because events happen at a specific moment, the + * metric only supports a push-style interface. + * + * This is a lightweight reference wrapper which is cheap to copy and assign. + * When the last reference goes away, the metric is no longer collected. + */ class Event final { public: using value_type = EventImpl::value_type; - /** Create a null metric. - A null metric reports no information. - */ + /** + * Create a null metric. + * A null metric reports no information. + */ Event() = default; - /** Create the metric reference the specified implementation. - Normally this won't be called directly. Instead, call the appropriate - factory function in the Collector interface. - @see Collector. - */ + /** + * Create the metric reference the specified implementation. + * Normally this won't be called directly. Instead, call the appropriate + * factory function in the Collector interface. + * @see Collector. + */ explicit Event(std::shared_ptr impl) : impl_(std::move(impl)) { } - /** Push an event notification. */ + /** + * Push an event notification. + */ template void notify(std::chrono::duration const& value) const diff --git a/include/xrpl/beast/insight/Gauge.h b/include/xrpl/beast/insight/Gauge.h index b24c4366c3..ef62e252b3 100644 --- a/include/xrpl/beast/insight/Gauge.h +++ b/include/xrpl/beast/insight/Gauge.h @@ -7,40 +7,44 @@ namespace beast::insight { -/** A metric for measuring an integral value. - - A gauge is an instantaneous measurement of a value, like the gas gauge - in a car. The caller directly sets the value, or adjusts it by a - specified amount. The value is kept in the client rather than the collector. - - This is a lightweight reference wrapper which is cheap to copy and assign. - When the last reference goes away, the metric is no longer collected. -*/ +/** + * A metric for measuring an integral value. + * + * A gauge is an instantaneous measurement of a value, like the gas gauge + * in a car. The caller directly sets the value, or adjusts it by a + * specified amount. The value is kept in the client rather than the collector. + * + * This is a lightweight reference wrapper which is cheap to copy and assign. + * When the last reference goes away, the metric is no longer collected. + */ class Gauge final { public: using value_type = GaugeImpl::value_type; using difference_type = GaugeImpl::difference_type; - /** Create a null metric. - A null metric reports no information. - */ + /** + * Create a null metric. + * A null metric reports no information. + */ Gauge() = default; - /** Create the metric reference the specified implementation. - Normally this won't be called directly. Instead, call the appropriate - factory function in the Collector interface. - @see Collector. - */ + /** + * Create the metric reference the specified implementation. + * Normally this won't be called directly. Instead, call the appropriate + * factory function in the Collector interface. + * @see Collector. + */ explicit Gauge(std::shared_ptr impl) : impl_(std::move(impl)) { } - /** Set the value on the gauge. - A Collector implementation should combine multiple calls to value - changes into a single change if the calls occur within a single - collection interval. - */ + /** + * Set the value on the gauge. + * A Collector implementation should combine multiple calls to value + * changes into a single change if the calls occur within a single + * collection interval. + */ /** @{ */ void set(value_type value) const @@ -49,6 +53,11 @@ public: impl_->set(value); } + // This is a write-through handle: assignment sets the value of the + // referenced metric. It is const-qualified and returns Gauge const& + // (a non-const Gauge& would require a const_cast), so it does not follow + // the conventional assignment-operator signature. + // NOLINTNEXTLINE(misc-unconventional-assign-operator) Gauge const& operator=(value_type value) const { @@ -57,7 +66,9 @@ public: } /** @} */ - /** Adjust the value of the gauge. */ + /** + * Adjust the value of the gauge. + */ /** @{ */ void increment(difference_type amount) const diff --git a/include/xrpl/beast/insight/Group.h b/include/xrpl/beast/insight/Group.h index 3e0eb93452..ecf7709546 100644 --- a/include/xrpl/beast/insight/Group.h +++ b/include/xrpl/beast/insight/Group.h @@ -7,13 +7,17 @@ namespace beast::insight { -/** A collector front-end that manages a group of metrics. */ +/** + * A collector front-end that manages a group of metrics. + */ class Group : public Collector { public: using ptr = std::shared_ptr; - /** Returns the name of this group, for diagnostics. */ + /** + * Returns the name of this group, for diagnostics. + */ [[nodiscard]] virtual std::string const& name() const = 0; }; diff --git a/include/xrpl/beast/insight/Groups.h b/include/xrpl/beast/insight/Groups.h index cfe4d99bdc..77fc2d3336 100644 --- a/include/xrpl/beast/insight/Groups.h +++ b/include/xrpl/beast/insight/Groups.h @@ -8,13 +8,17 @@ namespace beast::insight { -/** A container for managing a set of metric groups. */ +/** + * A container for managing a set of metric groups. + */ class Groups { public: virtual ~Groups() = 0; - /** Find or create a new collector with a given name. */ + /** + * Find or create a new collector with a given name. + */ /** @{ */ virtual Group::ptr const& get(std::string const& name) = 0; @@ -27,7 +31,9 @@ public: /** @} */ }; -/** Create a group container that uses the specified collector. */ +/** + * Create a group container that uses the specified collector. + */ std::unique_ptr makeGroups(Collector::ptr const& collector); diff --git a/include/xrpl/beast/insight/Hook.h b/include/xrpl/beast/insight/Hook.h index 8dbe5a4be0..572a9ffcb4 100644 --- a/include/xrpl/beast/insight/Hook.h +++ b/include/xrpl/beast/insight/Hook.h @@ -7,20 +7,24 @@ namespace beast::insight { -/** A reference to a handler for performing polled collection. */ +/** + * A reference to a handler for performing polled collection. + */ class Hook final { public: - /** Create a null hook. - A null hook has no associated handler. - */ + /** + * Create a null hook. + * A null hook has no associated handler. + */ Hook() = default; - /** Create a hook referencing the specified implementation. - Normally this won't be called directly. Instead, call the appropriate - factory function in the Collector interface. - @see Collector. - */ + /** + * Create a hook referencing the specified implementation. + * Normally this won't be called directly. Instead, call the appropriate + * factory function in the Collector interface. + * @see Collector. + */ explicit Hook(std::shared_ptr impl) : impl_(std::move(impl)) { } diff --git a/include/xrpl/beast/insight/Insight.h b/include/xrpl/beast/insight/Insight.h deleted file mode 100644 index bf3743cfd8..0000000000 --- a/include/xrpl/beast/insight/Insight.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include diff --git a/include/xrpl/beast/insight/Meter.h b/include/xrpl/beast/insight/Meter.h index 25ffabd928..ac2f3a352c 100644 --- a/include/xrpl/beast/insight/Meter.h +++ b/include/xrpl/beast/insight/Meter.h @@ -7,33 +7,38 @@ namespace beast::insight { -/** A metric for measuring an integral value. - - A meter may be thought of as an increment-only counter. - - This is a lightweight reference wrapper which is cheap to copy and assign. - When the last reference goes away, the metric is no longer collected. -*/ +/** + * A metric for measuring an integral value. + * + * A meter may be thought of as an increment-only counter. + * + * This is a lightweight reference wrapper which is cheap to copy and assign. + * When the last reference goes away, the metric is no longer collected. + */ class Meter final { public: using value_type = MeterImpl::value_type; - /** Create a null metric. - A null metric reports no information. - */ + /** + * Create a null metric. + * A null metric reports no information. + */ Meter() = default; - /** Create the metric reference the specified implementation. - Normally this won't be called directly. Instead, call the appropriate - factory function in the Collector interface. - @see Collector. - */ + /** + * Create the metric reference the specified implementation. + * Normally this won't be called directly. Instead, call the appropriate + * factory function in the Collector interface. + * @see Collector. + */ explicit Meter(std::shared_ptr impl) : impl_(std::move(impl)) { } - /** Increment the meter. */ + /** + * Increment the meter. + */ /** @{ */ void increment(value_type amount) const diff --git a/include/xrpl/beast/insight/NullCollector.h b/include/xrpl/beast/insight/NullCollector.h index b865526ade..ffafe6d6d5 100644 --- a/include/xrpl/beast/insight/NullCollector.h +++ b/include/xrpl/beast/insight/NullCollector.h @@ -2,9 +2,13 @@ #include +#include + namespace beast::insight { -/** A Collector which does not collect metrics. */ +/** + * A Collector which does not collect metrics. + */ class NullCollector : public Collector { public: diff --git a/include/xrpl/beast/insight/StatsDCollector.h b/include/xrpl/beast/insight/StatsDCollector.h index ad436dc626..e14d3a27ff 100644 --- a/include/xrpl/beast/insight/StatsDCollector.h +++ b/include/xrpl/beast/insight/StatsDCollector.h @@ -4,22 +4,27 @@ #include #include +#include +#include + namespace beast::insight { -/** A Collector that reports metrics to a StatsD server. - Reference: - https://github.com/b/statsd_spec -*/ +/** + * A Collector that reports metrics to a StatsD server. + * Reference: + * https://github.com/b/statsd_spec + */ class StatsDCollector : public Collector { public: explicit StatsDCollector() = default; - /** Create a StatsD collector. - @param address The IP address and port of the StatsD server. - @param prefix A string pre-pended before each metric name. - @param journal Destination for logging output. - */ + /** + * Create a StatsD collector. + * @param address The IP address and port of the StatsD server. + * @param prefix A string pre-pended before each metric name. + * @param journal Destination for logging output. + */ static std::shared_ptr make(IP::Endpoint const& address, std::string const& prefix, Journal journal); }; diff --git a/include/xrpl/beast/net/IPAddress.h b/include/xrpl/beast/net/IPAddress.h index 67deaaa787..4f4fb189a6 100644 --- a/include/xrpl/beast/net/IPAddress.h +++ b/include/xrpl/beast/net/IPAddress.h @@ -9,6 +9,7 @@ #include #include +#include #include //------------------------------------------------------------------------------ @@ -18,42 +19,54 @@ namespace IP { using Address = boost::asio::ip::address; -/** Returns the address represented as a string. */ +/** + * Returns the address represented as a string. + */ inline std::string to_string(Address const& addr) { return addr.to_string(); } -/** Returns `true` if this is a loopback address. */ +/** + * Returns `true` if this is a loopback address. + */ inline bool isLoopback(Address const& addr) { return addr.is_loopback(); } -/** Returns `true` if the address is unspecified. */ +/** + * Returns `true` if the address is unspecified. + */ inline bool isUnspecified(Address const& addr) { return addr.is_unspecified(); } -/** Returns `true` if the address is a multicast address. */ +/** + * Returns `true` if the address is a multicast address. + */ inline bool isMulticast(Address const& addr) { return addr.is_multicast(); } -/** Returns `true` if the address is a private unroutable address. */ +/** + * Returns `true` if the address is a private unroutable address. + */ inline bool isPrivate(Address const& addr) { return (addr.is_v4()) ? isPrivate(addr.to_v4()) : isPrivate(addr.to_v6()); } -/** Returns `true` if the address is a public routable address. */ +/** + * Returns `true` if the address is a public routable address. + */ inline bool isPublic(Address const& addr) { diff --git a/include/xrpl/beast/net/IPAddressConversion.h b/include/xrpl/beast/net/IPAddressConversion.h index b5fb697233..73777cf841 100644 --- a/include/xrpl/beast/net/IPAddressConversion.h +++ b/include/xrpl/beast/net/IPAddressConversion.h @@ -6,23 +6,29 @@ namespace beast::IP { -/** Convert to Endpoint. - The port is set to zero. -*/ +/** + * Convert to Endpoint. + * The port is set to zero. + */ Endpoint fromAsio(boost::asio::ip::address const& address); -/** Convert to Endpoint. */ +/** + * Convert to Endpoint. + */ Endpoint fromAsio(boost::asio::ip::tcp::endpoint const& endpoint); -/** Convert to asio::ip::address. - The port is ignored. -*/ +/** + * Convert to asio::ip::address. + * The port is ignored. + */ boost::asio::ip::address toAsioAddress(Endpoint const& endpoint); -/** Convert to asio::ip::tcp::endpoint. */ +/** + * Convert to asio::ip::tcp::endpoint. + */ boost::asio::ip::tcp::endpoint toAsioEndpoint(Endpoint const& endpoint); diff --git a/include/xrpl/beast/net/IPAddressV4.h b/include/xrpl/beast/net/IPAddressV4.h index dbe5a6095f..94943af3ea 100644 --- a/include/xrpl/beast/net/IPAddressV4.h +++ b/include/xrpl/beast/net/IPAddressV4.h @@ -1,24 +1,27 @@ #pragma once -#include - #include namespace beast::IP { using AddressV4 = boost::asio::ip::address_v4; -/** Returns `true` if the address is a private unroutable address. */ +/** + * Returns `true` if the address is a private unroutable address. + */ bool isPrivate(AddressV4 const& addr); -/** Returns `true` if the address is a public routable address. */ +/** + * Returns `true` if the address is a public routable address. + */ bool isPublic(AddressV4 const& addr); -/** Returns the address class for the given address. - @note Class 'D' represents multicast addresses (224.*.*.*). -*/ +/** + * Returns the address class for the given address. + * @note Class 'D' represents multicast addresses (224.*.*.*). + */ char getClass(AddressV4 const& address); diff --git a/include/xrpl/beast/net/IPAddressV6.h b/include/xrpl/beast/net/IPAddressV6.h index 10f806417d..b51cb62532 100644 --- a/include/xrpl/beast/net/IPAddressV6.h +++ b/include/xrpl/beast/net/IPAddressV6.h @@ -1,18 +1,20 @@ #pragma once -#include - #include namespace beast::IP { using AddressV6 = boost::asio::ip::address_v6; -/** Returns `true` if the address is a private unroutable address. */ +/** + * Returns `true` if the address is a private unroutable address. + */ bool isPrivate(AddressV6 const& addr); -/** Returns `true` if the address is a public routable address. */ +/** + * Returns `true` if the address is a public routable address. + */ bool isPublic(AddressV6 const& addr); diff --git a/include/xrpl/beast/net/IPEndpoint.h b/include/xrpl/beast/net/IPEndpoint.h index fec6e1556f..c4b269e9c3 100644 --- a/include/xrpl/beast/net/IPEndpoint.h +++ b/include/xrpl/beast/net/IPEndpoint.h @@ -3,8 +3,13 @@ #include #include #include +#include +#include +#include #include +#include +#include #include #include @@ -12,51 +17,68 @@ namespace beast::IP { using Port = std::uint16_t; -/** A version-independent IP address and port combination. */ +/** + * A version-independent IP address and port combination. + */ class Endpoint { public: - /** Create an unspecified endpoint. */ + /** + * Create an unspecified endpoint. + */ Endpoint(); - /** Create an endpoint from the address and optional port. */ + /** + * Create an endpoint from the address and optional port. + */ explicit Endpoint(Address addr, Port port = 0); - /** Create an Endpoint from a string. - If the port is omitted, the endpoint will have a zero port. - @return An optional endpoint; will be `std::nullopt` on failure - */ + /** + * Create an Endpoint from a string. + * If the port is omitted, the endpoint will have a zero port. + * @return An optional endpoint; will be `std::nullopt` on failure + */ static std::optional fromStringChecked(std::string const& s); static Endpoint fromString(std::string const& s); - /** Returns a string representing the endpoint. */ + /** + * Returns a string representing the endpoint. + */ [[nodiscard]] std::string toString() const; - /** Returns the port number on the endpoint. */ + /** + * Returns the port number on the endpoint. + */ [[nodiscard]] Port port() const { return port_; } - /** Returns a new Endpoint with a different port. */ + /** + * Returns a new Endpoint with a different port. + */ [[nodiscard]] Endpoint atPort(Port port) const { return Endpoint(addr_, port); } - /** Returns the address portion of this endpoint. */ + /** + * Returns the address portion of this endpoint. + */ [[nodiscard]] Address const& address() const { return addr_; } - /** Convenience accessors for the address part. */ + /** + * Convenience accessors for the address part. + */ /** @{ */ [[nodiscard]] bool isV4() const @@ -80,7 +102,9 @@ public: } /** @} */ - /** Arithmetic comparison. */ + /** + * Arithmetic comparison. + */ /** @{ */ friend bool operator==(Endpoint const& lhs, Endpoint const& rhs); @@ -126,35 +150,45 @@ private: // Properties -/** Returns `true` if the endpoint is a loopback address. */ +/** + * Returns `true` if the endpoint is a loopback address. + */ inline bool isLoopback(Endpoint const& endpoint) { return isLoopback(endpoint.address()); } -/** Returns `true` if the endpoint is unspecified. */ +/** + * Returns `true` if the endpoint is unspecified. + */ inline bool isUnspecified(Endpoint const& endpoint) { return isUnspecified(endpoint.address()); } -/** Returns `true` if the endpoint is a multicast address. */ +/** + * Returns `true` if the endpoint is a multicast address. + */ inline bool isMulticast(Endpoint const& endpoint) { return isMulticast(endpoint.address()); } -/** Returns `true` if the endpoint is a private unroutable address. */ +/** + * Returns `true` if the endpoint is a private unroutable address. + */ inline bool isPrivate(Endpoint const& endpoint) { return isPrivate(endpoint.address()); } -/** Returns `true` if the endpoint is a public routable address. */ +/** + * Returns `true` if the endpoint is a public routable address. + */ inline bool isPublic(Endpoint const& endpoint) { @@ -163,14 +197,18 @@ isPublic(Endpoint const& endpoint) //------------------------------------------------------------------------------ -/** Returns the endpoint represented as a string. */ +/** + * Returns the endpoint represented as a string. + */ inline std::string to_string(Endpoint const& endpoint) { return endpoint.toString(); } -/** Output stream conversion. */ +/** + * Output stream conversion. + */ template OutputStream& operator<<(OutputStream& os, Endpoint const& endpoint) @@ -179,7 +217,9 @@ operator<<(OutputStream& os, Endpoint const& endpoint) return os; } -/** Input stream conversion. */ +/** + * Input stream conversion. + */ std::istream& operator>>(std::istream& is, Endpoint& endpoint); @@ -188,7 +228,9 @@ operator>>(std::istream& is, Endpoint& endpoint); //------------------------------------------------------------------------------ namespace std { -/** std::hash support. */ +/** + * std::hash support. + */ template <> struct hash<::beast::IP::Endpoint> { @@ -203,7 +245,9 @@ struct hash<::beast::IP::Endpoint> } // namespace std namespace boost { -/** boost::hash support. */ +/** + * boost::hash support. + */ template <> struct hash<::beast::IP::Endpoint> { diff --git a/include/xrpl/beast/rfc2616.h b/include/xrpl/beast/rfc2616.h index e810733210..bd9a78fddb 100644 --- a/include/xrpl/beast/rfc2616.h +++ b/include/xrpl/beast/rfc2616.h @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -29,17 +30,20 @@ struct CiEqualPred } }; -/** Returns `true` if `c` is linear white space. - - This excludes the CRLF sequence allowed for line continuations. -*/ +/** + * Returns `true` if `c` is linear white space. + * + * This excludes the CRLF sequence allowed for line continuations. + */ inline bool isLws(char c) { return c == ' ' || c == '\t'; } -/** Returns `true` if `c` is any whitespace character. */ +/** + * Returns `true` if `c` is any whitespace character. + */ inline bool isWhite(char c) { @@ -86,14 +90,15 @@ trimRight(String const& s) } // namespace detail -/** Parse a character sequence of values separated by commas. - Double quotes and escape sequences will be converted. Excess white - space, commas, double quotes, and empty elements are not copied. - Format: - #(token|quoted-string) - Reference: - http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2 -*/ +/** + * Parse a character sequence of values separated by commas. + * Double quotes and escape sequences will be converted. Excess white + * space, commas, double quotes, and empty elements are not copied. + * Format: + * #(token|quoted-string) + * Reference: + * http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2 + */ template < class FwdIt, class Result = std::vector::value_type>>, @@ -188,14 +193,15 @@ splitCommas(boost::beast::string_view const& s) //------------------------------------------------------------------------------ -/** Iterates through a comma separated list. - - Meets the requirements of ForwardIterator. - - List defined in rfc2616 2.1. - - @note Values returned may contain backslash escapes. -*/ +/** + * Iterates through a comma separated list. + * + * Meets the requirements of ForwardIterator. + * + * List defined in rfc2616 2.1. + * + * @note Values returned may contain backslash escapes. + */ class ListIterator { using iter_type = boost::string_ref::const_iterator; @@ -322,17 +328,20 @@ ListIterator::increment() } } } -/** Returns true if two strings are equal. - - A case-insensitive comparison is used. -*/ +/** + * Returns true if two strings are equal. + * + * A case-insensitive comparison is used. + */ inline bool ciEqual(boost::string_ref s1, boost::string_ref s2) { return boost::range::equal(s1, s2, detail::CiEqualPred{}); } -/** Returns a range representing the list. */ +/** + * Returns a range representing the list. + */ inline boost::iterator_range makeList(boost::string_ref const& field) { @@ -340,10 +349,11 @@ makeList(boost::string_ref const& field) ListIterator{field.begin(), field.end()}, ListIterator{field.end(), field.end()}}; } -/** Returns true if the specified token exists in the list. - - A case-insensitive comparison is used. -*/ +/** + * Returns true if the specified token exists in the list. + * + * A case-insensitive comparison is used. + */ template bool tokenInList(boost::string_ref const& value, boost::string_ref const& token) diff --git a/include/xrpl/beast/test/yield_to.h b/include/xrpl/beast/test/yield_to.h index 84d7d8846d..b3aa482dd5 100644 --- a/include/xrpl/beast/test/yield_to.h +++ b/include/xrpl/beast/test/yield_to.h @@ -11,18 +11,21 @@ #include #include +#include +#include #include #include #include namespace beast::test { -/** Mix-in to support tests using asio coroutines. - - Derive from this class and use yield_to to launch test - functions inside coroutines. This is handy for testing - asynchronous asio code. -*/ +/** + * Mix-in to support tests using asio coroutines. + * + * Derive from this class and use yield_to to launch test + * functions inside coroutines. This is handy for testing + * asynchronous asio code. + */ class EnableYieldTo { protected: @@ -36,7 +39,9 @@ private: std::size_t running_ = 0; public: - /// The type of yield context passed to functions. + /** + * The type of yield context passed to functions. + */ using yield_context = boost::asio::yield_context; explicit EnableYieldTo(std::size_t concurrency = 1) : work_(boost::asio::make_work_guard(ios_)) @@ -55,24 +60,27 @@ public: t.join(); } - /// Return the `io_context` associated with the object + /** + * Return the `io_context` associated with the object + */ boost::asio::io_context& getIoContext() { return ios_; } - /** Run one or more functions, each in a coroutine. - - This call will block until all coroutines terminate. - - Each functions should have this signature: - @code - void f(yield_context); - @endcode - - @param fn... One or more functions to invoke. - */ + /** + * Run one or more functions, each in a coroutine. + * + * This call will block until all coroutines terminate. + * + * Each functions should have this signature: + * @code + * void f(yield_context); + * @endcode + * + * @param fn... One or more functions to invoke. + */ #if BEAST_DOXYGEN template void diff --git a/include/xrpl/beast/type_name.h b/include/xrpl/beast/type_name.h index ae7b681af9..85fd9ae6a2 100644 --- a/include/xrpl/beast/type_name.h +++ b/include/xrpl/beast/type_name.h @@ -23,6 +23,7 @@ typeName() if (auto s = abi::__cxa_demangle(name.c_str(), nullptr, nullptr, nullptr)) { name = s; + // NOLINTNEXTLINE(cppcoreguidelines-no-malloc) std::free(s); } #endif diff --git a/include/xrpl/beast/unit_test.h b/include/xrpl/beast/unit_test.h index 51ac96cacb..b4d53b2b1c 100644 --- a/include/xrpl/beast/unit_test.h +++ b/include/xrpl/beast/unit_test.h @@ -1,15 +1,6 @@ #pragma once -#include -#include -#include -#include -#include -#include -#include #include -#include -#include #ifndef BEAST_EXPECT #define BEAST_EXPECT_S1(x) #x diff --git a/include/xrpl/beast/unit_test/amount.h b/include/xrpl/beast/unit_test/amount.h index 3a392f393f..c1e4357753 100644 --- a/include/xrpl/beast/unit_test/amount.h +++ b/include/xrpl/beast/unit_test/amount.h @@ -10,7 +10,9 @@ namespace beast::unit_test { -/** Utility for producing nicely composed output of amounts with units. */ +/** + * Utility for producing nicely composed output of amounts with units. + */ class Amount { private: diff --git a/include/xrpl/beast/unit_test/detail/const_container.h b/include/xrpl/beast/unit_test/detail/const_container.h index 6826bf4258..9f4646cbdb 100644 --- a/include/xrpl/beast/unit_test/detail/const_container.h +++ b/include/xrpl/beast/unit_test/detail/const_container.h @@ -6,10 +6,11 @@ namespace beast::unit_test::detail { -/** Adapter to constrain a container interface. - The interface allows for limited read only operations. Derived classes - provide additional behavior. -*/ +/** + * Adapter to constrain a container interface. + * The interface allows for limited read only operations. Derived classes + * provide additional behavior. + */ template class ConstContainer { @@ -38,21 +39,27 @@ public: using iterator = cont_type::const_iterator; using const_iterator = cont_type::const_iterator; - /** Returns `true` if the container is empty. */ + /** + * Returns `true` if the container is empty. + */ [[nodiscard]] bool empty() const { return cont_.empty(); } - /** Returns the number of items in the container. */ + /** + * Returns the number of items in the container. + */ [[nodiscard]] size_type size() const { return cont_.size(); } - /** Returns forward iterators for traversal. */ + /** + * Returns forward iterators for traversal. + */ /** @{ */ [[nodiscard]] const_iterator begin() const diff --git a/include/xrpl/beast/unit_test/global_suites.h b/include/xrpl/beast/unit_test/global_suites.h index 72ed738bdb..18e5bc3a6b 100644 --- a/include/xrpl/beast/unit_test/global_suites.h +++ b/include/xrpl/beast/unit_test/global_suites.h @@ -10,7 +10,9 @@ namespace beast::unit_test { namespace detail { -/// Holds test suites registered during static initialization. +/** + * Holds test suites registered during static initialization. + */ inline SuiteList& globalSuites() { @@ -34,7 +36,9 @@ struct InsertSuite } // namespace detail -/// Holds test suites registered during static initialization. +/** + * Holds test suites registered during static initialization. + */ inline SuiteList const& globalSuites() { diff --git a/include/xrpl/beast/unit_test/match.h b/include/xrpl/beast/unit_test/match.h index da466ab228..966574b833 100644 --- a/include/xrpl/beast/unit_test/match.h +++ b/include/xrpl/beast/unit_test/match.h @@ -7,6 +7,7 @@ #include #include +#include namespace beast::unit_test { @@ -120,42 +121,48 @@ Selector::operator()(SuiteInfo const& s) // Utility functions for producing predicates to select suites. -/** Returns a predicate that implements a smart matching rule. - The predicate checks the suite, module, and library fields of the - SuiteInfo in that order. When it finds a match, it changes modes - depending on what was found: - - If a suite is matched first, then only the suite is selected. The - suite may be marked manual. - - If a module is matched first, then only suites from that module - and library not marked manual are selected from then on. - - If a library is matched first, then only suites from that library - not marked manual are selected from then on. - -*/ +/** + * Returns a predicate that implements a smart matching rule. + * The predicate checks the suite, module, and library fields of the + * SuiteInfo in that order. When it finds a match, it changes modes + * depending on what was found: + * + * If a suite is matched first, then only the suite is selected. The + * suite may be marked manual. + * + * If a module is matched first, then only suites from that module + * and library not marked manual are selected from then on. + * + * If a library is matched first, then only suites from that library + * not marked manual are selected from then on. + */ inline Selector matchAuto(std::string const& name) { return Selector(Selector::ModeT::Automatch, name); } -/** Return a predicate that matches all suites not marked manual. */ +/** + * Return a predicate that matches all suites not marked manual. + */ inline Selector matchAll() { return Selector(Selector::ModeT::All); } -/** Returns a predicate that matches a specific suite. */ +/** + * Returns a predicate that matches a specific suite. + */ inline Selector matchSuite(std::string const& name) { return Selector(Selector::ModeT::Suite, name); } -/** Returns a predicate that matches all suites in a library. */ +/** + * Returns a predicate that matches all suites in a library. + */ inline Selector matchLibrary(std::string const& name) { diff --git a/include/xrpl/beast/unit_test/recorder.h b/include/xrpl/beast/unit_test/recorder.h index 2ed88d4a46..fcadb63fc9 100644 --- a/include/xrpl/beast/unit_test/recorder.h +++ b/include/xrpl/beast/unit_test/recorder.h @@ -6,10 +6,16 @@ #include #include +#include + +#include +#include namespace beast::unit_test { -/** A test runner that stores the results. */ +/** + * A test runner that stores the results. + */ class Recorder : public Runner { private: @@ -20,7 +26,9 @@ private: public: Recorder() = default; - /** Returns a report with the results of all completed suites. */ + /** + * Returns a report with the results of all completed suites. + */ [[nodiscard]] Results const& report() const { diff --git a/include/xrpl/beast/unit_test/reporter.h b/include/xrpl/beast/unit_test/reporter.h index ff990dece5..0fe77a7862 100644 --- a/include/xrpl/beast/unit_test/reporter.h +++ b/include/xrpl/beast/unit_test/reporter.h @@ -5,26 +5,30 @@ #pragma once #include -#include +#include +#include #include #include #include #include +#include #include #include #include #include #include +#include namespace beast::unit_test { namespace detail { -/** A simple test runner that writes everything to a stream in real time. - The totals are output when the object is destroyed. -*/ +/** + * A simple test runner that writes everything to a stream in real time. + * The totals are output when the object is destroyed. + */ template class Reporter : public Runner { diff --git a/include/xrpl/beast/unit_test/results.h b/include/xrpl/beast/unit_test/results.h index 02aa9730d1..273ad5b129 100644 --- a/include/xrpl/beast/unit_test/results.h +++ b/include/xrpl/beast/unit_test/results.h @@ -6,17 +6,22 @@ #include +#include #include #include #include namespace beast::unit_test { -/** Holds a set of test condition outcomes in a testcase. */ +/** + * Holds a set of test condition outcomes in a testcase. + */ class CaseResults { public: - /** Holds the result of evaluating one test condition. */ + /** + * Holds the result of evaluating one test condition. + */ struct Test { explicit Test(bool pass) : pass(pass) @@ -40,28 +45,36 @@ private: public: TestsT() = default; - /** Returns the total number of test conditions. */ + /** + * Returns the total number of test conditions. + */ [[nodiscard]] std::size_t total() const { return cont().size(); } - /** Returns the number of failed test conditions. */ + /** + * Returns the number of failed test conditions. + */ [[nodiscard]] std::size_t failed() const { return failed_; } - /** Register a successful test condition. */ + /** + * Register a successful test condition. + */ void pass() { cont().emplace_back(true); } - /** Register a failed test condition. */ + /** + * Register a failed test condition. + */ void fail(std::string const& reason = "") { @@ -73,7 +86,9 @@ private: class LogT : public detail::ConstContainer> { public: - /** Insert a string into the log. */ + /** + * Insert a string into the log. + */ void insert(std::string const& s) { @@ -88,23 +103,31 @@ public: { } - /** Returns the name of this testcase. */ + /** + * Returns the name of this testcase. + */ [[nodiscard]] std::string const& name() const { return name_; } - /** Memberspace for a container of test condition outcomes. */ + /** + * Memberspace for a container of test condition outcomes. + */ TestsT tests; - /** Memberspace for a container of testcase log messages. */ + /** + * Memberspace for a container of testcase log messages. + */ LogT log; }; //-------------------------------------------------------------------------- -/** Holds the set of testcase results in a suite. */ +/** + * Holds the set of testcase results in a suite. + */ class SuiteResults : public detail::ConstContainer> { private: @@ -117,28 +140,36 @@ public: { } - /** Returns the name of this suite. */ + /** + * Returns the name of this suite. + */ [[nodiscard]] std::string const& name() const { return name_; } - /** Returns the total number of test conditions. */ + /** + * Returns the total number of test conditions. + */ [[nodiscard]] std::size_t total() const { return total_; } - /** Returns the number of failures. */ + /** + * Returns the number of failures. + */ [[nodiscard]] std::size_t failed() const { return failed_; } - /** Insert a set of testcase results. */ + /** + * Insert a set of testcase results. + */ /** @{ */ void insert(CaseResults&& r) @@ -161,7 +192,9 @@ public: //------------------------------------------------------------------------------ // VFALCO TODO Make this a template class using scoped allocators -/** Holds the results of running a set of testsuites. */ +/** + * Holds the results of running a set of testsuites. + */ class Results : public detail::ConstContainer> { private: @@ -172,28 +205,36 @@ private: public: Results() = default; - /** Returns the total number of test cases. */ + /** + * Returns the total number of test cases. + */ [[nodiscard]] std::size_t cases() const { return cases_; } - /** Returns the total number of test conditions. */ + /** + * Returns the total number of test conditions. + */ [[nodiscard]] std::size_t total() const { return total_; } - /** Returns the number of failures. */ + /** + * Returns the number of failures. + */ [[nodiscard]] std::size_t failed() const { return failed_; } - /** Insert a set of suite results. */ + /** + * Insert a set of suite results. + */ /** @{ */ void insert(SuiteResults&& r) diff --git a/include/xrpl/beast/unit_test/runner.h b/include/xrpl/beast/unit_test/runner.h index b88bfc5fe1..f8f9deca48 100644 --- a/include/xrpl/beast/unit_test/runner.h +++ b/include/xrpl/beast/unit_test/runner.h @@ -13,11 +13,12 @@ namespace beast::unit_test { -/** Unit test runner interface. - - Derived classes can customize the reporting behavior. This interface is - injected into the unit_test class to receive the results of the tests. -*/ +/** + * Unit test runner interface. + * + * Derived classes can customize the reporting behavior. This interface is + * injected into the unit_test class to receive the results of the tests. + */ class Runner { std::string arg_; @@ -33,110 +34,132 @@ public: Runner& operator=(Runner const&) = delete; - /** Set the argument string. - - The argument string is available to suites and - allows for customization of the test. Each suite - defines its own syntax for the argument string. - The same argument is passed to all suites. - */ + /** + * Set the argument string. + * + * The argument string is available to suites and + * allows for customization of the test. Each suite + * defines its own syntax for the argument string. + * The same argument is passed to all suites. + */ void arg(std::string const& s) { arg_ = s; } - /** Returns the argument string. */ + /** + * Returns the argument string. + */ [[nodiscard]] std::string const& arg() const { return arg_; } - /** Run the specified suite. - @return `true` if any conditions failed. - */ + /** + * Run the specified suite. + * @return `true` if any conditions failed. + */ template bool run(SuiteInfo const& s); - /** Run a sequence of suites. - The expression - `FwdIter::value_type` - must be convertible to `SuiteInfo`. - @return `true` if any conditions failed. - */ + /** + * Run a sequence of suites. + * The expression + * `FwdIter::value_type` + * must be convertible to `SuiteInfo`. + * @return `true` if any conditions failed. + */ template bool run(FwdIter first, FwdIter last); - /** Conditionally run a sequence of suites. - pred will be called as: - @code - bool pred(SuiteInfo const&); - @endcode - @return `true` if any conditions failed. - */ + /** + * Conditionally run a sequence of suites. + * pred will be called as: + * @code + * bool pred(SuiteInfo const&); + * @endcode + * @return `true` if any conditions failed. + */ template bool runIf(FwdIter first, FwdIter last, Pred pred = Pred{}); - /** Run all suites in a container. - @return `true` if any conditions failed. - */ + /** + * Run all suites in a container. + * @return `true` if any conditions failed. + */ template bool runEach(SequenceContainer const& c); - /** Conditionally run suites in a container. - pred will be called as: - @code - bool pred(SuiteInfo const&); - @endcode - @return `true` if any conditions failed. - */ + /** + * Conditionally run suites in a container. + * pred will be called as: + * @code + * bool pred(SuiteInfo const&); + * @endcode + * @return `true` if any conditions failed. + */ template bool runEachIf(SequenceContainer const& c, Pred pred = Pred{}); protected: - /// Called when a new suite starts. + /** + * Called when a new suite starts. + */ virtual void onSuiteBegin(SuiteInfo const&) { } - /// Called when a suite ends. + /** + * Called when a suite ends. + */ virtual void onSuiteEnd() { } - /// Called when a new case starts. + /** + * Called when a new case starts. + */ virtual void onCaseBegin(std::string const&) { } - /// Called when a new case ends. + /** + * Called when a new case ends. + */ virtual void onCaseEnd() { } - /// Called for each passing condition. + /** + * Called for each passing condition. + */ virtual void onPass() { } - /// Called for each failing condition. + /** + * Called for each failing condition. + */ virtual void onFail(std::string const&) { } - /// Called when a test logs output. + /** + * Called when a test logs output. + */ virtual void onLog(std::string const&) { diff --git a/include/xrpl/beast/unit_test/suite.h b/include/xrpl/beast/unit_test/suite.h index fded866da0..c20fe2522c 100644 --- a/include/xrpl/beast/unit_test/suite.h +++ b/include/xrpl/beast/unit_test/suite.h @@ -10,6 +10,8 @@ #include #include +#include +#include #include #include #include @@ -39,13 +41,14 @@ class Thread; enum class AbortT { NoAbortOnFail, AbortOnFail }; -/** A testsuite class. - - Derived classes execute a series of testcases, where each testcase is - a series of pass/fail tests. To provide a unit test using this class, - derive from it and use the BEAST_DEFINE_UNIT_TEST macro in a - translation unit. -*/ +/** + * A testsuite class. + * + * Derived classes execute a series of testcases, where each testcase is + * a series of pass/fail tests. To provide a unit test using this class, + * derive from it and use the BEAST_DEFINE_UNIT_TEST macro in a + * translation unit. + */ class Suite { private: @@ -116,16 +119,17 @@ private: { } - /** Open a new testcase. - - A testcase is a series of evaluated test conditions. A test - suite may have multiple test cases. A test is associated with - the last opened testcase. When the test first runs, a default - unnamed case is opened. Tests with only one case may omit the - call to testcase. - - @param abort Determines if suite continues running after a failure. - */ + /** + * Open a new testcase. + * + * A testcase is a series of evaluated test conditions. A test + * suite may have multiple test cases. A test is associated with + * the last opened testcase. When the test first runs, a default + * unnamed case is opened. Tests with only one case may omit the + * call to testcase. + * + * @param abort Determines if suite continues running after a failure. + */ void operator()(std::string const& name, AbortT abort = AbortT::NoAbortOnFail); @@ -138,19 +142,23 @@ private: }; public: - /** Logging output stream. - - Text sent to the log output stream will be forwarded to - the output stream associated with the runner. - */ + /** + * Logging output stream. + * + * Text sent to the log output stream will be forwarded to + * the output stream associated with the runner. + */ LogOs log; - /** Memberspace for declaring test cases. */ + /** + * Memberspace for declaring test cases. + */ TestcaseT testcase; - /** Returns the "current" running suite. - If no suite is running, nullptr is returned. - */ + /** + * Returns the "current" running suite. + * If no suite is running, nullptr is returned. + */ static Suite* thisSuite() { @@ -166,30 +174,34 @@ public: Suite& operator=(Suite const&) = delete; - /** Invokes the test using the specified runner. - - Data members are set up here instead of the constructor as a - convenience to writing the derived class to avoid repetition of - forwarded constructor arguments to the base. - Normally this is called by the framework for you. - */ + /** + * Invokes the test using the specified runner. + * + * Data members are set up here instead of the constructor as a + * convenience to writing the derived class to avoid repetition of + * forwarded constructor arguments to the base. + * Normally this is called by the framework for you. + */ template void operator()(Runner& r); - /** Record a successful test condition. */ + /** + * Record a successful test condition. + */ template void pass(); - /** Record a failure. - - @param reason Optional text added to the output on a failure. - - @param file The source code file where the test failed. - - @param line The source code line number where the test failed. - */ + /** + * Record a failure. + * + * @param reason Optional text added to the output on a failure. + * + * @param file The source code file where the test failed. + * + * @param line The source code line number where the test failed. + */ /** @{ */ template void @@ -200,23 +212,24 @@ public: fail(std::string const& reason = ""); /** @} */ - /** Evaluate a test condition. - - This function provides improved logging by incorporating the - file name and line number into the reported output on failure, - as well as additional text specified by the caller. - - @param shouldBeTrue The condition to test. The condition - is evaluated in a boolean context. - - @param reason Optional added text to output on a failure. - - @param file The source code file where the test failed. - - @param line The source code line number where the test failed. - - @return `true` if the test condition indicates success. - */ + /** + * Evaluate a test condition. + * + * This function provides improved logging by incorporating the + * file name and line number into the reported output on failure, + * as well as additional text specified by the caller. + * + * @param shouldBeTrue The condition to test. The condition + * is evaluated in a boolean context. + * + * @param reason Optional added text to output on a failure. + * + * @param file The source code file where the test failed. + * + * @param line The source code line number where the test failed. + * + * @return `true` if the test condition indicates success. + */ /** @{ */ template bool @@ -273,15 +286,19 @@ public: return unexcept(f, ""); } - /** Return the argument associated with the runner. */ + /** + * Return the argument associated with the runner. + */ std::string const& arg() const { return runner_->arg(); } - // DEPRECATED - // @return `true` if the test condition indicates success(a false value) + /** + * DEPRECATED + * @return `true` if the test condition indicates success(a false value) + */ template bool unexpected(Condition shouldBeFalse, String const& reason); @@ -303,7 +320,9 @@ private: return &kPTs; } - /** Runs the suite. */ + /** + * Runs the suite. + */ virtual void run() = 0; @@ -556,18 +575,20 @@ Suite::run(Runner& r) } #ifndef BEAST_EXPECT -/** Check a precondition. - - If the condition is false, the file and line number are reported. -*/ +/** + * Check a precondition. + * + * If the condition is false, the file and line number are reported. + */ #define BEAST_EXPECT(cond) expect(cond, __FILE__, __LINE__) #endif #ifndef BEAST_EXPECTS -/** Check a precondition. - - If the condition is false, the file and line number are reported. -*/ +/** + * Check a precondition. + * + * If the condition is false, the file and line number are reported. + */ #define BEAST_EXPECTS(cond, reason) \ ((cond) ? (pass(), true) : (fail((reason), __FILE__, __LINE__), false)) #endif @@ -591,41 +612,43 @@ Suite::run(Runner& r) // #ifndef BEAST_DEFINE_TESTSUITE -/** Enables insertion of test suites into the global container. - The default is to insert all test suite definitions into the global - container. If BEAST_DEFINE_TESTSUITE is user defined, this macro - has no effect. -*/ +/** + * Enables insertion of test suites into the global container. + * The default is to insert all test suite definitions into the global + * container. If BEAST_DEFINE_TESTSUITE is user defined, this macro + * has no effect. + */ #ifndef BEAST_NO_UNIT_TEST_INLINE #define BEAST_NO_UNIT_TEST_INLINE 0 #endif -/** Define a unit test suite. - - Class The type representing the class being tested. - Module Identifies the module. - Library Identifies the library. - - The declaration for the class implementing the test should be the same - as Class ## _test. For example, if Class is aged_ordered_container, the - test class must be declared as: - - @code - - struct aged_ordered_container_test : beast::unit_test::suite - { - //... - }; - - @endcode - - The macro invocation must appear in the same namespace as the test class. - - Unit test priorities were introduced so parallel unit_test::suites would - execute faster. Suites with longer running times have higher priorities - than unit tests with shorter running times. Suites with no priorities - are assumed to run most quickly, so they run last. -*/ +/** + * Define a unit test suite. + * + * Class The type representing the class being tested. + * Module Identifies the module. + * Library Identifies the library. + * + * The declaration for the class implementing the test should be the same + * as Class ## _test. For example, if Class is aged_ordered_container, the + * test class must be declared as: + * + * @code + * + * struct aged_ordered_container_test : beast::unit_test::suite + * { + * //... + * }; + * + * @endcode + * + * The macro invocation must appear in the same namespace as the test class. + * + * Unit test priorities were introduced so parallel unit_test::suites would + * execute faster. Suites with longer running times have higher priorities + * than unit tests with shorter running times. Suites with no priorities + * are assumed to run most quickly, so they run last. + */ #if BEAST_NO_UNIT_TEST_INLINE #define BEAST_DEFINE_TESTSUITE(Class, Module, Library) @@ -634,7 +657,7 @@ Suite::run(Runner& r) #define BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(Class, Module, Library, Priority) #else -#include +#include // IWYU pragma: keep #define BEAST_DEFINE_TESTSUITE(Class, Module, Library) \ BEAST_DEFINE_TESTSUITE_INSERT(Class, Module, Library, false, 0) #define BEAST_DEFINE_TESTSUITE_MANUAL(Class, Module, Library) \ diff --git a/include/xrpl/beast/unit_test/suite_info.h b/include/xrpl/beast/unit_test/suite_info.h index c09a0c2257..c4e3496f13 100644 --- a/include/xrpl/beast/unit_test/suite_info.h +++ b/include/xrpl/beast/unit_test/suite_info.h @@ -4,16 +4,18 @@ #pragma once -#include #include #include +#include #include namespace beast::unit_test { class Runner; -/** Associates a unit test type with metadata. */ +/** + * Associates a unit test type with metadata. + */ class SuiteInfo { using run_type = std::function; @@ -60,21 +62,27 @@ public: return library_; } - /// Returns `true` if this suite only runs manually. + /** + * Returns `true` if this suite only runs manually. + */ [[nodiscard]] bool manual() const { return manual_; } - /// Return the canonical suite name as a string. + /** + * Return the canonical suite name as a string. + */ [[nodiscard]] std::string fullName() const { return library_ + "." + module_ + "." + name_; } - /// Run a new instance of the associated test suite. + /** + * Run a new instance of the associated test suite. + */ void run(Runner& r) const { @@ -93,7 +101,9 @@ public: //------------------------------------------------------------------------------ -/// Convenience for producing SuiteInfo for a given test type. +/** + * Convenience for producing SuiteInfo for a given test type. + */ template SuiteInfo makeSuiteInfo(std::string name, std::string module, std::string library, bool manual, int priority) diff --git a/include/xrpl/beast/unit_test/suite_list.h b/include/xrpl/beast/unit_test/suite_list.h index 748f994602..057a362859 100644 --- a/include/xrpl/beast/unit_test/suite_list.h +++ b/include/xrpl/beast/unit_test/suite_list.h @@ -10,12 +10,15 @@ #include #include -#include -#include +#include // IWYU pragma: keep +#include // IWYU pragma: keep +#include // IWYU pragma: keep namespace beast::unit_test { -/// A container of test suites. +/** + * A container of test suites. + */ class SuiteList : public detail::ConstContainer> { private: @@ -25,10 +28,11 @@ private: #endif public: - /** Insert a suite into the set. - - The suite must not already exist. - */ + /** + * Insert a suite into the set. + * + * The suite must not already exist. + */ template void insert(char const* name, char const* module, char const* library, bool manual, int priority); diff --git a/include/xrpl/beast/unit_test/thread.h b/include/xrpl/beast/unit_test/thread.h index 7ae093eb85..5a5a99d149 100644 --- a/include/xrpl/beast/unit_test/thread.h +++ b/include/xrpl/beast/unit_test/thread.h @@ -6,13 +6,17 @@ #include +#include #include +#include #include #include namespace beast::unit_test { -/** Replacement for std::thread that handles exceptions in unit tests. */ +/** + * Replacement for std::thread that handles exceptions in unit tests. + */ class Thread { private: @@ -43,7 +47,10 @@ public: template explicit Thread(Suite& s, F&& f, Args&&... args) : s_(&s) { - std::function b = std::bind(std::forward(f), std::forward(args)...); + std::function b = [f = std::forward(f), + ... args = std::forward(args)]() mutable { + std::invoke(f, args...); + }; t_ = std::thread(&Thread::run, this, std::move(b)); } diff --git a/include/xrpl/beast/utility/Journal.h b/include/xrpl/beast/utility/Journal.h index 1262a64179..9f0a1ead66 100644 --- a/include/xrpl/beast/utility/Journal.h +++ b/include/xrpl/beast/utility/Journal.h @@ -3,11 +3,16 @@ #include #include +#include #include +#include +#include namespace beast { -/** Severity level / threshold of a Journal message. */ +/** + * Severity level / threshold of a Journal message. + */ enum class Severity : std::uint8_t { All = 0, @@ -22,18 +27,19 @@ enum class Severity : std::uint8_t { None = Disabled }; -/** A generic endpoint for log messages. - - The Journal has a few simple goals: - - * To be light-weight and copied by value. - * To allow logging statements to be left in source code. - * The logging is controlled at run-time based on a logging threshold. - - It is advisable to check Journal::active(level) prior to formatting log - text. Doing so sidesteps expensive text formatting when the results - will not be sent to the log. -*/ +/** + * A generic endpoint for log messages. + * + * The Journal has a few simple goals: + * + * * To be light-weight and copied by value. + * * To allow logging statements to be left in source code. + * * The logging is controlled at run-time based on a logging threshold. + * + * It is advisable to check Journal::active(level) prior to formatting log + * text. Doing so sidesteps expensive text formatting when the results + * will not be sent to the log. + */ class Journal { public: @@ -46,7 +52,9 @@ private: public: //-------------------------------------------------------------------------- - /** Abstraction for the underlying message destination. */ + /** + * Abstraction for the underlying message destination. + */ class Sink { protected: @@ -60,36 +68,47 @@ public: Sink& operator=(Sink const& lhs) = delete; - /** Returns `true` if text at the passed severity produces output. */ + /** + * Returns `true` if text at the passed severity produces output. + */ [[nodiscard]] virtual bool active(Severity level) const; - /** Returns `true` if a message is also written to the Output Window - * (MSVC). */ + /** + * Returns `true` if a message is also written to the Output Window + * (MSVC). + */ [[nodiscard]] virtual bool console() const; - /** Set whether messages are also written to the Output Window (MSVC). + /** + * Set whether messages are also written to the Output Window (MSVC). */ virtual void console(bool output); - /** Returns the minimum severity level this sink will report. */ + /** + * Returns the minimum severity level this sink will report. + */ [[nodiscard]] virtual Severity threshold() const; - /** Set the minimum severity this sink will report. */ + /** + * Set the minimum severity this sink will report. + */ virtual void threshold(Severity thresh); - /** Write text to the sink at the specified severity. - A conforming implementation will not write the text if the passed - level is below the current threshold(). - */ + /** + * Write text to the sink at the specified severity. + * A conforming implementation will not write the text if the passed + * level is below the current threshold(). + */ virtual void write(Severity level, std::string const& text) = 0; - /** Bypass filter and write text to the sink at the specified severity. + /** + * Bypass filter and write text to the sink at the specified severity. * Always write the message, but maintain the same formatting as if * it passed through a level filter. * @@ -105,15 +124,17 @@ public: }; #ifndef __INTELLISENSE__ - static_assert(!std::is_default_constructible_v, ""); - static_assert(!std::is_copy_constructible_v, ""); - static_assert(!std::is_move_constructible_v, ""); - static_assert(!std::is_copy_assignable_v, ""); - static_assert(!std::is_move_assignable_v, ""); - static_assert(std::is_nothrow_destructible_v, ""); + static_assert(!std::is_default_constructible_v); + static_assert(!std::is_copy_constructible_v); + static_assert(!std::is_move_constructible_v); + static_assert(!std::is_copy_assignable_v); + static_assert(!std::is_move_assignable_v); + static_assert(std::is_nothrow_destructible_v); #endif - /** Returns a Sink which does nothing. */ + /** + * Returns a Sink which does nothing. + */ static Sink& getNullSink(); @@ -161,36 +182,43 @@ public: }; #ifndef __INTELLISENSE__ - static_assert(!std::is_default_constructible_v, ""); - static_assert(std::is_copy_constructible_v, ""); - static_assert(std::is_move_constructible_v, ""); - static_assert(!std::is_copy_assignable_v, ""); - static_assert(!std::is_move_assignable_v, ""); - static_assert(std::is_nothrow_destructible_v, ""); + static_assert(!std::is_default_constructible_v); + static_assert(std::is_copy_constructible_v); + static_assert(std::is_move_constructible_v); + static_assert(!std::is_copy_assignable_v); + static_assert(!std::is_move_assignable_v); + static_assert(std::is_nothrow_destructible_v); #endif //-------------------------------------------------------------------------- public: - /** Provide a light-weight way to check active() before string formatting */ + /** + * Provide a light-weight way to check active() before string formatting + */ class Stream { public: - /** Create a stream which produces no output. */ + /** + * Create a stream which produces no output. + */ explicit Stream() : sink_(getNullSink()), level_(Severity::Disabled) { } - /** Create a stream that writes at the given level. - - Constructor is inlined so checking active() very inexpensive. - */ + /** + * Create a stream that writes at the given level. + * + * Constructor is inlined so checking active() very inexpensive. + */ Stream(Sink& sink, Severity level) : sink_(sink), level_(level) { XRPL_ASSERT( level_ < Severity::Disabled, "beast::Journal::Stream::Stream : maximum level"); } - /** Construct or copy another Stream. */ + /** + * Construct or copy another Stream. + */ Stream(Stream const& other) : Stream(other.sink_, other.level_) { } @@ -198,21 +226,27 @@ public: Stream& operator=(Stream const& other) = delete; - /** Returns the Sink that this Stream writes to. */ + /** + * Returns the Sink that this Stream writes to. + */ [[nodiscard]] Sink& sink() const { return sink_; } - /** Returns the Severity level of messages this Stream reports. */ + /** + * Returns the Severity level of messages this Stream reports. + */ [[nodiscard]] Severity level() const { return level_; } - /** Returns `true` if sink logs anything at this stream's level. */ + /** + * Returns `true` if sink logs anything at this stream's level. + */ /** @{ */ [[nodiscard]] bool active() const @@ -227,7 +261,9 @@ public: } /** @} */ - /** Output stream support. */ + /** + * Output stream support. + */ /** @{ */ ScopedStream operator<<(std::ostream& manip(std::ostream&)) const; @@ -243,49 +279,60 @@ public: }; #ifndef __INTELLISENSE__ - static_assert(std::is_default_constructible_v, ""); - static_assert(std::is_copy_constructible_v, ""); - static_assert(std::is_move_constructible_v, ""); - static_assert(!std::is_copy_assignable_v, ""); - static_assert(!std::is_move_assignable_v, ""); - static_assert(std::is_nothrow_destructible_v, ""); + static_assert(std::is_default_constructible_v); + static_assert(std::is_copy_constructible_v); + static_assert(std::is_move_constructible_v); + static_assert(!std::is_copy_assignable_v); + static_assert(!std::is_move_assignable_v); + static_assert(std::is_nothrow_destructible_v); #endif //-------------------------------------------------------------------------- - /** Journal has no default constructor. */ + /** + * Journal has no default constructor. + */ Journal() = delete; - /** Create a journal that writes to the specified sink. */ + /** + * Create a journal that writes to the specified sink. + */ explicit Journal(Sink& sink) : sink_(&sink) { } - /** Returns the Sink associated with this Journal. */ + /** + * Returns the Sink associated with this Journal. + */ [[nodiscard]] Sink& sink() const { return *sink_; } - /** Returns a stream for this sink, with the specified severity level. */ + /** + * Returns a stream for this sink, with the specified severity level. + */ [[nodiscard]] Stream stream(Severity level) const { return Stream(*sink_, level); } - /** Returns `true` if any message would be logged at this severity level. - For a message to be logged, the severity must be at or above the - sink's severity threshold. - */ + /** + * Returns `true` if any message would be logged at this severity level. + * For a message to be logged, the severity must be at or above the + * sink's severity threshold. + */ [[nodiscard]] bool active(Severity level) const { return sink_->active(level); } - /** Severity stream access functions. */ + /** + * Severity stream access functions. + */ /** @{ */ [[nodiscard]] Stream trace() const @@ -326,12 +373,12 @@ public: }; #ifndef __INTELLISENSE__ -static_assert(!std::is_default_constructible_v, ""); -static_assert(std::is_copy_constructible_v, ""); -static_assert(std::is_move_constructible_v, ""); -static_assert(std::is_copy_assignable_v, ""); -static_assert(std::is_move_assignable_v, ""); -static_assert(std::is_nothrow_destructible_v, ""); +static_assert(!std::is_default_constructible_v); +static_assert(std::is_copy_constructible_v); +static_assert(std::is_move_constructible_v); +static_assert(std::is_copy_assignable_v); +static_assert(std::is_move_assignable_v); +static_assert(std::is_nothrow_destructible_v); #endif //------------------------------------------------------------------------------ diff --git a/include/xrpl/beast/utility/PropertyStream.h b/include/xrpl/beast/utility/PropertyStream.h index 62de019edd..f32f5b7fef 100644 --- a/include/xrpl/beast/utility/PropertyStream.h +++ b/include/xrpl/beast/utility/PropertyStream.h @@ -3,14 +3,18 @@ #include #include +#include #include #include +#include namespace beast { //------------------------------------------------------------------------------ -/** Abstract stream with RAII containers that produce a property tree. */ +/** + * Abstract stream with RAII containers that produce a property tree. + */ class PropertyStream { public: @@ -304,7 +308,9 @@ public: // //------------------------------------------------------------------------------ -/** Subclasses can be called to write to a stream and have children. */ +/** + * Subclasses can be called to write to a stream and have children. + */ class PropertyStream::Source { private: @@ -322,17 +328,22 @@ public: Source& operator=(Source const&) = delete; - /** Returns the name of this source. */ + /** + * Returns the name of this source. + */ [[nodiscard]] std::string const& name() const; - /** Add a child source. */ + /** + * Add a child source. + */ void add(Source& source); - /** Add a child source by pointer. - The source pointer is returned so it can be used in ctor-initializers. - */ + /** + * Add a child source by pointer. + * The source pointer is returned so it can be used in ctor-initializers. + */ template Derived* add(Derived* child) @@ -341,45 +352,55 @@ public: return child; } - /** Remove a child source from this Source. */ + /** + * Remove a child source from this Source. + */ void remove(Source& child); - /** Remove all child sources from this Source. */ + /** + * Remove all child sources from this Source. + */ void removeAll(); - /** Write only this Source to the stream. */ + /** + * Write only this Source to the stream. + */ void writeOne(PropertyStream& stream); - /** write this source and all its children recursively to the stream. */ + /** + * write this source and all its children recursively to the stream. + */ void write(PropertyStream& stream); - /** Parse the path and write the corresponding Source and optional children. - If the source is found, it is written. If the wildcard character '*' - exists as the last character in the path, then all the children are - written recursively. - */ + /** + * Parse the path and write the corresponding Source and optional children. + * If the source is found, it is written. If the wildcard character '*' + * exists as the last character in the path, then all the children are + * written recursively. + */ void write(PropertyStream& stream, std::string const& path); - /** Parse the dot-delimited Source path and return the result. - The first value will be a pointer to the Source object corresponding - to the given path. If no Source object exists, then the first value - will be nullptr and the second value will be undefined. - The second value is a boolean indicating whether or not the path string - specifies the wildcard character '*' as the last character. - - print statement examples - "parent.child" prints child and all of its children - "parent.child." start at the parent and print down to child - "parent.grandchild" prints nothing- grandchild not direct descendent - "parent.grandchild." starts at the parent and prints down to grandchild - "parent.grandchild.*" starts at parent, print through grandchild - children - */ + /** + * Parse the dot-delimited Source path and return the result. + * The first value will be a pointer to the Source object corresponding + * to the given path. If no Source object exists, then the first value + * will be nullptr and the second value will be undefined. + * The second value is a boolean indicating whether or not the path string + * specifies the wildcard character '*' as the last character. + * + * print statement examples + * "parent.child" prints child and all of its children + * "parent.child." start at the parent and print down to child + * "parent.grandchild" prints nothing- grandchild not direct descendent + * "parent.grandchild." starts at the parent and prints down to grandchild + * "parent.grandchild.*" starts at parent, print through grandchild + * children + */ std::pair find(std::string path); @@ -399,9 +420,10 @@ public: //-------------------------------------------------------------------------- - /** Subclass override. - The default version does nothing. - */ + /** + * Subclass override. + * The default version does nothing. + */ virtual void onWrite(Map&); }; diff --git a/include/xrpl/beast/utility/WrappedSink.h b/include/xrpl/beast/utility/WrappedSink.h index 22d75927fe..3ab48e1939 100644 --- a/include/xrpl/beast/utility/WrappedSink.h +++ b/include/xrpl/beast/utility/WrappedSink.h @@ -2,11 +2,14 @@ #include +#include #include namespace beast { -/** Wraps a Journal::Sink to prefix its output with a string. */ +/** + * Wraps a Journal::Sink to prefix its output with a string. + */ // A WrappedSink both is a Sink and has a Sink: // o It inherits from Sink so it has the correct interface. diff --git a/include/xrpl/beast/utility/Zero.h b/include/xrpl/beast/utility/Zero.h index f54345d437..406921c500 100644 --- a/include/xrpl/beast/utility/Zero.h +++ b/include/xrpl/beast/utility/Zero.h @@ -4,33 +4,34 @@ namespace beast { -/** Zero allows classes to offer efficient comparisons to zero. - - Zero is a struct to allow classes to efficiently compare with zero without - requiring an rvalue construction. - - It's often the case that we have classes which combine a number and a unit. - In such cases, comparisons like t > 0 or t != 0 make sense, but comparisons - like t > 1 or t != 1 do not. - - The class Zero allows such comparisons to be easily made. - - The comparing class T either needs to have a method called signum() which - returns a positive number, 0, or a negative; or there needs to be a signum - function which resolves in the namespace which takes an instance of T and - returns a positive, zero or negative number. -*/ +/** + * Zero allows classes to offer efficient comparisons to zero. + * + * Zero is a struct to allow classes to efficiently compare with zero without + * requiring an rvalue construction. + * + * It's often the case that we have classes which combine a number and a unit. + * In such cases, comparisons like t > 0 or t != 0 make sense, but comparisons + * like t > 1 or t != 1 do not. + * + * The class Zero allows such comparisons to be easily made. + * + * The comparing class T either needs to have a method called signum() which + * returns a positive number, 0, or a negative; or there needs to be a signum + * function which resolves in the namespace which takes an instance of T and + * returns a positive, zero or negative number. + */ struct Zero { explicit Zero() = default; }; -namespace { -constexpr Zero kZero{}; -} // namespace +inline constexpr Zero kZero{}; -/** Default implementation of signum calls the method on the class. */ +/** + * Default implementation of signum calls the method on the class. + */ template auto signum(T const& t) diff --git a/include/xrpl/beast/utility/maybe_const.h b/include/xrpl/beast/utility/maybe_const.h index 10b2eaf7f6..848ea86cb2 100644 --- a/include/xrpl/beast/utility/maybe_const.h +++ b/include/xrpl/beast/utility/maybe_const.h @@ -4,7 +4,9 @@ namespace beast { -/** Makes T const or non const depending on a bool. */ +/** + * Makes T const or non const depending on a bool. + */ template struct MaybeConst { @@ -13,7 +15,9 @@ struct MaybeConst conditional_t::type const, std::remove_const_t>; }; -/** Alias for omitting `typename`. */ +/** + * Alias for omitting `typename`. + */ template using maybe_const_t = MaybeConst::type; diff --git a/include/xrpl/beast/utility/rngfill.h b/include/xrpl/beast/utility/rngfill.h index 2ea84a7a3d..5bd9d8bc5c 100644 --- a/include/xrpl/beast/utility/rngfill.h +++ b/include/xrpl/beast/utility/rngfill.h @@ -1,11 +1,8 @@ #pragma once -#include - #include #include #include -#include namespace beast { @@ -16,7 +13,7 @@ rngfill(void* const buffer, std::size_t const bytes, Generator& g) using result_type = Generator::result_type; constexpr std::size_t kResultSize = sizeof(result_type); - std::uint8_t* const bufferStart = static_cast(buffer); + auto* const bufferStart = static_cast(buffer); std::size_t const completeIterations = bytes / kResultSize; std::size_t const bytesRemaining = bytes % kResultSize; @@ -35,16 +32,14 @@ rngfill(void* const buffer, std::size_t const bytes, Generator& g) } } -template < - class Generator, - std::size_t N, - class = std::enable_if_t> +template void rngfill(std::array& a, Generator& g) + requires(N % sizeof(typename Generator::result_type) == 0) { using result_type = Generator::result_type; auto i = N / sizeof(result_type); - result_type* p = reinterpret_cast(a.data()); + auto* p = reinterpret_cast(a.data()); while (i--) *p++ = g(); } diff --git a/include/xrpl/beast/utility/temp_dir.h b/include/xrpl/beast/utility/temp_dir.h index ec661b51c4..a0ff1e6940 100644 --- a/include/xrpl/beast/utility/temp_dir.h +++ b/include/xrpl/beast/utility/temp_dir.h @@ -6,11 +6,12 @@ namespace beast { -/** RAII temporary directory. - - The directory and all its contents are deleted when - the instance of `temp_dir` is destroyed. -*/ +/** + * RAII temporary directory. + * + * The directory and all its contents are deleted when + * the instance of `temp_dir` is destroyed. + */ class TempDir { boost::filesystem::path path_; @@ -22,7 +23,9 @@ public: operator=(TempDir const&) = delete; #endif - /// Construct a temporary directory. + /** + * Construct a temporary directory. + */ TempDir() { auto const dir = boost::filesystem::temp_directory_path(); @@ -33,7 +36,9 @@ public: boost::filesystem::create_directory(path_); } - /// Destroy a temporary directory. + /** + * Destroy a temporary directory. + */ ~TempDir() { // use non-throwing calls in the destructor @@ -42,17 +47,20 @@ public: // TODO: warn/notify if ec set ? } - /// Get the native path for the temporary directory + /** + * Get the native path for the temporary directory + */ [[nodiscard]] std::string path() const { return path_.string(); } - /** Get the native path for the a file. - - The file does not need to exist. - */ + /** + * Get the native path for the a file. + * + * The file does not need to exist. + */ [[nodiscard]] std::string file(std::string const& name) const { diff --git a/include/xrpl/beast/xor_shift_engine.h b/include/xrpl/beast/xor_shift_engine.h index 45baecf101..6a7272c195 100644 --- a/include/xrpl/beast/xor_shift_engine.h +++ b/include/xrpl/beast/xor_shift_engine.h @@ -85,14 +85,15 @@ XorShiftEngine::murmurhash3(result_type x) -> result_type } // namespace detail -/** XOR-shift Generator. - - Meets the requirements of UniformRandomNumberGenerator. - - Simple and fast RNG based on: - http://xorshift.di.unimi.it/xorshift128plus.c - does not accept seed==0 -*/ +/** + * XOR-shift Generator. + * + * Meets the requirements of UniformRandomNumberGenerator. + * + * Simple and fast RNG based on: + * http://xorshift.di.unimi.it/xorshift128plus.c + * does not accept seed==0 + */ using xor_shift_engine = detail::XorShiftEngine<>; } // namespace beast diff --git a/include/xrpl/conditions/Condition.h b/include/xrpl/conditions/Condition.h index 66d1d24736..365a41a087 100644 --- a/include/xrpl/conditions/Condition.h +++ b/include/xrpl/conditions/Condition.h @@ -4,8 +4,12 @@ #include #include +#include #include +#include #include +#include +#include namespace xrpl::cryptoconditions { @@ -20,42 +24,49 @@ enum class Type : std::uint8_t { class Condition { public: - /** The largest binary condition we support. - - @note This value will be increased in the future, but it - must never decrease, as that could cause conditions - that were previously considered valid to no longer - be allowed. - */ + /** + * The largest binary condition we support. + * + * @note This value will be increased in the future, but it + * must never decrease, as that could cause conditions + * that were previously considered valid to no longer + * be allowed. + */ static constexpr std::size_t kMaxSerializedCondition = 128; - /** Load a condition from its binary form - - @param s The buffer containing the fulfillment to load. - @param ec Set to the error, if any occurred. - - The binary format for a condition is specified in the - cryptoconditions RFC. See: - - https://tools.ietf.org/html/draft-thomas-crypto-conditions-02#section-7.2 - */ + /** + * Load a condition from its binary form + * + * @param s The buffer containing the fulfillment to load. + * @param ec Set to the error, if any occurred. + * + * The binary format for a condition is specified in the + * cryptoconditions RFC. See: + * + * https://tools.ietf.org/html/draft-thomas-crypto-conditions-02#section-7.2 + */ static std::unique_ptr deserialize(Slice s, std::error_code& ec); public: Type type; - /** An identifier for this condition. - - This fingerprint is meant to be unique only with - respect to other conditions of the same type. - */ + /** + * An identifier for this condition. + * + * This fingerprint is meant to be unique only with + * respect to other conditions of the same type. + */ Buffer fingerprint; - /** The cost associated with this condition. */ + /** + * The cost associated with this condition. + */ std::uint32_t cost; - /** For compound conditions, set of conditions includes */ + /** + * For compound conditions, set of conditions includes + */ std::set subtypes; Condition(Type t, std::uint32_t c, Slice fp) : type(t), fingerprint(fp), cost(c) diff --git a/include/xrpl/conditions/Fulfillment.h b/include/xrpl/conditions/Fulfillment.h index fd8cd7d31e..11f3165a58 100644 --- a/include/xrpl/conditions/Fulfillment.h +++ b/include/xrpl/conditions/Fulfillment.h @@ -4,69 +4,83 @@ #include #include +#include +#include +#include +#include + namespace xrpl::cryptoconditions { struct Fulfillment { public: - /** The largest binary fulfillment we support. - - @note This value will be increased in the future, but it - must never decrease, as that could cause fulfillments - that were previously considered valid to no longer - be allowed. - */ + /** + * The largest binary fulfillment we support. + * + * @note This value will be increased in the future, but it + * must never decrease, as that could cause fulfillments + * that were previously considered valid to no longer + * be allowed. + */ static constexpr std::size_t kMaxSerializedFulfillment = 256; - /** Load a fulfillment from its binary form - - @param s The buffer containing the fulfillment to load. - @param ec Set to the error, if any occurred. - - The binary format for a fulfillment is specified in the - cryptoconditions RFC. See: - - https://tools.ietf.org/html/draft-thomas-crypto-conditions-02#section-7.3 - */ + /** + * Load a fulfillment from its binary form + * + * @param s The buffer containing the fulfillment to load. + * @param ec Set to the error, if any occurred. + * + * The binary format for a fulfillment is specified in the + * cryptoconditions RFC. See: + * + * https://tools.ietf.org/html/draft-thomas-crypto-conditions-02#section-7.3 + */ static std::unique_ptr deserialize(Slice s, std::error_code& ec); public: virtual ~Fulfillment() = default; - /** Returns the fulfillment's fingerprint: - - The fingerprint is an octet string uniquely - representing this fulfillment's condition - with respect to other conditions of the - same type. - */ + /** + * Returns the fulfillment's fingerprint: + * + * The fingerprint is an octet string uniquely + * representing this fulfillment's condition + * with respect to other conditions of the + * same type. + */ [[nodiscard]] virtual Buffer fingerprint() const = 0; - /** Returns the type of this condition. */ + /** + * Returns the type of this condition. + */ [[nodiscard]] virtual Type type() const = 0; - /** Validates a fulfillment. */ + /** + * Validates a fulfillment. + */ [[nodiscard]] virtual bool validate(Slice data) const = 0; - /** Calculates the cost associated with this fulfillment. * - - The cost function is deterministic and depends on the - type and properties of the condition and the fulfillment - that the condition is generated from. - */ + /** + * Calculates the cost associated with this fulfillment. * + * + * The cost function is deterministic and depends on the + * type and properties of the condition and the fulfillment + * that the condition is generated from. + */ [[nodiscard]] virtual std::uint32_t cost() const = 0; - /** Returns the condition associated with the given fulfillment. - - This process is completely deterministic. All implementations - will, if compliant, produce the identical condition for the - same fulfillment. - */ + /** + * Returns the condition associated with the given fulfillment. + * + * This process is completely deterministic. All implementations + * will, if compliant, produce the identical condition for the + * same fulfillment. + */ [[nodiscard]] virtual Condition condition() const = 0; }; @@ -85,36 +99,40 @@ operator!=(Fulfillment const& lhs, Fulfillment const& rhs) return !(lhs == rhs); } -/** Determine whether the given fulfillment and condition match */ +/** + * Determine whether the given fulfillment and condition match + */ bool match(Fulfillment const& f, Condition const& c); -/** Verify if the given message satisfies the fulfillment. - - @param f The fulfillment - @param c The condition - @param m The message - - @note the message is not relevant for some conditions - and a fulfillment will successfully satisfy its - condition for any given message. -*/ +/** + * Verify if the given message satisfies the fulfillment. + * + * @param f The fulfillment + * @param c The condition + * @param m The message + * + * @note the message is not relevant for some conditions + * and a fulfillment will successfully satisfy its + * condition for any given message. + */ bool validate(Fulfillment const& f, Condition const& c, Slice m); -/** Verify a cryptoconditional trigger. - - A cryptoconditional trigger is a cryptocondition with - an empty message. - - When using such triggers, it is recommended that the - trigger be of type preimage, prefix or threshold. If - a signature type is used (i.e. Ed25519 or RSA-SHA256) - then the Ed25519 or RSA keys should be single-use keys. - - @param f The fulfillment - @param c The condition -*/ +/** + * Verify a cryptoconditional trigger. + * + * A cryptoconditional trigger is a cryptocondition with + * an empty message. + * + * When using such triggers, it is recommended that the + * trigger be of type preimage, prefix or threshold. If + * a signature type is used (i.e. Ed25519 or RSA-SHA256) + * then the Ed25519 or RSA keys should be single-use keys. + * + * @param f The fulfillment + * @param c The condition + */ bool validate(Fulfillment const& f, Condition const& c); diff --git a/include/xrpl/conditions/detail/PreimageSha256.h b/include/xrpl/conditions/detail/PreimageSha256.h index c592ea37ee..007588a0b5 100644 --- a/include/xrpl/conditions/detail/PreimageSha256.h +++ b/include/xrpl/conditions/detail/PreimageSha256.h @@ -7,30 +7,36 @@ #include #include +#include +#include #include +#include +#include namespace xrpl::cryptoconditions { class PreimageSha256 final : public Fulfillment { public: - /** The maximum allowed length of a preimage. - - The specification does not specify a minimum supported - length, nor does it require all conditions to support - the same minimum length. - - While future versions of this code will never lower - this limit, they may opt to raise it. - */ + /** + * The maximum allowed length of a preimage. + * + * The specification does not specify a minimum supported + * length, nor does it require all conditions to support + * the same minimum length. + * + * While future versions of this code will never lower + * this limit, they may opt to raise it. + */ static constexpr std::size_t kMaxPreimageLength = 128; - /** Parse the payload for a PreimageSha256 condition - - @param s A slice containing the DER encoded payload - @param ec indicates success or failure of the operation - @return the preimage, if successful; empty pointer otherwise. - */ + /** + * Parse the payload for a PreimageSha256 condition + * + * @param s A slice containing the DER encoded payload + * @param ec indicates success or failure of the operation + * @return the preimage, if successful; empty pointer otherwise. + */ static std::unique_ptr deserialize(Slice s, std::error_code& ec) { diff --git a/include/xrpl/conditions/detail/utils.h b/include/xrpl/conditions/detail/utils.h index 87f2265034..bf16bfb42b 100644 --- a/include/xrpl/conditions/detail/utils.h +++ b/include/xrpl/conditions/detail/utils.h @@ -6,7 +6,10 @@ #include +#include +#include #include +#include // A collection of functions to decode binary blobs // encoded with X.690 Distinguished Encoding Rules. diff --git a/include/xrpl/config/BasicConfig.h b/include/xrpl/config/BasicConfig.h index 5a82f7d081..607a0c3e5f 100644 --- a/include/xrpl/config/BasicConfig.h +++ b/include/xrpl/config/BasicConfig.h @@ -6,9 +6,13 @@ #include #include +#include #include +#include +#include #include #include +#include #include namespace xrpl { @@ -17,9 +21,10 @@ using IniFileSections = std::unordered_map //------------------------------------------------------------------------------ -/** Holds a collection of configuration values. - A configuration file contains zero or more sections. -*/ +/** + * Holds a collection of configuration values. + * A configuration file contains zero or more sections. + */ class Section { private: @@ -32,28 +37,34 @@ private: using const_iterator = decltype(lookup_)::const_iterator; public: - /** Create an empty section. */ + /** + * Create an empty section. + */ explicit Section(std::string name = ""); - /** Returns the name of this section. */ + /** + * Returns the name of this section. + */ [[nodiscard]] std::string const& name() const { return name_; } - /** Returns all the lines in the section. - This includes everything. - */ + /** + * Returns all the lines in the section. + * This includes everything. + */ [[nodiscard]] std::vector const& lines() const { return lines_; } - /** Returns all the values in the section. - Values are non-empty lines which are not key/value pairs. - */ + /** + * Returns all the values in the section. + * Values are non-empty lines which are not key/value pairs. + */ [[nodiscard]] std::vector const& values() const { @@ -80,7 +91,7 @@ public: * Get the legacy value for this section. * * @return The retrieved value. A section with an empty legacy value returns - an empty string. + * an empty string. */ [[nodiscard]] std::string legacy() const @@ -95,28 +106,34 @@ public: return lines_[0]; } - /** Set a key/value pair. - The previous value is discarded. - */ + /** + * Set a key/value pair. + * The previous value is discarded. + */ void set(std::string const& key, std::string const& value); - /** Append a set of lines to this section. - Lines containing key/value pairs are added to the map, - else they are added to the values list. Everything is - added to the lines list. - */ + /** + * Append a set of lines to this section. + * Lines containing key/value pairs are added to the map, + * else they are added to the values list. Everything is + * added to the lines list. + */ void append(std::vector const& lines); - /** Append a line to this section. */ + /** + * Append a line to this section. + */ void append(std::string const& line) { append(std::vector{line}); } - /** Returns `true` if a key with the given name exists. */ + /** + * Returns `true` if a key with the given name exists. + */ [[nodiscard]] bool exists(std::string const& name) const; @@ -130,7 +147,9 @@ public: return boost::lexical_cast(iter->second); } - /// Returns a value if present, else another value. + /** + * Returns a value if present, else another value. + */ template [[nodiscard]] T valueOr(std::string const& name, T const& other) const @@ -195,23 +214,27 @@ public: //------------------------------------------------------------------------------ -/** Holds unparsed configuration information. - The raw data sections are processed with intermediate parsers specific - to each module instead of being all parsed in a central location. -*/ +/** + * Holds unparsed configuration information. + * The raw data sections are processed with intermediate parsers specific + * to each module instead of being all parsed in a central location. + */ class BasicConfig { private: std::unordered_map map_; public: - /** Returns `true` if a section with the given name exists. */ + /** + * Returns `true` if a section with the given name exists. + */ [[nodiscard]] bool exists(std::string const& name) const; - /** Returns the section with the given name. - If the section does not exist, an empty section is returned. - */ + /** + * Returns the section with the given name. + * If the section does not exist, an empty section is returned. + */ /** @{ */ Section& section(std::string const& name); @@ -232,37 +255,39 @@ public: } /** @} */ - /** Overwrite a key/value pair with a command line argument - If the section does not exist it is created. - The previous value, if any, is overwritten. - */ + /** + * Overwrite a key/value pair with a command line argument + * If the section does not exist it is created. + * The previous value, if any, is overwritten. + */ void overwrite(std::string const& section, std::string const& key, std::string const& value); - /** Remove all the key/value pairs from the section. + /** + * Remove all the key/value pairs from the section. */ void deprecatedClearSection(std::string const& section); /** - * Set a value that is not a key/value pair. + * Set a value that is not a key/value pair. * - * The value is stored as the section's first value and may be retrieved - * through section::legacy. + * The value is stored as the section's first value and may be retrieved + * through section::legacy. * - * @param section Name of the section to modify. - * @param value Contents of the legacy value. + * @param section Name of the section to modify. + * @param value Contents of the legacy value. */ void legacy(std::string const& section, std::string value); /** - * Get the legacy value of a section. A section with a - * single-line value may be retrieved as a legacy value. + * Get the legacy value of a section. A section with a + * single-line value may be retrieved as a legacy value. * - * @param sectionName Retrieve the contents of this section's - * legacy value. - * @return Contents of the legacy value. + * @param sectionName Retrieve the contents of this section's + * legacy value. + * @return Contents of the legacy value. */ [[nodiscard]] std::string legacy(std::string const& sectionName) const; @@ -285,11 +310,12 @@ protected: //------------------------------------------------------------------------------ -/** Set a value from a configuration Section - If the named value is not found or doesn't parse as a T, - the variable is unchanged. - @return `true` if value was set. -*/ +/** + * Set a value from a configuration Section + * If the named value is not found or doesn't parse as a T, + * the variable is unchanged. + * @return `true` if value was set. + */ template bool set(T& target, std::string const& name, Section const& section) @@ -298,7 +324,8 @@ set(T& target, std::string const& name, Section const& section) try { auto const val = section.get(name); - if ((foundAndValid = val.has_value())) + foundAndValid = val.has_value(); + if (foundAndValid) target = *val; } catch (boost::bad_lexical_cast const&) // NOLINT(bugprone-empty-catch) @@ -307,11 +334,12 @@ set(T& target, std::string const& name, Section const& section) return foundAndValid; } -/** Set a value from a configuration Section - If the named value is not found or doesn't cast to T, - the variable is assigned the default. - @return `true` if the named value was found and is valid. -*/ +/** + * Set a value from a configuration Section + * If the named value is not found or doesn't cast to T, + * the variable is assigned the default. + * @return `true` if the named value was found and is valid. + */ template bool set(T& target, T const& defaultValue, std::string const& name, Section const& section) @@ -322,10 +350,11 @@ set(T& target, T const& defaultValue, std::string const& name, Section const& se return foundAndValid; } -/** Retrieve a key/value pair from a section. - @return The value string converted to T if it exists - and can be parsed, or else defaultValue. -*/ +/** + * Retrieve a key/value pair from a section. + * @return The value string converted to T if it exists + * and can be parsed, or else defaultValue. + */ // NOTE This routine might be more clumsy than the previous two template T diff --git a/include/xrpl/core/ClosureCounter.h b/include/xrpl/core/ClosureCounter.h index fb13047f40..33899d671b 100644 --- a/include/xrpl/core/ClosureCounter.h +++ b/include/xrpl/core/ClosureCounter.h @@ -1,11 +1,14 @@ #pragma once #include +#include #include +#include #include #include #include +#include namespace xrpl { @@ -27,8 +30,8 @@ namespace xrpl { * the caller that they should drop the closure and cancel their operation. * `join` blocks until all existing closure substitutes are destroyed. * - * \tparam Ret The return type of the closure. - * \tparam Args The argument types of the closure. + * @tparam Ret The return type of the closure. + * @tparam Args The argument types of the closure. */ template class ClosureCounter @@ -128,18 +131,21 @@ public: ClosureCounter& operator=(ClosureCounter const&) = delete; - /** Destructor verifies all in-flight closures are complete. */ + /** + * Destructor verifies all in-flight closures are complete. + */ ~ClosureCounter() { using namespace std::chrono_literals; join("ClosureCounter", 1s, debugLog()); } - /** Returns once all counted in-flight closures are destroyed. - - @param name Name reported if join time exceeds wait. - @param wait If join() exceeds this duration report to Journal. - @param j Journal written to if wait is exceeded. + /** + * Returns once all counted in-flight closures are destroyed. + * + * @param name Name reported if join time exceeds wait. + * @param wait If join() exceeds this duration report to Journal. + * @param j Journal written to if wait is exceeded. */ void join(char const* name, std::chrono::milliseconds wait, beast::Journal j) @@ -157,13 +163,14 @@ public: } } - /** Wrap the passed closure with a reference counter. - - @param closure Closure that accepts Args parameters and returns Ret. - @return If join() has been called returns std::nullopt. Otherwise - returns a std::optional that wraps closure with a - reference counter. - */ + /** + * Wrap the passed closure with a reference counter. + * + * @param closure Closure that accepts Args parameters and returns Ret. + * @return If join() has been called returns std::nullopt. Otherwise + * returns a std::optional that wraps closure with a + * reference counter. + */ template std::optional> wrap(Closure&& closure) @@ -177,19 +184,22 @@ public: return ret; } - /** Current number of Closures outstanding. Only useful for testing. */ + /** + * Current number of Closures outstanding. Only useful for testing. + */ int count() const { return closureCount_; } - /** Returns true if this has been joined. - - Even if true is returned, counted closures may still be in flight. - However if (joined() && (count() == 0)) there should be no more - counted closures in flight. - */ + /** + * Returns true if this has been joined. + * + * Even if true is returned, counted closures may still be in flight. + * However if (joined() && (count() == 0)) there should be no more + * counted closures in flight. + */ bool joined() const { diff --git a/include/xrpl/core/Coro.ipp b/include/xrpl/core/Coro.ipp index 133caf37a9..9a45dac504 100644 --- a/include/xrpl/core/Coro.ipp +++ b/include/xrpl/core/Coro.ipp @@ -4,8 +4,10 @@ namespace xrpl { -/// Coroutine stack size (1.5 MB). Increased from 1 MB because -/// ASAN-instrumented deep call stacks exceeded the original limit. +/** + * Coroutine stack size (1.5 MB). Increased from 1 MB because + * ASAN-instrumented deep call stacks exceeded the original limit. + */ constexpr std::size_t kCoroStackSize = 1536 * 1024; template diff --git a/include/xrpl/core/HashRouter.h b/include/xrpl/core/HashRouter.h index d36b8aee6e..20aafecc5f 100644 --- a/include/xrpl/core/HashRouter.h +++ b/include/xrpl/core/HashRouter.h @@ -4,10 +4,16 @@ #include #include #include +#include #include +#include +#include +#include #include #include +#include +#include namespace xrpl { @@ -19,12 +25,14 @@ enum class HashRouterFlags : std::uint16_t { HELD = 0x08, // Held by LedgerMaster after potential processing failure TRUSTED = 0x10, // Comes from a trusted source - // Private flags (used internally in apply.cpp) - // Do not attempt to read, set, or reuse. + // Private flags. Each group is owned by one file; do not read, set, or + // reuse a flag outside the file noted. + // Used in apply.cpp PRIVATE1 = 0x0100, PRIVATE2 = 0x0200, PRIVATE3 = 0x0400, PRIVATE4 = 0x0800, + // Used in EscrowFinish.cpp PRIVATE5 = 0x1000, PRIVATE6 = 0x2000 }; @@ -67,19 +75,21 @@ any(HashRouterFlags flags) class Config; -/** Routing table for objects identified by hash. - - This table keeps track of which hashes have been received by which peers. - It is used to manage the routing and broadcasting of messages in the peer - to peer overlay. -*/ +/** + * Routing table for objects identified by hash. + * + * This table keeps track of which hashes have been received by which peers. + * It is used to manage the routing and broadcasting of messages in the peer + * to peer overlay. + */ class HashRouter { public: // The type here *MUST* match the type of Peer::id_t using PeerShortID = std::uint32_t; - /** Structure used to customize @ref HashRouter behavior. + /** + * Structure used to customize @ref HashRouter behavior. * * Even though these items are configurable, they are undocumented. Don't * change them unless there is a good reason, and network-wide coordination @@ -89,22 +99,27 @@ public: */ struct Setup { - /// Default constructor + /** + * Default constructor + */ explicit Setup() = default; using seconds = std::chrono::seconds; - /** Expiration time for a hash entry + /** + * Expiration time for a hash entry */ seconds holdTime{300}; - /** Amount of time required before a relayed item will be relayed again. + /** + * Amount of time required before a relayed item will be relayed again. */ seconds relayTime{30}; }; private: - /** An entry in the routing table. + /** + * An entry in the routing table. */ class Entry : public CountedObject { @@ -119,7 +134,7 @@ private: } [[nodiscard]] HashRouterFlags - getFlags(void) const + getFlags() const { return flags_; } @@ -130,26 +145,31 @@ private: flags_ |= flagsToSet; } - /** Return set of peers we've relayed to and reset tracking */ + /** + * Return set of peers we've relayed to and reset tracking + */ std::set releasePeerSet() { return std::move(peers_); } - /** Return seated relay time point if the message has been relayed */ + /** + * Return seated relay time point if the message has been relayed + */ [[nodiscard]] std::optional relayed() const { return relayed_; } - /** Determines if this item should be relayed. - - Checks whether the item has been recently relayed. - If it has, return false. If it has not, update the - last relay timestamp and return true. - */ + /** + * Determines if this item should be relayed. + * + * Checks whether the item has been recently relayed. + * If it has, return false. If it has not, update the + * last relay timestamp and return true. + */ bool shouldRelay(Stopwatch::time_point const& now, std::chrono::seconds relayTime) { @@ -195,11 +215,13 @@ public: bool addSuppressionPeer(uint256 const& key, PeerShortID peer); - /** Add a suppression peer and get message's relay status. + /** + * Add a suppression peer and get message's relay status. * Return pair: * element 1: true if the peer is added. * element 2: optional is seated to the relay time point or - * is unseated if has not relayed yet. */ + * is unseated if has not relayed yet. + */ std::pair> addSuppressionPeerWithStatus(uint256 const& key, PeerShortID peer); @@ -214,28 +236,30 @@ public: HashRouterFlags& flags, std::chrono::seconds txInterval); - /** Set the flags on a hash. - - @return `true` if the flags were changed. `false` if unchanged. - */ + /** + * Set the flags on a hash. + * + * @return `true` if the flags were changed. `false` if unchanged. + */ bool setFlags(uint256 const& key, HashRouterFlags flags); HashRouterFlags getFlags(uint256 const& key); - /** Determines whether the hashed item should be relayed. - - Effects: - - If the item should be relayed, this function will not - return a seated optional again until the relay time has expired. - The internal set of peers will also be reset. - - @return A `std::optional` set of peers which do not need to be - relayed to. If the result is unseated, the item should - _not_ be relayed. - */ + /** + * Determines whether the hashed item should be relayed. + * + * Effects: + * + * If the item should be relayed, this function will not + * return a seated optional again until the relay time has expired. + * The internal set of peers will also be reset. + * + * @return A `std::optional` set of peers which do not need to be + * relayed to. If the result is unseated, the item should + * _not_ be relayed. + */ std::optional> shouldRelay(uint256 const& key); diff --git a/include/xrpl/core/Job.h b/include/xrpl/core/Job.h index 6af32eb2d8..93b39701be 100644 --- a/include/xrpl/core/Job.h +++ b/include/xrpl/core/Job.h @@ -2,9 +2,14 @@ #include #include +#include #include +#include +#include #include +#include +#include namespace xrpl { @@ -78,12 +83,13 @@ class Job : public CountedObject public: using clock_type = std::chrono::steady_clock; - /** Default constructor. - - Allows Job to be used as a container type. - - This is used to allow things like jobMap [key] = value. - */ + /** + * Default constructor. + * + * Allows Job to be used as a container type. + * + * This is used to allow things like jobMap [key] = value. + */ // VFALCO NOTE I'd prefer not to have a default constructed object. // What is the semantic meaning of a Job with no associated // function? Having the invariant "all Job objects refer to @@ -103,7 +109,9 @@ public: [[nodiscard]] JobType getType() const; - /** Returns the time when the job was queued. */ + /** + * Returns the time when the job was queued. + */ [[nodiscard]] clock_type::time_point const& queueTime() const; diff --git a/include/xrpl/core/JobQueue.h b/include/xrpl/core/JobQueue.h index fc15e9a064..0c9fc76357 100644 --- a/include/xrpl/core/JobQueue.h +++ b/include/xrpl/core/JobQueue.h @@ -3,7 +3,6 @@ #include #include #include -#include #include #include @@ -12,10 +11,27 @@ // `boost/context/pooled_fixedsize_stack.hpp`, whose `.malloc()` / `.free()` // member calls on `boost::pool` collide with MSVC's `_CRTDBG_MAP_ALLOC` macros // in Debug builds (see cmake/XrplCompiler.cmake). +#include +#include +#include +#include +#include +#include + #include #include +#include +#include +#include +#include +#include +#include +#include +#include #include +#include +#include namespace xrpl { @@ -29,20 +45,23 @@ struct CoroCreateT explicit CoroCreateT() = default; }; -/** A pool of threads to perform work. - - A job posted will always run to completion. - - Coroutines that are suspended must be resumed, - and run to completion. - - When the JobQueue stops, it waits for all jobs - and coroutines to finish. -*/ +/** + * A pool of threads to perform work. + * + * A job posted will always run to completion. + * + * Coroutines that are suspended must be resumed, + * and run to completion. + * + * When the JobQueue stops, it waits for all jobs + * and coroutines to finish. + */ class JobQueue : private Workers::Callback { public: - /** Coroutines must run to completion. */ + /** + * Coroutines must run to completion. + */ class Coro : public std::enable_shared_from_this { private: @@ -71,55 +90,64 @@ public: ~Coro(); - /** Suspend coroutine execution. - Effects: - The coroutine's stack is saved. - The associated Job thread is released. - Note: - The associated Job function returns. - Undefined behavior if called consecutively without a corresponding - post. - */ + /** + * Suspend coroutine execution. + * Effects: + * The coroutine's stack is saved. + * The associated Job thread is released. + * Note: + * The associated Job function returns. + * Undefined behavior if called consecutively without a corresponding + * post. + */ void yield() const; - /** Schedule coroutine execution. - Effects: - Returns immediately. - A new job is scheduled to resume the execution of the coroutine. - When the job runs, the coroutine's stack is restored and execution - continues at the beginning of coroutine function or the - statement after the previous call to yield. Undefined behavior if - called after the coroutine has completed with a return (as opposed to - a yield()). Undefined behavior if post() or resume() called - consecutively without a corresponding yield. - - @return true if the Coro's job is added to the JobQueue. - */ + /** + * Schedule coroutine execution. + * Effects: + * Returns immediately. + * A new job is scheduled to resume the execution of the coroutine. + * When the job runs, the coroutine's stack is restored and execution + * continues at the beginning of coroutine function or the + * statement after the previous call to yield. Undefined behavior if + * called after the coroutine has completed with a return (as opposed to + * a yield()). Undefined behavior if post() or resume() called + * consecutively without a corresponding yield. + * + * @return true if the Coro's job is added to the JobQueue. + */ bool post(); - /** Resume coroutine execution. - Effects: - The coroutine continues execution from where it last left off - using this same thread. - If the coroutine has already completed, returns immediately - (handles the documented post-before-yield race condition). - Undefined behavior if resume() or post() called consecutively - without a corresponding yield. - */ + /** + * Resume coroutine execution. + * Effects: + * The coroutine continues execution from where it last left off + * using this same thread. + * If the coroutine has already completed, returns immediately + * (handles the documented post-before-yield race condition). + * Undefined behavior if resume() or post() called consecutively + * without a corresponding yield. + */ void resume(); - /** Returns true if the Coro is still runnable (has not returned). */ - bool + /** + * Returns true if the Coro is still runnable (has not returned). + */ + [[nodiscard]] bool runnable() const; - /** Once called, the Coro allows early exit without an assert. */ + /** + * Once called, the Coro allows early exit without an assert. + */ void expectEarlyExit(); - /** Waits until coroutine returns from the user function. */ + /** + * Waits until coroutine returns from the user function. + */ void join(); }; @@ -134,20 +162,19 @@ public: perf::PerfLog& perfLog); ~JobQueue() override; - /** Adds a job to the JobQueue. - - @param type The type of job. - @param name Name of the job. - @param jobHandler Lambda with signature void (Job&). Called when the - job is executed. - - @return true if jobHandler added to queue. - */ - template < - typename JobHandler, - typename = std::enable_if_t()()), void>>> + /** + * Adds a job to the JobQueue. + * + * @param type The type of job. + * @param name Name of the job. + * @param jobHandler Callable with signature void(). Called when the job is executed. + * + * @return true if jobHandler added to queue. + */ + template bool addJob(JobType type, std::string const& name, JobHandler&& jobHandler) + requires(std::is_void_v>) { if (auto optionalCountedJob = jobCounter_.wrap(std::forward(jobHandler))) { @@ -156,40 +183,46 @@ public: return false; } - /** Creates a coroutine and adds a job to the queue which will run it. - - @param t The type of job. - @param name Name of the job. - @param f Has a signature of void(std::shared_ptr). Called when the - job executes. - - @return shared_ptr to posted Coro. nullptr if post was not successful. - */ + /** + * Creates a coroutine and adds a job to the queue which will run it. + * + * @param t The type of job. + * @param name Name of the job. + * @param f Has a signature of void(std::shared_ptr). Called when the + * job executes. + * + * @return shared_ptr to posted Coro. nullptr if post was not successful. + */ template std::shared_ptr postCoro(JobType t, std::string const& name, F&& f); - /** Jobs waiting at this priority. + /** + * Jobs waiting at this priority. */ int getJobCount(JobType t) const; - /** Jobs waiting plus running at this priority. + /** + * Jobs waiting plus running at this priority. */ int getJobCountTotal(JobType t) const; - /** All waiting jobs at or greater than this priority. + /** + * All waiting jobs at or greater than this priority. */ int getJobCountGE(JobType t) const; - /** Return a scoped LoadEvent. + /** + * Return a scoped LoadEvent. */ std::unique_ptr makeLoadEvent(JobType t, std::string const& name); - /** Add multiple load events. + /** + * Add multiple load events. */ void addLoadEvents(JobType t, int count, std::chrono::milliseconds elapsed); @@ -202,7 +235,9 @@ public: json::Value getJson(int c = 0); - /** Block until no jobs running. */ + /** + * Block until no jobs running. + */ void rendezvous(); @@ -384,7 +419,7 @@ private: } // namespace xrpl -#include +#include // IWYU pragma: keep namespace xrpl { diff --git a/include/xrpl/core/JobTypeData.h b/include/xrpl/core/JobTypeData.h index 4e9f95dc04..d53440e1ca 100644 --- a/include/xrpl/core/JobTypeData.h +++ b/include/xrpl/core/JobTypeData.h @@ -2,7 +2,10 @@ #include #include +#include +#include #include +#include #include diff --git a/include/xrpl/core/JobTypeInfo.h b/include/xrpl/core/JobTypeInfo.h index 430e80b388..302a462ac6 100644 --- a/include/xrpl/core/JobTypeInfo.h +++ b/include/xrpl/core/JobTypeInfo.h @@ -2,23 +2,32 @@ #include +#include +#include +#include + namespace xrpl { -/** Holds all the 'static' information about a job, which does not change */ +/** + * Holds all the 'static' information about a job, which does not change + */ class JobTypeInfo { private: JobType const type_; std::string const name_; - /** The limit on the number of running jobs for this job type. - - A limit of 0 marks this as a "special job" which is not - dispatched via the job queue. + /** + * The limit on the number of running jobs for this job type. + * + * A limit of 0 marks this as a "special job" which is not + * dispatched via the job queue. */ int const limit_; - /** Average and peak latencies for this job type. 0 is none specified */ + /** + * Average and peak latencies for this job type. 0 is none specified + */ std::chrono::milliseconds const avgLatency_; std::chrono::milliseconds const peakLatency_; diff --git a/include/xrpl/core/JobTypes.h b/include/xrpl/core/JobTypes.h index fb5c7988cb..cc2f3ecbf5 100644 --- a/include/xrpl/core/JobTypes.h +++ b/include/xrpl/core/JobTypes.h @@ -1,10 +1,14 @@ #pragma once +#include #include #include +#include #include #include +#include +#include namespace xrpl { @@ -114,7 +118,7 @@ public: [[nodiscard]] JobTypeInfo const& get(JobType jt) const { - Map::const_iterator const iter(map.find(jt)); + auto const iter = map.find(jt); XRPL_ASSERT(iter != map.end(), "xrpl::JobTypes::get : valid input"); if (iter != map.end()) diff --git a/include/xrpl/core/LoadMonitor.h b/include/xrpl/core/LoadMonitor.h index 32a813baa7..f1a8eb6c56 100644 --- a/include/xrpl/core/LoadMonitor.h +++ b/include/xrpl/core/LoadMonitor.h @@ -5,6 +5,7 @@ #include #include +#include #include namespace xrpl { diff --git a/include/xrpl/core/NetworkIDService.h b/include/xrpl/core/NetworkIDService.h index 009f9ba6f8..8e2b3fcfe2 100644 --- a/include/xrpl/core/NetworkIDService.h +++ b/include/xrpl/core/NetworkIDService.h @@ -4,25 +4,27 @@ namespace xrpl { -/** Service that provides access to the network ID. - - This service provides read-only access to the network ID configured - for this server. The network ID identifies which network (mainnet, - testnet, devnet, or custom network) this server is configured to - connect to. - - Well-known network IDs: - - 0: Mainnet - - 1: Testnet - - 2: Devnet - - 1025+: Custom networks (require NetworkID field in transactions) -*/ +/** + * Service that provides access to the network ID. + * + * This service provides read-only access to the network ID configured + * for this server. The network ID identifies which network (mainnet, + * testnet, devnet, or custom network) this server is configured to + * connect to. + * + * Well-known network IDs: + * - 0: Mainnet + * - 1: Testnet + * - 2: Devnet + * - 1025+: Custom networks (require NetworkID field in transactions) + */ class NetworkIDService { public: virtual ~NetworkIDService() = default; - /** Get the configured network ID + /** + * Get the configured network ID * * @return The network ID this server is configured for */ diff --git a/include/xrpl/core/PeerReservationTable.h b/include/xrpl/core/PeerReservationTable.h index a9ab894124..c95c88b967 100644 --- a/include/xrpl/core/PeerReservationTable.h +++ b/include/xrpl/core/PeerReservationTable.h @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -80,7 +81,7 @@ public: /** * @return the replaced reservation if it existed - * @throw soci::soci_error + * @throws soci::soci_error */ std::optional insertOrAssign(PeerReservation const& reservation); diff --git a/include/xrpl/core/PerfLog.h b/include/xrpl/core/PerfLog.h index ca0d9333a4..f09665e291 100644 --- a/include/xrpl/core/PerfLog.h +++ b/include/xrpl/core/PerfLog.h @@ -1,6 +1,7 @@ #pragma once -#include +#include +#include #include #include diff --git a/include/xrpl/core/ServiceRegistry.h b/include/xrpl/core/ServiceRegistry.h index 1d0c9e38f4..592964134b 100644 --- a/include/xrpl/core/ServiceRegistry.h +++ b/include/xrpl/core/ServiceRegistry.h @@ -1,11 +1,17 @@ #pragma once #include +#include #include #include +#include +#include #include +#include +#include + namespace xrpl { // Forward declarations @@ -77,17 +83,17 @@ using RCLValidations = Validations; using NodeCache = TaggedCache; -/** Service registry for dependency injection. - - This abstract interface provides access to various services and components - used throughout the application. It separates the service locator pattern - from the Application lifecycle management. - - Components that need access to services can hold a reference to - ServiceRegistry rather than Application when they only need service - access and not lifecycle management. - -*/ +/** + * Service registry for dependency injection. + * + * This abstract interface provides access to various services and components + * used throughout the application. It separates the service locator pattern + * from the Application lifecycle management. + * + * Components that need access to services can hold a reference to + * ServiceRegistry rather than Application when they only need service + * access and not lifecycle management. + */ class ServiceRegistry { public: @@ -234,7 +240,9 @@ public: [[nodiscard]] virtual std::optional const& getTrapTxID() const = 0; - /** Retrieve the "wallet database" */ + /** + * Retrieve the "wallet database" + */ virtual DatabaseCon& getWalletDB() = 0; diff --git a/include/xrpl/core/StartUpType.h b/include/xrpl/core/StartUpType.h index 46359ad7b6..6d05149618 100644 --- a/include/xrpl/core/StartUpType.h +++ b/include/xrpl/core/StartUpType.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include namespace xrpl { diff --git a/include/xrpl/core/detail/Workers.h b/include/xrpl/core/detail/Workers.h index d20ebf7a64..6829d5a14b 100644 --- a/include/xrpl/core/detail/Workers.h +++ b/include/xrpl/core/detail/Workers.h @@ -60,7 +60,9 @@ class PerfLog; class Workers { public: - /** Called to perform tasks as needed. */ + /** + * Called to perform tasks as needed. + */ struct Callback { virtual ~Callback() = default; @@ -69,27 +71,29 @@ public: Callback& operator=(Callback const&) = delete; - /** Perform a task. - - The call is made on a thread owned by Workers. It is important - that you only process one task from inside your callback. Each - call to addTask will result in exactly one call to processTask. - - @param instance The worker thread instance. - - @see Workers::addTask - */ + /** + * Perform a task. + * + * The call is made on a thread owned by Workers. It is important + * that you only process one task from inside your callback. Each + * call to addTask will result in exactly one call to processTask. + * + * @param instance The worker thread instance. + * + * @see Workers::addTask + */ virtual void processTask(int instance) = 0; }; - /** Create the object. - - A number of initial threads may be optionally specified. The - default is to create one thread per CPU. - - @param threadNames The name given to each created worker thread. - */ + /** + * Create the object. + * + * A number of initial threads may be optionally specified. The + * default is to create one thread per CPU. + * + * @param threadNames The name given to each created worker thread. + */ explicit Workers( Callback& callback, perf::PerfLog* perfLog, @@ -98,49 +102,54 @@ public: ~Workers(); - /** Retrieve the desired number of threads. - - This just returns the number of active threads that were requested. If - there was a recent call to setNumberOfThreads, the actual number of - active threads may be temporarily different from what was last requested. - - @note This function is not thread-safe. - */ + /** + * Retrieve the desired number of threads. + * + * This just returns the number of active threads that were requested. If + * there was a recent call to setNumberOfThreads, the actual number of + * active threads may be temporarily different from what was last requested. + * + * @note This function is not thread-safe. + */ [[nodiscard]] int getNumberOfThreads() const noexcept; - /** Set the desired number of threads. - @note This function is not thread-safe. - */ + /** + * Set the desired number of threads. + * @note This function is not thread-safe. + */ void setNumberOfThreads(int numberOfThreads); - /** Pause all threads and wait until they are paused. - - If a thread is processing a task it will pause as soon as the task - completes. There may still be tasks signaled even after all threads - have paused. - - @note This function is not thread-safe. - */ + /** + * Pause all threads and wait until they are paused. + * + * If a thread is processing a task it will pause as soon as the task + * completes. There may still be tasks signaled even after all threads + * have paused. + * + * @note This function is not thread-safe. + */ void stop(); - /** Add a task to be performed. - - Every call to addTask will eventually result in a call to - Callback::processTask unless the Workers object is destroyed or - the number of threads is never set above zero. - - @note This function is thread-safe. - */ + /** + * Add a task to be performed. + * + * Every call to addTask will eventually result in a call to + * Callback::processTask unless the Workers object is destroyed or + * the number of threads is never set above zero. + * + * @note This function is thread-safe. + */ void addTask(); - /** Get the number of currently executing calls of Callback::processTask. - While this function is thread-safe, the value may not stay - accurate for very long. It's mainly for diagnostic purposes. - */ + /** + * Get the number of currently executing calls of Callback::processTask. + * While this function is thread-safe, the value may not stay + * accurate for very long. It's mainly for diagnostic purposes. + */ [[nodiscard]] int numberOfCurrentlyRunningTasks() const noexcept; diff --git a/include/xrpl/core/detail/semaphore.h b/include/xrpl/core/detail/semaphore.h index 7bc83f86f5..abf6705097 100644 --- a/include/xrpl/core/detail/semaphore.h +++ b/include/xrpl/core/detail/semaphore.h @@ -29,6 +29,7 @@ #pragma once #include +#include #include namespace xrpl { @@ -44,14 +45,17 @@ private: public: using size_type = std::size_t; - /** Create the semaphore, with an optional initial count. - If unspecified, the initial count is zero. - */ + /** + * Create the semaphore, with an optional initial count. + * If unspecified, the initial count is zero. + */ explicit BasicSemaphore(size_type count = 0) : count_(count) { } - /** Increment the count and unblock one waiting thread. */ + /** + * Increment the count and unblock one waiting thread. + */ void notify() { @@ -60,7 +64,9 @@ public: cond_.notify_one(); } - /** Block until notify is called. */ + /** + * Block until notify is called. + */ void wait() { @@ -70,9 +76,10 @@ public: --count_; } - /** Perform a non-blocking wait. - @return `true` If the wait would be satisfied. - */ + /** + * Perform a non-blocking wait. + * @return `true` If the wait would be satisfied. + */ bool tryWait() { diff --git a/include/xrpl/crypto/RFC1751.h b/include/xrpl/crypto/RFC1751.h index 19b636b9dc..3de65c3028 100644 --- a/include/xrpl/crypto/RFC1751.h +++ b/include/xrpl/crypto/RFC1751.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -15,13 +16,14 @@ public: static void getEnglishFromKey(std::string& strHuman, std::string const& strKey); - /** Chooses a single dictionary word from the data. - - This is not particularly secure but it can be useful to provide - a unique name for something given a GUID or fixed data. We use - it to turn the pubkey_node into an easily remembered and identified - 4 character string. - */ + /** + * Chooses a single dictionary word from the data. + * + * This is not particularly secure but it can be useful to provide + * a unique name for something given a GUID or fixed data. We use + * it to turn the pubkey_node into an easily remembered and identified + * 4 character string. + */ static std::string getWordFromBlob(void const* blob, size_t bytes); diff --git a/include/xrpl/crypto/csprng.h b/include/xrpl/crypto/csprng.h index e386d9d11e..e19d33a464 100644 --- a/include/xrpl/crypto/csprng.h +++ b/include/xrpl/crypto/csprng.h @@ -1,17 +1,21 @@ #pragma once +#include +#include +#include #include namespace xrpl { -/** A cryptographically secure random number engine - - The engine is thread-safe (it uses a lock to serialize - access) and will, automatically, mix in some randomness - from std::random_device. - - Meets the requirements of UniformRandomNumberEngine -*/ +/** + * A cryptographically secure random number engine + * + * The engine is thread-safe (it uses a lock to serialize + * access) and will, automatically, mix in some randomness + * from std::random_device. + * + * Meets the requirements of UniformRandomNumberEngine + */ class CsprngEngine { private: @@ -31,15 +35,21 @@ public: CsprngEngine(); ~CsprngEngine(); - /** Mix entropy into the pool */ + /** + * Mix entropy into the pool + */ void mixEntropy(void* buffer = nullptr, std::size_t count = 0); - /** Generate a random integer */ + /** + * Generate a random integer + */ result_type operator()(); - /** Fill a buffer with the requested amount of random data */ + /** + * Fill a buffer with the requested amount of random data + */ void operator()(void* ptr, std::size_t count); @@ -58,14 +68,15 @@ public: } }; -/** The default cryptographically secure PRNG - - Use this when you need to generate random numbers or - data that will be used for encryption or passed into - cryptographic routines. - - This meets the requirements of UniformRandomNumberEngine -*/ +/** + * The default cryptographically secure PRNG + * + * Use this when you need to generate random numbers or + * data that will be used for encryption or passed into + * cryptographic routines. + * + * This meets the requirements of UniformRandomNumberEngine + */ CsprngEngine& cryptoPrng(); diff --git a/include/xrpl/crypto/secure_erase.h b/include/xrpl/crypto/secure_erase.h index 74284b03f7..38531afc1d 100644 --- a/include/xrpl/crypto/secure_erase.h +++ b/include/xrpl/crypto/secure_erase.h @@ -4,20 +4,21 @@ namespace xrpl { -/** Attempts to clear the given blob of memory. - - The underlying implementation of this function takes pains to - attempt to outsmart the compiler from optimizing the clearing - away. Please note that, despite that, remnants of content may - remain floating around in memory as well as registers, caches - and more. - - For a more in-depth discussion of the subject please see the - below posts by Colin Percival: - - http://www.daemonology.net/blog/2014-09-04-how-to-zero-a-buffer.html - http://www.daemonology.net/blog/2014-09-06-zeroing-buffers-is-insufficient.html -*/ +/** + * Attempts to clear the given blob of memory. + * + * The underlying implementation of this function takes pains to + * attempt to outsmart the compiler from optimizing the clearing + * away. Please note that, despite that, remnants of content may + * remain floating around in memory as well as registers, caches + * and more. + * + * For a more in-depth discussion of the subject please see the + * below posts by Colin Percival: + * + * http://www.daemonology.net/blog/2014-09-04-how-to-zero-a-buffer.html + * http://www.daemonology.net/blog/2014-09-06-zeroing-buffers-is-insufficient.html + */ void secureErase(void* dest, std::size_t bytes); diff --git a/include/xrpl/json/JsonPropertyStream.h b/include/xrpl/json/JsonPropertyStream.h index 47317b9ddb..498283c16b 100644 --- a/include/xrpl/json/JsonPropertyStream.h +++ b/include/xrpl/json/JsonPropertyStream.h @@ -3,9 +3,14 @@ #include #include +#include +#include + namespace xrpl { -/** A PropertyStream::Sink which produces a json::Value of type ValueType::Object. */ +/** + * A PropertyStream::Sink which produces a json::Value of type ValueType::Object. + */ class JsonPropertyStream : public beast::PropertyStream { public: diff --git a/include/xrpl/json/Output.h b/include/xrpl/json/Output.h index c01253f713..53d453c277 100644 --- a/include/xrpl/json/Output.h +++ b/include/xrpl/json/Output.h @@ -17,18 +17,20 @@ stringOutput(std::string& s) return [&](boost::beast::string_view const& b) { s.append(b.data(), b.size()); }; } -/** Writes a minimal representation of a Json value to an Output in O(n) time. - - Data is streamed right to the output, so only a marginal amount of memory is - used. This can be very important for a very large json::Value. +/** + * Writes a minimal representation of a Json value to an Output in O(n) time. + * + * Data is streamed right to the output, so only a marginal amount of memory is + * used. This can be very important for a very large json::Value. */ void outputJson(json::Value const&, Output const&); -/** Return the minimal string representation of a json::Value in O(n) time. - - This requires a memory allocation for the full size of the output. - If possible, use outputJson(). +/** + * Return the minimal string representation of a json::Value in O(n) time. + * + * This requires a memory allocation for the full size of the output. + * If possible, use outputJson(). */ std::string jsonAsString(json::Value const&); diff --git a/include/xrpl/json/Writer.h b/include/xrpl/json/Writer.h index 87e3e99c7e..ec7fd6a0d2 100644 --- a/include/xrpl/json/Writer.h +++ b/include/xrpl/json/Writer.h @@ -1,107 +1,109 @@ #pragma once -#include #include #include #include +#include #include +#include +#include namespace json { /** - * Writer implements an O(1)-space, O(1)-granular output JSON writer. + * Writer implements an O(1)-space, O(1)-granular output JSON writer. * - * O(1)-space means that it uses a fixed amount of memory, and that there are - * no heap allocations at each step of the way. + * O(1)-space means that it uses a fixed amount of memory, and that there are + * no heap allocations at each step of the way. * - * O(1)-granular output means the writer only outputs in small segments of a - * bounded size, using a bounded number of CPU cycles in doing so. This is - * very helpful in scheduling long jobs. + * O(1)-granular output means the writer only outputs in small segments of a + * bounded size, using a bounded number of CPU cycles in doing so. This is + * very helpful in scheduling long jobs. * - * The tradeoff is that you have to fill items in the JSON tree as you go, - * and you can never go backward. + * The tradeoff is that you have to fill items in the JSON tree as you go, + * and you can never go backward. * - * Writer can write single JSON tokens, but the typical use is to write out an - * entire JSON object. For example: + * Writer can write single JSON tokens, but the typical use is to write out an + * entire JSON object. For example: * - * { - * Writer w (out); + * { + * Writer w (out); * - * w.startObject (); // Start the root object. - * w.set ("hello", "world"); - * w.set ("goodbye", 23); - * w.finishObject (); // Finish the root object. - * } + * w.startObject (); // Start the root object. + * w.set ("hello", "world"); + * w.set ("goodbye", 23); + * w.finishObject (); // Finish the root object. + * } * - * which outputs the string + * which outputs the string * - * {"hello":"world","goodbye":23} + * {"hello":"world","goodbye":23} * - * There can be an object inside an object: + * There can be an object inside an object: * - * { - * Writer w (out); + * { + * Writer w (out); * - * w.startObject (); // Start the root object. - * w.set ("hello", "world"); + * w.startObject (); // Start the root object. + * w.set ("hello", "world"); * - * w.startObjectSet ("subobject"); // Start a sub-object. - * w.set ("goodbye", 23); // Add a key, value assignment. - * w.finishObject (); // Finish the sub-object. + * w.startObjectSet ("subobject"); // Start a sub-object. + * w.set ("goodbye", 23); // Add a key, value assignment. + * w.finishObject (); // Finish the sub-object. * - * w.finishObject (); // Finish the root-object. - * } + * w.finishObject (); // Finish the root-object. + * } * - * which outputs the string + * which outputs the string * - * {"hello":"world","subobject":{"goodbye":23}}. + * {"hello":"world","subobject":{"goodbye":23}}. * - * Arrays work similarly + * Arrays work similarly * - * { - * Writer w (out); - * w.startObject (); // Start the root object. + * { + * Writer w (out); + * w.startObject (); // Start the root object. * - * w.startArraySet ("hello"); // Start an array. - * w.append (23) // Append some items. - * w.append ("skidoo") - * w.finishArray (); // Finish the array. + * w.startArraySet ("hello"); // Start an array. + * w.append (23) // Append some items. + * w.append ("skidoo") + * w.finishArray (); // Finish the array. * - * w.finishObject (); // Finish the root object. - * } + * w.finishObject (); // Finish the root object. + * } * - * which outputs the string + * which outputs the string * - * {"hello":[23,"skidoo"]}. + * {"hello":[23,"skidoo"]}. * * - * If you've reached the end of a long object, you can just use finishAll() - * which finishes all arrays and objects that you have started. + * If you've reached the end of a long object, you can just use finishAll() + * which finishes all arrays and objects that you have started. * - * { - * Writer w (out); - * w.startObject (); // Start the root object. + * { + * Writer w (out); + * w.startObject (); // Start the root object. * - * w.startArraySet ("hello"); // Start an array. - * w.append (23) // Append an item. + * w.startArraySet ("hello"); // Start an array. + * w.append (23) // Append an item. * - * w.startArrayAppend () // Start a sub-array. - * w.append ("one"); - * w.append ("two"); + * w.startArrayAppend () // Start a sub-array. + * w.append ("one"); + * w.append ("two"); * - * w.startObjectAppend (); // Append a sub-object. - * w.finishAll (); // Finish everything. - * } + * w.startObjectAppend (); // Append a sub-object. + * w.finishAll (); // Finish everything. + * } * - * which outputs the string + * which outputs the string * - * {"hello":[23,["one","two",{}]]}. + * {"hello":[23,["one","two",{}]]}. * - * For convenience, the destructor of Writer calls w.finishAll() which makes - * sure that all arrays and objects are closed. This means that you can throw - * an exception, or have a coroutine simply clean up the stack, and be sure - * that you do in fact generate a complete JSON object. + * For convenience, the destructor of Writer calls w.finishAll() which makes + * sure that all arrays and objects are closed. This means that you can throw + * an exception, or have a coroutine simply clean up the stack, and be sure + * that you do in fact generate a complete JSON object. */ class Writer @@ -116,26 +118,37 @@ public: ~Writer(); - /** Start a new collection at the root level. */ + /** + * Start a new collection at the root level. + */ void startRoot(CollectionType); - /** Start a new collection inside an array. */ + /** + * Start a new collection inside an array. + */ void startAppend(CollectionType); - /** Start a new collection inside an object. */ + /** + * Start a new collection inside an object. + */ void startSet(CollectionType, std::string const& key); - /** Finish the collection most recently started. */ + /** + * Finish the collection most recently started. + */ void finish(); - /** Finish all objects and arrays. After finishArray() has been called, no - * more operations can be performed. */ + /** + * Finish all objects and arrays. After finishArray() has been called, no + * more operations can be performed. + */ void finishAll(); - /** Append a value to an array. + /** + * Append a value to an array. * * Scalar must be a scalar - that is, a number, boolean, string, string * literal, nullptr or json::Value @@ -148,12 +161,15 @@ public: output(t); } - /** Add a comma before this next item if not the first item in an array. - Useful if you are writing the actual array yourself. */ + /** + * Add a comma before this next item if not the first item in an array. + * Useful if you are writing the actual array yourself. + */ void rawAppend(); - /** Add a key, value assignment to an object. + /** + * Add a key, value assignment to an object. * * Scalar must be a scalar - that is, a number, boolean, string, string * literal, or nullptr. @@ -172,8 +188,10 @@ public: output(t); } - /** Emit just "tag": as part of an object. Useful if you are writing the - actual value data yourself. */ + /** + * Emit just "tag": as part of an object. Useful if you are writing the + * actual value data yourself. + */ void rawSet(std::string const& key); @@ -192,22 +210,32 @@ public: void output(json::Value const&); - /** Output a null. */ + /** + * Output a null. + */ void output(std::nullptr_t); - /** Output a float. */ + /** + * Output a float. + */ void output(float); - /** Output a double. */ + /** + * Output a double. + */ void output(double); - /** Output a bool. */ + /** + * Output a bool. + */ void output(bool); - /** Output numbers or booleans. */ + /** + * Output numbers or booleans. + */ template void output(Type t) diff --git a/include/xrpl/json/detail/json_assert.h b/include/xrpl/json/detail/json_assert.h index 8e33f45b65..f501e42aa4 100644 --- a/include/xrpl/json/detail/json_assert.h +++ b/include/xrpl/json/detail/json_assert.h @@ -1,8 +1,5 @@ #pragma once -#include -#include - #define JSON_ASSERT_MESSAGE(condition, message) \ if (!(condition)) \ xrpl::Throw(message); diff --git a/include/xrpl/json/json_reader.h b/include/xrpl/json/json_reader.h index 9251183281..ed60f49ce4 100644 --- a/include/xrpl/json/json_reader.h +++ b/include/xrpl/json/json_reader.h @@ -5,13 +5,16 @@ #include +#include +#include #include +#include namespace json { -/** \brief Unserialize a JSON document into a +/** + * @brief Unserialize a JSON document into a * Value. - * */ class Reader { @@ -19,48 +22,55 @@ public: using Char = char; using Location = Char const*; - /** \brief Constructs a Reader allowing all features + /** + * @brief Constructs a Reader allowing all features * for parsing. */ Reader() = default; - /** \brief Read a Value from a JSON - * document. \param document UTF-8 encoded string containing the document to - * read. \param root [out] Contains the root value of the document if it was + /** + * @brief Read a Value from a JSON + * document. @param document UTF-8 encoded string containing the document to + * read. @param root [out] Contains the root value of the document if it was * successfully parsed. - * \return \c true if the document was successfully parsed, \c false if an + * @return @c true if the document was successfully parsed, @c false if an * error occurred. */ bool parse(std::string const& document, Value& root); - /** \brief Read a Value from a JSON - * document. \param document UTF-8 encoded string containing the document to - * read. \param root [out] Contains the root value of the document if it was + /** + * @brief Read a Value from a JSON + * document. @param document UTF-8 encoded string containing the document to + * read. @param root [out] Contains the root value of the document if it was * successfully parsed. - * \return \c true if the document was successfully parsed, \c false if an + * @return @c true if the document was successfully parsed, @c false if an * error occurred. */ bool parse(char const* beginDoc, char const* endDoc, Value& root); - /// \brief Parse from input stream. - /// \see json::operator>>(std::istream&, json::Value&). + /** + * @brief Parse from input stream. + * @see json::operator>>(std::istream&, json::Value&). + */ bool parse(std::istream& is, Value& root); - /** \brief Read a Value from a JSON buffer - * sequence. \param root [out] Contains the root value of the document if it - * was successfully parsed. \param UTF-8 encoded buffer sequence. \return \c - * true if the buffer was successfully parsed, \c false if an error + /** + * @brief Read a Value from a JSON buffer + * sequence. @param root [out] Contains the root value of the document if it + * was successfully parsed. @param UTF-8 encoded buffer sequence. @return @c + * true if the buffer was successfully parsed, @c false if an error * occurred. */ template bool parse(Value& root, BufferSequence const& bs); - /** \brief Returns a user friendly string that list errors in the parsed - * document. \return Formatted error message with the list of errors with + /** + * @brief Returns a user friendly string that list errors in the parsed + * document. @return Formatted error message with the list of errors with * their location in the parsed document. An empty string is returned if no * error occurred during parsing. */ @@ -151,7 +161,7 @@ private: Location end, unsigned int& unicode); bool - addError(std::string const& message, Token& token, Location extra = 0); + addError(std::string const& message, Token& token, Location extra = nullptr); bool recoverFromError(TokenType skipUntilToken); bool @@ -192,30 +202,31 @@ Reader::parse(Value& root, BufferSequence const& bs) return parse(s, root); } -/** \brief Read from 'sin' into 'root'. - - Always keep comments from the input JSON. - - This can be used to read a file into a particular sub-object. - For example: - \code - json::Value root; - cin >> root["dir"]["file"]; - cout << root; - \endcode - Result: - \verbatim - { -"dir": { - "file": { - // The input stream JSON would be nested here. - } -} - } - \endverbatim - \throw std::exception on parse error. - \see json::operator<<() -*/ +/** + * @brief Read from 'sin' into 'root'. + * + * Always keep comments from the input JSON. + * + * This can be used to read a file into a particular sub-object. + * For example: + * @code + * json::Value root; + * cin >> root["dir"]["file"]; + * cout << root; + * @endcode + * Result: + * @verbatim + * { + * "dir": { + * "file": { + * // The input stream JSON would be nested here. + * } + * } + * } + * @endverbatim + * @throws std::exception on parse error. + * @see json::operator<<() + */ std::istream& operator>>(std::istream&, Value&); diff --git a/include/xrpl/json/json_value.h b/include/xrpl/json/json_value.h index f786c6a9dc..47ad3ac1e0 100644 --- a/include/xrpl/json/json_value.h +++ b/include/xrpl/json/json_value.h @@ -9,11 +9,13 @@ #include #include -/** \brief JSON (JavaScript Object Notation). +/** + * @brief JSON (JavaScript Object Notation). */ namespace json { -/** \brief Type of the value held by a Value object. +/** + * @brief Type of the value held by a Value object. */ enum class ValueType { Null = 0, ///< 'null' value @@ -26,19 +28,20 @@ enum class ValueType { Object ///< object value (collection of name/value pairs). }; -/** \brief Lightweight wrapper to tag static string. +/** + * @brief Lightweight wrapper to tag static string. * * Value constructor and ValueType::Object member assignment takes advantage of the * StaticString and avoid the cost of string duplication when storing the * string or the member name. * * Example of usage: - * \code + * @code * json::Value aValue( StaticString("some text") ); * json::Value object; * static const StaticString code("code"); * object[code] = 1234; - * \endcode + * @endcode */ class StaticString { @@ -99,7 +102,8 @@ operator!=(StaticString x, std::string const& y) return !(y == x); } -/** \brief Represents a JSON value. +/** + * @brief Represents a JSON value. * * This class is a discriminated union wrapper that can represent a: * - signed integer [range: Value::kMinInt - Value::kMaxInt] @@ -175,37 +179,39 @@ public: using ObjectValues = std::map; public: - /** \brief Create a default Value of the given type. - - This is a very useful constructor. - To create an empty array, pass ValueType::Array. - To create an empty object, pass ValueType::Object. - Another Value can then be set to this one by assignment. - This is useful since clear() and resize() will not alter types. - - Examples: - \code - json::Value null_value; // null - json::Value arr_value(json::ValueType::Array); // [] - json::Value obj_value(json::ValueType::Object); // {} - \endcode - */ + /** + * @brief Create a default Value of the given type. + * + * This is a very useful constructor. + * To create an empty array, pass ValueType::Array. + * To create an empty object, pass ValueType::Object. + * Another Value can then be set to this one by assignment. + * This is useful since clear() and resize() will not alter types. + * + * Examples: + * @code + * json::Value null_value; // null + * json::Value arr_value(json::ValueType::Array); // [] + * json::Value obj_value(json::ValueType::Object); // {} + * @endcode + */ Value(ValueType type = ValueType::Null); Value(Int value); Value(UInt value); Value(double value); Value(char const* value); Value(xrpl::Number const& value); - /** \brief Constructs a value from a static string. - + /** + * @brief Constructs a value from a static string. + * * Like other value string constructor but do not duplicate the string for * internal storage. The given string must remain alive after the call to - this + * this * constructor. * Example of usage: - * \code + * @code * json::Value aValue( StaticString("some text") ); - * \endcode + * @endcode */ Value(StaticString const& value); Value(std::string const& value); @@ -220,7 +226,9 @@ public: Value(Value&& other) noexcept; - /// Swap values. + /** + * Swap values. + */ void swap(Value& other) noexcept; @@ -229,7 +237,9 @@ public: [[nodiscard]] char const* asCString() const; - /** Returns the unquoted string value. */ + /** + * Returns the unquoted string value. + */ [[nodiscard]] std::string asString() const; [[nodiscard]] Int @@ -241,13 +251,17 @@ public: [[nodiscard]] bool asBool() const; - /** Correct absolute value from int or unsigned int */ + /** + * Correct absolute value from int or unsigned int + */ [[nodiscard]] UInt asAbsUInt() const; // TODO: What is the "empty()" method this docstring mentions? - /** isNull() tests to see if this field is null. Don't use this method to - test for emptiness: use empty(). */ + /** + * isNull() tests to see if this field is null. Don't use this method to + * test for emptiness: use empty(). + */ [[nodiscard]] bool isNull() const; [[nodiscard]] bool @@ -276,116 +290,157 @@ public: [[nodiscard]] bool isConvertibleTo(ValueType other) const; - /// Number of values in array or object + /** + * Number of values in array or object + */ [[nodiscard]] UInt size() const; - /** Returns false if this is an empty array, empty object, empty string, - or null. */ + /** + * Returns false if this is an empty array, empty object, empty string, + * or null. + */ explicit operator bool() const; - /// Remove all object members and array elements. - /// \pre type() is ValueType::Array, ValueType::Object, or ValueType::Null - /// \post type() is unchanged + /** + * Remove all object members and array elements. + * @pre type() is ValueType::Array, ValueType::Object, or ValueType::Null + * @post type() is unchanged + */ void clear(); - /// Access an array element (zero based index ). - /// If the array contains less than index element, then null value are - /// inserted in the array so that its size is index+1. (You may need to say - /// 'value[0u]' to get your compiler to distinguish - /// this from the operator[] which takes a string.) + /** + * Access an array element (zero based index ). + * If the array contains less than index element, then null value are + * inserted in the array so that its size is index+1. (You may need to say + * 'value[0u]' to get your compiler to distinguish + * this from the operator[] which takes a string.) + */ Value& operator[](UInt index); - /// Access an array element (zero based index ) - /// (You may need to say 'value[0u]' to get your compiler to distinguish - /// this from the operator[] which takes a string.) + /** + * Access an array element (zero based index ) + * (You may need to say 'value[0u]' to get your compiler to distinguish + * this from the operator[] which takes a string.) + */ Value const& operator[](UInt index) const; - /// If the array contains at least index+1 elements, returns the element - /// value, otherwise returns defaultValue. + /** + * If the array contains at least index+1 elements, returns the element + * value, otherwise returns defaultValue. + */ [[nodiscard]] Value get(UInt index, Value const& defaultValue) const; - /// Return true if index < size(). + /** + * Return true if index < size(). + */ [[nodiscard]] bool isValidIndex(UInt index) const; - /// \brief Append value to array at the end. - /// - /// Equivalent to jsonvalue[jsonvalue.size()] = value; + /** + * @brief Append value to array at the end. + * + * Equivalent to jsonvalue[jsonvalue.size()] = value; + */ Value& append(Value const& value); Value& append(Value&& value); - /// Access an object value by name, create a null member if it does not - /// exist. + /** + * Access an object value by name, create a null member if it does not + * exist. + */ Value& operator[](char const* key); - /// Access an object value by name, returns null if there is no member with - /// that name. + /** + * Access an object value by name, returns null if there is no member with + * that name. + */ Value const& operator[](char const* key) const; - /// Access an object value by name, create a null member if it does not - /// exist. + /** + * Access an object value by name, create a null member if it does not + * exist. + */ Value& operator[](std::string const& key); - /// Access an object value by name, returns null if there is no member with - /// that name. + /** + * Access an object value by name, returns null if there is no member with + * that name. + */ Value const& operator[](std::string const& key) const; - /** \brief Access an object value by name, create a null member if it does - not exist. - + /** + * @brief Access an object value by name, create a null member if it does + * not exist. + * * If the object as no entry for that name, then the member name used to - store + * store * the new entry is not duplicated. * Example of use: - * \code + * @code * json::Value object; * static const StaticString code("code"); * object[code] = 1234; - * \endcode + * @endcode */ Value& operator[](StaticString const& key); Value const& operator[](StaticString const& key) const; - /// Return the member named key if it exist, defaultValue otherwise. + /** + * Return the member named key if it exist, defaultValue otherwise. + */ Value get(char const* key, Value const& defaultValue) const; - /// Return the member named key if it exist, defaultValue otherwise. + /** + * Return the member named key if it exist, defaultValue otherwise. + */ [[nodiscard]] Value get(std::string const& key, Value const& defaultValue) const; - /// \brief Remove and return the named member. - /// - /// Do nothing if it did not exist. - /// \return the removed Value, or null. - /// \pre type() is ValueType::Object or ValueType::Null - /// \post type() is unchanged + /** + * @brief Remove and return the named member. + * + * Do nothing if it did not exist. + * @return the removed Value, or null. + * @pre type() is ValueType::Object or ValueType::Null + * @post type() is unchanged + */ Value removeMember(char const* key); - /// Same as removeMember(const char*) + /** + * Same as removeMember(const char*) + */ Value removeMember(std::string const& key); - /// Return true if the object has a member named key. + /** + * Return true if the object has a member named key. + */ bool isMember(char const* key) const; - /// Return true if the object has a member named key. + /** + * Return true if the object has a member named key. + */ [[nodiscard]] bool isMember(std::string const& key) const; - /// Return true if the object has a member named key. + /** + * Return true if the object has a member named key. + */ [[nodiscard]] bool isMember(StaticString const& key) const; - /// \brief Return a list of the member names. - /// - /// If null, return an empty list. - /// \pre type() is ValueType::Object or ValueType::Null - /// \post if type() was ValueType::Null, it remains ValueType::Null + /** + * @brief Return a list of the member names. + * + * If null, return an empty list. + * @pre type() is ValueType::Object or ValueType::Null + * @post if type() was ValueType::Null, it remains ValueType::Null + */ [[nodiscard]] Members getMemberNames() const; @@ -461,7 +516,8 @@ operator>=(Value const& x, Value const& y) return !(x < y); } -/** \brief Experimental do not use: Allocator to customize member name and +/** + * @brief Experimental do not use: Allocator to customize member name and * string value memory management done by Value. * * - makeMemberName() and releaseMemberName() are called to respectively @@ -486,8 +542,8 @@ public: releaseStringValue(char* value) = 0; }; -/** \brief base class for Value iterators. - * +/** + * @brief base class for Value iterators. */ class ValueIteratorBase { @@ -512,17 +568,23 @@ public: return !isEqual(other); } - /// Return either the index or the member name of the referenced value as a - /// Value. + /** + * Return either the index or the member name of the referenced value as a + * Value. + */ [[nodiscard]] Value key() const; - /// Return the index of the referenced Value. -1 if it is not an ValueType::Array. + /** + * Return the index of the referenced Value. -1 if it is not an ValueType::Array. + */ [[nodiscard]] UInt index() const; - /// Return the member name of the referenced Value. "" if it is not an - /// ValueType::Object. + /** + * Return the member name of the referenced Value. "" if it is not an + * ValueType::Object. + */ [[nodiscard]] char const* memberName() const; @@ -551,8 +613,8 @@ private: bool isNull_; }; -/** \brief const iterator for object and array value. - * +/** + * @brief const iterator for object and array value. */ class ValueConstIterator : public ValueIteratorBase { @@ -569,7 +631,8 @@ public: ValueConstIterator(ValueConstIterator const& other) = default; private: - /*! \internal Use by Value to create an iterator. + /** + * @internal Use by Value to create an iterator. */ explicit ValueConstIterator(Value::ObjectValues::iterator const& current); @@ -614,7 +677,8 @@ public: } }; -/** \brief Iterator for object and array value. +/** + * @brief Iterator for object and array value. */ class ValueIterator : public ValueIteratorBase { @@ -632,7 +696,8 @@ public: ValueIterator(ValueIterator const& other); private: - /*! \internal Use by Value to create an iterator. + /** + * @internal Use by Value to create an iterator. */ explicit ValueIterator(Value::ObjectValues::iterator const& current); diff --git a/include/xrpl/json/json_writer.h b/include/xrpl/json/json_writer.h index afc99fe8c9..65c8b20931 100644 --- a/include/xrpl/json/json_writer.h +++ b/include/xrpl/json/json_writer.h @@ -3,14 +3,18 @@ #include #include +#include #include +#include +#include #include namespace json { class Value; -/** \brief Abstract class for writers. +/** + * @brief Abstract class for writers. */ class WriterBase { @@ -20,12 +24,13 @@ public: write(Value const& root) = 0; }; -/** \brief Outputs a Value in JSON format +/** + * @brief Outputs a Value in JSON format * without formatting (not human friendly). * * The JSON document is written in a single line. It is not intended for 'human' * consumption, but may be useful to support feature such as RPC where bandwidth - * is limited. \sa Reader, Value + * is limited. @see Reader, Value */ class FastWriter : public WriterBase @@ -45,7 +50,8 @@ private: std::string document_; }; -/** \brief Writes a Value in JSON format in a +/** + * @brief Writes a Value in JSON format in a * human friendly way. * * The rules for line break and indent are as follow: @@ -61,7 +67,7 @@ private: * - otherwise, it the values do not fit on one line, or the array contains * object or non empty array, then print one value per line. * - * \sa Reader, Value + * @see Reader, Value */ class StyledWriter : public WriterBase { @@ -70,8 +76,9 @@ public: ~StyledWriter() override = default; public: // overridden from Writer - /** \brief Serialize a Value in JSON - * format. \param root Value to serialize. \return String containing the + /** + * @brief Serialize a Value in JSON + * format. @param root Value to serialize. @return String containing the * JSON document that represents the root value. */ std::string @@ -105,26 +112,27 @@ private: bool addChildValues_{}; }; -/** \brief Writes a Value in JSON format in a - human friendly way, to a stream rather than to a string. +/** + * @brief Writes a Value in JSON format in a + * human friendly way, to a stream rather than to a string. * * The rules for line break and indent are as follow: * - Object value: * - if empty then print {} without indent and line break * - if not empty the print '{', line break & indent, print one value per - line + * line * and then unindent and line break and print '}'. * - Array value: * - if empty then print [] without indent and line break * - if the array contains no object value, empty array or some other value - types, + * types, * and all the values fit on one lines, then print the array on a single - line. + * line. * - otherwise, it the values do not fit on one line, or the array contains * object or non empty array, then print one value per line. * - * \param indentation Each level will be indented by this amount extra. - * \sa Reader, Value + * @param indentation Each level will be indented by this amount extra. + * @see Reader, Value */ class StyledStreamWriter { @@ -133,10 +141,11 @@ public: ~StyledStreamWriter() = default; public: - /** \brief Serialize a Value in JSON - * format. \param out Stream to write to. (Can be ostringstream, e.g.) - * \param root Value to serialize. - * \note There is no point in deriving from Writer, since write() should not + /** + * @brief Serialize a Value in JSON + * format. @param out Stream to write to. (Can be ostringstream, e.g.) + * @param root Value to serialize. + * @note There is no point in deriving from Writer, since write() should not * return a value. */ void @@ -181,8 +190,10 @@ valueToString(bool value); std::string valueToQuotedString(char const* value); -/// \brief Output using the StyledStreamWriter. -/// \see json::operator>>() +/** + * @brief Output using the StyledStreamWriter. + * @see json::operator>>() + */ std::ostream& operator<<(std::ostream&, Value const& root); @@ -262,12 +273,13 @@ writeValue(Write const& write, Value const& value) } // namespace detail -/** Stream compact JSON to the specified function. - - @param jv The json::Value to write - @param write Invocable with signature void(void const*, std::size_t) that - is called when output should be written to the stream. -*/ +/** + * Stream compact JSON to the specified function. + * + * @param jv The json::Value to write + * @param write Invocable with signature void(void const*, std::size_t) that + * is called when output should be written to the stream. + */ template void stream(json::Value const& jv, Write const& write) @@ -276,29 +288,31 @@ stream(json::Value const& jv, Write const& write) write("\n", 1); } -/** Decorator for streaming out compact json - - Use - - json::Value jv; - out << json::Compact{jv} - - to write a single-line, compact version of `jv` to the stream, rather - than the styled format that comes from undecorated streaming. -*/ +/** + * Decorator for streaming out compact json + * + * Use + * + * json::Value jv; + * out << json::Compact{jv} + * + * to write a single-line, compact version of `jv` to the stream, rather + * than the styled format that comes from undecorated streaming. + */ class Compact { json::Value jv_; public: - /** Wrap a json::Value for compact streaming - - @param jv The json::Value to stream - - @note For now, we do not support wrapping lvalues to avoid - potentially costly copies. If we find a need, we can consider - adding support for compact lvalue streaming in the future. - */ + /** + * Wrap a json::Value for compact streaming + * + * @param jv The json::Value to stream + * + * @note For now, we do not support wrapping lvalues to avoid + * potentially costly copies. If we find a need, we can consider + * adding support for compact lvalue streaming in the future. + */ Compact(json::Value&& jv) : jv_{std::move(jv)} { } diff --git a/include/xrpl/json/to_string.h b/include/xrpl/json/to_string.h index 1d7b4c785a..bdd7a51e6a 100644 --- a/include/xrpl/json/to_string.h +++ b/include/xrpl/json/to_string.h @@ -6,11 +6,15 @@ namespace json { -/** Writes a json::Value to an std::string. */ +/** + * Writes a json::Value to an std::string. + */ std::string to_string(Value const&); -/** Writes a json::Value to an std::string. */ +/** + * Writes a json::Value to an std::string. + */ std::string pretty(Value const&); diff --git a/include/xrpl/ledger/AcceptedLedgerTx.h b/include/xrpl/ledger/AcceptedLedgerTx.h index 0a1592f6e1..283dcf6e24 100644 --- a/include/xrpl/ledger/AcceptedLedgerTx.h +++ b/include/xrpl/ledger/AcceptedLedgerTx.h @@ -1,27 +1,37 @@ #pragma once +#include #include +#include #include #include +#include +#include #include +#include +#include #include #include +#include +#include +#include + namespace xrpl { /** - A transaction that is in a closed ledger. - - Description - - An accepted ledger transaction contains additional information that the - server needs to tell clients about the transaction. For example, - - The transaction in JSON form - - Which accounts are affected - * This is used by InfoSub to report to clients - - Cached stuff -*/ + * A transaction that is in a closed ledger. + * + * Description + * + * An accepted ledger transaction contains additional information that the + * server needs to tell clients about the transaction. For example, + * - The transaction in JSON form + * - Which accounts are affected + * * This is used by InfoSub to report to clients + * - Cached stuff + */ class AcceptedLedgerTx : public CountedObject { public: diff --git a/include/xrpl/ledger/AmendmentTable.h b/include/xrpl/ledger/AmendmentTable.h index 8ed3cb81ff..c3ef779eb1 100644 --- a/include/xrpl/ledger/AmendmentTable.h +++ b/include/xrpl/ledger/AmendmentTable.h @@ -1,23 +1,47 @@ #pragma once +#include +#include +#include +#include +#include +#include +#include #include #include +#include #include #include +#include +#include +#include +#include #include +#include +#include #include +#include +#include +#include +#include +#include +#include #include +#include +#include #include +#include namespace xrpl { class ServiceRegistry; -/** The amendment table stores the list of enabled and potential amendments. - Individuals amendments are voted on by validators during the consensus - process. -*/ +/** + * The amendment table stores the list of enabled and potential amendments. + * Individuals amendments are voted on by validators during the consensus + * process. + */ class AmendmentTable { public: @@ -67,11 +91,15 @@ public: [[nodiscard]] virtual json::Value getJson(bool isAdmin) const = 0; - /** Returns a json::ValueType::Object. */ + /** + * Returns a json::ValueType::Object. + */ [[nodiscard]] virtual json::Value getJson(uint256 const& amendment, bool isAdmin) const = 0; - /** Called when a new fully-validated ledger is accepted. */ + /** + * Called when a new fully-validated ledger is accepted. + */ void doValidatedLedger(std::shared_ptr const& lastValidatedLedger) { @@ -84,9 +112,10 @@ public: } } - /** Called to determine whether the amendment logic needs to process - a new validated ledger. (If it could have changed things.) - */ + /** + * Called to determine whether the amendment logic needs to process + * a new validated ledger. (If it could have changed things.) + */ [[nodiscard]] virtual bool needValidatedLedger(LedgerIndex seq) const = 0; diff --git a/include/xrpl/ledger/ApplyView.h b/include/xrpl/ledger/ApplyView.h index 362eae0f79..724d89b7c6 100644 --- a/include/xrpl/ledger/ApplyView.h +++ b/include/xrpl/ledger/ApplyView.h @@ -1,9 +1,24 @@ #pragma once +#include #include #include -#include +#include #include +#include +#include // IWYU pragma: keep +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include namespace xrpl { @@ -77,47 +92,50 @@ operator&=(ApplyFlags& lhs, ApplyFlags const& rhs) //------------------------------------------------------------------------------ -/** Writeable view to a ledger, for applying a transaction. - - This refinement of ReadView provides an interface where - the SLE can be "checked out" for modifications and put - back in an updated or removed state. Also added is an - interface to provide contextual information necessary - to calculate the results of transaction processing, - including the metadata if the view is later applied to - the parent (using an interface in the derived class). - The context info also includes values from the base - ledger such as sequence number and the network time. - - This allows implementations to journal changes made to - the state items in a ledger, with the option to apply - those changes to the base or discard the changes without - affecting the base. - - Typical usage is to call read() for non-mutating - operations. - - For mutating operations the sequence is as follows: - - // Add a new value - v.insert(sle); - - // Check out a value for modification - sle = v.peek(k); - - // Indicate that changes were made - v.update(sle) - - // Or, erase the value - v.erase(sle) - - The invariant is that insert, update, and erase may not - be called with any SLE which belongs to different view. -*/ +/** + * Writeable view to a ledger, for applying a transaction. + * + * This refinement of ReadView provides an interface where + * the SLE can be "checked out" for modifications and put + * back in an updated or removed state. Also added is an + * interface to provide contextual information necessary + * to calculate the results of transaction processing, + * including the metadata if the view is later applied to + * the parent (using an interface in the derived class). + * The context info also includes values from the base + * ledger such as sequence number and the network time. + * + * This allows implementations to journal changes made to + * the state items in a ledger, with the option to apply + * those changes to the base or discard the changes without + * affecting the base. + * + * Typical usage is to call read() for non-mutating + * operations. + * + * For mutating operations the sequence is as follows: + * + * // Add a new value + * v.insert(sle); + * + * // Check out a value for modification + * sle = v.peek(k); + * + * // Indicate that changes were made + * v.update(sle) + * + * // Or, erase the value + * v.erase(sle) + * + * The invariant is that insert, update, and erase may not + * be called with any SLE which belongs to different view. + */ class ApplyView : public ReadView { private: - /** Add an entry to a directory using the specified insert strategy */ + /** + * Add an entry to a directory using the specified insert strategy + */ std::optional dirAdd( bool preserveOrder, @@ -128,84 +146,89 @@ private: public: ApplyView() = default; - /** Returns the tx apply flags. - - Flags can affect the outcome of transaction - processing. For example, transactions applied - to an open ledger generate "local" failures, - while transactions applied to the consensus - ledger produce hard failures (and claim a fee). - */ + /** + * Returns the tx apply flags. + * + * Flags can affect the outcome of transaction + * processing. For example, transactions applied + * to an open ledger generate "local" failures, + * while transactions applied to the consensus + * ledger produce hard failures (and claim a fee). + */ [[nodiscard]] virtual ApplyFlags flags() const = 0; - /** Prepare to modify the SLE associated with key. - - Effects: - - Gives the caller ownership of a modifiable - SLE associated with the specified key. - - The returned SLE may be used in a subsequent - call to erase or update. - - The SLE must not be passed to any other ApplyView. - - @return `nullptr` if the key is not present - */ + /** + * Prepare to modify the SLE associated with key. + * + * Effects: + * + * Gives the caller ownership of a modifiable + * SLE associated with the specified key. + * + * The returned SLE may be used in a subsequent + * call to erase or update. + * + * The SLE must not be passed to any other ApplyView. + * + * @return `nullptr` if the key is not present + */ virtual SLE::pointer peek(Keylet const& k) = 0; - /** Remove a peeked SLE. - - Requirements: - - `sle` was obtained from prior call to peek() - on this instance of the RawView. - - Effects: - - The key is no longer associated with the SLE. - */ + /** + * Remove a peeked SLE. + * + * Requirements: + * + * `sle` was obtained from prior call to peek() + * on this instance of the RawView. + * + * Effects: + * + * The key is no longer associated with the SLE. + */ virtual void erase(SLE::ref sle) = 0; - /** Insert a new state SLE - - Requirements: - - `sle` was not obtained from any calls to - peek() on any instances of RawView. - - The SLE's key must not already exist. - - Effects: - - The key in the state map is associated - with the SLE. - - The RawView acquires ownership of the shared_ptr. - - @note The key is taken from the SLE - */ + /** + * Insert a new state SLE + * + * Requirements: + * + * `sle` was not obtained from any calls to + * peek() on any instances of RawView. + * + * The SLE's key must not already exist. + * + * Effects: + * + * The key in the state map is associated + * with the SLE. + * + * The RawView acquires ownership of the shared_ptr. + * + * @note The key is taken from the SLE + */ virtual void insert(SLE::ref sle) = 0; - /** Indicate changes to a peeked SLE - - Requirements: - - The SLE's key must exist. - - `sle` was obtained from prior call to peek() - on this instance of the RawView. - - Effects: - - The SLE is updated - - @note The key is taken from the SLE - */ + /** + * Indicate changes to a peeked SLE + * + * Requirements: + * + * The SLE's key must exist. + * + * `sle` was obtained from prior call to peek() + * on this instance of the RawView. + * + * Effects: + * + * The SLE is updated + * + * @note The key is taken from the SLE + */ /** @{ */ virtual void update(SLE::ref sle) = 0; @@ -235,7 +258,8 @@ public: XRPL_ASSERT(amount.holds(), "creditHookMPT: amount is for MPTIssue"); } - /** Facilitate tracking of MPT sold by an issuer owning MPT sell offer. + /** + * Facilitate tracking of MPT sold by an issuer owning MPT sell offer. * Unlike IOU, MPT doesn't have bi-directional relationship with an issuer, * where a trustline limits an amount that can be issued to a holder. * Consequently, the credit step (last MPTEndpointStep or @@ -275,27 +299,28 @@ public: // Called when the owner count changes // This is required to support PaymentSandbox virtual void - adjustOwnerCountHook(AccountID const& account, std::uint32_t cur, std::uint32_t next) + adjustOwnerCountHook(AccountID const& account, OwnerCounts const& cur, OwnerCounts const& next) { } - /** Append an entry to a directory - - Entries in the directory will be stored in order of insertion, i.e. new - entries will always be added at the tail end of the last page. - - @param directory the base of the directory - @param key the entry to insert - @param describe callback to add required entries to a new page - - @return a \c std::optional which, if insertion was successful, - will contain the page number in which the item was stored. - - @note this function may create a page (including a root page), if no - page with space is available. This function will only fail if the - page counter exceeds the protocol-defined maximum number of - allowable pages. - */ + /** + * Append an entry to a directory + * + * Entries in the directory will be stored in order of insertion, i.e. new + * entries will always be added at the tail end of the last page. + * + * @param directory the base of the directory + * @param key the entry to insert + * @param describe callback to add required entries to a new page + * + * @return a @c std::optional which, if insertion was successful, + * will contain the page number in which the item was stored. + * + * @note this function may create a page (including a root page), if no + * page with space is available. This function will only fail if the + * page counter exceeds the protocol-defined maximum number of + * allowable pages. + */ /** @{ */ std::optional dirAppend( @@ -318,23 +343,24 @@ public: } /** @} */ - /** Insert an entry to a directory - - Entries in the directory will be stored in a semi-random order, but - each page will be maintained in sorted order. - - @param directory the base of the directory - @param key the entry to insert - @param describe callback to add required entries to a new page - - @return a \c std::optional which, if insertion was successful, - will contain the page number in which the item was stored. - - @note this function may create a page (including a root page), if no - page with space is available.this function will only fail if the - page counter exceeds the protocol-defined maximum number of - allowable pages. - */ + /** + * Insert an entry to a directory + * + * Entries in the directory will be stored in a semi-random order, but + * each page will be maintained in sorted order. + * + * @param directory the base of the directory + * @param key the entry to insert + * @param describe callback to add required entries to a new page + * + * @return a @c std::optional which, if insertion was successful, + * will contain the page number in which the item was stored. + * + * @note this function may create a page (including a root page), if no + * page with space is available.this function will only fail if the + * page counter exceeds the protocol-defined maximum number of + * allowable pages. + */ /** @{ */ std::optional dirInsert( @@ -355,21 +381,22 @@ public: } /** @} */ - /** Remove an entry from a directory - - @param directory the base of the directory - @param page the page number for this page - @param key the entry to remove - @param keepRoot if deleting the last entry, don't - delete the root page (i.e. the directory itself). - - @return \c true if the entry was found and deleted and - \c false otherwise. - - @note This function will remove zero or more pages from the directory; - the root page will not be deleted even if it is empty, unless - \p keepRoot is not set and the directory is empty. - */ + /** + * Remove an entry from a directory + * + * @param directory the base of the directory + * @param page the page number for this page + * @param key the entry to remove + * @param keepRoot if deleting the last entry, don't + * delete the root page (i.e. the directory itself). + * + * @return @c true if the entry was found and deleted and + * @c false otherwise. + * + * @note This function will remove zero or more pages from the directory; + * the root page will not be deleted even if it is empty, unless + * \p keepRoot is not set and the directory is empty. + */ /** @{ */ bool dirRemove(Keylet const& directory, std::uint64_t page, uint256 const& key, bool keepRoot); @@ -381,29 +408,51 @@ public: } /** @} */ - /** Remove the specified directory, invoking the callback for every node. */ + /** + * Remove the specified directory, invoking the callback for every node. + */ bool dirDelete(Keylet const& directory, std::function const&); - /** Remove the specified directory, if it is empty. - - @param directory the identifier of the directory node to be deleted - @return \c true if the directory was found and was successfully deleted - \c false otherwise. - - @note The function should only be called with the root entry (i.e. with - the first page) of a directory. - */ + /** + * Remove the specified directory, if it is empty. + * + * @param directory the identifier of the directory node to be deleted + * @return @c true if the directory was found and was successfully deleted + * @c false otherwise. + * + * @note The function should only be called with the root entry (i.e. with + * the first page) of a directory. + */ bool emptyDirDelete(Keylet const& directory); }; -namespace directory { -/** Helper functions for managing low-level directory operations. - These are not part of the ApplyView interface. +/** + * Bundles the mutable ledger view and the transaction being applied. + * + * Passed together to avoid threading two separate parameters through every + * helper that needs both the view (for state reads/writes) and the + * transaction (for field inspection and metadata). + * + * Both members are non-owning references; the caller is responsible for + * ensuring that the referenced objects outlive the ApplyViewContext. + * + * TODO: replace with ApplyContext after it's untangled with xrpl/tx + */ +struct ApplyViewContext +{ + ApplyView& view; + STTx const& tx; +}; - Don't use them unless you really, really know what you're doing. - Instead use dirAdd, dirInsert, etc. +namespace directory { +/** + * Helper functions for managing low-level directory operations. + * These are not part of the ApplyView interface. + * + * Don't use them unless you really, really know what you're doing. + * Instead use dirAdd, dirInsert, etc. */ std::uint64_t diff --git a/include/xrpl/ledger/ApplyViewImpl.h b/include/xrpl/ledger/ApplyViewImpl.h index 1245568630..630153f90a 100644 --- a/include/xrpl/ledger/ApplyViewImpl.h +++ b/include/xrpl/ledger/ApplyViewImpl.h @@ -1,18 +1,30 @@ #pragma once +#include +#include +#include #include +#include #include #include +#include +#include #include +#include + +#include +#include +#include namespace xrpl { -/** Editable, discardable view that can build metadata for one tx. - - Iteration of the tx map is delegated to the base. - - @note Presented as ApplyView to clients. -*/ +/** + * Editable, discardable view that can build metadata for one tx. + * + * Iteration of the tx map is delegated to the base. + * + * @note Presented as ApplyView to clients. + */ class ApplyViewImpl final : public detail::ApplyViewBase { public: @@ -26,12 +38,13 @@ public: ApplyViewImpl(ApplyViewImpl&&) = default; ApplyViewImpl(ReadView const* base, ApplyFlags flags); - /** Apply the transaction. - - After a call to `apply`, the only valid - operation on this object is to call the - destructor. - */ + /** + * Apply the transaction. + * + * After a call to `apply`, the only valid + * operation on this object is to call the + * destructor. + */ std::optional apply( OpenView& to, @@ -41,25 +54,28 @@ public: bool isDryRun, beast::Journal j); - /** Set the amount of currency delivered. - - This value is used when generating metadata - for payments, to set the DeliveredAmount field. - If the amount is not specified, the field is - excluded from the resulting metadata. - */ + /** + * Set the amount of currency delivered. + * + * This value is used when generating metadata + * for payments, to set the DeliveredAmount field. + * If the amount is not specified, the field is + * excluded from the resulting metadata. + */ void deliver(STAmount const& amount) { deliver_ = amount; } - /** Get the number of modified entries + /** + * Get the number of modified entries */ std::size_t size(); - /** Visit modified entries + /** + * Visit modified entries */ void visit( diff --git a/include/xrpl/ledger/BookDirs.h b/include/xrpl/ledger/BookDirs.h index 36798934da..dc4361136d 100644 --- a/include/xrpl/ledger/BookDirs.h +++ b/include/xrpl/ledger/BookDirs.h @@ -1,6 +1,13 @@ #pragma once +#include #include +#include +#include + +#include +#include +#include namespace xrpl { diff --git a/include/xrpl/ledger/CachedView.h b/include/xrpl/ledger/CachedView.h index 462db48ee3..b9e2cf8d66 100644 --- a/include/xrpl/ledger/CachedView.h +++ b/include/xrpl/ledger/CachedView.h @@ -1,11 +1,20 @@ #pragma once +#include #include #include #include +#include +#include +#include +#include +#include +#include #include +#include #include +#include namespace xrpl { @@ -124,15 +133,16 @@ public: } // namespace detail -/** Wraps a DigestAwareReadView to provide caching. - - @tparam Base A subclass of DigestAwareReadView -*/ +/** + * Wraps a DigestAwareReadView to provide caching. + * + * @tparam Base A subclass of DigestAwareReadView + */ template class CachedView : public detail::CachedViewImpl { private: - static_assert(std::is_base_of_v, ""); + static_assert(std::is_base_of_v); std::shared_ptr sp_; @@ -149,10 +159,11 @@ public: { } - /** Returns the base type. - - @note This breaks encapsulation and bypasses the cache. - */ + /** + * Returns the base type. + * + * @note This breaks encapsulation and bypasses the cache. + */ std::shared_ptr const& base() const { diff --git a/include/xrpl/ledger/CanonicalTXSet.h b/include/xrpl/ledger/CanonicalTXSet.h index 4dffadd52f..11aadf4e92 100644 --- a/include/xrpl/ledger/CanonicalTXSet.h +++ b/include/xrpl/ledger/CanonicalTXSet.h @@ -1,19 +1,25 @@ #pragma once #include +#include +#include #include #include #include +#include +#include +#include + namespace xrpl { -/** Holds transactions which were deferred to the next pass of consensus. - - "Canonical" refers to the order in which transactions are applied. - - - Puts transactions from the same account in SeqProxy order - -*/ +/** + * Holds transactions which were deferred to the next pass of consensus. + * + * "Canonical" refers to the order in which transactions are applied. + * + * - Puts transactions from the same account in SeqProxy order + */ // VFALCO TODO rename to SortedTxSet class CanonicalTXSet : public CountedObject { diff --git a/include/xrpl/ledger/Dir.h b/include/xrpl/ledger/Dir.h index d305e21938..233719cdeb 100644 --- a/include/xrpl/ledger/Dir.h +++ b/include/xrpl/ledger/Dir.h @@ -1,22 +1,31 @@ #pragma once +#include #include -#include +#include +#include +#include + +#include +#include +#include +#include namespace xrpl { -/** A class that simplifies iterating ledger directory pages - - The Dir class provides a forward iterator for walking through - the uint256 values contained in ledger directories. - - The Dir class also allows accelerated directory walking by - stepping directly from one page to the next using the next_page() - member function. - - As of July 2024, the Dir class is only being used with NFTokenOffer - directories and for unit tests. -*/ +/** + * A class that simplifies iterating ledger directory pages + * + * The Dir class provides a forward iterator for walking through + * the uint256 values contained in ledger directories. + * + * The Dir class also allows accelerated directory walking by + * stepping directly from one page to the next using the next_page() + * member function. + * + * As of July 2024, the Dir class is only being used with NFTokenOffer + * directories and for unit tests. + */ class Dir { private: diff --git a/include/xrpl/ledger/Ledger.h b/include/xrpl/ledger/Ledger.h index 5f7d79c61d..e1dd2c422e 100644 --- a/include/xrpl/ledger/Ledger.h +++ b/include/xrpl/ledger/Ledger.h @@ -1,16 +1,32 @@ #pragma once #include +#include +#include +#include #include #include -#include +#include #include -#include +#include +#include +#include #include #include +#include +#include #include -#include +#include +#include #include +#include + +#include +#include +#include +#include +#include +#include namespace xrpl { @@ -26,32 +42,33 @@ struct CreateGenesisT }; extern CreateGenesisT const kCreateGenesis; -/** Holds a ledger. - - The ledger is composed of two SHAMaps. The state map holds all of the - ledger entries such as account roots and order books. The tx map holds - all of the transactions and associated metadata that made it into that - particular ledger. Most of the operations on a ledger are concerned - with the state map. - - This can hold just the header, a partial set of data, or the entire set - of data. It all depends on what is in the corresponding SHAMap entry. - Various functions are provided to populate or depopulate the caches that - the object holds references to. - - Ledgers are constructed as either mutable or immutable. - - 1) If you are the sole owner of a mutable ledger, you can do whatever you - want with no need for locks. - - 2) If you have an immutable ledger, you cannot ever change it, so no need - for locks. - - 3) Mutable ledgers cannot be shared. - - @note Presented to clients as ReadView - @note Calls virtuals in the constructor, so marked as final -*/ +/** + * Holds a ledger. + * + * The ledger is composed of two SHAMaps. The state map holds all of the + * ledger entries such as account roots and order books. The tx map holds + * all of the transactions and associated metadata that made it into that + * particular ledger. Most of the operations on a ledger are concerned + * with the state map. + * + * This can hold just the header, a partial set of data, or the entire set + * of data. It all depends on what is in the corresponding SHAMap entry. + * Various functions are provided to populate or depopulate the caches that + * the object holds references to. + * + * Ledgers are constructed as either mutable or immutable. + * + * 1) If you are the sole owner of a mutable ledger, you can do whatever you + * want with no need for locks. + * + * 2) If you have an immutable ledger, you cannot ever change it, so no need + * for locks. + * + * 3) Mutable ledgers cannot be shared. + * + * @note Presented to clients as ReadView + * @note Calls virtuals in the constructor, so marked as final + */ class Ledger final : public std::enable_shared_from_this, public DigestAwareReadView, public TxsRawView, @@ -66,20 +83,21 @@ public: Ledger& operator=(Ledger&&) = delete; - /** Create the Genesis ledger. - - The Genesis ledger contains a single account whose - AccountID is generated with a Generator using the seed - computed from the string "masterpassphrase" and ordinal - zero. - - The account has an XRP balance equal to the total amount - of XRP in the system. No more XRP than the amount which - starts in this account can ever exist, with amounts - used to pay fees being destroyed. - - Amendments specified are enabled in the genesis ledger - */ + /** + * Create the Genesis ledger. + * + * The Genesis ledger contains a single account whose + * AccountID is generated with a Generator using the seed + * computed from the string "masterpassphrase" and ordinal + * zero. + * + * The account has an XRP balance equal to the total amount + * of XRP in the system. No more XRP than the amount which + * starts in this account can ever exist, with amounts + * used to pay fees being destroyed. + * + * Amendments specified are enabled in the genesis ledger + */ Ledger( CreateGenesisT, Rules rules, @@ -89,13 +107,14 @@ public: Ledger(LedgerHeader const& info, Rules rules, Family& family); - /** Used for ledgers loaded from JSON files - - @param acquire If true, acquires the ledger if not found locally - - @note The fees parameter provides default values, but setup() may - override them from the ledger state if fee-related SLEs exist. - */ + /** + * Used for ledgers loaded from JSON files + * + * @param acquire If true, acquires the ledger if not found locally + * + * @note The fees parameter provides default values, but setup() may + * override them from the ledger state if fee-related SLEs exist. + */ Ledger( LedgerHeader const& info, bool& loaded, @@ -105,12 +124,13 @@ public: Family& family, beast::Journal j); - /** Create a new ledger following a previous ledger - - The ledger will have the sequence number that - follows previous, and have - parentCloseTime == previous.closeTime. - */ + /** + * Create a new ledger following a previous ledger + * + * The ledger will have the sequence number that + * follows previous, and have + * parentCloseTime == previous.closeTime. + */ Ledger(Ledger const& previous, NetClock::time_point closeTime); // used for database ledgers @@ -353,11 +373,15 @@ public: void updateNegativeUNL(); - /** Returns true if the ledger is a flag ledger */ + /** + * Returns true if the ledger is a flag ledger + */ bool isFlagLedger() const; - /** Returns true if the ledger directly precedes a flag ledger */ + /** + * Returns true if the ledger directly precedes a flag ledger + */ bool isVotingLedger() const; @@ -371,23 +395,25 @@ private: bool setup(); - /** @brief Deserialize a SHAMapItem containing a single STTx. + /** + * @brief Deserialize a SHAMapItem containing a single STTx. * * @param item The SHAMapItem to deserialize. * @return A shared pointer to the deserialized transaction. - * @throw May throw on deserialization error. + * @throws May throw on deserialization error. */ static std::shared_ptr deserializeTx(SHAMapItem const& item); - /** @brief Deserialize a SHAMapItem containing STTx + STObject metadata. + /** + * @brief Deserialize a SHAMapItem containing STTx + STObject metadata. * * The SHAMapItem must contain two variable length serialization objects. * * @param item The SHAMapItem to deserialize. * @return A pair containing shared pointers to the deserialized transaction * and metadata. - * @throw May throw on deserialization error. + * @throws May throw on deserialization error. */ static std::pair, std::shared_ptr> deserializeTxPlusMeta(SHAMapItem const& item); @@ -409,7 +435,9 @@ private: beast::Journal j_; }; -/** A ledger wrapped in a CachedView. */ +/** + * A ledger wrapped in a CachedView. + */ using CachedLedger = CachedView; } // namespace xrpl diff --git a/include/xrpl/ledger/LedgerTiming.h b/include/xrpl/ledger/LedgerTiming.h index 508403d760..77254a434b 100644 --- a/include/xrpl/ledger/LedgerTiming.h +++ b/include/xrpl/ledger/LedgerTiming.h @@ -1,17 +1,19 @@ #pragma once -#include -#include +#include +#include #include +#include namespace xrpl { -/** Possible ledger close time resolutions. - - Values should not be duplicated. - @see getNextLedgerTimeResolution -*/ +/** + * Possible ledger close time resolutions. + * + * Values should not be duplicated. + * @see getNextLedgerTimeResolution + */ constexpr std::chrono::seconds kLedgerPossibleTimeResolutions[] = { std::chrono::seconds{10}, std::chrono::seconds{20}, @@ -20,41 +22,50 @@ constexpr std::chrono::seconds kLedgerPossibleTimeResolutions[] = { std::chrono::seconds{90}, std::chrono::seconds{120}}; -//! Initial resolution of ledger close time. +/** + * Initial resolution of ledger close time. + */ constexpr auto kLedgerDefaultTimeResolution = kLedgerPossibleTimeResolutions[2]; -//! Close time resolution in genesis ledger +/** + * Close time resolution in genesis ledger + */ constexpr auto kLedgerGenesisTimeResolution = kLedgerPossibleTimeResolutions[0]; -//! How often we increase the close time resolution (in numbers of ledgers) +/** + * How often we increase the close time resolution (in numbers of ledgers) + */ constexpr auto kIncreaseLedgerTimeResolutionEvery = 8; -//! How often we decrease the close time resolution (in numbers of ledgers) +/** + * How often we decrease the close time resolution (in numbers of ledgers) + */ constexpr auto kDecreaseLedgerTimeResolutionEvery = 1; -/** Calculates the close time resolution for the specified ledger. - - The XRPL protocol uses binning to represent time intervals using only one - timestamp. This allows servers to derive a common time for the next ledger, - without the need for perfectly synchronized clocks. - The time resolution (i.e. the size of the intervals) is adjusted dynamically - based on what happened in the last ledger, to try to avoid disagreements. - - @param previousResolution the resolution used for the prior ledger - @param previousAgree whether consensus agreed on the close time of the prior - ledger - @param ledgerSeq the sequence number of the new ledger - - @pre previousResolution must be a valid bin - from @ref kLedgerPossibleTimeResolutions - - @tparam Rep Type representing number of ticks in std::chrono::duration - @tparam Period An std::ratio representing tick period in - std::chrono::duration - @tparam Seq Unsigned integer-like type corresponding to the ledger sequence - number. It should be comparable to 0 and support modular - division. Built-in and tagged_integers are supported. -*/ +/** + * Calculates the close time resolution for the specified ledger. + * + * The XRPL protocol uses binning to represent time intervals using only one + * timestamp. This allows servers to derive a common time for the next ledger, + * without the need for perfectly synchronized clocks. + * The time resolution (i.e. the size of the intervals) is adjusted dynamically + * based on what happened in the last ledger, to try to avoid disagreements. + * + * @tparam Rep Type representing number of ticks in std::chrono::duration + * @tparam Period An std::ratio representing tick period in + * std::chrono::duration + * @tparam Seq Unsigned integer-like type corresponding to the ledger sequence + * number. It should be comparable to 0 and support modular + * division. Built-in and tagged_integers are supported. + * + * @param previousResolution the resolution used for the prior ledger + * @param previousAgree whether consensus agreed on the close time of the prior + * ledger + * @param ledgerSeq the sequence number of the new ledger + * + * @pre previousResolution must be a valid bin + * from @ref kLedgerPossibleTimeResolutions + */ template std::chrono::duration getNextLedgerTimeResolution( @@ -97,13 +108,14 @@ getNextLedgerTimeResolution( return previousResolution; } -/** Calculates the close time for a ledger, given a close time resolution. - - @param closeTime The time to be rounded - @param closeResolution The resolution - @return @b closeTime rounded to the nearest multiple of @b closeResolution. - Rounds up if @b closeTime is midway between multiples of @b closeResolution. -*/ +/** + * Calculates the close time for a ledger, given a close time resolution. + * + * @param closeTime The time to be rounded + * @param closeResolution The resolution + * @return @b closeTime rounded to the nearest multiple of @b closeResolution. + * Rounds up if @b closeTime is midway between multiples of @b closeResolution. + */ template std::chrono::time_point roundCloseTime( @@ -118,15 +130,16 @@ roundCloseTime( return closeTime - (closeTime.time_since_epoch() % closeResolution); } -/** Calculate the effective ledger close time - - After adjusting the ledger close time based on the current resolution, also - ensure it is sufficiently separated from the prior close time. - - @param closeTime The raw ledger close time - @param resolution The current close time resolution - @param priorCloseTime The close time of the prior ledger -*/ +/** + * Calculate the effective ledger close time + * + * After adjusting the ledger close time based on the current resolution, also + * ensure it is sufficiently separated from the prior close time. + * + * @param closeTime The raw ledger close time + * @param resolution The current close time resolution + * @param priorCloseTime The close time of the prior ledger + */ template std::chrono::time_point effCloseTime( diff --git a/include/xrpl/ledger/OpenView.h b/include/xrpl/ledger/OpenView.h index 4ba2a7759b..3f8e950b02 100644 --- a/include/xrpl/ledger/OpenView.h +++ b/include/xrpl/ledger/OpenView.h @@ -1,34 +1,47 @@ #pragma once +#include +#include #include #include #include -#include +#include +#include +#include +#include +#include +#include #include #include #include +#include #include +#include +#include +#include #include namespace xrpl { -/** Open ledger construction tag. - - Views constructed with this tag will have the - rules of open ledgers applied during transaction - processing. +/** + * Open ledger construction tag. + * + * Views constructed with this tag will have the + * rules of open ledgers applied during transaction + * processing. */ inline constexpr struct OpenLedgerT { explicit constexpr OpenLedgerT() = default; } kOpenLedger{}; -/** Batch view construction tag. - - Views constructed with this tag are part of a stack of views - used during batch transaction applied. +/** + * Batch view construction tag. + * + * Views constructed with this tag are part of a stack of views + * used during batch transaction application. */ inline constexpr struct BatchViewT { @@ -37,10 +50,11 @@ inline constexpr struct BatchViewT //------------------------------------------------------------------------------ -/** Writable ledger view that accumulates state and tx changes. - - @note Presented as ReadView to clients. -*/ +/** + * Writable ledger view that accumulates state and tx changes. + * + * @note Presented as ReadView to clients. + */ class OpenView final : public ReadView, public TxsRawView { private: @@ -71,7 +85,7 @@ private: using txs_map = std::map< key_type, TxData, - std::less, + std::less<>, boost::container::pmr::polymorphic_allocator>>; // monotonic_resource_ must outlive `items_`. Make a pointer so it may be @@ -84,7 +98,9 @@ private: detail::RawStateTable items_; std::shared_ptr hold_; - /// In batch mode, the number of transactions already executed. + /** + * In batch mode, the number of transactions already executed. + */ std::size_t baseTxCount_ = 0; bool open_ = true; @@ -98,40 +114,42 @@ public: OpenView(OpenView&&) = default; - /** Construct a shallow copy. - - Effects: - - Creates a new object with a copy of - the modification state table. - - The objects managed by shared pointers are - not duplicated but shared between instances. - Since the SLEs are immutable, calls on the - RawView interface cannot break invariants. - */ + /** + * Construct a shallow copy. + * + * Effects: + * + * Creates a new object with a copy of + * the modification state table. + * + * The objects managed by shared pointers are + * not duplicated but shared between instances. + * Since the SLEs are immutable, calls on the + * RawView interface cannot break invariants. + */ OpenView(OpenView const&); - /** Construct an open ledger view. - - Effects: - - The sequence number is set to the - sequence number of parent plus one. - - The parentCloseTime is set to the - closeTime of parent. - - If `hold` is not nullptr, retains - ownership of a copy of `hold` until - the MetaView is destroyed. - - Calls to rules() will return the - rules provided on construction. - - The tx list starts empty and will contain - all newly inserted tx. - */ + /** + * Construct an open ledger view. + * + * Effects: + * + * The sequence number is set to the + * sequence number of parent plus one. + * + * The parentCloseTime is set to the + * closeTime of parent. + * + * If `hold` is not nullptr, retains + * ownership of a copy of `hold` until + * the MetaView is destroyed. + * + * Calls to rules() will return the + * rules provided on construction. + * + * The tx list starts empty and will contain + * all newly inserted tx. + */ OpenView( OpenLedgerT, ReadView const* base, @@ -148,35 +166,41 @@ public: baseTxCount_ = base.txCount(); } - /** Construct a new last closed ledger. - - Effects: - - The LedgerHeader is copied from the base. - - The rules are inherited from the base. - - The tx list starts empty and will contain - all newly inserted tx. - */ + /** + * Construct a new last closed ledger. + * + * Effects: + * + * The LedgerHeader is copied from the base. + * + * The rules are inherited from the base. + * + * The tx list starts empty and will contain + * all newly inserted tx. + */ OpenView(ReadView const* base, std::shared_ptr hold = nullptr); - /** Returns true if this reflects an open ledger. */ + /** + * Returns true if this reflects an open ledger. + */ bool open() const override { return open_; } - /** Return the number of tx inserted since creation. - - This is used to set the "apply ordinal" - when calculating transaction metadata. - */ + /** + * Return the number of tx inserted since creation. + * + * This is used to set the "apply ordinal" + * when calculating transaction metadata. + */ std::size_t txCount() const; - /** Apply changes. */ + /** + * Apply changes. + */ void apply(TxsRawView& to) const; diff --git a/include/xrpl/ledger/OrderBookDB.h b/include/xrpl/ledger/OrderBookDB.h index a44183900c..96dc94b1f4 100644 --- a/include/xrpl/ledger/OrderBookDB.h +++ b/include/xrpl/ledger/OrderBookDB.h @@ -14,85 +14,92 @@ namespace xrpl { -/** Tracks order books in the ledger. - - This interface provides access to order book information, including: - - Which order books exist in the ledger - - Querying order books by issue - - Managing order book subscriptions - - The order book database is updated as ledgers are accepted and provides - efficient lookup of order book information for pathfinding and client - subscriptions. -*/ +/** + * Tracks order books in the ledger. + * + * This interface provides access to order book information, including: + * - Which order books exist in the ledger + * - Querying order books by issue + * - Managing order book subscriptions + * + * The order book database is updated as ledgers are accepted and provides + * efficient lookup of order book information for pathfinding and client + * subscriptions. + */ class OrderBookDB { public: virtual ~OrderBookDB() = default; - /** Initialize or update the order book database with a new ledger. - - This method should be called when a new ledger is accepted to update - the order book database with the current state of all order books. - - @param ledger The ledger to scan for order books - */ + /** + * Initialize or update the order book database with a new ledger. + * + * This method should be called when a new ledger is accepted to update + * the order book database with the current state of all order books. + * + * @param ledger The ledger to scan for order books + */ virtual void setup(std::shared_ptr const& ledger) = 0; - /** Add an order book to track. - - @param book The order book to add - */ + /** + * Add an order book to track. + * + * @param book The order book to add + */ virtual void addOrderBook(Book const& book) = 0; - /** Get all order books that want a specific issue. - - Returns a list of all order books where the taker pays the specified - issue. This is useful for pathfinding to find all possible next hops - from a given currency. - - @param asset The asset to search for - @param domain Optional domain restriction for the order book - @return Vector of books that want this issue - */ + /** + * Get all order books that want a specific issue. + * + * Returns a list of all order books where the taker pays the specified + * issue. This is useful for pathfinding to find all possible next hops + * from a given currency. + * + * @param asset The asset to search for + * @param domain Optional domain restriction for the order book + * @return Vector of books that want this issue + */ virtual std::vector getBooksByTakerPays(Asset const& asset, std::optional const& domain = std::nullopt) = 0; - /** Get the count of order books that want a specific issue. - - @param asset The asset to search for - @param domain Optional domain restriction for the order book - @return Number of books that want this issue - */ + /** + * Get the count of order books that want a specific issue. + * + * @param asset The asset to search for + * @param domain Optional domain restriction for the order book + * @return Number of books that want this issue + */ virtual int getBookSize(Asset const& asset, std::optional const& domain = std::nullopt) = 0; - /** Check if an order book to XRP exists for the given issue. - - @param asset The asset to check - @param domain Optional domain restriction for the order book - @return true if a book from this issue to XRP exists - */ + /** + * Check if an order book to XRP exists for the given issue. + * + * @param asset The asset to check + * @param domain Optional domain restriction for the order book + * @return true if a book from this issue to XRP exists + */ virtual bool isBookToXRP(Asset const& asset, std::optional const& domain = std::nullopt) = 0; }; -/** Extract the set of books affected by a transaction. +/** + * Extract the set of books affected by a transaction. * - * Walks the transaction's metadata nodes and collects every order book - * whose offers were created, modified, or deleted. Used by NetworkOPs to - * fan transaction notifications out to book subscribers. + * Walks the transaction's metadata nodes and collects every order book + * whose offers were created, modified, or deleted. Used by NetworkOPs to + * fan transaction notifications out to book subscribers. * - * @param alTx The accepted ledger transaction to inspect. - * @param j Journal used to log per-node parsing failures. Inspecting an - * offer node can throw if a required field is missing; in that - * case the bad node is skipped and a warn-level message is - * emitted via @p j. Other affected books in the same transaction - * are still returned. - * @return The set of books whose offers were created, modified, or - * deleted. May be empty for non-offer transactions. + * @param alTx The accepted ledger transaction to inspect. + * @param j Journal used to log per-node parsing failures. Inspecting an + * offer node can throw if a required field is missing; in that + * case the bad node is skipped and a warn-level message is + * emitted via @p j. Other affected books in the same transaction + * are still returned. + * @return The set of books whose offers were created, modified, or + * deleted. May be empty for non-offer transactions. */ hash_set affectedBooks(AcceptedLedgerTx const& alTx, beast::Journal const& j); diff --git a/include/xrpl/ledger/OwnerCounts.h b/include/xrpl/ledger/OwnerCounts.h new file mode 100644 index 0000000000..74d60014b5 --- /dev/null +++ b/include/xrpl/ledger/OwnerCounts.h @@ -0,0 +1,70 @@ +#pragma once + +#include +#include +#include +#include // IWYU pragma: keep +#include + +#include +#include + +namespace xrpl { + +struct OwnerCounts +{ + std::uint32_t owner = 0; + std::uint32_t sponsored = 0; + std::uint32_t sponsoring = 0; + + OwnerCounts() = default; + OwnerCounts(SLE::const_ref sle) + : owner(sle->at(sfOwnerCount)) + , sponsored(sle->at(sfSponsoredOwnerCount)) + , sponsoring(sle->at(sfSponsoringOwnerCount)) + { + XRPL_ASSERT( + owner >= sponsored, + "xrpl::OwnerCounts : OwnerCount must be greater than or equal to " + "SponsoredOwnerCount"); + XRPL_ASSERT(sle->getType() == ltACCOUNT_ROOT, "xrpl::OwnerCounts : sle is AccountRoot"); + } + + [[nodiscard]] std::uint32_t + count() const + { + std::int64_t const x = static_cast(owner) - sponsored + sponsoring; + if (x < 0) + { + // LCOV_EXCL_START + UNREACHABLE("xrpl::OwnerCounts::count : count less than zero"); + return 0; + // LCOV_EXCL_STOP + } + + if (x > std::numeric_limits::max()) + return std::numeric_limits::max(); // LCOV_EXCL_LINE + return static_cast(x); + } + + auto + operator<=>(OwnerCounts const& o) const + { + if (auto cmp = count() <=> o.count(); cmp != 0) // NOLINT(modernize-use-nullptr) + return cmp; + if (auto cmp = owner <=> o.owner; cmp != 0) // NOLINT(modernize-use-nullptr) + return cmp; + if (auto cmp = sponsored <=> o.sponsored; cmp != 0) // NOLINT(modernize-use-nullptr) + return cmp; + return sponsoring <=> o.sponsoring; + } + + bool + operator==(OwnerCounts const& o) const + { + return this == &o || + (owner == o.owner && sponsored == o.sponsored && sponsoring == o.sponsoring); + } +}; + +} // namespace xrpl diff --git a/include/xrpl/ledger/PaymentSandbox.h b/include/xrpl/ledger/PaymentSandbox.h index 1cd89d9388..e725bdd556 100644 --- a/include/xrpl/ledger/PaymentSandbox.h +++ b/include/xrpl/ledger/PaymentSandbox.h @@ -1,11 +1,20 @@ #pragma once +#include +#include #include -#include +#include #include #include +#include +#include +#include +#include +#include #include +#include +#include #include namespace xrpl { @@ -99,12 +108,12 @@ public: issuerSelfDebitMPT(MPTIssue const& issue, std::uint64_t amount, std::int64_t origBalance); void - ownerCount(AccountID const& id, std::uint32_t cur, std::uint32_t next); + ownerCount(AccountID const& id, OwnerCounts const& cur, OwnerCounts const& next); // Get the adjusted owner count. Since DeferredCredits is meant to be used // in payments, and payments only decrease owner counts, return the max // remembered owner count. - [[nodiscard]] std::optional + [[nodiscard]] std::optional ownerCount(AccountID const& id) const; void @@ -116,25 +125,26 @@ private: std::map creditsIOU_; std::map creditsMPT_; - std::map ownerCounts_; + std::map ownerCounts_; }; } // namespace detail //------------------------------------------------------------------------------ -/** A wrapper which makes credits unavailable to balances. - - This is used for payments and pathfinding, so that consuming - liquidity from a path never causes portions of that path or - other paths to gain liquidity. - - The behavior of certain free functions in the ApplyView API - will change via the balanceHook and creditHook overrides - of PaymentSandbox. - - @note Presented as ApplyView to clients -*/ +/** + * A wrapper which makes credits unavailable to balances. + * + * This is used for payments and pathfinding, so that consuming + * liquidity from a path never causes portions of that path or + * other paths to gain liquidity. + * + * The behavior of certain free functions in the ApplyView API + * will change via the balanceHook and creditHook overrides + * of PaymentSandbox. + * + * @note Presented as ApplyView to clients + */ class PaymentSandbox final : public detail::ApplyViewBase { public: @@ -155,16 +165,17 @@ public: { } - /** Construct on top of existing PaymentSandbox. - - The changes are pushed to the parent when - apply() is called. - - @param parent A non-null pointer to the parent. - - @note A pointer is used to prevent confusion - with copy construction. - */ + /** + * Construct on top of existing PaymentSandbox. + * + * The changes are pushed to the parent when + * apply() is called. + * + * @param parent A non-null pointer to the parent. + * + * @note A pointer is used to prevent confusion + * with copy construction. + */ // VFALCO If we are constructing on top of a PaymentSandbox, // or a PaymentSandbox-derived class, we MUST go through // one of these constructors or invariants will be broken. @@ -210,17 +221,19 @@ public: override; void - adjustOwnerCountHook(AccountID const& account, std::uint32_t cur, std::uint32_t next) override; + adjustOwnerCountHook(AccountID const& account, OwnerCounts const& cur, OwnerCounts const& next) + override; - [[nodiscard]] std::uint32_t - ownerCountHook(AccountID const& account, std::uint32_t count) const override; + [[nodiscard]] OwnerCounts + ownerCountHook(AccountID const& account, OwnerCounts const& count) const override; - /** Apply changes to base view. - - `to` must contain contents identical to the parent - view passed upon construction, else undefined - behavior will result. - */ + /** + * Apply changes to base view. + * + * `to` must contain contents identical to the parent + * view passed upon construction, else undefined + * behavior will result. + */ /** @{ */ void apply(RawView& to); diff --git a/include/xrpl/ledger/PendingSaves.h b/include/xrpl/ledger/PendingSaves.h index a18292df68..723ae1aef1 100644 --- a/include/xrpl/ledger/PendingSaves.h +++ b/include/xrpl/ledger/PendingSaves.h @@ -8,12 +8,13 @@ namespace xrpl { -/** Keeps track of which ledgers haven't been fully saved. - - During the ledger building process this collection will keep - track of those ledgers that are being built but have not yet - been completely written. -*/ +/** + * Keeps track of which ledgers haven't been fully saved. + * + * During the ledger building process this collection will keep + * track of those ledgers that are being built but have not yet + * been completely written. + */ class PendingSaves { private: @@ -22,12 +23,13 @@ private: std::condition_variable await_; public: - /** Start working on a ledger - - This is called prior to updating the SQLite indexes. - - @return 'true' if work should be done - */ + /** + * Start working on a ledger + * + * This is called prior to updating the SQLite indexes. + * + * @return 'true' if work should be done + */ bool startWork(LedgerIndex seq) { @@ -45,12 +47,13 @@ public: return true; } - /** Finish working on a ledger - - This is called after updating the SQLite indexes. - The tracking of the work in progress is removed and - threads awaiting completion are notified. - */ + /** + * Finish working on a ledger + * + * This is called after updating the SQLite indexes. + * The tracking of the work in progress is removed and + * threads awaiting completion are notified. + */ void finishWork(LedgerIndex seq) { @@ -60,7 +63,9 @@ public: await_.notify_all(); } - /** Return `true` if a ledger is in the progress of being saved. */ + /** + * Return `true` if a ledger is in the progress of being saved. + */ bool pending(LedgerIndex seq) { @@ -68,14 +73,15 @@ public: return map_.contains(seq); } - /** Check if a ledger should be dispatched - - Called to determine whether work should be done or - dispatched. If work is already in progress and the - call is synchronous, wait for work to be completed. - - @return 'true' if work should be done or dispatched - */ + /** + * Check if a ledger should be dispatched + * + * Called to determine whether work should be done or + * dispatched. If work is already in progress and the + * call is synchronous, wait for work to be completed. + * + * @return 'true' if work should be done or dispatched + */ bool shouldWork(LedgerIndex seq, bool isSynchronous) { @@ -108,12 +114,13 @@ public: } while (true); } - /** Get a snapshot of the pending saves - - Each entry in the returned map corresponds to a ledger - that is in progress or dispatched. The boolean indicates - whether work is currently in progress. - */ + /** + * Get a snapshot of the pending saves + * + * Each entry in the returned map corresponds to a ledger + * that is in progress or dispatched. The boolean indicates + * whether work is currently in progress. + */ std::map getSnapshot() const { diff --git a/include/xrpl/ledger/RawView.h b/include/xrpl/ledger/RawView.h index cf61c3e814..b94a7aab27 100644 --- a/include/xrpl/ledger/RawView.h +++ b/include/xrpl/ledger/RawView.h @@ -3,13 +3,17 @@ #include #include #include +#include + +#include namespace xrpl { -/** Interface for ledger entry changes. - - Subclasses allow raw modification of ledger entries. -*/ +/** + * Interface for ledger entry changes. + * + * Subclasses allow raw modification of ledger entries. + */ class RawView { public: @@ -19,66 +23,72 @@ public: RawView& operator=(RawView const&) = delete; - /** Delete an existing state item. - - The SLE is provided so the implementation - can calculate metadata. - */ + /** + * Delete an existing state item. + * + * The SLE is provided so the implementation + * can calculate metadata. + */ virtual void rawErase(SLE::ref sle) = 0; - /** Unconditionally insert a state item. - - Requirements: - The key must not already exist. - - Effects: - - The key is associated with the SLE. - - @note The key is taken from the SLE - */ + /** + * Unconditionally insert a state item. + * + * Requirements: + * The key must not already exist. + * + * Effects: + * + * The key is associated with the SLE. + * + * @note The key is taken from the SLE + */ virtual void rawInsert(SLE::ref sle) = 0; - /** Unconditionally replace a state item. - - Requirements: - - The key must exist. - - Effects: - - The key is associated with the SLE. - - @note The key is taken from the SLE - */ + /** + * Unconditionally replace a state item. + * + * Requirements: + * + * The key must exist. + * + * Effects: + * + * The key is associated with the SLE. + * + * @note The key is taken from the SLE + */ virtual void rawReplace(SLE::ref sle) = 0; - /** Destroy XRP. - - This is used to pay for transaction fees. - */ + /** + * Destroy XRP. + * + * This is used to pay for transaction fees. + */ virtual void rawDestroyXRP(XRPAmount const& fee) = 0; }; //------------------------------------------------------------------------------ -/** Interface for changing ledger entries with transactions. - - Allows raw modification of ledger entries and insertion - of transactions into the transaction map. -*/ +/** + * Interface for changing ledger entries with transactions. + * + * Allows raw modification of ledger entries and insertion + * of transactions into the transaction map. + */ class TxsRawView : public RawView { public: - /** Add a transaction to the tx map. - - Closed ledgers must have metadata, - while open ledgers omit metadata. - */ + /** + * Add a transaction to the tx map. + * + * Closed ledgers must have metadata, + * while open ledgers omit metadata. + */ virtual void rawTxInsert( ReadView::key_type const& key, diff --git a/include/xrpl/ledger/ReadView.h b/include/xrpl/ledger/ReadView.h index f4ee7e6fd2..d0010b6030 100644 --- a/include/xrpl/ledger/ReadView.h +++ b/include/xrpl/ledger/ReadView.h @@ -1,32 +1,42 @@ #pragma once +#include #include #include +#include +#include #include +#include #include -#include -#include +#include // IWYU pragma: keep +#include #include +#include #include #include +#include #include #include +#include #include #include +#include #include #include +#include namespace xrpl { //------------------------------------------------------------------------------ -/** A view into a ledger. - - This interface provides read access to state - and transaction items. There is no checkpointing - or calculation of metadata. -*/ +/** + * A view into a ledger. + * + * This interface provides read access to state + * and transaction items. There is no checkpointing + * or calculation of metadata. + */ class ReadView { public: @@ -77,72 +87,87 @@ public: { } - /** Returns information about the ledger. */ + /** + * Returns information about the ledger. + */ [[nodiscard]] virtual LedgerHeader const& header() const = 0; - /** Returns true if this reflects an open ledger. */ + /** + * Returns true if this reflects an open ledger. + */ [[nodiscard]] virtual bool open() const = 0; - /** Returns the close time of the previous ledger. */ + /** + * Returns the close time of the previous ledger. + */ [[nodiscard]] NetClock::time_point parentCloseTime() const { return header().parentCloseTime; } - /** Returns the sequence number of the base ledger. */ + /** + * Returns the sequence number of the base ledger. + */ [[nodiscard]] LedgerIndex seq() const { return header().seq; } - /** Returns the fees for the base ledger. */ + /** + * Returns the fees for the base ledger. + */ [[nodiscard]] virtual Fees const& fees() const = 0; - /** Returns the tx processing rules. */ + /** + * Returns the tx processing rules. + */ [[nodiscard]] virtual Rules const& rules() const = 0; - /** Determine if a state item exists. - - @note This can be more efficient than calling read. - - @return `true` if a SLE is associated with the - specified key. - */ + /** + * Determine if a state item exists. + * + * @note This can be more efficient than calling read. + * + * @return `true` if a SLE is associated with the + * specified key. + */ [[nodiscard]] virtual bool exists(Keylet const& k) const = 0; - /** Return the key of the next state item. - - This returns the key of the first state item - whose key is greater than the specified key. If - no such key is present, std::nullopt is returned. - - If `last` is engaged, returns std::nullopt when - the key returned would be outside the open - interval (key, last). - */ + /** + * Return the key of the next state item. + * + * This returns the key of the first state item + * whose key is greater than the specified key. If + * no such key is present, std::nullopt is returned. + * + * If `last` is engaged, returns std::nullopt when + * the key returned would be outside the open + * interval (key, last). + */ [[nodiscard]] virtual std::optional succ(key_type const& key, std::optional const& last = std::nullopt) const = 0; - /** Return the state item associated with a key. - - Effects: - If the key exists, gives the caller ownership - of the non-modifiable corresponding SLE. - - @note While the returned SLE is `const` from the - perspective of the caller, it can be changed - by other callers through raw operations. - - @return `nullptr` if the key is not present or - if the type does not match. - */ + /** + * Return the state item associated with a key. + * + * Effects: + * If the key exists, gives the caller ownership + * of the non-modifiable corresponding SLE. + * + * @note While the returned SLE is `const` from the + * perspective of the caller, it can be changed + * by other callers through raw operations. + * + * @return `nullptr` if the key is not present or + * if the type does not match. + */ [[nodiscard]] virtual SLE::const_pointer read(Keylet const& k) const = 0; @@ -182,8 +207,8 @@ public: // changes that accounts make during a payment. `ownerCountHook` adjusts the // ownerCount so it returns the max value of the ownerCount so far. // This is required to support PaymentSandbox. - [[nodiscard]] virtual std::uint32_t - ownerCountHook(AccountID const& account, std::uint32_t count) const + [[nodiscard]] virtual OwnerCounts + ownerCountHook(AccountID const& account, OwnerCounts const& count) const { return count; } @@ -208,22 +233,24 @@ public: [[nodiscard]] virtual std::unique_ptr txsEnd() const = 0; - /** Returns `true` if a tx exists in the tx map. - - A tx exists in the map if it is part of the - base ledger, or if it is a newly inserted tx. - */ + /** + * Returns `true` if a tx exists in the tx map. + * + * A tx exists in the map if it is part of the + * base ledger, or if it is a newly inserted tx. + */ [[nodiscard]] virtual bool txExists(key_type const& key) const = 0; - /** Read a transaction from the tx map. - - If the view represents an open ledger, - the metadata object will be empty. - - @return A pair of nullptr if the - key is not found in the tx map. - */ + /** + * Read a transaction from the tx map. + * + * If the view represents an open ledger, + * the metadata object will be empty. + * + * @return A pair of nullptr if the + * key is not found in the tx map. + */ [[nodiscard]] virtual tx_type txRead(key_type const& key) const = 0; @@ -231,11 +258,12 @@ public: // Memberspaces // - /** Iterable range of ledger state items. - - @note Visiting each state entry in the ledger can - become quite expensive as the ledger grows. - */ + /** + * Iterable range of ledger state items. + * + * @note Visiting each state entry in the ledger can + * become quite expensive as the ledger grows. + */ SlesType sles; // The range of transactions @@ -244,7 +272,9 @@ public: //------------------------------------------------------------------------------ -/** ReadView that associates keys with digests. */ +/** + * ReadView that associates keys with digests. + */ class DigestAwareReadView : public ReadView { public: @@ -253,10 +283,11 @@ public: DigestAwareReadView() = default; DigestAwareReadView(DigestAwareReadView const&) = default; - /** Return the digest associated with the key. - - @return std::nullopt if the item does not exist. - */ + /** + * Return the digest associated with the key. + * + * @return std::nullopt if the item does not exist. + */ [[nodiscard]] virtual std::optional digest(key_type const& key) const = 0; }; diff --git a/include/xrpl/ledger/Sandbox.h b/include/xrpl/ledger/Sandbox.h index dc80df5ba2..fd48e339eb 100644 --- a/include/xrpl/ledger/Sandbox.h +++ b/include/xrpl/ledger/Sandbox.h @@ -1,16 +1,19 @@ #pragma once +#include #include +#include #include namespace xrpl { -/** Discardable, editable view to a ledger. - - The sandbox inherits the flags of the base. - - @note Presented as ApplyView to clients. -*/ +/** + * Discardable, editable view to a ledger. + * + * The sandbox inherits the flags of the base. + * + * @note Presented as ApplyView to clients. + */ class Sandbox : public detail::ApplyViewBase { public: diff --git a/include/xrpl/ledger/View.h b/include/xrpl/ledger/View.h index 255413e459..768e518008 100644 --- a/include/xrpl/ledger/View.h +++ b/include/xrpl/ledger/View.h @@ -1,13 +1,22 @@ #pragma once +#include +#include #include #include #include +#include +#include +#include +#include #include #include +#include +#include #include #include #include +#include #include #include @@ -26,26 +35,27 @@ enum class SkipEntry : bool { No = false, Yes }; // //------------------------------------------------------------------------------ -/** Determines whether the given expiration time has passed. - - In the XRP Ledger, expiration times are defined as the number of whole - seconds after the "XRPL epoch" which, for historical reasons, is set - to January 1, 2000 (00:00 UTC). - - This is like the way the Unix epoch works, except the XRPL epoch is - precisely 946,684,800 seconds after the Unix Epoch. - - See https://xrpl.org/basic-data-types.html#specifying-time - - Expiration is defined in terms of the close time of the parent ledger, - because we definitively know the time that it closed (since consensus - agrees on time) but we do not know the closing time of the ledger that - is under construction. - - @param view The ledger whose parent time is used as the clock. - @param exp The optional expiration time we want to check. - - @returns `true` if `exp` is in the past; `false` otherwise. +/** + * Determines whether the given expiration time has passed. + * + * In the XRP Ledger, expiration times are defined as the number of whole + * seconds after the "XRPL epoch" which, for historical reasons, is set + * to January 1, 2000 (00:00 UTC). + * + * This is like the way the Unix epoch works, except the XRPL epoch is + * precisely 946,684,800 seconds after the Unix Epoch. + * + * See https://xrpl.org/basic-data-types.html#specifying-time + * + * Expiration is defined in terms of the close time of the parent ledger, + * because we definitively know the time that it closed (since consensus + * agrees on time) but we do not know the closing time of the ledger that + * is under construction. + * + * @param view The ledger whose parent time is used as the clock. + * @param exp The optional expiration time we want to check. + * + * @return `true` if `exp` is in the past; `false` otherwise. */ [[nodiscard]] bool hasExpired(ReadView const& view, std::optional const& exp); @@ -74,41 +84,44 @@ using majorityAmendments_t = std::map; [[nodiscard]] majorityAmendments_t getMajorityAmendments(ReadView const& view); -/** Return the hash of a ledger by sequence. - The hash is retrieved by looking up the "skip list" - in the passed ledger. As the skip list is limited - in size, if the requested ledger sequence number is - out of the range of ledgers represented in the skip - list, then std::nullopt is returned. - @return The hash of the ledger with the - given sequence number or std::nullopt. -*/ +/** + * Return the hash of a ledger by sequence. + * The hash is retrieved by looking up the "skip list" + * in the passed ledger. As the skip list is limited + * in size, if the requested ledger sequence number is + * out of the range of ledgers represented in the skip + * list, then std::nullopt is returned. + * @return The hash of the ledger with the + * given sequence number or std::nullopt. + */ [[nodiscard]] std::optional hashOfSeq(ReadView const& ledger, LedgerIndex seq, beast::Journal journal); -/** Find a ledger index from which we could easily get the requested ledger - - The index that we return should meet two requirements: - 1) It must be the index of a ledger that has the hash of the ledger - we are looking for. This means that its sequence must be equal to - greater than the sequence that we want but not more than 256 greater - since each ledger contains the hashes of the 256 previous ledgers. - - 2) Its hash must be easy for us to find. This means it must be 0 mod 256 - because every such ledger is permanently enshrined in a LedgerHashes - page which we can easily retrieve via the skip list. -*/ +/** + * Find a ledger index from which we could easily get the requested ledger + * + * The index that we return should meet two requirements: + * 1) It must be the index of a ledger that has the hash of the ledger + * we are looking for. This means that its sequence must be equal to + * greater than the sequence that we want but not more than 256 greater + * since each ledger contains the hashes of the 256 previous ledgers. + * + * 2) Its hash must be easy for us to find. This means it must be 0 mod 256 + * because every such ledger is permanently enshrined in a LedgerHashes + * page which we can easily retrieve via the skip list. + */ inline LedgerIndex getCandidateLedger(LedgerIndex requested) { return (requested + 255) & (~255); } -/** Return false if the test ledger is provably incompatible - with the valid ledger, that is, they could not possibly - both be valid. Use the first form if you have both ledgers, - use the second form if you have not acquired the valid ledger yet -*/ +/** + * Return false if the test ledger is provably incompatible + * with the valid ledger, that is, they could not possibly + * both be valid. Use the first form if you have both ledgers, + * use the second form if you have not acquired the valid ledger yet + */ [[nodiscard]] bool areCompatible( ReadView const& validLedger, @@ -137,7 +150,8 @@ dirLink( SLE::pointer& object, SF_UINT64 const& node = sfOwnerNode); -/** Checks that can withdraw funds from an object to itself or a destination. +/** + * Checks that can withdraw funds from an object to itself or a destination. * * The receiver may be either the submitting account (sfAccount) or a different * destination account (sfDestination). @@ -160,7 +174,8 @@ canWithdraw( STAmount const& amount, bool hasDestinationTag); -/** Checks that can withdraw funds from an object to itself or a destination. +/** + * Checks that can withdraw funds from an object to itself or a destination. * * The receiver may be either the submitting account (sfAccount) or a different * destination account (sfDestination). @@ -182,7 +197,8 @@ canWithdraw( STAmount const& amount, bool hasDestinationTag); -/** Checks that can withdraw funds from an object to itself or a destination. +/** + * Checks that can withdraw funds from an object to itself or a destination. * * The receiver may be either the submitting account (sfAccount) or a different * destination account (sfDestination). @@ -201,8 +217,7 @@ canWithdraw(ReadView const& view, STTx const& tx); [[nodiscard]] TER doWithdraw( - ApplyView& view, - STTx const& tx, + ApplyViewContext ctx, AccountID const& senderAcct, AccountID const& dstAcct, AccountID const& sourceAcct, @@ -210,13 +225,15 @@ doWithdraw( STAmount const& amount, beast::Journal j); -/** Deleter function prototype. Returns the status of the entry deletion +/** + * Deleter function prototype. Returns the status of the entry deletion * (if should not be skipped) and if the entry should be skipped. The status * is always tesSUCCESS if the entry should be skipped. */ using EntryDeleter = std::function(LedgerEntryType, uint256 const&, SLE::pointer&)>; -/** Cleanup owner directory entries on account delete. +/** + * Cleanup owner directory entries on account delete. * Used for a regular and AMM accounts deletion. The caller * has to provide the deleter function, which handles details of * specific account-owned object deletion. @@ -231,12 +248,13 @@ cleanupOnAccountDelete( beast::Journal j, std::optional maxNodesToDelete = std::nullopt); -/** Has the specified time passed? - - @param now the current time - @param mark the cutoff point - @return true if \a now refers to a time strictly after \a mark, else false. -*/ +/** + * Has the specified time passed? + * + * @param now the current time + * @param mark the cutoff point + * @return true if \a now refers to a time strictly after \a mark, else false. + */ bool after(NetClock::time_point now, std::uint32_t mark); diff --git a/include/xrpl/ledger/detail/ApplyStateTable.h b/include/xrpl/ledger/detail/ApplyStateTable.h index f40e3d0d1c..752c87d588 100644 --- a/include/xrpl/ledger/detail/ApplyStateTable.h +++ b/include/xrpl/ledger/detail/ApplyStateTable.h @@ -1,13 +1,26 @@ #pragma once +#include +#include #include #include #include #include +#include +#include +#include +#include +#include #include #include #include +#include +#include +#include +#include +#include + namespace xrpl::detail { // Helper class that buffers modifications diff --git a/include/xrpl/ledger/detail/ApplyViewBase.h b/include/xrpl/ledger/detail/ApplyViewBase.h index d6493c46a8..b5b01de277 100644 --- a/include/xrpl/ledger/detail/ApplyViewBase.h +++ b/include/xrpl/ledger/detail/ApplyViewBase.h @@ -1,10 +1,20 @@ #pragma once +#include #include +#include #include #include +#include +#include +#include +#include +#include #include +#include +#include + namespace xrpl::detail { class ApplyViewBase : public ApplyView, public RawView diff --git a/include/xrpl/ledger/detail/RawStateTable.h b/include/xrpl/ledger/detail/RawStateTable.h index d2567e34f1..2e36a42eaf 100644 --- a/include/xrpl/ledger/detail/RawStateTable.h +++ b/include/xrpl/ledger/detail/RawStateTable.h @@ -1,12 +1,20 @@ #pragma once +#include +#include #include #include +#include +#include #include #include +#include +#include #include +#include +#include #include namespace xrpl::detail { @@ -97,7 +105,7 @@ private: using items_t = std::map< key_type, SleAction, - std::less, + std::less<>, boost::container::pmr::polymorphic_allocator>>; // monotonic_resource_ must outlive `items_`. Make a pointer so it may be // easily moved. diff --git a/include/xrpl/ledger/detail/ReadViewFwdRange.h b/include/xrpl/ledger/detail/ReadViewFwdRange.h index c548ccb101..19ac0698c2 100644 --- a/include/xrpl/ledger/detail/ReadViewFwdRange.h +++ b/include/xrpl/ledger/detail/ReadViewFwdRange.h @@ -1,8 +1,10 @@ #pragma once #include +#include #include #include +#include namespace xrpl { @@ -106,8 +108,8 @@ public: std::optional mutable cache_; }; - static_assert(std::is_nothrow_move_constructible{}, ""); - static_assert(std::is_nothrow_move_assignable{}, ""); + static_assert(std::is_nothrow_move_constructible{}); + static_assert(std::is_nothrow_move_assignable{}); using const_iterator = Iterator; diff --git a/include/xrpl/ledger/helpers/AMMHelpers.h b/include/xrpl/ledger/helpers/AMMHelpers.h index de8bb9d3f7..7d41bfce81 100644 --- a/include/xrpl/ledger/helpers/AMMHelpers.h +++ b/include/xrpl/ledger/helpers/AMMHelpers.h @@ -2,22 +2,36 @@ #include #include +#include #include +#include +#include #include #include -#include #include #include +#include #include +#include #include #include #include +#include #include #include #include #include +#include +#include +#include +#include #include +#include +#include +#include +#include +#include namespace xrpl { @@ -39,7 +53,8 @@ enum class IsDeposit : bool { No = false, Yes = true }; inline Number const kAMMInvariantRelativeTolerance{1, -11}; -/** Calculate LP Tokens given AMM pool reserves. +/** + * Calculate LP Tokens given AMM pool reserves. * @param asset1 AMM one side of the pool reserve * @param asset2 AMM another side of the pool reserve * @return LP Tokens as IOU @@ -47,7 +62,8 @@ inline Number const kAMMInvariantRelativeTolerance{1, -11}; STAmount ammLPTokens(STAmount const& asset1, STAmount const& asset2, Asset const& lptIssue); -/** Calculate LP Tokens given asset's deposit amount. +/** + * Calculate LP Tokens given asset's deposit amount. * @param asset1Balance current AMM asset1 balance * @param asset1Deposit requested asset1 deposit amount * @param lptAMMBalance AMM LPT balance @@ -61,10 +77,11 @@ lpTokensOut( STAmount const& lptAMMBalance, std::uint16_t tfee); -/** Calculate asset deposit given LP Tokens. +/** + * Calculate asset deposit given LP Tokens. * @param asset1Balance current AMM asset1 balance - * @param lpTokens LP Tokens * @param lptAMMBalance AMM LPT balance + * @param lpTokens LP Tokens * @param tfee trading fee in basis points * @return */ @@ -75,7 +92,8 @@ ammAssetIn( STAmount const& lpTokens, std::uint16_t tfee); -/** Calculate LP Tokens given asset's withdraw amount. Return 0 +/** + * Calculate LP Tokens given asset's withdraw amount. Return 0 * if can't calculate. * @param asset1Balance current AMM asset1 balance * @param asset1Withdraw requested asset1 withdraw amount @@ -90,7 +108,8 @@ lpTokensIn( STAmount const& lptAMMBalance, std::uint16_t tfee); -/** Calculate asset withdrawal by tokens +/** + * Calculate asset withdrawal by tokens * @param assetBalance balance of the asset being withdrawn * @param lptAMMBalance total AMM Tokens balance * @param lpTokens LP Tokens balance @@ -104,7 +123,8 @@ ammAssetOut( STAmount const& lpTokens, std::uint16_t tfee); -/** Check if the relative distance between the qualities +/** + * Check if the relative distance between the qualities * is within the requested distance. * @param calcQuality calculated quality * @param reqQuality requested quality @@ -123,7 +143,8 @@ withinRelativeDistance(Quality const& calcQuality, Quality const& reqQuality, Nu return ((min.rate() - max.rate()) / min.rate()) < dist; } -/** Check if the relative distance between the amounts +/** + * Check if the relative distance between the amounts * is within the requested distance. * @param calc calculated amount * @param req requested amount @@ -144,13 +165,15 @@ withinRelativeDistance(Amt const& calc, Amt const& req, Number const& dist) return ((max - min) / max) < dist; } -/** Solve quadratic equation to find takerGets or takerPays. Round +/** + * Solve quadratic equation to find takerGets or takerPays. Round * to minimize the amount in order to maximize the quality. */ std::optional solveQuadraticEqSmallest(Number const& a, Number const& b, Number const& c); -/** Generate AMM offer starting with takerGets when AMM pool +/** + * Generate AMM offer starting with takerGets when AMM pool * from the payment perspective is IOU(in)/XRP(out) * Equations: * Spot Price Quality after the offer is consumed: @@ -217,7 +240,8 @@ getAMMOfferStartWithTakerGets( return amounts; } -/** Generate AMM offer starting with takerPays when AMM pool +/** + * Generate AMM offer starting with takerPays when AMM pool * from the payment perspective is XRP(in)/IOU(out) or IOU(in)/IOU(out). * Equations: * Spot Price Quality after the offer is consumed: @@ -284,7 +308,8 @@ getAMMOfferStartWithTakerPays( return amounts; } -/** Generate AMM offer so that either updated Spot Price Quality (SPQ) +/** + * Generate AMM offer so that either updated Spot Price Quality (SPQ) * is equal to LOB quality (in this case AMM offer quality is * better than LOB quality) or AMM offer is equal to LOB quality * (in this case SPQ is better than LOB quality). @@ -401,7 +426,8 @@ changeSpotPriceQuality( return amounts; } -/** AMM pool invariant - the product (A * B) after swap in/out has to remain +/** + * AMM pool invariant - the product (A * B) after swap in/out has to remain * at least the same: (A + in) * (B - out) >= A * B * XRP round-off may result in a smaller product after swap in/out. * To address this: @@ -413,7 +439,8 @@ changeSpotPriceQuality( * value is increased. */ -/** Swap assetIn into the pool and swap out a proportional amount +/** + * Swap assetIn into the pool and swap out a proportional amount * of the other asset. Implements AMM Swap in. * @see [XLS30d:AMM * Swap](https://github.com/XRPLF/XRPL-Standards/discussions/78) @@ -479,7 +506,8 @@ swapAssetIn(TAmounts const& pool, TIn const& assetIn, std::uint16_t t Number::RoundingMode::Downward); } -/** Swap assetOut out of the pool and swap in a proportional amount +/** + * Swap assetOut out of the pool and swap in a proportional amount * of the other asset. Implements AMM Swap out. * @see [XLS30d:AMM * Swap](https://github.com/XRPLF/XRPL-Standards/discussions/78) @@ -545,12 +573,14 @@ swapAssetOut(TAmounts const& pool, TOut const& assetOut, std::uint16_ Number::RoundingMode::Upward); } -/** Return square of n. +/** + * Return square of n. */ Number square(Number const& n); -/** Adjust LP tokens to deposit/withdraw. +/** + * Adjust LP tokens to deposit/withdraw. * Amount type keeps 16 digits. Maintaining the LP balance by adding * deposited tokens or subtracting withdrawn LP tokens from LP balance * results in losing precision in LP balance. I.e. the resulting LP balance @@ -564,7 +594,8 @@ square(Number const& n); STAmount adjustLPTokens(STAmount const& lptAMMBalance, STAmount const& lpTokens, IsDeposit isDeposit); -/** Calls adjustLPTokens() and adjusts deposit or withdraw amounts if +/** + * Calls adjustLPTokens() and adjusts deposit or withdraw amounts if * the adjusted LP tokens are less than the provided LP tokens. * @param amountBalance asset1 pool balance * @param amount asset1 to deposit or withdraw @@ -585,7 +616,8 @@ adjustAmountsByLPTokens( std::uint16_t tfee, IsDeposit isDeposit); -/** Positive solution for quadratic equation: +/** + * Positive solution for quadratic equation: * x = (-b + sqrt(b**2 + 4*a*c))/(2*a) */ Number @@ -616,7 +648,8 @@ getAssetRounding(IsDeposit isDeposit) } // namespace detail -/** Round AMM equal deposit/withdrawal amount. Deposit/withdrawal formulas +/** + * Round AMM equal deposit/withdrawal amount. Deposit/withdrawal formulas * calculate the amount as a fractional value of the pool balance. The rounding * takes place on the last step of multiplying the balance by the fraction if * AMMv1_3 is enabled. @@ -640,7 +673,8 @@ getRoundedAsset(Rules const& rules, STAmount const& balance, A const& frac, IsDe return multiply(balance, frac, rm); } -/** Round AMM single deposit/withdrawal amount. +/** + * Round AMM single deposit/withdrawal amount. * The lambda's are used to delay evaluation until the function * is executed so that the calculation is not done twice. noRoundCb() is * called if AMMv1_3 is disabled. Otherwise, the rounding is set and @@ -657,7 +691,8 @@ getRoundedAsset( std::function const& productCb, IsDeposit isDeposit); -/** Round AMM deposit/withdrawal LPToken amount. Deposit/withdrawal formulas +/** + * Round AMM deposit/withdrawal LPToken amount. Deposit/withdrawal formulas * calculate the lptokens as a fractional value of the AMM total lptokens. * The rounding takes place on the last step of multiplying the balance by * the fraction if AMMv1_3 is enabled. The tokens are then @@ -671,7 +706,8 @@ getRoundedLPTokens( Number const& frac, IsDeposit isDeposit); -/** Round AMM single deposit/withdrawal LPToken amount. +/** + * Round AMM single deposit/withdrawal LPToken amount. * The lambda's are used to delay evaluation until the function is executed * so that the calculations are not done twice. * noRoundCb() is called if AMMv1_3 is disabled. Otherwise, the rounding is set @@ -718,7 +754,8 @@ adjustAssetOutByTokens( STAmount const& tokens, std::uint16_t tfee); -/** Find a fraction of tokens after the tokens are adjusted. The fraction +/** + * Find a fraction of tokens after the tokens are adjusted. The fraction * is used to adjust equal deposit/withdraw amount. */ Number @@ -728,7 +765,8 @@ adjustFracByTokens( STAmount const& tokens, Number const& frac); -/** Get AMM pool balances. +/** + * Get AMM pool balances. */ std::pair ammPoolHolds( @@ -740,7 +778,8 @@ ammPoolHolds( AuthHandling authHandling, beast::Journal const j); -/** Check AMM pool product invariant after an AMM operation that changes LP tokens +/** + * Check AMM pool product invariant after an AMM operation that changes LP tokens * (deposit/withdraw/clawback) from an already calculated pool product mean. * Returns tecPRECISION_LOSS if poolProductMean < newLPTokenBalance beyond the * invariant tolerance, @@ -749,7 +788,8 @@ ammPoolHolds( TER checkAMMPrecisionLoss(Number const& poolProductMean, STAmount const& newLPTokenBalance); -/** Check AMM pool product invariant after an AMM operation that changes LP tokens +/** + * Check AMM pool product invariant after an AMM operation that changes LP tokens * (deposit/withdraw/clawback). * Returns tecPRECISION_LOSS if sqrt(asset1 * asset2) < newLPTokenBalance beyond * the invariant tolerance, @@ -764,7 +804,8 @@ checkAMMPrecisionLoss( STAmount const& newLPTokenBalance, beast::Journal const j); -/** Get AMM pool and LP token balances. If both optIssue are +/** + * Get AMM pool and LP token balances. If both optIssue are * provided then they are used as the AMM token pair issues. * Otherwise the missing issues are fetched from ammSle. */ @@ -778,7 +819,8 @@ ammHolds( AuthHandling authHandling, beast::Journal const j); -/** Get the balance of LP tokens. +/** + * Get the balance of LP tokens. */ STAmount ammLPHolds( @@ -796,25 +838,29 @@ ammLPHolds( AccountID const& lpAccount, beast::Journal const j); -/** Get AMM trading fee for the given account. The fee is discounted +/** + * Get AMM trading fee for the given account. The fee is discounted * if the account is the auction slot owner or one of the slot's authorized * accounts. */ std::uint16_t getTradingFee(ReadView const& view, SLE const& ammSle, AccountID const& account); -/** Returns total amount held by AMM for the given token. +/** + * Returns total amount held by AMM for the given token. */ STAmount ammAccountHolds(ReadView const& view, AccountID const& ammAccountID, Asset const& asset); -/** Delete trustlines to AMM. If all trustlines are deleted then +/** + * Delete trustlines to AMM. If all trustlines are deleted then * AMM object and account are deleted. Otherwise tecINCOMPLETE is returned. */ TER deleteAMMAccount(Sandbox& view, Asset const& asset, Asset const& asset2, beast::Journal j); -/** Initialize Auction and Voting slots and set the trading/discounted fee. +/** + * Initialize Auction and Voting slots and set the trading/discounted fee. */ void initializeFeeAuctionVote( @@ -824,14 +870,16 @@ initializeFeeAuctionVote( Asset const& lptAsset, std::uint16_t tfee); -/** Return true if the Liquidity Provider is the only AMM provider, false +/** + * Return true if the Liquidity Provider is the only AMM provider, false * otherwise. Return tecINTERNAL if encountered an unexpected condition, * for instance Liquidity Provider has more than one LPToken trustline. */ std::expected isOnlyLiquidityProvider(ReadView const& view, Issue const& ammIssue, AccountID const& lpAccount); -/** Due to rounding, the LPTokenBalance of the last LP might +/** + * Due to rounding, the LPTokenBalance of the last LP might * not match the LP's trustline balance. If it's within the tolerance, * update LPTokenBalance to match the LP's trustline balance. */ diff --git a/include/xrpl/ledger/helpers/AccountRootHelpers.h b/include/xrpl/ledger/helpers/AccountRootHelpers.h index cf6082d533..350fc6ca85 100644 --- a/include/xrpl/ledger/helpers/AccountRootHelpers.h +++ b/include/xrpl/ledger/helpers/AccountRootHelpers.h @@ -1,43 +1,337 @@ #pragma once +#include #include #include #include +#include #include #include +#include #include #include +#include +#include #include +#include #include #include namespace xrpl { -/** Check if the issuer has the global freeze flag set. - @param issuer The account to check - @return true if the account has global freeze set -*/ +/** + * Check if the issuer has the global freeze flag set. + * @param issuer The account to check + * @return true if the account has global freeze set + */ [[nodiscard]] bool isGlobalFrozen(ReadView const& view, AccountID const& issuer); -// Calculate liquid XRP balance for an account. -// This function may be used to calculate the amount of XRP that -// the holder is able to freely spend. It subtracts reserve requirements. -// -// ownerCountAdj adjusts the owner count in case the caller calculates -// before ledger entries are added or removed. Positive to add, negative -// to subtract. -// -// @param ownerCountAdj positive to add to count, negative to reduce count. +/** + * Calculate liquid XRP balance for an account. + * + * This function may be used to calculate the amount of XRP that + * the holder is able to freely spend. It subtracts reserve requirements. + * + * ownerCountAdj adjusts the owner count in case the caller calculates + * before ledger entries are added or removed. Positive to add, negative + * to subtract. + * + * @param view The ledger view to read from + * @param id The account ID to check + * @param ownerCountAdj Positive to add to count, negative to reduce count + * @param j Journal for logging + * @return The liquid XRP amount available to the account + */ [[nodiscard]] XRPAmount xrpLiquid(ReadView const& view, AccountID const& id, std::int32_t ownerCountAdj, beast::Journal j); -/** Adjust the owner count up or down. */ -void -adjustOwnerCount(ApplyView& view, SLE::ref sle, std::int32_t amount, beast::Journal j); +struct Adjustment +{ + std::int32_t ownerCountDelta = 0; + std::int32_t accountCountDelta = 0; +}; -/** Returns IOU issuer transfer fee as Rate. Rate specifies +/** + * 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 view The ledger view to read from + * @param sle The ledger entry for the account + * @param j Journal for logging + * @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 +accountReserve(ReadView const& view, SLE::const_ref sle, beast::Journal j, Adjustment adj = {}); + +/** + * Convenience overload that accepts AccountID instead of SLE. + * + * @param view The ledger view to read from + * @param id The account ID + * @param j Journal for logging + * @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]] inline XRPAmount +accountReserve(ReadView const& view, AccountID const& id, beast::Journal j, Adjustment 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::const_ref accSle, + XRPAmount accBalance, + SLE::const_ref 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::const_ref 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::const_ref 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. + * + * @param view The apply view for making changes + * @param account The account ID + * @param sponsor The optional sponsor account ID + * @param count Amount to add to the owner count + * @param j Journal for logging + */ +inline void +increaseOwnerCount( + ApplyView& view, + AccountID const& account, + std::optional const& sponsor, + std::uint32_t count, + beast::Journal j) +{ + increaseOwnerCount( + view, + view.peek(keylet::account(account)), + sponsor ? view.peek(keylet::account(*sponsor)) : SLE::pointer(), + 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. + * + * @param view The apply view for making changes + * @param account The account ID + * @param sponsor The optional sponsor account ID + * @param count Amount to remove from the owner count + * @param j Journal for logging + */ +inline void +decreaseOwnerCount( + ApplyView& view, + AccountID const& account, + std::optional const& sponsor, + std::uint32_t count, + beast::Journal j) +{ + decreaseOwnerCount( + view, + view.peek(keylet::account(account)), + sponsor ? view.peek(keylet::account(*sponsor)) : SLE::pointer(), + count, + j); +} + +/** + * Decrease owner-count fields for an existing ledger object. + * + * This helper derives the reserve sponsor from objectSle's sfSponsor field, + * then updates the same owner-count fields as decreaseOwnerCount. Use this + * when removing an existing object whose reserve sponsor is stored on that + * object. + * + * @param view The apply view for making changes + * @param accountSle The account's ledger entry + * @param objectSle The object's ledger entry + * @param count Amount to remove from the owner count + * @param j Journal for logging + */ +void +decreaseOwnerCountForObject( + ApplyView& view, + SLE::ref accountSle, + SLE::ref objectSle, + std::uint32_t count, + beast::Journal j); + +/** + * Convenience overload that accepts AccountID instead of account SLE reference. + * + * @param view The apply view for making changes + * @param account The account ID + * @param objectSle The object's ledger entry + * @param count Amount to remove from the owner count + * @param j Journal for logging + */ +inline void +decreaseOwnerCountForObject( + ApplyView& view, + AccountID const& account, + SLE::ref objectSle, + std::uint32_t count, + beast::Journal j) +{ + SLE::ref accountSle = view.peek(keylet::account(account)); + decreaseOwnerCountForObject(view, accountSle, objectSle, count, j); +} + +/** + * Adjust a LoanBroker's owner count. + * + * A LoanBroker's sfOwnerCount tracks the number of outstanding loans on + * that broker; it is not a reserve-backed owner count and is distinct + * from the broker's pseudo-account's owner count. Loans can never carry a + * reserve sponsor (LoanSet rejects reserve sponsorship at preflight), so + * this never involves sponsor accounting and never invokes the + * ownerCountHook used for ACCOUNT_ROOT reserve tracking. + * + * @param view The apply view for making changes + * @param brokerSle The LoanBroker's ledger entry + * @param delta Amount to add (positive) or remove (negative) from the count + * @param j Journal for logging + */ +void +adjustLoanBrokerOwnerCount( + ApplyView& view, + SLE::ref brokerSle, + std::int32_t delta, + beast::Journal j); + +/** + * Returns IOU issuer transfer fee as Rate. Rate specifies * the fee as fractions of 1 billion. For example, 1% transfer rate * is represented as 1,010,000,000. * @param issuer The IOU issuer @@ -45,35 +339,40 @@ adjustOwnerCount(ApplyView& view, SLE::ref sle, std::int32_t amount, beast::Jour [[nodiscard]] Rate transferRate(ReadView const& view, AccountID const& issuer); -/** Generate a pseudo-account address from a pseudo owner key. - @param pseudoOwnerKey The key to generate the address from - @return The generated account ID -*/ +/** + * Generate a pseudo-account address from a pseudo owner key. + * @param pseudoOwnerKey The key to generate the address from + * @return The generated account ID + */ AccountID pseudoAccountAddress(ReadView const& view, uint256 const& pseudoOwnerKey); -/** Returns the list of fields that define an ACCOUNT_ROOT as a pseudo-account - if set. - - The list is constructed during initialization and is const after that. - Pseudo-account designator fields MUST be maintained by including the - SField::sMD_PseudoAccount flag in the SField definition. -*/ +/** + * Returns the list of fields that define an ACCOUNT_ROOT as a pseudo-account + * if set. + * + * The list is constructed during initialization and is const after that. + * Pseudo-account designator fields MUST be maintained by including the + * SField::sMD_PseudoAccount flag in the SField definition. + */ [[nodiscard]] std::vector const& getPseudoAccountFields(); -/** Returns true if and only if sleAcct is a pseudo-account or specific - pseudo-accounts in pseudoFieldFilter. - - Returns false if sleAcct is: - - NOT a pseudo-account OR - - NOT a ltACCOUNT_ROOT OR - - null pointer -*/ +/** + * Returns true if and only if sleAcct is a pseudo-account or specific + * pseudo-accounts in pseudoFieldFilter. + * + * Returns false if sleAcct is: + * - NOT a pseudo-account OR + * - NOT a ltACCOUNT_ROOT OR + * - null pointer + */ [[nodiscard]] bool isPseudoAccount(SLE::const_pointer sleAcct, std::set const& pseudoFieldFilter = {}); -/** Convenience overload that reads the account from the view. */ +/** + * Convenience overload that reads the account from the view. + */ [[nodiscard]] inline bool isPseudoAccount( ReadView const& view, @@ -94,11 +393,12 @@ isPseudoAccount( [[nodiscard]] std::expected createPseudoAccount(ApplyView& view, uint256 const& pseudoOwnerKey, SField const& ownerField); -/** Checks the destination and tag. - - - Checks that the SLE is not null. - - If the SLE requires a destination tag, checks that there is a tag. -*/ +/** + * Checks the destination and tag. + * + * - Checks that the SLE is not null. + * - If the SLE requires a destination tag, checks that there is a tag. + */ [[nodiscard]] TER checkDestinationAndTag(SLE::const_ref toSle, bool hasDestinationTag); diff --git a/include/xrpl/ledger/helpers/CredentialHelpers.h b/include/xrpl/ledger/helpers/CredentialHelpers.h index 0cfbbde538..8e78a00923 100644 --- a/include/xrpl/ledger/helpers/CredentialHelpers.h +++ b/include/xrpl/ledger/helpers/CredentialHelpers.h @@ -1,15 +1,22 @@ #pragma once -#include +#include #include +#include #include #include #include #include #include +#include #include +#include #include +#include +#include +#include + namespace xrpl { namespace credentials { @@ -63,6 +70,39 @@ checkArray(STArray const& credentials, unsigned maxSize, beast::Journal j); TER verifyValidDomain(ApplyView& view, AccountID const& account, uint256 domainID, beast::Journal j); +/** + * @brief Check whether src is authorized to deposit to dst. + * + * @param tx Transaction containing optional credential IDs. + * @param view Read-only ledger view. + * @param src Source account. + * @param dst Destination account. + * @param sleDst Destination AccountRoot, if it exists. + * @param j Journal for diagnostics. + * @return tesSUCCESS if the deposit is allowed, otherwise an authorization + * error. + */ +TER +checkDepositPreauth( + STTx const& tx, + ReadView const& view, + AccountID const& src, + AccountID const& dst, + std::shared_ptr const& sleDst, + beast::Journal j); + +/** + * @brief Remove expired credentials referenced by the transaction. + * + * @param tx Transaction containing optional sfCredentialIDs. + * @param view Mutable ledger view. + * @param j Journal for diagnostics. + * @return tesSUCCESS if no referenced credentials expired, tecEXPIRED if any + * were removed, or an error from credential deletion. + */ +TER +cleanupExpiredCredentials(STTx const& tx, ApplyView& view, beast::Journal j); + // Check expired credentials and for existing DepositPreauth ledger object TER verifyDepositPreauth( diff --git a/include/xrpl/ledger/helpers/DelegateHelpers.h b/include/xrpl/ledger/helpers/DelegateHelpers.h index a517eefdaa..3c277cb4f7 100644 --- a/include/xrpl/ledger/helpers/DelegateHelpers.h +++ b/include/xrpl/ledger/helpers/DelegateHelpers.h @@ -4,6 +4,9 @@ #include #include #include +#include + +#include namespace xrpl { diff --git a/include/xrpl/ledger/helpers/DirectoryHelpers.h b/include/xrpl/ledger/helpers/DirectoryHelpers.h index a0be52df99..25085c4252 100644 --- a/include/xrpl/ledger/helpers/DirectoryHelpers.h +++ b/include/xrpl/ledger/helpers/DirectoryHelpers.h @@ -1,12 +1,16 @@ #pragma once +#include #include #include #include +#include #include +#include +#include #include -#include +#include #include #include #include @@ -15,11 +19,7 @@ namespace xrpl { namespace detail { -template < - class V, - class N, - class = std::enable_if_t< - std::is_same_v, SLE> && std::is_base_of_v>> +template bool internalDirNext( V& view, @@ -27,6 +27,7 @@ internalDirNext( std::shared_ptr& page, unsigned int& index, uint256& entry) + requires(std::is_same_v, SLE> && std::is_base_of_v) { auto const& svIndexes = page->getFieldV256(sfIndexes); XRPL_ASSERT(index <= svIndexes.size(), "xrpl::detail::internalDirNext : index inside range"); @@ -64,11 +65,7 @@ internalDirNext( return true; } -template < - class V, - class N, - class = std::enable_if_t< - std::is_same_v, SLE> && std::is_base_of_v>> +template bool internalDirFirst( V& view, @@ -76,6 +73,7 @@ internalDirFirst( std::shared_ptr& page, unsigned int& index, uint256& entry) + requires(std::is_same_v, SLE> && std::is_base_of_v) { if constexpr (std::is_const_v) { @@ -97,19 +95,20 @@ internalDirFirst( } // namespace detail /** @{ */ -/** Returns the first entry in the directory, advancing the index - - @deprecated These are legacy function that are considered deprecated - and will soon be replaced with an iterator-based model - that is easier to use. You should not use them in new code. - - @param view The view against which to operate - @param root The root (i.e. first page) of the directory to iterate - @param page The current page - @param index The index inside the current page - @param entry The entry at the current index - - @return true if the directory isn't empty; false otherwise +/** + * Returns the first entry in the directory, advancing the index + * + * @deprecated These are legacy function that are considered deprecated + * and will soon be replaced with an iterator-based model + * that is easier to use. You should not use them in new code. + * + * @param view The view against which to operate + * @param root The root (i.e. first page) of the directory to iterate + * @param page The current page + * @param index The index inside the current page + * @param entry The entry at the current index + * + * @return true if the directory isn't empty; false otherwise */ bool cdirFirst( @@ -129,19 +128,20 @@ dirFirst( /** @} */ /** @{ */ -/** Returns the next entry in the directory, advancing the index - - @deprecated These are legacy function that are considered deprecated - and will soon be replaced with an iterator-based model - that is easier to use. You should not use them in new code. - - @param view The view against which to operate - @param root The root (i.e. first page) of the directory to iterate - @param page The current page - @param index The index inside the current page - @param entry The entry at the current index - - @return true if the directory isn't empty; false otherwise +/** + * Returns the next entry in the directory, advancing the index + * + * @deprecated These are legacy function that are considered deprecated + * and will soon be replaced with an iterator-based model + * that is easier to use. You should not use them in new code. + * + * @param view The view against which to operate + * @param root The root (i.e. first page) of the directory to iterate + * @param page The current page + * @param index The index inside the current page + * @param entry The entry at the current index + * + * @return true if the directory isn't empty; false otherwise */ bool cdirNext( @@ -160,16 +160,19 @@ dirNext( uint256& entry); /** @} */ -/** Iterate all items in the given directory. */ +/** + * Iterate all items in the given directory. + */ void forEachItem(ReadView const& view, Keylet const& root, std::function const& f); -/** Iterate all items after an item in the given directory. - @param after The key of the item to start after - @param hint The directory page containing `after` - @param limit The maximum number of items to return - @return `false` if the iteration failed -*/ +/** + * Iterate all items after an item in the given directory. + * @param after The key of the item to start after + * @param hint The directory page containing `after` + * @param limit The maximum number of items to return + * @return `false` if the iteration failed + */ bool forEachItemAfter( ReadView const& view, @@ -179,19 +182,22 @@ forEachItemAfter( unsigned int limit, std::function const& f); -/** Iterate all items in an account's owner directory. */ +/** + * Iterate all items in an account's owner directory. + */ inline void forEachItem(ReadView const& view, AccountID const& id, std::function const& f) { forEachItem(view, keylet::ownerDir(id), f); } -/** Iterate all items after an item in an owner directory. - @param after The key of the item to start after - @param hint The directory page containing `after` - @param limit The maximum number of items to return - @return `false` if the iteration failed -*/ +/** + * Iterate all items after an item in an owner directory. + * @param after The key of the item to start after + * @param hint The directory page containing `after` + * @param limit The maximum number of items to return + * @return `false` if the iteration failed + */ inline bool forEachItemAfter( ReadView const& view, @@ -204,13 +210,16 @@ forEachItemAfter( return forEachItemAfter(view, keylet::ownerDir(id), after, hint, limit, f); } -/** Returns `true` if the directory is empty - @param key The key of the directory -*/ +/** + * Returns `true` if the directory is empty + * @param key The key of the directory + */ [[nodiscard]] bool dirIsEmpty(ReadView const& view, Keylet const& k); -/** Returns a function that sets the owner on a directory SLE */ +/** + * Returns a function that sets the owner on a directory SLE + */ [[nodiscard]] std::function describeOwnerDir(AccountID const& account); diff --git a/include/xrpl/ledger/helpers/EscrowHelpers.h b/include/xrpl/ledger/helpers/EscrowHelpers.h index bdb83230eb..9f54e53769 100644 --- a/include/xrpl/ledger/helpers/EscrowHelpers.h +++ b/include/xrpl/ledger/helpers/EscrowHelpers.h @@ -1,25 +1,37 @@ #pragma once #include +#include #include -#include #include #include #include +#include +#include +#include +#include #include #include -#include +#include +#include +#include +#include #include +#include +#include +#include +#include +#include namespace xrpl { template TER escrowUnlockApplyHelper( - ApplyView& view, + ApplyViewContext ctx, Rate lockedRate, SLE::ref sleDest, - STAmount const& xrpBalance, + XRPAmount xrpBalance, STAmount const& amount, AccountID const& issuer, AccountID const& sender, @@ -30,10 +42,10 @@ escrowUnlockApplyHelper( template <> inline TER escrowUnlockApplyHelper( - ApplyView& view, + ApplyViewContext ctx, Rate lockedRate, SLE::ref sleDest, - STAmount const& xrpBalance, + XRPAmount xrpBalance, STAmount const& amount, AccountID const& issuer, AccountID const& sender, @@ -41,8 +53,8 @@ escrowUnlockApplyHelper( bool createAsset, beast::Journal journal) { - Issue const& issue = amount.get(); - Keylet const trustLineKey = keylet::line(receiver, issue); + auto const& issue = amount.get(); + Keylet const trustLineKey = keylet::trustLine(receiver, issue); bool const recvLow = issuer > receiver; bool const senderIssuer = issuer == sender; bool const receiverIssuer = issuer == receiver; @@ -53,16 +65,26 @@ escrowUnlockApplyHelper( if (receiverIssuer) return tesSUCCESS; - if (!view.exists(trustLineKey) && createAsset) + if (!ctx.view.exists(trustLineKey) && createAsset) { // Can the account cover the trust line's reserve? - if (std::uint32_t const ownerCount = {sleDest->at(sfOwnerCount)}; - xrpBalance < view.fees().accountReserve(ownerCount + 1)) + auto const sponsorSle = getEffectiveTxReserveSponsor(ctx, sleDest); + if (!sponsorSle) + return sponsorSle.error(); // LCOV_EXCL_LINE + + if (auto const ret = checkReserve( + ctx, + sleDest, + xrpBalance, + *sponsorSle, + {.ownerCountDelta = 1}, + journal, + tecNO_LINE_INSUF_RESERVE); + !isTesSuccess(ret)) { JLOG(journal.trace()) << "Trust line does not exist. " "Insufficient reserve to create line."; - - return tecNO_LINE_INSUF_RESERVE; + return ret; } Currency const currency = issue.currency; @@ -70,7 +92,7 @@ escrowUnlockApplyHelper( initialBalance.get().account = noAccount(); if (TER const ter = trustCreate( - view, // payment sandbox + ctx.view, // payment sandbox recvLow, // is dest low? issuer, // source receiver, // destination @@ -84,19 +106,20 @@ escrowUnlockApplyHelper( Issue(currency, receiver), // limit of zero 0, // quality in 0, // quality out + *sponsorSle, // sponsor journal); // journal !isTesSuccess(ter)) { return ter; // LCOV_EXCL_LINE } - view.update(sleDest); + ctx.view.update(sleDest); } - if (!view.exists(trustLineKey) && !receiverIssuer) + if (!ctx.view.exists(trustLineKey) && !receiverIssuer) return tecNO_LINE; - auto const xferRate = transferRate(view, amount); + auto const xferRate = transferRate(ctx.view, amount); // update if issuer rate is less than locked rate if (xferRate < lockedRate) lockedRate = xferRate; @@ -124,7 +147,7 @@ escrowUnlockApplyHelper( // of the funds if (!createAsset) { - auto const sleRippleState = view.peek(trustLineKey); + auto const sleRippleState = ctx.view.peek(trustLineKey); if (!sleRippleState) return tecINTERNAL; // LCOV_EXCL_LINE @@ -150,7 +173,7 @@ escrowUnlockApplyHelper( // if destination is not the issuer then transfer funds if (!receiverIssuer) { - auto const ter = directSendNoFee(view, issuer, receiver, finalAmt, true, journal); + auto const ter = directSendNoFee(ctx.view, issuer, receiver, finalAmt, true, journal); if (!isTesSuccess(ter)) return ter; // LCOV_EXCL_LINE } @@ -160,10 +183,10 @@ escrowUnlockApplyHelper( template <> inline TER escrowUnlockApplyHelper( - ApplyView& view, + ApplyViewContext ctx, Rate lockedRate, SLE::ref sleDest, - STAmount const& xrpBalance, + XRPAmount xrpBalance, STAmount const& amount, AccountID const& issuer, AccountID const& sender, @@ -175,28 +198,33 @@ escrowUnlockApplyHelper( bool const receiverIssuer = issuer == receiver; auto const mptID = amount.get().getMptID(); - auto const issuanceKey = keylet::mptIssuance(mptID); - if (!view.exists(keylet::mptoken(issuanceKey.key, receiver)) && createAsset && !receiverIssuer) + auto const issuanceKey = keylet::mptokenIssuance(mptID); + auto const mptKeylet = keylet::mptoken(issuanceKey.key, receiver); + if (!ctx.view.exists(mptKeylet) && createAsset && !receiverIssuer) { - if (std::uint32_t const ownerCount = {sleDest->at(sfOwnerCount)}; - xrpBalance < view.fees().accountReserve(ownerCount + 1)) - { - return tecINSUFFICIENT_RESERVE; - } + auto const sponsorSle = getEffectiveTxReserveSponsor(ctx, sleDest); + if (!sponsorSle) + return sponsorSle.error(); // LCOV_EXCL_LINE - if (auto const ter = createMPToken(view, mptID, receiver, 0); !isTesSuccess(ter)) + if (auto const ret = checkReserve( + ctx, sleDest, xrpBalance, *sponsorSle, {.ownerCountDelta = 1}, journal); + !isTesSuccess(ret)) + return ret; + + if (auto const ter = createMPToken(ctx.view, mptID, receiver, *sponsorSle, 0); + !isTesSuccess(ter)) { return ter; // LCOV_EXCL_LINE } // update owner count. - adjustOwnerCount(view, sleDest, 1, journal); + increaseOwnerCount(ctx.view, sleDest, *sponsorSle, 1, journal); } - if (!view.exists(keylet::mptoken(issuanceKey.key, receiver)) && !receiverIssuer) + if (!ctx.view.exists(mptKeylet) && !receiverIssuer) return tecNO_PERMISSION; - auto const xferRate = transferRate(view, amount); + auto const xferRate = transferRate(ctx.view, amount); // update if issuer rate is less than locked rate if (xferRate < lockedRate) lockedRate = xferRate; @@ -219,11 +247,11 @@ escrowUnlockApplyHelper( finalAmt = amount.value() - xferFee; } return unlockEscrowMPT( - view, + ctx.view, sender, receiver, finalAmt, - view.rules().enabled(fixTokenEscrowV1) ? amount : finalAmt, + ctx.view.rules().enabled(fixTokenEscrowV1) ? amount : finalAmt, journal); } diff --git a/include/xrpl/ledger/helpers/LendingHelpers.h b/include/xrpl/ledger/helpers/LendingHelpers.h index 8de945233b..e2605e9ab7 100644 --- a/include/xrpl/ledger/helpers/LendingHelpers.h +++ b/include/xrpl/ledger/helpers/LendingHelpers.h @@ -1,11 +1,28 @@ #pragma once -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // IWYU pragma: keep +#include #include -#include +#include +#include +#include +#include // IWYU pragma: keep +#include +#include +#include +#include #include #include +#include namespace xrpl { @@ -46,7 +63,9 @@ static constexpr std::uint32_t kSecondsInYear = 365 * 24 * 60 * 60; Number loanPeriodicRate(TenthBips32 interestRate, std::uint32_t paymentInterval); -/// Ensure the periodic payment is always rounded consistently +/** + * Ensure the periodic payment is always rounded consistently + */ inline Number roundPeriodicPayment(Asset const& asset, Number const& periodicPayment, std::int32_t scale) { @@ -110,7 +129,8 @@ struct LoanPaymentParts operator==(LoanPaymentParts const& other) const; }; -/** This structure captures the parts of a loan state. +/** + * This structure captures the parts of a loan state. * * Whether the values are theoretical (unrounded) or rounded will depend on how * it was computed. @@ -307,12 +327,14 @@ struct PaymentComponents // - extra: An additional payment beyond the regular schedule (overpayment) PaymentSpecialCase specialCase = PaymentSpecialCase::None; - // Calculates the tracked interest portion of this payment. - // This is derived from the other components as: - // trackedValueDelta - trackedPrincipalDelta - trackedManagementFeeDelta - // - // @return The amount of tracked interest included in this payment that - // will be paid to the vault. + /** + * Calculates the tracked interest portion of this payment. + * This is derived from the other components as: + * trackedValueDelta - trackedPrincipalDelta - trackedManagementFeeDelta + * + * @return The amount of tracked interest included in this payment that + * will be paid to the vault. + */ [[nodiscard]] Number trackedInterestPart() const; }; @@ -384,7 +406,8 @@ struct LoanStateDeltas // The difference in management fee outstanding between two loan states. Number managementFee; - /* Calculates the total change across all components. + /** + * Calculates the total change across all components. * @return The sum of principal, interest, and management fee deltas. */ [[nodiscard]] Number diff --git a/include/xrpl/ledger/helpers/MPTokenHelpers.h b/include/xrpl/ledger/helpers/MPTokenHelpers.h index c709badab8..5418e5b26a 100644 --- a/include/xrpl/ledger/helpers/MPTokenHelpers.h +++ b/include/xrpl/ledger/helpers/MPTokenHelpers.h @@ -4,11 +4,17 @@ #include #include #include +#include +#include #include #include #include +#include #include +#include +#include +#include #include #include @@ -23,6 +29,17 @@ namespace xrpl { [[nodiscard]] bool isGlobalFrozen(ReadView const& view, MPTIssue const& mptIssue); +/** + * Returns true if @p account's MPToken for @p mptIssue carries the + * individual-lock flag (lsfMPTLocked). + * + * @warning This checks only the raw per-holder lock bit. It does **not** + * perform the transitive vault pseudo-account check: if @p mptIssue is a + * vault share whose underlying asset is frozen, this function returns false. + * Call @ref isFrozen instead when determining whether an account may send or + * receive tokens — it combines isIndividualFrozen, isGlobalFrozen, and + * isVaultPseudoAccountFrozen into a single complete check. + */ [[nodiscard]] bool isIndividualFrozen(ReadView const& view, AccountID const& account, MPTIssue const& mptIssue); @@ -46,7 +63,8 @@ isAnyFrozen( // //------------------------------------------------------------------------------ -/** Returns MPT transfer fee as Rate. Rate specifies +/** + * Returns MPT transfer fee as Rate. Rate specifies * the fee as fractions of 1 billion. For example, 1% transfer rate * is represented as 1,010,000,000. * @param issuanceID MPTokenIssuanceID of MPTTokenIssuance object @@ -71,7 +89,7 @@ canAddHolding(ReadView const& view, MPTIssue const& mptIssue); [[nodiscard]] TER authorizeMPToken( - ApplyView& view, + ApplyViewContext ctx, XRPAmount const& priorBalance, MPTID const& mptIssuanceID, AccountID const& account, @@ -79,7 +97,8 @@ authorizeMPToken( std::uint32_t flags = 0, std::optional holderID = std::nullopt); -/** Check if the account lacks required authorization for MPT. +/** + * Check if the account lacks required authorization for MPT. * * requireAuth check is recursive for MPT shares in a vault, descending to * assets in the vault, up to maxAssetCheckDepth recursion depth. This is @@ -94,7 +113,8 @@ requireAuth( AuthType authType = AuthType::Legacy, std::uint8_t depth = 0); -/** Enforce account has MPToken to match its authorization. +/** + * Enforce account has MPToken to match its authorization. * * Called from doApply - it will check for expired (and delete if found any) * credentials matching DomainID set in MPTokenIssuance. Must be called if @@ -102,50 +122,52 @@ requireAuth( */ [[nodiscard]] TER enforceMPTokenAuthorization( - ApplyView& view, + ApplyViewContext ctx, MPTID const& mptIssuanceID, AccountID const& account, XRPAmount const& priorBalance, beast::Journal j); -/** Resolve the underlying asset of a vault share. +/** + * Resolve the underlying asset of a vault share. * - * Reads sfReferenceHolding from @p sleShareIssuance to determine which - * asset the vault wraps. @p sleHolding must be the SLE that - * sfReferenceHolding points to — either an ltMPTOKEN (returns its - * MPTIssue) or an ltRIPPLE_STATE (returns its low/high Issue). + * Reads sfReferenceHolding from @p sleShareIssuance to determine which + * asset the vault wraps. @p sleHolding must be the SLE that + * sfReferenceHolding points to — either an ltMPTOKEN (returns its + * MPTIssue) or an ltRIPPLE_STATE (returns its low/high Issue). * - * @pre Both SLEs must exist and @p sleHolding must be of type ltMPTOKEN - * or ltRIPPLE_STATE. Passing any other type is undefined behaviour. - * @param sleShareIssuance MPTokenIssuance SLE for the vault share token. - * @param sleHolding SLE referenced by sfReferenceHolding. - * @return The underlying Asset (MPTIssue or Issue). + * @pre Both SLEs must exist and @p sleHolding must be of type ltMPTOKEN + * or ltRIPPLE_STATE. Passing any other type is undefined behaviour. + * @param sleShareIssuance MPTokenIssuance SLE for the vault share token. + * @param sleHolding SLE referenced by sfReferenceHolding. + * @return The underlying Asset (MPTIssue or Issue). */ [[nodiscard]] Asset assetOfHolding(SLE const& sleShareIssuance, SLE const& sleHolding); -/** Check whether @p to may receive the given MPT from @p from. +/** + * Check whether @p to may receive the given MPT from @p from. * - * The check passes when any of the following is true: - * - @p waive is WaiveMPTCanTransfer::Yes (recovery-path exemption), or - * - @p from or @p to is the issuer, or - * - lsfMPTCanTransfer is set on the MPTokenIssuance. + * The check passes when any of the following is true: + * - @p waive is WaiveMPTCanTransfer::Yes (recovery-path exemption), or + * - @p from or @p to is the issuer, or + * - lsfMPTCanTransfer is set on the MPTokenIssuance. * - * For vault shares (MPTokenIssuances that carry sfReferenceHolding) the - * check recurses into the underlying asset's transferability. This - * recursion is defensive; vault-of-vault-shares is rejected at vault - * creation, so in practice depth never exceeds 1. + * For vault shares (MPTokenIssuances that carry sfReferenceHolding) the + * check recurses into the underlying asset's transferability. This + * recursion is defensive; vault-of-vault-shares is rejected at vault + * creation, so in practice depth never exceeds 1. * - * @param view Ledger state to read from. - * @param mptIssue The MPT issuance being transferred. - * @param from Sending account. - * @param to Receiving account. - * @param waive WaiveMPTCanTransfer::Yes skips the lsfMPTCanTransfer - * check. Use for recovery paths (e.g. unwinding SAV or - * Lending Protocol positions after an issuer revokes - * transferability). - * @param depth Recursion depth; bounded at kMaxAssetCheckDepth. - * @return tesSUCCESS if the transfer is allowed, tecNO_AUTH otherwise. + * @param view Ledger state to read from. + * @param mptIssue The MPT issuance being transferred. + * @param from Sending account. + * @param to Receiving account. + * @param waive WaiveMPTCanTransfer::Yes skips the lsfMPTCanTransfer + * check. Use for recovery paths (e.g. unwinding SAV or + * Lending Protocol positions after an issuer revokes + * transferability). + * @param depth Recursion depth; bounded at kMaxAssetCheckDepth. + * @return tesSUCCESS if the transfer is allowed, tecNO_AUTH otherwise. */ [[nodiscard]] TER canTransfer( @@ -156,22 +178,24 @@ canTransfer( WaiveMPTCanTransfer waive = WaiveMPTCanTransfer::No, std::uint8_t depth = 0); -/** Check whether @p asset may be traded on the DEX. +/** + * Check whether @p asset may be traded on the DEX. * - * For IOU assets the check delegates to the existing offer/AMM freeze - * logic. For MPT assets it checks lsfMPTCanTrade on the MPTokenIssuance. - * Vault shares recurse into the underlying asset's tradability via - * sfReferenceHolding; depth is bounded at kMaxAssetCheckDepth. + * For IOU assets the check delegates to the existing offer/AMM freeze + * logic. For MPT assets it checks lsfMPTCanTrade on the MPTokenIssuance. + * Vault shares recurse into the underlying asset's tradability via + * sfReferenceHolding; depth is bounded at kMaxAssetCheckDepth. * - * @param view Ledger state to read from. - * @param asset The asset to check. - * @param depth Recursion depth; bounded at kMaxAssetCheckDepth. - * @return tesSUCCESS if trading is allowed, tecNO_PERMISSION otherwise. + * @param view Ledger state to read from. + * @param asset The asset to check. + * @param depth Recursion depth; bounded at kMaxAssetCheckDepth. + * @return tesSUCCESS if trading is allowed, tecNO_PERMISSION otherwise. */ [[nodiscard]] TER canTrade(ReadView const& view, Asset const& asset, std::uint8_t depth = 0); -/** Convenience to combine canTrade/Transfer. Returns tesSUCCESS if Asset is Issue. +/** + * Convenience to combine canTrade/Transfer. Returns tesSUCCESS if Asset is Issue. */ [[nodiscard]] TER canMPTTradeAndTransfer( @@ -188,7 +212,7 @@ canMPTTradeAndTransfer( [[nodiscard]] TER addEmptyHolding( - ApplyView& view, + ApplyViewContext ctx, AccountID const& accountID, XRPAmount priorBalance, MPTIssue const& mptIssue, @@ -196,7 +220,7 @@ addEmptyHolding( [[nodiscard]] TER removeEmptyHolding( - ApplyView& view, + ApplyViewContext ctx, AccountID const& accountID, MPTIssue const& mptIssue, beast::Journal journal); @@ -228,6 +252,7 @@ createMPToken( ApplyView& view, MPTID const& mptIssuanceID, AccountID const& account, + SLE::ref sponsorSle, std::uint32_t const flags); TER @@ -235,6 +260,7 @@ checkCreateMPT( xrpl::ApplyView& view, xrpl::MPTIssue const& mptIssue, xrpl::AccountID const& holder, + SLE::ref sponsorSle, beast::Journal j); //------------------------------------------------------------------------------ @@ -255,7 +281,8 @@ availableMPTAmount(SLE const& sleIssuance); std::int64_t availableMPTAmount(ReadView const& view, MPTID const& mptID); -/** Checks for two types of OutstandingAmount overflow during a send operation. +/** + * Checks for two types of OutstandingAmount overflow during a send operation. * 1. **Direct directSendNoFee (Overflow: No):** A true overflow check when * `OutstandingAmount > MaximumAmount`. This threshold is used for direct * directSendNoFee transactions that bypass the payment engine. @@ -280,7 +307,8 @@ isMPTOverflow( [[nodiscard]] STAmount issuerFundsToSelfIssue(ReadView const& view, MPTIssue const& issue); -/** Facilitate tracking of MPT sold by an issuer owning MPT sell offer. +/** + * Facilitate tracking of MPT sold by an issuer owning MPT sell offer. * See ApplyView::issuerSelfDebitHookMPT(). */ void diff --git a/include/xrpl/ledger/helpers/NFTokenHelpers.h b/include/xrpl/ledger/helpers/NFTokenHelpers.h index 362cfe5a8c..d9d195c559 100644 --- a/include/xrpl/ledger/helpers/NFTokenHelpers.h +++ b/include/xrpl/ledger/helpers/NFTokenHelpers.h @@ -1,30 +1,48 @@ #pragma once -#include +#include #include +#include #include +#include #include +#include +#include +#include +#include +#include +#include +#include #include #include -#include +#include +#include +#include +#include #include namespace xrpl::nft { -/** Delete up to a specified number of offers from the specified token offer - * directory. */ +/** + * Delete up to a specified number of offers from the specified token offer + * directory. + */ std::size_t removeTokenOffersWithLimit( ApplyView& view, Keylet const& directory, std::size_t maxDeletableOffers); -/** Finds the specified token in the owner's token directory. */ +/** + * Finds the specified token in the owner's token directory. + */ std::optional findToken(ReadView const& view, AccountID const& owner, uint256 const& nftokenID); -/** Finds the token in the owner's token directory. Returns token and page. */ +/** + * Finds the token in the owner's token directory. Returns token and page. + */ struct TokenAndPage { STObject token; @@ -37,33 +55,39 @@ struct TokenAndPage std::optional findTokenAndPage(ApplyView& view, AccountID const& owner, uint256 const& nftokenID); -/** Insert the token in the owner's token directory. */ +/** + * Insert the token in the owner's token directory. + */ TER insertToken(ApplyView& view, AccountID owner, STObject&& nft); -/** Remove the token from the owner's token directory. */ +/** + * Remove the token from the owner's token directory. + */ TER removeToken(ApplyView& view, AccountID const& owner, uint256 const& nftokenID); TER removeToken(ApplyView& view, AccountID const& owner, uint256 const& nftokenID, SLE::ref page); -/** Deletes the given token offer. - - An offer is tracked in two separate places: - - The token's 'buy' directory, if it's a buy offer; or - - The token's 'sell' directory, if it's a sell offer; and - - The owner directory of the account that placed the offer. - - The offer also consumes one incremental reserve. +/** + * Deletes the given token offer. + * + * An offer is tracked in two separate places: + * - The token's 'buy' directory, if it's a buy offer; or + * - The token's 'sell' directory, if it's a sell offer; and + * - The owner directory of the account that placed the offer. + * + * The offer also consumes one incremental reserve. */ bool deleteTokenOffer(ApplyView& view, SLE::ref offer); -/** Repairs the links in an NFTokenPage directory. - - Returns true if a repair took place, otherwise false. -*/ +/** + * Repairs the links in an NFTokenPage directory. + * + * Returns true if a repair took place, otherwise false. + */ bool repairNFTokenDirectoryLinks(ApplyView& view, AccountID const& owner); @@ -77,7 +101,9 @@ changeTokenURI( uint256 const& nftokenID, std::optional const& uri); -/** Preflight checks shared by NFTokenCreateOffer and NFTokenMint */ +/** + * Preflight checks shared by NFTokenCreateOffer and NFTokenMint + */ NotTEC tokenOfferCreatePreflight( AccountID const& acctID, @@ -89,7 +115,9 @@ tokenOfferCreatePreflight( std::optional const& owner = std::nullopt, std::uint32_t txFlags = tfSellNFToken); -/** Preclaim checks shared by NFTokenCreateOffer and NFTokenMint */ +/** + * Preclaim checks shared by NFTokenCreateOffer and NFTokenMint + */ TER tokenOfferCreatePreclaim( ReadView const& view, @@ -103,7 +131,9 @@ tokenOfferCreatePreclaim( std::optional const& owner = std::nullopt, std::uint32_t txFlags = tfSellNFToken); -/** doApply implementation shared by NFTokenCreateOffer and NFTokenMint */ +/** + * doApply implementation shared by NFTokenCreateOffer and NFTokenMint + */ TER tokenOfferCreateApply( ApplyView& view, diff --git a/include/xrpl/ledger/helpers/OfferHelpers.h b/include/xrpl/ledger/helpers/OfferHelpers.h index fc863dff0a..524288ea33 100644 --- a/include/xrpl/ledger/helpers/OfferHelpers.h +++ b/include/xrpl/ledger/helpers/OfferHelpers.h @@ -7,18 +7,19 @@ namespace xrpl { -/** Delete an offer. - - Requirements: - The offer must exist. - The caller must have already checked permissions. - - @param view The ApplyView to modify. - @param sle The offer to delete. - @param j Journal for logging. - - @return tesSUCCESS on success, otherwise an error code. -*/ +/** + * Delete an offer. + * + * Requirements: + * The offer must exist. + * The caller must have already checked permissions. + * + * @param view The ApplyView to modify. + * @param sle The offer to delete. + * @param j Journal for logging. + * + * @return tesSUCCESS on success, otherwise an error code. + */ // [[nodiscard]] // nodiscard commented out so Flow, BookTip and others compile. TER offerDelete(ApplyView& view, SLE::ref sle, beast::Journal j); diff --git a/include/xrpl/ledger/helpers/OracleHelpers.h b/include/xrpl/ledger/helpers/OracleHelpers.h new file mode 100644 index 0000000000..da04618e46 --- /dev/null +++ b/include/xrpl/ledger/helpers/OracleHelpers.h @@ -0,0 +1,31 @@ +#pragma once + +#include +#include // IWYU pragma: keep +#include + +#include +#include + +namespace xrpl { + +constexpr std::uint32_t kMinOracleReserveCount = 1; +constexpr std::uint32_t kMaxOracleReserveCount = 2; +constexpr std::size_t kOracleReserveCountThreshold = 5; + +template + requires requires(T const& t) { t.size(); } +inline std::uint32_t +calculateOracleReserve(T const& priceDataSeries) +{ + return priceDataSeries.size() > kOracleReserveCountThreshold ? kMaxOracleReserveCount + : kMinOracleReserveCount; +} + +inline std::uint32_t +calculateOracleReserve(SLE::const_ref oracleSle) +{ + return calculateOracleReserve(oracleSle->getFieldArray(sfPriceDataSeries)); +} + +} // namespace xrpl diff --git a/include/xrpl/ledger/helpers/PaymentChannelHelpers.h b/include/xrpl/ledger/helpers/PaymentChannelHelpers.h index 3c08ee9f32..5e1f590c58 100644 --- a/include/xrpl/ledger/helpers/PaymentChannelHelpers.h +++ b/include/xrpl/ledger/helpers/PaymentChannelHelpers.h @@ -1,47 +1,51 @@ #pragma once +#include #include #include +#include +#include #include -#include #include -#include #include namespace xrpl { -/** Close a payment channel and return its remaining funds to the channel owner. +/** + * Close a payment channel and return its remaining funds to the channel owner. * - * @param slep The SLE for the PayChannel object to close. - * @param view The apply view in which ledger state modifications are made. - * @param key The ledger key identifying the PayChannel entry. - * @param j Journal used for fatal-level diagnostic messages. - * @return tesSUCCESS on success; tefBAD_LEDGER if a directory removal - * fails; tefINTERNAL if the source account SLE cannot be found. + * @param slep The SLE for the PayChannel object to close. + * @param view The apply view in which ledger state modifications are made. + * @param key The ledger key identifying the PayChannel entry. + * @param j Journal used for fatal-level diagnostic messages. + * @return tesSUCCESS on success; tefBAD_LEDGER if a directory removal + * fails; tefINTERNAL if the source account SLE cannot be found. */ TER closeChannel(SLE::ref slep, ApplyView& view, uint256 const& key, beast::Journal j); -/** Add two uint32_t values with saturation at UINT32_MAX. +/** + * Add two uint32_t values with saturation at UINT32_MAX. * - * @param rules The current ledger rules used to check amendment status. - * @param lhs Left-hand operand. - * @param rhs Right-hand operand. - * @return @p lhs + @p rhs, saturated at UINT32_MAX when the amendment - * is active. + * @param rules The current ledger rules used to check amendment status. + * @param lhs Left-hand operand. + * @param rhs Right-hand operand. + * @return @p lhs + @p rhs, saturated at UINT32_MAX when the amendment + * is active. */ uint32_t saturatingAdd(Rules const& rules, uint32_t const lhs, uint32_t const rhs); -/** Determine whether a payment channel time field represents an expired time. +/** + * Determine whether a payment channel time field represents an expired time. * - * @param view The apply view providing the parent close time and rules. - * @param timeField The optional expiry timestamp (seconds since the XRP - * Ledger epoch). If empty, the function returns false. - * @return @c true if @p timeField is set and the indicated time is - * in the past relative to the view's parent close time; - * @c false otherwise. + * @param view The apply view providing the parent close time and rules. + * @param timeField The optional expiry timestamp (seconds since the XRP + * Ledger epoch). If empty, the function returns false. + * @return @c true if @p timeField is set and the indicated time is + * in the past relative to the view's parent close time; + * @c false otherwise. */ bool isChannelExpired(ApplyView const& view, std::optional timeField); diff --git a/include/xrpl/ledger/helpers/PermissionedDEXHelpers.h b/include/xrpl/ledger/helpers/PermissionedDEXHelpers.h index 695a4950f0..12681257aa 100644 --- a/include/xrpl/ledger/helpers/PermissionedDEXHelpers.h +++ b/include/xrpl/ledger/helpers/PermissionedDEXHelpers.h @@ -1,6 +1,10 @@ #pragma once -#include +#include +#include +#include +#include +#include namespace xrpl::permissioned_dex { diff --git a/include/xrpl/ledger/helpers/RippleStateHelpers.h b/include/xrpl/ledger/helpers/RippleStateHelpers.h index 3aaaa541fd..a0508d074f 100644 --- a/include/xrpl/ledger/helpers/RippleStateHelpers.h +++ b/include/xrpl/ledger/helpers/RippleStateHelpers.h @@ -1,14 +1,21 @@ #pragma once +#include #include #include #include #include +#include #include #include #include #include #include +#include +#include + +#include +#include //------------------------------------------------------------------------------ // @@ -24,13 +31,14 @@ namespace xrpl { // //------------------------------------------------------------------------------ -/** Calculate the maximum amount of IOUs that an account can hold - @param view the ledger to check against. - @param account the account of interest. - @param issuer the issuer of the IOU. - @param currency the IOU to check. - @return The maximum amount that can be held. -*/ +/** + * Calculate the maximum amount of IOUs that an account can hold + * @param view the ledger to check against. + * @param account the account of interest. + * @param issuer the issuer of the IOU. + * @param currency the IOU to check. + * @return The maximum amount that can be held. + */ /** @{ */ STAmount creditLimit( @@ -43,12 +51,13 @@ IOUAmount creditLimit2(ReadView const& v, AccountID const& acc, AccountID const& iss, Currency const& cur); /** @} */ -/** Returns the amount of IOUs issued by issuer that are held by an account - @param view the ledger to check against. - @param account the account of interest. - @param issuer the issuer of the IOU. - @param currency the IOU to check. -*/ +/** + * Returns the amount of IOUs issued by issuer that are held by an account + * @param view the ledger to check against. + * @param account the account of interest. + * @param issuer the issuer of the IOU. + * @param currency the IOU to check. + */ /** @{ */ STAmount creditBalance( @@ -127,10 +136,11 @@ checkDeepFrozen(ReadView const& view, AccountID const& account, Issue const& iss // //------------------------------------------------------------------------------ -/** Create a trust line - - This can set an initial balance. -*/ +/** + * Create a trust line + * + * This can set an initial balance. + */ [[nodiscard]] TER trustCreate( ApplyView& view, @@ -149,6 +159,7 @@ trustCreate( // Issuer should be the account being set. std::uint32_t uQualityIn, std::uint32_t uQualityOut, + SLE::ref sponsorSle, beast::Journal j); [[nodiscard]] TER @@ -171,6 +182,7 @@ issueIOU( AccountID const& account, STAmount const& amount, Issue const& issue, + SLE::ref sponsorSle, beast::Journal j); [[nodiscard]] TER @@ -187,7 +199,8 @@ redeemIOU( // //------------------------------------------------------------------------------ -/** Check if the account lacks required authorization. +/** + * Check if the account lacks required authorization. * * Return tecNO_AUTH or tecNO_LINE if it does * and tesSUCCESS otherwise. @@ -211,7 +224,8 @@ requireAuth( AccountID const& account, AuthType authType = AuthType::Legacy); -/** Check if the destination account is allowed +/** + * Check if the destination account is allowed * to receive IOU. Return terNO_RIPPLE if rippling is * disabled on both sides and tesSUCCESS otherwise. */ @@ -224,11 +238,13 @@ canTransfer(ReadView const& view, Issue const& issue, AccountID const& from, Acc // //------------------------------------------------------------------------------ -/// Any transactors that call addEmptyHolding() in doApply must call -/// canAddHolding() in preflight with the same View and Asset +/** + * Any transactors that call addEmptyHolding() in doApply must call + * canAddHolding() in preflight with the same View and Asset + */ [[nodiscard]] TER addEmptyHolding( - ApplyView& view, + ApplyViewContext ctx, AccountID const& accountID, XRPAmount priorBalance, Issue const& issue, @@ -236,12 +252,13 @@ addEmptyHolding( [[nodiscard]] TER removeEmptyHolding( - ApplyView& view, + ApplyViewContext ctx, AccountID const& accountID, Issue const& issue, beast::Journal journal); -/** Delete trustline to AMM. The passed `sle` must be obtained from a prior +/** + * Delete trustline to AMM. The passed `sle` must be obtained from a prior * call to view.peek(). Fail if neither side of the trustline is AMM or * if ammAccountID is seated and is not one of the trustline's side. */ @@ -252,7 +269,8 @@ deleteAMMTrustLine( std::optional const& ammAccountID, beast::Journal j); -/** Delete AMMs MPToken. The passed `sle` must be obtained from a prior +/** + * Delete AMMs MPToken. The passed `sle` must be obtained from a prior * call to view.peek(). */ [[nodiscard]] TER diff --git a/include/xrpl/ledger/helpers/SponsorHelpers.h b/include/xrpl/ledger/helpers/SponsorHelpers.h new file mode 100644 index 0000000000..98bf419140 --- /dev/null +++ b/include/xrpl/ledger/helpers/SponsorHelpers.h @@ -0,0 +1,204 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace xrpl { + +/** + * Whether the given transaction type may use reserve sponsorship (v1). + * + * Reserve sponsorship is restricted to an explicit allow-list of transaction + * types; all others reject spfSponsorReserve at preflight. + */ +bool +isReserveSponsorAllowed(TxType txType); + +/** + * Whether the transaction's fee is sponsored (sfSponsor present + spfSponsorFee set). + */ +inline bool +isFeeSponsored(STTx const& tx) +{ + return tx.isFieldPresent(sfSponsor) && ((tx.getFieldU32(sfSponsorFlags) & spfSponsorFee) != 0u); +} + +/** + * Whether the transaction's reserve is sponsored (sfSponsor present + spfSponsorReserve set). + */ +inline bool +isReserveSponsored(STTx const& tx) +{ + return tx.isFieldPresent(sfSponsor) && + ((tx.getFieldU32(sfSponsorFlags) & spfSponsorReserve) != 0u); +} + +/** + * Return the AccountID of the transaction's reserve sponsor, or nullopt if unsponsored. + */ +std::optional +getTxReserveSponsorID(STTx const& tx); + +/** + * Return a mutable SLE for the transaction's reserve sponsor account. + * + * @param ctx The apply-view context (view + tx) + * @return The sponsor account SLE, a null pointer if the tx is not + * reserve-sponsored, or tecINTERNAL if the sponsor account cannot + * be loaded (an already-checked invariant). + */ +std::expected +getTxReserveSponsor(ApplyViewContext ctx); + +/** + * Return a read-only SLE for the transaction's reserve sponsor account. + * + * @param view The ledger read view + * @param tx The transaction to inspect + * @return The sponsor account SLE, a null pointer if the tx is not + * reserve-sponsored, or tecINTERNAL if the sponsor account cannot + * be loaded (an already-checked invariant). + */ +std::expected +getTxReserveSponsor(ReadView const& view, STTx const& tx); + +/** + * The transaction's reserve sponsor for the given account, if applicable. + * + * A reserve sponsor only covers the transaction submitter's own objects, so + * this returns the tx reserve sponsor SLE only when accountSle is the tx's own + * (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 + * that the sponsor-deriving helper overloads in AccountRootHelpers rely on. + * + * @param ctx The apply-view context (view + tx) + * @param accountSle The account whose sponsor is being resolved + * @return The sponsor SLE (nullptr if unsponsored), or tecINTERNAL if the + * sponsor account cannot be loaded (an already-checked invariant) + */ +[[nodiscard]] std::expected +getEffectiveTxReserveSponsor(ApplyViewContext ctx, SLE::const_ref accountSle); + +/** + * Return the AccountID stored in the given sponsor field of a ledger entry, or nullopt if absent. + */ +std::optional +getLedgerEntryReserveSponsorID(SLE::const_ref sle, SF_ACCOUNT const& field = sfSponsor); + +/** + * Return a mutable SLE for the reserve sponsor recorded on a ledger entry. + * + * Reads the sponsor AccountID from @p field on @p sle and peeks the + * corresponding account root in @p view. + * + * @param view The mutable apply view + * @param sle The ledger entry whose sponsor field is inspected + * @param field The field that holds the sponsor AccountID (defaults to sfSponsor) + * @return The sponsor account SLE, or a null pointer if the entry is unsponsored. + */ +SLE::pointer +getLedgerEntryReserveSponsor( + ApplyView& view, + SLE::const_ref sle, + SF_ACCOUNT const& field = sfSponsor); + +/** + * Stamp a reserve sponsor onto a ledger entry using an explicit sponsor SLE. + * + * Sets @p field on @p sle to the AccountID from @p sponsorSle. A no-op when + * @p sponsorSle is null (unsponsored). For RippleState entries the field must + * be sfHighSponsor or sfLowSponsor; for all other entry types it must be + * sfSponsor. + * + * @param sle The ledger entry to stamp + * @param sponsorSle The sponsor's account root SLE (null → no-op) + * @param field The sponsor field to set (defaults to sfSponsor) + */ +void +addSponsorToLedgerEntry( + SLE::ref sle, + SLE::const_ref sponsorSle, + SF_ACCOUNT const& field = sfSponsor); + +/** + * Stamp the transaction's reserve sponsor onto a newly-created ledger entry. + * + * Equivalent to the overload above, but resolves the sponsor via + * getTxReserveSponsor(ctx) instead of taking it explicitly. A no-op when the + * transaction is not reserve-sponsored. The entry is assumed to be owned by + * the transaction submitter, which is the only account a tx reserve sponsor + * can cover. + */ +void +addSponsorToLedgerEntry(ApplyViewContext ctx, SLE::ref sle, SF_ACCOUNT const& field = sfSponsor); + +/** + * Remove the reserve sponsor field from a ledger entry. + * + * A no-op when @p field is not present on @p sle. For RippleState entries + * the field must be sfHighSponsor or sfLowSponsor; for all other entry types + * it must be sfSponsor. + * + * @param sle The ledger entry to modify + * @param field The sponsor field to clear (defaults to sfSponsor) + */ +void +removeSponsorFromLedgerEntry(SLE::ref sle, SF_ACCOUNT const& field = sfSponsor); + +/** + * Whether @p account is the owner of a ledger entry for sponsorship purposes. + * + * Ownership rules vary by entry type. For RippleState entries the owner is + * whichever side of the trust line holds the reserve. For credentials, the + * owner is the subject once accepted and the issuer before acceptance. + * + * @param view The ledger read view (used for SignerList lookup) + * @param sle The ledger entry whose owner is checked + * @param account The candidate account to match against + * @return true if @p account owns @p sle, false otherwise. + */ +bool +isLedgerEntryOwner(ReadView const& view, SLE const& sle, AccountID const& account); + +/** + * Whether this ledger entry type can have a reserve sponsor attached to it. + */ +bool +isLedgerEntrySupportedBySponsorship(SLE const& sle); + +/** + * Return the number of owner-count units the ledger entry consumes. + * + * Most entries cost 1. Exceptions: Oracles scale with their price-data series + * size, Vaults cost 2 (vault + pseudo-account), and legacy SignerList entries + * (pre-MultiSignReserve) cost 2 + signer count. + */ +std::uint32_t +getLedgerEntryOwnerCount(SLE const& sle); + +/** + * Return the SField used to store the reserve sponsor for @p owner on @p sle. + * + * For most entry types this is sfSponsor. RippleState entries use + * sfHighSponsor or sfLowSponsor depending on which side of the trust line + * @p owner holds. + * + * @param sle The ledger entry + * @param owner The account whose sponsor field is needed + * @return sfHighSponsor, sfLowSponsor, or sfSponsor as appropriate. + */ +SF_ACCOUNT const& +getLedgerEntrySponsorField(SLE const& sle, AccountID const& owner); + +} // namespace xrpl diff --git a/include/xrpl/ledger/helpers/TokenHelpers.h b/include/xrpl/ledger/helpers/TokenHelpers.h index f736e51d28..501101136a 100644 --- a/include/xrpl/ledger/helpers/TokenHelpers.h +++ b/include/xrpl/ledger/helpers/TokenHelpers.h @@ -1,15 +1,23 @@ #pragma once +#include #include #include #include +#include #include +#include #include #include #include +#include #include +#include +#include +#include #include +#include #include namespace xrpl { @@ -20,21 +28,30 @@ namespace xrpl { // //------------------------------------------------------------------------------ -/** Controls the treatment of frozen account balances */ +/** + * Controls the treatment of frozen account balances + */ enum class FreezeHandling { IgnoreFreeze, ZeroIfFrozen }; -/** Controls the treatment of unauthorized MPT balances */ +/** + * Controls the treatment of unauthorized MPT balances + */ enum class AuthHandling { IgnoreAuth, ZeroIfUnauthorized }; -/** Controls whether to include the account's full spendable balance */ +/** + * Controls whether to include the account's full spendable balance + */ enum class SpendableHandling { SimpleBalance, FullBalance }; enum class WaiveTransferFee : bool { No = false, Yes }; -/** Controls whether accountSend is allowed to overflow OutstandingAmount **/ +/** + * Controls whether accountSend is allowed to overflow OutstandingAmount * + */ enum class AllowMPTOverflow : bool { No = false, Yes }; -/** Controls whether canTransfer enforces lsfMPTCanTransfer on MPTs. +/** + * Controls whether canTransfer enforces lsfMPTCanTransfer on MPTs. * * Default is No (enforce). Use Yes at call sites that must remain available * even when an MPT issuer has cleared lsfMPTCanTransfer - for example, @@ -73,9 +90,9 @@ isIndividualFrozen(ReadView const& view, AccountID const& account, Asset const& checkIndividualFrozen(ReadView const& view, AccountID const& account, Asset const& asset); /** - * isFrozen check is recursive for MPT shares in a vault, descending to - * assets in the vault, up to maxAssetCheckDepth recursion depth. This is - * purely defensive, as we currently do not allow such vaults to be created. + * isFrozen check is recursive for MPT shares in a vault, descending to + * assets in the vault, up to maxAssetCheckDepth recursion depth. This is + * purely defensive, as we currently do not allow such vaults to be created. */ [[nodiscard]] bool isFrozen( @@ -114,9 +131,9 @@ isDeepFrozen( std::uint8_t depth = 0); /** - * isFrozen check is recursive for MPT shares in a vault, descending to - * assets in the vault, up to maxAssetCheckDepth recursion depth. This is - * purely defensive, as we currently do not allow such vaults to be created. + * isFrozen check is recursive for MPT shares in a vault, descending to + * assets in the vault, up to maxAssetCheckDepth recursion depth. This is + * purely defensive, as we currently do not allow such vaults to be created. */ [[nodiscard]] bool isDeepFrozen( @@ -131,6 +148,71 @@ checkDeepFrozen(ReadView const& view, AccountID const& account, MPTIssue const& [[nodiscard]] TER checkDeepFrozen(ReadView const& view, AccountID const& account, Asset const& asset); +/** + * Checks freeze compliance for withdrawing an asset from a pseudo-account (e.g. Vault, AMM, + * LoanBroker) to a destination account. + * + * Asserts that sourceAcct is a pseudo-account and that submitterAcct and dstAcct are not. + * + * Issuer exemption: returns tesSUCCESS immediately when dstAcct is the asset issuer — the issuer + * can always receive their own token, even when the pool is frozen. Callers that need to block + * withdrawals from a frozen pool even for the issuer (e.g. because the pool math cannot handle it) + * must check checkFrozen(sourceAcct, asset) separately before calling this function. + * + * Otherwise checks, in order: + * 1. If the asset is globally frozen the remaining checks are redundant. + * 2. The pseudo-account's trustline / MPToken must not be individually frozen for sending. + * 3. The submitter's trustline / MPToken must not be individually frozen. Skipped when + * submitter == dst (self-withdrawal) so a regular freeze does not prevent recovering one's own + * funds. (Enforced as defensive code; no current caller exercises a frozen submitter ≠ dst.) + * 4. The destination must not be deep-frozen. + * + * For IOUs a regular individual freeze on the submitter does NOT block self-withdrawal; only deep + * freeze does. For MPTs "locked" is equivalent to deep-frozen, so locked MPT holders are always + * blocked. + * + * @param view Ledger view to read freeze state from. + * @param pseudoAcct Pseudo-account the funds are withdrawn from (sender). + * @param submitterAcct Account that submitted the withdrawal transaction. + * @param dstAcct Account receiving the withdrawn funds. + * @param asset Asset being withdrawn. + * @return tesSUCCESS if the withdrawal is permitted, otherwise a freeze + * result (tecFROZEN for IOUs, tecLOCKED for MPTs). + */ +[[nodiscard]] TER +checkWithdrawFreeze( + ReadView const& view, + AccountID const& pseudoAcct, + AccountID const& submitterAcct, + AccountID const& dstAcct, + Asset const& asset); + +/** + * Checks freeze compliance for depositing an asset into a pseudo-account (e.g. Vault, AMM, + * LoanBroker). + * + * Checks, in order: + * 1. If the asset is globally frozen the remaining checks are redundant. + * 2. The depositor must not be individually frozen for the asset. Skipped when srcAcct is the + * asset issuer, since the issuer can always send its own asset. + * 3. The pseudo-account must not be individually frozen for the asset. Unlike regular accounts, + * pseudo-accounts cannot receive deposits under a regular freeze because the deposited funds + * could not later be withdrawn. + * + * @param view Ledger view to read freeze state from. + * @param srcAcct Depositor sending the funds. + * @param pseudoAcct Pseudo-account receiving the deposit. + * @param asset Asset being deposited. + * @return tesSUCCESS if the deposit is permitted, otherwise a freeze result + * (tecFROZEN for IOUs, tecLOCKED for MPTs). + */ +[[nodiscard]] TER +checkDepositFreeze( + ReadView const& view, + AccountID const& srcAcct, + AccountID const& pseudoAcct, + Asset const& asset); + //------------------------------------------------------------------------------ // // Account balance functions (Asset-based dispatchers) @@ -212,7 +294,8 @@ accountFunds( AuthHandling authHandling, beast::Journal j); -/** Returns the transfer fee as Rate based on the type of token +/** + * Returns the transfer fee as Rate based on the type of token * @param view The ledger view * @param amount The amount to transfer */ @@ -230,7 +313,7 @@ canAddHolding(ReadView const& view, Asset const& asset); [[nodiscard]] TER addEmptyHolding( - ApplyView& view, + ApplyViewContext ctx, AccountID const& accountID, XRPAmount priorBalance, Asset const& asset, @@ -238,7 +321,7 @@ addEmptyHolding( [[nodiscard]] TER removeEmptyHolding( - ApplyView& view, + ApplyViewContext ctx, AccountID const& accountID, Asset const& asset, beast::Journal journal); @@ -277,7 +360,8 @@ canTransfer( // --> bCheckIssuer : normally require issuer to be involved. // [[nodiscard]] // nodiscard commented out so DirectStep.cpp compiles. -/** Calls static directSendNoFeeIOU if saAmount represents Issue. +/** + * Calls static directSendNoFeeIOU if saAmount represents Issue. * Calls static directSendNoFeeMPT if saAmount represents MPTIssue. */ TER @@ -289,7 +373,8 @@ directSendNoFee( bool bCheckIssuer, beast::Journal j); -/** Calls static accountSendIOU if saAmount represents Issue. +/** + * Calls static accountSendIOU if saAmount represents Issue. * Calls static accountSendMPT if saAmount represents MPTIssue. */ [[nodiscard]] TER @@ -299,11 +384,13 @@ accountSend( AccountID const& to, STAmount const& saAmount, beast::Journal j, + SLE::ref sponsorSle = {}, WaiveTransferFee waiveFee = WaiveTransferFee::No, AllowMPTOverflow allowOverflow = AllowMPTOverflow::No); using MultiplePaymentDestinations = std::vector>; -/** Like accountSend, except one account is sending multiple payments (with the +/** + * Like accountSend, except one account is sending multiple payments (with the * same asset!) simultaneously * * Calls static accountSendMultiIOU if saAmount represents Issue. diff --git a/include/xrpl/ledger/helpers/VaultHelpers.h b/include/xrpl/ledger/helpers/VaultHelpers.h index 2344b4de77..1bd1663314 100644 --- a/include/xrpl/ledger/helpers/VaultHelpers.h +++ b/include/xrpl/ledger/helpers/VaultHelpers.h @@ -9,57 +9,63 @@ namespace xrpl { -/** From the perspective of a vault, return the number of shares to give - depositor when they offer a fixed amount of assets. Note, since shares are - MPT, this number is integral and always truncated in this calculation. - - @param vault The vault SLE. - @param issuance The MPTokenIssuance SLE for the vault's shares. - @param assets The amount of assets to convert. - - @return The number of shares, or nullopt on error. -*/ +/** + * From the perspective of a vault, return the number of shares to give + * depositor when they offer a fixed amount of assets. Note, since shares are + * MPT, this number is integral and always truncated in this calculation. + * + * @param vault The vault SLE. + * @param issuance The MPTokenIssuance SLE for the vault's shares. + * @param assets The amount of assets to convert. + * + * @return The number of shares, or nullopt on error. + */ [[nodiscard]] std::optional assetsToSharesDeposit(SLE::const_ref vault, SLE::const_ref issuance, STAmount const& assets); -/** From the perspective of a vault, return the number of assets to take from - depositor when they receive a fixed amount of shares. Note, since shares are - MPT, they are always an integral number. - - @param vault The vault SLE. - @param issuance The MPTokenIssuance SLE for the vault's shares. - @param shares The amount of shares to convert. - - @return The number of assets, or nullopt on error. -*/ +/** + * From the perspective of a vault, return the number of assets to take from + * depositor when they receive a fixed amount of shares. Note, since shares are + * MPT, they are always an integral number. + * + * @param vault The vault SLE. + * @param issuance The MPTokenIssuance SLE for the vault's shares. + * @param shares The amount of shares to convert. + * + * @return The number of assets, or nullopt on error. + */ [[nodiscard]] std::optional sharesToAssetsDeposit(SLE::const_ref vault, SLE::const_ref issuance, STAmount const& shares); -/** Controls whether to truncate shares instead of rounding. */ +/** + * Controls whether to truncate shares instead of rounding. + */ enum class TruncateShares : bool { No = false, Yes = true }; -/** Controls whether the withdraw conversion helpers - (assetsToSharesWithdraw and sharesToAssetsWithdraw) subtract - sfLossUnrealized from sfAssetsTotal before computing the exchange rate. - The default (No) applies the standard discounted rate; Yes is used when - the redeemer is the sole remaining shareholder. -*/ +/** + * Controls whether the withdraw conversion helpers + * (assetsToSharesWithdraw and sharesToAssetsWithdraw) subtract + * sfLossUnrealized from sfAssetsTotal before computing the exchange rate. + * The default (No) applies the standard discounted rate; Yes is used when + * the redeemer is the sole remaining shareholder. + */ enum class WaiveUnrealizedLoss : bool { No = false, Yes = true }; -/** From the perspective of a vault, return the number of shares to demand from - the depositor when they ask to withdraw a fixed amount of assets. Since - shares are MPT this number is integral, and it will be rounded to nearest - unless explicitly requested to be truncated instead. - - @param vault The vault SLE. - @param issuance The MPTokenIssuance SLE for the vault's shares. - @param assets The amount of assets to convert. - @param truncate Whether to truncate instead of rounding. - @param waive Whether to waive the unrealized-loss discount when computing - the exchange rate. - - @return The number of shares, or nullopt on error. -*/ +/** + * From the perspective of a vault, return the number of shares to demand from + * the depositor when they ask to withdraw a fixed amount of assets. Since + * shares are MPT this number is integral, and it will be rounded to nearest + * unless explicitly requested to be truncated instead. + * + * @param vault The vault SLE. + * @param issuance The MPTokenIssuance SLE for the vault's shares. + * @param assets The amount of assets to convert. + * @param truncate Whether to truncate instead of rounding. + * @param waive Whether to waive the unrealized-loss discount when computing + * the exchange rate. + * + * @return The number of shares, or nullopt on error. + */ [[nodiscard]] std::optional assetsToSharesWithdraw( SLE::const_ref vault, @@ -68,18 +74,19 @@ assetsToSharesWithdraw( TruncateShares truncate = TruncateShares::No, WaiveUnrealizedLoss waive = WaiveUnrealizedLoss::No); -/** From the perspective of a vault, return the number of assets to give the - depositor when they redeem a fixed amount of shares. Note, since shares are - MPT, they are always an integral number. - - @param vault The vault SLE. - @param issuance The MPTokenIssuance SLE for the vault's shares. - @param shares The amount of shares to convert. - @param waive Whether to waive (i.e. not subtract) the vault's unrealized - loss when computing the exchange rate. - - @return The number of assets, or nullopt on error. -*/ +/** + * From the perspective of a vault, return the number of assets to give the + * depositor when they redeem a fixed amount of shares. Note, since shares are + * MPT, they are always an integral number. + * + * @param vault The vault SLE. + * @param issuance The MPTokenIssuance SLE for the vault's shares. + * @param shares The amount of shares to convert. + * @param waive Whether to waive (i.e. not subtract) the vault's unrealized + * loss when computing the exchange rate. + * + * @return The number of assets, or nullopt on error. + */ [[nodiscard]] std::optional sharesToAssetsWithdraw( SLE::const_ref vault, @@ -87,15 +94,16 @@ sharesToAssetsWithdraw( STAmount const& shares, WaiveUnrealizedLoss waive = WaiveUnrealizedLoss::No); -/** Returns true iff `account` holds all of the vault's outstanding shares — - i.e. is the sole remaining shareholder. Returns false if the account - holds no shares or fewer than the total outstanding. - - @param view The ledger view. - @param account The candidate sole shareholder. - @param issuance The MPTokenIssuance SLE for the vault's shares; provides - both the share MPTID and the outstanding-amount total. -*/ +/** + * Returns true iff `account` holds all of the vault's outstanding shares — + * i.e. is the sole remaining shareholder. Returns false if the account + * holds no shares or fewer than the total outstanding. + * + * @param view The ledger view. + * @param account The candidate sole shareholder. + * @param issuance The MPTokenIssuance SLE for the vault's shares; provides + * both the share MPTID and the outstanding-amount total. + */ [[nodiscard]] bool isSoleShareholder(ReadView const& view, AccountID const& account, SLE::const_ref issuance); diff --git a/include/xrpl/net/AutoSocket.h b/include/xrpl/net/AutoSocket.h index 16ed0d6ca9..b98885959d 100644 --- a/include/xrpl/net/AutoSocket.h +++ b/include/xrpl/net/AutoSocket.h @@ -2,12 +2,20 @@ #include #include +#include #include #include #include #include +#include +#include +#include +#include +#include +#include + // Socket wrapper that supports both SSL and non-SSL connections. // Generally, handle it as you would an SSL connection. // To force a non-SSL connection, just don't call async_handshake. @@ -112,12 +120,9 @@ public: socket_->next_layer().async_receive( boost::asio::buffer(buffer_), boost::asio::socket_base::message_peek, - std::bind( - &AutoSocket::handleAutodetect, - this, - cbFunc, - std::placeholders::_1, - std::placeholders::_2)); + [this, cbFunc](error_code const& ec, size_t bytesTransferred) { + handleAutodetect(cbFunc, ec, bytesTransferred); + }); } } diff --git a/include/xrpl/net/HTTPClient.h b/include/xrpl/net/HTTPClient.h index 456f769922..752afac9c4 100644 --- a/include/xrpl/net/HTTPClient.h +++ b/include/xrpl/net/HTTPClient.h @@ -7,13 +7,15 @@ #include #include +#include #include #include #include namespace xrpl { -/** Provides an asynchronous HTTP client implementation with optional SSL. +/** + * Provides an asynchronous HTTP client implementation with optional SSL. */ class HTTPClient { @@ -29,14 +31,15 @@ public: bool sslVerify, beast::Journal j); - /** Destroys the global SSL context created by initializeSSLContext(). + /** + * Destroys the global SSL context created by initializeSSLContext(). * - * This releases the underlying boost::asio::ssl::context and any - * associated OpenSSL resources. Must not be called while any - * HTTPClient requests are in flight. + * This releases the underlying boost::asio::ssl::context and any + * associated OpenSSL resources. Must not be called while any + * HTTPClient requests are in flight. * - * @note Currently only called from tests during teardown. In production, - * the SSL context lives for the lifetime of the process. + * @note Currently only called from tests during teardown. In production, + * the SSL context lives for the lifetime of the process. */ static void cleanupSSLContext(); diff --git a/include/xrpl/net/HTTPClientSSLContext.h b/include/xrpl/net/HTTPClientSSLContext.h index ca1983f141..51b50a084c 100644 --- a/include/xrpl/net/HTTPClientSSLContext.h +++ b/include/xrpl/net/HTTPClientSSLContext.h @@ -10,6 +10,13 @@ #include #include +#include +#include + +#include +#include +#include + namespace xrpl { class HTTPClientSSLContext @@ -76,13 +83,12 @@ public: * * @return error_code indicating failures, if any */ - template < - class T, - class = std::enable_if_t< - std::is_same_v> || - std::is_same_v>>> + template boost::system::error_code preConnectVerify(T& strm, std::string const& host) + requires( + std::is_same_v> || + std::is_same_v>) { boost::system::error_code ec; if (!SSL_set_tlsext_host_name(strm.native_handle(), host.c_str())) @@ -96,11 +102,7 @@ public: return ec; } - template < - class T, - class = std::enable_if_t< - std::is_same_v> || - std::is_same_v>>> + template /** * @brief invoked after connect/async_connect but before sending data * on an ssl stream - to setup name verification. @@ -110,6 +112,9 @@ public: */ boost::system::error_code postConnectVerify(T& strm, std::string const& host) + requires( + std::is_same_v> || + std::is_same_v>) { boost::system::error_code ec; @@ -119,8 +124,9 @@ public: if (!ec) { strm.set_verify_callback( - std::bind( - &rfc6125Verify, host, std::placeholders::_1, std::placeholders::_2, j_), + [host, j = j_](bool preverified, boost::asio::ssl::verify_context& ctx) { + return rfc6125Verify(host, preverified, ctx, j); + }, ec); } } diff --git a/include/xrpl/net/RegisterSSLCerts.h b/include/xrpl/net/RegisterSSLCerts.h index e313b1cb06..004f893515 100644 --- a/include/xrpl/net/RegisterSSLCerts.h +++ b/include/xrpl/net/RegisterSSLCerts.h @@ -1,17 +1,18 @@ #pragma once -#include +#include #include namespace xrpl { -/** Register default SSL certificates. - - Register the system default SSL root certificates. On linux/mac, - this just calls asio's `set_default_verify_paths` to look in standard - operating system locations. On windows, it uses the OS certificate - store accessible via CryptoAPI. -*/ +/** + * Register default SSL certificates. + * + * Register the system default SSL root certificates. On linux/mac, + * this just calls asio's `set_default_verify_paths` to look in standard + * operating system locations. On windows, it uses the OS certificate + * store accessible via CryptoAPI. + */ void registerSSLCerts(boost::asio::ssl::context&, boost::system::error_code&, beast::Journal j); diff --git a/include/xrpl/nodestore/Backend.h b/include/xrpl/nodestore/Backend.h index 0061890237..564a874c5e 100644 --- a/include/xrpl/nodestore/Backend.h +++ b/include/xrpl/nodestore/Backend.h @@ -1,38 +1,51 @@ #pragma once +#include +#include +#include #include +#include #include +#include +#include +#include +#include +#include namespace xrpl::NodeStore { -/** A backend used for the NodeStore. - - The NodeStore uses a swappable backend so that other database systems - can be tried. Different databases may offer various features such - as improved performance, fault tolerant or distributed storage, or - all in-memory operation. - - A given instance of a backend is fixed to a particular key size. -*/ +/** + * A backend used for the NodeStore. + * + * The NodeStore uses a swappable backend so that other database systems + * can be tried. Different databases may offer various features such + * as improved performance, fault tolerant or distributed storage, or + * all in-memory operation. + * + * A given instance of a backend is fixed to a particular key size. + */ class Backend { public: - /** Destroy the backend. - - All open files are closed and flushed. If there are batched writes - or other tasks scheduled, they will be completed before this call - returns. - */ + /** + * Destroy the backend. + * + * All open files are closed and flushed. If there are batched writes + * or other tasks scheduled, they will be completed before this call + * returns. + */ virtual ~Backend() = default; - /** Get the human-readable name of this backend. - This is used for diagnostic output. - */ + /** + * Get the human-readable name of this backend. + * This is used for diagnostic output. + */ virtual std::string getName() = 0; - /** Get the block size for backends that support it + /** + * Get the block size for backends that support it */ [[nodiscard]] virtual std::optional getBlockSize() const @@ -40,25 +53,28 @@ public: return std::nullopt; } - /** Open the backend. - @param createIfMissing Create the database files if necessary. - This allows the caller to catch exceptions. - */ + /** + * Open the backend. + * @param createIfMissing Create the database files if necessary. + * This allows the caller to catch exceptions. + */ virtual void open(bool createIfMissing = true) = 0; - /** Returns true is the database is open. + /** + * Returns true is the database is open. */ virtual bool isOpen() = 0; - /** Open the backend. - @param createIfMissing Create the database files if necessary. - @param appType Deterministic appType used to create a backend. - @param uid Deterministic uid used to create a backend. - @param salt Deterministic salt used to create a backend. - @throws std::runtime_error is function is called not for NuDB backend. - */ + /** + * Open the backend. + * @param createIfMissing Create the database files if necessary. + * @param appType Deterministic appType used to create a backend. + * @param uid Deterministic uid used to create a backend. + * @param salt Deterministic salt used to create a backend. + * @throws std::runtime_error is function is called not for NuDB backend. + */ virtual void open(bool createIfMissing, uint64_t appType, uint64_t uid, uint64_t salt) { @@ -66,60 +82,70 @@ public: "Deterministic appType/uid/salt not supported by backend " + getName()); } - /** Close the backend. - This allows the caller to catch exceptions. - */ + /** + * Close the backend. + * This allows the caller to catch exceptions. + */ virtual void close() = 0; - /** Fetch a single object. - If the object is not found or an error is encountered, the - result will indicate the condition. - @note This will be called concurrently. - @param hash The hash of the object. - @param pObject [out] The created object if successful. - @return The result of the operation. - */ + /** + * Fetch a single object. + * If the object is not found or an error is encountered, the + * result will indicate the condition. + * @note This will be called concurrently. + * @param hash The hash of the object. + * @param pObject [out] The created object if successful. + * @return The result of the operation. + */ virtual Status fetch(uint256 const& hash, std::shared_ptr* pObject) = 0; - /** Store a single object. - Depending on the implementation this may happen immediately - or deferred using a scheduled task. - @note This will be called concurrently. - @param object The object to store. - */ + /** + * Store a single object. + * Depending on the implementation this may happen immediately + * or deferred using a scheduled task. + * @note This will be called concurrently. + * @param object The object to store. + */ virtual void store(std::shared_ptr const& object) = 0; - /** Store a group of objects. - @note This function will not be called concurrently with - itself or @ref store. - */ + /** + * Store a group of objects. + * @note This function will not be called concurrently with + * itself or @ref store. + */ virtual void storeBatch(Batch const& batch) = 0; virtual void sync() = 0; - /** Visit every object in the database - This is usually called during import. - @note This routine will not be called concurrently with itself - or other methods. - @see import - */ + /** + * Visit every object in the database + * This is usually called during import. + * @note This routine will not be called concurrently with itself + * or other methods. + * @see import + */ virtual void forEach(std::function)> f) = 0; - /** Estimate the number of write operations pending. */ + /** + * Estimate the number of write operations pending. + */ virtual int getWriteLoad() = 0; - /** Remove contents on disk upon destruction. */ + /** + * Remove contents on disk upon destruction. + */ virtual void setDeletePath() = 0; - /** Perform consistency checks on database. + /** + * Perform consistency checks on database. * * This method is implemented only by NuDBBackend. It is not yet called * anywhere, but it might be a good idea to one day call it at startup to @@ -130,7 +156,9 @@ public: { } - /** Returns the number of file descriptors the backend expects to need. */ + /** + * Returns the number of file descriptors the backend expects to need. + */ [[nodiscard]] virtual int fdRequired() const = 0; }; diff --git a/include/xrpl/nodestore/Database.h b/include/xrpl/nodestore/Database.h index 68c5dcefb6..96ba91bd76 100644 --- a/include/xrpl/nodestore/Database.h +++ b/include/xrpl/nodestore/Database.h @@ -1,13 +1,25 @@ #pragma once -#include -#include +#include +#include // IWYU pragma: keep +#include +#include +#include +#include #include #include #include -#include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include namespace xrpl { class Section; @@ -15,100 +27,109 @@ class Section; namespace xrpl::NodeStore { -/** Persistency layer for NodeObject - - A Node is a ledger object which is uniquely identified by a key, which is - the 256-bit hash of the body of the node. The payload is a variable length - block of serialized data. - - All ledger data is stored as node objects and as such, needs to be persisted - between launches. Furthermore, since the set of node objects will in - general be larger than the amount of available memory, purged node objects - which are later accessed must be retrieved from the node store. - - @see NodeObject -*/ +/** + * Persistency layer for NodeObject + * + * A Node is a ledger object which is uniquely identified by a key, which is + * the 256-bit hash of the body of the node. The payload is a variable length + * block of serialized data. + * + * All ledger data is stored as node objects and as such, needs to be persisted + * between launches. Furthermore, since the set of node objects will in + * general be larger than the amount of available memory, purged node objects + * which are later accessed must be retrieved from the node store. + * + * @see NodeObject + */ class Database { public: Database() = delete; - /** Construct the node store. - - @param scheduler The scheduler to use for performing asynchronous tasks. - @param readThreads The number of asynchronous read threads to create. - @param config The configuration settings - @param journal Destination for logging output. - */ + /** + * Construct the node store. + * + * @param scheduler The scheduler to use for performing asynchronous tasks. + * @param readThreads The number of asynchronous read threads to create. + * @param config The configuration settings + * @param journal Destination for logging output. + */ Database(Scheduler& scheduler, int readThreads, Section const& config, beast::Journal j); - /** Destroy the node store. - All pending operations are completed, pending writes flushed, - and files closed before this returns. - */ + /** + * Destroy the node store. + * All pending operations are completed, pending writes flushed, + * and files closed before this returns. + */ virtual ~Database(); - /** Retrieve the name associated with this backend. - This is used for diagnostics and may not reflect the actual path - or paths used by the underlying backend. - */ + /** + * Retrieve the name associated with this backend. + * This is used for diagnostics and may not reflect the actual path + * or paths used by the underlying backend. + */ virtual std::string getName() const = 0; - /** Import objects from another database. */ + /** + * Import objects from another database. + */ virtual void importDatabase(Database& source) = 0; - /** Retrieve the estimated number of pending write operations. - This is used for diagnostics. - */ + /** + * Retrieve the estimated number of pending write operations. + * This is used for diagnostics. + */ virtual std::int32_t getWriteLoad() const = 0; - /** Store the object. - - The caller's Blob parameter is overwritten. - - @param type The type of object. - @param data The payload of the object. The caller's - variable is overwritten. - @param hash The 256-bit hash of the payload data. - @param ledgerSeq The sequence of the ledger the object belongs to. - - @return `true` if the object was stored? - */ + /** + * Store the object. + * + * The caller's Blob parameter is overwritten. + * + * @param type The type of object. + * @param data The payload of the object. The caller's + * variable is overwritten. + * @param hash The 256-bit hash of the payload data. + * @param ledgerSeq The sequence of the ledger the object belongs to. + * + * @return `true` if the object was stored? + */ virtual void store(NodeObjectType type, Blob&& data, uint256 const& hash, std::uint32_t ledgerSeq) = 0; - /* Check if two ledgers are in the same database - - If these two sequence numbers map to the same database, - the result of a fetch with either sequence number would - be identical. - - @param s1 The first sequence number - @param s2 The second sequence number - - @return 'true' if both ledgers would be in the same DB - - */ + /** + * Check if two ledgers are in the same database + * + * If these two sequence numbers map to the same database, + * the result of a fetch with either sequence number would + * be identical. + * + * @param s1 The first sequence number + * @param s2 The second sequence number + * + * @return 'true' if both ledgers would be in the same DB + */ virtual bool isSameDB(std::uint32_t s1, std::uint32_t s2) = 0; virtual void sync() = 0; - /** Fetch a node object. - If the object is known to be not in the database, isn't found in the - database during the fetch, or failed to load correctly during the fetch, - `nullptr` is returned. - - @note This can be called concurrently. - @param hash The key of the object to retrieve. - @param ledgerSeq The sequence of the ledger where the object is stored. - @param fetchType the type of fetch, synchronous or asynchronous. - @return The object, or nullptr if it couldn't be retrieved. - */ + /** + * Fetch a node object. + * If the object is known to be not in the database, isn't found in the + * database during the fetch, or failed to load correctly during the fetch, + * `nullptr` is returned. + * + * @note This can be called concurrently. + * @param hash The key of the object to retrieve. + * @param ledgerSeq The sequence of the ledger where the object is stored. + * @param fetchType the type of fetch, synchronous or asynchronous. + * @return The object, or nullptr if it couldn't be retrieved. + */ std::shared_ptr fetchNodeObject( uint256 const& hash, @@ -116,29 +137,33 @@ public: FetchType fetchType = FetchType::Synchronous, bool duplicate = false); - /** Fetch an object without waiting. - If I/O is required to determine whether or not the object is present, - `false` is returned. Otherwise, `true` is returned and `object` is set - to refer to the object, or `nullptr` if the object is not present. - If I/O is required, the I/O is scheduled and `true` is returned - - @note This can be called concurrently. - @param hash The key of the object to retrieve - @param ledgerSeq The sequence of the ledger where the - object is stored. - @param callback Callback function when read completes - */ + /** + * Fetch an object without waiting. + * If I/O is required to determine whether or not the object is present, + * `false` is returned. Otherwise, `true` is returned and `object` is set + * to refer to the object, or `nullptr` if the object is not present. + * If I/O is required, the I/O is scheduled and `true` is returned + * + * @note This can be called concurrently. + * @param hash The key of the object to retrieve + * @param ledgerSeq The sequence of the ledger where the + * object is stored. + * @param callback Callback function when read completes + */ virtual void asyncFetch( uint256 const& hash, std::uint32_t ledgerSeq, std::function const&)>&& callback); - /** Remove expired entries from the positive and negative caches. */ + /** + * Remove expired entries from the positive and negative caches. + */ virtual void sweep() = 0; - /** Gather statistics pertaining to read and write activities. + /** + * Gather statistics pertaining to read and write activities. * * @param obj Json object reference into which to place counters. */ @@ -175,7 +200,9 @@ public: void getCountsJson(json::Value& obj); - /** Returns the number of file descriptors the database expects to need */ + /** + * Returns the number of file descriptors the database expects to need + */ int fdRequired() const { @@ -188,7 +215,8 @@ public: bool isStopping() const; - /** @return The earliest ledger sequence allowed + /** + * @return The earliest ledger sequence allowed */ [[nodiscard]] std::uint32_t earliestLedgerSeq() const noexcept @@ -265,13 +293,14 @@ private: FetchReport& fetchReport, bool duplicate) = 0; - /** Visit every object in the database - This is usually called during import. - - @note This routine will not be called concurrently with itself - or other methods. - @see import - */ + /** + * Visit every object in the database + * This is usually called during import. + * + * @note This routine will not be called concurrently with itself + * or other methods. + * @see import + */ virtual void forEach(std::function)> f) = 0; diff --git a/include/xrpl/nodestore/DatabaseRotating.h b/include/xrpl/nodestore/DatabaseRotating.h index a7deed294a..1c5bb0efaf 100644 --- a/include/xrpl/nodestore/DatabaseRotating.h +++ b/include/xrpl/nodestore/DatabaseRotating.h @@ -1,6 +1,13 @@ #pragma once +#include +#include #include +#include + +#include +#include +#include namespace xrpl::NodeStore { @@ -21,13 +28,14 @@ public: { } - /** Rotates the backends. - - @param newBackend New writable backend - @param f A function executed after the rotation outside of lock. The - values passed to f will be the new backend database names _after_ - rotation. - */ + /** + * Rotates the backends. + * + * @param newBackend New writable backend + * @param f A function executed after the rotation outside of lock. The + * values passed to f will be the new backend database names _after_ + * rotation. + */ virtual void rotate( std::unique_ptr&& newBackend, diff --git a/include/xrpl/nodestore/DummyScheduler.h b/include/xrpl/nodestore/DummyScheduler.h index 472684ff13..49b0d37462 100644 --- a/include/xrpl/nodestore/DummyScheduler.h +++ b/include/xrpl/nodestore/DummyScheduler.h @@ -1,10 +1,13 @@ #pragma once #include +#include namespace xrpl::NodeStore { -/** Simple NodeStore Scheduler that just performs the tasks synchronously. */ +/** + * Simple NodeStore Scheduler that just performs the tasks synchronously. + */ class DummyScheduler : public Scheduler { public: diff --git a/include/xrpl/nodestore/Factory.h b/include/xrpl/nodestore/Factory.h index 3e6ba76a08..a18023a8a8 100644 --- a/include/xrpl/nodestore/Factory.h +++ b/include/xrpl/nodestore/Factory.h @@ -4,7 +4,11 @@ #include #include -#include +#include + +#include +#include +#include namespace xrpl { class Section; @@ -12,24 +16,29 @@ class Section; namespace xrpl::NodeStore { -/** Base class for backend factories. */ +/** + * Base class for backend factories. + */ class Factory { public: virtual ~Factory() = default; - /** Retrieve the name of this factory. */ + /** + * Retrieve the name of this factory. + */ [[nodiscard]] virtual std::string getName() const = 0; - /** Create an instance of this factory's backend. - - @param keyBytes The fixed number of bytes per key. - @param parameters A set of key/value configuration pairs. - @param burstSize Backend burst size in bytes. - @param scheduler The scheduler to use for running tasks. - @return A pointer to the Backend object. - */ + /** + * Create an instance of this factory's backend. + * + * @param keyBytes The fixed number of bytes per key. + * @param parameters A set of key/value configuration pairs. + * @param burstSize Backend burst size in bytes. + * @param scheduler The scheduler to use for running tasks. + * @return A pointer to the Backend object. + */ virtual std::unique_ptr createInstance( size_t keyBytes, @@ -38,15 +47,16 @@ public: Scheduler& scheduler, beast::Journal journal) = 0; - /** Create an instance of this factory's backend. - - @param keyBytes The fixed number of bytes per key. - @param parameters A set of key/value configuration pairs. - @param burstSize Backend burst size in bytes. - @param scheduler The scheduler to use for running tasks. - @param context The context used by database. - @return A pointer to the Backend object. - */ + /** + * Create an instance of this factory's backend. + * + * @param keyBytes The fixed number of bytes per key. + * @param parameters A set of key/value configuration pairs. + * @param burstSize Backend burst size in bytes. + * @param scheduler The scheduler to use for running tasks. + * @param context The context used by database. + * @return A pointer to the Backend object. + */ virtual std::unique_ptr createInstance( size_t keyBytes, diff --git a/include/xrpl/nodestore/Manager.h b/include/xrpl/nodestore/Manager.h index 1c4e5b63cf..54d99fe94b 100644 --- a/include/xrpl/nodestore/Manager.h +++ b/include/xrpl/nodestore/Manager.h @@ -1,11 +1,20 @@ #pragma once -#include +#include +#include +#include #include +#include + +#include +#include +#include namespace xrpl::NodeStore { -/** Singleton for managing NodeStore factories and back ends. */ +/** + * Singleton for managing NodeStore factories and back ends. + */ class Manager { public: @@ -15,26 +24,35 @@ public: Manager& operator=(Manager const&) = delete; - /** Returns the instance of the manager singleton. */ + /** + * Returns the instance of the manager singleton. + */ static Manager& instance(); - /** Add a factory. */ + /** + * Add a factory. + */ virtual void insert(Factory& factory) = 0; - /** Remove a factory. */ + /** + * Remove a factory. + */ virtual void erase(Factory& factory) = 0; - /** Return a pointer to the matching factory if it exists. - @param name The name to match, performed case-insensitive. - @return `nullptr` if a match was not found. - */ + /** + * Return a pointer to the matching factory if it exists. + * @param name The name to match, performed case-insensitive. + * @return `nullptr` if a match was not found. + */ virtual Factory* find(std::string const& name) = 0; - /** Create a backend. */ + /** + * Create a backend. + */ virtual std::unique_ptr makeBackend( Section const& parameters, @@ -42,34 +60,35 @@ public: Scheduler& scheduler, beast::Journal journal) = 0; - /** Construct a NodeStore database. - - The parameters are key value pairs passed to the backend. The - 'type' key must exist, it defines the choice of backend. Most - backends also require a 'path' field. - - Some choices for 'type' are: - HyperLevelDB, LevelDBFactory, SQLite, MDB - - If the fastBackendParameter is omitted or empty, no ephemeral database - is used. If the scheduler parameter is omitted or unspecified, a - synchronous scheduler is used which performs all tasks immediately on - the caller's thread. - - @note If the database cannot be opened or created, an exception is - thrown. - - @param name A diagnostic label for the database. - @param burstSize Backend burst size in bytes. - @param scheduler The scheduler to use for performing asynchronous tasks. - @param readThreads The number of async read threads to create - @param backendParameters The parameter string for the persistent - backend. - @param fastBackendParameters [optional] The parameter string for the - ephemeral backend. - - @return The opened database. - */ + /** + * Construct a NodeStore database. + * + * The parameters are key value pairs passed to the backend. The + * 'type' key must exist, it defines the choice of backend. Most + * backends also require a 'path' field. + * + * Some choices for 'type' are: + * HyperLevelDB, LevelDBFactory, SQLite, MDB + * + * If the fastBackendParameter is omitted or empty, no ephemeral database + * is used. If the scheduler parameter is omitted or unspecified, a + * synchronous scheduler is used which performs all tasks immediately on + * the caller's thread. + * + * @note If the database cannot be opened or created, an exception is + * thrown. + * + * @param name A diagnostic label for the database. + * @param burstSize Backend burst size in bytes. + * @param scheduler The scheduler to use for performing asynchronous tasks. + * @param readThreads The number of async read threads to create + * @param backendParameters The parameter string for the persistent + * backend. + * @param fastBackendParameters [optional] The parameter string for the + * ephemeral backend. + * + * @return The opened database. + */ virtual std::unique_ptr makeDatabase( std::size_t burstSize, diff --git a/include/xrpl/nodestore/NodeObject.h b/include/xrpl/nodestore/NodeObject.h index 04ba391b2b..b96d65fa12 100644 --- a/include/xrpl/nodestore/NodeObject.h +++ b/include/xrpl/nodestore/NodeObject.h @@ -4,11 +4,17 @@ #include #include +#include +#include +#include + // VFALCO NOTE Intentionally not in the NodeStore namespace namespace xrpl { -/** The types of node objects. */ +/** + * The types of node objects. + */ enum class NodeObjectType : std::uint32_t { Unknown = 0, Ledger = 1, @@ -17,15 +23,16 @@ enum class NodeObjectType : std::uint32_t { Dummy = 512 // an invalid or missing object }; -/** A simple object that the Ledger uses to store entries. - NodeObjects are comprised of a type, a hash, and a blob. - They can be uniquely identified by the hash, which is a half-SHA512 of - the blob. The blob is a variable length block of serialized data. The - type identifies what the blob contains. - - @note No checking is performed to make sure the hash matches the data. - @see SHAMap -*/ +/** + * A simple object that the Ledger uses to store entries. + * NodeObjects are comprised of a type, a hash, and a blob. + * They can be uniquely identified by the hash, which is a half-SHA512 of + * the blob. The blob is a variable length block of serialized data. The + * type identifies what the blob contains. + * + * @note No checking is performed to make sure the hash matches the data. + * @see SHAMap + */ class NodeObject : public CountedObject { public: @@ -44,29 +51,36 @@ public: // This constructor is private, use createObject instead. NodeObject(NodeObjectType type, Blob&& data, uint256 const& hash, PrivateAccess); - /** Create an object from fields. - - The caller's variable is modified during this call. The - underlying storage for the Blob is taken over by the NodeObject. - - @param type The type of object. - @param ledgerIndex The ledger in which this object appears. - @param data A buffer containing the payload. The caller's variable - is overwritten. - @param hash The 256-bit hash of the payload data. - */ + /** + * Create an object from fields. + * + * The caller's variable is modified during this call. The + * underlying storage for the Blob is taken over by the NodeObject. + * + * @param type The type of object. + * @param ledgerIndex The ledger in which this object appears. + * @param data A buffer containing the payload. The caller's variable + * is overwritten. + * @param hash The 256-bit hash of the payload data. + */ static std::shared_ptr createObject(NodeObjectType type, Blob&& data, uint256 const& hash); - /** Returns the type of this object. */ + /** + * Returns the type of this object. + */ [[nodiscard]] NodeObjectType getType() const; - /** Returns the hash of the data. */ + /** + * Returns the hash of the data. + */ [[nodiscard]] uint256 const& getHash() const; - /** Returns the underlying data. */ + /** + * Returns the underlying data. + */ [[nodiscard]] Blob const& getData() const; diff --git a/include/xrpl/nodestore/Scheduler.h b/include/xrpl/nodestore/Scheduler.h index 588ff19bdc..5d93a80eaa 100644 --- a/include/xrpl/nodestore/Scheduler.h +++ b/include/xrpl/nodestore/Scheduler.h @@ -8,7 +8,9 @@ namespace xrpl::NodeStore { enum class FetchType { Synchronous, Async }; -/** Contains information about a fetch operation. */ +/** + * Contains information about a fetch operation. + */ struct FetchReport { explicit FetchReport(FetchType fetchType) : fetchType(fetchType) @@ -20,7 +22,9 @@ struct FetchReport bool wasFound = false; }; -/** Contains information about a batch write operation. */ +/** + * Contains information about a batch write operation. + */ struct BatchWriteReport { explicit BatchWriteReport() = default; @@ -29,36 +33,40 @@ struct BatchWriteReport int writeCount; }; -/** Scheduling for asynchronous backend activity - - For improved performance, a backend has the option of performing writes - in batches. These writes can be scheduled using the provided scheduler - object. - - @see BatchWriter -*/ +/** + * Scheduling for asynchronous backend activity + * + * For improved performance, a backend has the option of performing writes + * in batches. These writes can be scheduled using the provided scheduler + * object. + * + * @see BatchWriter + */ class Scheduler { public: virtual ~Scheduler() = default; - /** Schedules a task. - Depending on the implementation, the task may be invoked either on - the current thread of execution, or an unspecified - implementation-defined foreign thread. - */ + /** + * Schedules a task. + * Depending on the implementation, the task may be invoked either on + * the current thread of execution, or an unspecified + * implementation-defined foreign thread. + */ virtual void scheduleTask(Task& task) = 0; - /** Reports completion of a fetch - Allows the scheduler to monitor the node store's performance - */ + /** + * Reports completion of a fetch + * Allows the scheduler to monitor the node store's performance + */ virtual void onFetch(FetchReport const& report) = 0; - /** Reports the completion of a batch write - Allows the scheduler to monitor the node store's performance - */ + /** + * Reports the completion of a batch write + * Allows the scheduler to monitor the node store's performance + */ virtual void onBatchWrite(BatchWriteReport const& report) = 0; }; diff --git a/include/xrpl/nodestore/Task.h b/include/xrpl/nodestore/Task.h index 0695970a68..59fe648476 100644 --- a/include/xrpl/nodestore/Task.h +++ b/include/xrpl/nodestore/Task.h @@ -2,14 +2,17 @@ namespace xrpl::NodeStore { -/** Derived classes perform scheduled tasks. */ +/** + * Derived classes perform scheduled tasks. + */ struct Task { virtual ~Task() = default; - /** Performs the task. - The call may take place on a foreign thread. - */ + /** + * Performs the task. + * The call may take place on a foreign thread. + */ virtual void performScheduledTask() = 0; }; diff --git a/include/xrpl/nodestore/Types.h b/include/xrpl/nodestore/Types.h index 21c01e9111..872d948a36 100644 --- a/include/xrpl/nodestore/Types.h +++ b/include/xrpl/nodestore/Types.h @@ -2,6 +2,7 @@ #include +#include #include namespace xrpl::NodeStore { @@ -17,7 +18,9 @@ static constexpr auto kBatchWritePreallocationSize = 256; // static constexpr auto kBatchWriteLimitSize = 65536; -/** Return codes from Backend operations. */ +/** + * Return codes from Backend operations. + */ enum class Status { Ok = 0, NotFound = 1, @@ -28,7 +31,9 @@ enum class Status { CustomCode = 100 }; -/** A batch of NodeObjects to write at once. */ +/** + * A batch of NodeObjects to write at once. + */ using Batch = std::vector>; } // namespace xrpl::NodeStore diff --git a/include/xrpl/nodestore/detail/BatchWriter.h b/include/xrpl/nodestore/detail/BatchWriter.h index b0383838dc..b89df0da14 100644 --- a/include/xrpl/nodestore/detail/BatchWriter.h +++ b/include/xrpl/nodestore/detail/BatchWriter.h @@ -1,26 +1,31 @@ #pragma once +#include #include #include #include #include +#include #include namespace xrpl::NodeStore { -/** Batch-writing assist logic. - - The batch writes are performed with a scheduled task. Use of the - class it not required. A backend can implement its own write batching, - or skip write batching if doing so yields a performance benefit. - - @see Scheduler -*/ +/** + * Batch-writing assist logic. + * + * The batch writes are performed with a scheduled task. Use of the + * class it not required. A backend can implement its own write batching, + * or skip write batching if doing so yields a performance benefit. + * + * @see Scheduler + */ class BatchWriter : private Task { public: - /** This callback does the actual writing. */ + /** + * This callback does the actual writing. + */ struct Callback { virtual ~Callback() = default; @@ -33,24 +38,30 @@ public: writeBatch(Batch const& batch) = 0; }; - /** Create a batch writer. */ + /** + * Create a batch writer. + */ BatchWriter(Callback& callback, Scheduler& scheduler); - /** Destroy a batch writer. - - Anything pending in the batch is written out before this returns. - */ + /** + * Destroy a batch writer. + * + * Anything pending in the batch is written out before this returns. + */ ~BatchWriter() override; - /** Store the object. - - This will add to the batch and initiate a scheduled task to - write the batch out. - */ + /** + * Store the object. + * + * This will add to the batch and initiate a scheduled task to + * write the batch out. + */ void store(std::shared_ptr const& object); - /** Get an estimate of the amount of writing I/O pending. */ + /** + * Get an estimate of the amount of writing I/O pending. + */ int getWriteLoad(); diff --git a/include/xrpl/nodestore/detail/DatabaseNodeImp.h b/include/xrpl/nodestore/detail/DatabaseNodeImp.h index 38b8763f31..6f2fca682f 100644 --- a/include/xrpl/nodestore/detail/DatabaseNodeImp.h +++ b/include/xrpl/nodestore/detail/DatabaseNodeImp.h @@ -1,10 +1,26 @@ #pragma once +#include #include +#include #include +#include +#include +#include #include #include +#include #include +#include +#include + +#include +#include +#include +#include +#include +#include +#include namespace xrpl::NodeStore { diff --git a/include/xrpl/nodestore/detail/DatabaseRotatingImp.h b/include/xrpl/nodestore/detail/DatabaseRotatingImp.h index 1ba9435a5f..6343275c76 100644 --- a/include/xrpl/nodestore/detail/DatabaseRotatingImp.h +++ b/include/xrpl/nodestore/detail/DatabaseRotatingImp.h @@ -1,8 +1,19 @@ #pragma once +#include +#include +#include +#include +#include #include +#include +#include +#include +#include +#include #include +#include namespace xrpl::NodeStore { diff --git a/include/xrpl/nodestore/detail/DecodedBlob.h b/include/xrpl/nodestore/detail/DecodedBlob.h index 90a7b6c9cb..d0cc5e3404 100644 --- a/include/xrpl/nodestore/detail/DecodedBlob.h +++ b/include/xrpl/nodestore/detail/DecodedBlob.h @@ -2,41 +2,50 @@ #include +#include + namespace xrpl::NodeStore { -/** Parsed key/value blob into NodeObject components. - - This will extract the information required to construct a NodeObject. It - also does consistency checking and returns the result, so it is possible - to determine if the data is corrupted without throwing an exception. Not - all forms of corruption are detected so further analysis will be needed - to eliminate false negatives. - - @note This defines the database format of a NodeObject! -*/ +/** + * Parsed key/value blob into NodeObject components. + * + * This will extract the information required to construct a NodeObject. It + * also does consistency checking and returns the result, so it is possible + * to determine if the data is corrupted without throwing an exception. Not + * all forms of corruption are detected so further analysis will be needed + * to eliminate false negatives. + * + * @note This defines the database format of a NodeObject! + */ class DecodedBlob { public: - /** Construct the decoded blob from raw data. */ + /** + * Construct the decoded blob from raw data. + */ DecodedBlob(void const* key, void const* value, int valueBytes); - /** Determine if the decoding was successful. */ + /** + * Determine if the decoding was successful. + */ [[nodiscard]] bool wasOk() const noexcept { return success_; } - /** Create a NodeObject from this data. */ + /** + * Create a NodeObject from this data. + */ std::shared_ptr createObject(); private: - bool success_; + bool success_{false}; void const* key_; - NodeObjectType objectType_; - unsigned char const* objectData_; + NodeObjectType objectType_{NodeObjectType::Unknown}; + unsigned char const* objectData_{nullptr}; int dataBytes_; }; diff --git a/include/xrpl/nodestore/detail/EncodedBlob.h b/include/xrpl/nodestore/detail/EncodedBlob.h index 343e1720a0..d668cdccd8 100644 --- a/include/xrpl/nodestore/detail/EncodedBlob.h +++ b/include/xrpl/nodestore/detail/EncodedBlob.h @@ -7,51 +7,61 @@ #include #include +#include #include +#include +#include namespace xrpl::NodeStore { -/** Convert a NodeObject from in-memory to database format. - - The (suboptimal) database format consists of: - - - 8 prefix bytes which will typically be 0, but don't assume that's the - case; earlier versions of the code would use these bytes to store the - ledger index either once or twice. - - A single byte denoting the type of the object. - - The payload. - - @note This class is typically instantiated on the stack, so the size of - the object does not matter as much as it normally would since the - allocation is, effectively, free. - - We leverage that fact to preallocate enough memory to handle most - payloads as part of this object, eliminating the need for dynamic - allocation. As of this writing ~94% of objects require fewer than - 1024 payload bytes. +/** + * Convert a NodeObject from in-memory to database format. + * + * The (suboptimal) database format consists of: + * + * - 8 prefix bytes which will typically be 0, but don't assume that's the + * case; earlier versions of the code would use these bytes to store the + * ledger index either once or twice. + * - A single byte denoting the type of the object. + * - The payload. + * + * @note This class is typically instantiated on the stack, so the size of + * the object does not matter as much as it normally would since the + * allocation is, effectively, free. + * + * We leverage that fact to preallocate enough memory to handle most + * payloads as part of this object, eliminating the need for dynamic + * allocation. As of this writing ~94% of objects require fewer than + * 1024 payload bytes. */ class EncodedBlob { - /** The 32-byte key of the serialized object. */ + /** + * The 32-byte key of the serialized object. + */ std::array key_{}; - /** A pre-allocated buffer for the serialized object. - - The buffer is large enough for the 9 byte prefix and at least - 1024 more bytes. The precise size is calculated automatically - at compile time so as to avoid wasting space on padding bytes. + /** + * A pre-allocated buffer for the serialized object. + * + * The buffer is large enough for the 9 byte prefix and at least + * 1024 more bytes. The precise size is calculated automatically + * at compile time so as to avoid wasting space on padding bytes. */ std::array payload_{}; - /** The size of the serialized data. */ + /** + * The size of the serialized data. + */ std::uint32_t size_; - /** A pointer to the serialized data. - - This may point to the pre-allocated buffer (if it is sufficiently - large) or to a dynamically allocated buffer. + /** + * A pointer to the serialized data. + * + * This may point to the pre-allocated buffer (if it is sufficiently + * large) or to a dynamically allocated buffer. */ std::uint8_t* const ptr_; diff --git a/include/xrpl/nodestore/detail/ManagerImp.h b/include/xrpl/nodestore/detail/ManagerImp.h index 98aec6459b..fc84b0aa57 100644 --- a/include/xrpl/nodestore/detail/ManagerImp.h +++ b/include/xrpl/nodestore/detail/ManagerImp.h @@ -1,6 +1,17 @@ #pragma once +#include +#include +#include +#include #include +#include + +#include +#include +#include +#include +#include namespace xrpl::NodeStore { diff --git a/include/xrpl/nodestore/detail/codec.h b/include/xrpl/nodestore/detail/codec.h index 49238fa34a..2f69d532be 100644 --- a/include/xrpl/nodestore/detail/codec.h +++ b/include/xrpl/nodestore/detail/codec.h @@ -1,6 +1,10 @@ #pragma once // Disable lz4 deprecation warning due to incompatibility with clang attributes +#include +#include +#include +#include #define LZ4_DISABLE_DEPRECATE_WARNINGS #include @@ -58,7 +62,7 @@ lz4Compress(void const* in, std::size_t inSize, BufferFactory&& bf) std::array::kMax> vi{}; auto const n = writeVarint(vi.data(), inSize); auto const outMax = LZ4_compressBound(inSize); - std::uint8_t* out = reinterpret_cast(bf(n + outMax)); + auto* out = reinterpret_cast(bf(n + outMax)); result.first = out; std::memcpy(out, vi.data(), n); auto const outSize = LZ4_compress_default( @@ -86,7 +90,7 @@ nodeobjectDecompress(void const* in, std::size_t inSize, BufferFactory&& bf) { using namespace nudb::detail; - std::uint8_t const* p = reinterpret_cast(in); + auto const* p = reinterpret_cast(in); std::size_t type = 0; auto const vn = readVarint(p, inSize, type); if (vn == 0) @@ -233,7 +237,7 @@ nodeobjectCompress(void const* in, std::size_t inSize, BufferFactory&& bf) auto const vs = sizeVarint(type); result.second = vs + field::size + // mask (n * 32); // hashes - std::uint8_t* out = reinterpret_cast(bf(result.second)); + auto* out = reinterpret_cast(bf(result.second)); result.first = out; ostream os(out, result.second); write(os, type); @@ -245,7 +249,7 @@ nodeobjectCompress(void const* in, std::size_t inSize, BufferFactory&& bf) auto const type = 3U; auto const vs = sizeVarint(type); result.second = vs + (n * 32); // hashes - std::uint8_t* out = reinterpret_cast(bf(result.second)); + auto* out = reinterpret_cast(bf(result.second)); result.first = out; ostream os(out, result.second); write(os, type); diff --git a/include/xrpl/nodestore/detail/varint.h b/include/xrpl/nodestore/detail/varint.h index 0c49274d70..5a65545d3a 100644 --- a/include/xrpl/nodestore/detail/varint.h +++ b/include/xrpl/nodestore/detail/varint.h @@ -2,6 +2,7 @@ #include +#include #include #include @@ -38,7 +39,7 @@ readVarint(void const* buf, std::size_t buflen, std::size_t& t) if (buflen == 0) return 0; t = 0; - std::uint8_t const* p = reinterpret_cast(buf); + auto const* p = reinterpret_cast(buf); std::size_t n = 0; while (p[n] & 0x80) { @@ -67,9 +68,10 @@ readVarint(void const* buf, std::size_t buflen, std::size_t& t) return used; } -template >* = nullptr> +template std::size_t sizeVarint(T v) + requires(std::is_unsigned_v) { std::size_t n = 0; do @@ -85,7 +87,7 @@ std::size_t writeVarint(void* p0, std::size_t v) { // NOLINTNEXTLINE(misc-const-correctness) - std::uint8_t* p = reinterpret_cast(p0); + auto* p = reinterpret_cast(p0); do { std::uint8_t d = v % 127; @@ -99,9 +101,10 @@ writeVarint(void* p0, std::size_t v) // input stream -template >* = nullptr> +template void read(nudb::detail::istream& is, std::size_t& u) + requires(std::is_same_v) { auto p0 = is(1); auto p1 = p0; @@ -112,9 +115,10 @@ read(nudb::detail::istream& is, std::size_t& u) // output stream -template >* = nullptr> +template void write(nudb::detail::ostream& os, std::size_t t) + requires(std::is_same_v) { writeVarint(os.data(sizeVarint(t)), t); } diff --git a/include/xrpl/proto/org/xrpl/rpc/v1/README.md b/include/xrpl/proto/org/xrpl/rpc/v1/README.md index e8566ec179..d0ff14cd13 100644 --- a/include/xrpl/proto/org/xrpl/rpc/v1/README.md +++ b/include/xrpl/proto/org/xrpl/rpc/v1/README.md @@ -70,9 +70,9 @@ into helper functions (see Tx.cpp or AccountTx.cpp for an example). #### Testing When modifying an existing gRPC method, be sure to test that modification in the -corresponding, existing unit test. When creating a new gRPC method, implement a class that -derives from GRPCTestClientBase, and use the newly created class to call the new -method. See the class `GrpcTxClient` in the file Tx_test.cpp for an example. +corresponding, existing unit test. When creating a new gRPC method, create a +client stub with `XRPLedgerAPIService::NewStub` and `grpc::CreateChannel`, and +use it to call the new method. See `GRPCServerTLS_test.cpp` for an example. The gRPC tests are paired with their JSON counterpart, and the tests should mirror the JSON test as much as possible. diff --git a/include/xrpl/protocol/AMMCore.h b/include/xrpl/protocol/AMMCore.h index a83c8bfa84..a3666c7960 100644 --- a/include/xrpl/protocol/AMMCore.h +++ b/include/xrpl/protocol/AMMCore.h @@ -3,9 +3,14 @@ #include #include #include +#include #include #include +#include +#include +#include + namespace xrpl { constexpr std::uint16_t kTradingFeeThreshold = 1000; // 1% @@ -28,17 +33,20 @@ class STObject; class STAmount; class Rules; -/** Calculate Liquidity Provider Token (LPT) Currency. +/** + * Calculate Liquidity Provider Token (LPT) Currency. */ Currency ammLPTCurrency(Asset const& asset1, Asset const& asset2); -/** Calculate LPT Issue from AMM asset pair. +/** + * Calculate LPT Issue from AMM asset pair. */ Issue ammLPTIssue(Asset const& asset1, Asset const& asset2, AccountID const& ammAccountID); -/** Validate the amount. +/** + * Validate the amount. * If validZero is false and amount is beast::zero then invalid amount. * Return error code if invalid amount. * If pair then validate amount's issue matches one of the pair's issue. @@ -60,17 +68,20 @@ invalidAMMAssetPair( Asset const& asset2, std::optional> const& pair = std::nullopt); -/** Get time slot of the auction slot. +/** + * Get time slot of the auction slot. */ std::optional ammAuctionTimeSlot(std::uint64_t current, STObject const& auctionSlot); -/** Return true if required AMM amendment is enabled +/** + * Return true if required AMM amendment is enabled */ bool ammEnabled(Rules const&); -/** Convert to the fee from the basis points +/** + * Convert to the fee from the basis points * @param tfee trading fee in {0, 1000} * 1 = 1/10bps or 0.001%, 1000 = 1% */ @@ -80,7 +91,8 @@ getFee(std::uint16_t tfee) return Number{tfee} / kAuctionSlotFeeScaleFactor; } -/** Get fee multiplier (1 - tfee) +/** + * Get fee multiplier (1 - tfee) * @tfee trading fee in basis points */ inline Number @@ -89,7 +101,8 @@ feeMult(std::uint16_t tfee) return 1 - getFee(tfee); } -/** Get fee multiplier (1 - tfee / 2) +/** + * Get fee multiplier (1 - tfee / 2) * @tfee trading fee in basis points */ inline Number diff --git a/include/xrpl/protocol/AccountID.h b/include/xrpl/protocol/AccountID.h index 4938812ffa..ab3c5a996b 100644 --- a/include/xrpl/protocol/AccountID.h +++ b/include/xrpl/protocol/AccountID.h @@ -3,13 +3,17 @@ #include // VFALCO Uncomment when the header issues are resolved // #include -#include #include +#include +#include #include +#include #include #include +#include #include +#include #include namespace xrpl { @@ -24,43 +28,53 @@ public: } // namespace detail -/** A 160-bit unsigned that uniquely identifies an account. */ +/** + * A 160-bit unsigned that uniquely identifies an account. + */ using AccountID = BaseUInt<160, detail::AccountIDTag>; -/** Convert AccountID to base58 checked string */ +/** + * Convert AccountID to base58 checked string + */ std::string toBase58(AccountID const& v); -/** Parse AccountID from checked, base58 string. - @return std::nullopt if a parse error occurs -*/ +/** + * Parse AccountID from checked, base58 string. + * @return std::nullopt if a parse error occurs + */ template <> std::optional parseBase58(std::string const& s); -/** Compute AccountID from public key. - - The account ID is computed as the 160-bit hash of the - public key data. This excludes the version byte and - guard bytes included in the base58 representation. - -*/ +/** + * Compute AccountID from public key. + * + * The account ID is computed as the 160-bit hash of the + * public key data. This excludes the version byte and + * guard bytes included in the base58 representation. + */ // VFALCO In PublicKey.h for now // AccountID // calcAccountID (PublicKey const& pk); -/** A special account that's used as the "issuer" for XRP. */ +/** + * A special account that's used as the "issuer" for XRP. + */ AccountID const& xrpAccount(); -/** A placeholder for empty accounts. */ +/** + * A placeholder for empty accounts. + */ AccountID const& noAccount(); -/** Convert hex or base58 string to AccountID. - - @return `true` if the parsing was successful. -*/ +/** + * Convert hex or base58 string to AccountID. + * + * @return `true` if the parsing was successful. + */ // DEPRECATED bool toIssuer(AccountID&, std::string const&); @@ -87,17 +101,18 @@ operator<<(std::ostream& os, AccountID const& x) return os; } -/** Initialize the global cache used to map AccountID to base58 conversions. - - The cache is optional and need not be initialized. But because conversion - is expensive (it requires a SHA-256 operation) in most cases the overhead - of the cache is worth the benefit. - - @param count The number of entries the cache should accommodate. Zero will - disable the cache, releasing any memory associated with it. - - @note The function will only initialize the cache the first time it is - invoked. Subsequent invocations do nothing. +/** + * Initialize the global cache used to map AccountID to base58 conversions. + * + * The cache is optional and need not be initialized. But because conversion + * is expensive (it requires a SHA-256 operation) in most cases the overhead + * of the cache is worth the benefit. + * + * @param count The number of entries the cache should accommodate. Zero will + * disable the cache, releasing any memory associated with it. + * + * @note The function will only initialize the cache the first time it is + * invoked. Subsequent invocations do nothing. */ void initAccountIdCache(std::size_t count); diff --git a/include/xrpl/protocol/AmountConversions.h b/include/xrpl/protocol/AmountConversions.h index a5f7ec310f..3bcd80e827 100644 --- a/include/xrpl/protocol/AmountConversions.h +++ b/include/xrpl/protocol/AmountConversions.h @@ -1,10 +1,20 @@ #pragma once +#include +#include +#include +#include #include +#include +#include +#include #include #include #include +#include +#include // IWYU pragma: keep +#include #include namespace xrpl { diff --git a/include/xrpl/protocol/ApiVersion.h b/include/xrpl/protocol/ApiVersion.h index 10b7571641..c3292e6074 100644 --- a/include/xrpl/protocol/ApiVersion.h +++ b/include/xrpl/protocol/ApiVersion.h @@ -5,6 +5,7 @@ #include #include +#include #include #include diff --git a/include/xrpl/protocol/Asset.h b/include/xrpl/protocol/Asset.h index ec9d8db02f..8e9c09eb89 100644 --- a/include/xrpl/protocol/Asset.h +++ b/include/xrpl/protocol/Asset.h @@ -2,10 +2,19 @@ #include #include +#include +#include +#include #include #include #include -#include +#include + +#include +#include +#include +#include +#include namespace xrpl { @@ -53,7 +62,8 @@ private: public: Asset() = default; - /** Conversions to Asset are implicit and conversions to specific issue + /** + * Conversions to Asset are implicit and conversions to specific issue * type are explicit. This design facilitates the use of Asset. */ Asset(Issue const& issue) : issue_(issue) @@ -140,7 +150,8 @@ public: friend constexpr bool operator==(BadAsset const& lhs, Asset const& rhs); - /** Return true if both assets refer to the same currency (regardless of + /** + * Return true if both assets refer to the same currency (regardless of * issuer) or MPT issuance. Otherwise return false. */ friend constexpr bool diff --git a/include/xrpl/protocol/Batch.h b/include/xrpl/protocol/Batch.h index 2f2412b3ff..1e4f811fa9 100644 --- a/include/xrpl/protocol/Batch.h +++ b/include/xrpl/protocol/Batch.h @@ -1,15 +1,26 @@ #pragma once +#include +#include #include -#include #include +#include +#include + namespace xrpl { inline void -serializeBatch(Serializer& msg, std::uint32_t const& flags, std::vector const& txids) +serializeBatch( + Serializer& msg, + AccountID const& outerAccount, + std::uint32_t outerSeqValue, + std::uint32_t const& flags, + std::vector const& txids) { msg.add32(HashPrefix::Batch); + msg.addBitString(outerAccount); + msg.add32(outerSeqValue); msg.add32(flags); msg.add32(std::uint32_t(txids.size())); for (auto const& txid : txids) diff --git a/include/xrpl/protocol/Book.h b/include/xrpl/protocol/Book.h index 01dc40075b..a83eb41b24 100644 --- a/include/xrpl/protocol/Book.h +++ b/include/xrpl/protocol/Book.h @@ -2,16 +2,28 @@ #include #include +#include #include +#include +#include +#include #include +#include +#include +#include +#include +#include +#include + namespace xrpl { -/** Specifies an order book. - The order book is a pair of Issues called in and out. - @see Issue. -*/ +/** + * Specifies an order book. + * The order book is a pair of Issues called in and out. + * @see Issue. + */ class Book final : public CountedObject { public: @@ -49,7 +61,9 @@ hash_append(Hasher& h, Book const& b) Book reversed(Book const& book); -/** Equality comparison. */ +/** + * Equality comparison. + */ /** @{ */ [[nodiscard]] constexpr bool operator==(Book const& lhs, Book const& rhs) @@ -58,14 +72,16 @@ operator==(Book const& lhs, Book const& rhs) } /** @} */ -/** Strict weak ordering. */ +/** + * Strict weak ordering. + */ /** @{ */ [[nodiscard]] constexpr std::weak_ordering operator<=>(Book const& lhs, Book const& rhs) { - if (auto const c{lhs.in <=> rhs.in}; c != 0) + if (auto const c{lhs.in <=> rhs.in}; c != 0) // NOLINT(modernize-use-nullptr) return c; - if (auto const c{lhs.out <=> rhs.out}; c != 0) + if (auto const c{lhs.out <=> rhs.out}; c != 0) // NOLINT(modernize-use-nullptr) return c; // Manually compare optionals diff --git a/include/xrpl/protocol/BuildInfo.h b/include/xrpl/protocol/BuildInfo.h index 47a27339a8..18ba20f23c 100644 --- a/include/xrpl/protocol/BuildInfo.h +++ b/include/xrpl/protocol/BuildInfo.h @@ -2,75 +2,85 @@ #include #include +#include -/** Versioning information for this build. */ +/** + * Versioning information for this build. + */ // VFALCO The namespace is deprecated namespace xrpl::BuildInfo { -/** Server version. - Follows the Semantic Versioning Specification: - http://semver.org/ -*/ +/** + * Server version. + * Follows the Semantic Versioning Specification: + * http://semver.org/ + */ std::string const& getVersionString(); -/** Full server version string. - This includes the name of the server. It is used in the peer - protocol hello message and also the headers of some HTTP replies. -*/ +/** + * Full server version string. + * This includes the name of the server. It is used in the peer + * protocol hello message and also the headers of some HTTP replies. + */ std::string const& getFullVersionString(); -/** Encode an arbitrary server software version in a 64-bit integer. - - The general format is: - - ........-........-........-........-........-........-........-........ - XXXXXXXX-XXXXXXXX-YYYYYYYY-YYYYYYYY-YYYYYYYY-YYYYYYYY-YYYYYYYY-YYYYYYYY - - X: 16 bits identifying the particular implementation - Y: 48 bits of data specific to the implementation - - The xrpld-specific format (implementation ID is: 0x18 0x3B) is: - - 00011000-00111011-MMMMMMMM-mmmmmmmm-pppppppp-TTNNNNNN-00000000-00000000 - - M: 8-bit major version (0-255) - m: 8-bit minor version (0-255) - p: 8-bit patch version (0-255) - T: 11 if neither an RC nor a beta - 10 if an RC - 01 if a beta - N: 6-bit rc/beta number (1-63) - - @param the version string - @return the encoded version in a 64-bit integer -*/ +/** + * Encode an arbitrary server software version in a 64-bit integer. + * + * The general format is: + * + * ........-........-........-........-........-........-........-........ + * XXXXXXXX-XXXXXXXX-YYYYYYYY-YYYYYYYY-YYYYYYYY-YYYYYYYY-YYYYYYYY-YYYYYYYY + * + * X: 16 bits identifying the particular implementation + * Y: 48 bits of data specific to the implementation + * + * The xrpld-specific format (implementation ID is: 0x18 0x3B) is: + * + * 00011000-00111011-MMMMMMMM-mmmmmmmm-pppppppp-TTNNNNNN-00000000-00000000 + * + * M: 8-bit major version (0-255) + * m: 8-bit minor version (0-255) + * p: 8-bit patch version (0-255) + * T: 11 if neither an RC nor a beta + * 10 if an RC + * 01 if a beta + * N: 6-bit rc/beta number (1-63) + * + * @param the version string + * @return the encoded version in a 64-bit integer + */ std::uint64_t encodeSoftwareVersion(std::string_view versionStr); -/** Returns this server's version packed in a 64-bit integer. */ +/** + * Returns this server's version packed in a 64-bit integer. + */ std::uint64_t getEncodedVersion(); -/** Check if the encoded software version is an xrpld software version. - - @param version another node's encoded software version - @return true if the version is an xrpld software version, false otherwise -*/ +/** + * Check if the encoded software version is an xrpld software version. + * + * @param version another node's encoded software version + * @return true if the version is an xrpld software version, false otherwise + */ bool isXrpldVersion(std::uint64_t version); -/** Check if the version is newer than the local node's xrpld software - version. - - @param version another node's encoded software version - @return true if the version is newer than the local node's xrpld software - version, false otherwise. - - @note This function only understands version numbers that are generated by - xrpld. Please see the encodeSoftwareVersion() function for detail. -*/ +/** + * Check if the version is newer than the local node's xrpld software + * version. + * + * @param version another node's encoded software version + * @return true if the version is newer than the local node's xrpld software + * version, false otherwise. + * + * @note This function only understands version numbers that are generated by + * xrpld. Please see the encodeSoftwareVersion() function for detail. + */ bool isNewerVersion(std::uint64_t version); diff --git a/include/xrpl/protocol/ConfidentialTransfer.h b/include/xrpl/protocol/ConfidentialTransfer.h new file mode 100644 index 0000000000..ecf7970aba --- /dev/null +++ b/include/xrpl/protocol/ConfidentialTransfer.h @@ -0,0 +1,436 @@ +#pragma once + +#include +#include +#include +#include +#include +#include // IWYU pragma: keep +#include +#include +#include +#include + +#include + +#include +#include +#include + +namespace xrpl { + +/** + * @brief Bundles an ElGamal public key with its associated encrypted amount. + * + * Used to represent a recipient in confidential transfers, containing both + * the recipient's ElGamal public key and the ciphertext encrypting the + * transfer amount under that key. + */ +struct ConfidentialRecipient +{ + /** + * @brief The recipient's ElGamal public key (size=xrpl::kEcPubKeyLength). + */ + Slice publicKey; + + /** + * @brief The encrypted amount ciphertext + * (size=xrpl::kEcGamalEncryptedTotalLength). + */ + Slice encryptedAmount; +}; + +/** + * @brief Holds two secp256k1 public key components representing an ElGamal + * ciphertext (C1, C2). + */ +struct EcPair +{ + /** + * @brief First ElGamal ciphertext component. + */ + secp256k1_pubkey c1; + + /** + * @brief Second ElGamal ciphertext component. + */ + secp256k1_pubkey c2; +}; + +/** + * @brief Increments the confidential balance version counter on an MPToken. + * + * The version counter is used to prevent replay attacks by binding proofs + * to a specific state of the account's confidential balance. Wraps to 0 + * on overflow (defined behavior for unsigned integers). + * + * @param mptoken The MPToken ledger entry to update. + */ +inline void +incrementConfidentialVersion(STObject& mptoken) +{ + // Retrieve current version and increment, wrapping back to 0 at UINT32_MAX. + // The wrap is computed explicitly rather than relying on unsigned overflow + // of `+ 1u`, as it trips the unsigned-integer-overflow sanitizer in the UBSan CI build. + auto const current = mptoken[~sfConfidentialBalanceVersion].valueOr(0u); + mptoken[sfConfidentialBalanceVersion] = + current == std::numeric_limits::max() ? 0u : current + 1u; +} + +/** + * @brief Generates the context hash for ConfidentialMPTSend transactions. + * + * Creates a unique 256-bit hash that binds the zero-knowledge proofs to + * this specific send transaction, preventing proof reuse across transactions. + * + * @param account The sender's account ID. + * @param issuanceID The MPToken Issuance ID. + * @param sequence The transaction sequence number or ticket number. + * @param destination The destination account ID. + * @param version The sender's confidential balance version. + * @return A 256-bit context hash unique to this transaction. + */ +uint256 +getSendContextHash( + AccountID const& account, + uint192 const& issuanceID, + std::uint32_t sequence, + AccountID const& destination, + std::uint32_t version); + +/** + * @brief Generates the context hash for ConfidentialMPTClawback transactions. + * + * Creates a unique 256-bit hash that binds the equality proof to this + * specific clawback transaction. + * + * @param account The issuer's account ID. + * @param issuanceID The MPToken Issuance ID. + * @param sequence The transaction sequence number or ticket number. + * @param holder The holder's account ID being clawed back from. + * @return A 256-bit context hash unique to this transaction. + */ +uint256 +getClawbackContextHash( + AccountID const& account, + uint192 const& issuanceID, + std::uint32_t sequence, + AccountID const& holder); + +/** + * @brief Generates the context hash for ConfidentialMPTConvert transactions. + * + * Creates a unique 256-bit hash that binds the Schnorr proof (for key + * registration) to this specific convert transaction. + * + * @param account The holder's account ID. + * @param issuanceID The MPToken Issuance ID. + * @param sequence The transaction sequence number or a ticket number. + * @return A 256-bit context hash unique to this transaction. + */ +uint256 +getConvertContextHash(AccountID const& account, uint192 const& issuanceID, std::uint32_t sequence); + +/** + * @brief Generates the context hash for ConfidentialMPTConvertBack transactions. + * + * Creates a unique 256-bit hash that binds the zero-knowledge proofs to + * this specific convert-back transaction. + * + * @param account The holder's account ID. + * @param issuanceID The MPToken Issuance ID. + * @param sequence The transaction sequence number or a ticket number. + * @param version The holder's confidential balance version. + * @return A 256-bit context hash unique to this transaction. + */ +uint256 +getConvertBackContextHash( + AccountID const& account, + uint192 const& issuanceID, + std::uint32_t sequence, + std::uint32_t version); + +/** + * @brief Parses an ElGamal ciphertext into two secp256k1 public key components. + * + * Breaks an encrypted amount (size=xrpl::kEcGamalEncryptedTotalLength, two + * compressed EC points of size=xrpl::kEcCiphertextComponentLength) into + * a pair containing (C1, C2) for use in cryptographic operations. + * + * @param buffer The buffer containing the compressed ciphertext + * (size=xrpl::kEcGamalEncryptedTotalLength). + * @return The parsed pair (c1, c2) if successful, std::nullopt if the buffer is invalid. + */ +std::optional +makeEcPair(Slice const& buffer); + +/** + * @brief Serializes an EcPair into compressed form. + * + * Converts an EcPair (C1, C2) back into a buffer + * (size=xrpl::kEcGamalEncryptedTotalLength) containing two compressed EC + * points (size=xrpl::kEcCiphertextComponentLength each). + * + * @param pair The EcPair to serialize. + * @return The buffer (size=xrpl::kEcGamalEncryptedTotalLength), or std::nullopt + * if serialization fails. + */ +std::optional +serializeEcPair(EcPair const& pair); + +/** + * @brief Verifies that a buffer contains two valid, parsable EC public keys. + * + * @param buffer The input buffer containing two concatenated components. + * @return true if both components can be parsed successfully, false otherwise. + */ +bool +isValidCiphertext(Slice const& buffer); + +/** + * @brief Verifies that a buffer contains a valid, parsable compressed EC point. + * + * Can be used to validate both compressed public keys and Pedersen commitments. + * Fails early if the prefix byte is not 0x02 or 0x03. + * + * @param buffer The input buffer containing a compressed EC point + * (size=xrpl::kCompressedEcPointLength). + * @return true if the point can be parsed successfully, false otherwise. + */ +bool +isValidCompressedECPoint(Slice const& buffer); + +/** + * @brief Homomorphically adds two ElGamal ciphertexts. + * + * Uses the additive homomorphic property of ElGamal encryption to compute + * Enc(a + b) from Enc(a) and Enc(b) without decryption. + * + * @param a The first ciphertext (size=xrpl::kEcGamalEncryptedTotalLength). + * @param b The second ciphertext (size=xrpl::kEcGamalEncryptedTotalLength). + * @return The resulting ciphertext Enc(a + b), or std::nullopt on failure. + */ +std::optional +homomorphicAdd(Slice const& a, Slice const& b); + +/** + * @brief Homomorphically subtracts two ElGamal ciphertexts. + * + * Uses the additive homomorphic property of ElGamal encryption to compute + * Enc(a - b) from Enc(a) and Enc(b) without decryption. + * + * @param a The minuend ciphertext (size=xrpl::kEcGamalEncryptedTotalLength). + * @param b The subtrahend ciphertext (size=xrpl::kEcGamalEncryptedTotalLength). + * @return The resulting ciphertext Enc(a - b), or std::nullopt on failure. + */ +std::optional +homomorphicSubtract(Slice const& a, Slice const& b); + +/** + * @brief Re-randomizes an ElGamal ciphertext without changing its plaintext. + * + * Adds Enc(0; randomness) under the supplied public key to the ciphertext. + * This is used when a public, deterministic scalar must perturb ciphertext + * randomness while preserving ledger reproducibility. + * + * @param ciphertext The ciphertext to re-randomize + * (size=xrpl::kEcGamalEncryptedTotalLength). + * @param pubKeySlice The ElGamal public key matching the ciphertext recipient. + * @param randomness The scalar used as zero-encryption randomness + * (size=xrpl::kEcScalarLength). + * @return The re-randomized ciphertext, or std::nullopt on failure. + */ +std::optional +rerandomizeCiphertext(Slice const& ciphertext, Slice const& pubKeySlice, Slice const& randomness); + +/** + * @brief Encrypts an amount using ElGamal encryption. + * + * Produces a ciphertext C = (C1, C2) where C1 = r*G and C2 = m*G + r*Pk, + * using the provided blinding factor r. + * + * @param amt The plaintext amount to encrypt. + * @param pubKeySlice The recipient's ElGamal public key (size=xrpl::kEcPubKeyLength). + * @param blindingFactor The randomness used as blinding factor r + * (size=xrpl::ecBlindingFactorLength). + * @return The ciphertext (size=xrpl::kEcGamalEncryptedTotalLength), or std::nullopt on failure. + */ +std::optional +encryptAmount(uint64_t const amt, Slice const& pubKeySlice, Slice const& blindingFactor); + +/** + * @brief Generates the canonical zero encryption for a specific MPToken. + * + * Creates a deterministic encryption of zero that is unique to the account + * and MPT issuance. Used to initialize confidential balance fields. + * + * @param pubKeySlice The holder's ElGamal public key (size=xrpl::kEcPubKeyLength). + * @param account The account ID of the token holder. + * @param mptId The MPToken Issuance ID. + * @return The canonical zero ciphertext (size=xrpl::kEcGamalEncryptedTotalLength), or std::nullopt + * on failure. + */ +std::optional +encryptCanonicalZeroAmount(Slice const& pubKeySlice, AccountID const& account, MPTID const& mptId); + +/** + * @brief Verifies a Schnorr proof of knowledge of an ElGamal private key. + * + * Proves that the submitter knows the secret key corresponding to the + * provided public key, without revealing the secret key itself. + * + * @param pubKeySlice The ElGamal public key (size=xrpl::kEcPubKeyLength). + * @param proofSlice The Schnorr proof (size=xrpl::ecSchnorrProofLength). + * @param contextHash The 256-bit context hash binding the proof. + * @return tesSUCCESS if valid, or an error code otherwise. + */ +TER +verifySchnorrProof(Slice const& pubKeySlice, Slice const& proofSlice, uint256 const& contextHash); + +/** + * @brief Validates the format of encrypted amount fields in a transaction. + * + * Checks that all ciphertext fields in the transaction object have the + * correct length and contain valid EC points. This function is only used + * by ConfidentialMPTConvert and ConfidentialMPTConvertBack transactions. + * + * @param object The transaction object containing encrypted amount fields. + * @return tesSUCCESS if all formats are valid, temMALFORMED if required fields + * are missing, or temBAD_CIPHERTEXT if format validation fails. + */ +NotTEC +checkEncryptedAmountFormat(STObject const& object); + +/** + * @brief Verifies revealed amount encryptions for all recipients. + * + * Validates that the same amount was correctly encrypted for the holder, + * issuer, and optionally the auditor using their respective public keys. + * + * @param amount The revealed plaintext amount. + * @param blindingFactor The blinding factor used in all encryptions + * (size=xrpl::ecBlindingFactorLength). + * @param holder The holder's public key and encrypted amount. + * @param issuer The issuer's public key and encrypted amount. + * @param auditor Optional auditor's public key and encrypted amount. + * @return tesSUCCESS if all encryptions are valid, or an error code otherwise. + */ +TER +verifyRevealedAmount( + uint64_t const amount, + Slice const& blindingFactor, + ConfidentialRecipient const& holder, + ConfidentialRecipient const& issuer, + std::optional const& auditor); + +/** + * @brief Returns the number of recipients in a confidential transfer. + * + * Returns 4 if an auditor is present (sender, destination, issuer, auditor), + * or 3 if no auditor (sender, destination, issuer). + * + * @param hasAuditor Whether the issuance has an auditor configured. + * @return The number of recipients (3 or 4). + */ +constexpr uint8_t +getConfidentialRecipientCount(bool hasAuditor) +{ + return hasAuditor ? 4 : 3; +} + +/** + * @brief Verifies a compact sigma clawback proof. + * + * Proves that the issuer knows the exact amount encrypted in the holder's + * balance ciphertext. Used in ConfidentialMPTClawback to verify the issuer + * can decrypt the balance using their private key. + * + * @param amount The revealed plaintext amount. + * @param proof The zero-knowledge proof bytes (ecClawbackProofLength). + * @param pubKeySlice The issuer's ElGamal public key (kEcPubKeyLength bytes). + * @param ciphertext The issuer's encrypted balance on the holder's account + * (kEcGamalEncryptedTotalLength bytes). + * @param contextHash The 256-bit context hash binding the proof. + * @return tesSUCCESS if the proof is valid, or an error code otherwise. + */ +TER +verifyClawbackProof( + uint64_t const amount, + Slice const& proof, + Slice const& pubKeySlice, + Slice const& ciphertext, + uint256 const& contextHash); + +/** + * @brief Generates a cryptographically secure blinding factor + * (size=xrpl::kEcBlindingFactorLength). + * + * Produces random bytes suitable for use as an ElGamal blinding factor + * or Pedersen commitment randomness. + * + * @return A buffer containing the random blinding factor + * (size=xrpl::kEcBlindingFactorLength). + */ +Buffer +generateBlindingFactor(); + +/** + * @brief Verifies all zero-knowledge proofs for a ConfidentialMPTSend transaction. + * + * This function calls mpt_verify_send_proof API in the mpt-crypto utility lib, which verifies the + * equality proof, amount linkage, balance linkage, and range proof. + * Equality proof: Proves the same value is encrypted for the sender, receiver, issuer, and auditor. + * Amount linkage: Proves the send amount matches the amount Pedersen commitment. + * Balance linkage: Proves the sender's balance matches the balance Pedersen + * commitment. + * Range proof: Proves the amount and the remaining balance are within range [0, 2^64-1]. + * + * @param proof The full proof blob. + * @param sender The sender's public key and encrypted amount. + * @param destination The destination's public key and encrypted amount. + * @param issuer The issuer's public key and encrypted amount. + * @param auditor The auditor's public key and encrypted amount if present. + * @param spendingBalance The sender's current spending balance ciphertext. + * @param amountCommitment The Pedersen commitment to the send amount. + * @param balanceCommitment The Pedersen commitment to the sender's balance. + * @param contextHash The context hash binding the proof. + * @return tesSUCCESS if all proofs are valid, or an error code otherwise. + */ +TER +verifySendProof( + Slice const& proof, + ConfidentialRecipient const& sender, + ConfidentialRecipient const& destination, + ConfidentialRecipient const& issuer, + std::optional const& auditor, + Slice const& spendingBalance, + Slice const& amountCommitment, + Slice const& balanceCommitment, + uint256 const& contextHash); + +/** + * @brief Verifies all zero-knowledge proofs for a ConfidentialMPTConvertBack transaction. + * + * This function calls mpt_verify_convert_back_proof API in the mpt-crypto utility lib, which + * verifies the balance linkage proof and range proof. Balance linkage proof: proves the balance + * commitment matches the spending ciphertext. Range proof: proves the remaining balance after + * convert back is within range [0, 2^64-1]. + * + * @param proof The full proof blob. + * @param pubKeySlice The holder's public key. + * @param spendingBalance The holder's spending balance ciphertext. + * @param balanceCommitment The Pedersen commitment to the balance. + * @param amount The amount being converted back to public. + * @param contextHash The context hash binding the proof. + * @return tesSUCCESS if all proofs are valid, or an error code otherwise. + */ +TER +verifyConvertBackProof( + Slice const& proof, + Slice const& pubKeySlice, + Slice const& spendingBalance, + Slice const& balanceCommitment, + uint64_t amount, + uint256 const& contextHash); + +} // namespace xrpl diff --git a/include/xrpl/protocol/ErrorCodes.h b/include/xrpl/protocol/ErrorCodes.h index f5e67fd572..8ac7c8c58f 100644 --- a/include/xrpl/protocol/ErrorCodes.h +++ b/include/xrpl/protocol/ErrorCodes.h @@ -1,7 +1,8 @@ #pragma once #include -#include + +#include namespace xrpl { @@ -146,10 +147,11 @@ enum ErrorCodeI { RpcLast = RpcUnexpectedLedgerType // rpcLAST should always equal the last code. }; -/** Codes returned in the `warnings` array of certain RPC commands. - - These values need to remain stable. -*/ +/** + * Codes returned in the `warnings` array of certain RPC commands. + * + * These values need to remain stable. + */ // Protocol-wide, 50+ files // NOLINTNEXTLINE(cppcoreguidelines-use-enum-class) enum WarningCodeI { @@ -167,7 +169,9 @@ enum WarningCodeI { namespace RPC { -/** Maps an rpc error code to its token, default message, and HTTP status. */ +/** + * Maps an rpc error code to its token, default message, and HTTP status. + */ struct ErrorInfo { // Default ctor needed to produce an empty std::array during constexpr eval. @@ -192,11 +196,15 @@ struct ErrorInfo int httpStatus; }; -/** Returns an ErrorInfo that reflects the error code. */ +/** + * Returns an ErrorInfo that reflects the error code. + */ ErrorInfo const& getErrorInfo(ErrorCodeI code); -/** Add or update the json update to reflect the error code. */ +/** + * Add or update the json update to reflect the error code. + */ /** @{ */ void injectError(ErrorCodeI code, json::Value& json); @@ -205,7 +213,9 @@ void injectError(ErrorCodeI code, std::string const& message, json::Value& json); /** @} */ -/** Returns a new json object that reflects the error code. */ +/** + * Returns a new json object that reflects the error code. + */ /** @{ */ json::Value makeError(ErrorCodeI code); @@ -213,7 +223,9 @@ json::Value makeError(ErrorCodeI code, std::string const& message); /** @} */ -/** Returns a new json object that indicates invalid parameters. */ +/** + * Returns a new json object that indicates invalid parameters. + */ /** @{ */ inline json::Value makeParamError(std::string const& message) @@ -313,17 +325,23 @@ notValidatorError() /** @} */ -/** Returns `true` if the json contains an rpc error specification. */ +/** + * Returns `true` if the json contains an rpc error specification. + */ bool containsError(json::Value const& json); -/** Returns http status that corresponds to the error code. */ +/** + * Returns http status that corresponds to the error code. + */ int errorCodeHttpStatus(ErrorCodeI code); } // namespace RPC -/** Returns a single string with the contents of an RPC error. */ +/** + * Returns a single string with the contents of an RPC error. + */ std::string rpcErrorString(json::Value const& jv); diff --git a/include/xrpl/protocol/Feature.h b/include/xrpl/protocol/Feature.h index 5de8ca64a9..f15b7e2d3f 100644 --- a/include/xrpl/protocol/Feature.h +++ b/include/xrpl/protocol/Feature.h @@ -1,10 +1,12 @@ #pragma once #include +#include #include #include +#include #include #include #include @@ -110,7 +112,9 @@ validFeatureName(auto fn) -> bool enum class VoteBehavior : int { Obsolete = -1, DefaultNo = 0, DefaultYes = 1 }; enum class AmendmentSupport : int { Retired = -1, Supported = 0, Unsupported = 1 }; -/** All amendments libxrpl knows about. */ +/** + * All amendments libxrpl knows about. + */ std::map const& allAmendments(); @@ -150,23 +154,27 @@ static constexpr std::size_t kNumFeatures = #undef XRPL_FEATURE #pragma pop_macro("XRPL_FEATURE") -/** Amendments that this server supports and the default voting behavior. - Whether they are enabled depends on the Rules defined in the validated - ledger */ +/** + * Amendments that this server supports and the default voting behavior. + * Whether they are enabled depends on the Rules defined in the validated + * ledger + */ std::map const& supportedAmendments(); -/** Amendments that this server won't vote for by default. - - This function is only used in unit tests. -*/ +/** + * Amendments that this server won't vote for by default. + * + * This function is only used in unit tests. + */ std::size_t numDownVotedAmendments(); -/** Amendments that this server will vote for by default. - - This function is only used in unit tests. -*/ +/** + * Amendments that this server will vote for by default. + * + * This function is only used in unit tests. + */ std::size_t numUpVotedAmendments(); diff --git a/include/xrpl/protocol/Fees.h b/include/xrpl/protocol/Fees.h index 14bcc068bf..fdfadcd8fd 100644 --- a/include/xrpl/protocol/Fees.h +++ b/include/xrpl/protocol/Fees.h @@ -2,26 +2,35 @@ #include +#include + namespace xrpl { // Deprecated constant for backwards compatibility with pre-XRPFees amendment. // This was the reference fee units used in the old fee calculation. inline constexpr std::uint32_t kFeeUnitsDeprecated = 10; -/** Reflects the fee settings for a particular ledger. - - The fees are always the same for any transactions applied - to a ledger. Changes to fees occur in between ledgers. -*/ +/** + * Reflects the fee settings for a particular ledger. + * + * The fees are always the same for any transactions applied + * to a ledger. Changes to fees occur in between ledgers. + */ struct Fees { - /** @brief Cost of a reference transaction in drops. */ + /** + * @brief Cost of a reference transaction in drops. + */ XRPAmount base{0}; - /** @brief Minimum XRP an account must hold to exist on the ledger. */ + /** + * @brief Minimum XRP an account must hold to exist on the ledger. + */ XRPAmount reserve{0}; - /** @brief Additional XRP reserve required per owned ledger object. */ + /** + * @brief Additional XRP reserve required per owned ledger object. + */ XRPAmount increment{0}; explicit Fees() = default; @@ -34,15 +43,16 @@ struct Fees { } - /** Returns the account reserve given the owner count, in drops. - - The reserve is calculated as the reserve base plus - the reserve increment times the number of increments. - */ + /** + * Returns the account reserve given the owner count, in drops. + * + * The reserve is calculated as the reserve base times the number of accounts plus the reserve + * increment times the number of increments. + */ [[nodiscard]] XRPAmount - accountReserve(std::size_t ownerCount) const + accountReserve(std::uint32_t ownerCount, std::uint32_t accountCount) const { - return reserve + ownerCount * increment; + return (reserve * accountCount) + (increment * ownerCount); } }; diff --git a/include/xrpl/protocol/HashPrefix.h b/include/xrpl/protocol/HashPrefix.h index 1b05d450a1..9d4471d05c 100644 --- a/include/xrpl/protocol/HashPrefix.h +++ b/include/xrpl/protocol/HashPrefix.h @@ -17,55 +17,80 @@ makeHashPrefix(char a, char b, char c) } // namespace detail -/** Prefix for hashing functions. - - These prefixes are inserted before the source material used to generate - various hashes. This is done to put each hash in its own "space." This way, - two different types of objects with the same binary data will produce - different hashes. - - Each prefix is a 4-byte value with the last byte set to zero and the first - three bytes formed from the ASCII equivalent of some arbitrary string. For - example "TXN". - - @note Hash prefixes are part of the protocol; you cannot, arbitrarily, - change the type or the value of any of these without causing breakage. -*/ +/** + * Prefix for hashing functions. + * + * These prefixes are inserted before the source material used to generate + * various hashes. This is done to put each hash in its own "space." This way, + * two different types of objects with the same binary data will produce + * different hashes. + * + * Each prefix is a 4-byte value with the last byte set to zero and the first + * three bytes formed from the ASCII equivalent of some arbitrary string. For + * example "TXN". + * + * @note Hash prefixes are part of the protocol; you cannot, arbitrarily, + * change the type or the value of any of these without causing breakage. + */ enum class HashPrefix : std::uint32_t { - /** transaction plus signature to give transaction ID */ + /** + * transaction plus signature to give transaction ID + */ TransactionId = detail::makeHashPrefix('T', 'X', 'N'), - /** transaction plus metadata */ + /** + * transaction plus metadata + */ TxNode = detail::makeHashPrefix('S', 'N', 'D'), - /** account state */ + /** + * account state + */ LeafNode = detail::makeHashPrefix('M', 'L', 'N'), - /** inner node in V1 tree */ + /** + * inner node in V1 tree + */ InnerNode = detail::makeHashPrefix('M', 'I', 'N'), - /** ledger master data for signing */ + /** + * ledger master data for signing + */ LedgerMaster = detail::makeHashPrefix('L', 'W', 'R'), - /** inner transaction to sign */ + /** + * inner transaction to sign + */ TxSign = detail::makeHashPrefix('S', 'T', 'X'), - /** inner transaction to multi-sign */ + /** + * inner transaction to multi-sign + */ TxMultiSign = detail::makeHashPrefix('S', 'M', 'T'), - /** validation for signing */ + /** + * validation for signing + */ Validation = detail::makeHashPrefix('V', 'A', 'L'), - /** proposal for signing */ + /** + * proposal for signing + */ Proposal = detail::makeHashPrefix('P', 'R', 'P'), - /** Manifest */ + /** + * Manifest + */ Manifest = detail::makeHashPrefix('M', 'A', 'N'), - /** Payment Channel Claim */ + /** + * Payment Channel Claim + */ PaymentChannelClaim = detail::makeHashPrefix('C', 'L', 'M'), - /** Batch */ + /** + * Batch + */ Batch = detail::makeHashPrefix('B', 'C', 'H'), }; diff --git a/include/xrpl/protocol/IOUAmount.h b/include/xrpl/protocol/IOUAmount.h index b057f1c245..060ad3d828 100644 --- a/include/xrpl/protocol/IOUAmount.h +++ b/include/xrpl/protocol/IOUAmount.h @@ -6,20 +6,22 @@ #include #include +#include #include namespace xrpl { -/** Floating point representation of amounts with high dynamic range - - Amounts are stored as a normalized signed mantissa and an exponent. The - range of the normalized exponent is [-96,80] and the range of the absolute - value of the normalized mantissa is [1000000000000000, 9999999999999999]. - - Arithmetic operations can throw std::overflow_error during normalization - if the amount exceeds the largest representable amount, but underflows - will silently truncate to zero. -*/ +/** + * Floating point representation of amounts with high dynamic range + * + * Amounts are stored as a normalized signed mantissa and an exponent. The + * range of the normalized exponent is [-96,80] and the range of the absolute + * value of the normalized mantissa is [1000000000000000, 9999999999999999]. + * + * Arithmetic operations can throw std::overflow_error during normalization + * if the amount exceeds the largest representable amount, but underflows + * will silently truncate to zero. + */ class IOUAmount : private boost::totally_ordered, private boost::additive { private: @@ -28,12 +30,13 @@ private: mantissa_type mantissa_{}; exponent_type exponent_{}; - /** Adjusts the mantissa and exponent to the proper range. - - This can throw if the amount cannot be normalized, or is larger than - the largest value that can be represented as an IOU amount. Amounts - that are too small to be represented normalize to 0. - */ + /** + * Adjusts the mantissa and exponent to the proper range. + * + * This can throw if the amount cannot be normalized, or is larger than + * the largest value that can be represented as an IOU amount. Amounts + * that are too small to be represented normalize to 0. + */ void normalize(); @@ -65,11 +68,15 @@ public: bool operator<(IOUAmount const& other) const; - /** Returns true if the amount is not zero */ + /** + * Returns true if the amount is not zero + */ explicit operator bool() const noexcept; - /** Return the sign of the amount */ + /** + * Return the sign of the amount + */ [[nodiscard]] int signum() const noexcept; diff --git a/include/xrpl/protocol/Indexes.h b/include/xrpl/protocol/Indexes.h index 887a208ec6..5a76119649 100644 --- a/include/xrpl/protocol/Indexes.h +++ b/include/xrpl/protocol/Indexes.h @@ -1,108 +1,127 @@ #pragma once +#include #include +#include +#include +#include +#include #include +#include #include #include #include -#include #include -#include #include #include +#include #include +#include #include +#include namespace xrpl { class SeqProxy; -/** Keylet computation functions. - - Entries in the ledger are located using 256-bit locators. The locators are - calculated using a wide range of parameters specific to the entry whose - locator we are calculating (e.g. an account's locator is derived from the - account's address, whereas the locator for an offer is derived from the - account and the offer sequence.) - - To enhance type safety during lookup and make the code more robust, we use - keylets, which contain not only the locator of the object but also the type - of the object being referenced. - - These functions each return a type-specific keylet. -*/ +/** + * Keylet computation functions. + * + * Entries in the ledger are located using 256-bit locators. The locators are + * calculated using a wide range of parameters specific to the entry whose + * locator we are calculating (e.g. an account's locator is derived from the + * account's address, whereas the locator for an offer is derived from the + * account and the offer sequence.) + * + * To enhance type safety during lookup and make the code more robust, we use + * keylets, which contain not only the locator of the object but also the type + * of the object being referenced. + * + * These functions each return a type-specific keylet. + */ namespace keylet { -/** AccountID root */ +/** + * AccountID root + */ Keylet account(AccountID const& id) noexcept; -/** The index of the amendment table */ +/** + * The index of the amendment table + */ Keylet const& amendments() noexcept; -/** Any item that can be in an owner dir. */ +/** + * Any item that can be in an owner dir. + */ Keylet child(uint256 const& key) noexcept; -/** The index of the "short" skip list - - The "short" skip list is a node (at a fixed index) that holds the hashes - of ledgers since the last flag ledger. It will contain, at most, 256 hashes. -*/ +/** + * The index of the "short" skip list + * + * The "short" skip list is a node (at a fixed index) that holds the hashes + * of ledgers since the last flag ledger. It will contain, at most, 256 hashes. + */ Keylet const& skip() noexcept; -/** The index of the long skip for a particular ledger range. - - The "long" skip list is a node that holds the hashes of (up to) 256 flag - ledgers. - - It can be used to efficiently skip back to any ledger using only two hops: - the first hop gets the "long" skip list for the ledger it wants to retrieve - and uses it to get the hash of the flag ledger whose short skip list will - contain the hash of the requested ledger. -*/ +/** + * The index of the long skip for a particular ledger range. + * + * The "long" skip list is a node that holds the hashes of (up to) 256 flag + * ledgers. + * + * It can be used to efficiently skip back to any ledger using only two hops: + * the first hop gets the "long" skip list for the ledger it wants to retrieve + * and uses it to get the hash of the flag ledger whose short skip list will + * contain the hash of the requested ledger. + */ Keylet skip(LedgerIndex ledger) noexcept; -/** The (fixed) index of the object containing the ledger fees. */ +/** + * The (fixed) index of the object containing the ledger fees. + */ Keylet const& -fees() noexcept; +feeSettings() noexcept; -/** The (fixed) index of the object containing the ledger negativeUNL. */ +/** + * The (fixed) index of the object containing the ledger negativeUNL. + */ Keylet const& negativeUNL() noexcept; -/** The beginning of an order book */ -struct BookT -{ - explicit BookT() = default; +/** + * The beginning of an order book + */ +Keylet +book(Book const& b); - Keylet - operator()(Book const& b) const; -}; -static BookT const kBook{}; - -/** The index of a trust line for a given currency - - Note that a trustline is *shared* between two accounts (commonly referred - to as the issuer and the holder); if Alice sets up a trust line to Bob for - BTC, and Bob trusts Alice for BTC, here is only a single BTC trust line - between them. -*/ +/** + * The index of a trust line for a given currency + * + * Note that a trustline is *shared* between two accounts (commonly referred + * to as the issuer and the holder); if Alice sets up a trust line to Bob for + * BTC, and Bob trusts Alice for BTC, here is only a single BTC trust line + * between them. + */ /** @{ */ Keylet -line(AccountID const& id0, AccountID const& id1, Currency const& currency) noexcept; +trustLine(AccountID const& id0, AccountID const& id1, Currency const& currency) noexcept; inline Keylet -line(AccountID const& id, Issue const& issue) noexcept +trustLine(AccountID const& id, Issue const& issue) noexcept { - return line(id, issue.account, issue.currency); + return trustLine(id, issue.account, issue.currency); } /** @} */ -/** An offer from an account */ +/** + * An offer from an account + */ /** @{ */ Keylet offer(AccountID const& id, std::uint32_t seq) noexcept; @@ -114,44 +133,50 @@ offer(uint256 const& key) noexcept } /** @} */ -/** The initial directory page for a specific quality */ +/** + * The initial directory page for a specific quality + */ Keylet quality(Keylet const& k, std::uint64_t q) noexcept; -/** The directory for the next lower quality */ -struct NextT -{ - explicit NextT() = default; - - Keylet - operator()(Keylet const& k) const; -}; -static NextT const kNext{}; - -/** A ticket belonging to an account */ -struct TicketT -{ - explicit TicketT() = default; - - Keylet - operator()(AccountID const& id, std::uint32_t ticketSeq) const; - - Keylet - operator()(AccountID const& id, SeqProxy ticketSeq) const; - - Keylet - operator()(uint256 const& key) const - { - return {ltTICKET, key}; - } -}; -static TicketT const kTicket{}; - -/** A SignerList */ +/** + * The directory for the next lower quality + */ Keylet -signers(AccountID const& account) noexcept; +next(Keylet const& k); -/** A Check */ +/** + * A ticket belonging to an account + */ +/** @{ */ +Keylet +ticket(AccountID const& id, std::uint32_t ticketSeq); + +Keylet +ticket(AccountID const& id, SeqProxy ticketSeq); + +inline Keylet +ticket(uint256 const& key) +{ + return {ltTICKET, key}; +} +/** @} */ + +/** + * A SignerList + */ +Keylet +signerList(AccountID const& account) noexcept; + +/** + * A Sponsorship + */ +Keylet +sponsorship(AccountID const& sponsor, AccountID const& sponsee) noexcept; + +/** + * A Check + */ /** @{ */ Keylet check(AccountID const& id, std::uint32_t seq) noexcept; @@ -163,7 +188,9 @@ check(uint256 const& key) noexcept } /** @} */ -/** A DepositPreauth */ +/** + * A DepositPreauth + */ /** @{ */ Keylet depositPreauth(AccountID const& owner, AccountID const& preauthorized) noexcept; @@ -182,15 +209,21 @@ depositPreauth(uint256 const& key) noexcept //------------------------------------------------------------------------------ -/** Any ledger entry */ +/** + * Any ledger entry + */ Keylet unchecked(uint256 const& key) noexcept; -/** The root page of an account's directory */ +/** + * The root page of an account's directory + */ Keylet ownerDir(AccountID const& id) noexcept; -/** A page in a directory */ +/** + * A page in a directory + */ /** @{ */ Keylet page(uint256 const& root, std::uint64_t index = 0) noexcept; @@ -203,60 +236,79 @@ page(Keylet const& root, std::uint64_t index = 0) noexcept } /** @} */ -/** An escrow entry */ +/** + * An escrow entry + */ Keylet escrow(AccountID const& src, std::uint32_t seq) noexcept; -/** A PaymentChannel */ +/** + * A PaymentChannel + */ Keylet -payChan(AccountID const& src, AccountID const& dst, std::uint32_t seq) noexcept; +payChannel(AccountID const& src, AccountID const& dst, std::uint32_t seq) noexcept; -/** NFT page keylets - - Unlike objects whose ledger identifiers are produced by hashing data, - NFT page identifiers are composite identifiers, consisting of the owner's - 160-bit AccountID, followed by a 96-bit value that determines which NFT - tokens are candidates for that page. +/** + * NFT page keylets + * + * Unlike objects whose ledger identifiers are produced by hashing data, + * NFT page identifiers are composite identifiers, consisting of the owner's + * 160-bit AccountID, followed by a 96-bit value that determines which NFT + * tokens are candidates for that page. */ /** @{ */ -/** A keylet for the owner's first possible NFT page. */ +/** + * A keylet for the owner's first possible NFT page. + */ Keylet -nftpageMin(AccountID const& owner); +nftokenPageMin(AccountID const& owner); -/** A keylet for the owner's last possible NFT page. */ +/** + * A keylet for the owner's last possible NFT page. + */ Keylet -nftpageMax(AccountID const& owner); +nftokenPageMax(AccountID const& owner); Keylet -nftpage(Keylet const& k, uint256 const& token); +nftokenPage(Keylet const& k, uint256 const& token); /** @} */ -/** An offer from an account to buy or sell an NFT */ +/** + * An offer from an account to buy or sell an NFT + */ Keylet -nftoffer(AccountID const& owner, std::uint32_t seq); +nftokenOffer(AccountID const& owner, std::uint32_t seq); inline Keylet -nftoffer(uint256 const& offer) +nftokenOffer(uint256 const& offer) { return {ltNFTOKEN_OFFER, offer}; } -/** The directory of buy offers for the specified NFT */ +/** + * The directory of buy offers for the specified NFT + */ Keylet nftBuys(uint256 const& id) noexcept; -/** The directory of sell offers for the specified NFT */ +/** + * The directory of sell offers for the specified NFT + */ Keylet nftSells(uint256 const& id) noexcept; -/** AMM entry */ +/** + * AMM entry + */ Keylet amm(Asset const& issue1, Asset const& issue2) noexcept; Keylet amm(uint256 const& amm) noexcept; -/** A keylet for Delegate object */ +/** + * A keylet for Delegate object + */ Keylet delegate(AccountID const& account, AccountID const& authorizedAccount) noexcept; @@ -287,13 +339,13 @@ credential(uint256 const& key) noexcept } Keylet -mptIssuance(std::uint32_t seq, AccountID const& issuer) noexcept; +mptokenIssuance(std::uint32_t seq, AccountID const& issuer) noexcept; Keylet -mptIssuance(MPTID const& issuanceID) noexcept; +mptokenIssuance(MPTID const& issuanceID) noexcept; inline Keylet -mptIssuance(uint256 const& issuanceKey) +mptokenIssuance(uint256 const& issuanceKey) { return {ltMPTOKEN_ISSUANCE, issuanceKey}; } @@ -320,10 +372,10 @@ vault(uint256 const& vaultKey) } Keylet -loanbroker(AccountID const& owner, std::uint32_t seq) noexcept; +loanBroker(AccountID const& owner, std::uint32_t seq) noexcept; inline Keylet -loanbroker(uint256 const& key) +loanBroker(uint256 const& key) { return {ltLOAN_BROKER, key}; } @@ -376,11 +428,15 @@ struct KeyletDesc std::array, 6> const kDirectAccountKeylets{ {{.function = &keylet::account, .expectedLEName = jss::AccountRoot, .includeInTests = false}, {.function = &keylet::ownerDir, .expectedLEName = jss::DirectoryNode, .includeInTests = true}, - {.function = &keylet::signers, .expectedLEName = jss::SignerList, .includeInTests = true}, + {.function = &keylet::signerList, .expectedLEName = jss::SignerList, .includeInTests = true}, // It's normally impossible to create an item at nftpage_min, but // test it anyway, since the invariant checks for it. - {.function = &keylet::nftpageMin, .expectedLEName = jss::NFTokenPage, .includeInTests = true}, - {.function = &keylet::nftpageMax, .expectedLEName = jss::NFTokenPage, .includeInTests = true}, + {.function = &keylet::nftokenPageMin, + .expectedLEName = jss::NFTokenPage, + .includeInTests = true}, + {.function = &keylet::nftokenPageMax, + .expectedLEName = jss::NFTokenPage, + .includeInTests = true}, {.function = &keylet::did, .expectedLEName = jss::DID, .includeInTests = true}}}; MPTID diff --git a/include/xrpl/protocol/InnerObjectFormats.h b/include/xrpl/protocol/InnerObjectFormats.h index 9d07a21d1c..7364e83cfd 100644 --- a/include/xrpl/protocol/InnerObjectFormats.h +++ b/include/xrpl/protocol/InnerObjectFormats.h @@ -1,17 +1,21 @@ #pragma once #include +#include +#include namespace xrpl { -/** Manages the list of known inner object formats. +/** + * Manages the list of known inner object formats. */ class InnerObjectFormats : public KnownFormats { private: - /** Create the object. - This will load the object with all the known inner object formats. - */ + /** + * Create the object. + * This will load the object with all the known inner object formats. + */ InnerObjectFormats(); public: diff --git a/include/xrpl/protocol/Issue.h b/include/xrpl/protocol/Issue.h index c8022698d3..5cd8731609 100644 --- a/include/xrpl/protocol/Issue.h +++ b/include/xrpl/protocol/Issue.h @@ -1,14 +1,19 @@ #pragma once -#include #include +#include #include +#include +#include +#include + namespace xrpl { -/** A currency issued by an account. - @see Currency, AccountID, Issue, Book -*/ +/** + * A currency issued by an account. + * @see Currency, AccountID, Issue, Book + */ class Issue { public: @@ -66,7 +71,9 @@ hash_append(Hasher& h, Issue const& r) hash_append(h, r.currency, r.account); } -/** Equality comparison. */ +/** + * Equality comparison. + */ /** @{ */ [[nodiscard]] constexpr bool operator==(Issue const& lhs, Issue const& rhs) @@ -75,12 +82,14 @@ operator==(Issue const& lhs, Issue const& rhs) } /** @} */ -/** Strict weak ordering. */ +/** + * Strict weak ordering. + */ /** @{ */ [[nodiscard]] constexpr std::weak_ordering operator<=>(Issue const& lhs, Issue const& rhs) { - if (auto const c{lhs.currency <=> rhs.currency}; c != 0) + if (auto const c{lhs.currency <=> rhs.currency}; c != 0) // NOLINT(modernize-use-nullptr) return c; if (isXRP(lhs.currency)) @@ -92,7 +101,9 @@ operator<=>(Issue const& lhs, Issue const& rhs) //------------------------------------------------------------------------------ -/** Returns an asset specifier that represents XRP. */ +/** + * Returns an asset specifier that represents XRP. + */ inline Issue const& xrpIssue() { @@ -100,7 +111,9 @@ xrpIssue() return kIssue; } -/** Returns an asset specifier that represents no account and currency. */ +/** + * Returns an asset specifier that represents no account and currency. + */ inline Issue const& noIssue() { diff --git a/include/xrpl/protocol/Keylet.h b/include/xrpl/protocol/Keylet.h index 19704e2a11..48d494f564 100644 --- a/include/xrpl/protocol/Keylet.h +++ b/include/xrpl/protocol/Keylet.h @@ -7,14 +7,15 @@ namespace xrpl { class STLedgerEntry; -/** A pair of SHAMap key and LedgerEntryType. - - A Keylet identifies both a key in the state map - and its ledger entry type. - - @note Keylet is a portmanteau of the words key - and LET, an acronym for LedgerEntryType. -*/ +/** + * A pair of SHAMap key and LedgerEntryType. + * + * A Keylet identifies both a key in the state map + * and its ledger entry type. + * + * @note Keylet is a portmanteau of the words key + * and LET, an acronym for LedgerEntryType. + */ struct Keylet { uint256 key; @@ -24,7 +25,9 @@ struct Keylet { } - /** Returns true if the SLE matches the type */ + /** + * Returns true if the SLE matches the type + */ [[nodiscard]] bool check(STLedgerEntry const&) const; }; diff --git a/include/xrpl/protocol/KnownFormats.h b/include/xrpl/protocol/KnownFormats.h index 6e21d4bc3a..385feb2c27 100644 --- a/include/xrpl/protocol/KnownFormats.h +++ b/include/xrpl/protocol/KnownFormats.h @@ -7,22 +7,28 @@ #include #include +#include #include +#include +#include +#include namespace xrpl { -/** Manages a list of known formats. - - Each format has a name, an associated KeyType (typically an enumeration), - and a predefined @ref SOElement. - - @tparam KeyType The type of key identifying the format. -*/ +/** + * Manages a list of known formats. + * + * Each format has a name, an associated KeyType (typically an enumeration), + * and a predefined @ref SOElement. + * + * @tparam KeyType The type of key identifying the format. + */ template class KnownFormats { public: - /** A known format. + /** + * A known format. */ class Item { @@ -42,7 +48,8 @@ public: "KnownFormats KeyType must be integral or enum."); } - /** Retrieve the name of the format. + /** + * Retrieve the name of the format. */ [[nodiscard]] std::string const& getName() const @@ -50,7 +57,8 @@ public: return name_; } - /** Retrieve the transaction type this format represents. + /** + * Retrieve the transaction type this format represents. */ [[nodiscard]] KeyType getType() const @@ -70,32 +78,35 @@ public: KeyType const type_; }; - /** Create the known formats object. - - Derived classes will load the object with all the known formats. - */ + /** + * Create the known formats object. + * + * Derived classes will load the object with all the known formats. + */ private: KnownFormats() : name_(beast::typeName()) { } public: - /** Destroy the known formats object. - - The defined formats are deleted. - */ + /** + * Destroy the known formats object. + * + * The defined formats are deleted. + */ virtual ~KnownFormats() = default; KnownFormats(KnownFormats const&) = delete; KnownFormats& operator=(KnownFormats const&) = delete; - /** Retrieve the type for a format specified by name. - - If the format name is unknown, an exception is thrown. - - @param name The name of the type. - @return The type. - */ + /** + * Retrieve the type for a format specified by name. + * + * If the format name is unknown, an exception is thrown. + * + * @param name The name of the type. + * @return The type. + */ [[nodiscard]] KeyType findTypeByName(std::string const& name) const { @@ -106,7 +117,8 @@ public: name.substr(0, std::min(name.size(), std::size_t(32))) + "'"); } - /** Retrieve a format based on its type. + /** + * Retrieve a format based on its type. */ [[nodiscard]] Item const* findByType(KeyType type) const @@ -131,7 +143,8 @@ public: } protected: - /** Retrieve a format based on its name. + /** + * Retrieve a format based on its name. */ [[nodiscard]] Item const* findByName(std::string const& name) const @@ -142,15 +155,16 @@ protected: return itr->second; } - /** Add a new format. - - @param name The name of this format. - @param type The type of this format. - @param uniqueFields A std::vector of unique fields - @param commonFields A std::vector of common fields - - @return The created format. - */ + /** + * Add a new format. + * + * @param name The name of this format. + * @param type The type of this format. + * @param uniqueFields A std::vector of unique fields + * @param commonFields A std::vector of common fields + * + * @return The created format. + */ Item const& add(char const* name, KeyType type, diff --git a/include/xrpl/protocol/LedgerFormats.h b/include/xrpl/protocol/LedgerFormats.h index c1274e9e91..7c504f6bdd 100644 --- a/include/xrpl/protocol/LedgerFormats.h +++ b/include/xrpl/protocol/LedgerFormats.h @@ -3,34 +3,38 @@ // NOLINTBEGIN(readability-identifier-naming) #include +#include +#include #include #include +#include #include namespace xrpl { -/** Identifiers for on-ledger objects. - - Each ledger object requires a unique type identifier, which is stored within the object itself; - this makes it possible to iterate the entire ledger and determine each object's type and verify - that the object you retrieved from a given hash matches the expected type. - - @warning Since these values are stored inside objects stored on the ledger they are part of the - protocol. - **Changing them should be avoided because without special handling, this will result in a hard - fork.** - - @note Values outside this range may be used internally by the code for various purposes, but - attempting to use such values to identify on-ledger objects will result in an invariant failure. - - @note When retiring types, the specific values should not be removed but should be marked as - [[deprecated]]. This is to avoid accidental reuse of identifiers. - - @todo The C++ language does not enable checking for duplicate values here. - If it becomes possible then we should do this. - - @ingroup protocol -*/ +/** + * Identifiers for on-ledger objects. + * + * Each ledger object requires a unique type identifier, which is stored within the object itself; + * this makes it possible to iterate the entire ledger and determine each object's type and verify + * that the object you retrieved from a given hash matches the expected type. + * + * @warning Since these values are stored inside objects stored on the ledger they are part of the + * protocol. + * **Changing them should be avoided because without special handling, this will result in a hard + * fork.** + * + * @note Values outside this range may be used internally by the code for various purposes, but + * attempting to use such values to identify on-ledger objects will result in an invariant failure. + * + * @note When retiring types, the specific values should not be removed but should be marked as + * [[deprecated]]. This is to avoid accidental reuse of identifiers. + * + * @todo The C++ language does not enable checking for duplicate values here. + * If it becomes possible then we should do this. + * + * @ingroup protocol + */ // Protocol-critical, hundreds of usages // NOLINTNEXTLINE(cppcoreguidelines-use-enum-class) enum LedgerEntryType : std::uint16_t { @@ -46,66 +50,72 @@ enum LedgerEntryType : std::uint16_t { #pragma pop_macro("LEDGER_ENTRY") //--------------------------------------------------------------------------- - /** A special type, matching any ledger entry type. - - The value does not represent a concrete type, but rather is used in contexts where the - specific type of a ledger object is unimportant, unknown or unavailable. - - Objects with this special type cannot be created or stored on the ledger. - - \sa keylet::unchecked - */ + /** + * A special type, matching any ledger entry type. + * + * The value does not represent a concrete type, but rather is used in contexts where the + * specific type of a ledger object is unimportant, unknown or unavailable. + * + * Objects with this special type cannot be created or stored on the ledger. + * + * @see keylet::unchecked + */ ltANY = 0, - /** A special type, matching any ledger type except directory nodes. - - The value does not represent a concrete type, but rather is used in contexts where the - ledger object must not be a directory node but its specific type is otherwise unimportant, - unknown or unavailable. - - Objects with this special type cannot be created or stored on the ledger. - - \sa keylet::child + /** + * A special type, matching any ledger type except directory nodes. + * + * The value does not represent a concrete type, but rather is used in contexts where the + * ledger object must not be a directory node but its specific type is otherwise unimportant, + * unknown or unavailable. + * + * Objects with this special type cannot be created or stored on the ledger. + * + * @see keylet::child */ ltCHILD = 0x1CD2, //--------------------------------------------------------------------------- - /** A legacy, deprecated type. - - \deprecated **This object type is not supported and should not be used.** - Support for this type of object was never implemented. - No objects of this type were ever created. + /** + * A legacy, deprecated type. + * + * @deprecated **This object type is not supported and should not be used.** + * Support for this type of object was never implemented. + * No objects of this type were ever created. */ ltNICKNAME [[deprecated("This object type is not supported and should not be used.")]] = 0x006e, - /** A legacy, deprecated type. - - \deprecated **This object type is not supported and should not be used.** - Support for this type of object was never implemented. - No objects of this type were ever created. + /** + * A legacy, deprecated type. + * + * @deprecated **This object type is not supported and should not be used.** + * Support for this type of object was never implemented. + * No objects of this type were ever created. */ ltCONTRACT [[deprecated("This object type is not supported and should not be used.")]] = 0x0063, - /** A legacy, deprecated type. - - \deprecated **This object type is not supported and should not be used.** - Support for this type of object was never implemented. - No objects of this type were ever created. + /** + * A legacy, deprecated type. + * + * @deprecated **This object type is not supported and should not be used.** + * Support for this type of object was never implemented. + * No objects of this type were ever created. */ ltGENERATOR_MAP [[deprecated("This object type is not supported and should not be used.")]] = 0x0067, }; -/** Ledger object flags. - - These flags are specified in ledger objects and modify their behavior. - - @warning Ledger object flags form part of the protocol. - **Changing them should be avoided because without special handling, this will result in a hard - fork.** - - @ingroup protocol -*/ +/** + * Ledger object flags. + * + * These flags are specified in ledger objects and modify their behavior. + * + * @warning Ledger object flags form part of the protocol. + * **Changing them should be avoided because without special handling, this will result in a hard + * fork.** + * + * @ingroup protocol + */ #pragma push_macro("XMACRO") #pragma push_macro("TO_VALUE") #pragma push_macro("VALUE_TO_MAP") @@ -177,7 +187,8 @@ enum LedgerEntryType : std::uint16_t { LSF_FLAG(lsfMPTCanEscrow, 0x00000008) \ LSF_FLAG(lsfMPTCanTrade, 0x00000010) \ LSF_FLAG(lsfMPTCanTransfer, 0x00000020) \ - LSF_FLAG(lsfMPTCanClawback, 0x00000040)) \ + LSF_FLAG(lsfMPTCanClawback, 0x00000040) \ + LSF_FLAG(lsfMPTCanHoldConfidentialBalance, 0x00000080)) \ \ LEDGER_OBJECT(MPTokenIssuanceMutable, \ LSF_FLAG(lsmfMPTCanEnableCanLock, 0x00000002) \ @@ -186,8 +197,9 @@ enum LedgerEntryType : std::uint16_t { LSF_FLAG(lsmfMPTCanEnableCanTrade, 0x00000010) \ LSF_FLAG(lsmfMPTCanEnableCanTransfer, 0x00000020) \ LSF_FLAG(lsmfMPTCanEnableCanClawback, 0x00000040) \ + LSF_FLAG(lsmfMPTCannotEnableCanHoldConfidentialBalance, 0x00000080) \ LSF_FLAG(lsmfMPTCanMutateMetadata, 0x00010000) \ - LSF_FLAG(lsmfMPTCanMutateTransferFee, 0x00020000)) \ + LSF_FLAG(lsmfMPTCanMutateTransferFee, 0x00020000)) \ \ LEDGER_OBJECT(MPToken, \ LSF_FLAG2(lsfMPTLocked, 0x00000001) \ @@ -203,7 +215,11 @@ enum LedgerEntryType : std::uint16_t { LEDGER_OBJECT(Loan, \ LSF_FLAG(lsfLoanDefault, 0x00010000) \ LSF_FLAG(lsfLoanImpaired, 0x00020000) \ - LSF_FLAG(lsfLoanOverpayment, 0x00040000)) /* True, loan allows overpayments */ + LSF_FLAG(lsfLoanOverpayment, 0x00040000)) /* True, loan allows overpayments */ \ + \ + LEDGER_OBJECT(Sponsorship, \ + LSF_FLAG(lsfSponsorshipRequireSignForFee, 0x00010000) \ + LSF_FLAG(lsfSponsorshipRequireSignForReserve, 0x00020000)) // clang-format on @@ -280,14 +296,16 @@ getAllLedgerFlags() //------------------------------------------------------------------------------ -/** Holds the list of known ledger entry formats. +/** + * Holds the list of known ledger entry formats. */ class LedgerFormats : public KnownFormats { private: - /** Create the object. - This will load the object with all the known ledger formats. - */ + /** + * Create the object. + * This will load the object with all the known ledger formats. + */ LedgerFormats(); public: diff --git a/include/xrpl/protocol/LedgerHeader.h b/include/xrpl/protocol/LedgerHeader.h index f05b11d1eb..d169e53e2c 100644 --- a/include/xrpl/protocol/LedgerHeader.h +++ b/include/xrpl/protocol/LedgerHeader.h @@ -3,13 +3,18 @@ #include #include #include +#include #include #include #include +#include + namespace xrpl { -/** Information about the notional ledger backing the view. */ +/** + * Information about the notional ledger backing the view. + */ struct LedgerHeader { explicit LedgerHeader() = default; @@ -64,15 +69,21 @@ getCloseAgree(LedgerHeader const& info) void addRaw(LedgerHeader const&, Serializer&, bool includeHash = false); -/** Deserialize a ledger header from a byte array. */ +/** + * Deserialize a ledger header from a byte array. + */ LedgerHeader deserializeHeader(Slice data, bool hasHash = false); -/** Deserialize a ledger header (prefixed with 4 bytes) from a byte array. */ +/** + * Deserialize a ledger header (prefixed with 4 bytes) from a byte array. + */ LedgerHeader deserializePrefixedHeader(Slice data, bool hasHash = false); -/** Calculate the hash of a ledger header. */ +/** + * Calculate the hash of a ledger header. + */ uint256 calculateLedgerHash(LedgerHeader const& info); diff --git a/include/xrpl/protocol/LedgerShortcut.h b/include/xrpl/protocol/LedgerShortcut.h index 68c31c4c3c..037621121d 100644 --- a/include/xrpl/protocol/LedgerShortcut.h +++ b/include/xrpl/protocol/LedgerShortcut.h @@ -9,13 +9,19 @@ namespace xrpl { * without needing to specify their exact hash or sequence number. */ enum class LedgerShortcut { - /** The current working ledger (open, not yet closed) */ + /** + * The current working ledger (open, not yet closed) + */ Current, - /** The most recently closed ledger (may not be validated) */ + /** + * The most recently closed ledger (may not be validated) + */ Closed, - /** The most recently validated ledger */ + /** + * The most recently validated ledger + */ Validated }; diff --git a/include/xrpl/protocol/MPTAmount.h b/include/xrpl/protocol/MPTAmount.h index 6ea36fc294..462092f7dd 100644 --- a/include/xrpl/protocol/MPTAmount.h +++ b/include/xrpl/protocol/MPTAmount.h @@ -2,13 +2,15 @@ #include #include -#include #include #include #include #include +#include +#include +#include #include namespace xrpl { @@ -58,7 +60,9 @@ public: bool operator<(MPTAmount const& other) const; - /** Returns true if the amount is not zero */ + /** + * Returns true if the amount is not zero + */ explicit constexpr operator bool() const noexcept; @@ -67,14 +71,17 @@ public: return value(); } - /** Return the sign of the amount */ + /** + * Return the sign of the amount + */ [[nodiscard]] constexpr int signum() const noexcept; - /** Returns the underlying value. Code SHOULD NOT call this - function unless the type has been abstracted away, - e.g. in a templated function. - */ + /** + * Returns the underlying value. Code SHOULD NOT call this + * function unless the type has been abstracted away, + * e.g. in a templated function. + */ [[nodiscard]] constexpr value_type value() const; @@ -98,14 +105,18 @@ MPTAmount::operator=(beast::Zero) return *this; } -/** Returns true if the amount is not zero */ +/** + * Returns true if the amount is not zero + */ constexpr MPTAmount:: operator bool() const noexcept { return value_ != 0; } -/** Return the sign of the amount */ +/** + * Return the sign of the amount + */ constexpr int MPTAmount::signum() const noexcept { @@ -114,10 +125,11 @@ MPTAmount::signum() const noexcept return (value_ != 0) ? 1 : 0; } -/** Returns the underlying value. Code SHOULD NOT call this - function unless the type has been abstracted away, - e.g. in a templated function. -*/ +/** + * Returns the underlying value. Code SHOULD NOT call this + * function unless the type has been abstracted away, + * e.g. in a templated function. + */ constexpr MPTAmount::value_type MPTAmount::value() const { diff --git a/include/xrpl/protocol/MPTIssue.h b/include/xrpl/protocol/MPTIssue.h index f55029f50d..7f473da6a2 100644 --- a/include/xrpl/protocol/MPTIssue.h +++ b/include/xrpl/protocol/MPTIssue.h @@ -1,8 +1,18 @@ #pragma once +#include #include #include +#include +#include +#include +#include +#include +#include +#include +#include + namespace xrpl { /* Adapt MPTID to provide the same interface as Issue. Enables using static @@ -72,7 +82,8 @@ operator<=>(MPTIssue const& lhs, MPTIssue const& rhs) return lhs.mptID_ <=> rhs.mptID_; } -/** MPT is a non-native token. +/** + * MPT is a non-native token. */ inline bool isXRP(MPTID const&) diff --git a/include/xrpl/protocol/NFTSyntheticSerializer.h b/include/xrpl/protocol/NFTSyntheticSerializer.h index a1d8bce985..bef05b9a8f 100644 --- a/include/xrpl/protocol/NFTSyntheticSerializer.h +++ b/include/xrpl/protocol/NFTSyntheticSerializer.h @@ -9,10 +9,9 @@ namespace xrpl::RPC { /** - Adds common synthetic fields to transaction-related JSON responses - - @{ + * Adds common synthetic fields to transaction-related JSON responses */ +/** @{ */ void insertNFTSyntheticInJson(json::Value&, std::shared_ptr const&, TxMeta const&); /** @} */ diff --git a/include/xrpl/protocol/NFTokenID.h b/include/xrpl/protocol/NFTokenID.h index f61c6bd5cb..b1b994eabd 100644 --- a/include/xrpl/protocol/NFTokenID.h +++ b/include/xrpl/protocol/NFTokenID.h @@ -12,13 +12,13 @@ namespace xrpl { /** - Add a `nftoken_ids` field to the `meta` output parameter. - The field is only added to successful NFTokenMint, NFTokenAcceptOffer, - and NFTokenCancelOffer transactions. - - Helper functions are not static because they can be used by Clio. - @{ + * Add a `nftoken_ids` field to the `meta` output parameter. + * The field is only added to successful NFTokenMint, NFTokenAcceptOffer, + * and NFTokenCancelOffer transactions. + * + * Helper functions are not static because they can be used by Clio. */ +/** @{ */ bool canHaveNFTokenID(std::shared_ptr const& serializedTx, TxMeta const& transactionMeta); diff --git a/include/xrpl/protocol/NFTokenOfferID.h b/include/xrpl/protocol/NFTokenOfferID.h index c4a80356bf..4810f7932a 100644 --- a/include/xrpl/protocol/NFTokenOfferID.h +++ b/include/xrpl/protocol/NFTokenOfferID.h @@ -11,12 +11,12 @@ namespace xrpl { /** - Add an `offer_id` field to the `meta` output parameter. - The field is only added to successful NFTokenCreateOffer transactions. - - Helper functions are not static because they can be used by Clio. - @{ + * Add an `offer_id` field to the `meta` output parameter. + * The field is only added to successful NFTokenCreateOffer transactions. + * + * Helper functions are not static because they can be used by Clio. */ +/** @{ */ bool canHaveNFTokenOfferID( std::shared_ptr const& serializedTx, diff --git a/include/xrpl/protocol/PathAsset.h b/include/xrpl/protocol/PathAsset.h index b51dc52b47..ebf6fb68a4 100644 --- a/include/xrpl/protocol/PathAsset.h +++ b/include/xrpl/protocol/PathAsset.h @@ -1,7 +1,14 @@ #pragma once +#include #include #include +#include + +#include +#include +#include +#include namespace xrpl { diff --git a/include/xrpl/protocol/Permissions.h b/include/xrpl/protocol/Permissions.h index eb161ef7ad..703a0939c9 100644 --- a/include/xrpl/protocol/Permissions.h +++ b/include/xrpl/protocol/Permissions.h @@ -1,9 +1,12 @@ #pragma once +#include #include -#include +#include #include +#include +#include #include #include #include @@ -106,7 +109,7 @@ public: txToPermissionType(TxType type); // tx type value is permission value minus one - [[nodiscard]] static TxType + [[nodiscard]] static std::optional permissionToTxType(std::uint32_t value); /** diff --git a/include/xrpl/protocol/Protocol.h b/include/xrpl/protocol/Protocol.h index 6a96b2ccbe..e83e1c97b6 100644 --- a/include/xrpl/protocol/Protocol.h +++ b/include/xrpl/protocol/Protocol.h @@ -1,71 +1,101 @@ #pragma once #include +#include #include +#include #include +#include +#include + +#include #include namespace xrpl { -/** Protocol specific constants. - - This information is, implicitly, part of the protocol. - - @note Changing these values without adding code to the - server to detect "pre-change" and "post-change" - will result in a hard fork. - - @ingroup protocol -*/ -/** Smallest legal byte size of a transaction. */ +/** + * Protocol specific constants. + * + * This information is, implicitly, part of the protocol. + * + * @note Changing these values without adding code to the + * server to detect "pre-change" and "post-change" + * will result in a hard fork. + * + * @ingroup protocol + */ +/** + * Smallest legal byte size of a transaction. + */ constexpr std::size_t kTxMinSizeBytes = 32; -/** Largest legal byte size of a transaction. */ +/** + * Largest legal byte size of a transaction. + */ constexpr std::size_t kTxMaxSizeBytes = megabytes(1); -/** The maximum number of unfunded offers to delete at once */ +/** + * The maximum number of unfunded offers to delete at once + */ constexpr std::size_t kUnfundedOfferRemoveLimit = 1000; -/** The maximum number of expired offers to delete at once */ +/** + * The maximum number of expired offers to delete at once + */ constexpr std::size_t kExpiredOfferRemoveLimit = 256; -/** The maximum number of metadata entries allowed in one transaction */ +/** + * The maximum number of metadata entries allowed in one transaction + */ constexpr std::size_t kOversizeMetaDataCap = 5200; -/** The maximum number of entries per directory page */ +/** + * The maximum number of entries per directory page + */ constexpr std::size_t kDirNodeMaxEntries = 32; -/** The maximum number of pages allowed in a directory - - Made obsolete by fixDirectoryLimit amendment. -*/ +/** + * The maximum number of pages allowed in a directory + * + * Made obsolete by fixDirectoryLimit amendment. + */ constexpr std::uint64_t kDirNodeMaxPages = 262144; -/** The maximum number of items in an NFT page */ +/** + * The maximum number of items in an NFT page + */ constexpr std::size_t kDirMaxTokensPerPage = 32; -/** The maximum number of owner directory entries for account to be deletable */ +/** + * The maximum number of owner directory entries for account to be deletable + */ constexpr std::size_t kMaxDeletableDirEntries = 1000; -/** The maximum number of token offers that can be canceled at once */ +/** + * The maximum number of token offers that can be canceled at once + */ constexpr std::size_t kMaxTokenOfferCancelCount = 500; -/** The maximum number of offers in an offer directory for NFT to be burnable */ +/** + * The maximum number of offers in an offer directory for NFT to be burnable + */ constexpr std::size_t kMaxDeletableTokenOfferEntries = 500; -/** The maximum token transfer fee allowed. - - Token transfer fees can range from 0% to 50% and are specified in tenths of - a basis point; that is a value of 1000 represents a transfer fee of 1% and - a value of 10000 represents a transfer fee of 10%. - - Note that for extremely low transfer fees values, it is possible that the - calculated fee will be 0. +/** + * The maximum token transfer fee allowed. + * + * Token transfer fees can range from 0% to 50% and are specified in tenths of + * a basis point; that is a value of 1000 represents a transfer fee of 1% and + * a value of 10000 represents a transfer fee of 10%. + * + * Note that for extremely low transfer fees values, it is possible that the + * calculated fee will be 0. */ constexpr std::uint16_t kMaxTransferFee = 50000; -/** There are 10,000 basis points (bips) in 100%. +/** + * There are 10,000 basis points (bips) in 100%. * * Basis points represent 0.01%. * @@ -110,36 +140,41 @@ tenthBipsOfValue(T value, TenthBips bips) } namespace Lending { -/** The maximum management fee rate allowed by a loan broker in 1/10 bips. - - Valid values are between 0 and 10% inclusive. -*/ +/** + * The maximum management fee rate allowed by a loan broker in 1/10 bips. + * + * Valid values are between 0 and 10% inclusive. + */ constexpr TenthBips16 kMaxManagementFeeRate( unsafeCast(percentageToTenthBips(10).value())); static_assert(kMaxManagementFeeRate == TenthBips16(std::uint16_t(10'000u))); -/** The maximum coverage rate required of a loan broker in 1/10 bips. - - Valid values are between 0 and 100% inclusive. -*/ +/** + * The maximum coverage rate required of a loan broker in 1/10 bips. + * + * Valid values are between 0 and 100% inclusive. + */ constexpr TenthBips32 kMaxCoverRate = percentageToTenthBips(100); static_assert(kMaxCoverRate == TenthBips32(100'000u)); -/** The maximum overpayment fee on a loan in 1/10 bips. -* - Valid values are between 0 and 100% inclusive. -*/ +/** + * The maximum overpayment fee on a loan in 1/10 bips. + * + * Valid values are between 0 and 100% inclusive. + */ constexpr TenthBips32 kMaxOverpaymentFee = percentageToTenthBips(100); static_assert(kMaxOverpaymentFee == TenthBips32(100'000u)); -/** Annualized interest rate of the Loan in 1/10 bips. +/** + * Annualized interest rate of the Loan in 1/10 bips. * * Valid values are between 0 and 100% inclusive. */ constexpr TenthBips32 kMaxInterestRate = percentageToTenthBips(100); static_assert(kMaxInterestRate == TenthBips32(100'000u)); -/** The maximum premium added to the interest rate for late payments on a loan +/** + * The maximum premium added to the interest rate for late payments on a loan * in 1/10 bips. * * Valid values are between 0 and 100% inclusive. @@ -147,7 +182,8 @@ static_assert(kMaxInterestRate == TenthBips32(100'000u)); constexpr TenthBips32 kMaxLateInterestRate = percentageToTenthBips(100); static_assert(kMaxLateInterestRate == TenthBips32(100'000u)); -/** The maximum close interest rate charged for repaying a loan early in 1/10 +/** + * The maximum close interest rate charged for repaying a loan early in 1/10 * bips. * * Valid values are between 0 and 100% inclusive. @@ -155,7 +191,8 @@ static_assert(kMaxLateInterestRate == TenthBips32(100'000u)); constexpr TenthBips32 kMaxCloseInterestRate = percentageToTenthBips(100); static_assert(kMaxCloseInterestRate == TenthBips32(100'000u)); -/** The maximum overpayment interest rate charged on loan overpayments in 1/10 +/** + * The maximum overpayment interest rate charged on loan overpayments in 1/10 * bips. * * Valid values are between 0 and 100% inclusive. @@ -163,7 +200,8 @@ static_assert(kMaxCloseInterestRate == TenthBips32(100'000u)); constexpr TenthBips32 kMaxOverpaymentInterestRate = percentageToTenthBips(100); static_assert(kMaxOverpaymentInterestRate == TenthBips32(100'000u)); -/** LoanPay transaction cost will be one base fee per X combined payments +/** + * LoanPay transaction cost will be one base fee per X combined payments * * The number of payments is estimated based on the Amount paid and the Loan's * Fixed Payment size. Overpayments (indicated with the tfLoanOverpayment flag) @@ -174,7 +212,8 @@ static_assert(kMaxOverpaymentInterestRate == TenthBips32(100'000u)); */ static constexpr int kLoanPaymentsPerFeeIncrement = 5; -/** Maximum number of combined payments that a LoanPay transaction will process +/** + * Maximum number of combined payments that a LoanPay transaction will process * * This limit is enforced during the loan payment process, and thus is not * estimated. If the limit is hit, no further payments or overpayments will be @@ -199,112 +238,267 @@ static constexpr int kLoanPaymentsPerFeeIncrement = 5; static constexpr int kLoanMaximumPaymentsPerTransaction = 100; } // namespace Lending -/** The maximum length of a URI inside an NFT */ +/** + * The maximum length of a URI inside an NFT + */ constexpr std::size_t kMaxTokenUriLength = 256; -/** The maximum length of a Data element inside a DID */ +/** + * The maximum length of a Data element inside a DID + */ constexpr std::size_t kMaxDidDocumentLength = 256; -/** The maximum length of a URI inside a DID */ +/** + * The maximum length of a URI inside a DID + */ constexpr std::size_t kMaxDidUriLength = 256; -/** The maximum length of an Attestation inside a DID */ +/** + * The maximum length of an Attestation inside a DID + */ constexpr std::size_t kMaxDidDataLength = 256; -/** The maximum length of a domain */ +/** + * The maximum length of a domain + */ constexpr std::size_t kMaxDomainLength = 256; -/** The maximum length of a URI inside a Credential */ +/** + * The maximum length of a URI inside a Credential + */ constexpr std::size_t kMaxCredentialUriLength = 256; -/** The maximum length of a CredentialType inside a Credential */ +/** + * The maximum length of a CredentialType inside a Credential + */ constexpr std::size_t kMaxCredentialTypeLength = 64; -/** The maximum number of credentials can be passed in array */ +/** + * The maximum number of credentials can be passed in array + */ constexpr std::size_t kMaxCredentialsArraySize = 8; -/** The maximum number of credentials can be passed in array for permissioned - * domain */ +/** + * The maximum number of credentials can be passed in array for permissioned + * domain + */ constexpr std::size_t kMaxPermissionedDomainCredentialsArraySize = 10; -/** The maximum length of MPTokenMetadata */ +/** + * The maximum length of MPTokenMetadata + */ constexpr std::size_t kMaxMpTokenMetadataLength = 1024; -/** The maximum amount of MPTokenIssuance */ +/** + * The maximum amount of MPTokenIssuance + */ constexpr std::uint64_t kMaxMpTokenAmount = 0x7FFF'FFFF'FFFF'FFFFull; static_assert(Number::kMaxRep >= kMaxMpTokenAmount); -/** The maximum length of Data payload */ +/** + * The maximum length of Data payload + */ constexpr std::size_t kMaxDataPayloadLength = 256; -/** Vault withdrawal policies */ +/** + * Vault withdrawal policies + */ constexpr std::uint8_t kVaultStrategyFirstComeFirstServe = 1; -/** Default IOU scale factor for a Vault */ +/** + * Default IOU scale factor for a Vault + */ constexpr std::uint8_t kVaultDefaultIouScale = 6; -/** Maximum scale factor for a Vault. The number is chosen to ensure that -1 IOU can be always converted to shares. -10^19 > maxMPTokenAmount (2^64-1) > 10^18 */ +/** + * Maximum scale factor for a Vault. The number is chosen to ensure that + * 1 IOU can be always converted to shares. + * 10^19 > maxMPTokenAmount (2^64-1) > 10^18 + */ constexpr std::uint8_t kVaultMaximumIouScale = 18; -/** Maximum recursion depth for vault shares being put as an asset inside - * another vault; counted from 0 */ +/** + * Maximum recursion depth for vault shares being put as an asset inside + * another vault; counted from 0 + */ constexpr std::uint8_t kMaxAssetCheckDepth = 5; -/** A ledger index. */ +/** + * A ledger index. + */ using LedgerIndex = std::uint32_t; constexpr std::uint32_t kFlagLedgerInterval = 256; -/** Returns true if the given ledgerIndex is a voting ledgerIndex */ +/** + * Returns true if the given ledgerIndex is a voting ledgerIndex + */ bool isVotingLedger(LedgerIndex seq); -/** Returns true if the given ledgerIndex is a flag ledgerIndex */ +/** + * Returns true if the given ledgerIndex is a flag ledgerIndex + */ bool isFlagLedger(LedgerIndex seq); -/** A transaction identifier. - The value is computed as the hash of the - canonicalized, serialized transaction object. -*/ +/** + * A transaction identifier. + * The value is computed as the hash of the + * canonicalized, serialized transaction object. + */ using TxID = uint256; -/** The maximum number of trustlines to delete as part of AMM account +/** + * The maximum number of trustlines to delete as part of AMM account * deletion cleanup. */ constexpr std::uint16_t kMaxDeletableAmmTrustLines = 512; -/** The maximum length of a URI inside an Oracle */ +/** + * The maximum length of a URI inside an Oracle + */ constexpr std::size_t kMaxOracleUri = 256; -/** The maximum length of a Provider inside an Oracle */ +/** + * The maximum length of a Provider inside an Oracle + */ constexpr std::size_t kMaxOracleProvider = 256; -/** The maximum size of a data series array inside an Oracle */ +/** + * The maximum size of a data series array inside an Oracle + */ constexpr std::size_t kMaxOracleDataSeries = 10; -/** The maximum length of a SymbolClass inside an Oracle */ +/** + * The maximum length of a SymbolClass inside an Oracle + */ constexpr std::size_t kMaxOracleSymbolClass = 16; -/** The maximum allowed time difference between lastUpdateTime and the time - of the last closed ledger -*/ +/** + * The maximum allowed time difference between lastUpdateTime and the time + * of the last closed ledger + */ constexpr std::size_t kMaxLastUpdateTimeDelta = 300; -/** The maximum price scaling factor +/** + * The maximum price scaling factor */ constexpr std::size_t kMaxPriceScale = 20; -/** The maximum percentage of outliers to trim +/** + * The maximum percentage of outliers to trim */ constexpr std::size_t kMaxTrim = 25; -/** The maximum number of delegate permissions an account can grant +/** + * The maximum number of delegate permissions an account can grant */ constexpr std::size_t kPermissionMaxSize = 10; -/** The maximum number of transactions that can be in a batch. */ +/** + * The maximum number of transactions that can be in a batch. + */ constexpr std::size_t kMaxBatchTxCount = 8; +/** + * The maximum number of batch signers. + */ +constexpr std::size_t kMaxBatchSigners = kMaxBatchTxCount * 3; + +/** + * Length of a secp256k1 scalar in bytes. + */ +constexpr std::size_t kEcScalarLength = kMPT_SCALAR_SIZE; + +/** + * Length of EC point (compressed) + */ +constexpr std::size_t kCompressedEcPointLength = 33; + +/** + * Length of one compressed EC point component in an EC ElGamal ciphertext. + */ +constexpr std::size_t kEcCiphertextComponentLength = kMPT_ELGAMAL_CIPHER_SIZE; + +/** + * EC ElGamal ciphertext length: two compressed EC points concatenated. + */ +constexpr std::size_t kEcGamalEncryptedTotalLength = kMPT_ELGAMAL_TOTAL_SIZE; + +/** + * Length of EC public key (compressed) + */ +constexpr std::size_t kEcPubKeyLength = kMPT_PUBKEY_SIZE; + +/** + * Length of EC private key in bytes + */ +constexpr std::size_t kEcPrivKeyLength = kMPT_PRIVKEY_SIZE; + +/** + * Length of the EC blinding factor in bytes + */ +constexpr std::size_t kEcBlindingFactorLength = kMPT_BLINDING_FACTOR_SIZE; + +/** + * Length of Schnorr ZKProof for public key registration (compact form) in bytes + */ +constexpr std::size_t kEcSchnorrProofLength = kMPT_SCHNORR_PROOF_SIZE; + +/** + * Length of Pedersen Commitment (compressed) + */ +constexpr std::size_t kEcPedersenCommitmentLength = kMPT_PEDERSEN_COMMIT_SIZE; + +/** + * Length of single bulletproof (range proof for 1 commitment) in bytes + */ +constexpr std::size_t kEcSingleBulletproofLength = kMPT_SINGLE_BULLETPROOF_SIZE; + +/** + * Length of double bulletproof (range proof for 2 commitments) in bytes + */ +constexpr std::size_t kEcDoubleBulletproofLength = kMPT_DOUBLE_BULLETPROOF_SIZE; + +/** + * Length of the compact sigma proof component for ConfidentialMPTSend. + */ +constexpr std::size_t kEcSendSigmaProofLength = SECP256K1_COMPACT_STANDARD_PROOF_SIZE; + +/** + * 192 bytes compact sigma proof + 754 bytes double bulletproof. + */ +constexpr std::size_t kEcSendProofLength = kEcSendSigmaProofLength + kEcDoubleBulletproofLength; + +/** + * Length of the compact sigma proof component for ConfidentialMPTConvertBack. + */ +constexpr std::size_t kEcConvertBackSigmaProofLength = SECP256K1_COMPACT_CONVERTBACK_PROOF_SIZE; + +/** + * 128 bytes compact sigma proof + 688 bytes single bulletproof. + */ +constexpr std::size_t kEcConvertBackProofLength = + kEcConvertBackSigmaProofLength + kEcSingleBulletproofLength; + +/** + * Length of the ZKProof for ConfidentialMPTClawback. + */ +constexpr std::size_t kEcClawbackProofLength = SECP256K1_COMPACT_CLAWBACK_PROOF_SIZE; + +/** + * Extra base fee multiplier charged to confidential MPT transactions. + */ +constexpr std::uint32_t kConfidentialFeeMultiplier = 9; + +/** + * Compressed EC point prefix for even y-coordinate + */ +constexpr std::uint8_t kEcCompressedPrefixEvenY = 0x02; + +/** + * Compressed EC point prefix for odd y-coordinate + */ +constexpr std::uint8_t kEcCompressedPrefixOddY = 0x03; + } // namespace xrpl diff --git a/include/xrpl/protocol/PublicKey.h b/include/xrpl/protocol/PublicKey.h index 20693160d3..98301af487 100644 --- a/include/xrpl/protocol/PublicKey.h +++ b/include/xrpl/protocol/PublicKey.h @@ -1,8 +1,15 @@ #pragma once #include +#include +#include +#include #include +#include +#include #include +#include +#include #include #include #include @@ -11,33 +18,37 @@ #include #include #include +#include #include #include +#include +#include namespace xrpl { -/** A public key. - - Public keys are used in the public-key cryptography - system used to verify signatures attached to messages. - - The format of the public key is XRPL specific, - information needed to determine the cryptosystem - parameters used is stored inside the key. - - As of this writing two systems are supported: - - secp256k1 - ed25519 - - secp256k1 public keys consist of a 33 byte - compressed public key, with the lead byte equal - to 0x02 or 0x03. - - The ed25519 public keys consist of a 1 byte - prefix constant 0xED, followed by 32 bytes of - public key data. -*/ +/** + * A public key. + * + * Public keys are used in the public-key cryptography + * system used to verify signatures attached to messages. + * + * The format of the public key is XRPL specific, + * information needed to determine the cryptosystem + * parameters used is stored inside the key. + * + * As of this writing two systems are supported: + * + * secp256k1 + * ed25519 + * + * secp256k1 public keys consist of a 33 byte + * compressed public key, with the lead byte equal + * to 0x02 or 0x03. + * + * The ed25519 public keys consist of a 1 byte + * prefix constant 0xED, followed by 32 bytes of + * public key data. + */ class PublicKey { protected: @@ -56,11 +67,12 @@ public: PublicKey& operator=(PublicKey const& other); - /** Create a public key. - - Preconditions: - publicKeyType(slice) != std::nullopt - */ + /** + * Create a public key. + * + * Preconditions: + * publicKeyType(slice) != std::nullopt + */ explicit PublicKey(Slice const& slice); [[nodiscard]] std::uint8_t const* @@ -111,7 +123,8 @@ public: } }; -/** Print the public key to a stream. +/** + * Print the public key to a stream. */ std::ostream& operator<<(std::ostream& os, PublicKey const& pk); @@ -170,39 +183,41 @@ parseBase58(TokenType type, std::string const& s); enum class ECDSACanonicality { Canonical, FullyCanonical }; -/** Determines the canonicality of a signature. - - A canonical signature is in its most reduced form. - For example the R and S components do not contain - additional leading zeroes. However, even in - canonical form, (R,S) and (R,G-S) are both - valid signatures for message M. - - Therefore, to prevent malleability attacks we - define a fully canonical signature as one where: - - R < G - S - - where G is the curve order. - - This routine returns std::nullopt if the format - of the signature is invalid (for example, the - points are encoded incorrectly). - - @return std::nullopt if the signature fails - validity checks. - - @note Only the format of the signature is checked, - no verification cryptography is performed. -*/ +/** + * Determines the canonicality of a signature. + * + * A canonical signature is in its most reduced form. + * For example the R and S components do not contain + * additional leading zeroes. However, even in + * canonical form, (R,S) and (R,G-S) are both + * valid signatures for message M. + * + * Therefore, to prevent malleability attacks we + * define a fully canonical signature as one where: + * + * R < G - S + * + * where G is the curve order. + * + * This routine returns std::nullopt if the format + * of the signature is invalid (for example, the + * points are encoded incorrectly). + * + * @return std::nullopt if the signature fails + * validity checks. + * + * @note Only the format of the signature is checked, + * no verification cryptography is performed. + */ std::optional ecdsaCanonicality(Slice const& sig); -/** Returns the type of public key. - - @return std::nullopt If the public key does not - represent a known type. -*/ +/** + * Returns the type of public key. + * + * @return std::nullopt If the public key does not + * represent a known type. + */ /** @{ */ [[nodiscard]] std::optional publicKeyType(Slice const& slice); @@ -214,7 +229,9 @@ publicKeyType(PublicKey const& publicKey) } /** @} */ -/** Verify a secp256k1 signature on the digest of a message. */ +/** + * Verify a secp256k1 signature on the digest of a message. + */ [[nodiscard]] bool verifyDigest( PublicKey const& publicKey, @@ -222,14 +239,17 @@ verifyDigest( Slice const& sig, bool mustBeFullyCanonical = true) noexcept; -/** Verify a signature on a message. - With secp256k1 signatures, the data is first hashed with - SHA512-Half, and the resulting digest is signed. -*/ +/** + * Verify a signature on a message. + * With secp256k1 signatures, the data is first hashed with + * SHA512-Half, and the resulting digest is signed. + */ [[nodiscard]] bool verify(PublicKey const& publicKey, Slice const& m, Slice const& sig) noexcept; -/** Calculate the 160-bit node ID from a node public key. */ +/** + * Calculate the 160-bit node ID from a node public key. + */ NodeID calcNodeID(PublicKey const&); diff --git a/include/xrpl/protocol/Quality.h b/include/xrpl/protocol/Quality.h index e261025cb8..3475efa977 100644 --- a/include/xrpl/protocol/Quality.h +++ b/include/xrpl/protocol/Quality.h @@ -1,26 +1,29 @@ #pragma once +#include +#include #include -#include #include -#include #include +#include +#include #include #include #include namespace xrpl { -/** Represents a pair of input and output currencies. - - The input currency can be converted to the output - currency by multiplying by the rate, represented by - Quality. - - For offers, "in" is always TakerPays and "out" is - always TakerGets. -*/ +/** + * Represents a pair of input and output currencies. + * + * The input currency can be converted to the output + * currency by multiplying by the rate, represented by + * Quality. + * + * For offers, "in" is always TakerPays and "out" is + * always TakerGets. + */ template struct TAmounts { @@ -34,7 +37,9 @@ struct TAmounts { } - /** Returns `true` if either quantity is not positive. */ + /** + * Returns `true` if either quantity is not positive. + */ [[nodiscard]] bool empty() const noexcept { @@ -82,11 +87,12 @@ operator!=(TAmounts const& lhs, TAmounts const& rhs) noexcept // XRPL specific constant used for parsing qualities and other things #define QUALITY_ONE 1'000'000'000 -/** Represents the logical ratio of output currency to input currency. - Internally this is stored using a custom floating point representation, - as the inverse of the ratio, so that quality will be descending in - a sequence of actual values that represent qualities. -*/ +/** + * Represents the logical ratio of output currency to input currency. + * Internally this is stored using a custom floating point representation, + * as the inverse of the ratio, so that quality will be descending in + * a sequence of actual values that represent qualities. + */ class Quality { public: @@ -107,26 +113,36 @@ private: public: Quality() = default; - /** Create a quality from the integer encoding of an STAmount */ + /** + * Create a quality from the integer encoding of an STAmount + */ explicit Quality(std::uint64_t value); - /** Create a quality from the ratio of two amounts. */ + /** + * Create a quality from the ratio of two amounts. + */ explicit Quality(Amounts const& amount); - /** Create a quality from the ratio of two amounts. */ + /** + * Create a quality from the ratio of two amounts. + */ template explicit Quality(TAmounts const& amount) : Quality(Amounts(toSTAmount(amount.in), toSTAmount(amount.out))) { } - /** Create a quality from the ratio of two amounts. */ + /** + * Create a quality from the ratio of two amounts. + */ template Quality(Out const& out, In const& in) : Quality(Amounts(toSTAmount(in), toSTAmount(out))) { } - /** Advances to the next higher quality level. */ + /** + * Advances to the next higher quality level. + */ /** @{ */ Quality& operator++(); @@ -135,7 +151,9 @@ public: operator++(int); /** @} */ - /** Advances to the next lower quality level. */ + /** + * Advances to the next lower quality level. + */ /** @{ */ Quality& operator--(); @@ -144,23 +162,27 @@ public: operator--(int); /** @} */ - /** Returns the quality as STAmount. */ + /** + * Returns the quality as STAmount. + */ [[nodiscard]] STAmount rate() const { return amountFromQuality(value_); } - /** Returns the quality rounded up to the specified number - of decimal digits. - */ + /** + * Returns the quality rounded up to the specified number + * of decimal digits. + */ [[nodiscard]] Quality round(int tickSize) const; - /** Returns the scaled amount with in capped. - Math is avoided if the result is exact. The output is clamped - to prevent money creation. - */ + /** + * Returns the scaled amount with in capped. + * Math is avoided if the result is exact. The output is clamped + * to prevent money creation. + */ [[nodiscard]] Amounts ceilIn(Amounts const& amount, STAmount const& limit) const; @@ -178,10 +200,11 @@ public: [[nodiscard]] TAmounts ceilInStrict(TAmounts const& amount, In const& limit, bool roundUp) const; - /** Returns the scaled amount with out capped. - Math is avoided if the result is exact. The input is clamped - to prevent money creation. - */ + /** + * Returns the scaled amount with out capped. + * Math is avoided if the result is exact. The input is clamped + * to prevent money creation. + */ [[nodiscard]] Amounts ceilOut(Amounts const& amount, STAmount const& limit) const; @@ -213,10 +236,11 @@ private: Round... round) const; public: - /** Returns `true` if lhs is lower quality than `rhs`. - Lower quality means the taker receives a worse deal. - Higher quality is better for the taker. - */ + /** + * Returns `true` if lhs is lower quality than `rhs`. + * Lower quality means the taker receives a worse deal. + * Higher quality is better for the taker. + */ friend bool operator<(Quality const& lhs, Quality const& rhs) noexcept { @@ -280,7 +304,7 @@ public: auto const maxVMantissa = mantissa(maxV); auto const expDiff = exponent(maxV) - exponent(minV); - double const minVD = static_cast(minVMantissa); + auto const minVD = static_cast(minVMantissa); double const maxVD = (expDiff != 0) ? maxVMantissa * pow(10, expDiff) : static_cast(maxVMantissa); @@ -355,10 +379,11 @@ Quality::ceilOutStrict(TAmounts const& amount, Out const& limit, bool r return ceilTAmountsHelper(amount, limit, amount.out, kCeilOutFnPtr, roundUp); } -/** Calculate the quality of a two-hop path given the two hops. - @param lhs The first leg of the path: input to intermediate. - @param rhs The second leg of the path: intermediate to output. -*/ +/** + * Calculate the quality of a two-hop path given the two hops. + * @param lhs The first leg of the path: input to intermediate. + * @param rhs The second leg of the path: intermediate to output. + */ Quality composedQuality(Quality const& lhs, Quality const& rhs); diff --git a/include/xrpl/protocol/QualityFunction.h b/include/xrpl/protocol/QualityFunction.h index 96d30735b8..128b37ce12 100644 --- a/include/xrpl/protocol/QualityFunction.h +++ b/include/xrpl/protocol/QualityFunction.h @@ -1,12 +1,19 @@ #pragma once #include +#include +#include #include #include +#include +#include +#include + namespace xrpl { -/** Average quality of a path as a function of `out`: q(out) = m * out + b, +/** + * Average quality of a path as a function of `out`: q(out) = m * out + b, * where m = -1 / poolGets, b = poolPays / poolGets. If CLOB offer then * `m` is equal to 0 `b` is equal to the offer's quality. The function * is derived by substituting `in` in q = out / in with the swap out formula @@ -39,19 +46,22 @@ public: template QualityFunction(TAmounts const& amounts, std::uint32_t tfee, AMMTag); - /** Combines QF with the next step QF + /** + * Combines QF with the next step QF */ void combine(QualityFunction const& qf); - /** Find output to produce the requested + /** + * Find output to produce the requested * average quality. * @param quality requested average quality (quality limit) */ std::optional outFromAvgQ(Quality const& quality); - /** Return true if the quality function is constant + /** + * Return true if the quality function is constant */ [[nodiscard]] bool isConst() const diff --git a/include/xrpl/protocol/Rate.h b/include/xrpl/protocol/Rate.h index 504b17ed80..048787cab5 100644 --- a/include/xrpl/protocol/Rate.h +++ b/include/xrpl/protocol/Rate.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include @@ -10,12 +10,13 @@ namespace xrpl { -/** Represents a transfer rate - - Transfer rates are specified as fractions of 1 billion. - For example, a transfer rate of 1% is represented as - 1,010,000,000. -*/ +/** + * Represents a transfer rate + * + * Transfer rates are specified as fractions of 1 billion. + * For example, a transfer rate of 1% is represented as + * 1,010,000,000. + */ struct Rate : private boost::totally_ordered { std::uint32_t value; @@ -65,13 +66,17 @@ STAmount divideRound(STAmount const& amount, Rate const& rate, Asset const& asset, bool roundUp); namespace nft { -/** Given a transfer fee (in basis points) convert it to a transfer rate. */ +/** + * Given a transfer fee (in basis points) convert it to a transfer rate. + */ Rate transferFeeAsRate(std::uint16_t fee); } // namespace nft -/** A transfer rate signifying a 1:1 exchange */ +/** + * A transfer rate signifying a 1:1 exchange + */ extern Rate const kParityRate; } // namespace xrpl diff --git a/include/xrpl/protocol/Rules.h b/include/xrpl/protocol/Rules.h index 47b20756db..2c2136b6e8 100644 --- a/include/xrpl/protocol/Rules.h +++ b/include/xrpl/protocol/Rules.h @@ -4,11 +4,15 @@ #include #include +#include +#include #include +#include namespace xrpl { -/** Check whether a feature is enabled in the current ledger rules +/** + * Check whether a feature is enabled in the current ledger rules * * @param feature The feature to be tested. * @param resultIfNoRules What to return if called from outside a Transactor context. @@ -16,7 +20,8 @@ namespace xrpl { bool isFeatureEnabled(uint256 const& feature, bool resultIfNoRules); -/** Check whether a feature is enabled in the current ledger rules +/** + * Check whether a feature is enabled in the current ledger rules * * @param feature The feature to be tested. * @@ -28,7 +33,9 @@ isFeatureEnabled(uint256 const& feature); class DigestAwareReadView; -/** Rules controlling protocol behavior. */ +/** + * Rules controlling protocol behavior. + */ class Rules { private: @@ -51,11 +58,12 @@ public: Rules() = delete; - /** Construct an empty rule set. - - These are the rules reflected by - the genesis ledger. - */ + /** + * Construct an empty rule set. + * + * These are the rules reflected by + * the genesis ledger. + */ explicit Rules(std::unordered_set> const& presets); private: @@ -77,14 +85,17 @@ private: presets() const; public: - /** Returns `true` if a feature is enabled. */ + /** + * Returns `true` if a feature is enabled. + */ [[nodiscard]] bool enabled(uint256 const& feature) const; - /** Returns `true` if two rule sets are identical. - - @note This is for diagnostics. - */ + /** + * Returns `true` if two rule sets are identical. + * + * @note This is for diagnostics. + */ bool operator==(Rules const&) const; @@ -98,7 +109,8 @@ getCurrentTransactionRules(); void setCurrentTransactionRules(std::optional r); -/** RAII class to set and restore the current transaction rules +/** + * RAII class to set and restore the current transaction rules */ class CurrentTransactionRulesGuard { diff --git a/include/xrpl/protocol/SField.h b/include/xrpl/protocol/SField.h index 34fb66ce00..21ab7813f9 100644 --- a/include/xrpl/protocol/SField.h +++ b/include/xrpl/protocol/SField.h @@ -2,10 +2,11 @@ #include #include -#include #include #include +#include +#include namespace xrpl { @@ -116,16 +117,17 @@ fieldCode(int id, int index) return (id << 16) | index; } -/** Identifies fields. - - Fields are necessary to tag data in signed transactions so that - the binary format of the transaction can be canonicalized. All - SFields are created at compile time. - - Each SField, once constructed, lives until program termination, and there - is only one instance per fieldType/fieldValue pair which serves the - entire application. -*/ +/** + * Identifies fields. + * + * Fields are necessary to tag data in signed transactions so that + * the binary format of the transaction can be canonicalized. All + * SFields are created at compile time. + * + * Each SField, once constructed, lives until program termination, and there + * is only one instance per fieldType/fieldValue pair which serves the + * entire application. + */ class SField { public: @@ -298,7 +300,9 @@ private: static std::unordered_map knownNameToField; }; -/** A field with a type known at compile time. */ +/** + * A field with a type known at compile time. + */ template struct TypedField : SField { @@ -308,7 +312,9 @@ struct TypedField : SField explicit TypedField(PrivateAccessTagT pat, Args&&... args); }; -/** Indicate std::optional field semantics. */ +/** + * Indicate std::optional field semantics. + */ template struct OptionaledField { diff --git a/include/xrpl/protocol/SOTemplate.h b/include/xrpl/protocol/SOTemplate.h index 72e0573d29..cb24ee315a 100644 --- a/include/xrpl/protocol/SOTemplate.h +++ b/include/xrpl/protocol/SOTemplate.h @@ -3,14 +3,18 @@ #include #include +#include #include #include #include +#include #include namespace xrpl { -/** Kind of element in each entry of an SOTemplate. */ +/** + * Kind of element in each entry of an SOTemplate. + */ // 2026 usages, 129 files // NOLINTNEXTLINE(cppcoreguidelines-use-enum-class) enum SOEStyle { @@ -23,13 +27,17 @@ enum SOEStyle { }; // Part of a Python-parsed DSL (transactions.macro); bare enumerator names required by the parser -/** Amount fields that can support MPT */ +/** + * Amount fields that can support MPT + */ // NOLINTNEXTLINE(cppcoreguidelines-use-enum-class) enum SOETxMPTIssue { SoeMptNone, SoeMptSupported, SoeMptNotSupported }; //------------------------------------------------------------------------------ -/** An element in a SOTemplate. */ +/** + * An element in a SOTemplate. + */ class SOElement { // Use std::reference_wrapper so SOElement can be stored in a std::vector. @@ -88,10 +96,11 @@ public: //------------------------------------------------------------------------------ -/** Defines the fields and their attributes within a STObject. - Each subclass of SerializedObject will provide its own template - describing the available fields and their metadata attributes. -*/ +/** + * Defines the fields and their attributes within a STObject. + * Each subclass of SerializedObject will provide its own template + * describing the available fields and their metadata attributes. + */ class SOTemplate { public: @@ -101,14 +110,16 @@ public: SOTemplate& operator=(SOTemplate&& other) = default; - /** Create a template populated with all fields. - After creating the template fields cannot be added, modified, or removed. - */ + /** + * Create a template populated with all fields. + * After creating the template fields cannot be added, modified, or removed. + */ SOTemplate(std::vector uniqueFields, std::vector commonFields = {}); - /** Create a template populated with all fields. - Note: Defers to the vector constructor above. - */ + /** + * Create a template populated with all fields. + * Note: Defers to the vector constructor above. + */ SOTemplate( std::initializer_list uniqueFields, std::initializer_list commonFields = {}); @@ -138,14 +149,18 @@ public: return end(); } - /** The number of entries in this template */ + /** + * The number of entries in this template + */ [[nodiscard]] std::size_t size() const { return elements_.size(); } - /** Retrieve the position of a named field. */ + /** + * Retrieve the position of a named field. + */ [[nodiscard]] int getIndex(SField const&) const; diff --git a/include/xrpl/protocol/STAccount.h b/include/xrpl/protocol/STAccount.h index 65f404d58d..17d3affc57 100644 --- a/include/xrpl/protocol/STAccount.h +++ b/include/xrpl/protocol/STAccount.h @@ -1,9 +1,13 @@ #pragma once +#include #include #include +#include #include +#include +#include #include namespace xrpl { diff --git a/include/xrpl/protocol/STAmount.h b/include/xrpl/protocol/STAmount.h index 1a5b442d8b..cc80481582 100644 --- a/include/xrpl/protocol/STAmount.h +++ b/include/xrpl/protocol/STAmount.h @@ -1,14 +1,20 @@ #pragma once #include -#include #include +#include +#include #include +#include #include +#include +#include #include +#include #include #include #include +#include #include #include #include @@ -16,6 +22,14 @@ #include #include +#include +#include +#include +#include +#include +#include +#include + namespace xrpl { // Internal form: @@ -176,7 +190,9 @@ public: [[nodiscard]] int signum() const noexcept; - /** Returns a zero value with the same issuer and currency. */ + /** + * Returns a zero value with the same issuer and currency. + */ [[nodiscard]] STAmount zeroed() const; @@ -241,7 +257,9 @@ public: void clear(Asset const& asset); - /** Set the Issue for this amount. */ + /** + * Set the Issue for this amount. + */ void setIssue(Asset const& asset); @@ -690,7 +708,8 @@ divRoundStrict(STAmount const& v1, STAmount const& v2, Asset const& asset, bool std::uint64_t getRate(STAmount const& offerOut, STAmount const& offerIn); -/** Round an arbitrary precision Amount to the precision of an STAmount that has +/** + * Round an arbitrary precision Amount to the precision of an STAmount that has * a given exponent. * * This is used to ensure that calculations involving IOU amounts do not collect @@ -700,7 +719,6 @@ getRate(STAmount const& offerOut, STAmount const& offerIn); * @param scale An exponent value to establish the precision limit of * `value`. Should be larger than `value.exponent()`. * @param rounding Optional Number rounding mode - * */ [[nodiscard]] STAmount roundToScale( @@ -708,7 +726,8 @@ roundToScale( std::int32_t scale, Number::RoundingMode rounding = Number::getround()); -/** Round an arbitrary precision Number IN PLACE to the precision of a given +/** + * Round an arbitrary precision Number IN PLACE to the precision of a given * Asset. * * This is used to ensure that calculations do not collect dust for IOUs, or @@ -724,7 +743,8 @@ roundToAsset(A const& asset, Number& value) value = STAmount{asset, value}; } -/** Round an arbitrary precision Number to the precision of a given Asset. +/** + * Round an arbitrary precision Number to the precision of a given Asset. * * This is used to ensure that calculations do not collect dust beyond specified * scale for IOUs, or fractional amounts for the integral types XRP and MPT. @@ -766,7 +786,8 @@ canAdd(STAmount const& amt1, STAmount const& amt2); bool canSubtract(STAmount const& amt1, STAmount const& amt2); -/** Get the scale of a Number for a given asset. +/** + * Get the scale of a Number for a given asset. * * "scale" is similar to "exponent", but from the perspective of STAmount, which has different rules * and mantissa ranges for determining the exponent than Number. diff --git a/include/xrpl/protocol/STArray.h b/include/xrpl/protocol/STArray.h index 61753c52dc..573bb6dad8 100644 --- a/include/xrpl/protocol/STArray.h +++ b/include/xrpl/protocol/STArray.h @@ -1,7 +1,18 @@ #pragma once #include +#include +#include +#include #include +#include + +#include +#include +#include +#include +#include +#include namespace xrpl { @@ -21,17 +32,13 @@ public: STArray() = default; STArray(STArray const&) = default; - template < - class Iter, - class = std::enable_if_t< - std::is_convertible_v::reference, STObject>>> - explicit STArray(Iter first, Iter last); + template + explicit STArray(Iter first, Iter last) + requires(std::is_convertible_v::reference, STObject>); - template < - class Iter, - class = std::enable_if_t< - std::is_convertible_v::reference, STObject>>> - STArray(SField const& f, Iter first, Iter last); + template + STArray(SField const& f, Iter first, Iter last) + requires(std::is_convertible_v::reference, STObject>); STArray& operator=(STArray const&) = default; @@ -159,13 +166,17 @@ private: friend class detail::STVar; }; -template -STArray::STArray(Iter first, Iter last) : v_(first, last) +template +STArray::STArray(Iter first, Iter last) + requires(std::is_convertible_v::reference, STObject>) + : v_(first, last) { } -template -STArray::STArray(SField const& f, Iter first, Iter last) : STBase(f), v_(first, last) +template +STArray::STArray(SField const& f, Iter first, Iter last) + requires(std::is_convertible_v::reference, STObject>) + : STBase(f), v_(first, last) { } diff --git a/include/xrpl/protocol/STBase.h b/include/xrpl/protocol/STBase.h index 6633253d3b..acc5500a57 100644 --- a/include/xrpl/protocol/STBase.h +++ b/include/xrpl/protocol/STBase.h @@ -1,9 +1,12 @@ #pragma once #include +#include #include #include +#include +#include #include #include #include @@ -12,7 +15,9 @@ namespace xrpl { -/// Note, should be treated as flags that can be | and & +/** + * Note, should be treated as flags that can be | and & + */ struct JsonOptions { using underlying_t = unsigned int; @@ -50,22 +55,28 @@ struct JsonOptions [[nodiscard]] constexpr auto friend operator!=(JsonOptions lh, JsonOptions rh) noexcept -> bool = default; - /// Returns JsonOptions union of lh and rh + /** + * Returns JsonOptions union of lh and rh + */ [[nodiscard]] constexpr JsonOptions friend operator|(JsonOptions lh, JsonOptions rh) noexcept { return {lh.value | rh.value}; } - /// Returns JsonOptions intersection of lh and rh + /** + * Returns JsonOptions intersection of lh and rh + */ [[nodiscard]] constexpr JsonOptions friend operator&(JsonOptions lh, JsonOptions rh) noexcept { return {lh.value & rh.value}; } - /// Returns JsonOptions binary negation, can be used with & (above) for set - /// difference e.g. `(options & ~JsonOptions::kIncludeDate)` + /** + * Returns JsonOptions binary negation, can be used with & (above) for set + * difference e.g. `(options & ~JsonOptions::kIncludeDate)` + */ [[nodiscard]] constexpr JsonOptions friend operator~(JsonOptions v) noexcept { @@ -100,19 +111,20 @@ class STVar; //------------------------------------------------------------------------------ -/** A type which can be exported to a well known binary format. - - A STBase: - - Always a field - - Can always go inside an eligible enclosing STBase - (such as STArray) - - Has a field name - - Like JSON, a SerializedObject is a basket which has rules - on what it can hold. - - @note "ST" stands for "Serialized Type." -*/ +/** + * A type which can be exported to a well known binary format. + * + * A STBase: + * - Always a field + * - Can always go inside an eligible enclosing STBase + * (such as STArray) + * - Has a field name + * + * Like JSON, a SerializedObject is a basket which has rules + * on what it can hold. + * + * @note "ST" stands for "Serialized Type." + */ class STBase { SField const* fName_; @@ -159,9 +171,10 @@ public: [[nodiscard]] virtual bool isDefault() const; - /** A STBase is a field. - This sets the name. - */ + /** + * A STBase is a field. + * This sets the name. + */ void setFName(SField const& n); diff --git a/include/xrpl/protocol/STBitString.h b/include/xrpl/protocol/STBitString.h index 0267eac22d..6f71f48f25 100644 --- a/include/xrpl/protocol/STBitString.h +++ b/include/xrpl/protocol/STBitString.h @@ -1,8 +1,15 @@ #pragma once #include +#include #include +#include +#include #include +#include + +#include +#include namespace xrpl { @@ -141,7 +148,7 @@ template bool STBitString::isEquivalent(STBase const& t) const { - STBitString const* v = dynamic_cast(&t); + auto const* v = dynamic_cast(&t); return v && (value_ == v->value_); } diff --git a/include/xrpl/protocol/STBlob.h b/include/xrpl/protocol/STBlob.h index 0667c54e30..ab6175f5e3 100644 --- a/include/xrpl/protocol/STBlob.h +++ b/include/xrpl/protocol/STBlob.h @@ -3,10 +3,14 @@ #include #include #include -#include +#include #include +#include +#include #include +#include +#include namespace xrpl { diff --git a/include/xrpl/protocol/STCurrency.h b/include/xrpl/protocol/STCurrency.h index 55d1ab1e74..18642b20cf 100644 --- a/include/xrpl/protocol/STCurrency.h +++ b/include/xrpl/protocol/STCurrency.h @@ -1,11 +1,15 @@ #pragma once -#include +#include #include #include #include #include +#include +#include +#include + namespace xrpl { class STCurrency final : public STBase diff --git a/include/xrpl/protocol/STExchange.h b/include/xrpl/protocol/STExchange.h index c733df37cf..ad5bd4c012 100644 --- a/include/xrpl/protocol/STExchange.h +++ b/include/xrpl/protocol/STExchange.h @@ -1,14 +1,15 @@ #pragma once -#include #include #include #include #include +#include #include #include #include +#include #include #include #include @@ -17,7 +18,9 @@ namespace xrpl { -/** Convert between serialized type U and C++ type T. */ +/** + * Convert between serialized type U and C++ type T. + */ template struct STExchange; @@ -89,7 +92,9 @@ struct STExchange //------------------------------------------------------------------------------ -/** Return the value of a field in an STObject as a given type. */ +/** + * Return the value of a field in an STObject as a given type. + */ /** @{ */ template std::optional @@ -118,7 +123,9 @@ get(STObject const& st, TypedField const& f) } /** @} */ -/** Set a field value in an STObject. */ +/** + * Set a field value in an STObject. + */ template void set(STObject& st, TypedField const& f, T&& t) @@ -126,7 +133,9 @@ set(STObject& st, TypedField const& f, T&& t) st.set(STExchange>::set(f, std::forward(t))); } -/** Set a blob field using an init function. */ +/** + * Set a blob field using an init function. + */ template void set(STObject& st, TypedField const& f, std::size_t size, Init&& init) @@ -134,7 +143,9 @@ set(STObject& st, TypedField const& f, std::size_t size, Init&& init) st.set(std::make_unique(f, size, init)); } -/** Set a blob field from data. */ +/** + * Set a blob field from data. + */ template void set(STObject& st, TypedField const& f, void const* data, std::size_t size) @@ -142,7 +153,9 @@ set(STObject& st, TypedField const& f, void const* data, std::size_t siz st.set(std::make_unique(f, data, size)); } -/** Remove a field in an STObject. */ +/** + * Remove a field in an STObject. + */ template void erase(STObject& st, TypedField const& f) diff --git a/include/xrpl/protocol/STInteger.h b/include/xrpl/protocol/STInteger.h index 52e0f7a365..951c4fc52f 100644 --- a/include/xrpl/protocol/STInteger.h +++ b/include/xrpl/protocol/STInteger.h @@ -1,7 +1,15 @@ #pragma once #include +#include +#include +#include #include +#include + +#include +#include +#include namespace xrpl { @@ -107,7 +115,7 @@ template inline bool STInteger::isEquivalent(STBase const& t) const { - STInteger const* v = dynamic_cast(&t); + auto const* v = dynamic_cast(&t); return v && (value_ == v->value_); } diff --git a/include/xrpl/protocol/STIssue.h b/include/xrpl/protocol/STIssue.h index f5e1f61168..8ff579553f 100644 --- a/include/xrpl/protocol/STIssue.h +++ b/include/xrpl/protocol/STIssue.h @@ -1,11 +1,20 @@ #pragma once #include +#include +#include #include +#include +#include #include #include #include +#include +#include +#include +#include + namespace xrpl { class STIssue final : public STBase, CountedObject diff --git a/include/xrpl/protocol/STLedgerEntry.h b/include/xrpl/protocol/STLedgerEntry.h index aa87411ae6..8731488adb 100644 --- a/include/xrpl/protocol/STLedgerEntry.h +++ b/include/xrpl/protocol/STLedgerEntry.h @@ -1,7 +1,19 @@ #pragma once -#include +#include +#include +#include +#include +#include +#include +#include #include +#include + +#include +#include +#include +#include namespace xrpl { @@ -21,7 +33,9 @@ public: using const_pointer = std::shared_ptr; using const_ref = std::shared_ptr const&; - /** Create an empty object with the given key and type. */ + /** + * Create an empty object with the given key and type. + */ explicit STLedgerEntry(Keylet const& k); STLedgerEntry(LedgerEntryType type, uint256 const& key); STLedgerEntry(SerialIter& sit, uint256 const& index); @@ -40,10 +54,11 @@ public: [[nodiscard]] json::Value getJson(JsonOptions options = JsonOptions::Values::None) const override; - /** Returns the 'key' (or 'index') of this item. - The key identifies this entry's position in - the SHAMap associative container. - */ + /** + * Returns the 'key' (or 'index') of this item. + * The key identifies this entry's position in + * the SHAMap associative container. + */ [[nodiscard]] uint256 const& key() const; @@ -93,10 +108,11 @@ inline STLedgerEntry::STLedgerEntry( { } -/** Returns the 'key' (or 'index') of this item. - The key identifies this entry's position in - the SHAMap associative container. -*/ +/** + * Returns the 'key' (or 'index') of this item. + * The key identifies this entry's position in + * the SHAMap associative container. + */ inline uint256 const& STLedgerEntry::key() const { diff --git a/include/xrpl/protocol/STNumber.h b/include/xrpl/protocol/STNumber.h index 8594a292f4..7efb63ac5e 100644 --- a/include/xrpl/protocol/STNumber.h +++ b/include/xrpl/protocol/STNumber.h @@ -2,10 +2,17 @@ #include #include +#include +#include +#include #include #include +#include +#include +#include #include +#include namespace xrpl { diff --git a/include/xrpl/protocol/STObject.h b/include/xrpl/protocol/STObject.h index e65cc79c78..a1cdff22e0 100644 --- a/include/xrpl/protocol/STObject.h +++ b/include/xrpl/protocol/STObject.h @@ -1,27 +1,39 @@ #pragma once +#include #include +#include #include -#include +#include #include #include +#include +#include #include +#include #include #include #include +#include #include #include #include #include +#include #include #include #include +#include +#include +#include #include #include +#include #include #include +#include namespace xrpl { @@ -217,6 +229,13 @@ public: [[nodiscard]] AccountID getAccountID(SField const& field) const; + /** + * The account responsible for the authorization: the delegate when + * sfDelegate is present, otherwise the account. + */ + [[nodiscard]] AccountID + getInitiator() const; + [[nodiscard]] Blob getFieldVL(SField const& field) const; [[nodiscard]] STAmount const& @@ -235,103 +254,112 @@ public: [[nodiscard]] STNumber const& getFieldNumber(SField const& field) const; - /** Get the value of a field. - @param A TypedField built from an SField value representing the desired - object field. In typical use, the TypedField will be implicitly - constructed. - @return The value of the specified field. - @throws STObject::FieldErr if the field is not present. - */ + /** + * Get the value of a field. + * @param A TypedField built from an SField value representing the desired + * object field. In typical use, the TypedField will be implicitly + * constructed. + * @return The value of the specified field. + * @throws STObject::FieldErr if the field is not present. + */ template T::value_type operator[](TypedField const& f) const; - /** Get the value of a field as a std::optional - - @param An OptionaledField built from an SField value representing the - desired object field. In typical use, the OptionaledField will be - constructed by using the ~ operator on an SField. - @return std::nullopt if the field is not present, else the value of - the specified field. - */ + /** + * Get the value of a field as a std::optional + * + * @param An OptionaledField built from an SField value representing the + * desired object field. In typical use, the OptionaledField will be + * constructed by using the ~ operator on an SField. + * @return std::nullopt if the field is not present, else the value of + * the specified field. + */ template std::optional> operator[](OptionaledField const& of) const; - /** Get a modifiable field value. - @param A TypedField built from an SField value representing the desired - object field. In typical use, the TypedField will be implicitly - constructed. - @return A modifiable reference to the value of the specified field. - @throws STObject::FieldErr if the field is not present. - */ + /** + * Get a modifiable field value. + * @param A TypedField built from an SField value representing the desired + * object field. In typical use, the TypedField will be implicitly + * constructed. + * @return A modifiable reference to the value of the specified field. + * @throws STObject::FieldErr if the field is not present. + */ template ValueProxy operator[](TypedField const& f); - /** Return a modifiable field value as std::optional - - @param An OptionaledField built from an SField value representing the - desired object field. In typical use, the OptionaledField will be - constructed by using the ~ operator on an SField. - @return Transparent proxy object to an `optional` holding a modifiable - reference to the value of the specified field. Returns - std::nullopt if the field is not present. - */ + /** + * Return a modifiable field value as std::optional + * + * @param An OptionaledField built from an SField value representing the + * desired object field. In typical use, the OptionaledField will be + * constructed by using the ~ operator on an SField. + * @return Transparent proxy object to an `optional` holding a modifiable + * reference to the value of the specified field. Returns + * std::nullopt if the field is not present. + */ template OptionalProxy operator[](OptionaledField const& of); - /** Get the value of a field. - @param A TypedField built from an SField value representing the desired - object field. In typical use, the TypedField will be implicitly - constructed. - @return The value of the specified field. - @throws STObject::FieldErr if the field is not present. - */ + /** + * Get the value of a field. + * @param A TypedField built from an SField value representing the desired + * object field. In typical use, the TypedField will be implicitly + * constructed. + * @return The value of the specified field. + * @throws STObject::FieldErr if the field is not present. + */ template [[nodiscard]] T::value_type at(TypedField const& f) const; - /** Get the value of a field as std::optional - - @param An OptionaledField built from an SField value representing the - desired object field. In typical use, the OptionaledField will be - constructed by using the ~ operator on an SField. - @return std::nullopt if the field is not present, else the value of - the specified field. - */ + /** + * Get the value of a field as std::optional + * + * @param An OptionaledField built from an SField value representing the + * desired object field. In typical use, the OptionaledField will be + * constructed by using the ~ operator on an SField. + * @return std::nullopt if the field is not present, else the value of + * the specified field. + */ template [[nodiscard]] std::optional> at(OptionaledField const& of) const; - /** Get a modifiable field value. - @param A TypedField built from an SField value representing the desired - object field. In typical use, the TypedField will be implicitly - constructed. - @return A modifiable reference to the value of the specified field. - @throws STObject::FieldErr if the field is not present. - */ + /** + * Get a modifiable field value. + * @param A TypedField built from an SField value representing the desired + * object field. In typical use, the TypedField will be implicitly + * constructed. + * @return A modifiable reference to the value of the specified field. + * @throws STObject::FieldErr if the field is not present. + */ template ValueProxy at(TypedField const& f); - /** Return a modifiable field value as std::optional - - @param An OptionaledField built from an SField value representing the - desired object field. In typical use, the OptionaledField will be - constructed by using the ~ operator on an SField. - @return Transparent proxy object to an `optional` holding a modifiable - reference to the value of the specified field. Returns - std::nullopt if the field is not present. - */ + /** + * Return a modifiable field value as std::optional + * + * @param An OptionaledField built from an SField value representing the + * desired object field. In typical use, the OptionaledField will be + * constructed by using the ~ operator on an SField. + * @return Transparent proxy object to an `optional` holding a modifiable + * reference to the value of the specified field. Returns + * std::nullopt if the field is not present. + */ template OptionalProxy at(OptionaledField const& of); - /** Set a field. - if the field already exists, it is replaced. - */ + /** + * Set a field. + * if the field already exists, it is replaced. + */ void set(std::unique_ptr v); @@ -486,8 +514,10 @@ public: value_type operator*() const; - /// Do not use operator->() unless the field is required, or you've checked - /// that it's set. + /** + * Do not use operator->() unless the field is required, or you've checked + * that it's set. + */ T const* operator->() const; @@ -538,9 +568,14 @@ public: ValueProxy& operator=(ValueProxy const&) = delete; + // Write-through proxy: assignment sets the referenced field to the given + // value, so it intentionally takes the assigned value rather than a + // ValueProxy. template - std::enable_if_t, ValueProxy&> - operator=(U&& u); + // NOLINTNEXTLINE(misc-unconventional-assign-operator) + ValueProxy& + operator=(U&& u) + requires(std::is_assignable_v); // Convenience operators for value types supporting // arithmetic operations @@ -582,17 +617,20 @@ public: OptionalProxy& operator=(OptionalProxy const&) = delete; - /** Returns `true` if the field is set. - - Fields with soeDEFAULT and set to the - default value will return `true` - */ + /** + * Returns `true` if the field is set. + * + * Fields with soeDEFAULT and set to the + * default value will return `true` + */ explicit operator bool() const noexcept; operator optional_type() const; - /** Explicit conversion to std::optional */ + /** + * Explicit conversion to std::optional + */ optional_type operator~() const; @@ -674,8 +712,9 @@ public: operator=(optional_type const& v); template - std::enable_if_t, OptionalProxy&> - operator=(U&& u); + OptionalProxy& + operator=(U&& u) + requires(std::is_assignable_v); private: friend class STObject; @@ -738,8 +777,10 @@ STObject::Proxy::operator*() const -> value_type return this->value(); } -/// Do not use operator->() unless the field is required, or you've checked that -/// it's set. +/** + * Do not use operator->() unless the field is required, or you've checked that + * it's set. + */ template T const* STObject::Proxy::operator->() const @@ -781,8 +822,10 @@ STObject::Proxy::assign(U&& u) template template -std::enable_if_t, STObject::ValueProxy&> +// NOLINTNEXTLINE(misc-unconventional-assign-operator) +STObject::ValueProxy& STObject::ValueProxy::operator=(U&& u) + requires(std::is_assignable_v) { this->assign(std::forward(u)); return *this; @@ -885,8 +928,9 @@ STObject::OptionalProxy::operator=(optional_type const& v) -> OptionalProxy& template template -std::enable_if_t, STObject::OptionalProxy&> +STObject::OptionalProxy& STObject::OptionalProxy::operator=(U&& u) + requires(std::is_assignable_v) { this->assign(std::forward(u)); return *this; @@ -1224,7 +1268,7 @@ template void STObject::setFieldUsingSetValue(SField const& field, V value) { - static_assert(!std::is_lvalue_reference_v, ""); + static_assert(!std::is_lvalue_reference_v); STBase* rf = getPField(field, true); diff --git a/include/xrpl/protocol/STParsedJSON.h b/include/xrpl/protocol/STParsedJSON.h index 2557ab055b..7189e0ec89 100644 --- a/include/xrpl/protocol/STParsedJSON.h +++ b/include/xrpl/protocol/STParsedJSON.h @@ -1,31 +1,41 @@ #pragma once -#include +#include +#include +#include #include +#include namespace xrpl { -/** Maximum JSON object nesting depth permitted during parsing. */ +/** + * Maximum JSON object nesting depth permitted during parsing. + */ inline constexpr std::size_t kMaxParsedJsonDepth = 64; -/** Maximum number of elements permitted in any JSON array field during parsing. - Requests exceeding this limit are rejected with an invalidParams error. */ +/** + * Maximum number of elements permitted in any JSON array field during parsing. + * Requests exceeding this limit are rejected with an invalidParams error. + */ inline constexpr std::size_t kMaxParsedJsonArraySize = 512; -/** Holds the serialized result of parsing an input JSON object. - This does validation and checking on the provided JSON. -*/ +/** + * Holds the serialized result of parsing an input JSON object. + * This does validation and checking on the provided JSON. + */ class STParsedJSONObject { public: - /** Parses and creates an STParsedJSON object. - The result of the parsing is stored in object and error. - Exceptions: - Does not throw. - @param name The name of the JSON field, used in diagnostics. - @param json The JSON-RPC to parse. - */ + /** + * Parses and creates an STParsedJSON object. + * The result of the parsing is stored in object and error. + * + * @note Does not throw. + * + * @param name The name of the JSON field, used in diagnostics. + * @param json The JSON-RPC to parse. + */ STParsedJSONObject(std::string const& name, json::Value const& json); STParsedJSONObject() = delete; @@ -34,10 +44,14 @@ public: operator=(STParsedJSONObject const&) = delete; ~STParsedJSONObject() = default; - /** The STObject if the parse was successful. */ + /** + * The STObject if the parse was successful. + */ std::optional object; - /** On failure, an appropriate set of error values. */ + /** + * On failure, an appropriate set of error values. + */ json::Value error; }; diff --git a/include/xrpl/protocol/STPathSet.h b/include/xrpl/protocol/STPathSet.h index 1508dcb727..23f4e653c4 100644 --- a/include/xrpl/protocol/STPathSet.h +++ b/include/xrpl/protocol/STPathSet.h @@ -3,14 +3,17 @@ #include #include #include -#include +#include #include #include #include +#include #include #include #include +#include +#include namespace xrpl { @@ -237,6 +240,9 @@ private: inline STPathElement::STPathElement() : type_(TypeNone), isOffer_(true) { + // hashValue_ is derived from the whole object, so it is computed in the body + // once every other member is initialized (as in the other constructors). + // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer) hashValue_ = getHash(*this); } @@ -312,6 +318,9 @@ inline STPathElement::STPathElement( assetID_.visit( [&](Currency const&) { type_ = type_ & (~Type::TypeMpt); }, [&](MPTID const&) { type_ = type_ & (~Type::TypeCurrency); }); + // hashValue_ must be computed after type_ is adjusted above, so this cannot + // be a member initializer. + // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer) hashValue_ = getHash(*this); } diff --git a/include/xrpl/protocol/STTakesAsset.h b/include/xrpl/protocol/STTakesAsset.h index bf75ffccf7..95667e4868 100644 --- a/include/xrpl/protocol/STTakesAsset.h +++ b/include/xrpl/protocol/STTakesAsset.h @@ -3,9 +3,12 @@ #include #include +#include + namespace xrpl { -/** Intermediate class for any STBase-derived class to store an Asset. +/** + * Intermediate class for any STBase-derived class to store an Asset. * * In the class definition, this class should be specified as a base class * _instead_ of STBase. @@ -39,7 +42,8 @@ STTakesAsset::associateAsset(Asset const& a) class STLedgerEntry; -/** Associate an Asset with all sMD_NeedsAsset fields in a ledger entry. +/** + * Associate an Asset with all sMD_NeedsAsset fields in a ledger entry. * * This function iterates over all fields in the given ledger entry. For each * field that is set and has the SField::sMD_NeedsAsset metadata flag, it calls @@ -52,7 +56,6 @@ class STLedgerEntry; * * @param sle The ledger entry whose fields will be updated. * @param asset The Asset to associate with the relevant fields. - * */ void associateAsset(STLedgerEntry& sle, Asset const& asset); diff --git a/include/xrpl/protocol/STTx.h b/include/xrpl/protocol/STTx.h index 659fede31d..989bd11c10 100644 --- a/include/xrpl/protocol/STTx.h +++ b/include/xrpl/protocol/STTx.h @@ -1,17 +1,30 @@ #pragma once -#include +#include +#include +#include +#include +#include #include #include +#include +#include #include #include #include +#include #include #include +#include +#include #include #include +#include +#include +#include +#include namespace xrpl { @@ -42,60 +55,60 @@ public: explicit STTx(SerialIter&& sit); explicit STTx(STObject&& object); - /** Constructs a transaction. - - The returned transaction will have the specified type and - any fields that the callback function adds to the object - that's passed in. - */ + /** + * Constructs a transaction. + * + * The returned transaction will have the specified type and + * any fields that the callback function adds to the object + * that's passed in. + */ STTx(TxType type, std::function assembler); // STObject functions. - SerializedTypeID + [[nodiscard]] SerializedTypeID getSType() const override; - std::string + [[nodiscard]] std::string getFullText() const override; // Outer transaction functions / signature functions. static Blob getSignature(STObject const& sigObject); - Blob + [[nodiscard]] Blob getSignature() const { return getSignature(*this); } - uint256 + [[nodiscard]] uint256 getSigningHash() const; - TxType + [[nodiscard]] TxType getTxnType() const; - Blob + [[nodiscard]] Blob getSigningPubKey() const; - SeqProxy + [[nodiscard]] SeqProxy getSeqProxy() const; - /** Returns the first non-zero value of (Sequence, TicketSequence). */ - std::uint32_t + /** + * Returns the first non-zero value of (Sequence, TicketSequence). + */ + [[nodiscard]] std::uint32_t getSeqValue() const; - AccountID - getFeePayer() const; - - boost::container::flat_set + [[nodiscard]] boost::container::flat_set getMentionedAccounts() const; - uint256 + [[nodiscard]] uint256 getTransactionID() const; - json::Value + [[nodiscard]] json::Value getJson(JsonOptions options) const override; - json::Value + [[nodiscard]] json::Value getJson(JsonOptions options, bool binary) const; void @@ -104,78 +117,89 @@ public: SecretKey const& secretKey, std::optional> signatureTarget = {}); - /** Check the signature. - @param rules The current ledger rules. - @return `true` if valid signature. If invalid, the error message string. - */ - std::expected + /** + * Check the signature. + * @param rules The current ledger rules. + * @return `true` if valid signature. If invalid, the error message string. + */ + [[nodiscard]] std::expected checkSign(Rules const& rules) const; - std::expected + [[nodiscard]] std::expected checkBatchSign(Rules const& rules) const; // SQL Functions with metadata. static std::string const& getMetaSQLInsertReplaceHeader(); - std::string + [[nodiscard]] std::string getMetaSQL(std::uint32_t inLedger, std::string const& escapedMetaData) const; - std::string + [[nodiscard]] std::string getMetaSQL( Serializer rawTxn, std::uint32_t inLedger, TxnSql status, std::string const& escapedMetaData) const; - std::vector const& + [[nodiscard]] std::vector const& getBatchTransactionIDs() const; + [[nodiscard]] AccountID + getFeePayerID() const; + private: - /** Check the signature. - @param rules The current ledger rules. - @param sigObject Reference to object that contains the signature fields. - Will be *this more often than not. - @return `true` if valid signature. If invalid, the error message string. - */ - std::expected + /** + * Check the signature. + * @param rules The current ledger rules. + * @param sigObject Reference to object that contains the signature fields. + * Will be *this more often than not. + * @return `true` if valid signature. If invalid, the error message string. + */ + [[nodiscard]] std::expected checkSign(Rules const& rules, STObject const& sigObject) const; - std::expected + [[nodiscard]] std::expected checkSingleSign(STObject const& sigObject) const; - std::expected + [[nodiscard]] std::expected checkMultiSign(Rules const& rules, STObject const& sigObject) const; - std::expected + [[nodiscard]] std::expected checkBatchSingleSign(STObject const& batchSigner) const; - std::expected + [[nodiscard]] std::expected checkBatchMultiSign(STObject const& batchSigner, Rules const& rules) const; + void + buildBatchTxnIds(); + STBase* copy(std::size_t n, void* buf) const override; STBase* move(std::size_t n, void* buf) override; friend class detail::STVar; - mutable std::vector batchTxnIds_; + std::optional> batchTxnIds_; }; bool passesLocalChecks(STObject const& st, std::string&); -/** Sterilize a transaction. - - The transaction is serialized and then deserialized, - ensuring that all equivalent transactions are in canonical - form. This also ensures that program metadata such as - the transaction's digest, are all computed. -*/ +/** + * Sterilize a transaction. + * + * The transaction is serialized and then deserialized, + * ensuring that all equivalent transactions are in canonical + * form. This also ensures that program metadata such as + * the transaction's digest, are all computed. + */ std::shared_ptr sterilize(STTx const& stx); -/** Check whether a transaction is a pseudo-transaction */ +/** + * Check whether a transaction is a pseudo-transaction + */ bool isPseudoTx(STObject const& tx); diff --git a/include/xrpl/protocol/STValidation.h b/include/xrpl/protocol/STValidation.h index 91ce88b441..444fdfa600 100644 --- a/include/xrpl/protocol/STValidation.h +++ b/include/xrpl/protocol/STValidation.h @@ -1,15 +1,30 @@ #pragma once +#include +#include #include +#include +#include +#include +#include #include +#include #include +#include +#include +#include #include #include -#include +#include +#include +#include +#include #include #include #include +#include +#include namespace xrpl { @@ -39,30 +54,32 @@ class STValidation final : public STObject, public CountedObject NetClock::time_point seenTime_; public: - /** Construct a STValidation from a peer from serialized data. - - @param sit Iterator over serialized data - @param lookupNodeID Invocable with signature - NodeID(PublicKey const&) - used to find the Node ID based on the public key - that signed the validation. For manifest based - validators, this should be the NodeID of the master - public key. - @param checkSignature Whether to verify the data was signed properly - - @note Throws if the object is not valid - */ + /** + * Construct a STValidation from a peer from serialized data. + * + * @param sit Iterator over serialized data + * @param lookupNodeID Invocable with signature + * NodeID(PublicKey const&) + * used to find the Node ID based on the public key + * that signed the validation. For manifest based + * validators, this should be the NodeID of the master + * public key. + * @param checkSignature Whether to verify the data was signed properly + * + * @note Throws if the object is not valid + */ template STValidation(SerialIter& sit, LookupNodeID&& lookupNodeID, bool checkSignature); - /** Construct, sign and trust a new STValidation issued by this node. - - @param signTime When the validation is signed - @param publicKey The current signing public key - @param secretKey The current signing secret key - @param nodeID ID corresponding to node's public master key - @param f callback function to "fill" the validation with necessary data - */ + /** + * Construct, sign and trust a new STValidation issued by this node. + * + * @param signTime When the validation is signed + * @param publicKey The current signing public key + * @param secretKey The current signing secret key + * @param nodeID ID corresponding to node's public master key + * @param f callback function to "fill" the validation with necessary data + */ template STValidation( NetClock::time_point signTime, @@ -72,35 +89,35 @@ public: F&& f); // Hash of the validated ledger - uint256 + [[nodiscard]] uint256 getLedgerHash() const; // Hash of consensus transaction set used to generate ledger - uint256 + [[nodiscard]] uint256 getConsensusHash() const; - NetClock::time_point + [[nodiscard]] NetClock::time_point getSignTime() const; - NetClock::time_point + [[nodiscard]] NetClock::time_point getSeenTime() const noexcept; - PublicKey const& + [[nodiscard]] PublicKey const& getSignerPublic() const noexcept; - NodeID const& + [[nodiscard]] NodeID const& getNodeID() const noexcept; - bool + [[nodiscard]] bool isValid() const noexcept; - bool + [[nodiscard]] bool isFull() const noexcept; - bool + [[nodiscard]] bool isTrusted() const noexcept; - uint256 + [[nodiscard]] uint256 getSigningHash() const; void @@ -112,13 +129,13 @@ public: void setSeen(NetClock::time_point s); - Blob + [[nodiscard]] Blob getSerialized() const; - Blob + [[nodiscard]] Blob getSignature() const; - std::string + [[nodiscard]] std::string render() const { std::stringstream ss; @@ -168,14 +185,15 @@ STValidation::STValidation(SerialIter& sit, LookupNodeID&& lookupNodeID, bool ch XRPL_ASSERT(nodeID_.isNonZero(), "xrpl::STValidation::STValidation(SerialIter) : nonzero node"); } -/** Construct, sign and trust a new STValidation issued by this node. - - @param signTime When the validation is signed - @param publicKey The current signing public key - @param secretKey The current signing secret key - @param nodeID ID corresponding to node's public master key - @param f callback function to "fill" the validation with necessary data -*/ +/** + * Construct, sign and trust a new STValidation issued by this node. + * + * @param signTime When the validation is signed + * @param publicKey The current signing public key + * @param secretKey The current signing secret key + * @param nodeID ID corresponding to node's public master key + * @param f callback function to "fill" the validation with necessary data + */ template STValidation::STValidation( NetClock::time_point signTime, diff --git a/include/xrpl/protocol/STVector256.h b/include/xrpl/protocol/STVector256.h index 5c454b6be0..5a8418fef5 100644 --- a/include/xrpl/protocol/STVector256.h +++ b/include/xrpl/protocol/STVector256.h @@ -1,9 +1,15 @@ #pragma once #include +#include +#include +#include #include -#include -#include +#include + +#include +#include +#include namespace xrpl { @@ -44,7 +50,9 @@ public: void setValue(STVector256 const& v); - /** Retrieve a copy of the vector we contain */ + /** + * Retrieve a copy of the vector we contain + */ explicit operator std::vector() const; @@ -132,7 +140,9 @@ STVector256::setValue(STVector256 const& v) value_ = v.value_; } -/** Retrieve a copy of the vector we contain */ +/** + * Retrieve a copy of the vector we contain + */ inline STVector256:: operator std::vector() const { diff --git a/include/xrpl/protocol/STXChainBridge.h b/include/xrpl/protocol/STXChainBridge.h index 292ffe2767..24d64ef02b 100644 --- a/include/xrpl/protocol/STXChainBridge.h +++ b/include/xrpl/protocol/STXChainBridge.h @@ -1,9 +1,19 @@ #pragma once #include +#include +#include +#include +#include #include #include #include +#include + +#include +#include +#include +#include namespace xrpl { diff --git a/include/xrpl/protocol/SecretKey.h b/include/xrpl/protocol/SecretKey.h index 712b095f81..6d353acac0 100644 --- a/include/xrpl/protocol/SecretKey.h +++ b/include/xrpl/protocol/SecretKey.h @@ -2,18 +2,24 @@ #include #include +#include #include #include #include #include #include +#include #include +#include #include +#include namespace xrpl { -/** A secret key. */ +/** + * A secret key. + */ class SecretKey { public: @@ -52,11 +58,12 @@ public: return sizeof(buf_); } - /** Convert the secret key to a hexadecimal string. - - @note The operator<< function is deliberately omitted - to avoid accidental exposure of secret key material. - */ + /** + * Convert the secret key to a hexadecimal string. + * + * @note The operator<< function is deliberately omitted + * to avoid accidental exposure of secret key material. + */ [[nodiscard]] std::string toString() const; @@ -93,7 +100,9 @@ operator!=(SecretKey const& lhs, SecretKey const& rhs) = delete; //------------------------------------------------------------------------------ -/** Parse a secret key */ +/** + * Parse a secret key + */ template <> std::optional parseBase58(TokenType type, std::string const& s); @@ -104,38 +113,48 @@ toBase58(TokenType type, SecretKey const& sk) return encodeBase58Token(type, sk.data(), sk.size()); } -/** Create a secret key using secure random numbers. */ +/** + * Create a secret key using secure random numbers. + */ SecretKey randomSecretKey(); -/** Generate a new secret key deterministically. */ +/** + * Generate a new secret key deterministically. + */ SecretKey generateSecretKey(KeyType type, Seed const& seed); -/** Derive the public key from a secret key. */ +/** + * Derive the public key from a secret key. + */ PublicKey derivePublicKey(KeyType type, SecretKey const& sk); -/** Generate a key pair deterministically. - - This algorithm is specific to the XRPL: - - For secp256k1 key pairs, the seed is converted - to a Generator and used to compute the key pair - corresponding to ordinal 0 for the generator. -*/ +/** + * Generate a key pair deterministically. + * + * This algorithm is specific to the XRPL: + * + * For secp256k1 key pairs, the seed is converted + * to a Generator and used to compute the key pair + * corresponding to ordinal 0 for the generator. + */ std::pair generateKeyPair(KeyType type, Seed const& seed); -/** Create a key pair using secure random numbers. */ +/** + * Create a key pair using secure random numbers. + */ std::pair randomKeyPair(KeyType type); -/** Generate a signature for a message digest. - This can only be used with secp256k1 since Ed25519's - security properties come, in part, from how the message - is hashed. -*/ +/** + * Generate a signature for a message digest. + * This can only be used with secp256k1 since Ed25519's + * security properties come, in part, from how the message + * is hashed. + */ /** @{ */ Buffer signDigest(PublicKey const& pk, SecretKey const& sk, uint256 const& digest); @@ -147,10 +166,11 @@ signDigest(KeyType type, SecretKey const& sk, uint256 const& digest) } /** @} */ -/** Generate a signature for a message. - With secp256k1 signatures, the data is first hashed with - SHA512-Half, and the resulting digest is signed. -*/ +/** + * Generate a signature for a message. + * With secp256k1 signatures, the data is first hashed with + * SHA512-Half, and the resulting digest is signed. + */ /** @{ */ Buffer sign(PublicKey const& pk, SecretKey const& sk, Slice const& message); diff --git a/include/xrpl/protocol/Seed.h b/include/xrpl/protocol/Seed.h index 0b93b84516..4ccdd6707f 100644 --- a/include/xrpl/protocol/Seed.h +++ b/include/xrpl/protocol/Seed.h @@ -5,11 +5,16 @@ #include #include +#include +#include #include +#include namespace xrpl { -/** Seeds are used to generate deterministic secret keys. */ +/** + * Seeds are used to generate deterministic secret keys. + */ class Seed { private: @@ -24,12 +29,15 @@ public: Seed& operator=(Seed const&) = default; - /** Destroy the seed. - The buffer will first be securely erased. - */ + /** + * Destroy the seed. + * The buffer will first be securely erased. + */ ~Seed(); - /** Construct a seed */ + /** + * Construct a seed + */ /** @{ */ explicit Seed(Slice const& slice); explicit Seed(uint128 const& seed); @@ -74,42 +82,52 @@ public: //------------------------------------------------------------------------------ -/** Create a seed using secure random numbers. */ +/** + * Create a seed using secure random numbers. + */ Seed randomSeed(); -/** Generate a seed deterministically. - - The algorithm is specific to the XRPL: - - The seed is calculated as the first 128 bits - of the SHA512-Half of the string text excluding - any terminating null. - - @note This will not attempt to determine the format of - the string (e.g. hex or base58). -*/ +/** + * Generate a seed deterministically. + * + * The algorithm is specific to the XRPL: + * + * The seed is calculated as the first 128 bits + * of the SHA512-Half of the string text excluding + * any terminating null. + * + * @note This will not attempt to determine the format of + * the string (e.g. hex or base58). + */ Seed generateSeed(std::string const& passPhrase); -/** Parse a Base58 encoded string into a seed */ +/** + * Parse a Base58 encoded string into a seed + */ template <> std::optional parseBase58(std::string const& s); -/** Attempt to parse a string as a seed. - - @param str the string to parse - @param rfc1751 true if we should attempt RFC1751 style parsing (deprecated) - * */ +/** + * Attempt to parse a string as a seed. + * + * @param str the string to parse + * @param rfc1751 true if we should attempt RFC1751 style parsing (deprecated) + */ std::optional parseGenericSeed(std::string const& str, bool rfc1751 = true); -/** Encode a Seed in RFC1751 format */ +/** + * Encode a Seed in RFC1751 format + */ std::string seedAs1751(Seed const& seed); -/** Format a seed as a Base58 string */ +/** + * Format a seed as a Base58 string + */ inline std::string toBase58(Seed const& seed) { diff --git a/include/xrpl/protocol/SeqProxy.h b/include/xrpl/protocol/SeqProxy.h index be040cceec..e6a97be0e7 100644 --- a/include/xrpl/protocol/SeqProxy.h +++ b/include/xrpl/protocol/SeqProxy.h @@ -5,33 +5,34 @@ namespace xrpl { -/** A type that represents either a sequence value or a ticket value. - - We use the value() of a SeqProxy in places where a sequence was used - before. An example of this is the sequence of an Offer stored in the - ledger. We do the same thing with the in-ledger identifier of a - Check, Payment Channel, and Escrow. - - Why is this safe? If we use the SeqProxy::value(), how do we know that - each ledger entry will be unique? - - There are two components that make this safe: - - 1. A "TicketCreate" transaction carefully avoids creating a ticket - that corresponds with an already used Sequence or Ticket value. - The transactor does this by referring to the account root's - sequence number. Creating the ticket advances the account root's - sequence number so the same ticket (or sequence) value cannot be - used again. - - 2. When a "TicketCreate" transaction creates a batch of tickets it advances - the account root sequence to one past the largest created ticket. - - Therefore all tickets in a batch other than the first may never have - the same value as a sequence on that same account. And since a ticket - may only be used once there will never be any duplicates within this - account. -*/ +/** + * A type that represents either a sequence value or a ticket value. + * + * We use the value() of a SeqProxy in places where a sequence was used + * before. An example of this is the sequence of an Offer stored in the + * ledger. We do the same thing with the in-ledger identifier of a + * Check, Payment Channel, and Escrow. + * + * Why is this safe? If we use the SeqProxy::value(), how do we know that + * each ledger entry will be unique? + * + * There are two components that make this safe: + * + * 1. A "TicketCreate" transaction carefully avoids creating a ticket + * that corresponds with an already used Sequence or Ticket value. + * The transactor does this by referring to the account root's + * sequence number. Creating the ticket advances the account root's + * sequence number so the same ticket (or sequence) value cannot be + * used again. + * + * 2. When a "TicketCreate" transaction creates a batch of tickets it advances + * the account root sequence to one past the largest created ticket. + * + * Therefore all tickets in a batch other than the first may never have + * the same value as a sequence on that same account. And since a ticket + * may only be used once there will never be any duplicates within this + * account. + */ class SeqProxy { public: @@ -51,7 +52,9 @@ public: SeqProxy& operator=(SeqProxy const& other) = default; - /** Factory function to return a sequence-based SeqProxy */ + /** + * Factory function to return a sequence-based SeqProxy + */ static constexpr SeqProxy sequence(std::uint32_t v) { diff --git a/include/xrpl/protocol/Serializer.h b/include/xrpl/protocol/Serializer.h index ffe9afabe8..73bd9c8289 100644 --- a/include/xrpl/protocol/Serializer.h +++ b/include/xrpl/protocol/Serializer.h @@ -6,13 +6,14 @@ #include #include #include -#include #include #include #include #include #include +#include +#include #include namespace xrpl { @@ -333,7 +334,7 @@ public: template explicit SerialIter(std::uint8_t const (&data)[N]) : SerialIter(&data[0], N) { - static_assert(N > 0, ""); + static_assert(N > 0); } [[nodiscard]] bool diff --git a/include/xrpl/protocol/Sign.h b/include/xrpl/protocol/Sign.h index 0b5b5d7239..fad2c35c9e 100644 --- a/include/xrpl/protocol/Sign.h +++ b/include/xrpl/protocol/Sign.h @@ -1,23 +1,28 @@ #pragma once +#include #include +#include #include +#include #include #include +#include namespace xrpl { -/** Sign an STObject - - @param st Object to sign - @param prefix Prefix to insert before serialized object when hashing - @param type Signing key type used to derive public key - @param sk Signing secret key - @param sigField Field in which to store the signature on the object. - If not specified the value defaults to `sfSignature`. - - @note If a signature already exists, it is overwritten. -*/ +/** + * Sign an STObject + * + * @param st Object to sign + * @param prefix Prefix to insert before serialized object when hashing + * @param type Signing key type used to derive public key + * @param sk Signing secret key + * @param sigField Field in which to store the signature on the object. + * If not specified the value defaults to `sfSignature`. + * + * @note If a signature already exists, it is overwritten. + */ void sign( STObject& st, @@ -26,14 +31,15 @@ sign( SecretKey const& sk, SF_VL const& sigField = sfSignature); -/** Returns `true` if STObject contains valid signature - - @param st Signed object - @param prefix Prefix inserted before serialized object when hashing - @param pk Public key for verifying signature - @param sigField Object's field containing the signature. - If not specified the value defaults to `sfSignature`. -*/ +/** + * Returns `true` if STObject contains valid signature + * + * @param st Signed object + * @param prefix Prefix inserted before serialized object when hashing + * @param pk Public key for verifying signature + * @param sigField Object's field containing the signature. + * If not specified the value defaults to `sfSignature`. + */ bool verify( STObject const& st, @@ -41,22 +47,25 @@ verify( PublicKey const& pk, SF_VL const& sigField = sfSignature); -/** Return a Serializer suitable for computing a multisigning TxnSignature. */ +/** + * Return a Serializer suitable for computing a multisigning TxnSignature. + */ Serializer buildMultiSigningData(STObject const& obj, AccountID const& signingID); -/** Break the multi-signing hash computation into 2 parts for optimization. - - We can optimize verifying multiple multisignatures by splitting the - data building into two parts; - o A large part that is shared by all of the computations. - o A small part that is unique to each signer in the multisignature. - - The following methods support that optimization: - 1. startMultiSigningData provides the large part which can be shared. - 2. finishMultiSigningData caps the passed in serializer with each - signer's unique data. -*/ +/** + * Break the multi-signing hash computation into 2 parts for optimization. + * + * We can optimize verifying multiple multisignatures by splitting the + * data building into two parts; + * o A large part that is shared by all of the computations. + * o A small part that is unique to each signer in the multisignature. + * + * The following methods support that optimization: + * 1. startMultiSigningData provides the large part which can be shared. + * 2. finishMultiSigningData caps the passed in serializer with each + * signer's unique data. + */ Serializer startMultiSigningData(STObject const& obj); diff --git a/include/xrpl/protocol/SystemParameters.h b/include/xrpl/protocol/SystemParameters.h index 1cc35a0f31..6ca36c8d9a 100644 --- a/include/xrpl/protocol/SystemParameters.h +++ b/include/xrpl/protocol/SystemParameters.h @@ -1,9 +1,12 @@ #pragma once +#include #include #include +#include #include +#include #include namespace xrpl { @@ -18,22 +21,30 @@ systemName() return kName; } -/** Configure the native currency. */ +/** + * Configure the native currency. + */ -/** Number of drops in the genesis account. */ +/** + * Number of drops in the genesis account. + */ constexpr XRPAmount kInitialXrp{100'000'000'000 * kDropsPerXrp}; static_assert(kInitialXrp.drops() == 100'000'000'000'000'000); static_assert(Number::kMaxRep >= kInitialXrp.drops()); -/** Returns true if the amount does not exceed the initial XRP in existence. */ +/** + * Returns true if the amount does not exceed the initial XRP in existence. + */ inline bool isLegalAmount(XRPAmount const& amount) { return amount <= kInitialXrp; } -/** Returns true if the absolute value of the amount does not exceed the initial - * XRP in existence. */ +/** + * Returns true if the absolute value of the amount does not exceed the initial + * XRP in existence. + */ inline bool isLegalAmountSigned(XRPAmount const& amount) { @@ -48,20 +59,30 @@ systemCurrencyCode() return kCode; } -/** The XRP ledger network's earliest allowed sequence */ +/** + * The XRP ledger network's earliest allowed sequence + */ static constexpr std::uint32_t kXrpLedgerEarliestSeq{32570u}; -/** The XRP Ledger mainnet's earliest ledger with a FeeSettings object. Only - * used in asserts and tests. */ +/** + * The XRP Ledger mainnet's earliest ledger with a FeeSettings object. Only + * used in asserts and tests. + */ static constexpr std::uint32_t kXrpLedgerEarliestFees{562177u}; -/** The minimum amount of support an amendment should have. */ +/** + * The minimum amount of support an amendment should have. + */ constexpr std::ratio<80, 100> kAmendmentMajorityCalcThreshold; -/** The minimum amount of time an amendment must hold a majority */ +/** + * The minimum amount of time an amendment must hold a majority + */ constexpr std::chrono::seconds const kDefaultAmendmentMajorityTime = weeks{2}; } // namespace xrpl -/** Default peer port (IANA registered) */ +/** + * Default peer port (IANA registered) + */ inline constexpr std::uint16_t kDefaultPeerPort{2459}; diff --git a/include/xrpl/protocol/TER.h b/include/xrpl/protocol/TER.h index 072bd4778f..730d021254 100644 --- a/include/xrpl/protocol/TER.h +++ b/include/xrpl/protocol/TER.h @@ -8,7 +8,9 @@ #include #include #include +#include #include +#include namespace xrpl { @@ -128,6 +130,7 @@ enum TEMcodes : TERUnderlyingType { temBAD_TRANSFER_FEE, temINVALID_INNER_BATCH, temBAD_MPT, + temBAD_CIPHERTEXT, }; //------------------------------------------------------------------------------ @@ -174,6 +177,8 @@ enum TEFcodes : TERUnderlyingType { tefNO_TICKET, tefNFTOKEN_IS_NOT_TRANSFERABLE, tefINVALID_LEDGER_FIX_TYPE, + tefNO_DST_PARTIAL, + tefBAD_PATH_COUNT, }; //------------------------------------------------------------------------------ @@ -220,6 +225,7 @@ enum TERcodes : TERUnderlyingType { // create a pseudo-account terNO_DELEGATE_PERMISSION, // Delegate does not have permission terLOCKED, // MPT is locked + terNO_PERMISSION, // No permission but retry }; //------------------------------------------------------------------------------ @@ -358,6 +364,12 @@ enum TECcodes : TERUnderlyingType { tecLIMIT_EXCEEDED = 195, tecPSEUDO_ACCOUNT = 196, tecPRECISION_LOSS = 197, + // DEPRECATED: This error code tecNO_DELEGATE_PERMISSION is reserved for + // backward compatibility with historical data on non-prod networks, can be + // reclaimed after those networks reset. + tecNO_DELEGATE_PERMISSION = 198, + tecBAD_PROOF = 199, + tecNO_SPONSOR_PERMISSION = 200, }; //------------------------------------------------------------------------------ @@ -401,7 +413,7 @@ TERtoInt(TECcodes v) //------------------------------------------------------------------------------ // Template class that is specific to selected ranges of error codes. The -// Trait tells std::enable_if which ranges are allowed. +// Trait tells the requires-clause which ranges are allowed. template