mirror of
https://github.com/XRPLF/rippled.git
synced 2026-03-02 10:42:33 +00:00
Compare commits
47 Commits
pratik/Fix
...
ximinez/ac
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6fc972746d | ||
|
|
930afbdea8 | ||
|
|
95c5bef48b | ||
|
|
b489b6c3ce | ||
|
|
70765acef4 | ||
|
|
77aa90bd0e | ||
|
|
4758bb6dc9 | ||
|
|
46e3dcb5fb | ||
|
|
d57579f10b | ||
|
|
d8dd376d1c | ||
|
|
a8c03e2e6c | ||
|
|
2167a66bc7 | ||
|
|
ed948a858c | ||
|
|
608c102743 | ||
|
|
36d1607a4e | ||
|
|
53ebb86d60 | ||
|
|
1d989bc6de | ||
|
|
64c0cb8c7e | ||
|
|
c77cfef41c | ||
|
|
08aa8c06d1 | ||
|
|
9498672f8e | ||
|
|
e91d55a0e0 | ||
|
|
afdc452cfc | ||
|
|
a0d4ef1a54 | ||
|
|
8bc384f8bf | ||
|
|
bd961c484b | ||
|
|
aee242a8d4 | ||
|
|
fcae74de58 | ||
|
|
a56effcb00 | ||
|
|
64c2eca465 | ||
|
|
e56f750e1d | ||
|
|
fde000f3eb | ||
|
|
d0a62229da | ||
|
|
d5932cc7d4 | ||
|
|
0b534da781 | ||
|
|
71a70d343b | ||
|
|
0899e65030 | ||
|
|
31ba529761 | ||
|
|
e2c6e5ebb6 | ||
|
|
9d807fce48 | ||
|
|
9ef160765c | ||
|
|
d6c0eb243b | ||
|
|
84c9fc123c | ||
|
|
00a2a58cfa | ||
|
|
bb2098d873 | ||
|
|
46a5bc74db | ||
|
|
7b72b9cc82 |
309
.clang-tidy
309
.clang-tidy
@@ -1,143 +1,105 @@
|
||||
---
|
||||
Checks: "-*,
|
||||
bugprone-argument-comment,
|
||||
bugprone-assert-side-effect,
|
||||
bugprone-bad-signal-to-kill-thread,
|
||||
bugprone-bool-pointer-implicit-conversion,
|
||||
bugprone-casting-through-void,
|
||||
bugprone-chained-comparison,
|
||||
bugprone-compare-pointer-to-member-virtual-function,
|
||||
bugprone-copy-constructor-init,
|
||||
bugprone-dangling-handle,
|
||||
bugprone-dynamic-static-initializers,
|
||||
bugprone-fold-init-type,
|
||||
bugprone-forward-declaration-namespace,
|
||||
bugprone-inaccurate-erase,
|
||||
bugprone-incorrect-enable-if,
|
||||
bugprone-incorrect-roundings,
|
||||
bugprone-infinite-loop,
|
||||
bugprone-integer-division,
|
||||
bugprone-lambda-function-name,
|
||||
bugprone-macro-parentheses,
|
||||
bugprone-macro-repeated-side-effects,
|
||||
bugprone-misplaced-operator-in-strlen-in-alloc,
|
||||
bugprone-misplaced-pointer-arithmetic-in-alloc,
|
||||
bugprone-misplaced-widening-cast,
|
||||
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-parent-virtual-call,
|
||||
bugprone-posix-return,
|
||||
bugprone-redundant-branch-condition,
|
||||
bugprone-shared-ptr-array-mismatch,
|
||||
bugprone-signal-handler,
|
||||
bugprone-signed-char-misuse,
|
||||
bugprone-sizeof-container,
|
||||
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-realloc-usage,
|
||||
bugprone-suspicious-semicolon,
|
||||
bugprone-suspicious-string-compare,
|
||||
bugprone-swapped-arguments,
|
||||
bugprone-terminating-continue,
|
||||
bugprone-throw-keyword-missing,
|
||||
bugprone-undefined-memory-manipulation,
|
||||
bugprone-undelegated-constructor,
|
||||
bugprone-unhandled-exception-at-new,
|
||||
bugprone-unique-ptr-array-mismatch,
|
||||
bugprone-unsafe-functions,
|
||||
bugprone-virtual-near-miss,
|
||||
cppcoreguidelines-no-suspend-with-lock,
|
||||
cppcoreguidelines-virtual-class-destructor,
|
||||
hicpp-ignored-remove-result,
|
||||
misc-definitions-in-headers,
|
||||
misc-header-include-cycle,
|
||||
misc-misplaced-const,
|
||||
misc-static-assert,
|
||||
misc-throw-by-value-catch-by-reference,
|
||||
misc-unused-alias-decls,
|
||||
misc-unused-using-decls,
|
||||
readability-duplicate-include,
|
||||
readability-enum-initial-value,
|
||||
readability-misleading-indentation,
|
||||
readability-non-const-parameter,
|
||||
readability-redundant-declaration,
|
||||
readability-reference-to-constructed-temporary,
|
||||
modernize-deprecated-headers,
|
||||
modernize-make-shared,
|
||||
modernize-make-unique,
|
||||
performance-implicit-conversion-in-loop,
|
||||
performance-move-constructor-init,
|
||||
performance-trivially-destructible
|
||||
bugprone-argument-comment
|
||||
"
|
||||
# ---
|
||||
# checks that have some issues that need to be resolved:
|
||||
#
|
||||
# bugprone-empty-catch,
|
||||
# bugprone-assert-side-effect,
|
||||
# bugprone-bad-signal-to-kill-thread,
|
||||
# bugprone-bool-pointer-implicit-conversion,
|
||||
# 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-dynamic-static-initializers,
|
||||
# bugprone-empty-catch,
|
||||
# bugprone-fold-init-type,
|
||||
# bugprone-forward-declaration-namespace,
|
||||
# bugprone-inaccurate-erase,
|
||||
# bugprone-inc-dec-in-conditions,
|
||||
# bugprone-reserved-identifier,
|
||||
# bugprone-incorrect-enable-if,
|
||||
# bugprone-incorrect-roundings,
|
||||
# bugprone-infinite-loop,
|
||||
# bugprone-integer-division,
|
||||
# bugprone-lambda-function-name,
|
||||
# bugprone-macro-parentheses,
|
||||
# bugprone-macro-repeated-side-effects,
|
||||
# bugprone-misplaced-operator-in-strlen-in-alloc,
|
||||
# bugprone-misplaced-pointer-arithmetic-in-alloc,
|
||||
# bugprone-misplaced-widening-cast,
|
||||
# bugprone-move-forwarding-reference,
|
||||
# bugprone-unused-local-non-trivial-variable,
|
||||
# bugprone-return-const-ref-from-parameter,
|
||||
# bugprone-switch-missing-default-case,
|
||||
# bugprone-sizeof-expression,
|
||||
# bugprone-suspicious-stringview-data-usage,
|
||||
# bugprone-suspicious-missing-comma,
|
||||
# bugprone-pointer-arithmetic-on-polymorphic-object,
|
||||
# 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-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-unhandled-self-assignment,
|
||||
# bugprone-unused-raii,
|
||||
#
|
||||
# cppcoreguidelines-misleading-capture-default-by-value,
|
||||
# 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-use-default-member-init,
|
||||
# cppcoreguidelines-rvalue-reference-param-not-moved,
|
||||
#
|
||||
# cppcoreguidelines-use-default-member-init,
|
||||
# cppcoreguidelines-virtual-class-destructor,
|
||||
# hicpp-ignored-remove-result,
|
||||
# llvm-namespace-comment,
|
||||
# misc-const-correctness,
|
||||
# misc-definitions-in-headers,
|
||||
# misc-header-include-cycle,
|
||||
# misc-include-cleaner,
|
||||
# misc-misplaced-const,
|
||||
# misc-redundant-expression,
|
||||
#
|
||||
# readability-avoid-nested-conditional-operator,
|
||||
# readability-avoid-return-with-void-value,
|
||||
# readability-braces-around-statements,
|
||||
# readability-container-contains,
|
||||
# readability-container-size-empty,
|
||||
# readability-convert-member-functions-to-static,
|
||||
# readability-const-return-type,
|
||||
# readability-else-after-return,
|
||||
# readability-implicit-bool-conversion,
|
||||
# readability-inconsistent-declaration-parameter-name,
|
||||
# readability-identifier-naming,
|
||||
# readability-make-member-function-const,
|
||||
# readability-math-missing-parentheses,
|
||||
# readability-redundant-inline-specifier,
|
||||
# readability-redundant-member-init,
|
||||
# readability-redundant-casting,
|
||||
# readability-redundant-string-init,
|
||||
# readability-simplify-boolean-expr,
|
||||
# readability-static-definition-in-anonymous-namespace,
|
||||
# readability-suspicious-call-argument,
|
||||
# readability-use-std-min-max,
|
||||
# readability-static-accessed-through-instance,
|
||||
#
|
||||
# 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,
|
||||
@@ -149,50 +111,79 @@ Checks: "-*,
|
||||
# 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-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-implicit-bool-conversion,
|
||||
# readability-inconsistent-declaration-parameter-name,
|
||||
# readability-identifier-naming,
|
||||
# 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-string-init,
|
||||
# readability-reference-to-constructed-temporary,
|
||||
# readability-simplify-boolean-expr,
|
||||
# readability-static-accessed-through-instance,
|
||||
# readability-static-definition-in-anonymous-namespace,
|
||||
# readability-suspicious-call-argument,
|
||||
# readability-use-std-min-max
|
||||
#
|
||||
CheckOptions:
|
||||
# readability-braces-around-statements.ShortStatementLines: 2
|
||||
# readability-identifier-naming.MacroDefinitionCase: UPPER_CASE
|
||||
# readability-identifier-naming.ClassCase: CamelCase
|
||||
# readability-identifier-naming.StructCase: CamelCase
|
||||
# readability-identifier-naming.UnionCase: CamelCase
|
||||
# readability-identifier-naming.EnumCase: CamelCase
|
||||
# readability-identifier-naming.EnumConstantCase: CamelCase
|
||||
# readability-identifier-naming.ScopedEnumConstantCase: CamelCase
|
||||
# readability-identifier-naming.GlobalConstantCase: UPPER_CASE
|
||||
# readability-identifier-naming.GlobalConstantPrefix: "k"
|
||||
# readability-identifier-naming.GlobalVariableCase: CamelCase
|
||||
# readability-identifier-naming.GlobalVariablePrefix: "g"
|
||||
# readability-identifier-naming.ConstexprFunctionCase: camelBack
|
||||
# readability-identifier-naming.ConstexprMethodCase: camelBack
|
||||
# readability-identifier-naming.ClassMethodCase: camelBack
|
||||
# readability-identifier-naming.ClassMemberCase: camelBack
|
||||
# readability-identifier-naming.ClassConstantCase: UPPER_CASE
|
||||
# readability-identifier-naming.ClassConstantPrefix: "k"
|
||||
# readability-identifier-naming.StaticConstantCase: UPPER_CASE
|
||||
# readability-identifier-naming.StaticConstantPrefix: "k"
|
||||
# readability-identifier-naming.StaticVariableCase: UPPER_CASE
|
||||
# readability-identifier-naming.StaticVariablePrefix: "k"
|
||||
# readability-identifier-naming.ConstexprVariableCase: UPPER_CASE
|
||||
# readability-identifier-naming.ConstexprVariablePrefix: "k"
|
||||
# readability-identifier-naming.LocalConstantCase: camelBack
|
||||
# readability-identifier-naming.LocalVariableCase: camelBack
|
||||
# readability-identifier-naming.TemplateParameterCase: CamelCase
|
||||
# readability-identifier-naming.ParameterCase: camelBack
|
||||
# readability-identifier-naming.FunctionCase: camelBack
|
||||
# readability-identifier-naming.MemberCase: camelBack
|
||||
# readability-identifier-naming.PrivateMemberSuffix: _
|
||||
# readability-identifier-naming.ProtectedMemberSuffix: _
|
||||
# readability-identifier-naming.PublicMemberSuffix: ""
|
||||
# readability-identifier-naming.FunctionIgnoredRegexp: ".*tag_invoke.*"
|
||||
bugprone-unsafe-functions.ReportMoreUnsafeFunctions: true
|
||||
# CheckOptions:
|
||||
# readability-braces-around-statements.ShortStatementLines: 2
|
||||
# readability-identifier-naming.MacroDefinitionCase: UPPER_CASE
|
||||
# readability-identifier-naming.ClassCase: CamelCase
|
||||
# readability-identifier-naming.StructCase: CamelCase
|
||||
# readability-identifier-naming.UnionCase: CamelCase
|
||||
# readability-identifier-naming.EnumCase: CamelCase
|
||||
# readability-identifier-naming.EnumConstantCase: CamelCase
|
||||
# readability-identifier-naming.ScopedEnumConstantCase: CamelCase
|
||||
# readability-identifier-naming.GlobalConstantCase: UPPER_CASE
|
||||
# readability-identifier-naming.GlobalConstantPrefix: "k"
|
||||
# readability-identifier-naming.GlobalVariableCase: CamelCase
|
||||
# readability-identifier-naming.GlobalVariablePrefix: "g"
|
||||
# readability-identifier-naming.ConstexprFunctionCase: camelBack
|
||||
# readability-identifier-naming.ConstexprMethodCase: camelBack
|
||||
# readability-identifier-naming.ClassMethodCase: camelBack
|
||||
# readability-identifier-naming.ClassMemberCase: camelBack
|
||||
# readability-identifier-naming.ClassConstantCase: UPPER_CASE
|
||||
# readability-identifier-naming.ClassConstantPrefix: "k"
|
||||
# readability-identifier-naming.StaticConstantCase: UPPER_CASE
|
||||
# readability-identifier-naming.StaticConstantPrefix: "k"
|
||||
# readability-identifier-naming.StaticVariableCase: UPPER_CASE
|
||||
# readability-identifier-naming.StaticVariablePrefix: "k"
|
||||
# readability-identifier-naming.ConstexprVariableCase: UPPER_CASE
|
||||
# readability-identifier-naming.ConstexprVariablePrefix: "k"
|
||||
# readability-identifier-naming.LocalConstantCase: camelBack
|
||||
# readability-identifier-naming.LocalVariableCase: camelBack
|
||||
# readability-identifier-naming.TemplateParameterCase: CamelCase
|
||||
# readability-identifier-naming.ParameterCase: camelBack
|
||||
# readability-identifier-naming.FunctionCase: camelBack
|
||||
# readability-identifier-naming.MemberCase: camelBack
|
||||
# readability-identifier-naming.PrivateMemberSuffix: _
|
||||
# readability-identifier-naming.ProtectedMemberSuffix: _
|
||||
# readability-identifier-naming.PublicMemberSuffix: ""
|
||||
# readability-identifier-naming.FunctionIgnoredRegexp: ".*tag_invoke.*"
|
||||
# bugprone-unsafe-functions.ReportMoreUnsafeFunctions: true
|
||||
# bugprone-unused-return-value.CheckedReturnTypes: ::std::error_code;::std::error_condition;::std::errc
|
||||
# misc-include-cleaner.IgnoreHeaders: '.*/(detail|impl)/.*;.*(expected|unexpected).*;.*ranges_lower_bound\.h;time.h;stdlib.h;__chrono/.*;fmt/chrono.h;boost/uuid/uuid_hash.hpp'
|
||||
#
|
||||
|
||||
27
.github/workflows/reusable-build-test-config.yml
vendored
27
.github/workflows/reusable-build-test-config.yml
vendored
@@ -76,7 +76,7 @@ jobs:
|
||||
name: ${{ inputs.config_name }}
|
||||
runs-on: ${{ fromJSON(inputs.runs_on) }}
|
||||
container: ${{ inputs.image != '' && inputs.image || null }}
|
||||
timeout-minutes: ${{ inputs.sanitizers != '' && 360 || 60 }}
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
# Use a namespace to keep the objects separate for each configuration.
|
||||
CCACHE_NAMESPACE: ${{ inputs.config_name }}
|
||||
@@ -101,7 +101,7 @@ jobs:
|
||||
steps:
|
||||
- name: Cleanup workspace (macOS and Windows)
|
||||
if: ${{ runner.os == 'macOS' || runner.os == 'Windows' }}
|
||||
uses: XRPLF/actions/cleanup-workspace@c7d9ce5ebb03c752a354889ecd870cadfc2b1cd4
|
||||
uses: XRPLF/actions/cleanup-workspace@cf0433aa74563aead044a1e395610c96d65a37cf
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
@@ -204,14 +204,8 @@ jobs:
|
||||
|
||||
- name: Set sanitizer options
|
||||
if: ${{ !inputs.build_only && env.SANITIZERS_ENABLED == 'true' }}
|
||||
env:
|
||||
CONFIG_NAME: ${{ inputs.config_name }}
|
||||
run: |
|
||||
ASAN_OPTS="halt_on_error=0:use_sigaltstack=0:print_stacktrace=1:detect_container_overflow=0:detect_stack_use_after_return=0:suppressions=${GITHUB_WORKSPACE}/sanitizers/suppressions/asan.supp"
|
||||
if [[ "${CONFIG_NAME}" == *gcc* ]]; then
|
||||
ASAN_OPTS="${ASAN_OPTS}:alloc_dealloc_mismatch=0"
|
||||
fi
|
||||
echo "ASAN_OPTIONS=${ASAN_OPTS}" >> ${GITHUB_ENV}
|
||||
echo "ASAN_OPTIONS=print_stacktrace=1:detect_container_overflow=0:suppressions=${GITHUB_WORKSPACE}/sanitizers/suppressions/asan.supp" >> ${GITHUB_ENV}
|
||||
echo "TSAN_OPTIONS=second_deadlock_stack=1:halt_on_error=0:suppressions=${GITHUB_WORKSPACE}/sanitizers/suppressions/tsan.supp" >> ${GITHUB_ENV}
|
||||
echo "UBSAN_OPTIONS=suppressions=${GITHUB_WORKSPACE}/sanitizers/suppressions/ubsan.supp" >> ${GITHUB_ENV}
|
||||
echo "LSAN_OPTIONS=suppressions=${GITHUB_WORKSPACE}/sanitizers/suppressions/lsan.supp" >> ${GITHUB_ENV}
|
||||
@@ -235,21 +229,8 @@ jobs:
|
||||
env:
|
||||
BUILD_NPROC: ${{ steps.nproc.outputs.nproc }}
|
||||
run: |
|
||||
set -o pipefail
|
||||
./xrpld --unittest --unittest-jobs "${BUILD_NPROC}" 2>&1 | tee unittest.log
|
||||
./xrpld --unittest --unittest-jobs "${BUILD_NPROC}"
|
||||
|
||||
- name: Show test failure summary
|
||||
if: ${{ failure() && !inputs.build_only }}
|
||||
working-directory: ${{ runner.os == 'Windows' && format('{0}/{1}', env.BUILD_DIR, inputs.build_type) || env.BUILD_DIR }}
|
||||
run: |
|
||||
if [ ! -f unittest.log ]; then
|
||||
echo "unittest.log not found; embedded tests may not have run."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if ! grep -E "failed" unittest.log; then
|
||||
echo "Log present but no failure lines found in unittest.log."
|
||||
fi
|
||||
- name: Debug failure (Linux)
|
||||
if: ${{ failure() && runner.os == 'Linux' && !inputs.build_only }}
|
||||
run: |
|
||||
|
||||
@@ -78,9 +78,9 @@ jobs:
|
||||
id: run_clang_tidy
|
||||
continue-on-error: true
|
||||
env:
|
||||
TARGETS: ${{ inputs.files != '' && inputs.files || 'src tests' }}
|
||||
FILES: ${{ inputs.files }}
|
||||
run: |
|
||||
run-clang-tidy -j ${{ steps.nproc.outputs.nproc }} -p "${BUILD_DIR}" ${TARGETS} 2>&1 | tee clang-tidy-output.txt
|
||||
run-clang-tidy -j ${{ steps.nproc.outputs.nproc }} -p "$BUILD_DIR" $FILES 2>&1 | tee clang-tidy-output.txt
|
||||
|
||||
- name: Upload clang-tidy output
|
||||
if: steps.run_clang_tidy.outcome != 'success'
|
||||
|
||||
14
.github/workflows/reusable-clang-tidy.yml
vendored
14
.github/workflows/reusable-clang-tidy.yml
vendored
@@ -22,8 +22,7 @@ jobs:
|
||||
if: ${{ inputs.check_only_changed }}
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
clang_tidy_config_changed: ${{ steps.changed_clang_tidy.outputs.any_changed }}
|
||||
any_cpp_changed: ${{ steps.changed_files.outputs.any_changed }}
|
||||
any_changed: ${{ steps.changed_files.outputs.any_changed }}
|
||||
all_changed_files: ${{ steps.changed_files.outputs.all_changed_files }}
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
@@ -39,17 +38,10 @@ jobs:
|
||||
**/*.ipp
|
||||
separator: " "
|
||||
|
||||
- name: Get changed clang-tidy configuration
|
||||
id: changed_clang_tidy
|
||||
uses: tj-actions/changed-files@7dee1b0c1557f278e5c7dc244927139d78c0e22a # v47.0.4
|
||||
with:
|
||||
files: |
|
||||
.clang-tidy
|
||||
|
||||
run-clang-tidy:
|
||||
needs: [determine-files]
|
||||
if: ${{ always() && !cancelled() && (!inputs.check_only_changed || needs.determine-files.outputs.any_cpp_changed == 'true' || needs.determine-files.outputs.clang_tidy_config_changed == 'true') }}
|
||||
if: ${{ always() && !cancelled() && (!inputs.check_only_changed || needs.determine-files.outputs.any_changed == 'true') }}
|
||||
uses: ./.github/workflows/reusable-clang-tidy-files.yml
|
||||
with:
|
||||
files: ${{ (needs.determine-files.outputs.clang_tidy_config_changed == 'true' && '') || (inputs.check_only_changed && needs.determine-files.outputs.all_changed_files || '') }}
|
||||
files: ${{ inputs.check_only_changed && needs.determine-files.outputs.all_changed_files || '' }}
|
||||
create_issue_on_failure: ${{ inputs.create_issue_on_failure }}
|
||||
|
||||
2
.github/workflows/upload-conan-deps.yml
vendored
2
.github/workflows/upload-conan-deps.yml
vendored
@@ -64,7 +64,7 @@ jobs:
|
||||
steps:
|
||||
- name: Cleanup workspace (macOS and Windows)
|
||||
if: ${{ runner.os == 'macOS' || runner.os == 'Windows' }}
|
||||
uses: XRPLF/actions/cleanup-workspace@c7d9ce5ebb03c752a354889ecd870cadfc2b1cd4
|
||||
uses: XRPLF/actions/cleanup-workspace@cf0433aa74563aead044a1e395610c96d65a37cf
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
@@ -251,29 +251,6 @@ pip3 install pre-commit
|
||||
pre-commit install
|
||||
```
|
||||
|
||||
## Clang-tidy
|
||||
|
||||
All code must pass `clang-tidy` checks according to the settings in [`.clang-tidy`](./.clang-tidy).
|
||||
|
||||
There is a Continuous Integration job that runs clang-tidy on pull requests. The CI will check:
|
||||
|
||||
- All changed C++ files (`.cpp`, `.h`, `.ipp`) when only code files are modified
|
||||
- **All files in the repository** when the `.clang-tidy` configuration file is changed
|
||||
|
||||
This ensures that configuration changes don't introduce new warnings across the codebase.
|
||||
|
||||
### Running clang-tidy locally
|
||||
|
||||
Before running clang-tidy, you must build the project to generate required files (particularly protobuf headers). Refer to [`BUILD.md`](./BUILD.md) for build instructions.
|
||||
|
||||
Then run clang-tidy on your local changes:
|
||||
|
||||
```
|
||||
run-clang-tidy -p build src tests
|
||||
```
|
||||
|
||||
This will check all source files in the `src` and `tests` directories using the compile commands from your `build` directory.
|
||||
|
||||
## Contracts and instrumentation
|
||||
|
||||
We are using [Antithesis](https://antithesis.com/) for continuous fuzzing,
|
||||
|
||||
@@ -17,10 +17,12 @@ find_dependency(Boost
|
||||
chrono
|
||||
container
|
||||
context
|
||||
coroutine
|
||||
date_time
|
||||
filesystem
|
||||
program_options
|
||||
regex
|
||||
system
|
||||
thread)
|
||||
#[=========================================================[
|
||||
OpenSSL
|
||||
|
||||
@@ -22,7 +22,7 @@ target_compile_definitions(
|
||||
BOOST_FILESYSTEM_NO_DEPRECATED
|
||||
>
|
||||
$<$<NOT:$<BOOL:${boost_show_deprecated}>>:
|
||||
BOOST_COROUTINES2_NO_DEPRECATION_WARNING
|
||||
BOOST_COROUTINES_NO_DEPRECATION_WARNING
|
||||
BOOST_BEAST_ALLOW_DEPRECATED
|
||||
BOOST_FILESYSTEM_DEPRECATED
|
||||
>
|
||||
|
||||
@@ -4,12 +4,13 @@ include(XrplSanitizers)
|
||||
find_package(Boost REQUIRED
|
||||
COMPONENTS chrono
|
||||
container
|
||||
context
|
||||
coroutine
|
||||
date_time
|
||||
filesystem
|
||||
json
|
||||
program_options
|
||||
regex
|
||||
system
|
||||
thread)
|
||||
|
||||
add_library(xrpl_boost INTERFACE)
|
||||
@@ -20,7 +21,7 @@ target_link_libraries(
|
||||
INTERFACE Boost::headers
|
||||
Boost::chrono
|
||||
Boost::container
|
||||
Boost::context
|
||||
Boost::coroutine
|
||||
Boost::date_time
|
||||
Boost::filesystem
|
||||
Boost::json
|
||||
@@ -31,35 +32,14 @@ target_link_libraries(
|
||||
if (Boost_COMPILER)
|
||||
target_link_libraries(xrpl_boost INTERFACE Boost::disable_autolinking)
|
||||
endif ()
|
||||
|
||||
# GCC 14+ has a false positive -Wuninitialized warning in Boost.Coroutine2's
|
||||
# state.hpp when compiled with -O3. This is due to GCC's intentional behavior
|
||||
# change (Bug #98871, #119388) where warnings from inlined system header code
|
||||
# are no longer suppressed by -isystem. The warning occurs in operator|= in
|
||||
# boost/coroutine2/detail/state.hpp when inlined from push_control_block::destroy().
|
||||
# See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=119388
|
||||
if (is_gcc AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 14)
|
||||
target_compile_options(xrpl_boost INTERFACE -Wno-uninitialized)
|
||||
if (SANITIZERS_ENABLED AND is_clang)
|
||||
# TODO: gcc does not support -fsanitize-blacklist...can we do something else for gcc ?
|
||||
if (NOT Boost_INCLUDE_DIRS AND TARGET Boost::headers)
|
||||
get_target_property(Boost_INCLUDE_DIRS Boost::headers INTERFACE_INCLUDE_DIRECTORIES)
|
||||
endif ()
|
||||
message(STATUS "Adding [${Boost_INCLUDE_DIRS}] to sanitizer blacklist")
|
||||
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/san_bl.txt "src:${Boost_INCLUDE_DIRS}/*")
|
||||
target_compile_options(
|
||||
opts INTERFACE # ignore boost headers for sanitizing
|
||||
-fsanitize-blacklist=${CMAKE_CURRENT_BINARY_DIR}/san_bl.txt)
|
||||
endif ()
|
||||
|
||||
# Boost.Context's ucontext backend has ASAN fiber-switching annotations
|
||||
# (start/finish_switch_fiber) that are compiled in when BOOST_USE_ASAN is defined.
|
||||
# This tells ASAN about coroutine stack switches, preventing false positive
|
||||
# stack-use-after-scope errors. BOOST_USE_UCONTEXT ensures the ucontext backend
|
||||
# is selected (fcontext does not support ASAN annotations).
|
||||
# These defines must match what Boost was compiled with (see conan/profiles/sanitizers).
|
||||
if (enable_asan)
|
||||
target_compile_definitions(xrpl_boost INTERFACE BOOST_USE_ASAN BOOST_USE_UCONTEXT)
|
||||
endif ()
|
||||
|
||||
# if (SANITIZERS_ENABLED AND is_clang)
|
||||
# # TODO: gcc does not support -fsanitize-blacklist...can we do something else for gcc ?
|
||||
# if (NOT Boost_INCLUDE_DIRS AND TARGET Boost::headers)
|
||||
# get_target_property(Boost_INCLUDE_DIRS Boost::headers INTERFACE_INCLUDE_DIRECTORIES)
|
||||
# endif ()
|
||||
# message(STATUS "Adding [${Boost_INCLUDE_DIRS}] to sanitizer blacklist")
|
||||
# file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/san_bl.txt "src:${Boost_INCLUDE_DIRS}/*")
|
||||
# target_compile_options(
|
||||
# opts INTERFACE # ignore boost headers for sanitizing
|
||||
# -fsanitize-blacklist=${CMAKE_CURRENT_BINARY_DIR}/san_bl.txt)
|
||||
# endif ()
|
||||
|
||||
@@ -7,21 +7,16 @@ include(default)
|
||||
{% if compiler == "gcc" %}
|
||||
{% if "address" in sanitizers or "thread" in sanitizers or "undefinedbehavior" in sanitizers %}
|
||||
{% set sanitizer_list = [] %}
|
||||
{% set defines = [] %}
|
||||
{% set model_code = "" %}
|
||||
{% set extra_cxxflags = ["-fno-omit-frame-pointer", "-O1", "-Wno-stringop-overflow"] %}
|
||||
|
||||
{% if "address" in sanitizers %}
|
||||
{% set _ = sanitizer_list.append("address") %}
|
||||
{% set model_code = "-mcmodel=large" %}
|
||||
{% set _ = defines.append("BOOST_USE_ASAN")%}
|
||||
{% set _ = defines.append("BOOST_USE_UCONTEXT")%}
|
||||
{% elif "thread" in sanitizers %}
|
||||
{% set _ = sanitizer_list.append("thread") %}
|
||||
{% set model_code = "-mcmodel=medium" %}
|
||||
{% set _ = extra_cxxflags.append("-Wno-tsan") %}
|
||||
{% set _ = defines.append("BOOST_USE_TSAN")%}
|
||||
{% set _ = defines.append("BOOST_USE_UCONTEXT")%}
|
||||
{% endif %}
|
||||
|
||||
{% if "undefinedbehavior" in sanitizers %}
|
||||
@@ -34,22 +29,16 @@ include(default)
|
||||
tools.build:cxxflags+=['{{sanitizer_flags}} {{" ".join(extra_cxxflags)}}']
|
||||
tools.build:sharedlinkflags+=['{{sanitizer_flags}}']
|
||||
tools.build:exelinkflags+=['{{sanitizer_flags}}']
|
||||
tools.build:defines+={{defines}}
|
||||
{% endif %}
|
||||
{% elif compiler == "apple-clang" or compiler == "clang" %}
|
||||
{% if "address" in sanitizers or "thread" in sanitizers or "undefinedbehavior" in sanitizers %}
|
||||
{% set sanitizer_list = [] %}
|
||||
{% set defines = [] %}
|
||||
{% set extra_cxxflags = ["-fno-omit-frame-pointer", "-O1"] %}
|
||||
|
||||
{% if "address" in sanitizers %}
|
||||
{% set _ = sanitizer_list.append("address") %}
|
||||
{% set _ = defines.append("BOOST_USE_ASAN")%}
|
||||
{% set _ = defines.append("BOOST_USE_UCONTEXT")%}
|
||||
{% elif "thread" in sanitizers %}
|
||||
{% set _ = sanitizer_list.append("thread") %}
|
||||
{% set _ = defines.append("BOOST_USE_TSAN")%}
|
||||
{% set _ = defines.append("BOOST_USE_UCONTEXT")%}
|
||||
{% endif %}
|
||||
|
||||
{% if "undefinedbehavior" in sanitizers %}
|
||||
@@ -63,24 +52,8 @@ include(default)
|
||||
tools.build:cxxflags+=['{{sanitizer_flags}} {{" ".join(extra_cxxflags)}}']
|
||||
tools.build:sharedlinkflags+=['{{sanitizer_flags}}']
|
||||
tools.build:exelinkflags+=['{{sanitizer_flags}}']
|
||||
tools.build:defines+={{defines}}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
tools.info.package_id:confs+=["tools.build:cxxflags", "tools.build:exelinkflags", "tools.build:sharedlinkflags", "tools.build:defines"]
|
||||
|
||||
[options]
|
||||
{% if sanitizers %}
|
||||
{% if "address" in sanitizers %}
|
||||
# Build Boost.Context with ucontext backend (not fcontext) so that
|
||||
# ASAN fiber-switching annotations (__sanitizer_start/finish_switch_fiber)
|
||||
# are compiled into the library. fcontext (assembly) has no ASAN support.
|
||||
# define=BOOST_USE_ASAN=1 is critical: it must be defined when building
|
||||
# Boost.Context itself so the ucontext backend compiles in the ASAN annotations.
|
||||
boost/*:extra_b2_flags=context-impl=ucontext address-sanitizer=on define=BOOST_USE_ASAN=1
|
||||
boost/*:without_context=False
|
||||
# Boost stacktrace fails to build with some sanitizers
|
||||
boost/*:without_stacktrace=True
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
tools.info.package_id:confs+=["tools.build:cxxflags", "tools.build:exelinkflags", "tools.build:sharedlinkflags"]
|
||||
|
||||
15
conanfile.py
15
conanfile.py
@@ -1,5 +1,4 @@
|
||||
import re
|
||||
import os
|
||||
|
||||
from conan.tools.cmake import CMake, CMakeToolchain, cmake_layout
|
||||
|
||||
@@ -58,9 +57,6 @@ class Xrpl(ConanFile):
|
||||
"tests": False,
|
||||
"unity": False,
|
||||
"xrpld": False,
|
||||
"boost/*:without_context": False,
|
||||
"boost/*:without_coroutine": True,
|
||||
"boost/*:without_coroutine2": False,
|
||||
"date/*:header_only": True,
|
||||
"ed25519/*:shared": False,
|
||||
"grpc/*:shared": False,
|
||||
@@ -129,14 +125,6 @@ class Xrpl(ConanFile):
|
||||
self.options["boost"].visibility = "global"
|
||||
if self.settings.compiler in ["clang", "gcc"]:
|
||||
self.options["boost"].without_cobalt = True
|
||||
self.options["boost"].without_context = False
|
||||
self.options["boost"].without_coroutine = True
|
||||
self.options["boost"].without_coroutine2 = False
|
||||
# Check if environment variable exists
|
||||
if "SANITIZERS" in os.environ:
|
||||
sanitizers = os.environ["SANITIZERS"]
|
||||
if "address" in sanitizers.lower():
|
||||
self.default_options["fPIC"] = False
|
||||
|
||||
def requirements(self):
|
||||
# Conan 2 requires transitive headers to be specified
|
||||
@@ -208,8 +196,7 @@ class Xrpl(ConanFile):
|
||||
"boost::headers",
|
||||
"boost::chrono",
|
||||
"boost::container",
|
||||
"boost::context",
|
||||
"boost::coroutine2",
|
||||
"boost::coroutine",
|
||||
"boost::date_time",
|
||||
"boost::filesystem",
|
||||
"boost::json",
|
||||
|
||||
@@ -99,7 +99,6 @@ words:
|
||||
- endmacro
|
||||
- exceptioned
|
||||
- Falco
|
||||
- fcontext
|
||||
- finalizers
|
||||
- firewalled
|
||||
- fmtdur
|
||||
|
||||
139
include/xrpl/basics/CanProcess.h
Normal file
139
include/xrpl/basics/CanProcess.h
Normal file
@@ -0,0 +1,139 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2024 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_BASICS_CANPROCESS_H_INCLUDED
|
||||
#define RIPPLE_BASICS_CANPROCESS_H_INCLUDED
|
||||
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <set>
|
||||
|
||||
/** RAII class to check if an Item is already being processed on another thread,
|
||||
* as indicated by it's presence in a Collection.
|
||||
*
|
||||
* If the Item is not in the Collection, it will be added under lock in the
|
||||
* ctor, and removed under lock in the dtor. The object will be considered
|
||||
* "usable" and evaluate to `true`.
|
||||
*
|
||||
* If the Item is in the Collection, no changes will be made to the collection,
|
||||
* and the CanProcess object will be considered "unusable".
|
||||
*
|
||||
* It's up to the caller to decide what "usable" and "unusable" mean. (e.g.
|
||||
* Process or skip a block of code, or set a flag.)
|
||||
*
|
||||
* The current use is to avoid lock contention that would be involved in
|
||||
* processing something associated with the Item.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* void IncomingLedgers::acquireAsync(LedgerHash const& hash, ...)
|
||||
* {
|
||||
* if (CanProcess check{acquiresMutex_, pendingAcquires_, hash})
|
||||
* {
|
||||
* acquire(hash, ...);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* bool
|
||||
* NetworkOPsImp::recvValidation(
|
||||
* std::shared_ptr<STValidation> const& val,
|
||||
* std::string const& source)
|
||||
* {
|
||||
* CanProcess check(
|
||||
* validationsMutex_, pendingValidations_, val->getLedgerHash());
|
||||
* BypassAccept bypassAccept =
|
||||
* check ? BypassAccept::no : BypassAccept::yes;
|
||||
* handleNewValidation(app_, val, source, bypassAccept, m_journal);
|
||||
* }
|
||||
*
|
||||
*/
|
||||
class CanProcess
|
||||
{
|
||||
public:
|
||||
template <class Mutex, class Collection, class Item>
|
||||
CanProcess(Mutex& mtx, Collection& collection, Item const& item)
|
||||
: cleanup_(insert(mtx, collection, item))
|
||||
{
|
||||
}
|
||||
|
||||
~CanProcess()
|
||||
{
|
||||
if (cleanup_)
|
||||
cleanup_();
|
||||
}
|
||||
|
||||
CanProcess(CanProcess const&) = delete;
|
||||
|
||||
CanProcess&
|
||||
operator=(CanProcess const&) = delete;
|
||||
|
||||
explicit
|
||||
operator bool() const
|
||||
{
|
||||
return static_cast<bool>(cleanup_);
|
||||
}
|
||||
|
||||
private:
|
||||
template <bool useIterator, class Mutex, class Collection, class Item>
|
||||
std::function<void()>
|
||||
doInsert(Mutex& mtx, Collection& collection, Item const& item)
|
||||
{
|
||||
std::unique_lock<Mutex> lock(mtx);
|
||||
// TODO: Use structured binding once LLVM 16 is the minimum supported
|
||||
// version. See also: https://github.com/llvm/llvm-project/issues/48582
|
||||
// https://github.com/llvm/llvm-project/commit/127bf44385424891eb04cff8e52d3f157fc2cb7c
|
||||
auto const insertResult = collection.insert(item);
|
||||
auto const it = insertResult.first;
|
||||
if (!insertResult.second)
|
||||
return {};
|
||||
if constexpr (useIterator)
|
||||
return [&, it]() {
|
||||
std::unique_lock<Mutex> lock(mtx);
|
||||
collection.erase(it);
|
||||
};
|
||||
else
|
||||
return [&]() {
|
||||
std::unique_lock<Mutex> lock(mtx);
|
||||
collection.erase(item);
|
||||
};
|
||||
}
|
||||
|
||||
// Generic insert() function doesn't use iterators because they may get
|
||||
// invalidated
|
||||
template <class Mutex, class Collection, class Item>
|
||||
std::function<void()>
|
||||
insert(Mutex& mtx, Collection& collection, Item const& item)
|
||||
{
|
||||
return doInsert<false>(mtx, collection, item);
|
||||
}
|
||||
|
||||
// Specialize insert() for std::set, which does not invalidate iterators for
|
||||
// insert and erase
|
||||
template <class Mutex, class Item>
|
||||
std::function<void()>
|
||||
insert(Mutex& mtx, std::set<Item>& collection, Item const& item)
|
||||
{
|
||||
return doInsert<true>(mtx, collection, item);
|
||||
}
|
||||
|
||||
// If set, then the item is "usable"
|
||||
std::function<void()> cleanup_;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/basics/ByteUtilities.h>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
template <class F>
|
||||
@@ -9,18 +11,16 @@ JobQueue::Coro::Coro(Coro_create_t, JobQueue& jq, JobType type, std::string cons
|
||||
, name_(name)
|
||||
, running_(false)
|
||||
, coro_(
|
||||
// Stack size of 1MB wasn't sufficient for deep calls. ASAN tests flagged the issue. Hence
|
||||
// increasing the size to 1.5MB.
|
||||
boost::context::protected_fixedsize_stack(1536 * 1024),
|
||||
[this, fn = std::forward<F>(f)](
|
||||
boost::coroutines2::asymmetric_coroutine<void>::push_type& do_yield) {
|
||||
boost::coroutines::asymmetric_coroutine<void>::push_type& do_yield) {
|
||||
yield_ = &do_yield;
|
||||
yield();
|
||||
fn(shared_from_this());
|
||||
#ifndef NDEBUG
|
||||
finished_ = true;
|
||||
#endif
|
||||
})
|
||||
},
|
||||
boost::coroutines::attributes(megabytes(1)))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -199,7 +199,7 @@ public:
|
||||
|
||||
/** Add a suppression peer and get message's relay status.
|
||||
* Return pair:
|
||||
* element 1: true if the peer is added.
|
||||
* element 1: true if the key is added.
|
||||
* element 2: optional is seated to the relay time point or
|
||||
* is unseated if has not relayed yet. */
|
||||
std::pair<bool, std::optional<Stopwatch::time_point>>
|
||||
|
||||
@@ -7,8 +7,7 @@
|
||||
#include <xrpl/core/detail/Workers.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
|
||||
#include <boost/context/protected_fixedsize_stack.hpp>
|
||||
#include <boost/coroutine2/all.hpp>
|
||||
#include <boost/coroutine/all.hpp>
|
||||
|
||||
#include <set>
|
||||
|
||||
@@ -49,8 +48,8 @@ public:
|
||||
std::mutex mutex_;
|
||||
std::mutex mutex_run_;
|
||||
std::condition_variable cv_;
|
||||
boost::coroutines2::coroutine<void>::pull_type coro_;
|
||||
boost::coroutines2::coroutine<void>::push_type* yield_;
|
||||
boost::coroutines::asymmetric_coroutine<void>::pull_type coro_;
|
||||
boost::coroutines::asymmetric_coroutine<void>::push_type* yield_;
|
||||
#ifndef NDEBUG
|
||||
bool finished_ = false;
|
||||
#endif
|
||||
|
||||
@@ -77,16 +77,16 @@ public:
|
||||
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 key A pointer to the key data.
|
||||
@param pObject [out] The created object if successful.
|
||||
@return The result of the operation.
|
||||
*/
|
||||
virtual Status
|
||||
fetch(uint256 const& hash, std::shared_ptr<NodeObject>* pObject) = 0;
|
||||
fetch(void const* key, std::shared_ptr<NodeObject>* pObject) = 0;
|
||||
|
||||
/** Fetch a batch synchronously. */
|
||||
virtual std::pair<std::vector<std::shared_ptr<NodeObject>>, Status>
|
||||
fetchBatch(std::vector<uint256> const& hashes) = 0;
|
||||
fetchBatch(std::vector<uint256 const*> const& hashes) = 0;
|
||||
|
||||
/** Store a single object.
|
||||
Depending on the implementation this may happen immediately
|
||||
|
||||
@@ -35,6 +35,8 @@ struct LedgerHeader
|
||||
|
||||
// If validated is false, it means "not yet validated."
|
||||
// Once validated is true, it will never be set false at a later time.
|
||||
// NOTE: If you are accessing this directly, you are probably doing it
|
||||
// wrong. Use LedgerMaster::isValidated().
|
||||
// VFALCO TODO Make this not mutable
|
||||
bool mutable validated = false;
|
||||
bool accepted = false;
|
||||
|
||||
@@ -185,7 +185,7 @@ public:
|
||||
virtual bool
|
||||
isFull() = 0;
|
||||
virtual void
|
||||
setMode(OperatingMode om) = 0;
|
||||
setMode(OperatingMode om, char const* reason) = 0;
|
||||
virtual bool
|
||||
isBlocked() = 0;
|
||||
virtual bool
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||
# The idea is to empty this file gradually by fixing the underlying issues and removing suppressions.
|
||||
#
|
||||
# ASAN_OPTIONS="print_stacktrace=1:detect_container_overflow=0:suppressions=sanitizers/suppressions/asan.supp:halt_on_error=0"
|
||||
#
|
||||
# The detect_container_overflow=0 option disables false positives from:
|
||||
# - Boost intrusive containers (slist_iterator.hpp, hashtable.hpp, aged_unordered_container.h)
|
||||
# - Boost context/coroutine stack switching (Workers.cpp, thread.h)
|
||||
#
|
||||
# See: https://github.com/google/sanitizers/wiki/AddressSanitizerContainerOverflow
|
||||
|
||||
# Boost
|
||||
interceptor_name:boost/asio
|
||||
|
||||
# Leaks in Doctest tests: xrpl.test.*
|
||||
interceptor_name:src/libxrpl/net/HTTPClient.cpp
|
||||
@@ -12,25 +20,6 @@ interceptor_name:xrpl/net/HTTPClient.h
|
||||
interceptor_name:xrpl/net/HTTPClientSSLContext.h
|
||||
interceptor_name:xrpl/net/RegisterSSLCerts.h
|
||||
|
||||
# Boost.Context fiber/coroutine false positives
|
||||
# ASan doesn't fully support makecontext/swapcontext (see first warning in output)
|
||||
# The "attempting free on address which was not malloc()-ed" errors are false positives
|
||||
# caused by Boost.Context's fiber stack management.
|
||||
#
|
||||
# Suppress bad-free errors in Boost.Context fiber/coroutine stack deallocation
|
||||
# These are triggered when fiber stacks are deallocated but ASan doesn't recognize them
|
||||
# as having been allocated via malloc (because they use mmap via boost's stack allocator)
|
||||
# We ignore these files from intrumentation already on Clang, but on GCC, we need to suppress the issues.
|
||||
|
||||
#interceptor_via_fun:swapcontext
|
||||
#interceptor_via_fun:makecontext
|
||||
#interceptor_via_fun:boost::context::basic_fixedsize_stack*deallocate
|
||||
#interceptor_via_fun:boost::context::fiber::~fiber
|
||||
#interceptor_name:boost/context/fiber_ucontext.hpp
|
||||
#interceptor_name:boost/context/fixedsize_stack.hpp
|
||||
#interceptor_name:Coro.ipp
|
||||
|
||||
|
||||
# Suppress false positive stack-buffer errors in thread stack allocation
|
||||
# Related to ASan's __asan_handle_no_return warnings (github.com/google/sanitizers/issues/189)
|
||||
# These occur during multi-threaded test initialization on macOS
|
||||
|
||||
@@ -33,7 +33,7 @@ DatabaseNodeImp::fetchNodeObject(
|
||||
|
||||
try
|
||||
{
|
||||
status = backend_->fetch(hash, &nodeObject);
|
||||
status = backend_->fetch(hash.data(), &nodeObject);
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
@@ -68,10 +68,18 @@ DatabaseNodeImp::fetchBatch(std::vector<uint256> const& hashes)
|
||||
using namespace std::chrono;
|
||||
auto const before = steady_clock::now();
|
||||
|
||||
std::vector<uint256 const*> batch{};
|
||||
batch.reserve(hashes.size());
|
||||
for (size_t i = 0; i < hashes.size(); ++i)
|
||||
{
|
||||
auto const& hash = hashes[i];
|
||||
batch.push_back(&hash);
|
||||
}
|
||||
|
||||
// Get the node objects that match the hashes from the backend. To protect
|
||||
// against the backends returning fewer or more results than expected, the
|
||||
// container is resized to the number of hashes.
|
||||
auto results = backend_->fetchBatch(hashes).first;
|
||||
auto results = backend_->fetchBatch(batch).first;
|
||||
XRPL_ASSERT(
|
||||
results.size() == hashes.size() || results.empty(),
|
||||
"number of output objects either matches number of input hashes or is empty");
|
||||
|
||||
@@ -105,7 +105,7 @@ DatabaseRotatingImp::fetchNodeObject(
|
||||
std::shared_ptr<NodeObject> nodeObject;
|
||||
try
|
||||
{
|
||||
status = backend->fetch(hash, &nodeObject);
|
||||
status = backend->fetch(hash.data(), &nodeObject);
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
|
||||
@@ -116,9 +116,10 @@ public:
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
Status
|
||||
fetch(uint256 const& hash, std::shared_ptr<NodeObject>* pObject) override
|
||||
fetch(void const* key, std::shared_ptr<NodeObject>* pObject) override
|
||||
{
|
||||
XRPL_ASSERT(db_, "xrpl::NodeStore::MemoryBackend::fetch : non-null database");
|
||||
uint256 const hash(uint256::fromVoid(key));
|
||||
|
||||
std::lock_guard _(db_->mutex);
|
||||
|
||||
@@ -133,14 +134,14 @@ public:
|
||||
}
|
||||
|
||||
std::pair<std::vector<std::shared_ptr<NodeObject>>, Status>
|
||||
fetchBatch(std::vector<uint256> const& hashes) override
|
||||
fetchBatch(std::vector<uint256 const*> const& hashes) override
|
||||
{
|
||||
std::vector<std::shared_ptr<NodeObject>> results;
|
||||
results.reserve(hashes.size());
|
||||
for (auto const& h : hashes)
|
||||
{
|
||||
std::shared_ptr<NodeObject> nObj;
|
||||
Status status = fetch(h, &nObj);
|
||||
Status status = fetch(h->begin(), &nObj);
|
||||
if (status != ok)
|
||||
results.push_back({});
|
||||
else
|
||||
|
||||
@@ -179,17 +179,17 @@ public:
|
||||
}
|
||||
|
||||
Status
|
||||
fetch(uint256 const& hash, std::shared_ptr<NodeObject>* pno) override
|
||||
fetch(void const* key, std::shared_ptr<NodeObject>* pno) override
|
||||
{
|
||||
Status status;
|
||||
pno->reset();
|
||||
nudb::error_code ec;
|
||||
db_.fetch(
|
||||
hash.data(),
|
||||
[&hash, pno, &status](void const* data, std::size_t size) {
|
||||
key,
|
||||
[key, pno, &status](void const* data, std::size_t size) {
|
||||
nudb::detail::buffer bf;
|
||||
auto const result = nodeobject_decompress(data, size, bf);
|
||||
DecodedBlob decoded(hash.data(), result.first, result.second);
|
||||
DecodedBlob decoded(key, result.first, result.second);
|
||||
if (!decoded.wasOk())
|
||||
{
|
||||
status = dataCorrupt;
|
||||
@@ -207,14 +207,14 @@ public:
|
||||
}
|
||||
|
||||
std::pair<std::vector<std::shared_ptr<NodeObject>>, Status>
|
||||
fetchBatch(std::vector<uint256> const& hashes) override
|
||||
fetchBatch(std::vector<uint256 const*> const& hashes) override
|
||||
{
|
||||
std::vector<std::shared_ptr<NodeObject>> results;
|
||||
results.reserve(hashes.size());
|
||||
for (auto const& h : hashes)
|
||||
{
|
||||
std::shared_ptr<NodeObject> nObj;
|
||||
Status status = fetch(h, &nObj);
|
||||
Status status = fetch(h->begin(), &nObj);
|
||||
if (status != ok)
|
||||
results.push_back({});
|
||||
else
|
||||
|
||||
@@ -36,13 +36,13 @@ public:
|
||||
}
|
||||
|
||||
Status
|
||||
fetch(uint256 const&, std::shared_ptr<NodeObject>*) override
|
||||
fetch(void const*, std::shared_ptr<NodeObject>*) override
|
||||
{
|
||||
return notFound;
|
||||
}
|
||||
|
||||
std::pair<std::vector<std::shared_ptr<NodeObject>>, Status>
|
||||
fetchBatch(std::vector<uint256> const& hashes) override
|
||||
fetchBatch(std::vector<uint256 const*> const& hashes) override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -244,7 +244,7 @@ public:
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
Status
|
||||
fetch(uint256 const& hash, std::shared_ptr<NodeObject>* pObject) override
|
||||
fetch(void const* key, std::shared_ptr<NodeObject>* pObject) override
|
||||
{
|
||||
XRPL_ASSERT(m_db, "xrpl::NodeStore::RocksDBBackend::fetch : non-null database");
|
||||
pObject->reset();
|
||||
@@ -252,7 +252,7 @@ public:
|
||||
Status status(ok);
|
||||
|
||||
rocksdb::ReadOptions const options;
|
||||
rocksdb::Slice const slice(std::bit_cast<char const*>(hash.data()), m_keyBytes);
|
||||
rocksdb::Slice const slice(static_cast<char const*>(key), m_keyBytes);
|
||||
|
||||
std::string string;
|
||||
|
||||
@@ -260,7 +260,7 @@ public:
|
||||
|
||||
if (getStatus.ok())
|
||||
{
|
||||
DecodedBlob decoded(hash.data(), string.data(), string.size());
|
||||
DecodedBlob decoded(key, string.data(), string.size());
|
||||
|
||||
if (decoded.wasOk())
|
||||
{
|
||||
@@ -295,14 +295,14 @@ public:
|
||||
}
|
||||
|
||||
std::pair<std::vector<std::shared_ptr<NodeObject>>, Status>
|
||||
fetchBatch(std::vector<uint256> const& hashes) override
|
||||
fetchBatch(std::vector<uint256 const*> const& hashes) override
|
||||
{
|
||||
std::vector<std::shared_ptr<NodeObject>> results;
|
||||
results.reserve(hashes.size());
|
||||
for (auto const& h : hashes)
|
||||
{
|
||||
std::shared_ptr<NodeObject> nObj;
|
||||
Status status = fetch(h, &nObj);
|
||||
Status status = fetch(h->begin(), &nObj);
|
||||
if (status != ok)
|
||||
results.push_back({});
|
||||
else
|
||||
@@ -332,8 +332,9 @@ public:
|
||||
EncodedBlob encoded(e);
|
||||
|
||||
wb.Put(
|
||||
rocksdb::Slice(std::bit_cast<char const*>(encoded.getKey()), m_keyBytes),
|
||||
rocksdb::Slice(std::bit_cast<char const*>(encoded.getData()), encoded.getSize()));
|
||||
rocksdb::Slice(reinterpret_cast<char const*>(encoded.getKey()), m_keyBytes),
|
||||
rocksdb::Slice(
|
||||
reinterpret_cast<char const*>(encoded.getData()), encoded.getSize()));
|
||||
}
|
||||
|
||||
rocksdb::WriteOptions const options;
|
||||
|
||||
@@ -85,7 +85,12 @@ public:
|
||||
}
|
||||
|
||||
virtual void
|
||||
acquireAsync(uint256 const& hash, std::uint32_t seq, InboundLedger::Reason reason) override
|
||||
acquireAsync(
|
||||
JobType type,
|
||||
std::string const& name,
|
||||
uint256 const& hash,
|
||||
std::uint32_t seq,
|
||||
InboundLedger::Reason reason) override
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -5340,20 +5340,20 @@ class Vault_test : public beast::unit_test::suite
|
||||
env.close();
|
||||
|
||||
// 2. Mantissa larger than uint64 max
|
||||
env.set_parse_failure_expected(true);
|
||||
try
|
||||
{
|
||||
tx[sfAssetsMaximum] = "18446744073709551617e5"; // uint64 max + 1
|
||||
env(tx, THISLINE);
|
||||
BEAST_EXPECTS(false, "Expected parse_error for mantissa larger than uint64 max");
|
||||
BEAST_EXPECT(false);
|
||||
}
|
||||
catch (parse_error const& e)
|
||||
{
|
||||
using namespace std::string_literals;
|
||||
BEAST_EXPECT(
|
||||
e.what() == "invalidParamsField 'tx_json.AssetsMaximum' has invalid data."s);
|
||||
e.what() ==
|
||||
"invalidParamsField 'tx_json.AssetsMaximum' has invalid "
|
||||
"data."s);
|
||||
}
|
||||
env.set_parse_failure_expected(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
165
src/test/basics/CanProcess_test.cpp
Normal file
165
src/test/basics/CanProcess_test.cpp
Normal file
@@ -0,0 +1,165 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012-2016 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <xrpl/basics/CanProcess.h>
|
||||
#include <xrpl/beast/unit_test.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace ripple {
|
||||
namespace test {
|
||||
|
||||
struct CanProcess_test : beast::unit_test::suite
|
||||
{
|
||||
template <class Mutex, class Collection, class Item>
|
||||
void
|
||||
test(
|
||||
std::string const& name,
|
||||
Mutex& mtx,
|
||||
Collection& collection,
|
||||
std::vector<Item> const& items)
|
||||
{
|
||||
testcase(name);
|
||||
|
||||
if (!BEAST_EXPECT(!items.empty()))
|
||||
return;
|
||||
if (!BEAST_EXPECT(collection.empty()))
|
||||
return;
|
||||
|
||||
// CanProcess objects can't be copied or moved. To make that easier,
|
||||
// store shared_ptrs
|
||||
std::vector<std::shared_ptr<CanProcess>> trackers;
|
||||
// Fill up the vector with two CanProcess for each Item. The first
|
||||
// inserts the item into the collection and is "good". The second does
|
||||
// not and is "bad".
|
||||
for (int i = 0; i < items.size(); ++i)
|
||||
{
|
||||
{
|
||||
auto const& good =
|
||||
trackers.emplace_back(std::make_shared<CanProcess>(mtx, collection, items[i]));
|
||||
BEAST_EXPECT(*good);
|
||||
}
|
||||
BEAST_EXPECT(trackers.size() == (2 * i) + 1);
|
||||
BEAST_EXPECT(collection.size() == i + 1);
|
||||
{
|
||||
auto const& bad =
|
||||
trackers.emplace_back(std::make_shared<CanProcess>(mtx, collection, items[i]));
|
||||
BEAST_EXPECT(!*bad);
|
||||
}
|
||||
BEAST_EXPECT(trackers.size() == 2 * (i + 1));
|
||||
BEAST_EXPECT(collection.size() == i + 1);
|
||||
}
|
||||
BEAST_EXPECT(collection.size() == items.size());
|
||||
// Now remove the items from the vector<CanProcess> two at a time, and
|
||||
// try to get another CanProcess for that item.
|
||||
for (int i = 0; i < items.size(); ++i)
|
||||
{
|
||||
// Remove the "bad" one in the second position
|
||||
// This will have no effect on the collection
|
||||
{
|
||||
auto const iter = trackers.begin() + 1;
|
||||
BEAST_EXPECT(!**iter);
|
||||
trackers.erase(iter);
|
||||
}
|
||||
BEAST_EXPECT(trackers.size() == (2 * items.size()) - 1);
|
||||
BEAST_EXPECT(collection.size() == items.size());
|
||||
{
|
||||
// Append a new "bad" one
|
||||
auto const& bad =
|
||||
trackers.emplace_back(std::make_shared<CanProcess>(mtx, collection, items[i]));
|
||||
BEAST_EXPECT(!*bad);
|
||||
}
|
||||
BEAST_EXPECT(trackers.size() == 2 * items.size());
|
||||
BEAST_EXPECT(collection.size() == items.size());
|
||||
|
||||
// Remove the "good" one from the front
|
||||
{
|
||||
auto const iter = trackers.begin();
|
||||
BEAST_EXPECT(**iter);
|
||||
trackers.erase(iter);
|
||||
}
|
||||
BEAST_EXPECT(trackers.size() == (2 * items.size()) - 1);
|
||||
BEAST_EXPECT(collection.size() == items.size() - 1);
|
||||
{
|
||||
// Append a new "good" one
|
||||
auto const& good =
|
||||
trackers.emplace_back(std::make_shared<CanProcess>(mtx, collection, items[i]));
|
||||
BEAST_EXPECT(*good);
|
||||
}
|
||||
BEAST_EXPECT(trackers.size() == 2 * items.size());
|
||||
BEAST_EXPECT(collection.size() == items.size());
|
||||
}
|
||||
// Now remove them all two at a time
|
||||
for (int i = items.size() - 1; i >= 0; --i)
|
||||
{
|
||||
// Remove the "bad" one from the front
|
||||
{
|
||||
auto const iter = trackers.begin();
|
||||
BEAST_EXPECT(!**iter);
|
||||
trackers.erase(iter);
|
||||
}
|
||||
BEAST_EXPECT(trackers.size() == (2 * i) + 1);
|
||||
BEAST_EXPECT(collection.size() == i + 1);
|
||||
// Remove the "good" one now in front
|
||||
{
|
||||
auto const iter = trackers.begin();
|
||||
BEAST_EXPECT(**iter);
|
||||
trackers.erase(iter);
|
||||
}
|
||||
BEAST_EXPECT(trackers.size() == 2 * i);
|
||||
BEAST_EXPECT(collection.size() == i);
|
||||
}
|
||||
BEAST_EXPECT(trackers.empty());
|
||||
BEAST_EXPECT(collection.empty());
|
||||
}
|
||||
|
||||
void
|
||||
run() override
|
||||
{
|
||||
{
|
||||
std::mutex m;
|
||||
std::set<int> collection;
|
||||
std::vector<int> const items{1, 2, 3, 4, 5};
|
||||
test("set of int", m, collection, items);
|
||||
}
|
||||
{
|
||||
std::mutex m;
|
||||
std::set<std::string> collection;
|
||||
std::vector<std::string> const items{"one", "two", "three", "four", "five"};
|
||||
test("set of string", m, collection, items);
|
||||
}
|
||||
{
|
||||
std::mutex m;
|
||||
std::unordered_set<char> collection;
|
||||
std::vector<char> const items{'1', '2', '3', '4', '5'};
|
||||
test("unorderd_set of char", m, collection, items);
|
||||
}
|
||||
{
|
||||
std::mutex m;
|
||||
std::unordered_set<std::uint64_t> collection;
|
||||
std::vector<std::uint64_t> const items{100u, 1000u, 150u, 4u, 0u};
|
||||
test("unordered_set of uint64_t", m, collection, items);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(CanProcess, ripple_basics, ripple);
|
||||
|
||||
} // namespace test
|
||||
} // namespace ripple
|
||||
@@ -138,7 +138,7 @@ public:
|
||||
{
|
||||
std::shared_ptr<NodeObject> object;
|
||||
|
||||
Status const status = backend.fetch(batch[i]->getHash(), &object);
|
||||
Status const status = backend.fetch(batch[i]->getHash().cbegin(), &object);
|
||||
|
||||
BEAST_EXPECT(status == ok);
|
||||
|
||||
@@ -158,7 +158,7 @@ public:
|
||||
{
|
||||
std::shared_ptr<NodeObject> object;
|
||||
|
||||
Status const status = backend.fetch(batch[i]->getHash(), &object);
|
||||
Status const status = backend.fetch(batch[i]->getHash().cbegin(), &object);
|
||||
|
||||
BEAST_EXPECT(status == notFound);
|
||||
}
|
||||
|
||||
@@ -314,7 +314,7 @@ public:
|
||||
std::shared_ptr<NodeObject> obj;
|
||||
std::shared_ptr<NodeObject> result;
|
||||
obj = seq1_.obj(dist_(gen_));
|
||||
backend_.fetch(obj->getHash(), &result);
|
||||
backend_.fetch(obj->getHash().data(), &result);
|
||||
suite_.expect(result && isSame(result, obj));
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
@@ -377,9 +377,9 @@ public:
|
||||
{
|
||||
try
|
||||
{
|
||||
auto const hash = seq2_.key(i);
|
||||
auto const key = seq2_.key(i);
|
||||
std::shared_ptr<NodeObject> result;
|
||||
backend_.fetch(hash, &result);
|
||||
backend_.fetch(key.data(), &result);
|
||||
suite_.expect(!result);
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
@@ -449,9 +449,9 @@ public:
|
||||
{
|
||||
if (rand_(gen_) < missingNodePercent)
|
||||
{
|
||||
auto const hash = seq2_.key(dist_(gen_));
|
||||
auto const key = seq2_.key(dist_(gen_));
|
||||
std::shared_ptr<NodeObject> result;
|
||||
backend_.fetch(hash, &result);
|
||||
backend_.fetch(key.data(), &result);
|
||||
suite_.expect(!result);
|
||||
}
|
||||
else
|
||||
@@ -459,7 +459,7 @@ public:
|
||||
std::shared_ptr<NodeObject> obj;
|
||||
std::shared_ptr<NodeObject> result;
|
||||
obj = seq1_.obj(dist_(gen_));
|
||||
backend_.fetch(obj->getHash(), &result);
|
||||
backend_.fetch(obj->getHash().data(), &result);
|
||||
suite_.expect(result && isSame(result, obj));
|
||||
}
|
||||
}
|
||||
@@ -540,7 +540,8 @@ public:
|
||||
std::shared_ptr<NodeObject> result;
|
||||
auto const j = older_(gen_);
|
||||
obj = seq1_.obj(j);
|
||||
backend_.fetch(obj->getHash(), &result);
|
||||
std::shared_ptr<NodeObject> result1;
|
||||
backend_.fetch(obj->getHash().data(), &result);
|
||||
suite_.expect(result != nullptr);
|
||||
suite_.expect(isSame(result, obj));
|
||||
}
|
||||
@@ -558,7 +559,7 @@ public:
|
||||
std::shared_ptr<NodeObject> result;
|
||||
auto const j = recent_(gen_);
|
||||
obj = seq1_.obj(j);
|
||||
backend_.fetch(obj->getHash(), &result);
|
||||
backend_.fetch(obj->getHash().data(), &result);
|
||||
suite_.expect(!result || isSame(result, obj));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -107,10 +107,8 @@ RCLConsensus::Adaptor::acquireLedger(LedgerHash const& hash)
|
||||
// Tell the ledger acquire system that we need the consensus ledger
|
||||
acquiringLedger_ = hash;
|
||||
|
||||
app_.getJobQueue().addJob(jtADVANCE, "GetConsL1", [id = hash, &app = app_, this]() {
|
||||
JLOG(j_.debug()) << "JOB advanceLedger getConsensusLedger1 started";
|
||||
app.getInboundLedgers().acquireAsync(id, 0, InboundLedger::Reason::CONSENSUS);
|
||||
});
|
||||
app_.getInboundLedgers().acquireAsync(
|
||||
jtADVANCE, "GetConsL1", hash, 0, InboundLedger::Reason::CONSENSUS);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
@@ -985,7 +983,7 @@ void
|
||||
RCLConsensus::Adaptor::updateOperatingMode(std::size_t const positions) const
|
||||
{
|
||||
if (!positions && app_.getOPs().isFull())
|
||||
app_.getOPs().setMode(OperatingMode::CONNECTED);
|
||||
app_.getOPs().setMode(OperatingMode::CONNECTED, "updateOperatingMode: no positions");
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -117,12 +117,8 @@ RCLValidationsAdaptor::acquire(LedgerHash const& hash)
|
||||
{
|
||||
JLOG(j_.warn()) << "Need validated ledger for preferred ledger analysis " << hash;
|
||||
|
||||
Application* pApp = &app_;
|
||||
|
||||
app_.getJobQueue().addJob(jtADVANCE, "GetConsL2", [pApp, hash, this]() {
|
||||
JLOG(j_.debug()) << "JOB advanceLedger getConsensusLedger2 started";
|
||||
pApp->getInboundLedgers().acquireAsync(hash, 0, InboundLedger::Reason::CONSENSUS);
|
||||
});
|
||||
app_.getInboundLedgers().acquireAsync(
|
||||
jtADVANCE, "GetConsL2", hash, 0, InboundLedger::Reason::CONSENSUS);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,12 @@ public:
|
||||
// Queue. TODO review whether all callers of acquire() can use this
|
||||
// instead. Inbound ledger acquisition is asynchronous anyway.
|
||||
virtual void
|
||||
acquireAsync(uint256 const& hash, std::uint32_t seq, InboundLedger::Reason reason) = 0;
|
||||
acquireAsync(
|
||||
JobType type,
|
||||
std::string const& name,
|
||||
uint256 const& hash,
|
||||
std::uint32_t seq,
|
||||
InboundLedger::Reason reason) = 0;
|
||||
|
||||
virtual std::shared_ptr<InboundLedger>
|
||||
find(LedgerHash const& hash) = 0;
|
||||
|
||||
@@ -353,7 +353,14 @@ InboundLedger::onTimer(bool wasProgress, ScopedLockType&)
|
||||
|
||||
if (!wasProgress)
|
||||
{
|
||||
checkLocal();
|
||||
if (checkLocal())
|
||||
{
|
||||
// Done. Something else (probably consensus) built the ledger
|
||||
// locally while waiting for data (or possibly before requesting)
|
||||
XRPL_ASSERT(isDone(), "ripple::InboundLedger::onTimer : done");
|
||||
JLOG(journal_.info()) << "Finished while waiting " << hash_;
|
||||
return;
|
||||
}
|
||||
|
||||
mByHash = true;
|
||||
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
#include <xrpld/app/ledger/LedgerMaster.h>
|
||||
#include <xrpld/app/main/Application.h>
|
||||
|
||||
#include <xrpl/basics/CanProcess.h>
|
||||
#include <xrpl/basics/DecayingSample.h>
|
||||
#include <xrpl/basics/Log.h>
|
||||
#include <xrpl/basics/scope.h>
|
||||
#include <xrpl/beast/container/aged_map.h>
|
||||
#include <xrpl/core/JobQueue.h>
|
||||
#include <xrpl/core/PerfLog.h>
|
||||
@@ -59,12 +59,15 @@ public:
|
||||
(reason != InboundLedger::Reason::CONSENSUS))
|
||||
return {};
|
||||
|
||||
std::stringstream ss;
|
||||
|
||||
bool isNew = true;
|
||||
std::shared_ptr<InboundLedger> inbound;
|
||||
{
|
||||
ScopedLockType sl(mLock);
|
||||
if (stopping_)
|
||||
{
|
||||
JLOG(j_.debug()) << "Abort(stopping): " << ss.str();
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -83,47 +86,61 @@ public:
|
||||
++mCounter;
|
||||
}
|
||||
}
|
||||
ss << " IsNew: " << (isNew ? "true" : "false");
|
||||
|
||||
if (inbound->isFailed())
|
||||
{
|
||||
JLOG(j_.debug()) << "Abort(failed): " << ss.str();
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!isNew)
|
||||
inbound->update(seq);
|
||||
|
||||
if (!inbound->isComplete())
|
||||
{
|
||||
JLOG(j_.debug()) << "InProgress: " << ss.str();
|
||||
return {};
|
||||
}
|
||||
|
||||
JLOG(j_.debug()) << "Complete: " << ss.str();
|
||||
return inbound->getLedger();
|
||||
};
|
||||
using namespace std::chrono_literals;
|
||||
std::shared_ptr<Ledger const> ledger =
|
||||
perf::measureDurationAndLog(doAcquire, "InboundLedgersImp::acquire", 500ms, j_);
|
||||
|
||||
return ledger;
|
||||
return perf::measureDurationAndLog(doAcquire, "InboundLedgersImp::acquire", 500ms, j_);
|
||||
}
|
||||
|
||||
void
|
||||
acquireAsync(uint256 const& hash, std::uint32_t seq, InboundLedger::Reason reason) override
|
||||
acquireAsync(
|
||||
JobType type,
|
||||
std::string const& name,
|
||||
uint256 const& hash,
|
||||
std::uint32_t seq,
|
||||
InboundLedger::Reason reason) override
|
||||
{
|
||||
std::unique_lock lock(acquiresMutex_);
|
||||
try
|
||||
if (auto check = std::make_shared<CanProcess const>(acquiresMutex_, pendingAcquires_, hash);
|
||||
*check)
|
||||
{
|
||||
if (pendingAcquires_.contains(hash))
|
||||
return;
|
||||
pendingAcquires_.insert(hash);
|
||||
scope_unlock unlock(lock);
|
||||
acquire(hash, seq, reason);
|
||||
app_.getJobQueue().addJob(type, name, [check, name, hash, seq, reason, this]() {
|
||||
JLOG(j_.debug()) << "JOB acquireAsync " << name << " started ";
|
||||
try
|
||||
{
|
||||
acquire(hash, seq, reason);
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
JLOG(j_.warn()) << "Exception thrown for acquiring new "
|
||||
"inbound ledger "
|
||||
<< hash << ": " << e.what();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
JLOG(j_.warn()) << "Unknown exception thrown for acquiring new "
|
||||
"inbound ledger "
|
||||
<< hash;
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
JLOG(j_.warn()) << "Exception thrown for acquiring new inbound ledger " << hash << ": "
|
||||
<< e.what();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
JLOG(j_.warn()) << "Unknown exception thrown for acquiring new inbound ledger " << hash;
|
||||
}
|
||||
pendingAcquires_.erase(hash);
|
||||
}
|
||||
|
||||
std::shared_ptr<InboundLedger>
|
||||
|
||||
@@ -907,8 +907,9 @@ LedgerMaster::checkAccept(std::shared_ptr<Ledger const> const& ledger)
|
||||
return;
|
||||
}
|
||||
|
||||
JLOG(m_journal.info()) << "Advancing accepted ledger to " << ledger->header().seq
|
||||
<< " with >= " << minVal << " validations";
|
||||
JLOG(m_journal.info()) << "Advancing accepted ledger to " << ledger->header().seq << " ("
|
||||
<< to_short_string(ledger->header().hash) << ") with >= " << minVal
|
||||
<< " validations";
|
||||
|
||||
ledger->setValidated();
|
||||
ledger->setFull();
|
||||
|
||||
@@ -13,7 +13,8 @@ TimeoutCounter::TimeoutCounter(
|
||||
QueueJobParameter&& jobParameter,
|
||||
beast::Journal journal)
|
||||
: app_(app)
|
||||
, journal_(journal)
|
||||
, sink_(journal, to_short_string(hash) + " ")
|
||||
, journal_(sink_)
|
||||
, hash_(hash)
|
||||
, timeouts_(0)
|
||||
, complete_(false)
|
||||
@@ -33,6 +34,7 @@ TimeoutCounter::setTimer(ScopedLockType& sl)
|
||||
{
|
||||
if (isDone())
|
||||
return;
|
||||
JLOG(journal_.debug()) << "Setting timer for " << timerInterval_.count() << "ms";
|
||||
timer_.expires_after(timerInterval_);
|
||||
timer_.async_wait([wptr = pmDowncast()](boost::system::error_code const& ec) {
|
||||
if (ec == boost::asio::error::operation_aborted)
|
||||
@@ -40,6 +42,10 @@ TimeoutCounter::setTimer(ScopedLockType& sl)
|
||||
|
||||
if (auto ptr = wptr.lock())
|
||||
{
|
||||
JLOG(ptr->journal_.debug())
|
||||
<< "timer: ec: " << ec
|
||||
<< " (operation_aborted: " << boost::asio::error::operation_aborted << " - "
|
||||
<< (ec == boost::asio::error::operation_aborted ? "aborted" : "other") << ")";
|
||||
ScopedLockType sl(ptr->mtx_);
|
||||
ptr->queueJob(sl);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <xrpld/app/main/Application.h>
|
||||
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/beast/utility/WrappedSink.h>
|
||||
#include <xrpl/core/Job.h>
|
||||
|
||||
#include <boost/asio/basic_waitable_timer.hpp>
|
||||
@@ -103,6 +104,7 @@ protected:
|
||||
// Used in this class for access to boost::asio::io_context and
|
||||
// xrpl::Overlay. Used in subtypes for the kitchen sink.
|
||||
Application& app_;
|
||||
beast::WrappedSink sink_;
|
||||
beast::Journal journal_;
|
||||
mutable std::recursive_mutex mtx_;
|
||||
|
||||
|
||||
@@ -30,10 +30,10 @@
|
||||
#include <xrpld/rpc/MPTokenIssuanceID.h>
|
||||
#include <xrpld/rpc/ServerHandler.h>
|
||||
|
||||
#include <xrpl/basics/CanProcess.h>
|
||||
#include <xrpl/basics/UptimeClock.h>
|
||||
#include <xrpl/basics/mulDiv.h>
|
||||
#include <xrpl/basics/safe_cast.h>
|
||||
#include <xrpl/basics/scope.h>
|
||||
#include <xrpl/beast/utility/rngfill.h>
|
||||
#include <xrpl/core/HashRouter.h>
|
||||
#include <xrpl/core/NetworkIDService.h>
|
||||
@@ -396,7 +396,7 @@ public:
|
||||
isFull() override;
|
||||
|
||||
void
|
||||
setMode(OperatingMode om) override;
|
||||
setMode(OperatingMode om, char const* reason) override;
|
||||
|
||||
bool
|
||||
isBlocked() override;
|
||||
@@ -841,7 +841,7 @@ NetworkOPsImp::strOperatingMode(bool const admin /* = false */) const
|
||||
inline void
|
||||
NetworkOPsImp::setStandAlone()
|
||||
{
|
||||
setMode(OperatingMode::FULL);
|
||||
setMode(OperatingMode::FULL, "setStandAlone");
|
||||
}
|
||||
|
||||
inline void
|
||||
@@ -984,7 +984,7 @@ NetworkOPsImp::processHeartbeatTimer()
|
||||
{
|
||||
if (mMode != OperatingMode::DISCONNECTED)
|
||||
{
|
||||
setMode(OperatingMode::DISCONNECTED);
|
||||
setMode(OperatingMode::DISCONNECTED, "Heartbeat: insufficient peers");
|
||||
std::stringstream ss;
|
||||
ss << "Node count (" << numPeers << ") has fallen "
|
||||
<< "below required minimum (" << minPeerCount_ << ").";
|
||||
@@ -1008,7 +1008,7 @@ NetworkOPsImp::processHeartbeatTimer()
|
||||
|
||||
if (mMode == OperatingMode::DISCONNECTED)
|
||||
{
|
||||
setMode(OperatingMode::CONNECTED);
|
||||
setMode(OperatingMode::CONNECTED, "Heartbeat: sufficient peers");
|
||||
JLOG(m_journal.info()) << "Node count (" << numPeers << ") is sufficient.";
|
||||
CLOG(clog.ss()) << "setting mode to CONNECTED based on " << numPeers << " peers. ";
|
||||
}
|
||||
@@ -1018,9 +1018,9 @@ NetworkOPsImp::processHeartbeatTimer()
|
||||
auto origMode = mMode.load();
|
||||
CLOG(clog.ss()) << "mode: " << strOperatingMode(origMode, true);
|
||||
if (mMode == OperatingMode::SYNCING)
|
||||
setMode(OperatingMode::SYNCING);
|
||||
setMode(OperatingMode::SYNCING, "Heartbeat: check syncing");
|
||||
else if (mMode == OperatingMode::CONNECTED)
|
||||
setMode(OperatingMode::CONNECTED);
|
||||
setMode(OperatingMode::CONNECTED, "Heartbeat: check connected");
|
||||
auto newMode = mMode.load();
|
||||
if (origMode != newMode)
|
||||
{
|
||||
@@ -1710,7 +1710,7 @@ void
|
||||
NetworkOPsImp::setAmendmentBlocked()
|
||||
{
|
||||
amendmentBlocked_ = true;
|
||||
setMode(OperatingMode::CONNECTED);
|
||||
setMode(OperatingMode::CONNECTED, "setAmendmentBlocked");
|
||||
}
|
||||
|
||||
inline bool
|
||||
@@ -1741,7 +1741,7 @@ void
|
||||
NetworkOPsImp::setUNLBlocked()
|
||||
{
|
||||
unlBlocked_ = true;
|
||||
setMode(OperatingMode::CONNECTED);
|
||||
setMode(OperatingMode::CONNECTED, "setUNLBlocked");
|
||||
}
|
||||
|
||||
inline void
|
||||
@@ -1837,7 +1837,7 @@ NetworkOPsImp::checkLastClosedLedger(Overlay::PeerSequence const& peerList, uint
|
||||
|
||||
if ((mMode == OperatingMode::TRACKING) || (mMode == OperatingMode::FULL))
|
||||
{
|
||||
setMode(OperatingMode::CONNECTED);
|
||||
setMode(OperatingMode::CONNECTED, "check LCL: not on consensus ledger");
|
||||
}
|
||||
|
||||
if (consensus)
|
||||
@@ -1922,8 +1922,8 @@ NetworkOPsImp::beginConsensus(
|
||||
// this shouldn't happen unless we jump ledgers
|
||||
if (mMode == OperatingMode::FULL)
|
||||
{
|
||||
JLOG(m_journal.warn()) << "Don't have LCL, going to tracking";
|
||||
setMode(OperatingMode::TRACKING);
|
||||
JLOG(m_journal.warn()) << "beginConsensus Don't have LCL, going to tracking";
|
||||
setMode(OperatingMode::TRACKING, "beginConsensus: No LCL");
|
||||
CLOG(clog) << "beginConsensus Don't have LCL, going to tracking. ";
|
||||
}
|
||||
|
||||
@@ -2052,7 +2052,7 @@ NetworkOPsImp::endConsensus(std::unique_ptr<std::stringstream> const& clog)
|
||||
// validations we have for LCL. If the ledger is good enough, go to
|
||||
// TRACKING - TODO
|
||||
if (!needNetworkLedger_)
|
||||
setMode(OperatingMode::TRACKING);
|
||||
setMode(OperatingMode::TRACKING, "endConsensus: check tracking");
|
||||
}
|
||||
|
||||
if (((mMode == OperatingMode::CONNECTED) || (mMode == OperatingMode::TRACKING)) &&
|
||||
@@ -2065,7 +2065,7 @@ NetworkOPsImp::endConsensus(std::unique_ptr<std::stringstream> const& clog)
|
||||
if (registry_.timeKeeper().now() <
|
||||
(current->header().parentCloseTime + 2 * current->header().closeTimeResolution))
|
||||
{
|
||||
setMode(OperatingMode::FULL);
|
||||
setMode(OperatingMode::FULL, "endConsensus: check full");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2077,7 +2077,7 @@ NetworkOPsImp::consensusViewChange()
|
||||
{
|
||||
if ((mMode == OperatingMode::FULL) || (mMode == OperatingMode::TRACKING))
|
||||
{
|
||||
setMode(OperatingMode::CONNECTED);
|
||||
setMode(OperatingMode::CONNECTED, "consensusViewChange");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2379,7 +2379,7 @@ NetworkOPsImp::pubPeerStatus(std::function<Json::Value(void)> const& func)
|
||||
}
|
||||
|
||||
void
|
||||
NetworkOPsImp::setMode(OperatingMode om)
|
||||
NetworkOPsImp::setMode(OperatingMode om, char const* reason)
|
||||
{
|
||||
using namespace std::chrono_literals;
|
||||
if (om == OperatingMode::CONNECTED)
|
||||
@@ -2399,11 +2399,12 @@ NetworkOPsImp::setMode(OperatingMode om)
|
||||
if (mMode == om)
|
||||
return;
|
||||
|
||||
auto const sink = om < mMode ? m_journal.warn() : m_journal.info();
|
||||
mMode = om;
|
||||
|
||||
accounting_.mode(om);
|
||||
|
||||
JLOG(m_journal.info()) << "STATE->" << strOperatingMode();
|
||||
JLOG(sink) << "STATE->" << strOperatingMode() << " - " << reason;
|
||||
pubServer();
|
||||
}
|
||||
|
||||
@@ -2412,32 +2413,24 @@ NetworkOPsImp::recvValidation(std::shared_ptr<STValidation> const& val, std::str
|
||||
{
|
||||
JLOG(m_journal.trace()) << "recvValidation " << val->getLedgerHash() << " from " << source;
|
||||
|
||||
std::unique_lock lock(validationsMutex_);
|
||||
BypassAccept bypassAccept = BypassAccept::no;
|
||||
try
|
||||
{
|
||||
if (pendingValidations_.contains(val->getLedgerHash()))
|
||||
bypassAccept = BypassAccept::yes;
|
||||
else
|
||||
pendingValidations_.insert(val->getLedgerHash());
|
||||
scope_unlock unlock(lock);
|
||||
handleNewValidation(registry_.app(), val, source, bypassAccept, m_journal);
|
||||
CanProcess const check(validationsMutex_, pendingValidations_, val->getLedgerHash());
|
||||
try
|
||||
{
|
||||
BypassAccept bypassAccept = check ? BypassAccept::no : BypassAccept::yes;
|
||||
handleNewValidation(registry_.app(), val, source, bypassAccept, m_journal);
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
JLOG(m_journal.warn()) << "Exception thrown for handling new validation "
|
||||
<< val->getLedgerHash() << ": " << e.what();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
JLOG(m_journal.warn())
|
||||
<< "Unknown exception thrown for handling new validation " << val->getLedgerHash();
|
||||
}
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
JLOG(m_journal.warn()) << "Exception thrown for handling new validation "
|
||||
<< val->getLedgerHash() << ": " << e.what();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
JLOG(m_journal.warn()) << "Unknown exception thrown for handling new validation "
|
||||
<< val->getLedgerHash();
|
||||
}
|
||||
if (bypassAccept == BypassAccept::no)
|
||||
{
|
||||
pendingValidations_.erase(val->getLedgerHash());
|
||||
}
|
||||
lock.unlock();
|
||||
|
||||
pubValidation(val);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user