Compare commits

...

85 Commits

Author SHA1 Message Date
Bart
9922f214e9 Remove unreachable code 2026-06-08 15:20:06 -04:00
Bart
32bb0a6f72 Remove supported protocol features 2026-06-08 15:01:14 -04:00
Bart
d59efa6528 refactor: Remove support for protocol version 2.1 2026-06-08 14:52:06 -04:00
Ayaz Salikhov
a389f922dd ci: Use new packaging images and don't cancel develop builds (#7417)
Co-authored-by: Bart <bthomee@users.noreply.github.com>
2026-06-08 13:41:08 +00:00
dependabot[bot]
79f4ddc4a6 ci: [DEPENDABOT] bump codecov/codecov-action from 6.0.1 to 7.0.0 (#7426)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-08 09:37:50 +00:00
Ayaz Salikhov
949887feb9 build: Create single test binary xrpl_tests (#7327) 2026-06-05 19:24:32 +00:00
dependabot[bot]
fc57dab78b ci: [DEPENDABOT] bump actions/checkout from 6.0.2 to 6.0.3 (#7414)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-05 17:17:47 +00:00
Ayaz Salikhov
63ffdc39dc ci: Refactor build-related nix / docker / workflows (#7408) 2026-06-05 17:05:19 +00:00
Ayaz Salikhov
6571f75d39 ci: Use multiple directories in dependabot config (#7413) 2026-06-05 14:36:05 +00:00
Ayaz Salikhov
2111bb4b95 ci: Update clang-tidy to nix-based v22 (#7412) 2026-06-05 14:11:47 +00:00
Ayaz Salikhov
8abe82eefa ci: Redesign matrix configuration based on Nix images (#7385)
Co-authored-by: semgrep-companion-app[bot] <218312740+semgrep-companion-app[bot]@users.noreply.github.com>
2026-06-04 20:02:59 +00:00
Ayaz Salikhov
5b8e6cd1dd test: Fix LCOV_EXCL_END -> LCOV_EXCL_STOP (#7407) 2026-06-04 19:35:36 +00:00
Ayaz Salikhov
12e81abef3 ci: Improve sanitizer-libs, add doxygen, dpkg, rpm in nix (#7403) 2026-06-04 14:52:42 +00:00
Ayaz Salikhov
6c543426c3 ci: Fix clang asan include dirs in nix images, add curl & gnupg (#7400) 2026-06-03 22:19:15 +00:00
yinyiqian1
e5cf1a0985 fix: Add zero NFT Offer ID check for NFTokenCancelOffer (#7391) 2026-06-03 19:30:20 +00:00
Ayaz Salikhov
023bdaeeed ci: Install gcov, nettools, cacert in nix images (#7398) 2026-06-03 19:14:17 +00:00
Bart
96b2c0964f refactor: Replace intr_ptr::SharedPtr<SHAMapTreeNode> by SHAMapTreeNodePtr (#7396)
Co-authored-by: Bart <11445373+bthomee@users.noreply.github.com>
2026-06-03 15:34:19 +00:00
Ayaz Salikhov
1441d4690d chore: Update flake.lock to allow conan with clang-22 support (#7390) 2026-06-03 00:16:02 +00:00
Vito Tumas
225ed204ad test: Suppress invariant-failure logs in Vault and LoanBroker bug-regression tests (#7379) 2026-06-02 17:12:09 +00:00
Ayaz Salikhov
ad111bcc22 ci: Patch binaries in nix-based images and test in every distro (#7376)
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-02 13:51:20 +00:00
Ayaz Salikhov
d4cb68d5a1 ci: Check binaries separately from building them (#7355)
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-01 16:47:01 +00:00
dependabot[bot]
e209ee5371 ci: [DEPENDABOT] bump eps1lon/actions-label-merge-conflict from 3.0.3 to 3.1.0 (#7375)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-01 15:29:12 +00:00
Vito Tumas
109b649106 refactor: Use STLedgerEntry type aliases instead of std::shared_ptr (#7282) 2026-06-01 15:27:13 +00:00
Michael Legleux
0fffe23abc fix: Adjust xrpld systemd service and update timer (#7374) 2026-06-01 03:33:19 +00:00
Bart
7e15621e7b release: Bump version to 3.2.0-rc3 (#7371)
Co-authored-by: Bart <11445373+bthomee@users.noreply.github.com>
2026-05-31 22:55:18 +00:00
Vito Tumas
99431d7833 fix: Pin overpayment principal reduction to exact on-grid value (#7360) 2026-05-31 22:54:23 +00:00
Ed Hennis
47365f4220 fix: Improve upward rounding edge cases for Number::operator/= (#7328)
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Vito Tumas <5780819+Tapanito@users.noreply.github.com>
2026-05-31 00:23:29 +00:00
Bart
1599c1a672 refactor: Revert "perf: Remove unnecessary caches (#5439)" (#7359)
Co-authored-by: Bart <11445373+bthomee@users.noreply.github.com>
2026-05-30 18:48:59 +00:00
yinyiqian1
763dd503be fix: Add zero domainID check for permissionedDomain (#7362) 2026-05-30 00:16:25 +00:00
Bart
2f3558c610 ci: Run PR title and description checks on staging and release branches (#7331)
Co-authored-by: Bart <11445373+bthomee@users.noreply.github.com>
2026-05-28 14:57:29 +00:00
Ayaz Salikhov
f9551ac5ca style: Run shfmt on workflows, actions and markdown bash code (#7333) 2026-05-27 19:24:18 +00:00
Bart
1acc42313c release: Bump version to 3.2.0-rc2 (#7348) 2026-05-27 15:11:38 -04:00
Bart
396d772a15 refactor: Enable support for fixCleanup3_2_0 amendment (#7347) 2026-05-27 19:10:33 +00:00
Ayaz Salikhov
1438bf1c67 release: Bump version to 3.2.0-rc1 (#7335) 2026-05-27 13:20:57 -04:00
Ed Hennis
7da643d864 fix: Fix a rounding error at the Number::maxRep cusp (#7051)
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Vito Tumas <5780819+Tapanito@users.noreply.github.com>
2026-05-27 15:19:20 +00:00
Ayaz Salikhov
1162371def ci: Only push docker images in XRPLF/rippled (#7330) 2026-05-26 20:03:04 +00:00
dependabot[bot]
2a0feca46b ci: [DEPENDABOT] bump docker/setup-buildx-action from 4.0.0 to 4.1.0 (#7322)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-26 19:36:32 +00:00
dependabot[bot]
108a4c8217 ci: [DEPENDABOT] bump codecov/codecov-action from 6.0.0 to 6.0.1 (#7321)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-26 19:36:21 +00:00
dependabot[bot]
4584b01bde ci: [DEPENDABOT] bump docker/build-push-action from 7.1.0 to 7.2.0 (#7320)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-26 19:36:13 +00:00
dependabot[bot]
7c59786565 ci: [DEPENDABOT] bump docker/metadata-action from 6.0.0 to 6.1.0 (#7319)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-26 19:36:00 +00:00
dependabot[bot]
9623e67b76 ci: [DEPENDABOT] bump docker/login-action from 4.1.0 to 4.2.0 (#7318)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-26 19:35:52 +00:00
Andrzej Budzanowski
85af406a0f fix: Update clang-tidy to include src/tests directory header check (#7307) 2026-05-26 19:35:32 +00:00
Ayaz Salikhov
ac33fb32a7 chore: Pin Python packages for codegen using uv (#7329) 2026-05-26 18:35:38 +00:00
Ayaz Salikhov
23d0812827 style: Use shfmt instead of bashate (#7326) 2026-05-26 18:28:23 +00:00
Vito Tumas
49567e7283 fix: Fix edge-case where vault-depositor may get stuck (#7139) 2026-05-26 18:18:40 +00:00
Vito Tumas
633ef4706f fix: Fix VaultInvariant and VaultDeposit precision bugs at IOU scale boundaries (#7272)
Co-authored-by: Bart <bthomee@users.noreply.github.com>
2026-05-26 16:32:44 +00:00
Ayaz Salikhov
49cb3f45a4 ci: Add clang to nix images (#7308)
Co-authored-by: semgrep-companion-app[bot] <218312740+semgrep-companion-app[bot]@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-05-26 15:45:33 +00:00
Vito Tumas
22a21b175e fix: Include management-fee delta in doOverpayment assertion (#7039) 2026-05-26 14:01:52 +00:00
Pratik Mankawde
e9d885bd9b fix: Fix clang-tidy pre-commit hook to locate compile_commands.json from repo root (#7325)
Signed-off-by: Pratik Mankawde <3397372+pratikmankawde@users.noreply.github.com>
2026-05-26 13:50:18 +00:00
Jingchen
a911f9089e fix: Use consistent scale for debtTotal (#7093)
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-05-24 20:44:29 +00:00
Peter Chen
e34c2667d7 fix: Skip deleted book directories and non-root modifications in ValidBookDirectory invariant (#7312) 2026-05-24 20:37:16 +00:00
Valentin Balaschenko
30de556224 fix: Address review feedback on FD/handle guarding (#5823 follow-up) (#7310) 2026-05-23 14:48:48 +00:00
Gregory Tsipenyuk
dcd2ff0b5f fix: Fix non-canonical MPT amount (#7117)
Co-authored-by: xrplf-ai-reviewer[bot] <266832837+xrplf-ai-reviewer[bot]@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-05-23 06:40:26 +00:00
Bart
dfb9b8ed9a release: Bump version to 3.2.0-b7 (#7316)
Co-authored-by: Bart <11445373+bthomee@users.noreply.github.com>
2026-05-22 19:32:12 +00:00
Jingchen
179e73594a fix: Check if the MPT first loss cover can be sent to the broker before deleting the broker (#7125)
Co-authored-by: xrplf-ai-reviewer[bot] <266832837+xrplf-ai-reviewer[bot]@users.noreply.github.com>
2026-05-22 11:58:48 +00:00
Michael Legleux
15dd653e4b fix: Fix RPM prerelease ordering and start xrpld on DEB install (#7313) 2026-05-22 11:30:45 +00:00
Michael Legleux
a37afe13ff ci: Re-enable full nproc for Linux (#7315) 2026-05-22 11:30:37 +00:00
Gregory Tsipenyuk
3547a9335f fix: Add assorted MPT/DEX fixes (#7040)
Co-authored-by: xrplf-ai-reviewer[bot] <266832837+xrplf-ai-reviewer[bot]@users.noreply.github.com>
Co-authored-by: Shawn Xie <35279399+shawnxie999@users.noreply.github.com>
2026-05-21 18:29:53 +00:00
Bart
1a98182e23 refactor: Remove dead fetchBatch code (#7309)
Co-authored-by: Bart <11445373+bthomee@users.noreply.github.com>
2026-05-21 17:52:41 +00:00
Bart
79308705c5 release: Bump version to 3.2.0-b6 (#7311)
Co-authored-by: Bart <11445373+bthomee@users.noreply.github.com>
2026-05-21 17:50:59 +00:00
Vito Tumas
e24de65f42 chore: Revert graceful peer disconnection and follow-up fix (#7296) 2026-05-21 16:13:41 +00:00
Vito Tumas
7fdaa0a5ef fix: Fix IOU precision issues in LoanBrokerCover transactions (#7274) 2026-05-21 14:51:58 +00:00
Vito Tumas
795dc5e364 fix: Avoid principal-zeroing in non-final loan payments at coarse scale (#7050)
Co-authored-by: Ed Hennis <ed@ripple.com>
2026-05-21 14:46:26 +00:00
Pratik Mankawde
f6fd5ddb0a fix: Add null check (#7305)
Signed-off-by: Pratik Mankawde <3397372+pratikmankawde@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-21 13:24:04 +00:00
Rithvik Reddygari
afcf6fbcdc docs: Add --parallel flag to cmake build commands in BUILD.md (#7302) 2026-05-21 06:33:19 +00:00
Shawn Xie
28cc20c816 fix: Fix wrong hybrid offer orderbook placement and update LedgerStateFix to amend ExchangeRate meta (#7087)
Co-authored-by: Peter Chen <ychen@ripple.com>
2026-05-21 06:19:04 +00:00
Alex Kremer
a830ab10ef style: More clang-tidy identifier renaming (#7290) 2026-05-20 21:31:15 +00:00
Shawn Xie
8c0080020f fix: Update pDEX invariant firing under a valid offer deletion (#7118)
Co-authored-by: Peter Chen <ychen@ripple.com>
2026-05-20 21:10:04 +00:00
yinyiqian1
9cb0740673 fix: Fix multisign and signfor to check for delegate (#7064) 2026-05-20 20:24:09 +00:00
Mayukha Vadari
242ce3e9e4 refactor: Fix sfGeneric and sfInvalid field names (#7300) 2026-05-20 19:47:59 +00:00
box4wangjing
a5d238e7d4 docs: Fix some comments to improve readability (#7122)
Signed-off-by: box4wangjing <box4wangjing@outlook.com>
Co-authored-by: Mayukha Vadari <mvadari@ripple.com>
2026-05-20 19:46:45 +00:00
Vito Tumas
9cb049276d feat: Propagate underlying MPT flags to vault shares (#7077)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Denis Angell <dangell@transia.co>
Co-authored-by: Fomo <508629+shortthefomo@users.noreply.github.com>
Co-authored-by: Bart <bthomee@users.noreply.github.com>
Co-authored-by: Ayaz Salikhov <mathbunnyru@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-20 19:44:09 +00:00
Vito Tumas
93ac1aa7aa fix: Disable unnecessary sanity-check in VaultDeposit (#7288) 2026-05-19 16:38:50 +00:00
dependabot[bot]
d9a3af8207 ci: [DEPENDABOT] bump actions/upload-artifact from 7.0.0 to 7.0.1 (#7286)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-19 16:35:38 +00:00
Ayaz Salikhov
8d1083e5ea ci: Only run reusable package in public repos (#7293) 2026-05-19 13:15:11 +00:00
Fomo
1e45d363c5 fix: Set default peering port to 2459 (#6848)
Co-authored-by: Bart <bthomee@users.noreply.github.com>
2026-05-19 06:05:47 +00:00
Denis Angell
ad3d172a1f fix: Use account ledger entry when canceling token escrows (#6171) 2026-05-18 20:08:48 +00:00
Mayukha Vadari
ad7232cbc5 refactor: Rename account_ to accountID_ (#7284) 2026-05-18 10:56:54 +00:00
Michael Legleux
93836f22db ci: Add Linux package builds (DEB + RPM) to CI (#6639) 2026-05-16 05:08:37 +00:00
Mayukha Vadari
c7ecfc6a97 refactor: Clean up comments post-clang-tidy changes (#7283) 2026-05-15 23:02:04 +00:00
Ed Hennis
6809690fad release: Set version to 3.3.0-b0 (#7280)
Co-authored-by: Bart <bthomee@users.noreply.github.com>
2026-05-15 18:04:49 +00:00
Alex Kremer
5b6e8b6f93 refactor: Rename static constants (#7120)
Co-authored-by: Bart <bthomee@users.noreply.github.com>
2026-05-15 15:32:19 +00:00
Mayukha Vadari
028f0cb5da refactor: Use isFlag where possible instead of bitwise math (#7278) 2026-05-15 14:00:13 +00:00
Ayaz Salikhov
15b3ed1ae7 ci: Update XRPLF/actions (#7281) 2026-05-15 11:21:29 +00:00
Jingchen
cce4cfef10 feat: Add verify_endpoints to help local peer network development (#7268)
Co-authored-by: xrplf-ai-reviewer[bot] <266832837+xrplf-ai-reviewer[bot]@users.noreply.github.com>
2026-05-14 17:07:08 +00:00
941 changed files with 25096 additions and 14854 deletions

View File

@@ -154,7 +154,7 @@ Checks: "-*,
" "
# --- # ---
# readability-inconsistent-declaration-parameter-name, # in this codebase this check will break a lot of arg names # readability-inconsistent-declaration-parameter-name, # in this codebase this check will break a lot of arg names
# readability-static-accessed-through-instance, # this check is probably unnecessary. it makes the code less readable # readability-static-accessed-through-instance, # this check is probably unnecessary. It makes the code less readable
# --- # ---
CheckOptions: CheckOptions:
@@ -171,7 +171,7 @@ CheckOptions:
readability-identifier-naming.EnumCase: CamelCase readability-identifier-naming.EnumCase: CamelCase
readability-identifier-naming.EnumConstantCase: CamelCase readability-identifier-naming.EnumConstantCase: CamelCase
readability-identifier-naming.ScopedEnumConstantCase: CamelCase readability-identifier-naming.ScopedEnumConstantCase: CamelCase
readability-identifier-naming.GlobalConstantCase: UPPER_CASE readability-identifier-naming.GlobalConstantCase: CamelCase
readability-identifier-naming.GlobalConstantPrefix: "k" readability-identifier-naming.GlobalConstantPrefix: "k"
readability-identifier-naming.GlobalVariableCase: CamelCase readability-identifier-naming.GlobalVariableCase: CamelCase
readability-identifier-naming.GlobalVariablePrefix: "g" readability-identifier-naming.GlobalVariablePrefix: "g"
@@ -179,25 +179,26 @@ CheckOptions:
readability-identifier-naming.ConstexprMethodCase: camelBack readability-identifier-naming.ConstexprMethodCase: camelBack
readability-identifier-naming.ClassMethodCase: camelBack readability-identifier-naming.ClassMethodCase: camelBack
readability-identifier-naming.ClassMemberCase: camelBack readability-identifier-naming.ClassMemberCase: camelBack
readability-identifier-naming.ClassConstantCase: UPPER_CASE readability-identifier-naming.ClassConstantCase: CamelCase
readability-identifier-naming.ClassConstantPrefix: "k" readability-identifier-naming.ClassConstantPrefix: "k"
readability-identifier-naming.StaticConstantCase: UPPER_CASE readability-identifier-naming.StaticConstantCase: CamelCase
readability-identifier-naming.StaticConstantPrefix: "k" readability-identifier-naming.StaticConstantPrefix: "k"
readability-identifier-naming.StaticVariableCase: UPPER_CASE readability-identifier-naming.StaticVariableCase: camelBack
readability-identifier-naming.StaticVariablePrefix: "k" readability-identifier-naming.ConstexprVariableCase: camelBack
readability-identifier-naming.ConstexprVariableCase: UPPER_CASE
readability-identifier-naming.ConstexprVariablePrefix: "k"
readability-identifier-naming.LocalConstantCase: camelBack readability-identifier-naming.LocalConstantCase: camelBack
readability-identifier-naming.LocalVariableCase: camelBack readability-identifier-naming.LocalVariableCase: camelBack
readability-identifier-naming.TemplateParameterCase: CamelCase readability-identifier-naming.TemplateParameterCase: CamelCase
readability-identifier-naming.ParameterCase: camelBack readability-identifier-naming.ParameterCase: camelBack
readability-identifier-naming.FunctionCase: camelBack readability-identifier-naming.FunctionCase: camelBack
readability-identifier-naming.MemberCase: camelBack readability-identifier-naming.MemberCase: camelBack
readability-identifier-naming.PrivateMemberCase: camelBack
readability-identifier-naming.PrivateMemberSuffix: _ readability-identifier-naming.PrivateMemberSuffix: _
readability-identifier-naming.ProtectedMemberCase: camelBack
readability-identifier-naming.ProtectedMemberSuffix: _ readability-identifier-naming.ProtectedMemberSuffix: _
readability-identifier-naming.PublicMemberCase: camelBack
readability-identifier-naming.PublicMemberSuffix: "" readability-identifier-naming.PublicMemberSuffix: ""
readability-identifier-naming.GlobalFunctionIgnoredRegexp: "^(to_string|hash_append|tuple_hash)$" readability-identifier-naming.GlobalFunctionIgnoredRegexp: "^(to_string|hash_append|tuple_hash)$"
HeaderFilterRegex: '^.*/(test|xrpl|xrpld)/.*\.(h|hpp|ipp)$' HeaderFilterRegex: '^.*/(tests?|xrpl|xrpld)/.*\.(h|hpp|ipp)$'
ExcludeHeaderFilterRegex: '^.*/protocol_autogen/.*\.(h|hpp)$' ExcludeHeaderFilterRegex: '^.*/protocol_autogen/.*\.(h|hpp)$'
WarningsAsErrors: "*" WarningsAsErrors: "*"

View File

@@ -11,9 +11,6 @@ endfunction()
function(create_symbolic_link target link) function(create_symbolic_link target link)
endfunction() endfunction()
function(xrpl_add_test name)
endfunction()
macro(exclude_from_default target_) macro(exclude_from_default target_)
endmacro() endmacro()

View File

@@ -35,14 +35,13 @@ runs:
LOG_VERBOSITY: ${{ inputs.log_verbosity }} LOG_VERBOSITY: ${{ inputs.log_verbosity }}
SANITIZERS: ${{ inputs.sanitizers }} SANITIZERS: ${{ inputs.sanitizers }}
run: | run: |
echo 'Installing dependencies.'
conan install \ conan install \
--profile ci \ --profile:all ci \
--build="${BUILD_OPTION}" \ --build="${BUILD_OPTION}" \
--options:host='&:tests=True' \ --options:host='&:tests=True' \
--options:host='&:xrpld=True' \ --options:host='&:xrpld=True' \
--settings:all build_type="${BUILD_TYPE}" \ --settings:all build_type="${BUILD_TYPE}" \
--conf:all tools.build:jobs=${BUILD_NPROC} \ --conf:all tools.build:jobs=${BUILD_NPROC} \
--conf:all tools.build:verbosity="${LOG_VERBOSITY}" \ --conf:all tools.build:verbosity="${LOG_VERBOSITY}" \
--conf:all tools.compilation:verbosity="${LOG_VERBOSITY}" \ --conf:all tools.compilation:verbosity="${LOG_VERBOSITY}" \
. .

View File

@@ -15,7 +15,7 @@ runs:
shell: bash shell: bash
env: env:
VERSION: ${{ github.ref_name }} VERSION: ${{ github.ref_name }}
run: echo "VERSION=${VERSION}" >> "${GITHUB_ENV}" run: echo "VERSION=${VERSION}" >>"${GITHUB_ENV}"
# When a tag is not pushed, then the version (e.g. 1.2.3-b0) is extracted # When a tag is not pushed, then the version (e.g. 1.2.3-b0) is extracted
# from the BuildInfo.cpp file and the shortened commit hash appended to it. # from the BuildInfo.cpp file and the shortened commit hash appended to it.
@@ -28,17 +28,17 @@ runs:
echo 'Extracting version from BuildInfo.cpp.' echo 'Extracting version from BuildInfo.cpp.'
VERSION="$(cat src/libxrpl/protocol/BuildInfo.cpp | grep "versionString =" | awk -F '"' '{print $2}')" VERSION="$(cat src/libxrpl/protocol/BuildInfo.cpp | grep "versionString =" | awk -F '"' '{print $2}')"
if [[ -z "${VERSION}" ]]; then if [[ -z "${VERSION}" ]]; then
echo 'Unable to extract version from BuildInfo.cpp.' echo 'Unable to extract version from BuildInfo.cpp.'
exit 1 exit 1
fi fi
echo 'Appending shortened commit hash to version.' echo 'Appending shortened commit hash to version.'
SHA='${{ github.sha }}' SHA='${{ github.sha }}'
VERSION="${VERSION}+${SHA:0:7}" VERSION="${VERSION}+${SHA:0:7}"
echo "VERSION=${VERSION}" >> "${GITHUB_ENV}" echo "VERSION=${VERSION}" >>"${GITHUB_ENV}"
- name: Output version - name: Output version
id: version id: version
shell: bash shell: bash
run: echo "version=${VERSION}" >> "${GITHUB_OUTPUT}" run: echo "version=${VERSION}" >>"${GITHUB_OUTPUT}"

View File

@@ -0,0 +1,34 @@
name: Set compiler environment
description: "Set CC and CXX environment variables for the given compiler."
inputs:
compiler:
description: 'The compiler to use ("gcc" or "clang").'
required: true
runs:
using: composite
steps:
- name: Set CC and CXX for gcc
if: ${{ inputs.compiler == 'gcc' }}
shell: bash
run: |
echo "CC=gcc" >>"${GITHUB_ENV}"
echo "CXX=g++" >>"${GITHUB_ENV}"
- name: Set CC and CXX for clang
if: ${{ inputs.compiler == 'clang' }}
shell: bash
run: |
echo "CC=clang" >>"${GITHUB_ENV}"
echo "CXX=clang++" >>"${GITHUB_ENV}"
- name: Fail on unknown compiler
if: ${{ inputs.compiler != 'gcc' && inputs.compiler != 'clang' }}
shell: bash
env:
COMPILER: ${{ inputs.compiler }}
run: |
echo "Unknown compiler: $COMPILER" >&2
exit 1

View File

@@ -15,32 +15,35 @@ runs:
using: composite using: composite
steps: steps:
- name: Set up Conan configuration - name: Apply custom configuration to global.conf
shell: bash shell: bash
run: | run: |
echo 'Installing configuration.'
cat conan/global.conf ${{ runner.os == 'Linux' && '>>' || '>' }} $(conan config home)/global.conf cat conan/global.conf ${{ runner.os == 'Linux' && '>>' || '>' }} $(conan config home)/global.conf
echo 'Conan configuration:' - name: Show global configuration
conan config show '*' shell: bash
run: |
- name: Set up Conan profile conan config show '*'
- name: Install profiles
shell: bash shell: bash
run: | run: |
echo 'Installing profile.'
conan config install conan/profiles/ -tf $(conan config home)/profiles/ conan config install conan/profiles/ -tf $(conan config home)/profiles/
echo 'Conan profile:' - name: Show CI profile
shell: bash
run: |
conan profile show --profile ci conan profile show --profile ci
- name: Set up Conan remote - name: Add a remote
shell: bash shell: bash
env: env:
REMOTE_NAME: ${{ inputs.remote_name }} REMOTE_NAME: ${{ inputs.remote_name }}
REMOTE_URL: ${{ inputs.remote_url }} REMOTE_URL: ${{ inputs.remote_url }}
run: | run: |
echo "Adding Conan remote '${REMOTE_NAME}' at '${REMOTE_URL}'."
conan remote add --index 0 --force "${REMOTE_NAME}" "${REMOTE_URL}" conan remote add --index 0 --force "${REMOTE_NAME}" "${REMOTE_URL}"
echo 'Listing Conan remotes.' - name: List remotes
shell: bash
run: |
conan remote list conan remote list

View File

@@ -1,40 +1,12 @@
version: 2 version: 2
updates: updates:
- package-ecosystem: github-actions - package-ecosystem: github-actions
directory: / directories:
schedule: - /
interval: weekly - .github/actions/build-deps/
day: monday - .github/actions/generate-version/
time: "04:00" - .github/actions/set-compiler-env/
timezone: Etc/GMT - .github/actions/setup-conan/
commit-message:
prefix: "ci: [DEPENDABOT] "
target-branch: develop
- package-ecosystem: github-actions
directory: .github/actions/build-deps/
schedule:
interval: weekly
day: monday
time: "04:00"
timezone: Etc/GMT
commit-message:
prefix: "ci: [DEPENDABOT] "
target-branch: develop
- package-ecosystem: github-actions
directory: .github/actions/generate-version/
schedule:
interval: weekly
day: monday
time: "04:00"
timezone: Etc/GMT
commit-message:
prefix: "ci: [DEPENDABOT] "
target-branch: develop
- package-ecosystem: github-actions
directory: .github/actions/setup-conan/
schedule: schedule:
interval: weekly interval: weekly
day: monday day: monday

403
.github/scripts/format-inline-bash.py vendored Executable file
View File

@@ -0,0 +1,403 @@
#!/usr/bin/env python3
"""
Format embedded shell snippets using the shfmt hook configured in
.pre-commit-config.yaml.
Two shapes are recognised:
* YAML workflow/action files: literal block-scalar runs (`run: |`) and
single-line runs (`run: some command`). A single-line run is upgraded to
a `run: |` block scalar if shfmt's output spans multiple lines.
* Markdown files: ``` ```bash ``` fenced code blocks.
Any block that shfmt cannot parse is skipped with a warning on stderr, so
the file is left untouched and surrounding blocks still get formatted.
For each occurrence the body is dedented, written to a temp .sh file,
formatted via `pre-commit run shfmt --files <temp>` (falling back to
`prek`), then re-indented and written back in place.
When invoked without arguments, every .yml/.yaml under .github/ plus every
.md file in the repo is scanned. When invoked with file arguments (the
pre-commit case), only those files are processed.
"""
from __future__ import annotations
import re
import shutil
import subprocess
import sys
import tempfile
from dataclasses import dataclass
from pathlib import Path
from typing import Union
REPO = Path(__file__).resolve().parents[2]
_HOOK_RUNNER = next((cmd for cmd in ("pre-commit", "prek") if shutil.which(cmd)), None)
if _HOOK_RUNNER is None:
sys.exit("error: neither `pre-commit` nor `prek` found on PATH")
RUN_BLOCK_RE = re.compile(r"^(?P<prefix>[ \t]*(?:- )?)run:[ \t]*\|[+-]?[ \t]*$")
RUN_INLINE_RE = re.compile(
r"^(?P<prefix>[ \t]*(?:- )?)run:[ \t]+" r"(?P<value>(?!\|[+-]?[ \t]*$)\S.*?)[ \t]*$"
)
MD_BASH_OPEN_RE = re.compile(r"^(?P<indent>[ ]{0,3})`{3}bash[ \t]*$")
MD_FENCE_CLOSE_RE = re.compile(r"^[ ]{0,3}`{3,}[ \t]*$")
@dataclass(frozen=True)
class BlockRun:
"""A `run: |` block scalar; `body_start:body_end` slices into `lines`."""
body_start: int
body_end: int
body_indent: int
@dataclass(frozen=True)
class InlineRun:
"""A single-line `run: value` at `line_idx`."""
line_idx: int
prefix: str
value: str
@dataclass(frozen=True)
class MdBashBlock:
"""A markdown ``` ```bash ``` fenced code block.
`body_start:body_end` slices into the file's lines; `open_line_idx`
points at the opening fence line.
"""
open_line_idx: int
body_start: int
body_end: int
body_indent: int
RunItem = Union[BlockRun, InlineRun]
def _scan_block_body(
lines: list[str], body_start: int, run_col: int
) -> tuple[int | None, int]:
"""Locate the body of a `run: |` block scalar starting at `body_start`.
Returns `(body_indent, scan_end)`. `scan_end` is the line index where the
outer scanner should resume. `body_indent` is `None` when no body is
present (the scalar is empty, or the next non-blank line has indent
`<= run_col`).
"""
body_indent: int | None = None
scan_end = len(lines)
for idx in range(body_start, len(lines)):
line = lines[idx]
if line.strip() == "":
continue
indent = len(line) - len(line.lstrip(" "))
if body_indent is None:
if indent > run_col:
body_indent = indent
else:
scan_end = idx
break
elif indent < body_indent:
scan_end = idx
break
if body_indent is not None:
while scan_end > body_start and lines[scan_end - 1].strip() == "":
scan_end -= 1
if scan_end <= body_start:
body_indent = None
return body_indent, scan_end
def find_run_blocks(lines: list[str]) -> list[RunItem]:
"""Return run items in document order."""
items: list[RunItem] = []
line_idx = 0
while line_idx < len(lines):
line = lines[line_idx]
if block_match := RUN_BLOCK_RE.match(line):
run_col = len(block_match.group("prefix"))
body_start = line_idx + 1
body_indent, scan_end = _scan_block_body(lines, body_start, run_col)
if body_indent is not None:
items.append(
BlockRun(
body_start=body_start,
body_end=scan_end,
body_indent=body_indent,
)
)
line_idx = scan_end
continue
if inline_match := RUN_INLINE_RE.match(line):
items.append(
InlineRun(
line_idx=line_idx,
prefix=inline_match.group("prefix"),
value=inline_match.group("value"),
)
)
line_idx += 1
return items
def find_md_bash_blocks(lines: list[str]) -> list[MdBashBlock]:
"""Return ``` ```bash ``` fenced code blocks in document order."""
blocks: list[MdBashBlock] = []
line_idx = 0
while line_idx < len(lines):
open_match = MD_BASH_OPEN_RE.match(lines[line_idx])
if not open_match:
line_idx += 1
continue
body_start = line_idx + 1
close_idx = next(
(
j
for j in range(body_start, len(lines))
if MD_FENCE_CLOSE_RE.match(lines[j])
),
None,
)
if close_idx is None:
line_idx = body_start
continue
body = lines[body_start:close_idx]
non_blank = [b for b in body if b.strip()]
body_indent = (
min(len(b) - len(b.lstrip(" ")) for b in non_blank)
if non_blank
else len(open_match.group("indent"))
)
blocks.append(
MdBashBlock(
open_line_idx=line_idx,
body_start=body_start,
body_end=close_idx,
body_indent=body_indent,
)
)
line_idx = close_idx + 1
return blocks
def dedent(lines: list[str], n: int) -> list[str]:
pad = " " * n
return [
(
""
if line.strip() == ""
else (line[n:] if line.startswith(pad) else line.lstrip(" "))
)
for line in lines
]
def reindent(lines: list[str], n: int) -> list[str]:
pad = " " * n
return [pad + line if line else "" for line in lines]
_SHFMT_ERR_RE = re.compile(r"\.sh:\d+:\d+:\s")
_GHA_EXPR_RE = re.compile(r"\$\{\{.*?\}\}", re.DOTALL)
_GHA_PLACEHOLDER_RE = re.compile(r"__GHA_EXPR_(\d+)__")
def _encode_gha_exprs(text: str) -> tuple[str, list[str]]:
"""Replace `${{ ... }}` expressions with bash-safe placeholder identifiers."""
exprs: list[str] = []
def repl(match: re.Match[str]) -> str:
exprs.append(match.group(0))
return f"__GHA_EXPR_{len(exprs) - 1}__"
return _GHA_EXPR_RE.sub(repl, text), exprs
def _decode_gha_exprs(text: str, exprs: list[str]) -> str:
"""Restore `${{ ... }}` expressions from placeholder identifiers."""
return _GHA_PLACEHOLDER_RE.sub(lambda m: exprs[int(m.group(1))], text)
def shfmt_via_hook(tmp_path: Path) -> tuple[bool, str]:
# `${{ ... }}` is not valid shell, so swap it for a placeholder identifier
# that shfmt can parse, then restore it after formatting.
encoded, exprs = _encode_gha_exprs(tmp_path.read_text())
if exprs:
tmp_path.write_text(encoded)
res = subprocess.run(
[_HOOK_RUNNER, "run", "shfmt", "--files", str(tmp_path)],
cwd=REPO,
capture_output=True,
text=True,
)
output = res.stdout + res.stderr
# shfmt emits parse errors as "<path>:<line>:<col>: <message>".
parse_err = bool(_SHFMT_ERR_RE.search(output))
# A non-zero exit that is neither a parse error nor pre-commit's "I had
# to modify files" signal means the hook itself failed to run (missing
# binary, install failure, bad config, ...). Surface that loudly rather
# than silently treating it as a no-op.
if (
res.returncode != 0
and not parse_err
and "files were modified by this hook" not in output
):
sys.exit(
f"error: `{_HOOK_RUNNER} run shfmt` failed with exit {res.returncode}:\n{output}"
)
if exprs and not parse_err:
tmp_path.write_text(_decode_gha_exprs(tmp_path.read_text(), exprs))
return not parse_err, output
def _skip(path: Path, where: int, kind: str, output: str) -> None:
print(
f" shfmt could not parse {kind} at {path}:{where + 1} — skipped",
file=sys.stderr,
)
print(f" {output.strip()}", file=sys.stderr)
def process_yaml_file(path: Path, tmp_path: Path) -> int:
text = path.read_text()
had_nl = text.endswith("\n")
lines = text.split("\n")
if had_nl:
lines = lines[:-1]
items = find_run_blocks(lines)
if not items:
return 0
changed = 0
# Process in reverse so earlier indices remain valid as we splice.
for item in reversed(items):
if isinstance(item, BlockRun):
body = lines[item.body_start : item.body_end]
tmp_path.write_text("\n".join(dedent(body, item.body_indent)) + "\n")
ok, output = shfmt_via_hook(tmp_path)
if not ok:
_skip(path, item.body_start, "block", output)
continue
formatted = tmp_path.read_text().rstrip("\n")
new_body = reindent(formatted.split("\n"), item.body_indent)
if new_body != body:
lines[item.body_start : item.body_end] = new_body
changed += 1
else:
tmp_path.write_text(item.value + "\n")
ok, output = shfmt_via_hook(tmp_path)
if not ok:
_skip(path, item.line_idx, "inline run", output)
continue
formatted = tmp_path.read_text().rstrip("\n")
if formatted == item.value:
continue
formatted_lines = formatted.split("\n")
if len(formatted_lines) == 1:
lines[item.line_idx] = f"{item.prefix}run: {formatted}"
else:
body_indent = len(item.prefix) + 2
lines[item.line_idx : item.line_idx + 1] = [
f"{item.prefix}run: |",
*reindent(formatted_lines, body_indent),
]
changed += 1
new_text = "\n".join(lines) + ("\n" if had_nl else "")
if new_text != text:
path.write_text(new_text)
return changed
def process_md_file(path: Path, tmp_path: Path) -> int:
text = path.read_text()
had_nl = text.endswith("\n")
lines = text.split("\n")
if had_nl:
lines = lines[:-1]
blocks = find_md_bash_blocks(lines)
if not blocks:
return 0
changed = 0
for block in reversed(blocks):
body = lines[block.body_start : block.body_end]
tmp_path.write_text("\n".join(dedent(body, block.body_indent)) + "\n")
ok, output = shfmt_via_hook(tmp_path)
if not ok:
_skip(path, block.open_line_idx, "```bash block", output)
continue
formatted = tmp_path.read_text().rstrip("\n")
formatted_lines = formatted.split("\n") if formatted else []
new_body = reindent(formatted_lines, block.body_indent)
if new_body != body:
lines[block.body_start : block.body_end] = new_body
changed += 1
new_text = "\n".join(lines) + ("\n" if had_nl else "")
if new_text != text:
path.write_text(new_text)
return changed
def process_file(path: Path, tmp_path: Path) -> int:
if path.suffix in (".yml", ".yaml"):
return process_yaml_file(path, tmp_path)
if path.suffix == ".md":
return process_md_file(path, tmp_path)
return 0
def gather_files(argv: list[str]) -> list[Path]:
"""Return YAML workflow/action files and markdown files that we should
process — either the paths in `argv` or, when `argv` is empty, every
such file in the repo (skipping `external/`)."""
if argv:
candidates: list[Path] = [
(REPO / a).resolve() if not Path(a).is_absolute() else Path(a) for a in argv
]
else:
gh = REPO / ".github"
candidates = [
*gh.rglob("*.yml"),
*gh.rglob("*.yaml"),
*(
p
for p in REPO.rglob("*.md")
if "external" not in p.relative_to(REPO).parts
),
]
return sorted(
p
for p in candidates
if p.exists()
and (
(p.suffix in (".yml", ".yaml") and ".github" in p.parts)
or p.suffix == ".md"
)
)
def main(argv: list[str]) -> int:
files = gather_files(argv)
if not files:
return 0
with tempfile.TemporaryDirectory(prefix="format-inline-bash-") as tmpdir:
tmp_path = Path(tmpdir) / "shfmt.sh"
total = 0
for f in files:
n = process_file(f, tmp_path)
if n:
print(f"{f.relative_to(REPO)}: reformatted {n} block(s)")
total += n
return 1 if total else 0
if __name__ == "__main__":
sys.exit(main(sys.argv[1:]))

0
.github/scripts/levelization/generate.py vendored Normal file → Executable file
View File

View File

@@ -6,7 +6,7 @@ set -e
# On MacOS, ensure that GNU sed is installed and available as `gsed`. # On MacOS, ensure that GNU sed is installed and available as `gsed`.
SED_COMMAND=sed SED_COMMAND=sed
if [[ "${OSTYPE}" == 'darwin'* ]]; then if [[ "${OSTYPE}" == 'darwin'* ]]; then
if ! command -v gsed &> /dev/null; then if ! command -v gsed &>/dev/null; then
echo "Error: gsed is not installed. Please install it using 'brew install gnu-sed'." echo "Error: gsed is not installed. Please install it using 'brew install gnu-sed'."
exit 1 exit 1
fi fi

View File

@@ -8,12 +8,12 @@ set -e
SED_COMMAND=sed SED_COMMAND=sed
HEAD_COMMAND=head HEAD_COMMAND=head
if [[ "${OSTYPE}" == 'darwin'* ]]; then if [[ "${OSTYPE}" == 'darwin'* ]]; then
if ! command -v gsed &> /dev/null; then if ! command -v gsed &>/dev/null; then
echo "Error: gsed is not installed. Please install it using 'brew install gnu-sed'." echo "Error: gsed is not installed. Please install it using 'brew install gnu-sed'."
exit 1 exit 1
fi fi
SED_COMMAND=gsed SED_COMMAND=gsed
if ! command -v ghead &> /dev/null; then if ! command -v ghead &>/dev/null; then
echo "Error: ghead is not installed. Please install it using 'brew install coreutils'." echo "Error: ghead is not installed. Please install it using 'brew install coreutils'."
exit 1 exit 1
fi fi
@@ -43,9 +43,6 @@ pushd "${DIRECTORY}"
# Rename the files. # Rename the files.
find cmake -type f -name 'Rippled*.cmake' -exec bash -c 'mv "${1}" "${1/Rippled/Xrpl}"' - {} \; find cmake -type f -name 'Rippled*.cmake' -exec bash -c 'mv "${1}" "${1/Rippled/Xrpl}"' - {} \;
find cmake -type f -name 'Ripple*.cmake' -exec bash -c 'mv "${1}" "${1/Ripple/Xrpl}"' - {} \; find cmake -type f -name 'Ripple*.cmake' -exec bash -c 'mv "${1}" "${1/Ripple/Xrpl}"' - {} \;
if [ -e cmake/xrpl_add_test.cmake ]; then
mv cmake/xrpl_add_test.cmake cmake/XrplAddTest.cmake
fi
if [ -e include/xrpl/proto/ripple.proto ]; then if [ -e include/xrpl/proto/ripple.proto ]; then
mv include/xrpl/proto/ripple.proto include/xrpl/proto/xrpl.proto mv include/xrpl/proto/ripple.proto include/xrpl/proto/xrpl.proto
fi fi
@@ -60,7 +57,6 @@ find cmake -type f -name '*.cmake' | while read -r FILE; do
done done
${SED_COMMAND} -i -E 's/Rippled?/Xrpl/g' CMakeLists.txt ${SED_COMMAND} -i -E 's/Rippled?/Xrpl/g' CMakeLists.txt
${SED_COMMAND} -i 's/ripple/xrpl/g' CMakeLists.txt ${SED_COMMAND} -i 's/ripple/xrpl/g' CMakeLists.txt
${SED_COMMAND} -i 's/include(xrpl_add_test)/include(XrplAddTest)/' src/tests/libxrpl/CMakeLists.txt
${SED_COMMAND} -i 's/ripple.pb.h/xrpl.pb.h/' include/xrpl/protocol/messages.h ${SED_COMMAND} -i 's/ripple.pb.h/xrpl.pb.h/' include/xrpl/protocol/messages.h
${SED_COMMAND} -i 's/ripple.pb.h/xrpl.pb.h/' BUILD.md ${SED_COMMAND} -i 's/ripple.pb.h/xrpl.pb.h/' BUILD.md
${SED_COMMAND} -i 's/ripple.pb.h/xrpl.pb.h/' BUILD.md ${SED_COMMAND} -i 's/ripple.pb.h/xrpl.pb.h/' BUILD.md
@@ -74,10 +70,10 @@ if grep -q '"xrpld"' cmake/XrplCore.cmake; then
# The script has been rerun, so just restore the name of the binary. # The script has been rerun, so just restore the name of the binary.
${SED_COMMAND} -i 's/"xrpld"/"rippled"/' cmake/XrplCore.cmake ${SED_COMMAND} -i 's/"xrpld"/"rippled"/' cmake/XrplCore.cmake
elif ! grep -q '"rippled"' cmake/XrplCore.cmake; then elif ! grep -q '"rippled"' cmake/XrplCore.cmake; then
${HEAD_COMMAND} -n -1 cmake/XrplCore.cmake > cmake.tmp ${HEAD_COMMAND} -n -1 cmake/XrplCore.cmake >cmake.tmp
echo ' # For the time being, we will keep the name of the binary as it was.' >> cmake.tmp echo ' # For the time being, we will keep the name of the binary as it was.' >>cmake.tmp
echo ' set_target_properties(xrpld PROPERTIES OUTPUT_NAME "rippled")' >> cmake.tmp echo ' set_target_properties(xrpld PROPERTIES OUTPUT_NAME "rippled")' >>cmake.tmp
tail -1 cmake/XrplCore.cmake >> cmake.tmp tail -1 cmake/XrplCore.cmake >>cmake.tmp
mv cmake.tmp cmake/XrplCore.cmake mv cmake.tmp cmake/XrplCore.cmake
fi fi

View File

@@ -6,7 +6,7 @@ set -e
# On MacOS, ensure that GNU sed is installed and available as `gsed`. # On MacOS, ensure that GNU sed is installed and available as `gsed`.
SED_COMMAND=sed SED_COMMAND=sed
if [[ "${OSTYPE}" == 'darwin'* ]]; then if [[ "${OSTYPE}" == 'darwin'* ]]; then
if ! command -v gsed &> /dev/null; then if ! command -v gsed &>/dev/null; then
echo "Error: gsed is not installed. Please install it using 'brew install gnu-sed'." echo "Error: gsed is not installed. Please install it using 'brew install gnu-sed'."
exit 1 exit 1
fi fi
@@ -62,7 +62,7 @@ ${SED_COMMAND} -i 's@ripple/@xrpld/@g' src/test/core/Config_test.cpp
${SED_COMMAND} -i 's/Rippled/File/g' src/test/core/Config_test.cpp ${SED_COMMAND} -i 's/Rippled/File/g' src/test/core/Config_test.cpp
# Restore the old config file name in the code that maintains support for now. # Restore the old config file name in the code that maintains support for now.
${SED_COMMAND} -i 's/kCONFIG_LEGACY_NAME = "xrpld.cfg"/kCONFIG_LEGACY_NAME = "rippled.cfg"/g' src/xrpld/core/detail/Config.cpp ${SED_COMMAND} -i 's/kConfigLegacyName = "xrpld.cfg"/kConfigLegacyName = "rippled.cfg"/g' src/xrpld/core/detail/Config.cpp
# Restore an URL. # Restore an URL.
${SED_COMMAND} -i 's/connect-your-xrpld-to-the-xrp-test-net.html/connect-your-rippled-to-the-xrp-test-net.html/g' cfg/xrpld-example.cfg ${SED_COMMAND} -i 's/connect-your-xrpld-to-the-xrp-test-net.html/connect-your-rippled-to-the-xrp-test-net.html/g' cfg/xrpld-example.cfg

View File

@@ -6,7 +6,7 @@ set -e
# On MacOS, ensure that GNU sed is installed and available as `gsed`. # On MacOS, ensure that GNU sed is installed and available as `gsed`.
SED_COMMAND=sed SED_COMMAND=sed
if [[ "${OSTYPE}" == 'darwin'* ]]; then if [[ "${OSTYPE}" == 'darwin'* ]]; then
if ! command -v gsed &> /dev/null; then if ! command -v gsed &>/dev/null; then
echo "Error: gsed is not installed. Please install it using 'brew install gnu-sed'." echo "Error: gsed is not installed. Please install it using 'brew install gnu-sed'."
exit 1 exit 1
fi fi
@@ -62,37 +62,37 @@ done
# restoring the verbiage that is already present in LICENSE.md. Ensure that if # restoring the verbiage that is already present in LICENSE.md. Ensure that if
# the script is run multiple times, duplicate notices are not added. # the script is run multiple times, duplicate notices are not added.
if ! grep -q 'Raw Material Software' include/xrpl/beast/core/CurrentThreadName.h; then if ! grep -q 'Raw Material Software' include/xrpl/beast/core/CurrentThreadName.h; then
echo -e "// Portions of this file are from JUCE (http://www.juce.com).\n// Copyright (c) 2013 - Raw Material Software Ltd.\n// Please visit http://www.juce.com\n\n$(cat include/xrpl/beast/core/CurrentThreadName.h)" > include/xrpl/beast/core/CurrentThreadName.h echo -e "// Portions of this file are from JUCE (http://www.juce.com).\n// Copyright (c) 2013 - Raw Material Software Ltd.\n// Please visit http://www.juce.com\n\n$(cat include/xrpl/beast/core/CurrentThreadName.h)" >include/xrpl/beast/core/CurrentThreadName.h
fi fi
if ! grep -q 'Dev Null' src/test/app/NetworkID_test.cpp; then if ! grep -q 'Dev Null' src/test/app/NetworkID_test.cpp; then
echo -e "// Copyright (c) 2020 Dev Null Productions\n\n$(cat src/test/app/NetworkID_test.cpp)" > src/test/app/NetworkID_test.cpp echo -e "// Copyright (c) 2020 Dev Null Productions\n\n$(cat src/test/app/NetworkID_test.cpp)" >src/test/app/NetworkID_test.cpp
fi fi
if ! grep -q 'Dev Null' src/test/app/tx/apply_test.cpp; then if ! grep -q 'Dev Null' src/test/app/tx/apply_test.cpp; then
echo -e "// Copyright (c) 2020 Dev Null Productions\n\n$(cat src/test/app/tx/apply_test.cpp)" > src/test/app/tx/apply_test.cpp echo -e "// Copyright (c) 2020 Dev Null Productions\n\n$(cat src/test/app/tx/apply_test.cpp)" >src/test/app/tx/apply_test.cpp
fi fi
if ! grep -q 'Dev Null' src/test/rpc/ManifestRPC_test.cpp; then if ! grep -q 'Dev Null' src/test/rpc/ManifestRPC_test.cpp; then
echo -e "// Copyright (c) 2020 Dev Null Productions\n\n$(cat src/test/rpc/ManifestRPC_test.cpp)" > src/test/rpc/ManifestRPC_test.cpp echo -e "// Copyright (c) 2020 Dev Null Productions\n\n$(cat src/test/rpc/ManifestRPC_test.cpp)" >src/test/rpc/ManifestRPC_test.cpp
fi fi
if ! grep -q 'Dev Null' src/test/rpc/ValidatorInfo_test.cpp; then if ! grep -q 'Dev Null' src/test/rpc/ValidatorInfo_test.cpp; then
echo -e "// Copyright (c) 2020 Dev Null Productions\n\n$(cat src/test/rpc/ValidatorInfo_test.cpp)" > src/test/rpc/ValidatorInfo_test.cpp echo -e "// Copyright (c) 2020 Dev Null Productions\n\n$(cat src/test/rpc/ValidatorInfo_test.cpp)" >src/test/rpc/ValidatorInfo_test.cpp
fi fi
if ! grep -q 'Dev Null' src/xrpld/rpc/handlers/server_info/Manifest.cpp; then if ! grep -q 'Dev Null' src/xrpld/rpc/handlers/server_info/Manifest.cpp; then
echo -e "// Copyright (c) 2019 Dev Null Productions\n\n$(cat src/xrpld/rpc/handlers/server_info/Manifest.cpp)" > src/xrpld/rpc/handlers/server_info/Manifest.cpp echo -e "// Copyright (c) 2019 Dev Null Productions\n\n$(cat src/xrpld/rpc/handlers/server_info/Manifest.cpp)" >src/xrpld/rpc/handlers/server_info/Manifest.cpp
fi fi
if ! grep -q 'Dev Null' src/xrpld/rpc/handlers/admin/status/ValidatorInfo.cpp; then if ! grep -q 'Dev Null' src/xrpld/rpc/handlers/admin/status/ValidatorInfo.cpp; then
echo -e "// Copyright (c) 2019 Dev Null Productions\n\n$(cat src/xrpld/rpc/handlers/admin/status/ValidatorInfo.cpp)" > src/xrpld/rpc/handlers/admin/status/ValidatorInfo.cpp echo -e "// Copyright (c) 2019 Dev Null Productions\n\n$(cat src/xrpld/rpc/handlers/admin/status/ValidatorInfo.cpp)" >src/xrpld/rpc/handlers/admin/status/ValidatorInfo.cpp
fi fi
if ! grep -q 'Bougalis' include/xrpl/basics/SlabAllocator.h; then if ! grep -q 'Bougalis' include/xrpl/basics/SlabAllocator.h; then
echo -e "// Copyright (c) 2022, Nikolaos D. Bougalis <nikb@bougalis.net>\n\n$(cat include/xrpl/basics/SlabAllocator.h)" > include/xrpl/basics/SlabAllocator.h # cspell: ignore Nikolaos Bougalis nikb echo -e "// Copyright (c) 2022, Nikolaos D. Bougalis <nikb@bougalis.net>\n\n$(cat include/xrpl/basics/SlabAllocator.h)" >include/xrpl/basics/SlabAllocator.h # cspell: ignore Nikolaos Bougalis nikb
fi fi
if ! grep -q 'Bougalis' include/xrpl/basics/spinlock.h; then if ! grep -q 'Bougalis' include/xrpl/basics/spinlock.h; then
echo -e "// Copyright (c) 2022, Nikolaos D. Bougalis <nikb@bougalis.net>\n\n$(cat include/xrpl/basics/spinlock.h)" > include/xrpl/basics/spinlock.h # cspell: ignore Nikolaos Bougalis nikb echo -e "// Copyright (c) 2022, Nikolaos D. Bougalis <nikb@bougalis.net>\n\n$(cat include/xrpl/basics/spinlock.h)" >include/xrpl/basics/spinlock.h # cspell: ignore Nikolaos Bougalis nikb
fi fi
if ! grep -q 'Bougalis' include/xrpl/basics/tagged_integer.h; then if ! grep -q 'Bougalis' include/xrpl/basics/tagged_integer.h; then
echo -e "// Copyright (c) 2014, Nikolaos D. Bougalis <nikb@bougalis.net>\n\n$(cat include/xrpl/basics/tagged_integer.h)" > include/xrpl/basics/tagged_integer.h # cspell: ignore Nikolaos Bougalis nikb echo -e "// Copyright (c) 2014, Nikolaos D. Bougalis <nikb@bougalis.net>\n\n$(cat include/xrpl/basics/tagged_integer.h)" >include/xrpl/basics/tagged_integer.h # cspell: ignore Nikolaos Bougalis nikb
fi fi
if ! grep -q 'Ritchford' include/xrpl/beast/utility/Zero.h; then if ! grep -q 'Ritchford' include/xrpl/beast/utility/Zero.h; then
echo -e "// Copyright (c) 2014, Tom Ritchford <tom@swirly.com>\n\n$(cat include/xrpl/beast/utility/Zero.h)" > include/xrpl/beast/utility/Zero.h # cspell: ignore Ritchford echo -e "// Copyright (c) 2014, Tom Ritchford <tom@swirly.com>\n\n$(cat include/xrpl/beast/utility/Zero.h)" >include/xrpl/beast/utility/Zero.h # cspell: ignore Ritchford
fi fi
# Restore newlines and tabs in string literals in the affected file. # Restore newlines and tabs in string literals in the affected file.

View File

@@ -6,7 +6,7 @@ set -e
# On MacOS, ensure that GNU sed is installed and available as `gsed`. # On MacOS, ensure that GNU sed is installed and available as `gsed`.
SED_COMMAND=sed SED_COMMAND=sed
if [[ "${OSTYPE}" == 'darwin'* ]]; then if [[ "${OSTYPE}" == 'darwin'* ]]; then
if ! command -v gsed &> /dev/null; then if ! command -v gsed &>/dev/null; then
echo "Error: gsed is not installed. Please install it using 'brew install gnu-sed'." echo "Error: gsed is not installed. Please install it using 'brew install gnu-sed'."
exit 1 exit 1
fi fi

View File

@@ -6,7 +6,7 @@ set -e
# On MacOS, ensure that GNU sed is installed and available as `gsed`. # On MacOS, ensure that GNU sed is installed and available as `gsed`.
SED_COMMAND=sed SED_COMMAND=sed
if [[ "${OSTYPE}" == 'darwin'* ]]; then if [[ "${OSTYPE}" == 'darwin'* ]]; then
if ! command -v gsed &> /dev/null; then if ! command -v gsed &>/dev/null; then
echo "Error: gsed is not installed. Please install it using 'brew install gnu-sed'." echo "Error: gsed is not installed. Please install it using 'brew install gnu-sed'."
exit 1 exit 1
fi fi
@@ -90,7 +90,7 @@ ${SED_COMMAND} -i 's/www.ripple.com/www.xrpl.org/g' src/test/protocol/Seed_test.
# Restore specific changes. # Restore specific changes.
${SED_COMMAND} -i 's@b5efcc/src/xrpld@b5efcc/src/ripple@' include/xrpl/protocol/README.md ${SED_COMMAND} -i 's@b5efcc/src/xrpld@b5efcc/src/ripple@' include/xrpl/protocol/README.md
${SED_COMMAND} -i 's/dbPrefix_ = "xrpldb"/dbPrefix_ = "rippledb"/' src/xrpld/app/misc/SHAMapStoreImp.h # cspell: disable-line ${SED_COMMAND} -i 's/dbPrefix_ = "xrpldb"/dbPrefix_ = "rippledb"/' src/xrpld/app/misc/SHAMapStoreImp.h # cspell: disable-line
${SED_COMMAND} -i 's/kCONFIG_LEGACY_NAME = "xrpld.cfg"/kCONFIG_LEGACY_NAME = "rippled.cfg"/' src/xrpld/core/detail/Config.cpp ${SED_COMMAND} -i 's/kConfigLegacyName = "xrpld.cfg"/kConfigLegacyName = "rippled.cfg"/' src/xrpld/core/detail/Config.cpp
popd popd
echo "Renaming complete." echo "Renaming complete."

View File

@@ -6,7 +6,7 @@ set -e
# On MacOS, ensure that GNU sed is installed and available as `gsed`. # On MacOS, ensure that GNU sed is installed and available as `gsed`.
SED_COMMAND=sed SED_COMMAND=sed
if [[ "${OSTYPE}" == 'darwin'* ]]; then if [[ "${OSTYPE}" == 'darwin'* ]]; then
if ! command -v gsed &> /dev/null; then if ! command -v gsed &>/dev/null; then
echo "Error: gsed is not installed. Please install it using 'brew install gnu-sed'." echo "Error: gsed is not installed. Please install it using 'brew install gnu-sed'."
exit 1 exit 1
fi fi

View File

@@ -1,352 +1,281 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import argparse import argparse
import dataclasses
import itertools import itertools
import json import json
from dataclasses import dataclass
from pathlib import Path from pathlib import Path
THIS_DIR = Path(__file__).parent.resolve() THIS_DIR = Path(__file__).parent.resolve()
_BASE_CMAKE_ARGS = ["-Dtests=ON", "-Dwerr=ON", "-Dxrpld=ON", "-Dwextra=ON"]
@dataclass # Maps sanitizer names (as used in cmake) to short config-name suffixes.
class Config: _SANITIZER_SUFFIX: dict[str, str] = {
architecture: list[dict] "address": "asan",
os: list[dict] "undefinedbehavior": "ubsan",
"thread": "tsan",
}
def get_cmake_args(build_type: str, extra_args: str) -> str:
"""Get the full list of CMake arguments for a config."""
args = _BASE_CMAKE_ARGS.copy()
if build_type == "Release":
args.append("-Dassert=ON")
if extra_args:
args.extend(extra_args.split())
return " ".join(args)
# ---------------------------------------------------------------------------
# Input types — shapes of the JSON config files
# ---------------------------------------------------------------------------
@dataclasses.dataclass
class LinuxConfig:
"""One entry in linux.json's 'configs' or 'package_configs' arrays."""
compiler: list[str]
build_type: list[str] build_type: list[str]
cmake_args: list[str] arch: list[str]
sanitizers: list[str] = dataclasses.field(default_factory=list)
suffix: str = ""
extra_cmake_args: str = ""
image: str = "" # only used by package_configs entries
""" @dataclasses.dataclass
Generate a strategy matrix for GitHub Actions CI. class LinuxFile:
"""Shape of linux.json."""
On each PR commit we will build a selection of Debian, RHEL, Ubuntu, MacOS, and image_tag: str
Windows configurations, while upon merge into the develop or release branches, configs: dict[str, list[LinuxConfig]] # distro → configs
we will build all configurations, and test most of them. package_configs: dict[str, list[LinuxConfig]] # distro → packaging configs
We will further set additional CMake arguments as follows: @classmethod
- All builds will have the `tests`, `werr`, and `xrpld` options. def load(cls, path: Path) -> "LinuxFile":
- All builds will have the `wextra` option except for GCC 12 and Clang 16. data = json.loads(path.read_text())
- All release builds will have the `assert` option.
- Certain Debian Bookworm configurations will change the reference fee, enable
codecov, and enable voidstar in PRs.
"""
def parse(section: dict) -> dict[str, list[LinuxConfig]]:
return {
distro: [LinuxConfig(**c) for c in cfgs]
for distro, cfgs in section.items()
}
def generate_strategy_matrix(all: bool, config: Config) -> list: return cls(
configurations = [] image_tag=data["image_tag"],
for architecture, os, build_type, cmake_args in itertools.product( configs=parse(data["configs"]),
config.architecture, config.os, config.build_type, config.cmake_args package_configs=parse(data.get("package_configs", {})),
):
# The default CMake target is 'all' for Linux and MacOS and 'install'
# for Windows, but it can get overridden for certain configurations.
cmake_target = "install" if os["distro_name"] == "windows" else "all"
# We build and test all configurations by default, except for Windows in
# Debug, because it is too slow, as well as when code coverage is
# enabled as that mode already runs the tests.
build_only = False
if os["distro_name"] == "windows" and build_type == "Debug":
build_only = True
# Only generate a subset of configurations in PRs.
if not all:
# Debian:
# - Bookworm using GCC 13: Debug on linux/amd64, set the reference
# fee to 500 and enable code coverage (which will be done below).
# - Bookworm using GCC 15: Debug on linux/amd64, enable Address and
# UB sanitizers (which will be done below).
# - Bookworm using Clang 16: Debug on linux/amd64, enable voidstar.
# - Bookworm using Clang 17: Release on linux/amd64, set the
# reference fee to 1000.
# - Bookworm using Clang 20: Debug on linux/amd64, enable Address
# and UB sanitizers (which will be done below).
if os["distro_name"] == "debian":
skip = True
if os["distro_version"] == "bookworm":
if (
f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-13"
and build_type == "Debug"
and architecture["platform"] == "linux/amd64"
):
cmake_args = f"-DUNIT_TEST_REFERENCE_FEE=500 {cmake_args}"
skip = False
if (
f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-15"
and build_type == "Release"
and architecture["platform"] == "linux/amd64"
):
skip = False
if (
f"{os['compiler_name']}-{os['compiler_version']}" == "clang-16"
and build_type == "Debug"
and architecture["platform"] == "linux/amd64"
):
cmake_args = f"-Dvoidstar=ON {cmake_args}"
skip = False
if (
f"{os['compiler_name']}-{os['compiler_version']}" == "clang-17"
and build_type == "Release"
and architecture["platform"] == "linux/amd64"
):
cmake_args = f"-DUNIT_TEST_REFERENCE_FEE=1000 {cmake_args}"
skip = False
elif os["distro_version"] == "trixie":
if (
f"{os['compiler_name']}-{os['compiler_version']}" == "clang-22"
and build_type == "Debug"
and architecture["platform"] == "linux/amd64"
):
skip = False
if skip:
continue
# RHEL:
# - 9 using GCC 12: Debug on linux/amd64.
# - 10 using Clang: Release on linux/amd64.
if os["distro_name"] == "rhel":
skip = True
if os["distro_version"] == "9":
if (
f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-12"
and build_type == "Debug"
and architecture["platform"] == "linux/amd64"
):
skip = False
elif os["distro_version"] == "10":
if (
f"{os['compiler_name']}-{os['compiler_version']}" == "clang-any"
and build_type == "Release"
and architecture["platform"] == "linux/amd64"
):
skip = False
if skip:
continue
# Ubuntu:
# - Jammy using GCC 12: Debug on linux/arm64.
# - Noble using GCC 14: Release on linux/amd64.
# - Noble using Clang 18: Debug on linux/amd64.
# - Noble using Clang 19: Release on linux/arm64.
if os["distro_name"] == "ubuntu":
skip = True
if os["distro_version"] == "jammy":
if (
f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-12"
and build_type == "Debug"
and architecture["platform"] == "linux/arm64"
):
skip = False
elif os["distro_version"] == "noble":
if (
f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-14"
and build_type == "Release"
and architecture["platform"] == "linux/amd64"
):
skip = False
if (
f"{os['compiler_name']}-{os['compiler_version']}" == "clang-18"
and build_type == "Debug"
and architecture["platform"] == "linux/amd64"
):
skip = False
if (
f"{os['compiler_name']}-{os['compiler_version']}" == "clang-19"
and build_type == "Release"
and architecture["platform"] == "linux/arm64"
):
skip = False
if skip:
continue
# MacOS:
# - Debug on macos/arm64.
if os["distro_name"] == "macos" and not (
build_type == "Debug" and architecture["platform"] == "macos/arm64"
):
continue
# Windows:
# - Release on windows/amd64.
if os["distro_name"] == "windows" and not (
build_type == "Release" and architecture["platform"] == "windows/amd64"
):
continue
# Additional CMake arguments.
cmake_args = f"{cmake_args} -Dtests=ON -Dwerr=ON -Dxrpld=ON"
if not f"{os['compiler_name']}-{os['compiler_version']}" in [
"gcc-12",
"clang-16",
]:
cmake_args = f"{cmake_args} -Dwextra=ON"
if build_type == "Release":
cmake_args = f"{cmake_args} -Dassert=ON"
# We skip all RHEL on arm64 due to a build failure that needs further
# investigation.
if os["distro_name"] == "rhel" and architecture["platform"] == "linux/arm64":
continue
# We skip all clang 20+ on arm64 due to Boost build error.
if (
os["compiler_name"] == "clang"
and os["compiler_version"].isdigit()
and int(os["compiler_version"]) >= 20
and architecture["platform"] == "linux/arm64"
):
continue
# Enable code coverage for Debian Bookworm using GCC 13 in Debug on
# linux/amd64.
if (
f"{os['distro_name']}-{os['distro_version']}" == "debian-bookworm"
and f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-13"
and build_type == "Debug"
and architecture["platform"] == "linux/amd64"
):
cmake_args = f"{cmake_args} -Dcoverage=ON -Dcoverage_format=xml -DCODE_COVERAGE_VERBOSE=ON -DCMAKE_C_FLAGS=-O0 -DCMAKE_CXX_FLAGS=-O0"
# Enable unity build for Ubuntu Jammy using GCC 12 in Debug on
# linux/amd64.
if (
f"{os['distro_name']}-{os['distro_version']}" == "ubuntu-jammy"
and f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-12"
and build_type == "Debug"
and architecture["platform"] == "linux/amd64"
):
cmake_args = f"{cmake_args} -Dunity=ON"
# Generate a unique name for the configuration, e.g. macos-arm64-debug
# or debian-bookworm-gcc-12-amd64-release.
config_name = os["distro_name"]
if (n := os["distro_version"]) != "":
config_name += f"-{n}"
if (n := os["compiler_name"]) != "":
config_name += f"-{n}"
if (n := os["compiler_version"]) != "":
config_name += f"-{n}"
config_name += (
f"-{architecture['platform'][architecture['platform'].find('/')+1:]}"
) )
config_name += f"-{build_type.lower()}"
if "-Dcoverage=ON" in cmake_args:
config_name += "-coverage"
if "-Dunity=ON" in cmake_args:
config_name += "-unity"
# Add the configuration to the list, with the most unique fields first,
# so that they are easier to identify in the GitHub Actions UI, as long @dataclasses.dataclass
# names get truncated. class PlatformConfig:
# Add Address and UB sanitizers as separate configurations for specific """One entry in macos.json's or windows.json's 'configs' array."""
# bookworm distros. Thread sanitizer is currently disabled (see below).
# GCC-Asan xrpld-embedded tests are failing because of https://github.com/google/sanitizers/issues/856 build_type: list[str]
if ( build_only: bool = False # if true, skip tests (e.g. macos/Windows Debug)
os["distro_version"] == "bookworm" extra_cmake_args: str = ""
and f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-15"
) or ( def __post_init__(self) -> None:
os["distro_version"] == "trixie" if isinstance(self.build_type, str):
and f"{os['compiler_name']}-{os['compiler_version']}" == "clang-22" self.build_type = [self.build_type]
):
# Add ASAN and UBSAN configurations for both gcc-15 and clang-22
configurations.append( @dataclasses.dataclass
{ class PlatformFile:
"config_name": config_name + "-asan", """Shape of macos.json and windows.json."""
"cmake_args": cmake_args,
"cmake_target": cmake_target, platform: str # e.g. "macos/arm64" or "windows/amd64"
"build_only": build_only, runner: list[str] # GitHub Actions runner labels
"build_type": build_type, configs: list[PlatformConfig]
"os": os,
"architecture": architecture, @classmethod
"sanitizers": "address", def load(cls, path: Path) -> "PlatformFile":
} data = json.loads(path.read_text())
) return cls(
configurations.append( platform=data["platform"],
{ runner=data["runner"],
"config_name": config_name + "-ubsan", configs=[PlatformConfig(**c) for c in data["configs"]],
"cmake_args": cmake_args, )
"cmake_target": cmake_target,
"build_only": build_only,
"build_type": build_type, # ---------------------------------------------------------------------------
"os": os, # Output types — shapes of the generated GitHub Actions matrix entries
"architecture": architecture, # ---------------------------------------------------------------------------
"sanitizers": "undefinedbehavior",
}
) @dataclasses.dataclass
# TSAN is deactivated due to seg faults with latest compilers. class Architecture:
activate_tsan = False platform: str
if activate_tsan: runner: list[str]
configurations.append(
{
"config_name": config_name + "-tsan-ubsan", @dataclasses.dataclass
"cmake_args": cmake_args, class MatrixEntry:
"cmake_target": cmake_target, """One entry in the generated build/test strategy matrix."""
"build_only": build_only,
"build_type": build_type, config_name: str
"os": os, cmake_args: str
"architecture": architecture, cmake_target: str
"sanitizers": "thread,undefinedbehavior", build_only: bool
} build_type: str
architecture: Architecture
sanitizers: str
image: str = "" # container image; empty for macOS/Windows (runs natively)
compiler: str = "" # compiler name ("gcc" or "clang"); empty for macOS/Windows
@dataclasses.dataclass
class PackagingEntry:
"""One entry in the generated packaging strategy matrix."""
artifact_name: str
image: str
distro: str # e.g. "debian" or "rhel"; drives package-format-specific steps
# ---------------------------------------------------------------------------
# Matrix expansion
# ---------------------------------------------------------------------------
_ARCHS: dict[str, Architecture] = {
"amd64": Architecture(
platform="linux/amd64", runner=["self-hosted", "Linux", "X64", "heavy"]
),
"arm64": Architecture(
platform="linux/arm64",
runner=["self-hosted", "Linux", "ARM64", "heavy-arm64"],
),
}
def expand_linux_matrix(linux: LinuxFile) -> list[MatrixEntry]:
"""Expand a LinuxFile into a flat list of matrix entries.
Each config entry is expanded over the cross-product of its
compiler, build_type, sanitizers, and architecture lists.
"""
entries: list[MatrixEntry] = []
for distro, configs in linux.configs.items():
for cfg in configs:
# An empty sanitizers list means "one entry with no sanitizer".
effective_sanitizers = cfg.sanitizers or [""]
effective_archs = {arch: _ARCHS[arch] for arch in cfg.arch}
for compiler, build_type, sanitizer, (arch, arch_info) in itertools.product(
cfg.compiler,
cfg.build_type,
effective_sanitizers,
effective_archs.items(),
):
name = f"{distro}-{compiler}-{build_type.lower()}-{arch}"
suffix_parts = [
s for s in [cfg.suffix, _SANITIZER_SUFFIX.get(sanitizer, "")] if s
]
if suffix_parts:
name += "-" + "-".join(suffix_parts)
entries.append(
MatrixEntry(
config_name=name,
image=f"ghcr.io/xrplf/xrpld/nix-{distro}:{linux.image_tag}",
cmake_args=get_cmake_args(build_type, cfg.extra_cmake_args),
cmake_target="all",
build_only=False,
build_type=build_type,
architecture=arch_info,
sanitizers=sanitizer,
compiler=compiler,
)
)
return entries
def expand_linux_packaging(linux: LinuxFile) -> list[PackagingEntry]:
"""Generate the packaging matrix from a LinuxFile's package_configs section.
Packaging uses vanilla distro images (debian:bookworm, ubi9, …) instead of
the nix-based build images, because deb/rpm tooling (debhelper, rpm-build)
is taken from the distro's archive rather than from nixpkgs. Each config
entry carries its own 'image'.
"""
entries = []
for distro, configs in linux.package_configs.items():
for cfg in configs:
for compiler, build_type in itertools.product(cfg.compiler, cfg.build_type):
entries.append(
PackagingEntry(
artifact_name=f"xrpld-{distro}-{compiler}-{build_type.lower()}-amd64",
image=cfg.image,
distro=distro,
)
)
return entries
def expand_platform_matrix(pf: PlatformFile) -> list[MatrixEntry]:
"""Expand a PlatformFile (macOS or Windows) into matrix entries."""
platform_name, arch = pf.platform.split("/")
is_windows = platform_name == "windows"
entries: list[MatrixEntry] = []
for cfg in pf.configs:
for build_type in cfg.build_type:
entries.append(
MatrixEntry(
config_name=f"{platform_name}-{arch}-{build_type.lower()}",
cmake_args=get_cmake_args(build_type, cfg.extra_cmake_args),
cmake_target="install" if is_windows else "all",
build_only=cfg.build_only,
build_type=build_type,
architecture=Architecture(platform=pf.platform, runner=pf.runner),
sanitizers="",
) )
else:
configurations.append(
{
"config_name": config_name,
"cmake_args": cmake_args,
"cmake_target": cmake_target,
"build_only": build_only,
"build_type": build_type,
"os": os,
"architecture": architecture,
"sanitizers": "",
}
) )
return entries
return configurations
def read_config(file: Path) -> Config: # ---------------------------------------------------------------------------
config = json.loads(file.read_text()) # Entry point
if ( # ---------------------------------------------------------------------------
config["architecture"] is None
or config["os"] is None
or config["build_type"] is None
or config["cmake_args"] is None
):
raise Exception("Invalid configuration file.")
return Config(**config)
if __name__ == "__main__": if __name__ == "__main__":
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser(
parser.add_argument( description="Generate a CI strategy matrix for all platforms or a specific one."
"-a",
"--all",
help="Set to generate all configurations (generally used when merging a PR) or leave unset to generate a subset of configurations (generally used when committing to a PR).",
action="store_true",
) )
parser.add_argument( parser.add_argument(
"-c", "-c",
"--config", "--config",
help="Path to the JSON file containing the strategy matrix configurations.", help="Platform to generate for ('linux', 'macos', or 'windows'). Defaults to all platforms.",
required=False, choices=["linux", "macos", "windows"],
type=Path, default=None,
)
parser.add_argument(
"-p",
"--packaging",
help="Emit the Linux packaging matrix instead of the build/test matrix.",
action="store_true",
) )
args = parser.parse_args() args = parser.parse_args()
matrix = [] matrix: list[MatrixEntry] | list[PackagingEntry] = []
if args.config is None or args.config == "":
matrix += generate_strategy_matrix(
args.all, read_config(THIS_DIR / "linux.json")
)
matrix += generate_strategy_matrix(
args.all, read_config(THIS_DIR / "macos.json")
)
matrix += generate_strategy_matrix(
args.all, read_config(THIS_DIR / "windows.json")
)
else:
matrix += generate_strategy_matrix(args.all, read_config(args.config))
# Generate the strategy matrix. if args.packaging:
print(f"matrix={json.dumps({'include': matrix})}") matrix = expand_linux_packaging(LinuxFile.load(THIS_DIR / "linux.json"))
else:
if args.config in ("linux", None):
matrix += expand_linux_matrix(LinuxFile.load(THIS_DIR / "linux.json"))
if args.config in ("macos", None):
matrix += expand_platform_matrix(PlatformFile.load(THIS_DIR / "macos.json"))
if args.config in ("windows", None):
matrix += expand_platform_matrix(
PlatformFile.load(THIS_DIR / "windows.json")
)
print(f"matrix={json.dumps({'include': [dataclasses.asdict(e) for e in matrix]})}")

View File

@@ -1,219 +1,83 @@
{ {
"architecture": [ "image_tag": "sha-63ffdc3",
{ "configs": {
"platform": "linux/amd64", "ubuntu": [
"runner": ["self-hosted", "Linux", "X64", "heavy"] {
}, "compiler": ["gcc", "clang"],
{ "build_type": ["Debug", "Release"],
"platform": "linux/arm64", "arch": ["amd64", "arm64"]
"runner": ["self-hosted", "Linux", "ARM64", "heavy-arm64"] },
}
], {
"os": [ "compiler": ["gcc", "clang"],
{ "build_type": ["Debug"],
"distro_name": "debian", "arch": ["amd64"],
"distro_version": "bookworm", "sanitizers": ["address", "undefinedbehavior"]
"compiler_name": "gcc", },
"compiler_version": "12",
"image_sha": "4c086b9" {
}, "compiler": ["gcc"],
{ "build_type": ["Debug"],
"distro_name": "debian", "arch": ["amd64"],
"distro_version": "bookworm", "suffix": "coverage",
"compiler_name": "gcc", "extra_cmake_args": "-DUNIT_TEST_REFERENCE_FEE=500 -Dcoverage=ON -Dcoverage_format=xml -DCODE_COVERAGE_VERBOSE=ON -DCMAKE_C_FLAGS=-O0 -DCMAKE_CXX_FLAGS=-O0"
"compiler_version": "13", },
"image_sha": "4c086b9" {
}, "compiler": ["clang"],
{ "build_type": ["Debug"],
"distro_name": "debian", "arch": ["amd64"],
"distro_version": "bookworm", "suffix": "voidstar",
"compiler_name": "gcc", "extra_cmake_args": "-Dvoidstar=ON"
"compiler_version": "14", },
"image_sha": "4c086b9" {
}, "compiler": ["clang"],
{ "build_type": ["Release"],
"distro_name": "debian", "arch": ["amd64"],
"distro_version": "bookworm", "suffix": "reffee",
"compiler_name": "gcc", "extra_cmake_args": "-DUNIT_TEST_REFERENCE_FEE=1000"
"compiler_version": "15", },
"image_sha": "4c086b9" {
}, "compiler": ["gcc"],
{ "build_type": ["Debug"],
"distro_name": "debian", "arch": ["amd64"],
"distro_version": "bookworm", "suffix": "unity",
"compiler_name": "clang", "extra_cmake_args": "-Dunity=ON"
"compiler_version": "16", }
"image_sha": "4c086b9" ],
},
{ "debian": [
"distro_name": "debian", {
"distro_version": "bookworm", "compiler": ["gcc"],
"compiler_name": "clang", "build_type": ["Release"],
"compiler_version": "17", "arch": ["amd64"]
"image_sha": "4c086b9" }
}, ],
{
"distro_name": "debian", "rhel": [
"distro_version": "bookworm", {
"compiler_name": "clang", "compiler": ["gcc"],
"compiler_version": "18", "build_type": ["Release"],
"image_sha": "4c086b9" "arch": ["amd64"]
}, }
{ ]
"distro_name": "debian", },
"distro_version": "bookworm", "package_configs": {
"compiler_name": "clang", "debian": [
"compiler_version": "19", {
"image_sha": "4c086b9" "compiler": ["gcc"],
}, "build_type": ["Release"],
{ "arch": ["amd64"],
"distro_name": "debian", "image": "ghcr.io/xrplf/xrpld/packaging-debian:sha-63ffdc3"
"distro_version": "bookworm", }
"compiler_name": "clang", ],
"compiler_version": "20",
"image_sha": "4c086b9" "rhel": [
}, {
{ "compiler": ["gcc"],
"distro_name": "debian", "build_type": ["Release"],
"distro_version": "trixie", "arch": ["amd64"],
"compiler_name": "gcc", "image": "ghcr.io/xrplf/xrpld/packaging-rhel:sha-63ffdc3"
"compiler_version": "14", }
"image_sha": "4c086b9" ]
}, }
{
"distro_name": "debian",
"distro_version": "trixie",
"compiler_name": "gcc",
"compiler_version": "15",
"image_sha": "4c086b9"
},
{
"distro_name": "debian",
"distro_version": "trixie",
"compiler_name": "clang",
"compiler_version": "20",
"image_sha": "4c086b9"
},
{
"distro_name": "debian",
"distro_version": "trixie",
"compiler_name": "clang",
"compiler_version": "21",
"image_sha": "4c086b9"
},
{
"distro_name": "debian",
"distro_version": "trixie",
"compiler_name": "clang",
"compiler_version": "22",
"image_sha": "4c086b9"
},
{
"distro_name": "rhel",
"distro_version": "8",
"compiler_name": "gcc",
"compiler_version": "14",
"image_sha": "4c086b9"
},
{
"distro_name": "rhel",
"distro_version": "8",
"compiler_name": "clang",
"compiler_version": "any",
"image_sha": "4c086b9"
},
{
"distro_name": "rhel",
"distro_version": "9",
"compiler_name": "gcc",
"compiler_version": "12",
"image_sha": "4c086b9"
},
{
"distro_name": "rhel",
"distro_version": "9",
"compiler_name": "gcc",
"compiler_version": "13",
"image_sha": "4c086b9"
},
{
"distro_name": "rhel",
"distro_version": "9",
"compiler_name": "gcc",
"compiler_version": "14",
"image_sha": "4c086b9"
},
{
"distro_name": "rhel",
"distro_version": "9",
"compiler_name": "clang",
"compiler_version": "any",
"image_sha": "4c086b9"
},
{
"distro_name": "rhel",
"distro_version": "10",
"compiler_name": "gcc",
"compiler_version": "14",
"image_sha": "4c086b9"
},
{
"distro_name": "rhel",
"distro_version": "10",
"compiler_name": "clang",
"compiler_version": "any",
"image_sha": "4c086b9"
},
{
"distro_name": "ubuntu",
"distro_version": "jammy",
"compiler_name": "gcc",
"compiler_version": "12",
"image_sha": "4c086b9"
},
{
"distro_name": "ubuntu",
"distro_version": "noble",
"compiler_name": "gcc",
"compiler_version": "13",
"image_sha": "4c086b9"
},
{
"distro_name": "ubuntu",
"distro_version": "noble",
"compiler_name": "gcc",
"compiler_version": "14",
"image_sha": "4c086b9"
},
{
"distro_name": "ubuntu",
"distro_version": "noble",
"compiler_name": "clang",
"compiler_version": "16",
"image_sha": "4c086b9"
},
{
"distro_name": "ubuntu",
"distro_version": "noble",
"compiler_name": "clang",
"compiler_version": "17",
"image_sha": "4c086b9"
},
{
"distro_name": "ubuntu",
"distro_version": "noble",
"compiler_name": "clang",
"compiler_version": "18",
"image_sha": "4c086b9"
},
{
"distro_name": "ubuntu",
"distro_version": "noble",
"compiler_name": "clang",
"compiler_version": "19",
"image_sha": "4c086b9"
}
],
"build_type": ["Debug", "Release"],
"cmake_args": [""]
} }

View File

@@ -1,19 +1,15 @@
{ {
"architecture": [ "platform": "macos/arm64",
"runner": ["self-hosted", "macOS", "ARM64", "mac-runner-m1"],
"configs": [
{ {
"platform": "macos/arm64", "build_type": "Release",
"runner": ["self-hosted", "macOS", "ARM64", "mac-runner-m1"] "extra_cmake_args": "-DCMAKE_POLICY_VERSION_MINIMUM=3.5"
} },
],
"os": [
{ {
"distro_name": "macos", "build_type": "Debug",
"distro_version": "", "extra_cmake_args": "-DCMAKE_POLICY_VERSION_MINIMUM=3.5",
"compiler_name": "", "build_only": true
"compiler_version": "",
"image_sha": ""
} }
], ]
"build_type": ["Debug", "Release"],
"cmake_args": ["-DCMAKE_POLICY_VERSION_MINIMUM=3.5"]
} }

View File

@@ -1,19 +1,8 @@
{ {
"architecture": [ "platform": "windows/amd64",
{ "runner": ["self-hosted", "Windows", "devbox"],
"platform": "windows/amd64", "configs": [
"runner": ["self-hosted", "Windows", "devbox"] { "build_type": "Release" },
} { "build_type": "Debug", "build_only": true }
], ]
"os": [
{
"distro_name": "windows",
"distro_version": "",
"compiler_name": "",
"compiler_version": "",
"image_sha": ""
}
],
"build_type": ["Debug", "Release"],
"cmake_args": [""]
} }

View File

@@ -1,101 +0,0 @@
name: Build Nix Docker image
on:
push:
branches:
- develop
paths:
- ".github/workflows/build-nix-image.yml"
- "docker/nix.Dockerfile"
- "flake.nix"
- "flake.lock"
- "nix/**"
pull_request:
paths:
- ".github/workflows/build-nix-image.yml"
- "docker/nix.Dockerfile"
- "flake.nix"
- "flake.lock"
- "nix/**"
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
defaults:
run:
shell: bash
env:
UBUNTU_VERSION: "20.04"
RHEL_VERSION: "9"
DEBIAN_VERSION: "bookworm"
jobs:
build:
name: Build and push Nix image (${{ matrix.distro }})
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
strategy:
matrix:
include:
- distro: nixos
- distro: ubuntu
- distro: rhel
- distro: debian
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Determine base image
id: vars
run: |
case "${{ matrix.distro }}" in
nixos)
echo "base_image=nixos/nix:latest" >> $GITHUB_OUTPUT
;;
ubuntu)
echo "base_image=ubuntu:${UBUNTU_VERSION}" >> $GITHUB_OUTPUT
;;
rhel)
echo "base_image=registry.access.redhat.com/ubi${RHEL_VERSION}/ubi:latest" >> $GITHUB_OUTPUT
;;
debian)
echo "base_image=debian:${DEBIAN_VERSION}" >> $GITHUB_OUTPUT
;;
esac
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
- name: Login to GitHub Container Registry
if: github.event_name == 'push'
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Docker metadata
id: meta
uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0
with:
images: ghcr.io/xrplf/ci/nix-${{ matrix.distro }}
tags: |
type=sha,prefix=sha-,format=short
type=raw,value=latest
- name: Build and push
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
with:
context: .
file: docker/nix.Dockerfile
platforms: linux/amd64
push: ${{ github.event_name == 'push' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: BASE_IMAGE=${{ steps.vars.outputs.base_image }}

57
.github/workflows/build-nix-images.yml vendored Normal file
View File

@@ -0,0 +1,57 @@
name: Build Nix Docker images
on:
push:
branches:
- develop
paths:
- ".github/workflows/build-nix-images.yml"
- ".github/workflows/reusable-build-docker-image.yml"
- ".github/workflows/reusable-build-merge-docker-images.yml"
- "flake.nix"
- "flake.lock"
- "nix/**"
pull_request:
paths:
- ".github/workflows/build-nix-images.yml"
- ".github/workflows/reusable-build-docker-image.yml"
- ".github/workflows/reusable-build-merge-docker-images.yml"
- "flake.nix"
- "flake.lock"
- "nix/**"
workflow_dispatch:
concurrency:
# Read `on-trigger.yml` for the rationale behind this concurrency group name.
group: ${{ github.workflow }}-${{ github.event_name == 'push' && github.ref == 'refs/heads/develop' && github.sha || github.ref }}
cancel-in-progress: true
defaults:
run:
shell: bash
jobs:
build-merge:
name: Build and push nix-${{ matrix.distro.name }}
permissions:
contents: read
packages: write
strategy:
fail-fast: false
matrix:
# The base images are the oldest supported version of each distro
# that we want to build images for.
distro:
- name: nixos
base_image: nixos/nix:latest
- name: ubuntu
base_image: ubuntu:20.04
- name: debian
base_image: debian:bookworm
- name: rhel
base_image: registry.access.redhat.com/ubi9/ubi:latest
uses: ./.github/workflows/reusable-build-merge-docker-images.yml
with:
image_name: ghcr.io/xrplf/xrpld/nix-${{ matrix.distro.name }}
dockerfile: nix/docker/Dockerfile
base_image: ${{ matrix.distro.base_image }}

View File

@@ -0,0 +1,49 @@
name: Build packaging Docker images
on:
push:
branches:
- develop
paths:
- ".github/workflows/build-packaging-images.yml"
- ".github/workflows/reusable-build-docker-image.yml"
- ".github/workflows/reusable-build-merge-docker-images.yml"
- "package/Dockerfile"
- "package/install-packaging-tools.sh"
pull_request:
paths:
- ".github/workflows/build-packaging-images.yml"
- ".github/workflows/reusable-build-docker-image.yml"
- ".github/workflows/reusable-build-merge-docker-images.yml"
- "package/Dockerfile"
- "package/install-packaging-tools.sh"
workflow_dispatch:
concurrency:
# Read `on-trigger.yml` for the rationale behind this concurrency group name.
group: ${{ github.workflow }}-${{ github.event_name == 'push' && github.ref == 'refs/heads/develop' && github.sha || github.ref }}
cancel-in-progress: true
defaults:
run:
shell: bash
jobs:
build-merge:
name: Build and push packaging-${{ matrix.distro.name }}
permissions:
contents: read
packages: write
strategy:
fail-fast: false
matrix:
distro:
- name: debian
base_image: debian:bookworm
- name: rhel
base_image: registry.access.redhat.com/ubi9/ubi:latest
uses: ./.github/workflows/reusable-build-merge-docker-images.yml
with:
image_name: ghcr.io/xrplf/xrpld/packaging-${{ matrix.distro.name }}
dockerfile: package/Dockerfile
base_image: ${{ matrix.distro.base_image }}

View File

@@ -5,8 +5,17 @@ on:
types: types:
- checks_requested - checks_requested
pull_request: pull_request:
types: [opened, edited, reopened, synchronize, ready_for_review] types:
branches: [develop] - opened
- edited
- reopened
- synchronize
- ready_for_review
branches:
- develop
- "release-*"
- "release/*"
- "staging/*"
jobs: jobs:
check_description: check_description:
@@ -14,17 +23,17 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Write PR body to file - name: Write PR body to file
env: env:
PR_BODY: ${{ github.event.pull_request.body }} PR_BODY: ${{ github.event.pull_request.body }}
if: ${{ github.event_name == 'pull_request' }} if: ${{ github.event_name == 'pull_request' }}
run: printenv PR_BODY > pr_body.md run: printenv PR_BODY >pr_body.md
- name: Check PR description differs from template - name: Check PR description differs from template
if: ${{ github.event_name == 'pull_request' }} if: ${{ github.event_name == 'pull_request' }}
run: > run: |
python .github/scripts/check-pr-description.py python .github/scripts/check-pr-description.py \
--template-file .github/pull_request_template.md --template-file .github/pull_request_template.md \
--pr-body-file pr_body.md --pr-body-file pr_body.md

View File

@@ -5,10 +5,19 @@ on:
types: types:
- checks_requested - checks_requested
pull_request: pull_request:
types: [opened, edited, reopened, synchronize, ready_for_review] types:
branches: [develop] - opened
- edited
- reopened
- synchronize
- ready_for_review
branches:
- develop
- "release-*"
- "release/*"
- "staging/*"
jobs: jobs:
check_title: check_title:
if: ${{ github.event.pull_request.draft != true }} if: ${{ github.event.pull_request.draft != true }}
uses: XRPLF/actions/.github/workflows/check-pr-title.yml@a5d8dd35be543365e90a11358447130c8763871d uses: XRPLF/actions/.github/workflows/check-pr-title.yml@cba1f0891650baf1a9c88624dc2d72573be2eb81

View File

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

View File

@@ -33,7 +33,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Determine changed files - name: Determine changed files
# This step checks whether any files have changed that should # This step checks whether any files have changed that should
# cause the next jobs to run. We do it this way rather than # cause the next jobs to run. We do it this way rather than
@@ -64,11 +64,13 @@ jobs:
.github/workflows/reusable-build-test-config.yml .github/workflows/reusable-build-test-config.yml
.github/workflows/reusable-build-test.yml .github/workflows/reusable-build-test.yml
.github/workflows/reusable-clang-tidy.yml .github/workflows/reusable-clang-tidy.yml
.github/workflows/reusable-package.yml
.github/workflows/reusable-strategy-matrix.yml .github/workflows/reusable-strategy-matrix.yml
.github/workflows/reusable-test.yml .github/workflows/reusable-test.yml
.github/workflows/reusable-upload-recipe.yml .github/workflows/reusable-upload-recipe.yml
.clang-tidy .clang-tidy
.codecov.yml .codecov.yml
cfg/**
cmake/** cmake/**
conan/** conan/**
external/** external/**
@@ -78,6 +80,10 @@ jobs:
CMakeLists.txt CMakeLists.txt
conanfile.py conanfile.py
conan.lock conan.lock
LICENSE.md
package/**
README.md
- name: Check whether to run - name: Check whether to run
# This step determines whether the rest of the workflow should # This step determines whether the rest of the workflow should
# run. The rest of the workflow will run if this job runs AND at # run. The rest of the workflow will run if this job runs AND at
@@ -92,7 +98,7 @@ jobs:
READY: ${{ contains(github.event.pull_request.labels.*.name, 'Ready to merge') }} READY: ${{ contains(github.event.pull_request.labels.*.name, 'Ready to merge') }}
MERGE: ${{ github.event_name == 'merge_group' }} MERGE: ${{ github.event_name == 'merge_group' }}
run: | run: |
echo "go=${{ (env.DRAFT != 'true' && env.READY == 'true') || env.FILES == 'true' || env.MERGE == 'true' }}" >> "${GITHUB_OUTPUT}" echo "go=${{ (env.DRAFT != 'true' && env.READY == 'true') || env.FILES == 'true' || env.MERGE == 'true' }}" >>"${GITHUB_OUTPUT}"
cat "${GITHUB_OUTPUT}" cat "${GITHUB_OUTPUT}"
outputs: outputs:
go: ${{ steps.go.outputs.go == 'true' }} go: ${{ steps.go.outputs.go == 'true' }}
@@ -134,6 +140,11 @@ jobs:
secrets: secrets:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
package:
needs: [should-run, build-test]
if: ${{ needs.should-run.outputs.go == 'true' }}
uses: ./.github/workflows/reusable-package.yml
upload-recipe: upload-recipe:
needs: needs:
- should-run - should-run
@@ -157,9 +168,9 @@ jobs:
PR_URL: ${{ github.event.pull_request.html_url }} PR_URL: ${{ github.event.pull_request.html_url }}
run: | run: |
gh api --method POST -H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28" \ gh api --method POST -H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28" \
/repos/xrplf/clio/dispatches -f "event_type=check_libxrpl" \ /repos/xrplf/clio/dispatches -f "event_type=check_libxrpl" \
-F "client_payload[ref]=${{ needs.upload-recipe.outputs.recipe_ref }}" \ -F "client_payload[ref]=${{ needs.upload-recipe.outputs.recipe_ref }}" \
-F "client_payload[pr_url]=${PR_URL}" -F "client_payload[pr_url]=${PR_URL}"
passed: passed:
if: failure() || cancelled() if: failure() || cancelled()
@@ -168,6 +179,7 @@ jobs:
- check-rename - check-rename
- clang-tidy - clang-tidy
- build-test - build-test
- package
- upload-recipe - upload-recipe
- notify-clio - notify-clio
runs-on: ubuntu-latest runs-on: ubuntu-latest

View File

@@ -1,5 +1,5 @@
# This workflow uploads the libxrpl recipe to the Conan remote when a versioned # This workflow uploads the libxrpl recipe to the Conan remote and builds
# tag is pushed. # release packages when a versioned tag is pushed.
name: Tag name: Tag
on: on:
@@ -22,3 +22,21 @@ jobs:
secrets: secrets:
remote_username: ${{ secrets.CONAN_REMOTE_USERNAME }} remote_username: ${{ secrets.CONAN_REMOTE_USERNAME }}
remote_password: ${{ secrets.CONAN_REMOTE_PASSWORD }} remote_password: ${{ secrets.CONAN_REMOTE_PASSWORD }}
build-test:
if: ${{ github.repository == 'XRPLF/rippled' }}
uses: ./.github/workflows/reusable-build-test.yml
strategy:
fail-fast: true
matrix:
os: [linux]
with:
ccache_enabled: false
os: ${{ matrix.os }}
secrets:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
package:
if: ${{ github.repository == 'XRPLF/rippled' }}
needs: build-test
uses: ./.github/workflows/reusable-package.yml

View File

@@ -21,11 +21,13 @@ on:
- ".github/workflows/reusable-build-test-config.yml" - ".github/workflows/reusable-build-test-config.yml"
- ".github/workflows/reusable-build-test.yml" - ".github/workflows/reusable-build-test.yml"
- ".github/workflows/reusable-clang-tidy.yml" - ".github/workflows/reusable-clang-tidy.yml"
- ".github/workflows/reusable-package.yml"
- ".github/workflows/reusable-strategy-matrix.yml" - ".github/workflows/reusable-strategy-matrix.yml"
- ".github/workflows/reusable-test.yml" - ".github/workflows/reusable-test.yml"
- ".github/workflows/reusable-upload-recipe.yml" - ".github/workflows/reusable-upload-recipe.yml"
- ".clang-tidy" - ".clang-tidy"
- ".codecov.yml" - ".codecov.yml"
- "cfg/**"
- "cmake/**" - "cmake/**"
- "conan/**" - "conan/**"
- "external/**" - "external/**"
@@ -35,6 +37,9 @@ on:
- "CMakeLists.txt" - "CMakeLists.txt"
- "conanfile.py" - "conanfile.py"
- "conan.lock" - "conan.lock"
- "LICENSE.md"
- "package/**"
- "README.md"
# Run at 06:32 UTC on every day of the week from Monday through Friday. This # Run at 06:32 UTC on every day of the week from Monday through Friday. This
# will force all dependencies to be rebuilt, which is useful to verify that # will force all dependencies to be rebuilt, which is useful to verify that
@@ -83,7 +88,6 @@ jobs:
# not identical to a regular compilation. # not identical to a regular compilation.
ccache_enabled: ${{ github.repository_owner == 'XRPLF' && !startsWith(github.ref, 'refs/heads/release') }} ccache_enabled: ${{ github.repository_owner == 'XRPLF' && !startsWith(github.ref, 'refs/heads/release') }}
os: ${{ matrix.os }} os: ${{ matrix.os }}
strategy_matrix: ${{ github.event_name == 'schedule' && 'all' || 'minimal' }}
secrets: secrets:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
@@ -95,3 +99,7 @@ jobs:
secrets: secrets:
remote_username: ${{ secrets.CONAN_REMOTE_USERNAME }} remote_username: ${{ secrets.CONAN_REMOTE_USERNAME }}
remote_password: ${{ secrets.CONAN_REMOTE_PASSWORD }} remote_password: ${{ secrets.CONAN_REMOTE_PASSWORD }}
package:
needs: build-test
uses: ./.github/workflows/reusable-package.yml

View File

@@ -14,7 +14,7 @@ on:
jobs: jobs:
# Call the workflow in the XRPLF/actions repo that runs the pre-commit hooks. # Call the workflow in the XRPLF/actions repo that runs the pre-commit hooks.
run-hooks: run-hooks:
uses: XRPLF/actions/.github/workflows/pre-commit.yml@5e942d61bf32f7557a7c159cfac4712a687b3e3a uses: XRPLF/actions/.github/workflows/pre-commit.yml@312aaab296060ff89d7f798dcab59f019bea6e02
with: with:
runs_on: ubuntu-latest runs_on: ubuntu-latest
container: '{ "image": "ghcr.io/xrplf/ci/tools-rippled-pre-commit:sha-41ec7c1" }' container: '{ "image": "ghcr.io/xrplf/ci/tools-rippled-pre-commit:sha-41ec7c1" }'

View File

@@ -41,13 +41,13 @@ env:
jobs: jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: ghcr.io/xrplf/ci/tools-rippled-documentation:sha-a8c7be1 container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-63ffdc3
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Prepare runner - name: Prepare runner
uses: XRPLF/actions/prepare-runner@90f11ee655d1687824fb8793db770477d52afbab uses: XRPLF/actions/prepare-runner@c47daebb2f9db64ffbac71b47d68a661498d5ce8
with: with:
enable_ccache: false enable_ccache: false
@@ -57,19 +57,11 @@ jobs:
with: with:
subtract: ${{ env.NPROC_SUBTRACT }} subtract: ${{ env.NPROC_SUBTRACT }}
- name: Check configuration - name: Print build environment
run: | uses: XRPLF/actions/print-build-env@59dec886e4afb05a1724443af08baccbc045b574
echo 'Checking path.'
echo ${PATH} | tr ':' '\n'
echo 'Checking environment variables.' - name: Check Doxygen version
env | sort run: doxygen --version
echo 'Checking CMake version.'
cmake --version
echo 'Checking Doxygen version.'
doxygen --version
- name: Build documentation - name: Build documentation
env: env:

View File

@@ -0,0 +1,89 @@
# Build a single-platform Docker image. On push, the image is pushed to
# GHCR with arch-suffixed tags (e.g. `:latest-amd64`, `:sha-abc-amd64`)
# so the calling workflow can stitch per-arch builds into a multi-arch
# manifest without needing to pass digests around.
name: Reusable build Docker image (single platform)
on:
workflow_call:
inputs:
image_name:
description: "Full image name without tag (e.g. 'ghcr.io/xrplf/xrpld/nix-ubuntu')"
required: true
type: string
dockerfile:
description: "Path to the Dockerfile, relative to the repository root"
required: true
type: string
base_image:
description: "Value passed to the Dockerfile as the BASE_IMAGE build arg"
required: true
type: string
platform:
description: "Docker platform string, e.g. linux/amd64"
required: true
type: string
runner:
description: "GitHub Actions runner label to build on"
required: true
type: string
push:
description: "Whether to push the image to GHCR"
required: true
type: boolean
defaults:
run:
shell: bash
jobs:
build:
name: Build ${{ inputs.platform }}
runs-on: ${{ inputs.runner }}
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Determine arch
id: vars
env:
PLATFORM: ${{ inputs.platform }}
run: |
echo "arch=${PLATFORM##*/}" >>$GITHUB_OUTPUT
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0
- name: Login to GitHub Container Registry
if: inputs.push
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Docker metadata
id: meta
uses: docker/metadata-action@80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9 # v6.1.0
with:
images: ${{ inputs.image_name }}
tags: |
type=sha,prefix=sha-,format=short
type=raw,value=latest
flavor: |
suffix=-${{ steps.vars.outputs.arch }},onlatest=true
- name: Build and push
uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0
with:
context: .
file: ${{ inputs.dockerfile }}
platforms: ${{ inputs.platform }}
push: ${{ inputs.push }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: BASE_IMAGE=${{ inputs.base_image }}

View File

@@ -0,0 +1,89 @@
name: Reusable build and merge Docker image (multi-arch)
on:
workflow_call:
inputs:
image_name:
description: "Full image name without tag (e.g. 'ghcr.io/xrplf/xrpld/nix-ubuntu')"
required: true
type: string
dockerfile:
description: "Path to the Dockerfile, relative to the repository root"
required: true
type: string
base_image:
description: "Value passed to the Dockerfile as the BASE_IMAGE build arg"
required: true
type: string
defaults:
run:
shell: bash
jobs:
build:
name: Build ${{ inputs.image_name }}
permissions:
contents: read
packages: write
strategy:
fail-fast: false
matrix:
target:
- platform: linux/amd64
runner: ubuntu-latest
- platform: linux/arm64
runner: ubuntu-24.04-arm
uses: ./.github/workflows/reusable-build-docker-image.yml
with:
image_name: ${{ inputs.image_name }}
dockerfile: ${{ inputs.dockerfile }}
base_image: ${{ inputs.base_image }}
platform: ${{ matrix.target.platform }}
runner: ${{ matrix.target.runner }}
push: ${{ github.repository == 'XRPLF/rippled' && github.event_name == 'push' }}
merge:
name: Merge ${{ inputs.image_name }}
needs: build
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0
- name: Docker metadata
id: meta
uses: docker/metadata-action@80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9 # v6.1.0
with:
images: ${{ inputs.image_name }}
tags: |
type=sha,prefix=sha-,format=short
type=raw,value=latest
- name: Login to GitHub Container Registry
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Create multi-arch manifests
if: ${{ github.repository == 'XRPLF/rippled' && github.event_name == 'push' }}
run: |
for tag in $(jq -cr '.tags[]' <<<"$DOCKER_METADATA_OUTPUT_JSON"); do
docker buildx imagetools create -t "$tag" "${tag}-amd64" "${tag}-arm64"
done
- name: Inspect image
if: ${{ github.repository == 'XRPLF/rippled' && github.event_name == 'push' }}
env:
IMAGE_NAME: ${{ inputs.image_name }}
IMAGE_VERSION: ${{ steps.meta.outputs.version }}
run: |
docker buildx imagetools inspect "${IMAGE_NAME}:${IMAGE_VERSION}"

View File

@@ -57,6 +57,12 @@ on:
type: string type: string
default: "" default: ""
compiler:
description: 'The compiler to use ("gcc" or "clang"). Leave empty for macOS/Windows (uses system default).'
required: false
type: string
default: ""
secrets: secrets:
CODECOV_TOKEN: CODECOV_TOKEN:
description: "The Codecov token to use for uploading coverage reports." description: "The Codecov token to use for uploading coverage reports."
@@ -104,16 +110,16 @@ jobs:
uses: XRPLF/actions/cleanup-workspace@c7d9ce5ebb03c752a354889ecd870cadfc2b1cd4 uses: XRPLF/actions/cleanup-workspace@c7d9ce5ebb03c752a354889ecd870cadfc2b1cd4
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Prepare runner - name: Prepare runner
uses: XRPLF/actions/prepare-runner@90f11ee655d1687824fb8793db770477d52afbab uses: XRPLF/actions/prepare-runner@c47daebb2f9db64ffbac71b47d68a661498d5ce8
with: with:
enable_ccache: ${{ inputs.ccache_enabled }} enable_ccache: ${{ inputs.ccache_enabled }}
- name: Set ccache log file - name: Set ccache log file
if: ${{ inputs.ccache_enabled && runner.debug == '1' }} if: ${{ inputs.ccache_enabled && runner.debug == '1' }}
run: echo "CCACHE_LOGFILE=${{ runner.temp }}/ccache.log" >> "${GITHUB_ENV}" run: echo "CCACHE_LOGFILE=${{ runner.temp }}/ccache.log" >>"${GITHUB_ENV}"
- name: Print build environment - name: Print build environment
uses: XRPLF/actions/print-build-env@59dec886e4afb05a1724443af08baccbc045b574 uses: XRPLF/actions/print-build-env@59dec886e4afb05a1724443af08baccbc045b574
@@ -124,6 +130,12 @@ jobs:
with: with:
subtract: ${{ inputs.nproc_subtract }} subtract: ${{ inputs.nproc_subtract }}
- name: Set compiler environment (Linux)
if: ${{ runner.os == 'Linux' }}
uses: ./.github/actions/set-compiler-env
with:
compiler: ${{ inputs.compiler }}
- name: Setup Conan - name: Setup Conan
env: env:
SANITIZERS: ${{ inputs.sanitizers }} SANITIZERS: ${{ inputs.sanitizers }}
@@ -146,11 +158,11 @@ jobs:
CMAKE_ARGS: ${{ inputs.cmake_args }} CMAKE_ARGS: ${{ inputs.cmake_args }}
run: | run: |
cmake \ cmake \
-G '${{ runner.os == 'Windows' && 'Visual Studio 17 2022' || 'Ninja' }}' \ -G '${{ runner.os == 'Windows' && 'Visual Studio 17 2022' || 'Ninja' }}' \
-DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake \ -DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake \
-DCMAKE_BUILD_TYPE="${BUILD_TYPE}" \ -DCMAKE_BUILD_TYPE="${BUILD_TYPE}" \
${CMAKE_ARGS} \ ${CMAKE_ARGS} \
.. ..
- name: Check protocol autogen files are up-to-date - name: Check protocol autogen files are up-to-date
working-directory: ${{ env.BUILD_DIR }} working-directory: ${{ env.BUILD_DIR }}
@@ -172,32 +184,47 @@ jobs:
cmake --build . --target code_gen cmake --build . --target code_gen
DIFF=$(git -C .. status --porcelain -- include/xrpl/protocol_autogen src/tests/libxrpl/protocol_autogen) DIFF=$(git -C .. status --porcelain -- include/xrpl/protocol_autogen src/tests/libxrpl/protocol_autogen)
if [ -n "${DIFF}" ]; then if [ -n "${DIFF}" ]; then
echo "::error::Generated protocol files are out of date" echo "::error::Generated protocol files are out of date"
git -C .. diff -- include/xrpl/protocol_autogen src/tests/libxrpl/protocol_autogen git -C .. diff -- include/xrpl/protocol_autogen src/tests/libxrpl/protocol_autogen
echo "${MESSAGE}" echo "${MESSAGE}"
exit 1 exit 1
fi fi
- name: Build the binary - name: Build the binary
working-directory: ${{ env.BUILD_DIR }} working-directory: ${{ env.BUILD_DIR }}
env: env:
BUILD_NPROC: ${{ runner.os == 'Linux' && '16' || steps.nproc.outputs.nproc }} BUILD_NPROC: ${{ steps.nproc.outputs.nproc }}
BUILD_TYPE: ${{ inputs.build_type }} BUILD_TYPE: ${{ inputs.build_type }}
CMAKE_TARGET: ${{ inputs.cmake_target }} CMAKE_TARGET: ${{ inputs.cmake_target }}
run: | run: |
cmake \ cmake \
--build . \ --build . \
--config "${BUILD_TYPE}" \ --config "${BUILD_TYPE}" \
--parallel "${BUILD_NPROC}" \ --parallel "${BUILD_NPROC}" \
--target "${CMAKE_TARGET}" --target "${CMAKE_TARGET}"
# This step is needed to allow running in non-Nix environments
- name: Patch binary to use default loader and remove rpath (Linux)
if: ${{ runner.os == 'Linux' && env.SANITIZERS_ENABLED == 'false' }}
run: |
loader="$(/tmp/loader-path.sh)"
patchelf --set-interpreter "${loader}" --remove-rpath "${{ env.BUILD_DIR }}/xrpld"
# We're only running aarch64 Linux builds in Ubuntu-based images, so this is kept simple
- name: Install libatomic (Linux aarch64)
if: ${{ runner.os == 'Linux' && runner.arch == 'ARM64' }}
run: |
apt update --yes
apt install -y --no-install-recommends \
libatomic1
- name: Show ccache statistics - name: Show ccache statistics
if: ${{ inputs.ccache_enabled }} if: ${{ inputs.ccache_enabled }}
run: | run: |
ccache --show-stats -vv ccache --show-stats -vv
if [ '${{ runner.debug }}' = '1' ]; then if [ '${{ runner.debug }}' = '1' ]; then
cat "${CCACHE_LOGFILE}" cat "${CCACHE_LOGFILE}"
curl ${CCACHE_REMOTE_STORAGE%|*}/status || true curl ${CCACHE_REMOTE_STORAGE%|*}/status || true
fi fi
- name: Upload the binary (Linux) - name: Upload the binary (Linux)
@@ -209,15 +236,24 @@ jobs:
retention-days: 3 retention-days: 3
if-no-files-found: error if-no-files-found: error
- name: Upload the test binary (Linux)
if: ${{ github.event.repository.visibility == 'public' && runner.os == 'Linux' }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: xrpl_tests-${{ inputs.config_name }}
path: ${{ env.BUILD_DIR }}/xrpl_tests
retention-days: 3
if-no-files-found: error
- name: Export server definitions - name: Export server definitions
if: ${{ runner.os != 'Windows' && !inputs.build_only && env.VOIDSTAR_ENABLED != 'true' }} if: ${{ runner.os != 'Windows' && !inputs.build_only && env.VOIDSTAR_ENABLED != 'true' }}
working-directory: ${{ env.BUILD_DIR }} working-directory: ${{ env.BUILD_DIR }}
run: | run: |
set -o pipefail set -o pipefail
./xrpld --definitions | python3 -m json.tool > server_definitions.json ./xrpld --definitions | python3 -m json.tool >server_definitions.json
- name: Upload server definitions - name: Upload server definitions
if: ${{ github.event.repository.visibility == 'public' && inputs.config_name == 'debian-bookworm-gcc-13-amd64-release' }} if: ${{ github.event.repository.visibility == 'public' && inputs.config_name == 'debian-gcc-release-amd64' }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with: with:
name: server-definitions name: server-definitions
@@ -231,10 +267,10 @@ jobs:
run: | run: |
ldd ./xrpld ldd ./xrpld
if [ "$(ldd ./xrpld | grep -E '(libstdc\+\+|libgcc)' | wc -l)" -eq 0 ]; then if [ "$(ldd ./xrpld | grep -E '(libstdc\+\+|libgcc)' | wc -l)" -eq 0 ]; then
echo 'The binary is statically linked.' echo 'The binary is statically linked.'
else else
echo 'The binary is dynamically linked.' echo 'The binary is dynamically linked.'
exit 1 exit 1
fi fi
- name: Verify presence of instrumentation (Linux) - name: Verify presence of instrumentation (Linux)
@@ -250,25 +286,17 @@ jobs:
run: | run: |
ASAN_OPTS="include=${GITHUB_WORKSPACE}/sanitizers/suppressions/runtime-asan-options.txt:suppressions=${GITHUB_WORKSPACE}/sanitizers/suppressions/asan.supp" ASAN_OPTS="include=${GITHUB_WORKSPACE}/sanitizers/suppressions/runtime-asan-options.txt:suppressions=${GITHUB_WORKSPACE}/sanitizers/suppressions/asan.supp"
if [[ "${CONFIG_NAME}" == *gcc* ]]; then if [[ "${CONFIG_NAME}" == *gcc* ]]; then
ASAN_OPTS="${ASAN_OPTS}:alloc_dealloc_mismatch=0" ASAN_OPTS="${ASAN_OPTS}:alloc_dealloc_mismatch=0"
fi fi
echo "ASAN_OPTIONS=${ASAN_OPTS}" >> ${GITHUB_ENV} echo "ASAN_OPTIONS=${ASAN_OPTS}" >>${GITHUB_ENV}
echo "TSAN_OPTIONS=include=${GITHUB_WORKSPACE}/sanitizers/suppressions/runtime-tsan-options.txt:suppressions=${GITHUB_WORKSPACE}/sanitizers/suppressions/tsan.supp" >> ${GITHUB_ENV} echo "TSAN_OPTIONS=include=${GITHUB_WORKSPACE}/sanitizers/suppressions/runtime-tsan-options.txt:suppressions=${GITHUB_WORKSPACE}/sanitizers/suppressions/tsan.supp" >>${GITHUB_ENV}
echo "UBSAN_OPTIONS=include=${GITHUB_WORKSPACE}/sanitizers/suppressions/runtime-ubsan-options.txt:suppressions=${GITHUB_WORKSPACE}/sanitizers/suppressions/ubsan.supp" >> ${GITHUB_ENV} echo "UBSAN_OPTIONS=include=${GITHUB_WORKSPACE}/sanitizers/suppressions/runtime-ubsan-options.txt:suppressions=${GITHUB_WORKSPACE}/sanitizers/suppressions/ubsan.supp" >>${GITHUB_ENV}
echo "LSAN_OPTIONS=include=${GITHUB_WORKSPACE}/sanitizers/suppressions/runtime-lsan-options.txt:suppressions=${GITHUB_WORKSPACE}/sanitizers/suppressions/lsan.supp" >> ${GITHUB_ENV} echo "LSAN_OPTIONS=include=${GITHUB_WORKSPACE}/sanitizers/suppressions/runtime-lsan-options.txt:suppressions=${GITHUB_WORKSPACE}/sanitizers/suppressions/lsan.supp" >>${GITHUB_ENV}
- name: Run the separate tests - name: Run the separate tests
if: ${{ !inputs.build_only }} if: ${{ !inputs.build_only }}
working-directory: ${{ env.BUILD_DIR }} working-directory: ${{ runner.os == 'Windows' && format('{0}/{1}', env.BUILD_DIR, inputs.build_type) || env.BUILD_DIR }}
# Windows locks some of the build files while running tests, and parallel jobs can collide run: ./xrpl_tests
env:
BUILD_TYPE: ${{ inputs.build_type }}
PARALLELISM: ${{ runner.os == 'Windows' && '1' || steps.nproc.outputs.nproc }}
run: |
ctest \
--output-on-failure \
-C "${BUILD_TYPE}" \
-j "${PARALLELISM}"
- name: Run the embedded tests - name: Run the embedded tests
if: ${{ !inputs.build_only }} if: ${{ !inputs.build_only }}
@@ -278,8 +306,26 @@ jobs:
run: | run: |
set -o pipefail set -o pipefail
# Coverage builds are slower due to instrumentation; use fewer parallel jobs to avoid flakiness # Coverage builds are slower due to instrumentation; use fewer parallel jobs to avoid flakiness
[ "$COVERAGE_ENABLED" = "true" ] && BUILD_NPROC=$(( BUILD_NPROC - 2 )) [ "$COVERAGE_ENABLED" = "true" ] && BUILD_NPROC=$((BUILD_NPROC - 2))
./xrpld --unittest --unittest-jobs "${BUILD_NPROC}" 2>&1 | tee unittest.log
# The resolver/preload workaround is only correct for the ASan build:
# a regular build doesn't hit the __dn_expand interceptor bug, and must
# NOT have libasan injected. So only preload when xrpld is ASan-built.
#
# libresolv hosts getaddrinfo's resolver helpers (dn_expand, res_*). Under ASan
# these are intercepted via dlsym(RTLD_NEXT, ...), which yields a NULL pointer
# and crashes DNS resolution if libresolv isn't loaded. Linking it guarantees
# the symbols are present; it's a harmless no-op on glibc >= 2.34 (merged into
# libc) and is what the compiler driver already does for sanitizer builds.
# https://github.com/llvm/llvm-project/issues/59007
# https://github.com/google/sanitizers/issues/1592
if ldd ./xrpld | grep -q libasan; then
PRELOAD="$(gcc -print-file-name=libasan.so):/usr/lib/x86_64-linux-gnu/libresolv.so.2"
else
PRELOAD=""
fi
LD_PRELOAD="$PRELOAD" ./xrpld --unittest --unittest-jobs "${BUILD_NPROC}" 2>&1 | tee unittest.log
- name: Show test failure summary - name: Show test failure summary
if: ${{ failure() && !inputs.build_only }} if: ${{ failure() && !inputs.build_only }}
@@ -287,19 +333,19 @@ jobs:
WORKING_DIR: ${{ runner.os == 'Windows' && format('{0}\{1}', env.BUILD_DIR, inputs.build_type) || env.BUILD_DIR }} WORKING_DIR: ${{ runner.os == 'Windows' && format('{0}\{1}', env.BUILD_DIR, inputs.build_type) || env.BUILD_DIR }}
run: | run: |
if [ ! -d "${WORKING_DIR}" ]; then if [ ! -d "${WORKING_DIR}" ]; then
echo "Working directory '${WORKING_DIR}' does not exist." echo "Working directory '${WORKING_DIR}' does not exist."
exit 0 exit 0
fi fi
cd "${WORKING_DIR}" cd "${WORKING_DIR}"
if [ ! -f unittest.log ]; then if [ ! -f unittest.log ]; then
echo "unittest.log not found; embedded tests may not have run." echo "unittest.log not found; embedded tests may not have run."
exit 0 exit 0
fi fi
if ! grep -E "failed" unittest.log; then if ! grep -E "failed" unittest.log; then
echo "Log present but no failure lines found in unittest.log." echo "Log present but no failure lines found in unittest.log."
fi fi
- name: Debug failure (Linux) - name: Debug failure (Linux)
if: ${{ failure() && runner.os == 'Linux' && !inputs.build_only }} if: ${{ failure() && runner.os == 'Linux' && !inputs.build_only }}
@@ -317,14 +363,14 @@ jobs:
BUILD_TYPE: ${{ inputs.build_type }} BUILD_TYPE: ${{ inputs.build_type }}
run: | run: |
cmake \ cmake \
--build . \ --build . \
--config "${BUILD_TYPE}" \ --config "${BUILD_TYPE}" \
--parallel "${BUILD_NPROC}" \ --parallel "${BUILD_NPROC}" \
--target coverage --target coverage
- name: Upload coverage report - name: Upload coverage report
if: ${{ github.repository == 'XRPLF/rippled' && !inputs.build_only && env.COVERAGE_ENABLED == 'true' }} if: ${{ github.repository == 'XRPLF/rippled' && !inputs.build_only && env.COVERAGE_ENABLED == 'true' }}
uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0 uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
with: with:
disable_search: true disable_search: true
disable_telem: true disable_telem: true

View File

@@ -19,13 +19,6 @@ on:
required: true required: true
type: string type: string
strategy_matrix:
# TODO: Support additional strategies, e.g. "ubuntu" for generating all Ubuntu configurations.
description: 'The strategy matrix to use for generating the configurations ("minimal", "all").'
required: false
type: string
default: "minimal"
secrets: secrets:
CODECOV_TOKEN: CODECOV_TOKEN:
description: "The Codecov token to use for uploading coverage reports." description: "The Codecov token to use for uploading coverage reports."
@@ -37,7 +30,6 @@ jobs:
uses: ./.github/workflows/reusable-strategy-matrix.yml uses: ./.github/workflows/reusable-strategy-matrix.yml
with: with:
os: ${{ inputs.os }} os: ${{ inputs.os }}
strategy_matrix: ${{ inputs.strategy_matrix }}
# Build and test the binary for each configuration. # Build and test the binary for each configuration.
build-test-config: build-test-config:
@@ -47,7 +39,6 @@ jobs:
strategy: strategy:
fail-fast: ${{ github.event_name == 'merge_group' }} fail-fast: ${{ github.event_name == 'merge_group' }}
matrix: ${{ fromJson(needs.generate-matrix.outputs.matrix) }} matrix: ${{ fromJson(needs.generate-matrix.outputs.matrix) }}
max-parallel: 10
with: with:
build_only: ${{ matrix.build_only }} build_only: ${{ matrix.build_only }}
build_type: ${{ matrix.build_type }} build_type: ${{ matrix.build_type }}
@@ -55,8 +46,9 @@ jobs:
cmake_args: ${{ matrix.cmake_args }} cmake_args: ${{ matrix.cmake_args }}
cmake_target: ${{ matrix.cmake_target }} cmake_target: ${{ matrix.cmake_target }}
runs_on: ${{ toJSON(matrix.architecture.runner) }} runs_on: ${{ toJSON(matrix.architecture.runner) }}
image: ${{ contains(matrix.architecture.platform, 'linux') && format('ghcr.io/xrplf/ci/{0}-{1}:{2}-{3}-sha-{4}', matrix.os.distro_name, matrix.os.distro_version, matrix.os.compiler_name, matrix.os.compiler_version, matrix.os.image_sha) || '' }} image: ${{ matrix.image || '' }}
config_name: ${{ matrix.config_name }} config_name: ${{ matrix.config_name }}
sanitizers: ${{ matrix.sanitizers }} sanitizers: ${{ matrix.sanitizers }}
compiler: ${{ matrix.compiler || '' }}
secrets: secrets:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

View File

@@ -18,7 +18,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Check levelization - name: Check levelization
run: python .github/scripts/levelization/generate.py run: python .github/scripts/levelization/generate.py
- name: Check for differences - name: Check for differences
@@ -38,9 +38,9 @@ jobs:
run: | run: |
DIFF=$(git status --porcelain) DIFF=$(git status --porcelain)
if [ -n "${DIFF}" ]; then if [ -n "${DIFF}" ]; then
# Print the differences to give the contributor a hint about what to # Print the differences to give the contributor a hint about what to
# expect when running levelization on their own machine. # expect when running levelization on their own machine.
git diff git diff
echo "${MESSAGE}" echo "${MESSAGE}"
exit 1 exit 1
fi fi

View File

@@ -18,7 +18,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Check definitions - name: Check definitions
run: .github/scripts/rename/definitions.sh . run: .github/scripts/rename/definitions.sh .
- name: Check copyright notices - name: Check copyright notices
@@ -48,9 +48,9 @@ jobs:
run: | run: |
DIFF=$(git status --porcelain) DIFF=$(git status --porcelain)
if [ -n "${DIFF}" ]; then if [ -n "${DIFF}" ]; then
# Print the differences to give the contributor a hint about what to # Print the differences to give the contributor a hint about what to
# expect when running the renaming scripts on their own machine. # expect when running the renaming scripts on their own machine.
git diff git diff
echo "${MESSAGE}" echo "${MESSAGE}"
exit 1 exit 1
fi fi

View File

@@ -29,23 +29,23 @@ jobs:
if: ${{ inputs.check_only_changed }} if: ${{ inputs.check_only_changed }}
permissions: permissions:
contents: read contents: read
uses: XRPLF/actions/.github/workflows/determine-tidy-files.yml@224f3c48d3014d082a1129237b8291ff0b0a331f uses: XRPLF/actions/.github/workflows/determine-tidy-files.yml@312aaab296060ff89d7f798dcab59f019bea6e02
run-clang-tidy: run-clang-tidy:
name: Run clang tidy name: Run clang tidy
needs: [determine-files] 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: ${{ always() && !cancelled() && (!inputs.check_only_changed || needs.determine-files.outputs.cpp_changed_files != '' || needs.determine-files.outputs.clang_tidy_config_changed == 'true') }}
runs-on: ["self-hosted", "Linux", "X64", "heavy"] runs-on: ["self-hosted", "Linux", "X64", "heavy"]
container: "ghcr.io/xrplf/ci/debian-trixie:clang-21-sha-53033a2" container: "ghcr.io/xrplf/xrpld/nix-debian:sha-63ffdc3"
permissions: permissions:
contents: read contents: read
issues: write issues: write
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Prepare runner - name: Prepare runner
uses: XRPLF/actions/prepare-runner@90f11ee655d1687824fb8793db770477d52afbab uses: XRPLF/actions/prepare-runner@c47daebb2f9db64ffbac71b47d68a661498d5ce8
with: with:
enable_ccache: false enable_ccache: false
@@ -56,6 +56,11 @@ jobs:
uses: XRPLF/actions/get-nproc@cf0433aa74563aead044a1e395610c96d65a37cf uses: XRPLF/actions/get-nproc@cf0433aa74563aead044a1e395610c96d65a37cf
id: nproc id: nproc
- name: Set compiler environment
uses: ./.github/actions/set-compiler-env
with:
compiler: clang
- name: Setup Conan - name: Setup Conan
uses: ./.github/actions/setup-conan uses: ./.github/actions/setup-conan
@@ -70,13 +75,13 @@ jobs:
working-directory: ${{ env.BUILD_DIR }} working-directory: ${{ env.BUILD_DIR }}
run: | run: |
cmake \ cmake \
-G 'Ninja' \ -G 'Ninja' \
-DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake \ -DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake \
-DCMAKE_BUILD_TYPE="${BUILD_TYPE}" \ -DCMAKE_BUILD_TYPE="${BUILD_TYPE}" \
-Dtests=ON \ -Dtests=ON \
-Dwerr=ON \ -Dwerr=ON \
-Dxrpld=ON \ -Dxrpld=ON \
.. ..
# clang-tidy needs headers generated from proto files # clang-tidy needs headers generated from proto files
- name: Build libxrpl.libpb - name: Build libxrpl.libpb
@@ -133,7 +138,7 @@ jobs:
- name: Write issue header - name: Write issue header
if: ${{ steps.run_clang_tidy.outcome != 'success' }} if: ${{ steps.run_clang_tidy.outcome != 'success' }}
run: | run: |
cat > "${ISSUE_FILE}" <<EOF cat >"${ISSUE_FILE}" <<EOF
## Clang-tidy Check Failed ## Clang-tidy Check Failed
### Clang-tidy Output: ### Clang-tidy Output:
@@ -144,30 +149,30 @@ jobs:
if: ${{ steps.run_clang_tidy.outcome != 'success' }} if: ${{ steps.run_clang_tidy.outcome != 'success' }}
run: | run: |
if [ -f "${OUTPUT_FILE}" ]; then if [ -f "${OUTPUT_FILE}" ]; then
# Extract lines containing 'error:', 'warning:', or 'note:' # Extract lines containing 'error:', 'warning:', or 'note:'
grep -E '(error:|warning:|note:)' "${OUTPUT_FILE}" > filtered-output.txt || true grep -E '(error:|warning:|note:)' "${OUTPUT_FILE}" >filtered-output.txt || true
# If filtered output is empty, use original (might be a different error format) # If filtered output is empty, use original (might be a different error format)
if [ ! -s filtered-output.txt ]; then if [ ! -s filtered-output.txt ]; then
cp "${OUTPUT_FILE}" filtered-output.txt cp "${OUTPUT_FILE}" filtered-output.txt
fi fi
# Truncate if too large # Truncate if too large
head -c 60000 filtered-output.txt >> "${ISSUE_FILE}" head -c 60000 filtered-output.txt >>"${ISSUE_FILE}"
if [ "$(wc -c < filtered-output.txt)" -gt 60000 ]; then if [ "$(wc -c <filtered-output.txt)" -gt 60000 ]; then
echo "" >> "${ISSUE_FILE}" echo "" >>"${ISSUE_FILE}"
echo "... (output truncated, see artifacts for full output)" >> "${ISSUE_FILE}" echo "... (output truncated, see artifacts for full output)" >>"${ISSUE_FILE}"
fi fi
rm filtered-output.txt rm filtered-output.txt
else else
echo "No output file found" >> "${ISSUE_FILE}" echo "No output file found" >>"${ISSUE_FILE}"
fi fi
- name: Append issue footer - name: Append issue footer
if: ${{ steps.run_clang_tidy.outcome != 'success' }} if: ${{ steps.run_clang_tidy.outcome != 'success' }}
run: | run: |
cat >> "${ISSUE_FILE}" <<EOF cat >>"${ISSUE_FILE}" <<EOF
\`\`\` \`\`\`
--- ---
@@ -176,7 +181,7 @@ jobs:
- name: Create issue - name: Create issue
if: ${{ steps.run_clang_tidy.outcome != 'success' && inputs.create_issue_on_failure }} if: ${{ steps.run_clang_tidy.outcome != 'success' && inputs.create_issue_on_failure }}
uses: XRPLF/actions/create-issue@fbcc16eb7f20dc3199eaf1aed0d3523a5ba9008c uses: XRPLF/actions/create-issue@2b8bc36af85b88bca0dd7bfac2e2dc05f94ad712
with: with:
title: "Clang-tidy check failed" title: "Clang-tidy check failed"
body_file: ${{ env.ISSUE_FILE }} body_file: ${{ env.ISSUE_FILE }}

97
.github/workflows/reusable-package.yml vendored Normal file
View File

@@ -0,0 +1,97 @@
# Build Linux packages (DEB and RPM) from pre-built binary artifacts.
# Discovers which configurations to package from linux.json (configs in
# "package_configs") and fans out one job per distro. Only linux/amd64 is
# supported; the runner is hardcoded in the job below.
name: Package
on:
workflow_call:
inputs:
pkg_release:
description: "Package release number. Increment when repackaging the same executable."
required: false
type: string
default: "1"
defaults:
run:
shell: bash
env:
BUILD_DIR: build
jobs:
generate-matrix:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.generate.outputs.matrix }}
steps:
- name: Checkout repository
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Set up Python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.13"
- name: Generate packaging matrix
id: generate
working-directory: .github/scripts/strategy-matrix
run: ./generate.py --packaging >>"${GITHUB_OUTPUT}"
generate-version:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.version }}
steps:
- name: Checkout repository
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
sparse-checkout: |
.github/actions/generate-version
src/libxrpl/protocol/BuildInfo.cpp
- name: Generate version
id: version
uses: ./.github/actions/generate-version
package:
needs: [generate-matrix, generate-version]
if: ${{ github.event.repository.visibility == 'public' }}
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.generate-matrix.outputs.matrix) }}
name: "${{ matrix.artifact_name }}"
permissions:
contents: read
runs-on: ["self-hosted", "Linux", "X64", "heavy"]
container: ${{ matrix.image }}
timeout-minutes: 30
steps:
- name: Checkout repository
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Download pre-built binary
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: ${{ matrix.artifact_name }}
path: ${{ env.BUILD_DIR }}
- name: Make binary executable
run: chmod +x "${BUILD_DIR}/xrpld"
- name: Build package
env:
PKG_VERSION: ${{ needs.generate-version.outputs.version }}
PKG_RELEASE: ${{ inputs.pkg_release }}
run: ./package/build_pkg.sh
- name: Upload package artifact
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: ${{ matrix.artifact_name }}-pkg-${{ needs.generate-version.outputs.version }}
path: |
${{ env.BUILD_DIR }}/debbuild/*.deb
${{ env.BUILD_DIR }}/debbuild/*.ddeb
${{ env.BUILD_DIR }}/rpmbuild/RPMS/**/*.rpm
if-no-files-found: error

View File

@@ -4,15 +4,9 @@ on:
workflow_call: workflow_call:
inputs: inputs:
os: os:
description: 'The operating system to use for the build ("linux", "macos", "windows").' description: 'The operating system to use for the build ("linux", "macos", "windows", or empty for all).'
required: false required: false
type: string type: string
strategy_matrix:
# TODO: Support additional strategies, e.g. "ubuntu" for generating all Ubuntu configurations.
description: 'The strategy matrix to use for generating the configurations ("minimal", "all").'
required: false
type: string
default: "minimal"
outputs: outputs:
matrix: matrix:
description: "The generated strategy matrix." description: "The generated strategy matrix."
@@ -29,17 +23,16 @@ jobs:
matrix: ${{ steps.generate.outputs.matrix }} matrix: ${{ steps.generate.outputs.matrix }}
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Set up Python - name: Set up Python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with: with:
python-version: 3.13 python-version: "3.13"
- name: Generate strategy matrix - name: Generate strategy matrix
working-directory: .github/scripts/strategy-matrix working-directory: .github/scripts/strategy-matrix
id: generate id: generate
env: env:
GENERATE_CONFIG: ${{ inputs.os != '' && format('--config={0}.json', inputs.os) || '' }} GENERATE_CONFIG: ${{ inputs.os != '' && format('--config={0}', inputs.os) || '' }}
GENERATE_OPTION: ${{ inputs.strategy_matrix == 'all' && '--all' || '' }} run: ./generate.py ${GENERATE_CONFIG} >>"${GITHUB_OUTPUT}"
run: ./generate.py ${GENERATE_OPTION} ${GENERATE_CONFIG} >> "${GITHUB_OUTPUT}"

View File

@@ -40,10 +40,10 @@ defaults:
jobs: jobs:
upload: upload:
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: ghcr.io/xrplf/ci/ubuntu-noble:gcc-13-sha-5dd7158 container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-63ffdc3
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Generate build version number - name: Generate build version number
id: version id: version

View File

@@ -48,8 +48,6 @@ jobs:
# Generate the strategy matrix to be used by the following job. # Generate the strategy matrix to be used by the following job.
generate-matrix: generate-matrix:
uses: ./.github/workflows/reusable-strategy-matrix.yml uses: ./.github/workflows/reusable-strategy-matrix.yml
with:
strategy_matrix: ${{ github.event_name == 'pull_request' && 'minimal' || 'all' }}
# Build and upload the dependencies for each configuration. # Build and upload the dependencies for each configuration.
run-upload-conan-deps: run-upload-conan-deps:
@@ -58,19 +56,18 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: ${{ fromJson(needs.generate-matrix.outputs.matrix) }} matrix: ${{ fromJson(needs.generate-matrix.outputs.matrix) }}
max-parallel: 10
runs-on: ${{ matrix.architecture.runner }} runs-on: ${{ matrix.architecture.runner }}
container: ${{ contains(matrix.architecture.platform, 'linux') && format('ghcr.io/xrplf/ci/{0}-{1}:{2}-{3}-sha-{4}', matrix.os.distro_name, matrix.os.distro_version, matrix.os.compiler_name, matrix.os.compiler_version, matrix.os.image_sha) || null }} container: ${{ matrix.image || null }}
steps: steps:
- name: Cleanup workspace (macOS and Windows) - name: Cleanup workspace (macOS and Windows)
if: ${{ runner.os == 'macOS' || runner.os == 'Windows' }} if: ${{ runner.os == 'macOS' || runner.os == 'Windows' }}
uses: XRPLF/actions/cleanup-workspace@c7d9ce5ebb03c752a354889ecd870cadfc2b1cd4 uses: XRPLF/actions/cleanup-workspace@c7d9ce5ebb03c752a354889ecd870cadfc2b1cd4
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Prepare runner - name: Prepare runner
uses: XRPLF/actions/prepare-runner@90f11ee655d1687824fb8793db770477d52afbab uses: XRPLF/actions/prepare-runner@c47daebb2f9db64ffbac71b47d68a661498d5ce8
with: with:
enable_ccache: false enable_ccache: false
@@ -83,6 +80,12 @@ jobs:
with: with:
subtract: ${{ env.NPROC_SUBTRACT }} subtract: ${{ env.NPROC_SUBTRACT }}
- name: Set compiler environment (Linux)
if: ${{ runner.os == 'Linux' }}
uses: ./.github/actions/set-compiler-env
with:
compiler: ${{ matrix.compiler }}
- name: Setup Conan - name: Setup Conan
env: env:
SANITIZERS: ${{ matrix.sanitizers }} SANITIZERS: ${{ matrix.sanitizers }}

View File

@@ -37,37 +37,50 @@ repos:
exclude: ^include/xrpl/protocol_autogen/(transactions|ledger_entries)/ exclude: ^include/xrpl/protocol_autogen/(transactions|ledger_entries)/
- repo: https://github.com/pre-commit/mirrors-clang-format - repo: https://github.com/pre-commit/mirrors-clang-format
rev: cd481d7b0bfb5c7b3090c21846317f9a8262e891 # frozen: v22.1.0 rev: dd18dad857d6133e90bbe478f4f2f22ec0030269 # frozen: v22.1.5
hooks: hooks:
- id: clang-format - id: clang-format
args: [--style=file] args: [--style=file]
"types_or": [c++, c, proto] "types_or": [c++, c, proto]
exclude: ^include/xrpl/protocol_autogen/(transactions|ledger_entries)/ exclude: ^include/xrpl/protocol_autogen/(transactions|ledger_entries)/
- repo: https://github.com/BlankSpruce/gersemi - repo: https://github.com/BlankSpruce/gersemi-pre-commit
rev: 0.26.0 rev: faadd6a9d852369ca94f4d15b2404c967ba8cb01 # frozen: 0.27.6
hooks: hooks:
- id: gersemi - id: gersemi
- repo: https://github.com/rbubley/mirrors-prettier - repo: https://github.com/rbubley/mirrors-prettier
rev: c2bc67fe8f8f549cc489e00ba8b45aa18ee713b1 # frozen: v3.8.1 rev: 515f543f5718ebfd6ce22e16708bb32c68ff96e1 # frozen: v3.8.3
hooks: hooks:
- id: prettier - id: prettier
args: [--end-of-line=auto] args: [--end-of-line=auto]
- repo: https://github.com/psf/black-pre-commit-mirror - repo: https://github.com/psf/black-pre-commit-mirror
rev: ea488cebbfd88a5f50b8bd95d5c829d0bb76feb8 # frozen: 26.1.0 rev: 4160603246a6b365d4a2af661c6d71b0a0f50478 # frozen: 26.5.1
hooks: hooks:
- id: black - id: black
- repo: https://github.com/openstack/bashate - repo: https://github.com/scop/pre-commit-shfmt
rev: 5798d24d571676fc407e81df574c1ef57b520f23 # frozen: 2.1.1 rev: 05c1426671b9237fb5e1444dd63aa5731bec0dfb # frozen: v3.13.1-1
hooks: hooks:
- id: bashate - id: shfmt
args: ["--ignore=E006"] args: [--write, --indent=4, --case-indent=true]
- repo: local
hooks:
- id: format-inline-bash-workflows
name: "format `run:` blocks in workflows/actions"
entry: ./.github/scripts/format-inline-bash.py
language: python
files: ^\.github/(workflows|actions)/.*\.ya?ml$
- id: format-inline-bash-markdown
name: "format ```bash blocks in markdown"
entry: ./.github/scripts/format-inline-bash.py
language: python
files: \.md$
- repo: https://github.com/streetsidesoftware/cspell-cli - repo: https://github.com/streetsidesoftware/cspell-cli
rev: a42085ade523f591dca134379a595e7859986445 # frozen: v9.7.0 rev: 4643f154907327ee0a2c7038f0296e0dd77d9776 # frozen: v10.0.0
hooks: hooks:
- id: cspell # Spell check changed files - id: cspell # Spell check changed files
exclude: | exclude: |

View File

@@ -151,8 +151,8 @@ git init
git remote add origin git@github.com:XRPLF/conan-center-index.git git remote add origin git@github.com:XRPLF/conan-center-index.git
git sparse-checkout init git sparse-checkout init
for recipe in "${recipes[@]}"; do for recipe in "${recipes[@]}"; do
echo "Checking out recipe '${recipe}'..." echo "Checking out recipe '${recipe}'..."
git sparse-checkout add recipes/${recipe} git sparse-checkout add recipes/${recipe}
done done
git fetch origin master git fetch origin master
git checkout master git checkout master
@@ -180,7 +180,7 @@ the new recipe will be automatically pulled from the official Conan Center.
If you see an error similar to the following after running `conan profile show`: If you see an error similar to the following after running `conan profile show`:
```bash ```text
ERROR: Invalid setting '17' is not a valid 'settings.compiler.version' value. ERROR: Invalid setting '17' is not a valid 'settings.compiler.version' value.
Possible values are ['5.0', '5.1', '6.0', '6.1', '7.0', '7.3', '8.0', '8.1', Possible values are ['5.0', '5.1', '6.0', '6.1', '7.0', '7.3', '8.0', '8.1',
'9.0', '9.1', '10.0', '11.0', '12.0', '13', '13.0', '13.1', '14', '14.0', '15', '9.0', '9.1', '10.0', '11.0', '12.0', '13', '13.0', '13.1', '14', '14.0', '15',
@@ -427,16 +427,19 @@ install ccache --version 4.11.3 --allow-downgrade`.
Single-config generators: Single-config generators:
``` ```
cmake --build . cmake --build . --parallel N
``` ```
Multi-config generators: Multi-config generators:
``` ```
cmake --build . --config Release cmake --build . --config Release --parallel N
cmake --build . --config Debug cmake --build . --config Debug --parallel N
``` ```
Replace the `--parallel` parameter N with the desired number of parallel jobs. A common starting point is half of the number of available CPU
cores.
5. Test xrpld. 5. Test xrpld.
Single-config generators: Single-config generators:

View File

@@ -134,6 +134,7 @@ endif()
include(XrplCore) include(XrplCore)
include(XrplProtocolAutogen) include(XrplProtocolAutogen)
include(XrplInstall) include(XrplInstall)
include(XrplPackaging)
include(XrplValidatorKeys) include(XrplValidatorKeys)
if(tests) if(tests)

View File

@@ -1,8 +1,8 @@
#!/bin/bash #!/bin/bash
if [[ $# -ne 1 || "$1" == "--help" || "$1" == "-h" ]]; then if [[ $# -ne 1 || "$1" == "--help" || "$1" == "-h" ]]; then
name=$( basename $0 ) name=$(basename $0)
cat <<- USAGE cat <<-USAGE
Usage: $name <username> Usage: $name <username>
Where <username> is the Github username of the upstream repo. e.g. XRPLF Where <username> is the Github username of the upstream repo. e.g. XRPLF
@@ -14,7 +14,7 @@ fi
shift shift
user="$1" user="$1"
# Get the origin URL. Expect it be an SSH-style URL # Get the origin URL. Expect it be an SSH-style URL
origin=$( git remote get-url origin ) origin=$(git remote get-url origin)
if [[ "${origin}" == "" ]]; then if [[ "${origin}" == "" ]]; then
echo Invalid origin remote >&2 echo Invalid origin remote >&2
exit 1 exit 1
@@ -22,11 +22,11 @@ fi
# echo "Origin: ${origin}" # echo "Origin: ${origin}"
# Parse the origin # Parse the origin
ifs_orig="${IFS}" ifs_orig="${IFS}"
IFS=':' read remote originpath <<< "${origin}" IFS=':' read remote originpath <<<"${origin}"
# echo "Remote: ${remote}, Originpath: ${originpath}" # echo "Remote: ${remote}, Originpath: ${originpath}"
IFS='@' read sshuser server <<< "${remote}" IFS='@' read sshuser server <<<"${remote}"
# echo "SSHUser: ${sshuser}, Server: ${server}" # echo "SSHUser: ${sshuser}, Server: ${server}"
IFS='/' read originuser repo <<< "${originpath}" IFS='/' read originuser repo <<<"${originpath}"
# echo "Originuser: ${originuser}, Repo: ${repo}" # echo "Originuser: ${originuser}, Repo: ${repo}"
if [[ "${sshuser}" == "" || "${server}" == "" || "${originuser}" == "" || "${repo}" == "" ]]; then if [[ "${sshuser}" == "" || "${server}" == "" || "${originuser}" == "" || "${repo}" == "" ]]; then
echo "Can't parse origin URL: ${origin}" >&2 echo "Can't parse origin URL: ${origin}" >&2
@@ -35,9 +35,9 @@ fi
upstream="https://${server}/${user}/${repo}" upstream="https://${server}/${user}/${repo}"
upstreampush="${remote}:${user}/${repo}" upstreampush="${remote}:${user}/${repo}"
upstreamgroup="upstream upstream-push" upstreamgroup="upstream upstream-push"
current=$( git remote get-url upstream 2>/dev/null ) current=$(git remote get-url upstream 2>/dev/null)
currentpush=$( git remote get-url upstream-push 2>/dev/null ) currentpush=$(git remote get-url upstream-push 2>/dev/null)
currentgroup=$( git config remotes.upstreams ) currentgroup=$(git config remotes.upstreams)
if [[ "${current}" == "${upstream}" ]]; then if [[ "${current}" == "${upstream}" ]]; then
echo "Upstream already set up correctly. Skip" echo "Upstream already set up correctly. Skip"
elif [[ -n "${current}" && "${current}" != "${upstream}" && "${current}" != "${upstreampush}" ]]; then elif [[ -n "${current}" && "${current}" != "${upstream}" && "${current}" != "${upstreampush}" ]]; then
@@ -45,9 +45,9 @@ elif [[ -n "${current}" && "${current}" != "${upstream}" && "${current}" != "${u
else else
if [[ "${current}" == "${upstreampush}" ]]; then if [[ "${current}" == "${upstreampush}" ]]; then
echo "Upstream set to dangerous push URL. Update." echo "Upstream set to dangerous push URL. Update."
_run git remote rename upstream upstream-push || \ _run git remote rename upstream upstream-push ||
_run git remote remove upstream _run git remote remove upstream
currentpush=$( git remote get-url upstream-push 2>/dev/null ) currentpush=$(git remote get-url upstream-push 2>/dev/null)
fi fi
_run git remote add upstream "${upstream}" _run git remote add upstream "${upstream}"
fi fi

View File

@@ -1,8 +1,8 @@
#!/bin/bash #!/bin/bash
if [[ $# -lt 3 || "$1" == "--help" || "$1" = "-h" ]]; then if [[ $# -lt 3 || "$1" == "--help" || "$1" = "-h" ]]; then
name=$( basename $0 ) name=$(basename $0)
cat <<- USAGE cat <<-USAGE
Usage: $name workbranch base/branch user/branch [user/branch [...]] Usage: $name workbranch base/branch user/branch [user/branch [...]]
* workbranch will be created locally from base/branch * workbranch will be created locally from base/branch
@@ -16,7 +16,7 @@ fi
work="$1" work="$1"
shift shift
branches=( $( echo "${@}" | sed "s/:/\//" ) ) branches=($(echo "${@}" | sed "s/:/\//"))
base="${branches[0]}" base="${branches[0]}"
unset branches[0] unset branches[0]
@@ -24,10 +24,10 @@ set -e
users=() users=()
for b in "${branches[@]}"; do for b in "${branches[@]}"; do
users+=( $( echo $b | cut -d/ -f1 ) ) users+=($(echo $b | cut -d/ -f1))
done done
users=( $( printf '%s\n' "${users[@]}" | sort -u ) ) users=($(printf '%s\n' "${users[@]}" | sort -u))
git fetch --multiple upstreams "${users[@]}" git fetch --multiple upstreams "${users[@]}"
git checkout -B "$work" --no-track "$base" git checkout -B "$work" --no-track "$base"
@@ -40,7 +40,7 @@ done
# Make sure the commits look right # Make sure the commits look right
git log --show-signature "$base..HEAD" git log --show-signature "$base..HEAD"
parts=( $( echo $base | sed "s/\// /" ) ) parts=($(echo $base | sed "s/\// /"))
repo="${parts[0]}" repo="${parts[0]}"
b="${parts[1]}" b="${parts[1]}"
push=$repo push=$repo
@@ -50,7 +50,7 @@ fi
if [[ "$repo" == "upstream" ]]; then if [[ "$repo" == "upstream" ]]; then
repo="upstreams" repo="upstreams"
fi fi
cat << PUSH cat <<PUSH
------------------------------------------------------------------- -------------------------------------------------------------------
This script will not push. Verify everything is correct, then push This script will not push. Verify everything is correct, then push

View File

@@ -1,8 +1,8 @@
#!/bin/bash #!/bin/bash
if [[ $# -ne 3 || "$1" == "--help" || "$1" = "-h" ]]; then if [[ $# -ne 3 || "$1" == "--help" || "$1" = "-h" ]]; then
name=$( basename $0 ) name=$(basename $0)
cat <<- USAGE cat <<-USAGE
Usage: $name workbranch base/branch version Usage: $name workbranch base/branch version
* workbranch will be created locally from base/branch. If it exists, * workbranch will be created locally from base/branch. If it exists,
@@ -16,7 +16,7 @@ fi
work="$1" work="$1"
shift shift
base=$( echo "$1" | sed "s/:/\//" ) base=$(echo "$1" | sed "s/:/\//")
shift shift
version=$1 version=$1
@@ -28,16 +28,16 @@ git fetch upstreams
git checkout -B "${work}" --no-track "${base}" git checkout -B "${work}" --no-track "${base}"
push=$( git rev-parse --abbrev-ref --symbolic-full-name '@{push}' \ push=$(git rev-parse --abbrev-ref --symbolic-full-name '@{push}' \
2>/dev/null ) || true 2>/dev/null) || true
if [[ "${push}" != "" ]]; then if [[ "${push}" != "" ]]; then
echo "Warning: ${push} may already exist." echo "Warning: ${push} may already exist."
fi fi
build=$( find -name BuildInfo.cpp ) build=$(find -name BuildInfo.cpp)
sed 's/\(^.*versionString =\).*$/\1 "'${version}'"/' ${build} > version.cpp && \ sed 's/\(^.*versionString =\).*$/\1 "'${version}'"/' ${build} >version.cpp &&
diff "${build}" version.cpp && exit 1 || \ diff "${build}" version.cpp && exit 1 ||
mv -vi version.cpp ${build} mv -vi version.cpp ${build}
git diff git diff
@@ -47,7 +47,7 @@ git commit -S -m "Set version to ${version}"
git log --oneline --first-parent ${base}^.. git log --oneline --first-parent ${base}^..
cat << PUSH cat <<PUSH
------------------------------------------------------------------- -------------------------------------------------------------------
This script will not push. Verify everything is correct, then push This script will not push. Verify everything is correct, then push

View File

@@ -168,7 +168,13 @@ def main():
if not os.environ.get("TIDY"): if not os.environ.get("TIDY"):
return 0 return 0
repo_root = Path(__file__).parent.parent repo_root = Path(
subprocess.check_output(
["git", "rev-parse", "--show-toplevel"],
cwd=Path(__file__).parent,
text=True,
).strip()
)
files = staged_files(repo_root) files = staged_files(repo_root)
if not files: if not files:
return 0 return 0

View File

@@ -28,7 +28,7 @@
# https://vl.ripple.com # https://vl.ripple.com
# https://unl.xrplf.org # https://unl.xrplf.org
# http://127.0.0.1:8000 # http://127.0.0.1:8000
# file:///etc/opt/xrpld/vl.txt # file:///etc/xrpld/vl.txt
# #
# [validator_list_keys] # [validator_list_keys]
# #

View File

@@ -527,6 +527,17 @@
# #
# The current default (which is subject to change) is 300 seconds. # The current default (which is subject to change) is 300 seconds.
# #
# verify_endpoints = <0 | 1>
#
# If set to 0, the server will skip validation of endpoint
# addresses received in TMEndpoints peer protocol messages,
# allowing addresses that are not publicly routable or have a
# port of 0. The default is 1 (verification enabled).
#
# WARNING: Disabling this option is a security risk and should
# only be used for local testing and debugging. Do not disable
# on mainnet.
#
# #
# [transaction_queue] EXPERIMENTAL # [transaction_queue] EXPERIMENTAL
# #
@@ -942,6 +953,21 @@
# #
# Optional keys for NuDB and RocksDB: # Optional keys for NuDB and RocksDB:
# #
# cache_size Size of cache for database records. Default is 16384.
# Setting this value to 0 will use the default value.
#
# cache_age Length of time in minutes to keep database records
# cached. Default is 5 minutes. Setting this value to
# 0 will use the default value.
#
# Note: if cache_size or cache_age is not specified,
# default values will be used for the unspecified
# parameter.
#
# Note: the cache will not be created if online_delete
# is specified, because the rotating NodeStore does
# not use this cache).
#
# fast_load Boolean. If set, load the last persisted ledger # fast_load Boolean. If set, load the last persisted ledger
# from disk upon process start before syncing to # from disk upon process start before syncing to
# the network. This is likely to improve performance # the network. This is likely to improve performance
@@ -1455,10 +1481,7 @@ admin = 127.0.0.1
protocol = http protocol = http
[port_peer] [port_peer]
# Many servers still use the legacy port of 51235, so for backward-compatibility port = 2459
# we maintain that port number here. However, for new servers we recommend
# changing this to the default port of 2459.
port = 51235
ip = 0.0.0.0 ip = 0.0.0.0
# alternatively, to accept connections on IPv4 + IPv6, use: # alternatively, to accept connections on IPv4 + IPv6, use:
#ip = :: #ip = ::

View File

@@ -1,22 +0,0 @@
include(isolate_headers)
function(xrpl_add_test name)
set(target ${PROJECT_NAME}.test.${name})
file(
GLOB_RECURSE sources
CONFIGURE_DEPENDS
"${CMAKE_CURRENT_SOURCE_DIR}/${name}/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/${name}.cpp"
)
add_executable(${target} ${ARGN} ${sources})
isolate_headers(
${target}
"${CMAKE_SOURCE_DIR}"
"${CMAKE_SOURCE_DIR}/tests/${name}"
PRIVATE
)
add_test(NAME ${target} COMMAND ${target})
endfunction()

View File

@@ -145,13 +145,39 @@ else()
INTERFACE INTERFACE
-rdynamic -rdynamic
$<$<BOOL:${is_linux}>:-Wl,-z,relro,-z,now,--build-id> $<$<BOOL:${is_linux}>:-Wl,-z,relro,-z,now,--build-id>
# link to static libc/c++ iff: * static option set and * NOT APPLE (AppleClang does not support static # link to static libc/c++ if:
# libc/c++) and * NOT SANITIZERS (sanitizers typically don't work with static libc/c++) # * static option set and
$<$<AND:$<BOOL:${static}>,$<NOT:$<BOOL:${APPLE}>>,$<NOT:$<BOOL:${SANITIZERS_ENABLED}>>>: # * NOT APPLE (AppleClang does not support static libc/c++)
$<$<AND:$<BOOL:${static}>,$<NOT:$<BOOL:${APPLE}>>>:
-static-libstdc++ -static-libstdc++
-static-libgcc -static-libgcc
> >
) )
# Keep -stdlib=libstdc++ off the compile commands, but preserve it for linking.
#
# Conan turns `compiler.libcxx=libstdc++` into `-stdlib=libstdc++` and puts it in
# CMAKE_CXX_FLAGS, which CMake passes to BOTH compile and link steps. On a normal Clang
# the compile step consumes it while choosing the C++ stdlib include paths. The Nixpkgs
# Clang wrapper supplies those paths itself (via -nostdinc++), so at compile time the
# flag is unused -> Clang errors under our -Werror. At link time the flag IS consumed
# (it selects the C++ runtime), so we move it there instead of dropping it entirely.
get_filename_component(_cxx_real "${CMAKE_CXX_COMPILER}" REALPATH)
if(
_cxx_real MATCHES "^/nix/store/"
AND is_linux
AND is_clang
AND CMAKE_CXX_FLAGS MATCHES "stdlib=libstdc"
)
string(
REPLACE "-stdlib=libstdc++"
""
CMAKE_CXX_FLAGS
"${CMAKE_CXX_FLAGS}"
)
string(STRIP "${CMAKE_CXX_FLAGS}" CMAKE_CXX_FLAGS)
add_link_options($<$<LINK_LANGUAGE:CXX>:-stdlib=libstdc++>)
endif()
endif() endif()
# Antithesis instrumentation will only be built and deployed using machines running Linux. # Antithesis instrumentation will only be built and deployed using machines running Linux.

View File

@@ -47,7 +47,7 @@ setup_target_for_coverage_gcovr(
"include/xrpl/beast/test" "include/xrpl/beast/test"
"include/xrpl/beast/unit_test" "include/xrpl/beast/unit_test"
"${CMAKE_BINARY_DIR}/pb-xrpl.libpb" "${CMAKE_BINARY_DIR}/pb-xrpl.libpb"
DEPENDENCIES xrpld xrpl.tests DEPENDENCIES xrpld xrpl_tests
) )
add_code_coverage_to_target(opts INTERFACE) add_code_coverage_to_target(opts INTERFACE)

44
cmake/XrplPackaging.cmake Normal file
View File

@@ -0,0 +1,44 @@
#[===================================================================[
Linux packaging support: 'package' target.
The packaging script (package/build_pkg.sh) installs to FHS-standard
paths (/usr/bin, /etc/xrpld, etc.) regardless of CMAKE_INSTALL_PREFIX,
so no prefix guard is needed here.
#]===================================================================]
if(NOT is_linux)
message(STATUS "Packaging not supported on non-Linux hosts")
return()
endif()
if(NOT DEFINED pkg_release)
set(pkg_release 1)
endif()
find_program(RPMBUILD_EXECUTABLE rpmbuild)
find_program(DPKG_BUILDPACKAGE_EXECUTABLE dpkg-buildpackage)
if(NOT (RPMBUILD_EXECUTABLE OR DPKG_BUILDPACKAGE_EXECUTABLE))
message(
STATUS
"Neither rpmbuild nor dpkg-buildpackage found; 'package' target not available"
)
return()
endif()
set(package_env
SRC_DIR=${CMAKE_SOURCE_DIR}
BUILD_DIR=${CMAKE_BINARY_DIR}
PKG_VERSION=${xrpld_version}
PKG_RELEASE=${pkg_release}
)
add_custom_target(
package
COMMAND
${CMAKE_COMMAND} -E env ${package_env}
${CMAKE_SOURCE_DIR}/package/build_pkg.sh
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
DEPENDS xrpld
COMMENT "Building Linux package (deb/rpm inferred from host tooling)"
VERBATIM
)

View File

@@ -0,0 +1,13 @@
# Python dependencies for XRP Ledger code generation scripts
#
# These packages are required to run the code generation scripts that
# parse macro files and generate C++ wrapper classes.
# C preprocessor for Python - used to preprocess macro files
pcpp>=1.30
# Parser combinator library - used to parse the macro DSL
pyparsing>=3.0.0
# Template engine - used to generate C++ code from templates
Mako>=1.2.2

View File

@@ -1,13 +1,105 @@
# Python dependencies for XRP Ledger code generation scripts # This file was autogenerated by uv via the following command:
# # uv pip compile requirements.in --generate-hashes --output-file requirements.txt
# These packages are required to run the code generation scripts that mako==1.3.12 \
# parse macro files and generate C++ wrapper classes. --hash=sha256:8f61569480282dbf557145ce441e4ba888be453c30989f879f0d652e39f53ea9 \
--hash=sha256:9f778e93289bd410bb35daadeb4fc66d95a746f0b75777b942088b7fd7af550a
# C preprocessor for Python - used to preprocess macro files # via -r requirements.in
pcpp>=1.30 markupsafe==3.0.3 \
--hash=sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f \
# Parser combinator library - used to parse the macro DSL --hash=sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a \
pyparsing>=3.0.0 --hash=sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf \
--hash=sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19 \
# Template engine - used to generate C++ code from templates --hash=sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf \
Mako>=1.2.2 --hash=sha256:0f4b68347f8c5eab4a13419215bdfd7f8c9b19f2b25520968adfad23eb0ce60c \
--hash=sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175 \
--hash=sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219 \
--hash=sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb \
--hash=sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6 \
--hash=sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab \
--hash=sha256:15d939a21d546304880945ca1ecb8a039db6b4dc49b2c5a400387cdae6a62e26 \
--hash=sha256:177b5253b2834fe3678cb4a5f0059808258584c559193998be2601324fdeafb1 \
--hash=sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce \
--hash=sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218 \
--hash=sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634 \
--hash=sha256:1ba88449deb3de88bd40044603fafffb7bc2b055d626a330323a9ed736661695 \
--hash=sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad \
--hash=sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73 \
--hash=sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c \
--hash=sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe \
--hash=sha256:2a15a08b17dd94c53a1da0438822d70ebcd13f8c3a95abe3a9ef9f11a94830aa \
--hash=sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559 \
--hash=sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa \
--hash=sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37 \
--hash=sha256:3537e01efc9d4dccdf77221fb1cb3b8e1a38d5428920e0657ce299b20324d758 \
--hash=sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f \
--hash=sha256:38664109c14ffc9e7437e86b4dceb442b0096dfe3541d7864d9cbe1da4cf36c8 \
--hash=sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d \
--hash=sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c \
--hash=sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97 \
--hash=sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a \
--hash=sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19 \
--hash=sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9 \
--hash=sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9 \
--hash=sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc \
--hash=sha256:591ae9f2a647529ca990bc681daebdd52c8791ff06c2bfa05b65163e28102ef2 \
--hash=sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4 \
--hash=sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354 \
--hash=sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50 \
--hash=sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698 \
--hash=sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9 \
--hash=sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b \
--hash=sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc \
--hash=sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115 \
--hash=sha256:7c3fb7d25180895632e5d3148dbdc29ea38ccb7fd210aa27acbd1201a1902c6e \
--hash=sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485 \
--hash=sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f \
--hash=sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12 \
--hash=sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025 \
--hash=sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009 \
--hash=sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d \
--hash=sha256:949b8d66bc381ee8b007cd945914c721d9aba8e27f71959d750a46f7c282b20b \
--hash=sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a \
--hash=sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5 \
--hash=sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f \
--hash=sha256:a320721ab5a1aba0a233739394eb907f8c8da5c98c9181d1161e77a0c8e36f2d \
--hash=sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1 \
--hash=sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287 \
--hash=sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6 \
--hash=sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f \
--hash=sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581 \
--hash=sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed \
--hash=sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b \
--hash=sha256:c0c0b3ade1c0b13b936d7970b1d37a57acde9199dc2aecc4c336773e1d86049c \
--hash=sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026 \
--hash=sha256:c4ffb7ebf07cfe8931028e3e4c85f0357459a3f9f9490886198848f4fa002ec8 \
--hash=sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676 \
--hash=sha256:d2ee202e79d8ed691ceebae8e0486bd9a2cd4794cec4824e1c99b6f5009502f6 \
--hash=sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e \
--hash=sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d \
--hash=sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d \
--hash=sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01 \
--hash=sha256:df2449253ef108a379b8b5d6b43f4b1a8e81a061d6537becd5582fba5f9196d7 \
--hash=sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419 \
--hash=sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795 \
--hash=sha256:e2103a929dfa2fcaf9bb4e7c091983a49c9ac3b19c9061b6d5427dd7d14d81a1 \
--hash=sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5 \
--hash=sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d \
--hash=sha256:e8fc20152abba6b83724d7ff268c249fa196d8259ff481f3b1476383f8f24e42 \
--hash=sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe \
--hash=sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda \
--hash=sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e \
--hash=sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737 \
--hash=sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523 \
--hash=sha256:f42d0984e947b8adf7dd6dde396e720934d12c506ce84eea8476409563607591 \
--hash=sha256:f71a396b3bf33ecaa1626c255855702aca4d3d9fea5e051b41ac59a9c1c41edc \
--hash=sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a \
--hash=sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50
# via mako
pcpp==1.30 \
--hash=sha256:05fe08292b6da57f385001c891a87f40d6aa7f46787b03e8ba326d20a3297c6e \
--hash=sha256:5af9fbce55f136d7931ae915fae03c34030a3b36c496e72d9636cedc8e2543a1
# via -r requirements.in
pyparsing==3.3.2 \
--hash=sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d \
--hash=sha256:c777f4d763f140633dcb6d8a3eda953bf7a214dc4eff598413c070bcdc117cbc
# via -r requirements.in

View File

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

View File

@@ -1 +1,8 @@
{% set os = detect_api.detect_os() %}
include(sanitizers) include(sanitizers)
[conf]
{% if os == "Linux" %}
user.package:libc_version=2.31
tools.info.package_id:confs+=["user.package:libc_version"]
{% endif %}

View File

@@ -50,6 +50,7 @@ words:
- AMMXRP - AMMXRP
- amt - amt
- amts - amts
- archs
- asnode - asnode
- asynchrony - asynchrony
- attestation - attestation
@@ -93,18 +94,22 @@ words:
- daria - daria
- dcmake - dcmake
- dearmor - dearmor
- dedented
- deleteme - deleteme
- demultiplexer - demultiplexer
- deserializaton - deserializaton
- desync - desync
- desynced - desynced
- determ - determ
- disablerepo
- distro - distro
- doxyfile - doxyfile
- dxrpl - dxrpl
- enabled - enabled
- enablerepo
- endmacro - endmacro
- exceptioned - exceptioned
- EXPECT_STREQ
- Falco - Falco
- fcontext - fcontext
- finalizers - finalizers
@@ -130,6 +135,7 @@ words:
- iou - iou
- ious - ious
- isrdc - isrdc
- isystem
- itype - itype
- jemalloc - jemalloc
- jlog - jlog
@@ -162,6 +168,7 @@ words:
- Merkle - Merkle
- Metafuncton - Metafuncton
- misprediction - misprediction
- missingok
- mptbalance - mptbalance
- MPTDEX - MPTDEX
- mptflags - mptflags
@@ -193,11 +200,15 @@ words:
- NOLINT - NOLINT
- NOLINTNEXTLINE - NOLINTNEXTLINE
- nonxrp - nonxrp
- noreplace
- noripple - noripple
- nostdinc
- notifempty
- nudb - nudb
- nullptr - nullptr
- nunl - nunl
- Nyffenegger - Nyffenegger
- onlatest
- ostr - ostr
- pargs - pargs
- partitioner - partitioner
@@ -213,6 +224,7 @@ words:
- preauthorize - preauthorize
- preauthorizes - preauthorizes
- preclaim - preclaim
- preun
- protobuf - protobuf
- protos - protos
- ptrs - ptrs
@@ -247,12 +259,15 @@ words:
- sfields - sfields
- shamap - shamap
- shamapitem - shamapitem
- shfmt
- shlibs
- sidechain - sidechain
- SIGGOOD - SIGGOOD
- sle - sle
- sles - sles
- soci - soci
- socidb - socidb
- SRPMS
- sslws - sslws
- statsd - statsd
- STATSDCOLLECTOR - STATSDCOLLECTOR
@@ -280,8 +295,8 @@ words:
- txn - txn
- txns - txns
- txs - txs
- UBSAN
- ubsan - ubsan
- UBSAN
- umant - umant
- unacquired - unacquired
- unambiguity - unambiguity
@@ -289,6 +304,7 @@ words:
- unauthorizing - unauthorizing
- unergonomic - unergonomic
- unfetched - unfetched
- unfindable
- unflatten - unflatten
- unfund - unfund
- unimpair - unimpair
@@ -318,7 +334,6 @@ words:
- xbridge - xbridge
- xchain - xchain
- ximinez - ximinez
- EXPECT_STREQ
- XMACRO - XMACRO
- xrpkuwait - xrpkuwait
- xrpl - xrpl
@@ -326,3 +341,4 @@ words:
- xrplf - xrplf
- xxhash - xxhash
- xxhasher - xxhasher
- CGNAT

View File

@@ -1,66 +0,0 @@
ARG BASE_IMAGE=nixos/nix:latest
# Nix builder
FROM nixos/nix:latest AS builder-source
RUN mkdir -p ~/.config/nix && \
echo "experimental-features = nix-command flakes" >> ~/.config/nix/nix.conf
# Copy our source and setup our working dir.
COPY nix/ci-env.nix /tmp/build/nix/ci-env.nix
COPY nix/packages.nix /tmp/build/nix/packages.nix
COPY nix/utils.nix /tmp/build/nix/utils.nix
COPY flake.nix /tmp/build/
COPY flake.lock /tmp/build/
WORKDIR /tmp/build
FROM builder-source AS builder
# Build our Nix CI environment (all build tools in a single store path)
RUN nix \
--option filter-syscalls false \
build
# Copy the Nix store closure into a directory. The Nix store closure is the
# entire set of Nix store values that we need for our build.
RUN mkdir /tmp/nix-store-closure && \
cp -R $(nix-store -qR result/) /tmp/nix-store-closure
# Final image
FROM ${BASE_IMAGE}
# bash is not located at /bin/bash in nixos/nix, so we need to create a symlink to it.
RUN if [ -d /nix ]; then \
ln -s /root/.nix-profile/bin/bash /bin/bash; \
fi
# Use Bash as the default shell for RUN commands, using the options
# `set -o errexit -o pipefail`, and as the entrypoint.
SHELL ["/bin/bash", "-e", "-o", "pipefail", "-c"]
ENTRYPOINT ["/bin/bash"]
# Copy /nix/store and the env symlink tree
COPY --from=builder /tmp/nix-store-closure /nix/store
COPY --from=builder /tmp/build/result /nix/ci-env
ENV PATH="/nix/ci-env/bin:$PATH"
RUN <<EOF
ccache --version
clang-format --version
cmake --version
conan --version
g++ --version
gcc --version
gcovr --version
git --version
make --version
mold --version
ninja --version
perl --version
pkg-config --version
pre-commit --version
python3 --version
run-clang-tidy --help
vim --version
EOF

10
flake.lock generated
View File

@@ -2,11 +2,11 @@
"nodes": { "nodes": {
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1777954456, "lastModified": 1780243769,
"narHash": "sha256-hGdgeU2Nk87RAuZyYjyDjFL6LK7dAZN5RE9+hrDTkDU=", "narHash": "sha256-x5UQuRsH3MqI0U9afaXSNqzTPSeZlRLvFAav2Ux1pNw=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "549bd84d6279f9852cae6225e372cc67fb91a4c1", "rev": "331800de5053fcebacf6813adb5db9c9dca22a0c",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -15,7 +15,7 @@
"type": "indirect" "type": "indirect"
} }
}, },
"nixpkgs-glibc231": { "nixpkgs-custom-glibc": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1593520194, "lastModified": 1593520194,
@@ -35,7 +35,7 @@
"root": { "root": {
"inputs": { "inputs": {
"nixpkgs": "nixpkgs", "nixpkgs": "nixpkgs",
"nixpkgs-glibc231": "nixpkgs-glibc231" "nixpkgs-custom-glibc": "nixpkgs-custom-glibc"
} }
} }
}, },

View File

@@ -6,16 +6,16 @@
# version — matches the system libc on Ubuntu 20.04 LTS. Imported # version — matches the system libc on Ubuntu 20.04 LTS. Imported
# manually (flake = false) because this revision predates nixpkgs' # manually (flake = false) because this revision predates nixpkgs'
# own flake.nix. # own flake.nix.
nixpkgs-glibc231 = { nixpkgs-custom-glibc = {
url = "github:NixOS/nixpkgs/9cd98386a38891d1074fc18036b842dc4416f562"; url = "github:NixOS/nixpkgs/9cd98386a38891d1074fc18036b842dc4416f562";
flake = false; flake = false;
}; };
}; };
outputs = outputs =
{ nixpkgs, nixpkgs-glibc231, ... }: { nixpkgs, nixpkgs-custom-glibc, ... }:
let let
forEachSystem = import ./nix/utils.nix { inherit nixpkgs nixpkgs-glibc231; }; forEachSystem = import ./nix/utils.nix { inherit nixpkgs nixpkgs-custom-glibc; };
in in
{ {
devShells = forEachSystem (import ./nix/devshell.nix); devShells = forEachSystem (import ./nix/devshell.nix);

View File

@@ -406,8 +406,8 @@ private:
// pointer. The low bit must be masked to zero when converting back to a // pointer. The low bit must be masked to zero when converting back to a
// pointer. If the low bit is '1', this is a weak pointer. // pointer. If the low bit is '1', this is a weak pointer.
std::uintptr_t tp_{0}; std::uintptr_t tp_{0};
static constexpr std::uintptr_t kTAG_MASK = 1; static constexpr std::uintptr_t kTagMask = 1;
static constexpr std::uintptr_t kPTR_MASK = ~kTAG_MASK; static constexpr std::uintptr_t kPtrMask = ~kTagMask;
private: private:
/** Return the raw pointer held by this object. /** Return the raw pointer held by this object.

View File

@@ -567,14 +567,14 @@ template <class T>
bool bool
SharedWeakUnion<T>::isStrong() const SharedWeakUnion<T>::isStrong() const
{ {
return (tp_ & kTAG_MASK) == 0u; return (tp_ & kTagMask) == 0u;
} }
template <class T> template <class T>
bool bool
SharedWeakUnion<T>::isWeak() const SharedWeakUnion<T>::isWeak() const
{ {
return (tp_ & kTAG_MASK) != 0u; return (tp_ & kTagMask) != 0u;
} }
template <class T> template <class T>
@@ -641,7 +641,7 @@ template <class T>
T* T*
SharedWeakUnion<T>::unsafeGetRawPtr() const SharedWeakUnion<T>::unsafeGetRawPtr() const
{ {
return reinterpret_cast<T*>(tp_ & kPTR_MASK); return reinterpret_cast<T*>(tp_ & kPtrMask);
} }
template <class T> template <class T>
@@ -650,7 +650,7 @@ SharedWeakUnion<T>::unsafeSetRawPtr(T* p, RefStrength rs)
{ {
tp_ = reinterpret_cast<std::uintptr_t>(p); tp_ = reinterpret_cast<std::uintptr_t>(p);
if (tp_ && rs == RefStrength::Weak) if (tp_ && rs == RefStrength::Weak)
tp_ |= kTAG_MASK; tp_ |= kTagMask;
} }
template <class T> template <class T>

View File

@@ -98,11 +98,11 @@ private:
// enough for strong pointers and 14 bit counts are enough for weak // enough for strong pointers and 14 bit counts are enough for weak
// pointers. Use type aliases to make it easy to switch types. // pointers. Use type aliases to make it easy to switch types.
using CountType = std::uint16_t; using CountType = std::uint16_t;
static constexpr size_t kSTRONG_COUNT_NUM_BITS = sizeof(CountType) * 8; static constexpr size_t kStrongCountNumBits = sizeof(CountType) * 8;
static constexpr size_t kWEAK_COUNT_NUM_BITS = kSTRONG_COUNT_NUM_BITS - 2; static constexpr size_t kWeakCountNumBits = kStrongCountNumBits - 2;
using FieldType = std::uint32_t; using FieldType = std::uint32_t;
static constexpr size_t kFIELD_TYPE_BITS = sizeof(FieldType) * 8; static constexpr size_t kFieldTypeBits = sizeof(FieldType) * 8;
static constexpr FieldType kONE = 1; static constexpr FieldType kOne = 1;
/** `refCounts` consists of four fields that are treated atomically: /** `refCounts` consists of four fields that are treated atomically:
@@ -137,21 +137,21 @@ private:
*/ */
mutable std::atomic<FieldType> refCounts_{kSTRONG_DELTA}; mutable std::atomic<FieldType> refCounts_{kStrongDelta};
/** Amount to change the strong count when adding or releasing a reference /** Amount to change the strong count when adding or releasing a reference
Note: The strong count is stored in the low `StrongCountNumBits` bits Note: The strong count is stored in the low `StrongCountNumBits` bits
of refCounts of refCounts
*/ */
static constexpr FieldType kSTRONG_DELTA = 1; static constexpr FieldType kStrongDelta = 1;
/** Amount to change the weak count when adding or releasing a reference /** Amount to change the weak count when adding or releasing a reference
Note: The weak count is stored in the high `WeakCountNumBits` bits of Note: The weak count is stored in the high `WeakCountNumBits` bits of
refCounts refCounts
*/ */
static constexpr FieldType kWEAK_DELTA = (kONE << kSTRONG_COUNT_NUM_BITS); static constexpr FieldType kWeakDelta = (kOne << kStrongCountNumBits);
/** Flag that is set when the partialDestroy function has started running /** Flag that is set when the partialDestroy function has started running
(or is about to start running). (or is about to start running).
@@ -159,34 +159,33 @@ private:
See description of the `refCounts` field for a fuller description of See description of the `refCounts` field for a fuller description of
this field. this field.
*/ */
static constexpr FieldType kPARTIAL_DESTROY_STARTED_MASK = (kONE << (kFIELD_TYPE_BITS - 1)); static constexpr FieldType kPartialDestroyStartedMask = (kOne << (kFieldTypeBits - 1));
/** Flag that is set when the partialDestroy function has finished running /** Flag that is set when the partialDestroy function has finished running
See description of the `refCounts` field for a fuller description of See description of the `refCounts` field for a fuller description of
this field. this field.
*/ */
static constexpr FieldType kPARTIAL_DESTROY_FINISHED_MASK = (kONE << (kFIELD_TYPE_BITS - 2)); static constexpr FieldType kPartialDestroyFinishedMask = (kOne << (kFieldTypeBits - 2));
/** Mask that will zero out all the `count` bits and leave the tag bits /** Mask that will zero out all the `count` bits and leave the tag bits
unchanged. unchanged.
*/ */
static constexpr FieldType kTAG_MASK = static constexpr FieldType kTagMask = kPartialDestroyStartedMask | kPartialDestroyFinishedMask;
kPARTIAL_DESTROY_STARTED_MASK | kPARTIAL_DESTROY_FINISHED_MASK;
/** Mask that will zero out the `tag` bits and leave the count bits /** Mask that will zero out the `tag` bits and leave the count bits
unchanged. unchanged.
*/ */
static constexpr FieldType kVALUE_MASK = ~kTAG_MASK; 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 kSTRONG_MASK = ((kONE << kSTRONG_COUNT_NUM_BITS) - 1) & kVALUE_MASK; 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 kWEAK_MASK = static constexpr FieldType kWeakMask =
(((kONE << kWEAK_COUNT_NUM_BITS) - 1) << kSTRONG_COUNT_NUM_BITS) & kVALUE_MASK; (((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 struct RefCountPair
@@ -211,29 +210,29 @@ private:
[[nodiscard]] FieldType [[nodiscard]] FieldType
combinedValue() const noexcept; combinedValue() const noexcept;
static constexpr CountType kMAX_STRONG_VALUE = static constexpr CountType kMaxStrongValue =
static_cast<CountType>((kONE << kSTRONG_COUNT_NUM_BITS) - 1); static_cast<CountType>((kOne << kStrongCountNumBits) - 1);
static constexpr CountType kMAX_WEAK_VALUE = static constexpr CountType kMaxWeakValue =
static_cast<CountType>((kONE << kWEAK_COUNT_NUM_BITS) - 1); static_cast<CountType>((kOne << kWeakCountNumBits) - 1);
/** Put an extra margin to detect when running up against limits. /** 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 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). number of bits in the strong and weak counts (to 16 and 14 bits).
*/ */
static constexpr CountType kCHECK_STRONG_MAX_VALUE = kMAX_STRONG_VALUE - 32; static constexpr CountType kCheckStrongMaxValue = kMaxStrongValue - 32;
static constexpr CountType kCHECK_WEAK_MAX_VALUE = kMAX_WEAK_VALUE - 32; static constexpr CountType kCheckWeakMaxValue = kMaxWeakValue - 32;
}; };
}; };
inline void inline void
IntrusiveRefCounts::addStrongRef() const noexcept IntrusiveRefCounts::addStrongRef() const noexcept
{ {
refCounts_.fetch_add(kSTRONG_DELTA, std::memory_order_acq_rel); refCounts_.fetch_add(kStrongDelta, std::memory_order_acq_rel);
} }
inline void inline void
IntrusiveRefCounts::addWeakRef() const noexcept IntrusiveRefCounts::addWeakRef() const noexcept
{ {
refCounts_.fetch_add(kWEAK_DELTA, std::memory_order_acq_rel); refCounts_.fetch_add(kWeakDelta, std::memory_order_acq_rel);
} }
inline ReleaseStrongRefAction inline ReleaseStrongRefAction
@@ -252,10 +251,10 @@ IntrusiveRefCounts::releaseStrongRef() const
{ {
RefCountPair const prevVal{prevIntVal}; RefCountPair const prevVal{prevIntVal};
XRPL_ASSERT( XRPL_ASSERT(
(prevVal.strong >= kSTRONG_DELTA), (prevVal.strong >= kStrongDelta),
"xrpl::IntrusiveRefCounts::releaseStrongRef : previous ref " "xrpl::IntrusiveRefCounts::releaseStrongRef : previous ref "
"higher than new"); "higher than new");
auto nextIntVal = prevIntVal - kSTRONG_DELTA; auto nextIntVal = prevIntVal - kStrongDelta;
ReleaseStrongRefAction action = NoOp; ReleaseStrongRefAction action = NoOp;
if (prevVal.strong == 1) if (prevVal.strong == 1)
{ {
@@ -265,7 +264,7 @@ IntrusiveRefCounts::releaseStrongRef() const
} }
else else
{ {
nextIntVal |= kPARTIAL_DESTROY_STARTED_MASK; nextIntVal |= kPartialDestroyStartedMask;
action = PartialDestroy; action = PartialDestroy;
} }
} }
@@ -276,7 +275,7 @@ IntrusiveRefCounts::releaseStrongRef() const
// count to zero can start a partial destroy, and that can't happen // count to zero can start a partial destroy, and that can't happen
// twice. // twice.
XRPL_ASSERT( XRPL_ASSERT(
(action == NoOp) || !(prevIntVal & kPARTIAL_DESTROY_STARTED_MASK), (action == NoOp) || !(prevIntVal & kPartialDestroyStartedMask),
"xrpl::IntrusiveRefCounts::releaseStrongRef : not in partial " "xrpl::IntrusiveRefCounts::releaseStrongRef : not in partial "
"destroy"); "destroy");
return action; return action;
@@ -289,8 +288,8 @@ IntrusiveRefCounts::addWeakReleaseStrongRef() const
{ {
using enum ReleaseStrongRefAction; using enum ReleaseStrongRefAction;
static_assert(kWEAK_DELTA > kSTRONG_DELTA); static_assert(kWeakDelta > kStrongDelta);
auto constexpr kDELTA = kWEAK_DELTA - kSTRONG_DELTA; static constexpr auto kDelta = kWeakDelta - kStrongDelta;
auto prevIntVal = refCounts_.load(std::memory_order_acquire); auto prevIntVal = refCounts_.load(std::memory_order_acquire);
// This loop will almost always run once. The loop is needed to atomically // This loop will almost always run once. The loop is needed to atomically
// change the counts and flags (the count could be atomically changed, but // change the counts and flags (the count could be atomically changed, but
@@ -312,7 +311,7 @@ IntrusiveRefCounts::addWeakReleaseStrongRef() const
"xrpl::IntrusiveRefCounts::addWeakReleaseStrongRef : not in " "xrpl::IntrusiveRefCounts::addWeakReleaseStrongRef : not in "
"partial destroy"); "partial destroy");
auto nextIntVal = prevIntVal + kDELTA; auto nextIntVal = prevIntVal + kDelta;
ReleaseStrongRefAction action = NoOp; ReleaseStrongRefAction action = NoOp;
if (prevVal.strong == 1) if (prevVal.strong == 1)
{ {
@@ -322,14 +321,14 @@ IntrusiveRefCounts::addWeakReleaseStrongRef() const
} }
else else
{ {
nextIntVal |= kPARTIAL_DESTROY_STARTED_MASK; nextIntVal |= kPartialDestroyStartedMask;
action = PartialDestroy; action = PartialDestroy;
} }
} }
if (refCounts_.compare_exchange_weak(prevIntVal, nextIntVal, std::memory_order_acq_rel)) if (refCounts_.compare_exchange_weak(prevIntVal, nextIntVal, std::memory_order_acq_rel))
{ {
XRPL_ASSERT( XRPL_ASSERT(
(!(prevIntVal & kPARTIAL_DESTROY_STARTED_MASK)), (!(prevIntVal & kPartialDestroyStartedMask)),
"xrpl::IntrusiveRefCounts::addWeakReleaseStrongRef : not " "xrpl::IntrusiveRefCounts::addWeakReleaseStrongRef : not "
"started partial destroy"); "started partial destroy");
return action; return action;
@@ -340,7 +339,7 @@ IntrusiveRefCounts::addWeakReleaseStrongRef() const
inline ReleaseWeakRefAction inline ReleaseWeakRefAction
IntrusiveRefCounts::releaseWeakRef() const IntrusiveRefCounts::releaseWeakRef() const
{ {
auto prevIntVal = refCounts_.fetch_sub(kWEAK_DELTA, std::memory_order_acq_rel); auto prevIntVal = refCounts_.fetch_sub(kWeakDelta, std::memory_order_acq_rel);
RefCountPair prev = prevIntVal; RefCountPair prev = prevIntVal;
if (prev.weak == 1 && prev.strong == 0) if (prev.weak == 1 && prev.strong == 0)
{ {
@@ -357,7 +356,7 @@ IntrusiveRefCounts::releaseWeakRef() const
{ {
// partial destroy MUST finish before running a full destroy (when // partial destroy MUST finish before running a full destroy (when
// using weak pointers) // using weak pointers)
refCounts_.wait(prevIntVal - kWEAK_DELTA, std::memory_order_acquire); refCounts_.wait(prevIntVal - kWeakDelta, std::memory_order_acquire);
} }
return ReleaseWeakRefAction::Destroy; return ReleaseWeakRefAction::Destroy;
} }
@@ -376,7 +375,7 @@ IntrusiveRefCounts::checkoutStrongRefFromWeak() const noexcept
if (prev.strong == 0u) if (prev.strong == 0u)
return false; return false;
desiredValue = curValue + kSTRONG_DELTA; desiredValue = curValue + kStrongDelta;
} }
return true; return true;
} }
@@ -400,23 +399,22 @@ inline IntrusiveRefCounts::~IntrusiveRefCounts() noexcept
#ifndef NDEBUG #ifndef NDEBUG
auto v = refCounts_.load(std::memory_order_acquire); auto v = refCounts_.load(std::memory_order_acquire);
XRPL_ASSERT( XRPL_ASSERT(
(!(v & kVALUE_MASK)), "xrpl::IntrusiveRefCounts::~IntrusiveRefCounts : count must be zero"); (!(v & kValueMask)), "xrpl::IntrusiveRefCounts::~IntrusiveRefCounts : count must be zero");
auto t = v & kTAG_MASK; auto t = v & kTagMask;
XRPL_ASSERT( XRPL_ASSERT((!t || t == kTagMask), "xrpl::IntrusiveRefCounts::~IntrusiveRefCounts : valid tag");
(!t || t == kTAG_MASK), "xrpl::IntrusiveRefCounts::~IntrusiveRefCounts : valid tag");
#endif #endif
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
inline IntrusiveRefCounts::RefCountPair::RefCountPair(IntrusiveRefCounts::FieldType v) noexcept inline IntrusiveRefCounts::RefCountPair::RefCountPair(IntrusiveRefCounts::FieldType v) noexcept
: strong{static_cast<CountType>(v & kSTRONG_MASK)} : strong{static_cast<CountType>(v & kStrongMask)}
, weak{static_cast<CountType>((v & kWEAK_MASK) >> kSTRONG_COUNT_NUM_BITS)} , weak{static_cast<CountType>((v & kWeakMask) >> kStrongCountNumBits)}
, partialDestroyStartedBit{v & kPARTIAL_DESTROY_STARTED_MASK} , partialDestroyStartedBit{v & kPartialDestroyStartedMask}
, partialDestroyFinishedBit{v & kPARTIAL_DESTROY_FINISHED_MASK} , partialDestroyFinishedBit{v & kPartialDestroyFinishedMask}
{ {
XRPL_ASSERT( XRPL_ASSERT(
(strong < kCHECK_STRONG_MAX_VALUE && weak < kCHECK_WEAK_MAX_VALUE), (strong < kCheckStrongMaxValue && weak < kCheckWeakMaxValue),
"xrpl::IntrusiveRefCounts::RefCountPair(FieldType) : inputs inside " "xrpl::IntrusiveRefCounts::RefCountPair(FieldType) : inputs inside "
"range"); "range");
} }
@@ -427,7 +425,7 @@ inline IntrusiveRefCounts::RefCountPair::RefCountPair(
: strong{s}, weak{w} : strong{s}, weak{w}
{ {
XRPL_ASSERT( XRPL_ASSERT(
(strong < kCHECK_STRONG_MAX_VALUE && weak < kCHECK_WEAK_MAX_VALUE), (strong < kCheckStrongMaxValue && weak < kCheckWeakMaxValue),
"xrpl::IntrusiveRefCounts::RefCountPair(CountType, CountType) : " "xrpl::IntrusiveRefCounts::RefCountPair(CountType, CountType) : "
"inputs inside range"); "inputs inside range");
} }
@@ -436,11 +434,11 @@ inline IntrusiveRefCounts::FieldType
IntrusiveRefCounts::RefCountPair::combinedValue() const noexcept IntrusiveRefCounts::RefCountPair::combinedValue() const noexcept
{ {
XRPL_ASSERT( XRPL_ASSERT(
(strong < kCHECK_STRONG_MAX_VALUE && weak < kCHECK_WEAK_MAX_VALUE), (strong < kCheckStrongMaxValue && weak < kCheckWeakMaxValue),
"xrpl::IntrusiveRefCounts::RefCountPair::combinedValue : inputs " "xrpl::IntrusiveRefCounts::RefCountPair::combinedValue : inputs "
"inside range"); "inside range");
return (static_cast<IntrusiveRefCounts::FieldType>(weak) return (static_cast<IntrusiveRefCounts::FieldType>(weak)
<< IntrusiveRefCounts::kSTRONG_COUNT_NUM_BITS) | << IntrusiveRefCounts::kStrongCountNumBits) |
static_cast<IntrusiveRefCounts::FieldType>(strong) | partialDestroyStartedBit | static_cast<IntrusiveRefCounts::FieldType>(strong) | partialDestroyStartedBit |
partialDestroyFinishedBit; partialDestroyFinishedBit;
} }
@@ -451,7 +449,7 @@ partialDestructorFinished(T** o)
{ {
T& self = **o; T& self = **o;
IntrusiveRefCounts::RefCountPair const p = IntrusiveRefCounts::RefCountPair const p =
self.refCounts_.fetch_or(IntrusiveRefCounts::kPARTIAL_DESTROY_FINISHED_MASK); self.refCounts_.fetch_or(IntrusiveRefCounts::kPartialDestroyFinishedMask);
XRPL_ASSERT( XRPL_ASSERT(
(!p.partialDestroyFinishedBit && p.partialDestroyStartedBit && !p.strong), (!p.partialDestroyFinishedBit && p.partialDestroyStartedBit && !p.strong),
"xrpl::partialDestructorFinished : not a weak ref"); "xrpl::partialDestructorFinished : not a weak ref");

View File

@@ -55,8 +55,8 @@ template <class = void>
boost::thread_specific_ptr<detail::LocalValues>& boost::thread_specific_ptr<detail::LocalValues>&
getLocalValues() getLocalValues()
{ {
static boost::thread_specific_ptr<detail::LocalValues> kTSP(&detail::LocalValues::cleanup); static boost::thread_specific_ptr<detail::LocalValues> kTsp(&detail::LocalValues::cleanup);
return kTSP; return kTsp;
} }
} // namespace detail } // namespace detail

View File

@@ -191,7 +191,7 @@ public:
private: private:
// Maximum line length for log messages. // Maximum line length for log messages.
// If the message exceeds this length it will be truncated with ellipses. // If the message exceeds this length it will be truncated with ellipses.
static constexpr auto kMAXIMUM_MESSAGE_CHARACTERS = 12 * 1024; static constexpr auto kMaximumMessageCharacters = 12 * 1024;
static void static void
format( format(

View File

@@ -2,12 +2,16 @@
#include <xrpl/beast/utility/instrumentation.h> #include <xrpl/beast/utility/instrumentation.h>
#include <array>
#include <cstdint> #include <cstdint>
#include <functional> #include <functional>
#include <limits> #include <limits>
#include <optional> #include <optional>
#include <ostream> #include <ostream>
#include <set>
#include <stdexcept>
#include <string> #include <string>
#include <unordered_map>
namespace xrpl { namespace xrpl {
@@ -38,17 +42,58 @@ isPowerOfTen(T value)
return logTen(value).has_value(); return logTen(value).has_value();
} }
namespace detail {
/** Builds a table of the powers of 10
*
* This function is marked consteval, so it can only be run in
* a constexpr context. This assures that it is and can only be run at
* compile time. Doing it at runtime would be pretty wasteful and
* inefficient.
*/
constexpr std::size_t kInt64Digits = 20;
consteval std::array<std::uint64_t, kInt64Digits>
buildPowersOfTen()
{
std::array<std::uint64_t, kInt64Digits> result{};
std::uint64_t power = 1;
std::size_t exponent = 0;
// end the loop early so it doesn't overflow;
for (; exponent < result.size() - 1; ++exponent, power *= 10)
{
result[exponent] = power;
if (power > std::numeric_limits<std::uint64_t>::max() / 10)
throw std::logic_error("Power of 10 table is too big");
}
result[exponent] = power;
if (power < std::numeric_limits<std::uint64_t>::max() / 10)
throw std::logic_error("Power of 10 table is not big enough for the uint64_t type");
return result;
}
} // namespace detail
constexpr std::array<std::uint64_t, detail::kInt64Digits> kPowerOfTen = detail::buildPowersOfTen();
static_assert(kPowerOfTen[0] == 1);
static_assert(kPowerOfTen[1] == 10);
static_assert(kPowerOfTen[10] == 10'000'000'000);
static_assert(
isPowerOfTen(kPowerOfTen.back()) && *logTen(kPowerOfTen.back()) == detail::kInt64Digits - 1);
/** MantissaRange defines a range for the mantissa of a normalized Number. /** MantissaRange defines a range for the mantissa of a normalized Number.
* *
* The mantissa is in the range [min, max], where * The mantissa is in the range [min, max], where
* * min is a power of 10, and * * min is a power of 10, and
* * max = min * 10 - 1. * * max = min * 10 - 1.
* *
* The mantissa_scale enum indicates whether the range is "small" or "large". * The MantissaScale enum indicates properties of the range: size, and some behavioral
* This intentionally restricts the number of MantissaRanges that can be * options. This intentionally restricts the number of unique MantissaRanges that can
* instantiated to two: one for each scale. * be instantiated: one for each scale.
* *
* The "small" scale is based on the behavior of STAmount for IOUs. It has a min * The "Small" scale is based on the behavior of STAmount for IOUs. It has a min
* value of 10^15, and a max value of 10^16-1. This was sufficient for * value of 10^15, and a max value of 10^16-1. This was sufficient for
* uses before Lending Protocol was implemented, mostly related to AMM. * uses before Lending Protocol was implemented, mostly related to AMM.
* *
@@ -59,46 +104,100 @@ isPowerOfTen(T value)
* STNumber field type, and for internal calculations. That necessitated the * STNumber field type, and for internal calculations. That necessitated the
* "large" scale. * "large" scale.
* *
* The "large" scale is intended to represent all values that can be represented * The "Large" scales are intended to represent all values that can be represented
* by an STAmount - IOUs, XRP, and MPTs. It has a min value of 10^18, and a max * by an STAmount - IOUs, XRP, and MPTs. It has a min value of 10^18, and a max
* value of 10^19-1. * value of 10^19-1. "LargeLegacy" is like "Large", but preserves
* a rounding error when a computation results in a mantissa of
* Number::kMaxRep that needs to be rounded up, but rounds down
* instead. It will maintain consistent behavior until the fixCleanup3_2_0
* amendment is enabled.
* *
* Note that if the mentioned amendments are eventually retired, this class * Note that if the mentioned amendments are eventually retired, this class
* should be left in place, but the "small" scale option should be removed. This * should be left in place, but the "Small" scale option should be removed. This
* will allow for future expansion beyond 64-bits if it is ever needed. * will allow for future expansion beyond 64-bits if it is ever needed.
*/ */
struct MantissaRange struct MantissaRange final
{ {
using rep = std::uint64_t; using rep = std::uint64_t;
enum class MantissaScale { Small, Large };
explicit constexpr MantissaRange(MantissaScale scale) enum class MantissaScale {
: min(getMin(scale)), log(logTen(min).value_or(-1)), scale(scale) Small,
// LargeLegacy can be removed when fixCleanup3_2_0 is retired
LargeLegacy,
Large,
};
// This entire enum can be removed when fixCleanup3_2_0 is retired
enum class CuspRoundingFix : bool {
Disabled = false,
Enabled = true,
};
explicit constexpr MantissaRange(MantissaScale sc) : scale(sc)
{ {
} }
rep min; MantissaScale const scale;
rep max{(min * 10) - 1}; int const log{getExponent(scale)};
int log; rep const min{getMin(scale, log)};
MantissaScale scale; rep const max{(min * 10) - 1};
CuspRoundingFix const cuspRoundingFixEnabled{isCuspFixEnabled(scale)};
static MantissaRange const&
getMantissaRange(MantissaScale scale);
static std::set<MantissaScale> const&
getAllScales();
private: private:
static constexpr rep static constexpr int
getMin(MantissaScale scale) getExponent(MantissaScale scale)
{ {
switch (scale) switch (scale)
{ {
case MantissaScale::Small: case MantissaScale::Small:
return 1'000'000'000'000'000ULL; return 15;
case MantissaScale::LargeLegacy:
case MantissaScale::Large: case MantissaScale::Large:
return 1'000'000'000'000'000'000ULL; return 18;
// LCOV_EXCL_START
default: default:
// Since this can never be called outside a non-constexpr // If called in a constexpr context, this throw assures that the build fails if an
// context, this throw assures that the build fails if an
// invalid scale is used. // invalid scale is used.
throw std::runtime_error("Unknown mantissa scale"); throw std::runtime_error("Unknown mantissa scale");
// LCOV_EXCL_STOP
} }
} }
// Keep this function for future use with different ways to compute
// the ranges.
static constexpr rep
getMin(MantissaScale scale, int exponent)
{
if (exponent < 0 || exponent >= kPowerOfTen.size())
throw std::runtime_error("Invalid exponent"); // LCOV_EXCL_LINE
return kPowerOfTen[exponent];
}
static constexpr CuspRoundingFix
isCuspFixEnabled(MantissaScale scale)
{
switch (scale)
{
case MantissaScale::Small:
case MantissaScale::LargeLegacy:
return CuspRoundingFix::Disabled;
case MantissaScale::Large:
return CuspRoundingFix::Enabled;
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<MantissaScale, MantissaRange> const&
getRanges();
}; };
// Like std::integral, but only 64-bit integral types. // Like std::integral, but only 64-bit integral types.
@@ -203,7 +302,7 @@ concept Integral64 = std::is_same_v<T, std::int64_t> || std::is_same_v<T, std::u
* amendments are enabled to determine which result to expect. * amendments are enabled to determine which result to expect.
* *
*/ */
class Number class Number final
{ {
using rep = std::int64_t; using rep = std::int64_t;
using internalrep = MantissaRange::rep; using internalrep = MantissaRange::rep;
@@ -214,12 +313,12 @@ class Number
public: public:
// The range for the exponent when normalized // The range for the exponent when normalized
constexpr static int kMIN_EXPONENT = -32768; static constexpr int kMinExponent = -32768;
constexpr static int kMAX_EXPONENT = 32768; static constexpr int kMaxExponent = 32768;
constexpr static internalrep kMAX_REP = std::numeric_limits<rep>::max(); static constexpr internalrep kMaxRep = std::numeric_limits<rep>::max();
static_assert(kMAX_REP == 9'223'372'036'854'775'807); static_assert(kMaxRep == 9'223'372'036'854'775'807);
static_assert(-kMAX_REP == std::numeric_limits<rep>::min() + 1); static_assert(-kMaxRep == std::numeric_limits<rep>::min() + 1);
// May need to make unchecked private // May need to make unchecked private
struct Unchecked struct Unchecked
@@ -409,69 +508,48 @@ public:
static internalrep static internalrep
minMantissa() minMantissa()
{ {
return kRANGE.get().min; return kRange.get().min;
} }
static internalrep static internalrep
maxMantissa() maxMantissa()
{ {
return kRANGE.get().max; return kRange.get().max;
} }
static int static int
mantissaLog() mantissaLog()
{ {
return kRANGE.get().log; return kRange.get().log;
} }
/// oneSmall is needed because the ranges are private
constexpr static Number
oneSmall();
/// oneLarge is needed because the ranges are private
constexpr static Number
oneLarge();
// And one is needed because it needs to choose between oneSmall and
// oneLarge based on the current range
static Number static Number
one(); one();
template <Integral64 T> template <
auto MinMantissa,
auto MaxMantissa,
Integral64 T = std::decay_t<decltype(MinMantissa)>>
[[nodiscard]] [[nodiscard]]
std::pair<T, int> std::pair<T, int>
normalizeToRange(T minMantissa, T maxMantissa) const; normalizeToRange() const;
private: private:
static thread_local RoundingMode mode; static thread_local RoundingMode mode;
// The available ranges for mantissa // The available ranges for mantissa
constexpr static MantissaRange kSMALL_RANGE{MantissaRange::MantissaScale::Small};
static_assert(isPowerOfTen(kSMALL_RANGE.min));
static_assert(kSMALL_RANGE.min == 1'000'000'000'000'000LL);
static_assert(kSMALL_RANGE.max == 9'999'999'999'999'999LL);
static_assert(kSMALL_RANGE.log == 15);
static_assert(kSMALL_RANGE.min < kMAX_REP);
static_assert(kSMALL_RANGE.max < kMAX_REP);
constexpr static MantissaRange kLARGE_RANGE{MantissaRange::MantissaScale::Large};
static_assert(isPowerOfTen(kLARGE_RANGE.min));
static_assert(kLARGE_RANGE.min == 1'000'000'000'000'000'000ULL);
static_assert(kLARGE_RANGE.max == internalrep(9'999'999'999'999'999'999ULL));
static_assert(kLARGE_RANGE.log == 18);
static_assert(kLARGE_RANGE.min < kMAX_REP);
static_assert(kLARGE_RANGE.max > kMAX_REP);
// The range for the mantissa when normalized. // The range for the mantissa when normalized.
// Use reference_wrapper to avoid making copies, and prevent accidentally // Use reference_wrapper to avoid making copies, and prevent accidentally
// changing the values inside the range. // changing the values inside the range.
static thread_local std::reference_wrapper<MantissaRange const> kRANGE; static thread_local std::reference_wrapper<MantissaRange const> kRange;
void void
normalize(); normalize(MantissaRange const& range);
/** Normalize Number components to an arbitrary range. /** Normalize Number components to an arbitrary range.
* *
* min/maxMantissa are parameters because this function is used by both * min/maxMantissa are parameters because this function is used by both
* normalize(), which reads from kRANGE, and by normalizeToRange, * normalize(), which reads from kRange, and by normalizeToRange,
* which is public and can accept an arbitrary range from the caller. * which is public and can accept an arbitrary range from the caller.
*/ */
template <class T> template <class T>
@@ -481,7 +559,8 @@ private:
T& mantissa, T& mantissa,
int& exponent, int& exponent,
internalrep const& minMantissa, internalrep const& minMantissa,
internalrep const& maxMantissa); internalrep const& maxMantissa,
MantissaRange::CuspRoundingFix cuspRoundingFixEnabled);
template <class T> template <class T>
friend void friend void
@@ -490,7 +569,9 @@ private:
T& mantissa, T& mantissa,
int& exponent, int& exponent,
MantissaRange::rep const& minMantissa, MantissaRange::rep const& minMantissa,
MantissaRange::rep const& maxMantissa); MantissaRange::rep const& maxMantissa,
MantissaRange::CuspRoundingFix cuspRoundingFixEnabled,
bool dropped);
[[nodiscard]] bool [[nodiscard]] bool
isnormal() const noexcept; isnormal() const noexcept;
@@ -521,12 +602,12 @@ constexpr Number::Number(internalrep mantissa, int exponent, Unchecked) noexcept
{ {
} }
constexpr static Number kNUM_ZERO{}; static constexpr Number kNumZero{};
inline Number::Number(bool negative, internalrep mantissa, int exponent, Normalized) inline Number::Number(bool negative, internalrep mantissa, int exponent, Normalized)
: Number(negative, mantissa, exponent, Unchecked{}) : Number(negative, mantissa, exponent, Unchecked{})
{ {
normalize(); normalize(kRange);
} }
inline Number::Number(internalrep mantissa, int exponent, Normalized) inline Number::Number(internalrep mantissa, int exponent, Normalized)
@@ -552,10 +633,10 @@ constexpr Number::rep
Number::mantissa() const noexcept Number::mantissa() const noexcept
{ {
auto m = mantissa_; auto m = mantissa_;
if (m > kMAX_REP) if (m > kMaxRep)
{ {
XRPL_ASSERT_PARTS( XRPL_ASSERT_PARTS(
!isnormal() || (m % 10 == 0 && m / 10 <= kMAX_REP), !isnormal() || (m % 10 == 0 && m / 10 <= kMaxRep),
"xrpl::Number::mantissa", "xrpl::Number::mantissa",
"large normalized mantissa has no remainder"); "large normalized mantissa has no remainder");
m /= 10; m /= 10;
@@ -573,10 +654,10 @@ constexpr int
Number::exponent() const noexcept Number::exponent() const noexcept
{ {
auto e = exponent_; auto e = exponent_;
if (mantissa_ > kMAX_REP) if (mantissa_ > kMaxRep)
{ {
XRPL_ASSERT_PARTS( XRPL_ASSERT_PARTS(
!isnormal() || (mantissa_ % 10 == 0 && mantissa_ / 10 <= kMAX_REP), !isnormal() || (mantissa_ % 10 == 0 && mantissa_ / 10 <= kMaxRep),
"xrpl::Number::exponent", "xrpl::Number::exponent",
"large normalized mantissa has no remainder"); "large normalized mantissa has no remainder");
++e; ++e;
@@ -671,35 +752,46 @@ operator/(Number const& x, Number const& y)
inline Number inline Number
Number::min() noexcept Number::min() noexcept
{ {
return Number{false, kRANGE.get().min, kMIN_EXPONENT, Unchecked{}}; return Number{false, kRange.get().min, kMinExponent, Unchecked{}};
} }
inline Number inline Number
Number::max() noexcept Number::max() noexcept
{ {
return Number{false, std::min(kRANGE.get().max, kMAX_REP), kMAX_EXPONENT, Unchecked{}}; return Number{false, std::min(kRange.get().max, kMaxRep), kMaxExponent, Unchecked{}};
} }
inline Number inline Number
Number::lowest() noexcept Number::lowest() noexcept
{ {
return Number{true, std::min(kRANGE.get().max, kMAX_REP), kMAX_EXPONENT, Unchecked{}}; return Number{true, std::min(kRange.get().max, kMaxRep), kMaxExponent, Unchecked{}};
} }
inline bool inline bool
Number::isnormal() const noexcept Number::isnormal() const noexcept
{ {
MantissaRange const& range = kRANGE; MantissaRange const& range = kRange;
auto const absM = mantissa_; auto const absM = mantissa_;
return *this == Number{} || return *this == Number{} ||
(range.min <= absM && absM <= range.max && (absM <= kMAX_REP || absM % 10 == 0) && (range.min <= absM && absM <= range.max && (absM <= kMaxRep || absM % 10 == 0) &&
kMIN_EXPONENT <= exponent_ && exponent_ <= kMAX_EXPONENT); kMinExponent <= exponent_ && exponent_ <= kMaxExponent);
} }
template <Integral64 T> template <auto MinMantissa, auto MaxMantissa, Integral64 T>
std::pair<T, int> std::pair<T, int>
Number::normalizeToRange(T minMantissa, T maxMantissa) const Number::normalizeToRange() const
{ {
static_assert(std::is_same_v<T, std::uint64_t> || std::is_same_v<T, std::int64_t>);
static_assert(std::is_same_v<T, std::decay_t<decltype(MinMantissa)>>);
static_assert(std::is_same_v<T, std::decay_t<decltype(MaxMantissa)>>);
auto constexpr kMIN = static_cast<T>(MinMantissa);
auto constexpr kMAX = static_cast<T>(MaxMantissa);
static_assert(kMIN > 0);
static_assert(kMIN % 10 == 0);
static_assert(isPowerOfTen(kMIN));
static_assert(kMAX % 10 == 9);
static_assert((kMAX + 1) / 10 == kMIN);
bool negative = negative_; bool negative = negative_;
internalrep mantissa = mantissa_; internalrep mantissa = mantissa_;
int exponent = exponent_; int exponent = exponent_;
@@ -711,7 +803,10 @@ Number::normalizeToRange(T minMantissa, T maxMantissa) const
"xrpl::Number::normalizeToRange", "xrpl::Number::normalizeToRange",
"Number is non-negative for unsigned range."); "Number is non-negative for unsigned range.");
} }
Number::normalize(negative, mantissa, exponent, minMantissa, maxMantissa); // Don't need to worry about the cuspRounding fix because rounding up will never take the
// mantissa over maxMantissa with a ones digit value other than 0. 0 can safely be truncated.
Number::normalize(
negative, mantissa, exponent, kMIN, kMAX, MantissaRange::CuspRoundingFix::Disabled);
auto const sign = negative ? -1 : 1; auto const sign = negative ? -1 : 1;
return std::make_pair(static_cast<T>(sign * mantissa), exponent); return std::make_pair(static_cast<T>(sign * mantissa), exponent);
@@ -763,6 +858,8 @@ to_string(MantissaRange::MantissaScale const& scale)
{ {
case MantissaRange::MantissaScale::Small: case MantissaRange::MantissaScale::Small:
return "small"; return "small";
case MantissaRange::MantissaScale::LargeLegacy:
return "largeLegacy";
case MantissaRange::MantissaScale::Large: case MantissaRange::MantissaScale::Large:
return "large"; return "large";
default: default:

View File

@@ -57,10 +57,10 @@ template <class T>
std::shared_ptr<T> const& std::shared_ptr<T> const&
SharedWeakCachePointer<T>::getStrong() const SharedWeakCachePointer<T>::getStrong() const
{ {
static std::shared_ptr<T> const kEMPTY; static std::shared_ptr<T> const kEmpty;
if (auto p = std::get_if<std::shared_ptr<T>>(&combo_)) if (auto p = std::get_if<std::shared_ptr<T>>(&combo_))
return *p; return *p;
return kEMPTY; return kEmpty;
} }
template <class T> template <class T>

View File

@@ -34,7 +34,7 @@ template <typename T>
concept SomeChar = std::same_as<std::remove_cvref_t<T>, int8_t> || concept SomeChar = std::same_as<std::remove_cvref_t<T>, int8_t> ||
std::same_as<std::remove_cvref_t<T>, char> || std::same_as<std::remove_cvref_t<T>, uint8_t>; std::same_as<std::remove_cvref_t<T>, char> || std::same_as<std::remove_cvref_t<T>, uint8_t>;
inline constexpr std::array<std::optional<int>, 256> const kDIGIT_LOOKUP_TABLE = []() { inline constexpr std::array<std::optional<int>, 256> const kDigitLookupTable = []() {
std::array<std::optional<int>, 256> t{}; std::array<std::optional<int>, 256> t{};
for (int i = 0; i < 10; ++i) for (int i = 0; i < 10; ++i)
@@ -52,7 +52,7 @@ inline constexpr std::array<std::optional<int>, 256> const kDIGIT_LOOKUP_TABLE =
inline std::optional<int> inline std::optional<int>
hexCharToInt(SomeChar auto hexChar) hexCharToInt(SomeChar auto hexChar)
{ {
return kDIGIT_LOOKUP_TABLE[static_cast<uint8_t>(hexChar)]; return kDigitLookupTable[static_cast<uint8_t>(hexChar)];
} }
} // namespace detail } // namespace detail

View File

@@ -157,7 +157,7 @@ public:
/** Fetch an item from the cache. /** Fetch an item from the cache.
If the digest was not found, Handler If the digest was not found, Handler
will be called with this signature: will be called with this signature:
std::shared_ptr<SLE const>(void) SLE::const_pointer(void)
*/ */
template <class Handler> template <class Handler>
SharedPointerType SharedPointerType
@@ -181,14 +181,14 @@ private:
beast::insight::Collector::ptr const& collector) beast::insight::Collector::ptr const& collector)
: hook(collector->makeHook(handler)) : hook(collector->makeHook(handler))
, size(collector->makeGauge(prefix, "size")) , size(collector->makeGauge(prefix, "size"))
, hit_rate(collector->makeGauge(prefix, "hit_rate")) , hitRate(collector->makeGauge(prefix, "hit_rate"))
{ {
} }
beast::insight::Hook hook; beast::insight::Hook hook;
beast::insight::Gauge size; beast::insight::Gauge size;
beast::insight::Gauge hit_rate; beast::insight::Gauge hitRate;
std::size_t hits{0}; std::size_t hits{0};
std::size_t misses{0}; std::size_t misses{0};
@@ -197,16 +197,16 @@ private:
class KeyOnlyEntry class KeyOnlyEntry
{ {
public: public:
clock_type::time_point last_access; clock_type::time_point lastAccess;
explicit KeyOnlyEntry(clock_type::time_point const& lastAccess) : last_access(lastAccess) explicit KeyOnlyEntry(clock_type::time_point const& lastAccess) : lastAccess(lastAccess)
{ {
} }
void void
touch(clock_type::time_point const& now) touch(clock_type::time_point const& now)
{ {
last_access = now; lastAccess = now;
} }
}; };
@@ -214,10 +214,10 @@ private:
{ {
public: public:
shared_weak_combo_pointer_type ptr; shared_weak_combo_pointer_type ptr;
clock_type::time_point last_access; clock_type::time_point lastAccess;
ValueEntry(clock_type::time_point const& lastAccess, shared_pointer_type const& ptr) ValueEntry(clock_type::time_point const& lastAccess, shared_pointer_type const& ptr)
: ptr(ptr), last_access(lastAccess) : ptr(ptr), lastAccess(lastAccess)
{ {
} }
@@ -246,7 +246,7 @@ private:
void void
touch(clock_type::time_point const& now) touch(clock_type::time_point const& now)
{ {
last_access = now; lastAccess = now;
} }
}; };
@@ -286,13 +286,13 @@ private:
std::string name_; std::string name_;
// Desired number of cache entries (0 = ignore) // Desired number of cache entries (0 = ignore)
int const target_size_; int const targetSize_;
// Desired maximum cache age // Desired maximum cache age
clock_type::duration const target_age_; clock_type::duration const targetAge_;
// Number of items cached // Number of items cached
int cache_count_{0}; int cacheCount_{0};
cache_type cache_; // Hold strong reference to recent objects cache_type cache_; // Hold strong reference to recent objects
std::uint64_t hits_{0}; std::uint64_t hits_{0};
std::uint64_t misses_{0}; std::uint64_t misses_{0};

View File

@@ -34,8 +34,8 @@ inline TaggedCache<
, clock_(clock) , clock_(clock)
, stats_(name, std::bind(&TaggedCache::collectMetrics, this), collector) , stats_(name, std::bind(&TaggedCache::collectMetrics, this), collector)
, name_(name) , name_(name)
, target_size_(size) , targetSize_(size)
, target_age_(expiration) , targetAge_(expiration)
{ {
} }
@@ -86,7 +86,7 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
getCacheSize() const getCacheSize() const
{ {
std::scoped_lock const lock(mutex_); std::scoped_lock const lock(mutex_);
return cache_count_; return cacheCount_;
} }
template < template <
@@ -139,7 +139,7 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
{ {
std::scoped_lock const lock(mutex_); std::scoped_lock const lock(mutex_);
cache_.clear(); cache_.clear();
cache_count_ = 0; cacheCount_ = 0;
} }
template < template <
@@ -157,7 +157,7 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
{ {
std::scoped_lock const lock(mutex_); std::scoped_lock const lock(mutex_);
cache_.clear(); cache_.clear();
cache_count_ = 0; cacheCount_ = 0;
hits_ = 0; hits_ = 0;
misses_ = 0; misses_ = 0;
} }
@@ -213,21 +213,21 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
{ {
std::scoped_lock const lock(mutex_); std::scoped_lock const lock(mutex_);
if (target_size_ == 0 || (static_cast<int>(cache_.size()) <= target_size_)) if (targetSize_ == 0 || (static_cast<int>(cache_.size()) <= targetSize_))
{ {
whenExpire = now - target_age_; whenExpire = now - targetAge_;
} }
else else
{ {
whenExpire = now - (target_age_ * target_size_ / cache_.size()); whenExpire = now - (targetAge_ * targetSize_ / cache_.size());
clock_type::duration const minimumAge(std::chrono::seconds(1)); clock_type::duration const minimumAge(std::chrono::seconds(1));
if (whenExpire > (now - minimumAge)) if (whenExpire > (now - minimumAge))
whenExpire = now - minimumAge; whenExpire = now - minimumAge;
JLOG(journal_.trace()) JLOG(journal_.trace())
<< name_ << " is growing fast " << cache_.size() << " of " << target_size_ << name_ << " is growing fast " << cache_.size() << " of " << targetSize_
<< " aging at " << (now - whenExpire).count() << " of " << target_age_.count(); << " aging at " << (now - whenExpire).count() << " of " << targetAge_.count();
} }
std::vector<std::thread> workers; std::vector<std::thread> workers;
@@ -242,7 +242,7 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
for (std::thread& worker : workers) for (std::thread& worker : workers)
worker.join(); worker.join();
cache_count_ -= allRemovals; cacheCount_ -= allRemovals;
} }
// At this point allStuffToSweep will go out of scope outside the lock // At this point allStuffToSweep will go out of scope outside the lock
// and decrement the reference count on each strong pointer. // and decrement the reference count on each strong pointer.
@@ -280,7 +280,7 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
if (entry.isCached()) if (entry.isCached())
{ {
--cache_count_; --cacheCount_;
entry.ptr.convertToWeak(); entry.ptr.convertToWeak();
ret = true; ret = true;
} }
@@ -317,7 +317,7 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
std::piecewise_construct, std::piecewise_construct,
std::forward_as_tuple(key), std::forward_as_tuple(key),
std::forward_as_tuple(clock_.now(), data)); std::forward_as_tuple(clock_.now(), data));
++cache_count_; ++cacheCount_;
return false; return false;
} }
@@ -366,12 +366,12 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
data = cachedData; data = cachedData;
} }
++cache_count_; ++cacheCount_;
return true; return true;
} }
entry.ptr = data; entry.ptr = data;
++cache_count_; ++cacheCount_;
return false; return false;
} }
@@ -477,7 +477,7 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
auto [it, inserted] = cache_.emplace( auto [it, inserted] = cache_.emplace(
std::piecewise_construct, std::forward_as_tuple(key), std::forward_as_tuple(now)); std::piecewise_construct, std::forward_as_tuple(key), std::forward_as_tuple(now));
if (!inserted) if (!inserted)
it->second.last_access = now; it->second.lastAccess = now;
return inserted; return inserted;
} }
@@ -626,7 +626,7 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
if (entry.isCached()) if (entry.isCached())
{ {
// independent of cache size, so not counted as a hit // independent of cache size, so not counted as a hit
++cache_count_; ++cacheCount_;
entry.touch(clock_.now()); entry.touch(clock_.now());
return entry.ptr.getStrong(); return entry.ptr.getStrong();
} }
@@ -658,7 +658,7 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
if (total != 0) if (total != 0)
hitRate = (hits_ * 100) / total; hitRate = (hits_ * 100) / total;
} }
stats_.hit_rate.set(hitRate); stats_.hitRate.set(hitRate);
} }
} }
@@ -706,7 +706,7 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
++cit; ++cit;
} }
} }
else if (cit->second.last_access <= whenExpire) else if (cit->second.lastAccess <= whenExpire)
{ {
// strong, expired // strong, expired
++cacheRemovals; ++cacheRemovals;
@@ -773,12 +773,12 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
auto cit = partition.begin(); auto cit = partition.begin();
while (cit != partition.end()) while (cit != partition.end())
{ {
if (cit->second.last_access > now) if (cit->second.lastAccess > now)
{ {
cit->second.last_access = now; cit->second.lastAccess = now;
++cit; ++cit;
} }
else if (cit->second.last_access <= whenExpire) else if (cit->second.lastAccess <= whenExpire)
{ {
cit = partition.erase(cit); cit = partition.erase(cit);
} }

View File

@@ -30,8 +30,8 @@ public:
now(); // seconds since xrpld program start now(); // seconds since xrpld program start
private: private:
static std::atomic<rep> kNOW; static std::atomic<rep> kNow;
static std::atomic<bool> kSTOP; static std::atomic<bool> kStop;
struct UpdateThread : private std::thread struct UpdateThread : private std::thread
{ {

View File

@@ -73,12 +73,12 @@ class BaseUInt
static_assert(Bits >= 64, "The length of a base_uint in bits must be at least 64."); static_assert(Bits >= 64, "The length of a base_uint in bits must be at least 64.");
static constexpr std::size_t kWIDTH = Bits / 32; static constexpr std::size_t kWidth = Bits / 32;
// This is really big-endian in byte order. // This is really big-endian in byte order.
// We sometimes use std::uint32_t for speed. // We sometimes use std::uint32_t for speed.
std::array<std::uint32_t, kWIDTH> data_; std::array<std::uint32_t, kWidth> data_;
public: public:
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
@@ -86,8 +86,8 @@ public:
// STL Container Interface // STL Container Interface
// //
static std::size_t constexpr kBYTES = Bits / 8; 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 size_type = std::size_t;
using difference_type = std::ptrdiff_t; using difference_type = std::ptrdiff_t;
@@ -121,7 +121,7 @@ public:
iterator iterator
end() end()
{ {
return data() + kBYTES; return data() + kBytes;
} }
[[nodiscard]] const_iterator [[nodiscard]] const_iterator
begin() const begin() const
@@ -131,7 +131,7 @@ public:
[[nodiscard]] const_iterator [[nodiscard]] const_iterator
end() const end() const
{ {
return data() + kBYTES; return data() + kBytes;
} }
[[nodiscard]] const_iterator [[nodiscard]] const_iterator
cbegin() const cbegin() const
@@ -141,7 +141,7 @@ public:
[[nodiscard]] const_iterator [[nodiscard]] const_iterator
cend() const cend() const
{ {
return data() + kBYTES; return data() + kBytes;
} }
/** Value hashing function. /** Value hashing function.
@@ -167,7 +167,7 @@ private:
explicit BaseUInt(void const* data, VoidHelper) explicit BaseUInt(void const* data, VoidHelper)
{ {
memcpy(data_.data(), data, kBYTES); memcpy(data_.data(), data, kBytes);
} }
// Helper function to initialize a base_uint from a std::string_view. // Helper function to initialize a base_uint from a std::string_view.
@@ -336,7 +336,7 @@ public:
[[nodiscard]] constexpr int [[nodiscard]] constexpr int
signum() const signum() const
{ {
for (int i = 0; i < kWIDTH; i++) for (int i = 0; i < kWidth; i++)
{ {
if (data_[i] != 0) if (data_[i] != 0)
return 1; return 1;
@@ -348,7 +348,7 @@ public:
bool bool
operator!() const operator!() const
{ {
return *this == beast::kZERO; return *this == beast::kZero;
} }
constexpr BaseUInt constexpr BaseUInt
@@ -356,7 +356,7 @@ public:
{ {
BaseUInt ret; BaseUInt ret;
for (int i = 0; i < kWIDTH; i++) for (int i = 0; i < kWidth; i++)
ret.data_[i] = ~data_[i]; ret.data_[i] = ~data_[i];
return ret; return ret;
@@ -365,7 +365,7 @@ public:
BaseUInt& BaseUInt&
operator=(std::uint64_t uHost) operator=(std::uint64_t uHost)
{ {
*this = beast::kZERO; *this = beast::kZero;
// NOLINTBEGIN(cppcoreguidelines-pro-type-member-init) // NOLINTBEGIN(cppcoreguidelines-pro-type-member-init)
union union
{ {
@@ -375,15 +375,15 @@ public:
// NOLINTEND(cppcoreguidelines-pro-type-member-init) // NOLINTEND(cppcoreguidelines-pro-type-member-init)
// Put in least significant bits. // Put in least significant bits.
ul = boost::endian::native_to_big(uHost); ul = boost::endian::native_to_big(uHost);
data_[kWIDTH - 2] = u[0]; data_[kWidth - 2] = u[0];
data_[kWIDTH - 1] = u[1]; data_[kWidth - 1] = u[1];
return *this; return *this;
} }
BaseUInt& BaseUInt&
operator^=(BaseUInt const& b) operator^=(BaseUInt const& b)
{ {
for (int i = 0; i < kWIDTH; i++) for (int i = 0; i < kWidth; i++)
data_[i] ^= b.data_[i]; data_[i] ^= b.data_[i];
return *this; return *this;
@@ -392,7 +392,7 @@ public:
BaseUInt& BaseUInt&
operator&=(BaseUInt const& b) operator&=(BaseUInt const& b)
{ {
for (int i = 0; i < kWIDTH; i++) for (int i = 0; i < kWidth; i++)
data_[i] &= b.data_[i]; data_[i] &= b.data_[i];
return *this; return *this;
@@ -401,7 +401,7 @@ public:
BaseUInt& BaseUInt&
operator|=(BaseUInt const& b) operator|=(BaseUInt const& b)
{ {
for (int i = 0; i < kWIDTH; i++) for (int i = 0; i < kWidth; i++)
data_[i] |= b.data_[i]; data_[i] |= b.data_[i];
return *this; return *this;
@@ -411,7 +411,7 @@ public:
operator++() operator++()
{ {
// prefix operator // prefix operator
for (int i = kWIDTH - 1; i >= 0; --i) for (int i = kWidth - 1; i >= 0; --i)
{ {
data_[i] = boost::endian::native_to_big(boost::endian::big_to_native(data_[i]) + 1); data_[i] = boost::endian::native_to_big(boost::endian::big_to_native(data_[i]) + 1);
if (data_[i] != 0) if (data_[i] != 0)
@@ -434,7 +434,7 @@ public:
BaseUInt& BaseUInt&
operator--() operator--()
{ {
for (int i = kWIDTH - 1; i >= 0; --i) for (int i = kWidth - 1; i >= 0; --i)
{ {
auto prev = data_[i]; auto prev = data_[i];
data_[i] = boost::endian::native_to_big(boost::endian::big_to_native(data_[i]) - 1); data_[i] = boost::endian::native_to_big(boost::endian::big_to_native(data_[i]) - 1);
@@ -475,7 +475,7 @@ public:
{ {
std::uint64_t carry = 0; std::uint64_t carry = 0;
for (int i = kWIDTH - 1; i >= 0; i--) for (int i = kWidth - 1; i >= 0; i--)
{ {
std::uint64_t const n = carry + boost::endian::big_to_native(data_[i]) + std::uint64_t const n = carry + boost::endian::big_to_native(data_[i]) +
boost::endian::big_to_native(b.data_[i]); boost::endian::big_to_native(b.data_[i]);
@@ -526,10 +526,10 @@ public:
return parseHex(std::string_view{str}); return parseHex(std::string_view{str});
} }
constexpr static std::size_t static constexpr std::size_t
size() size()
{ {
return kBYTES; return kBytes;
} }
BaseUInt<Bits, Tag>& BaseUInt<Bits, Tag>&
@@ -543,17 +543,17 @@ public:
[[nodiscard]] bool [[nodiscard]] bool
isZero() const isZero() const
{ {
return *this == beast::kZERO; return *this == beast::kZero;
} }
[[nodiscard]] bool [[nodiscard]] bool
isNonZero() const isNonZero() const
{ {
return *this != beast::kZERO; return *this != beast::kZero;
} }
void void
zero() zero()
{ {
*this = beast::kZERO; *this = beast::kZero;
} }
}; };
@@ -639,7 +639,7 @@ template <std::size_t Bits, class Tag>
inline std::string inline std::string
toShortString(BaseUInt<Bits, Tag> const& a) toShortString(BaseUInt<Bits, Tag> const& a)
{ {
static_assert(BaseUInt<Bits, Tag>::kBYTES > 4, "For 4 bytes or less, use a native type"); static_assert(BaseUInt<Bits, Tag>::kBytes > 4, "For 4 bytes or less, use a native type");
return strHex(a.cbegin(), a.cbegin() + 4) + "..."; return strHex(a.cbegin(), a.cbegin() + 4) + "...";
} }

View File

@@ -30,10 +30,10 @@ using weeks = std::chrono::duration<int, std::ratio_multiply<days::period, std::
= seconds(946684800) = seconds(946684800)
*/ */
constexpr static std::chrono::seconds kEPOCH_OFFSET = static constexpr std::chrono::seconds kEpochOffset =
date::sys_days{date::year{2000} / 1 / 1} - date::sys_days{date::year{1970} / 1 / 1}; date::sys_days{date::year{2000} / 1 / 1} - date::sys_days{date::year{1970} / 1 / 1};
static_assert(kEPOCH_OFFSET.count() == 946684800); static_assert(kEpochOffset.count() == 946684800);
class NetClock class NetClock
{ {
@@ -60,7 +60,7 @@ to_string(NetClock::time_point tp)
{ {
// 2000-01-01 00:00:00 UTC is 946684800s from 1970-01-01 00:00:00 UTC // 2000-01-01 00:00:00 UTC is 946684800s from 1970-01-01 00:00:00 UTC
using namespace std::chrono; using namespace std::chrono;
return to_string(system_clock::time_point{tp.time_since_epoch() + kEPOCH_OFFSET}); return to_string(system_clock::time_point{tp.time_since_epoch() + kEpochOffset});
} }
template <class Duration> template <class Duration>
@@ -77,7 +77,7 @@ toStringIso(NetClock::time_point tp)
// 2000-01-01 00:00:00 UTC is 946684800s from 1970-01-01 00:00:00 UTC // 2000-01-01 00:00:00 UTC is 946684800s from 1970-01-01 00:00:00 UTC
// Note, NetClock::duration is seconds, as checked by static_assert // Note, NetClock::duration is seconds, as checked by static_assert
static_assert(std::is_same_v<NetClock::duration::period, std::ratio<1>>); static_assert(std::is_same_v<NetClock::duration::period, std::ratio<1>>);
return toStringIso(date::sys_time<NetClock::duration>{tp.time_since_epoch() + kEPOCH_OFFSET}); return toStringIso(date::sys_time<NetClock::duration>{tp.time_since_epoch() + kEpochOffset});
} }
/** A clock for measuring elapsed time. /** A clock for measuring elapsed time.

View File

@@ -31,9 +31,9 @@ makeSeedPair() noexcept
// state_t(state_t const&) = delete; // state_t(state_t const&) = delete;
// state_t& operator=(state_t const&) = delete; // state_t& operator=(state_t const&) = delete;
}; };
static StateT kSTATE; static StateT kState;
std::scoped_lock const lock(kSTATE.mutex); std::scoped_lock const lock(kState.mutex);
return {kSTATE.dist(kSTATE.gen), kSTATE.dist(kSTATE.gen)}; return {kState.dist(kState.gen), kState.dist(kState.gen)};
} }
} // namespace detail } // namespace detail

View File

@@ -5,7 +5,7 @@
#include <optional> #include <optional>
namespace xrpl { namespace xrpl {
auto constexpr kMULDIV_MAX = std::numeric_limits<std::uint64_t>::max(); constexpr auto kMuldivMax = std::numeric_limits<std::uint64_t>::max();
/** Return value*mul/div accurately. /** Return value*mul/div accurately.
Computes the result of the multiplication and division in Computes the result of the multiplication and division in

View File

@@ -47,7 +47,7 @@ inline beast::xor_shift_engine&
defaultPrng() defaultPrng()
{ {
// This is used to seed the thread-specific PRNGs on demand // This is used to seed the thread-specific PRNGs on demand
static beast::xor_shift_engine kSEEDER = [] { static beast::xor_shift_engine kSeeder = [] {
std::random_device rng; std::random_device rng;
std::uniform_int_distribution<std::uint64_t> distribution{1}; std::uniform_int_distribution<std::uint64_t> distribution{1};
return beast::xor_shift_engine(distribution(rng)); return beast::xor_shift_engine(distribution(rng));
@@ -57,17 +57,17 @@ defaultPrng()
static std::mutex kM; static std::mutex kM;
// The thread-specific PRNGs: // The thread-specific PRNGs:
thread_local beast::xor_shift_engine kENGINE = [] { thread_local beast::xor_shift_engine kEngine = [] {
std::uint64_t seed = 0; std::uint64_t seed = 0;
{ {
std::scoped_lock const lk(kM); std::scoped_lock const lk(kM);
std::uniform_int_distribution<std::uint64_t> distribution{1}; std::uniform_int_distribution<std::uint64_t> distribution{1};
seed = distribution(kSEEDER); seed = distribution(kSeeder);
} }
return beast::xor_shift_engine{seed}; return beast::xor_shift_engine{seed};
}(); }();
return kENGINE; return kEngine;
} }
/** Return a uniformly distributed random integer. /** Return a uniformly distributed random integer.

View File

@@ -22,9 +22,9 @@ safeCast(Src s) noexcept
{ {
static_assert( static_assert(
std::is_signed_v<Dest> || std::is_unsigned_v<Src>, "Cannot cast signed to unsigned"); std::is_signed_v<Dest> || std::is_unsigned_v<Src>, "Cannot cast signed to unsigned");
constexpr unsigned kNOT_SAME = std::is_signed_v<Dest> != std::is_signed_v<Src>; constexpr unsigned kNotSame = std::is_signed_v<Dest> != std::is_signed_v<Src>;
static_assert( static_assert(
sizeof(Dest) >= sizeof(Src) + kNOT_SAME, sizeof(Dest) >= sizeof(Src) + kNotSame,
"Destination is too small to hold all values of source"); "Destination is too small to hold all values of source");
return static_cast<Dest>(s); return static_cast<Dest>(s);
} }

View File

@@ -24,20 +24,20 @@ namespace xrpl {
template <class EF> template <class EF>
class ScopeExit class ScopeExit
{ {
EF exit_function_; EF exitFunction_;
bool execute_on_destruction_{true}; bool executeOnDestruction_{true};
public: public:
~ScopeExit() ~ScopeExit()
{ {
if (execute_on_destruction_) if (executeOnDestruction_)
exit_function_(); exitFunction_();
} }
ScopeExit(ScopeExit&& rhs) noexcept( ScopeExit(ScopeExit&& rhs) noexcept(
std::is_nothrow_move_constructible_v<EF> || std::is_nothrow_copy_constructible_v<EF>) std::is_nothrow_move_constructible_v<EF> || std::is_nothrow_copy_constructible_v<EF>)
: exit_function_{std::forward<EF>(rhs.exit_function_)} : exitFunction_{std::forward<EF>(rhs.exitFunction_)}
, execute_on_destruction_{rhs.execute_on_destruction_} , executeOnDestruction_{rhs.executeOnDestruction_}
{ {
rhs.release(); rhs.release();
} }
@@ -51,7 +51,7 @@ public:
std::enable_if_t< std::enable_if_t<
!std::is_same_v<std::remove_cv_t<EFP>, ScopeExit> && !std::is_same_v<std::remove_cv_t<EFP>, ScopeExit> &&
std::is_constructible_v<EF, EFP>>* = 0) noexcept std::is_constructible_v<EF, EFP>>* = 0) noexcept
: exit_function_{std::forward<EFP>(f)} : exitFunction_{std::forward<EFP>(f)}
{ {
static_assert(std::is_nothrow_constructible_v<EF, decltype(std::forward<EFP>(f))>); static_assert(std::is_nothrow_constructible_v<EF, decltype(std::forward<EFP>(f))>);
} }
@@ -59,7 +59,7 @@ public:
void void
release() noexcept release() noexcept
{ {
execute_on_destruction_ = false; executeOnDestruction_ = false;
} }
}; };
@@ -69,22 +69,22 @@ ScopeExit(EF) -> ScopeExit<EF>;
template <class EF> template <class EF>
class ScopeFail class ScopeFail
{ {
EF exit_function_; EF exitFunction_;
bool execute_on_destruction_{true}; bool executeOnDestruction_{true};
int uncaught_on_creation_{std::uncaught_exceptions()}; int uncaughtOnCreation_{std::uncaught_exceptions()};
public: public:
~ScopeFail() ~ScopeFail()
{ {
if (execute_on_destruction_ && std::uncaught_exceptions() > uncaught_on_creation_) if (executeOnDestruction_ && std::uncaught_exceptions() > uncaughtOnCreation_)
exit_function_(); exitFunction_();
} }
ScopeFail(ScopeFail&& rhs) noexcept( ScopeFail(ScopeFail&& rhs) noexcept(
std::is_nothrow_move_constructible_v<EF> || std::is_nothrow_copy_constructible_v<EF>) std::is_nothrow_move_constructible_v<EF> || std::is_nothrow_copy_constructible_v<EF>)
: exit_function_{std::forward<EF>(rhs.exit_function_)} : exitFunction_{std::forward<EF>(rhs.exitFunction_)}
, execute_on_destruction_{rhs.execute_on_destruction_} , executeOnDestruction_{rhs.executeOnDestruction_}
, uncaught_on_creation_{rhs.uncaught_on_creation_} , uncaughtOnCreation_{rhs.uncaughtOnCreation_}
{ {
rhs.release(); rhs.release();
} }
@@ -98,7 +98,7 @@ public:
std::enable_if_t< std::enable_if_t<
!std::is_same_v<std::remove_cv_t<EFP>, ScopeFail> && !std::is_same_v<std::remove_cv_t<EFP>, ScopeFail> &&
std::is_constructible_v<EF, EFP>>* = 0) noexcept std::is_constructible_v<EF, EFP>>* = 0) noexcept
: exit_function_{std::forward<EFP>(f)} : exitFunction_{std::forward<EFP>(f)}
{ {
static_assert(std::is_nothrow_constructible_v<EF, decltype(std::forward<EFP>(f))>); static_assert(std::is_nothrow_constructible_v<EF, decltype(std::forward<EFP>(f))>);
} }
@@ -106,7 +106,7 @@ public:
void void
release() noexcept release() noexcept
{ {
execute_on_destruction_ = false; executeOnDestruction_ = false;
} }
}; };
@@ -116,22 +116,22 @@ ScopeFail(EF) -> ScopeFail<EF>;
template <class EF> template <class EF>
class ScopeSuccess class ScopeSuccess
{ {
EF exit_function_; EF exitFunction_;
bool execute_on_destruction_{true}; bool executeOnDestruction_{true};
int uncaught_on_creation_{std::uncaught_exceptions()}; int uncaughtOnCreation_{std::uncaught_exceptions()};
public: public:
~ScopeSuccess() noexcept(noexcept(exit_function_())) ~ScopeSuccess() noexcept(noexcept(exitFunction_()))
{ {
if (execute_on_destruction_ && std::uncaught_exceptions() <= uncaught_on_creation_) if (executeOnDestruction_ && std::uncaught_exceptions() <= uncaughtOnCreation_)
exit_function_(); exitFunction_();
} }
ScopeSuccess(ScopeSuccess&& rhs) noexcept( ScopeSuccess(ScopeSuccess&& rhs) noexcept(
std::is_nothrow_move_constructible_v<EF> || std::is_nothrow_copy_constructible_v<EF>) std::is_nothrow_move_constructible_v<EF> || std::is_nothrow_copy_constructible_v<EF>)
: exit_function_{std::forward<EF>(rhs.exit_function_)} : exitFunction_{std::forward<EF>(rhs.exitFunction_)}
, execute_on_destruction_{rhs.execute_on_destruction_} , executeOnDestruction_{rhs.executeOnDestruction_}
, uncaught_on_creation_{rhs.uncaught_on_creation_} , uncaughtOnCreation_{rhs.uncaughtOnCreation_}
{ {
rhs.release(); rhs.release();
} }
@@ -146,14 +146,14 @@ public:
!std::is_same_v<std::remove_cv_t<EFP>, ScopeSuccess> && !std::is_same_v<std::remove_cv_t<EFP>, ScopeSuccess> &&
std::is_constructible_v<EF, EFP>>* = std::is_constructible_v<EF, EFP>>* =
0) noexcept(std::is_nothrow_constructible_v<EF, EFP> || std::is_nothrow_constructible_v<EF, EFP&>) 0) noexcept(std::is_nothrow_constructible_v<EF, EFP> || std::is_nothrow_constructible_v<EF, EFP&>)
: exit_function_{std::forward<EFP>(f)} : exitFunction_{std::forward<EFP>(f)}
{ {
} }
void void
release() noexcept release() noexcept
{ {
execute_on_destruction_ = false; executeOnDestruction_ = false;
} }
}; };

View File

@@ -83,8 +83,8 @@ template <class Facade, class Clock = Facade>
AbstractClock<Facade>& AbstractClock<Facade>&
getAbstractClock() getAbstractClock()
{ {
static detail::AbstractClockWrapper<Facade, Clock> kCLOCK; static detail::AbstractClockWrapper<Facade, Clock> kClock;
return kCLOCK; return kClock;
} }
} // namespace beast } // namespace beast

View File

@@ -21,7 +21,7 @@ setCurrentThreadName(std::string_view newThreadName);
// On Linux, thread names are limited to 16 bytes including the null terminator. // On Linux, thread names are limited to 16 bytes including the null terminator.
// Maximum number of characters is therefore 15. // Maximum number of characters is therefore 15.
constexpr std::size_t kMAX_THREAD_NAME_LENGTH = 15; constexpr std::size_t kMaxThreadNameLength = 15;
/** Sets the name of the caller thread with compile-time size checking. /** Sets the name of the caller thread with compile-time size checking.
@tparam N The size of the string literal including null terminator @tparam N The size of the string literal including null terminator
@@ -34,7 +34,7 @@ template <std::size_t N>
void void
setCurrentThreadName(char const (&newThreadName)[N]) setCurrentThreadName(char const (&newThreadName)[N])
{ {
static_assert(N <= kMAX_THREAD_NAME_LENGTH + 1, "Thread name cannot exceed 15 characters"); static_assert(N <= kMaxThreadNameLength + 1, "Thread name cannot exceed 15 characters");
setCurrentThreadName(std::string_view(newThreadName, N - 1)); setCurrentThreadName(std::string_view(newThreadName, N - 1));
} }

View File

@@ -53,7 +53,7 @@ inline void
maybeReverseBytes(T& t, Hasher&) maybeReverseBytes(T& t, Hasher&)
{ {
maybeReverseBytes( maybeReverseBytes(
t, std::integral_constant<bool, Hasher::kENDIAN != boost::endian::order::native>{}); t, std::integral_constant<bool, Hasher::kEndian != boost::endian::order::native>{});
} }
} // namespace detail } // namespace detail
@@ -154,7 +154,7 @@ struct IsContiguouslyHashable
: public std::integral_constant< : public std::integral_constant<
bool, bool,
IsUniquelyRepresented<T>::value && IsUniquelyRepresented<T>::value &&
(sizeof(T) == 1 || HashAlgorithm::kENDIAN == boost::endian::order::native)> (sizeof(T) == 1 || HashAlgorithm::kEndian == boost::endian::order::native)>
{ {
explicit IsContiguouslyHashable() = default; explicit IsContiguouslyHashable() = default;
}; };

View File

@@ -21,9 +21,9 @@ private:
static_assert(sizeof(std::size_t) == 8, "requires 64-bit std::size_t"); static_assert(sizeof(std::size_t) == 8, "requires 64-bit std::size_t");
// Have an internal buffer to avoid the streaming API // Have an internal buffer to avoid the streaming API
// A 64-byte buffer should to be big enough for us // A 64-byte buffer should to be big enough for us
static constexpr std::size_t kINTERNAL_BUFFER_SIZE = 64; static constexpr std::size_t kInternalBufferSize = 64;
alignas(64) std::array<std::uint8_t, kINTERNAL_BUFFER_SIZE> buffer_{}; alignas(64) std::array<std::uint8_t, kInternalBufferSize> buffer_{};
std::span<std::uint8_t> readBuffer_; std::span<std::uint8_t> readBuffer_;
std::span<std::uint8_t> writeBuffer_; std::span<std::uint8_t> writeBuffer_;
@@ -102,7 +102,7 @@ private:
} }
public: public:
static constexpr auto const kENDIAN = boost::endian::order::native; static constexpr auto kEndian = boost::endian::order::native;
Xxhasher(Xxhasher const&) = delete; Xxhasher(Xxhasher const&) = delete;
Xxhasher& Xxhasher&

View File

@@ -62,7 +62,7 @@ private:
{ {
using run_time = std::pair<std::string, typename clock_type::duration>; using run_time = std::pair<std::string, typename clock_type::duration>;
static constexpr auto kMAX_TOP = 10; static constexpr auto kMaxTop = 10;
std::size_t suites = 0; std::size_t suites = 0;
std::size_t cases = 0; std::size_t cases = 0;
@@ -77,8 +77,8 @@ private:
std::ostream& os_; std::ostream& os_;
Results results_; Results results_;
SuiteResults suite_results_; SuiteResults suiteResults_;
CaseResults case_results_; CaseResults caseResults_;
public: public:
Reporter(Reporter const&) = delete; Reporter(Reporter const&) = delete;
@@ -146,11 +146,11 @@ Reporter<Unused>::Results::add(SuiteResults const& r)
}); });
if (iter != top.end()) if (iter != top.end())
{ {
if (top.size() == kMAX_TOP) if (top.size() == kMaxTop)
top.resize(top.size() - 1); top.resize(top.size() - 1);
top.emplace(iter, r.name, elapsed); top.emplace(iter, r.name, elapsed);
} }
else if (top.size() < kMAX_TOP) else if (top.size() < kMaxTop)
{ {
top.emplace_back(r.name, elapsed); top.emplace_back(r.name, elapsed);
} }
@@ -196,22 +196,22 @@ template <class Unused>
void void
Reporter<Unused>::onSuiteBegin(SuiteInfo const& info) Reporter<Unused>::onSuiteBegin(SuiteInfo const& info)
{ {
suite_results_ = SuiteResults{info.fullName()}; suiteResults_ = SuiteResults{info.fullName()};
} }
template <class Unused> template <class Unused>
void void
Reporter<Unused>::onSuiteEnd() Reporter<Unused>::onSuiteEnd()
{ {
results_.add(suite_results_); results_.add(suiteResults_);
} }
template <class Unused> template <class Unused>
void void
Reporter<Unused>::onCaseBegin(std::string const& name) Reporter<Unused>::onCaseBegin(std::string const& name)
{ {
case_results_ = CaseResults(name); caseResults_ = CaseResults(name);
os_ << suite_results_.name << (case_results_.name.empty() ? "" : (" " + case_results_.name)) os_ << suiteResults_.name << (caseResults_.name.empty() ? "" : (" " + caseResults_.name))
<< std::endl; << std::endl;
} }
@@ -219,23 +219,23 @@ template <class Unused>
void void
Reporter<Unused>::onCaseEnd() Reporter<Unused>::onCaseEnd()
{ {
suite_results_.add(case_results_); suiteResults_.add(caseResults_);
} }
template <class Unused> template <class Unused>
void void
Reporter<Unused>::onPass() Reporter<Unused>::onPass()
{ {
++case_results_.total; ++caseResults_.total;
} }
template <class Unused> template <class Unused>
void void
Reporter<Unused>::onFail(std::string const& reason) Reporter<Unused>::onFail(std::string const& reason)
{ {
++case_results_.failed; ++caseResults_.failed;
++case_results_.total; ++caseResults_.total;
os_ << "#" << case_results_.total << " failed" << (reason.empty() ? "" : ": ") << reason os_ << "#" << caseResults_.total << " failed" << (reason.empty() ? "" : ": ") << reason
<< std::endl; << std::endl;
} }

View File

@@ -299,8 +299,8 @@ private:
static Suite** static Suite**
pThisSuite() pThisSuite()
{ {
static Suite* kP_TS = nullptr; // NOLINT TODO static Suite* kPTs = nullptr; // NOLINT TODO
return &kP_TS; return &kPTs;
} }
/** Runs the suite. */ /** Runs the suite. */

View File

@@ -27,7 +27,7 @@ struct Zero
}; };
namespace { namespace {
constexpr Zero kZERO{}; constexpr Zero kZero{};
} // namespace } // namespace
/** Default implementation of signum calls the method on the class. */ /** Default implementation of signum calls the method on the class. */
@@ -102,42 +102,42 @@ template <typename T>
bool bool
operator==(Zero, T const& t) operator==(Zero, T const& t)
{ {
return t == kZERO; return t == kZero;
} }
template <typename T> template <typename T>
bool bool
operator!=(Zero, T const& t) operator!=(Zero, T const& t)
{ {
return t != kZERO; return t != kZero;
} }
template <typename T> template <typename T>
bool bool
operator<(Zero, T const& t) operator<(Zero, T const& t)
{ {
return t > kZERO; return t > kZero;
} }
template <typename T> template <typename T>
bool bool
operator>(Zero, T const& t) operator>(Zero, T const& t)
{ {
return t < kZERO; return t < kZero;
} }
template <typename T> template <typename T>
bool bool
operator>=(Zero, T const& t) operator>=(Zero, T const& t)
{ {
return t <= kZERO; return t <= kZero;
} }
template <typename T> template <typename T>
bool bool
operator<=(Zero, T const& t) operator<=(Zero, T const& t)
{ {
return t >= kZERO; return t >= kZero;
} }
} // namespace beast } // namespace beast

View File

@@ -14,23 +14,23 @@ void
rngfill(void* const buffer, std::size_t const bytes, Generator& g) rngfill(void* const buffer, std::size_t const bytes, Generator& g)
{ {
using result_type = typename Generator::result_type; using result_type = typename Generator::result_type;
constexpr std::size_t kRESULT_SIZE = sizeof(result_type); constexpr std::size_t kResultSize = sizeof(result_type);
std::uint8_t* const bufferStart = static_cast<std::uint8_t*>(buffer); std::uint8_t* const bufferStart = static_cast<std::uint8_t*>(buffer);
std::size_t const completeIterations = bytes / kRESULT_SIZE; std::size_t const completeIterations = bytes / kResultSize;
std::size_t const bytesRemaining = bytes % kRESULT_SIZE; std::size_t const bytesRemaining = bytes % kResultSize;
for (std::size_t count = 0; count < completeIterations; ++count) for (std::size_t count = 0; count < completeIterations; ++count)
{ {
result_type const v = g(); result_type const v = g();
std::size_t const offset = count * kRESULT_SIZE; std::size_t const offset = count * kResultSize;
std::memcpy(bufferStart + offset, &v, kRESULT_SIZE); std::memcpy(bufferStart + offset, &v, kResultSize);
} }
if (bytesRemaining > 0) if (bytesRemaining > 0)
{ {
result_type const v = g(); result_type const v = g();
std::size_t const offset = completeIterations * kRESULT_SIZE; std::size_t const offset = completeIterations * kResultSize;
std::memcpy(bufferStart + offset, &v, bytesRemaining); std::memcpy(bufferStart + offset, &v, bytesRemaining);
} }
} }

View File

@@ -26,12 +26,14 @@ public:
result_type result_type
operator()(); operator()();
static result_type constexpr min() static constexpr result_type
min()
{ {
return std::numeric_limits<result_type>::min(); return std::numeric_limits<result_type>::min();
} }
static result_type constexpr max() static constexpr result_type
max()
{ {
return std::numeric_limits<result_type>::max(); return std::numeric_limits<result_type>::max();
} }

View File

@@ -27,7 +27,7 @@ public:
that were previously considered valid to no longer that were previously considered valid to no longer
be allowed. be allowed.
*/ */
static constexpr std::size_t kMAX_SERIALIZED_CONDITION = 128; static constexpr std::size_t kMaxSerializedCondition = 128;
/** Load a condition from its binary form /** Load a condition from its binary form

View File

@@ -16,7 +16,7 @@ public:
that were previously considered valid to no longer that were previously considered valid to no longer
be allowed. be allowed.
*/ */
static constexpr std::size_t kMAX_SERIALIZED_FULFILLMENT = 256; static constexpr std::size_t kMaxSerializedFulfillment = 256;
/** Load a fulfillment from its binary form /** Load a fulfillment from its binary form

View File

@@ -23,7 +23,7 @@ public:
While future versions of this code will never lower While future versions of this code will never lower
this limit, they may opt to raise it. this limit, they may opt to raise it.
*/ */
static constexpr std::size_t kMAX_PREIMAGE_LENGTH = 128; static constexpr std::size_t kMaxPreimageLength = 128;
/** Parse the payload for a PreimageSha256 condition /** Parse the payload for a PreimageSha256 condition
@@ -65,7 +65,7 @@ public:
return {}; return {};
} }
if (s.size() > kMAX_PREIMAGE_LENGTH) if (s.size() > kMaxPreimageLength)
{ {
ec = Error::PreimageTooLong; ec = Error::PreimageTooLong;
return {}; return {};

View File

@@ -6,7 +6,7 @@ namespace xrpl {
/// Coroutine stack size (1.5 MB). Increased from 1 MB because /// Coroutine stack size (1.5 MB). Increased from 1 MB because
/// ASAN-instrumented deep call stacks exceeded the original limit. /// ASAN-instrumented deep call stacks exceeded the original limit.
constexpr std::size_t kCORO_STACK_SIZE = 1536 * 1024; constexpr std::size_t kCoroStackSize = 1536 * 1024;
template <class F> template <class F>
JobQueue::Coro::Coro(CoroCreateT, JobQueue& jq, JobType type, std::string name, F&& f) JobQueue::Coro::Coro(CoroCreateT, JobQueue& jq, JobType type, std::string name, F&& f)
@@ -14,7 +14,7 @@ JobQueue::Coro::Coro(CoroCreateT, JobQueue& jq, JobType type, std::string name,
, type_(type) , type_(type)
, name_(std::move(name)) , name_(std::move(name))
, coro_( , coro_(
boost::context::protected_fixedsize_stack(kCORO_STACK_SIZE), boost::context::protected_fixedsize_stack(kCoroStackSize),
[this, fn = std::forward<F>(f)](boost::coroutines2::coroutine<void>::push_type& doYield) { [this, fn = std::forward<F>(f)](boost::coroutines2::coroutine<void>::push_type& doYield) {
yield_ = &doYield; yield_ = &doYield;
yield(); yield();
@@ -47,7 +47,7 @@ inline bool
JobQueue::Coro::post() JobQueue::Coro::post()
{ {
{ {
std::scoped_lock const lk(mutex_run_); std::scoped_lock const lk(mutexRun_);
running_ = true; running_ = true;
} }
@@ -58,7 +58,7 @@ JobQueue::Coro::post()
} }
// The coroutine will not run. Clean up running_. // The coroutine will not run. Clean up running_.
std::scoped_lock const lk(mutex_run_); std::scoped_lock const lk(mutexRun_);
running_ = false; running_ = false;
cv_.notify_all(); cv_.notify_all();
return false; return false;
@@ -68,7 +68,7 @@ inline void
JobQueue::Coro::resume() JobQueue::Coro::resume()
{ {
{ {
std::scoped_lock const lk(mutex_run_); std::scoped_lock const lk(mutexRun_);
running_ = true; running_ = true;
} }
{ {
@@ -92,7 +92,7 @@ JobQueue::Coro::resume()
} }
detail::getLocalValues().release(); detail::getLocalValues().release();
detail::getLocalValues().reset(saved); detail::getLocalValues().reset(saved);
std::scoped_lock const lk(mutex_run_); std::scoped_lock const lk(mutexRun_);
running_ = false; running_ = false;
cv_.notify_all(); cv_.notify_all();
} }
@@ -127,7 +127,7 @@ JobQueue::Coro::expectEarlyExit()
inline void inline void
JobQueue::Coro::join() JobQueue::Coro::join()
{ {
std::unique_lock<std::mutex> lk(mutex_run_); std::unique_lock<std::mutex> lk(mutexRun_);
cv_.wait(lk, [this]() { return !running_; }); cv_.wait(lk, [this]() { return !running_; });
} }

View File

@@ -127,7 +127,7 @@ private:
std::function<void()> job_; std::function<void()> job_;
std::shared_ptr<LoadEvent> loadEvent_; std::shared_ptr<LoadEvent> loadEvent_;
std::string name_; std::string name_;
clock_type::time_point queue_time_; clock_type::time_point queueTime_;
}; };
using JobCounter = ClosureCounter<void>; using JobCounter = ClosureCounter<void>;

View File

@@ -52,7 +52,7 @@ public:
std::string name_; std::string name_;
bool running_{false}; bool running_{false};
std::mutex mutex_; std::mutex mutex_;
std::mutex mutex_run_; std::mutex mutexRun_;
std::condition_variable cv_; std::condition_variable cv_;
boost::coroutines2::coroutine<void>::push_type* yield_{}; boost::coroutines2::coroutine<void>::push_type* yield_{};
boost::coroutines2::coroutine<void>::pull_type coro_; boost::coroutines2::coroutine<void>::pull_type coro_;
@@ -246,7 +246,7 @@ private:
// Statistics tracking // Statistics tracking
perf::PerfLog& perfLog_; perf::PerfLog& perfLog_;
beast::insight::Collector::ptr collector_; beast::insight::Collector::ptr collector_;
beast::insight::Gauge job_count_; beast::insight::Gauge jobCount_;
beast::insight::Hook hook_; beast::insight::Hook hook_;
std::condition_variable cv_; std::condition_variable cv_;

View File

@@ -101,8 +101,8 @@ public:
static JobTypes const& static JobTypes const&
instance() instance()
{ {
static JobTypes const kTYPES; static JobTypes const kTypes;
return kTYPES; return kTypes;
} }
static std::string const& static std::string const&

View File

@@ -161,7 +161,7 @@ public:
* While the JSON spec doesn't explicitly disallow this, you should avoid * While the JSON spec doesn't explicitly disallow this, you should avoid
* calling this method twice with the same tag for the same object. * calling this method twice with the same tag for the same object.
* *
* If CHECK_JSON_WRITER is defined, this function throws an exception if if * If CHECK_JSON_WRITER is defined, this function throws an exception if
* the tag you use has already been used in this object. * the tag you use has already been used in this object.
*/ */
template <typename Type> template <typename Type>

View File

@@ -67,7 +67,7 @@ public:
[[nodiscard]] std::string [[nodiscard]] std::string
getFormattedErrorMessages() const; getFormattedErrorMessages() const;
static constexpr unsigned kNEST_LIMIT{25}; static constexpr unsigned kNestLimit{25};
private: private:
enum class TokenType { enum class TokenType {

View File

@@ -102,8 +102,8 @@ operator!=(StaticString x, std::string const& y)
/** \brief Represents a <a HREF="http://www.json.org">JSON</a> value. /** \brief Represents a <a HREF="http://www.json.org">JSON</a> value.
* *
* This class is a discriminated union wrapper that can represent a: * This class is a discriminated union wrapper that can represent a:
* - signed integer [range: Value::kMIN_INT - Value::kMAX_INT] * - signed integer [range: Value::kMinInt - Value::kMaxInt]
* - unsigned integer (range: 0 - Value::kMAX_UINT) * - unsigned integer (range: 0 - Value::kMaxUInt)
* - double * - double
* - UTF-8 string * - UTF-8 string
* - boolean * - boolean
@@ -138,10 +138,10 @@ public:
using Int = json::Int; using Int = json::Int;
using ArrayIndex = UInt; using ArrayIndex = UInt;
static Value const kNULL; static Value const kNull;
static constexpr Int kMIN_INT = std::numeric_limits<Int>::min(); static constexpr Int kMinInt = std::numeric_limits<Int>::min();
static constexpr Int kMAX_INT = std::numeric_limits<Int>::max(); static constexpr Int kMaxInt = std::numeric_limits<Int>::max();
static constexpr UInt kMAX_UINT = std::numeric_limits<UInt>::max(); static constexpr UInt kMaxUInt = std::numeric_limits<UInt>::max();
private: private:
class CZString class CZString
@@ -472,7 +472,7 @@ operator>=(Value const& x, Value const& y)
class ValueAllocator class ValueAllocator
{ {
public: public:
static constexpr auto kUNKNOWN = (unsigned)-1; static constexpr auto kUnknown = (unsigned)-1;
virtual ~ValueAllocator() = default; virtual ~ValueAllocator() = default;
@@ -481,7 +481,7 @@ public:
virtual void virtual void
releaseMemberName(char* memberName) = 0; releaseMemberName(char* memberName) = 0;
virtual char* virtual char*
duplicateStringValue(char const* value, unsigned int length = kUNKNOWN) = 0; duplicateStringValue(char const* value, unsigned int length = kUnknown) = 0;
virtual void virtual void
releaseStringValue(char* value) = 0; releaseStringValue(char* value) = 0;
}; };

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