Compare commits

..

210 Commits

Author SHA1 Message Date
Ed Hennis
6ce2752cad clang-tidy: readability-math-missing-parentheses 2026-06-02 11:56:28 -04:00
Ed Hennis
8c1b12c5f2 clang-tidy fixes: braces and variable names 2026-06-01 17:19:23 -04:00
Ed Hennis
4ac4ed179a Merge remote-tracking branch 'XRPLF/develop' into ximinez/number-maxint-range
* XRPLF/develop:
  ci: Check binaries separately from building them (7355)
  ci: [DEPENDABOT] bump eps1lon/actions-label-merge-conflict from 3.0.3 to 3.1.0 (7375)
  refactor: Use `STLedgerEntry` type aliases instead of `std::shared_ptr` (7282)
  fix: Adjust xrpld systemd service and update timer (7374)
  release: Bump version to 3.2.0-rc3 (7371)
  fix: Pin overpayment principal reduction to exact on-grid value (7360)
2026-06-01 14:37:14 -04:00
Ed Hennis
1e2d25b273 Merge commit '47365f4220' into ximinez/number-maxint-range
* commit '47365f4220':
  fix: Improve upward rounding edge cases for Number::operator/= (7328)
2026-06-01 14:37:02 -04:00
Ed Hennis
647685695e Merge commit '1599c1a672' into ximinez/number-maxint-range
* commit '1599c1a672':
  refactor: Revert "perf: Remove unnecessary caches (5439)" (7359)
  fix: Add zero domainID check for permissionedDomain (7362)
2026-06-01 14:33:08 -04:00
Ed Hennis
6e1ee4720a Merge remote-tracking branch 'XRPLF/ximinez/number-division-accuracy' into ximinez/number-maxint-range
* XRPLF/ximinez/number-division-accuracy:
  CI feedback: Add test cases covering other rounding modes
  Apply suggestions from code review
  Accept AI suggestion
  Update the testUpwardRoundsDown test to run under all scales
  Review feedback from Tapanito and AI
  Skip clang-tidy false positive: misc-include-cleaner
  ci: Run PR title and description checks on staging and release branches (7331)
  style: Run shfmt on workflows, actions and markdown bash code (7333)
  Remove TMax entirely from normalizeToRange; check type matching directly
  Tweak how the denominator is handled in division
  Minor fixes: missing include, variable init, typo
  Test optimization: Number_test::pow10
  Significant rewrite
  Use the local range instead of calling a function
  Make Number::operator/= significantly more accurate
2026-06-01 13:16:25 -04: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
Ed Hennis
f6a26ca34f CI feedback: Add test cases covering other rounding modes
- Downward with a negative result, and ToNearest with a remainder
  slightly larger than 0.5.
2026-05-29 18:54:08 -04:00
Ed Hennis
c0569037f8 Apply suggestions from code review
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-05-29 16:34:51 -04:00
Ed Hennis
be9ae88d48 Accept AI suggestion
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-05-28 23:38:54 -04:00
Ed Hennis
cd21d74538 Update the testUpwardRoundsDown test to run under all scales
- Demonstrates the incorrect "before" behavior
2026-05-28 19:58:52 -04:00
Ed Hennis
2fdfd2b420 Review feedback from Tapanito and AI
- Add missing headers.
- Improve code coverage exclusions.
- Clean up several variable names.
- Improve explanatory comments.
- Remove the switch statement from MantissaRange::getMin. Change it to
  a straight power of ten lookup.
2026-05-28 18:41:19 -04:00
Ed Hennis
06a3f76ccd Skip clang-tidy false positive: misc-include-cleaner 2026-05-28 17:47:41 -04:00
Ed Hennis
dadf4d737d Merge branch 'develop' into ximinez/number-division-accuracy 2026-05-28 17:46:40 -04: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
Ed Hennis
7b66b42713 Merge branch 'develop' into ximinez/number-division-accuracy 2026-05-27 17:00:59 -04:00
Ed Hennis
f622707b36 Merge remote-tracking branch 'XRPLF/develop' into ximinez/number-maxint-range
* XRPLF/develop:
  release: Bump version to 3.2.0-rc2 (7348)
  refactor: Enable support for `fixCleanup3_2_0` amendment (7347)
  release: Bump version to 3.2.0-rc1 (7335)
  fix: Fix a rounding error at the `Number::maxRep` cusp (7051)
2026-05-27 16:44:50 -04:00
Ayaz Salikhov
f9551ac5ca style: Run shfmt on workflows, actions and markdown bash code (#7333) 2026-05-27 19:24:18 +00:00
Ed Hennis
18ac8a0583 Merge branch 'develop' into ximinez/number-division-accuracy 2026-05-27 15:18:17 -04: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
de2efa5cb9 Remove TMax entirely from normalizeToRange; check type matching directly 2026-05-27 13:06:52 -04:00
Ed Hennis
8dcd88e83c Tweak how the denominator is handled in division
- Removes one int64 to 128 conversion
2026-05-27 12:34:49 -04:00
Ed Hennis
5333422402 Merge remote-tracking branch 'XRPLF/develop' into ximinez/number-division-accuracy
* XRPLF/develop:
  fix: Fix a rounding error at the `Number::maxRep` cusp (7051)
2026-05-27 12:17:30 -04:00
Ed Hennis
4ec049e727 Minor fixes: missing include, variable init, typo 2026-05-27 12:09:13 -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
Ed Hennis
ae9c72bb7c Test optimization: Number_test::pow10 2026-05-27 00:36:38 -04:00
Ed Hennis
5abecb9fcb Significant rewrite
- Simplify Number::operator/= to use more constexpr values, and fewer
  variations.
  - Most significantly, rounding up doesn't need more precision, it only
    needs to know if there's a remainder after the current precision work
    is done. Tracked similarly Guard::xbit_.
- Build a constexpr lookup array for powers of 10. Only a handful of
  values are used, but since it's built at compile time, and constexpr,
  unused values do not affect memory or performance.
2026-05-27 00:07:48 -04:00
Ed Hennis
7c45a3b197 Merge remote-tracking branch 'XRPLF/ximinez/number-fix-maxrepcusp' into ximinez/number-maxint-range
* XRPLF/ximinez/number-fix-maxrepcusp: (32 commits)
  ci: Only push docker images in XRPLF/rippled (7330)
  clang-tidy: missing header
  ci: [DEPENDABOT] bump docker/setup-buildx-action from 4.0.0 to 4.1.0 (7322)
  ci: [DEPENDABOT] bump codecov/codecov-action from 6.0.0 to 6.0.1 (7321)
  ci: [DEPENDABOT] bump docker/build-push-action from 7.1.0 to 7.2.0 (7320)
  ci: [DEPENDABOT] bump docker/metadata-action from 6.0.0 to 6.1.0 (7319)
  ci: [DEPENDABOT] bump docker/login-action from 4.1.0 to 4.2.0 (7318)
  fix: Update `clang-tidy` to include `src/tests` directory header check (7307)
  clang-tidy: implicit bool conversion
  chore: Pin Python packages for codegen using uv (7329)
  style: Use shfmt instead of bashate (7326)
  fix: Fix edge-case where vault-depositor may get stuck (7139)
  Address some AI review feedback: predeclare, include, format, comment
  fix: Fix `VaultInvariant` and `VaultDeposit` precision bugs at IOU scale boundaries (7272)
  ci: Add clang to nix images (7308)
  fix: Include management-fee delta in doOverpayment assertion (7039)
  fix: Fix clang-tidy pre-commit hook to locate compile_commands.json from repo root (7325)
  fix: Use consistent scale for `debtTotal` (7093)
  fix: Skip deleted book directories and non-root modifications in `ValidBookDirectory` invariant (7312)
  fix: Address review feedback on FD/handle guarding (5823 follow-up) (7310)
  ...
2026-05-26 22:51:14 -04:00
Ed Hennis
12670b0c3f Merge branch 'ximinez/number-fix-maxrepcusp' into ximinez/number-division-accuracy 2026-05-26 19:21:05 -04:00
Ed Hennis
1e7876a03c Merge branch 'develop' into ximinez/number-fix-maxrepcusp 2026-05-26 19:21:01 -04:00
Ed Hennis
e851e80de0 Merge branch 'ximinez/number-fix-maxrepcusp' into ximinez/number-division-accuracy 2026-05-26 16:56:47 -04:00
Ed Hennis
a963035f76 Merge branch 'develop' into ximinez/number-fix-maxrepcusp 2026-05-26 16:56:43 -04:00
Ayaz Salikhov
1162371def ci: Only push docker images in XRPLF/rippled (#7330) 2026-05-26 20:03:04 +00:00
Ed Hennis
8ab904de57 Merge branch 'ximinez/number-fix-maxrepcusp' into ximinez/number-division-accuracy 2026-05-26 16:01:44 -04:00
Ed Hennis
100ec464d9 Merge branch 'develop' into ximinez/number-fix-maxrepcusp 2026-05-26 16:01:40 -04:00
Ed Hennis
e89e6f50e8 Merge remote-tracking branch 'XRPLF/ximinez/number-fix-maxrepcusp' into ximinez/number-division-accuracy
* XRPLF/ximinez/number-fix-maxrepcusp:
  clang-tidy: implicit bool conversion
  Address some AI review feedback: predeclare, include, format, comment
  fix: Fix `VaultInvariant` and `VaultDeposit` precision bugs at IOU scale boundaries (7272)
  ci: Add clang to nix images (7308)
  fix: Include management-fee delta in doOverpayment assertion (7039)
  fix: Fix clang-tidy pre-commit hook to locate compile_commands.json from repo root (7325)
  fix: Use consistent scale for `debtTotal` (7093)
  fix: Skip deleted book directories and non-root modifications in `ValidBookDirectory` invariant (7312)
  fix: Address review feedback on FD/handle guarding (5823 follow-up) (7310)
  fix: Fix non-canonical MPT amount (7117)
2026-05-26 15:53:36 -04:00
Ed Hennis
27456fa439 Use the local range instead of calling a function 2026-05-26 15:52:25 -04:00
Ed Hennis
d6844311c0 clang-tidy: missing header 2026-05-26 15:48:29 -04: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
Ed Hennis
fbee0349f5 clang-tidy: implicit bool conversion 2026-05-26 15:21:42 -04: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
Ed Hennis
84ca271d95 Address some AI review feedback: predeclare, include, format, comment
- Predeclare type reference in Rules.h
- Remove an unneeded include in EscrowToken_test
- Number_test will format negative BigInts correctly (unused)
- Remove an inaccurate comment
2026-05-26 13:51:06 -04:00
Ed Hennis
75dfc65f5f Merge branch 'develop' into ximinez/number-fix-maxrepcusp 2026-05-26 13:47:33 -04: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
Ed Hennis
48b1716e6f Make Number::operator/= significantly more accurate
- Prevents extreme dust rounding from getting lost, especially when
  rounding away from zero. (Upward for positive, downward for negative.)
2026-05-23 19:02:03 +01: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
Ed Hennis
4ab886bcbc Merge branch 'develop' into ximinez/number-fix-maxrepcusp 2026-05-22 17:56:15 -04: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
Ed Hennis
7f64c337d8 Merge branch 'develop' into ximinez/number-fix-maxrepcusp 2026-05-21 14:25:50 -04: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
Ed Hennis
61bdd6fb78 Merge branch 'develop' into ximinez/number-fix-maxrepcusp 2026-05-21 10:10:00 -04:00
Ed Hennis
19c60924a5 Merge remote-tracking branch 'XRPLF/ximinez/number-fix-maxrepcusp' into ximinez/number-maxint-range
* XRPLF/ximinez/number-fix-maxrepcusp:
  Fix more AMM tests, and to not exclude fixCleanup3_2_0
  docs: Add --parallel flag to cmake build commands in BUILD.md (7302)
  fix: Fix wrong hybrid offer orderbook placement and update `LedgerStateFix` to amend `ExchangeRate` meta (7087)
  Change the priority of the amendments for large mantissas
  Apply suggestions from @Tapanito code review
  Apply suggestions from Copilot code review
  Review feedback from @tapanito: lambda checks condition in doRoundUp
  style: More clang-tidy identifier renaming (7290)
  fix: Update pDEX invariant firing under a valid offer deletion (7118)
  fix: Fix multisign and signfor to check for delegate (7064)
  refactor: Fix `sfGeneric` and `sfInvalid` field names (7300)
  docs: Fix some comments to improve readability (7122)
  feat: Propagate underlying MPT flags to vault shares (7077)
2026-05-21 15:07:39 +01: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
Ed Hennis
8e06e78f11 Merge branch 'develop' into ximinez/number-fix-maxrepcusp 2026-05-21 07:11:49 -04:00
Ed Hennis
42fda85fbc Fix more AMM tests, and to not exclude fixCleanup3_2_0 2026-05-21 12:04:29 +01: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
Ed Hennis
3a4b92b050 Change the priority of the amendments for large mantissas
- Order the checks so that large mantissa is only enabled if SAV or LP
  are enabled. fixCleanup3_2_0 only enables the rounding fix.
- Fix tests, and don't exclude fixCleanup3_2_0 in AMM tests
- Also fix formatting
2026-05-21 00:53:07 +01:00
Ed Hennis
aea19df3c1 Apply suggestions from @Tapanito code review
Co-authored-by: Vito Tumas <5780819+Tapanito@users.noreply.github.com>
2026-05-20 18:46:17 -04:00
Ed Hennis
8b56749ca3 Apply suggestions from Copilot code review
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-05-20 18:39:46 -04:00
Ed Hennis
71cf996fc6 Review feedback from @tapanito: lambda checks condition in doRoundUp 2026-05-20 23:28:26 +01: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
Ed Hennis
7cacb3cce5 Merge remote-tracking branch 'XRPLF/ximinez/number-fix-maxrepcusp' into ximinez/number-maxint-range
* XRPLF/ximinez/number-fix-maxrepcusp:
  fix: Disable unnecessary sanity-check in VaultDeposit (7288)
  ci: [DEPENDABOT] bump actions/upload-artifact from 7.0.0 to 7.0.1 (7286)
  ci: Only run reusable package in public repos (7293)
  fix: Set default peering port to 2459 (6848)
  fix: Use account ledger entry when canceling token escrows (6171)
  refactor: Rename `account_` to `accountID_` (7284)
  ci: Add Linux package builds (DEB + RPM) to CI (6639)
  refactor: Clean up comments post-clang-tidy changes (7283)
  release: Set version to 3.3.0-b0 (7280)
  refactor: Rename static constants (7120)
  refactor: Use `isFlag` where possible instead of bitwise math (7278)
  ci: Update XRPLF/actions (7281)
  clang-tidy: this is ridiculous
  clang-tidy: {}
2026-05-20 12:19:15 +01:00
Ed Hennis
4c7ea64b6c Merge branch 'develop' into ximinez/number-fix-maxrepcusp 2026-05-19 16:53:33 -04:00
Ed Hennis
c8947c6f75 Merge branch 'develop' into ximinez/number-fix-maxrepcusp 2026-05-19 10:15:10 -04:00
Ed Hennis
09ae5b719f Merge branch 'develop' into ximinez/number-fix-maxrepcusp 2026-05-19 05:15:47 -04:00
Ed Hennis
09f2d06dd4 Merge branch 'develop' into ximinez/number-fix-maxrepcusp 2026-05-15 21:32:09 -04:00
Ed Hennis
6964013941 Merge remote-tracking branch 'XRPLF/develop' into ximinez/number-fix-maxrepcusp
* XRPLF/develop:
  release: Set version to 3.3.0-b0 (7280)
  refactor: Rename static constants (7120)
  refactor: Use `isFlag` where possible instead of bitwise math (7278)
  ci: Update XRPLF/actions (7281)
2026-05-15 21:14:34 -04:00
Ed Hennis
ad32568f7e clang-tidy: Capitalization and other small things 2026-05-14 21:14:53 -04:00
Ed Hennis
70c6e01d7e clang-tidy: this is ridiculous 2026-05-14 21:02:49 -04:00
Ed Hennis
ddfb7ee69c clang-tidy: {} 2026-05-14 20:48:34 -04:00
Ed Hennis
29eb9a6df4 Merge branch 'ximinez/number-fix-maxrepcusp' into ximinez/number-maxint-range 2026-05-14 20:38:59 -04:00
Ed Hennis
b69b9242e2 fixup! clang-tidy: Avoid nested "?:" in global Rules initialization 2026-05-14 20:33:15 -04:00
Ed Hennis
cd2fcf0a5e Merge branch 'develop' into ximinez/number-fix-maxrepcusp 2026-05-14 18:25:17 -04:00
Ed Hennis
69656d6b67 clang-tidy: Avoid nested "?:" in global Rules initialization 2026-05-14 18:24:05 -04:00
Ed Hennis
06b9e18333 Merge branch 'ximinez/number-fix-maxrepcusp' into ximinez/number-maxint-range 2026-05-14 10:49:08 -04:00
Ed Hennis
46b946b22e clang-tidy: missing include 2026-05-13 22:32:37 -04:00
Ed Hennis
ae03b30f29 Merge branch 'develop' into ximinez/number-fix-maxrepcusp 2026-05-13 20:16:19 -04:00
Ed Hennis
974f36fc72 Merge branch 'ximinez/number-fix-maxrepcusp' into ximinez/number-maxint-range 2026-05-13 12:04:28 -04:00
Ed Hennis
4c7c019add Merge branch 'develop' into ximinez/number-fix-maxrepcusp 2026-05-13 12:03:35 -04:00
Ed Hennis
47f30c913d Fix broken unit tests: EscrowToken
- Some EscrowToken tests used a hard-coded list of amendments to
  determine whether to expect large mantissa logic. That ignored the
  effects of fixCleanup3_2_0, especially as applied to the previous fix
  affecting preflight, preclaim, etc.
- Add a helper function, useRulesGuards, which will return the same
  decision as createGuards and setCurrentRulesImpl. Use that helper
  function in the relevant tests.
- Also remove an #include that clang-tidy was complaining about.
2026-05-12 21:26:54 -04:00
Ed Hennis
e50bb3d307 Merge branch 'ximinez/number-fix-maxrepcusp' into ximinez/number-maxint-range 2026-05-12 20:11:56 -04:00
Ed Hennis
d7d5b83f6d Merge branch 'develop' into ximinez/number-fix-maxrepcusp 2026-05-12 19:18:45 -04:00
Ed Hennis
abc5f59fed Tweak tests after another big merge 2026-05-12 19:16:50 -04:00
Ed Hennis
e22938d69f AI review feedback: createGuards
- Refactor the Guard decision in withTxnType into createGuards, which
  lives in Rules.cpp. It is physically located near
  setCurrentTransactionRules, and documented to explain that changes
  need to be synchronized.
2026-05-12 18:44:05 -04:00
Ed Hennis
dae0943dc3 Fix a couple of bugs introduced by the previous merge 2026-05-12 16:57:01 -04:00
Ed Hennis
7c9a56ff24 Merge branch 'develop' into ximinez/number-fix-maxrepcusp 2026-05-12 16:26:09 -04:00
Ed Hennis
5a40416673 Merge branch 'develop' into ximinez/number-fix-maxrepcusp 2026-05-12 15:59:19 -04:00
Ed Hennis
f483118498 Merge remote-tracking branch 'mywork/ximinez/number-fix-maxrepcusp' into ximinez/number-maxint-range
* mywork/ximinez/number-fix-maxrepcusp:
  Address more nitpicky AI comments
  What is it going to take to get clang-tidy to shut up?
  More clang-tidy changes: AMMExtended_test member and Number_test includes
  Fix clang-tidy issues, and more AI complaints
  Fix AI-identified mistakes
  fix: Fix a rounding error at the Number::maxRep cusp
2026-05-12 01:24:36 -04:00
Ed Hennis
30334cd1f4 Merge branch 'develop' into ximinez/number-fix-maxrepcusp 2026-05-11 13:34:11 -04:00
Ed Hennis
257da7972f Merge branch 'develop' into ximinez/number-maxint-range 2026-05-07 18:10:49 -04:00
Ed Hennis
5558e1b522 Merge branch 'develop' into ximinez/number-fix-maxrepcusp 2026-05-07 18:10:03 -04:00
Ed Hennis
cd0f49a003 Address more nitpicky AI comments 2026-05-07 17:05:10 -04:00
Ed Hennis
22d2703ce8 What is it going to take to get clang-tidy to shut up? 2026-05-07 16:50:43 -04:00
Ed Hennis
501b027a76 Merge branch 'develop' into ximinez/number-maxint-range 2026-05-07 14:19:57 -04:00
Ed Hennis
d03274b731 Merge branch 'develop' into ximinez/number-fix-maxrepcusp 2026-05-07 14:18:28 -04:00
Ed Hennis
1b6047afe1 More clang-tidy changes: AMMExtended_test member and Number_test includes 2026-05-07 13:51:48 -04:00
Ed Hennis
668fa65384 Merge branch 'develop' into ximinez/number-maxint-range 2026-05-07 13:29:17 -04:00
Ed Hennis
175a04160d Merge branch 'develop' into ximinez/number-fix-maxrepcusp 2026-05-07 13:28:33 -04:00
Ed Hennis
b050c151f8 Fix clang-tidy issues, and more AI complaints 2026-05-06 23:26:11 -04:00
Ed Hennis
a2b21d75ce Fix AI-identified mistakes 2026-05-06 22:56:07 -04:00
Ed Hennis
b40d2a8e7d fix: Fix a rounding error at the Number::maxRep cusp
- Add helper function, doDropDigit, to wrap the common pattern:
    push(mantissa % 10);
    mantissa /= 10;
    ++exponent;
- Might have been helpful to catch this issue when developing.
2026-05-06 22:49:44 -04:00
Ed Hennis
54db82dc42 Merge branch 'develop' into ximinez/number-maxint-range 2026-05-06 22:35:06 -04:00
Ed Hennis
1b67c2260c Merge branch 'develop' into ximinez/number-maxint-range 2026-05-06 14:18:47 -04:00
Ed Hennis
257e568cb6 Merge remote-tracking branch 'XRPLF/develop' into ximinez/number-maxint-range
* XRPLF/develop:
  fix: Fix regressions in `server_definitions` (7008)
  chore: Do not duplicate sanitizer flags (7058)
  ci: Run pre-commit on diff in clang-tidy workflow (7078)
  ci: Use XRPLF/create-issue (7076)
  ci: Rewrite clang-tidy workflow(s) in a reusable manner (7062)
  chore: Ignore identifier-naming update in git blame (7066)
  refactor: Enable clang-tidy `readability-identifier-naming` check (6571)
2026-05-05 21:08:35 -04:00
Ed Hennis
fd2040a56d Merge remote-tracking branch 'XRPLF/develop' into ximinez/number-maxint-range
* XRPLF/develop:
  refactor: Revert certain `Throw`s by `LogicError`s (7036)
  ci: Rename print-env -> print-build-env (7061)
  fix: Gate -mcmodel flags to x86_64 in sanitizer builds (7049)
  fix: Prevents overwriting a bool value in an invariant (6609)
  fix: Address code review comments regarding `boost::coroutine2` (6977)
  refactor: Apply various minor improvements and corrections (7045)
  fix: Store `Delegate` object in delegating and authorized account directories for proper deletion (6681)
  ci: Use print-env from XRPLF/actions (7052)
  fix: Make assorted RPC fixes (6529)
  chore: Enable clang-tidy v21 new checks (7031)
2026-05-01 14:32:51 -04:00
Ed Hennis
c06504353c Number perf test
- Run the Number test suite 1000 times to allow for performance measurement
2026-05-01 14:02:39 -04:00
Ed Hennis
51ab048b97 fixup! Fix clang-tidy 2026-04-29 12:10:11 -04:00
Ed Hennis
fc569b9410 Merge branch 'develop' into ximinez/number-maxint-range 2026-04-29 11:05:57 -04:00
Ed Hennis
c2f25c2a34 Merge remote-tracking branch 'XRPLF/develop' into ximinez/number-maxint-range
* XRPLF/develop:
  chore: Enable clang-tidy modernize-use-nodiscard check (7015)
  fix: Resolve MSVC Debug build failure in JobQueue.h; re-enable _CRTDBG_MAP_ALLOC in CI (6993)
  docs: Update hybrid offer invariant comment (7007)
2026-04-26 22:29:50 -05:00
Ed Hennis
ee33d98f50 Merge branch 'develop' into ximinez/number-maxint-range 2026-04-24 12:54:01 -04:00
Ed Hennis
1226255662 Merge branch 'develop' into ximinez/number-maxint-range 2026-04-23 15:56:51 -04:00
Ed Hennis
d914b633da Merge branch 'develop' into ximinez/number-maxint-range 2026-04-22 23:53:36 -04:00
Ed Hennis
e3b390f949 Merge branch 'develop' into ximinez/number-maxint-range 2026-04-22 14:49:47 -04:00
Ed Hennis
5a7be26402 Merge branch 'develop' into ximinez/number-maxint-range 2026-04-22 13:11:20 -04:00
Ed Hennis
25e0b4eeb5 Merge branch 'develop' into ximinez/number-maxint-range 2026-04-21 19:35:21 -04:00
Ed Hennis
c4ef1e6997 Merge remote-tracking branch 'XRPLF/develop' into ximinez/number-maxint-range
* XRPLF/develop:
  fix: Disallow MPTClearRequireAuth if is set (6712)
  feat: Add GRPC TLS support (6374)
  fix: Check for empty `sfAdditionalBooks` array in hybrid offer invariant (6716)
  chore: Remove repetitive word in multiple files (6978)
  ci: Add workflow to check PR description has been filled (6965)
  ci: [DEPENDABOT] Bump tj-actions/changed-files from 47.0.5 to 47.0.6 (6973)
  chore: Enable clang-tidy include cleaner (6947)
  fix: Change AMMClawback return code to tecNO_PERMISSION (6946)
  ci: [DEPENDABOT] bump actions/upload-pages-artifact from 4.0.0 to 5.0.0 (6927)
  ci: [DEPENDABOT] bump actions/upload-artifact from 7.0.0 to 7.0.1 (6928)
  chore: Enable clang-tidy readability checks (6930)
2026-04-20 18:59:21 -04:00
Ed Hennis
ac20f3221f Merge branch 'develop' into ximinez/number-maxint-range 2026-04-16 13:45:08 -04:00
Ed Hennis
1e764cd172 Merge branch 'develop' into ximinez/number-maxint-range 2026-04-15 19:09:51 -04:00
Ed Hennis
371d3a6f30 Merge branch 'develop' into ximinez/number-maxint-range 2026-04-15 14:29:29 -04:00
Ed Hennis
018e36f1ca Merge branch 'develop' into ximinez/number-maxint-range 2026-04-13 20:45:31 -04:00
Ed Hennis
ee9b486f8b Fix clang-tidy 2026-04-13 20:17:55 -04:00
Ed Hennis
47f6422ee7 Merge branch 'develop' into ximinez/number-maxint-range 2026-04-10 12:12:38 -04:00
Ed Hennis
8201d0330e Merge branch 'develop' into ximinez/number-maxint-range 2026-04-10 09:11:23 -04:00
Ed Hennis
9ac062c5a0 Merge branch 'develop' into ximinez/number-maxint-range 2026-04-09 11:41:18 -04:00
Ed Hennis
f631d95585 Merge branch 'develop' into ximinez/number-maxint-range 2026-04-08 16:57:46 -04:00
Ed Hennis
efa3328aba Merge branch 'develop' into ximinez/number-maxint-range 2026-04-08 15:13:36 -04:00
Ed Hennis
9daa985bf1 Merge branch 'develop' into ximinez/number-maxint-range 2026-04-07 16:48:22 -04:00
Ed Hennis
d3b1ee9ec0 Merge branch 'develop' into ximinez/number-maxint-range 2026-04-06 19:07:42 -04:00
Ed Hennis
e160b95aef Merge branch 'develop' into ximinez/number-maxint-range 2026-04-06 18:34:11 -04:00
Ed Hennis
14843e15d8 Merge branch 'develop' into ximinez/number-maxint-range 2026-04-06 16:54:12 -04:00
Ed Hennis
f8359d9b0c Merge branch 'develop' into ximinez/number-maxint-range 2026-04-01 17:26:22 -04:00
Ed Hennis
8ed8b52dfe Merge remote-tracking branch 'XRPLF/develop' into ximinez/number-maxint-range
* XRPLF/develop:
  fix: Remove fatal assertion on Linux thread name truncation  (6690)
  chore: Enable clang-tidy `coreguidelines` checks (6698)
  ci: Allow uploading artifacts for XRPLF org (6702)
  fix: Enforce aggregate MaximumAmount in multi-send MPT (6644)
  chore: Use nudb recipe from the upstream (6701)
  fix: Fix previous ledger size typo in RCLConsensus (6696)
  chore: Enable clang-tidy misc checks (6655)
  ci: Use pull_request_target to check for signed commits (6697)
  chore: Remove unnecessary clang-format off/on directives (6682)
  fix: Fix Workers::stop() race between m_allPaused and m_runningTaskCount (6574)
2026-04-01 14:07:25 -04:00
Ed Hennis
62d0b07ee8 Merge remote-tracking branch 'XRPLF/develop' into ximinez/number-maxint-range
* XRPLF/develop: (81 commits)
  ci: Only publish docs in public repos (6687)
  chore: Enable remaining clang-tidy `performance` checks (6648)
  refactor: Address PR comments after the modularisation PRs (6389)
  chore: Fix clang-tidy header filter (6686)
  ci: [DEPENDABOT] bump actions/deploy-pages from 4.0.5 to 5.0.0 (6684)
  ci: [DEPENDABOT] bump codecov/codecov-action from 5.5.3 to 6.0.0 (6685)
  fix: Guard Coro::resume() against completed coroutines (6608)
  refactor: Split LoanInvariant into LoanBrokerInvariant and LoanInvariant (6674)
  ci: Don't publish docs on release branches (6673)
  refactor: Make function naming in ServiceRegistry consistent (6390)
  chore: Shorten job names to stay within Linux 15-char thread limit (6669)
  fix: Improve loan invariant message (6668)
  ci: Upload artifacts only in public repositories (6670)
  ci: Add conflicting-pr workflow (6656)
  chore: Add more AI tools to .gitignore (6658)
  chore: Show warning message if user may need to connect to VPN (6619)
  feat: Add placeholder amendment for assorted bug fixes (6652)
  chore: Update sqlite3->3.51.0, protobuf->6.33.5, openssl->3.6.1, grpc->1.78.1 (6653)
  refactor: Modularise ledger (6536)
  chore: Use unpatched version of soci (6649)
  ...
2026-03-30 22:01:54 -04:00
Ed Hennis
44ea0b24c8 Merge branch 'develop' into ximinez/number-maxint-range 2026-03-12 15:04:55 -04:00
Ed Hennis
e443a76d83 Merge branch 'develop' into ximinez/number-maxint-range 2026-03-10 13:38:28 -04:00
Ed Hennis
eef1f791e8 Merge branch 'develop' into ximinez/number-maxint-range 2026-03-06 13:04:09 -04:00
Ed Hennis
2191ef8d75 Merge branch 'develop' into ximinez/number-maxint-range 2026-03-04 17:11:35 -04:00
Ed Hennis
ea4f922492 Merge branch 'develop' into ximinez/number-maxint-range 2026-03-03 18:38:31 -04:00
Ed Hennis
9250ba9e27 Merge branch 'develop' into ximinez/number-maxint-range 2026-03-03 15:54:39 -04:00
Ed Hennis
61f38ba068 Review feedback from @copilot 2026-02-25 20:37:22 -05:00
Ed Hennis
3d5ff2c8a2 Apply suggestions from code review
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-25 21:10:11 -04:00
Ed Hennis
e27249134a Merge branch 'develop' into ximinez/number-maxint-range 2026-02-24 17:34:41 -04:00
Ed Hennis
d79fdec886 Merge branch 'develop' into ximinez/number-maxint-range 2026-02-24 16:46:05 -04:00
Ed Hennis
024d05b70c Merge branch 'develop' into ximinez/number-maxint-range 2026-02-20 18:49:46 -04:00
Ed Hennis
ffb3e1da53 Merge branch 'develop' into ximinez/number-maxint-range 2026-02-20 18:26:05 -04:00
Ed Hennis
aef7e5b335 Merge branch 'develop' into ximinez/number-maxint-range 2026-02-20 17:31:47 -04:00
Ed Hennis
e2c09e79d0 Merge branch 'develop' into ximinez/number-maxint-range 2026-02-20 17:21:09 -04:00
Ed Hennis
c6f854bbd8 Merge branch 'develop' into ximinez/number-maxint-range 2026-02-20 15:14:29 -04:00
Ed Hennis
6a1e0b0f5a Merge remote-tracking branch 'upstream/develop' into ximinez/number-maxint-range
* upstream/develop:
  ci: Add dependabot config (6379)
  Fix tautological assertion (6393)
2026-02-20 13:38:46 -05:00
Ed Hennis
01f5ae0927 Merge commit '2c1fad1023' into ximinez/number-maxint-range
* commit '2c1fad1023':
  chore: Apply clang-format width 100 (6387)
2026-02-20 13:38:00 -05:00
Ed Hennis
9b4587f9af Update formatting 2026-02-20 13:29:51 -05:00
Ed Hennis
fbc6f87983 Merge commit '25cca465538a56cce501477f9e5e2c1c7ea2d84c' into ximinez/number-maxint-range
* commit '25cca465538a56cce501477f9e5e2c1c7ea2d84c':
  chore: Set clang-format width to 100 in config file (6387)
2026-02-20 13:29:06 -05:00
Ed Hennis
0871eb0cb6 Address review feedback from @Copilot
- Clarify comments and add missing header
2026-02-19 19:06:03 -05:00
Ed Hennis
2ccf132f79 Apply suggestions from code review
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-19 19:02:03 -05:00
Ed Hennis
6600153958 Merge branch 'develop' into ximinez/number-maxint-range 2026-02-19 16:21:18 -05:00
Ed Hennis
fff73dac51 Merge branch 'develop' into ximinez/number-maxint-range 2026-02-18 20:18:56 -04:00
Ed Hennis
06ff77458a fixup! fixup! fixup! fixup! Address review feedback from @copilot 2026-02-05 20:33:30 -05:00
Ed Hennis
f19ecb3b80 fixup! fixup! fixup! Address review feedback from @copilot 2026-02-05 19:56:18 -05:00
Ed Hennis
cc2406bf3f fixup! fixup! Address review feedback from @copilot 2026-02-05 19:13:14 -05:00
Ed Hennis
30c65320e4 fixup! Address review feedback from @copilot 2026-02-05 18:25:23 -05:00
Ed Hennis
569d9ea94e Address review feedback from @copilot
- Update explanations.
- Use saver conversions between signed and unsigned.
2026-02-05 14:06:09 -05:00
Ed Hennis
02b7bcfa2b Merge branch 'develop' into ximinez/number-maxint-range 2026-02-05 13:29:56 -04:00
Ed Hennis
07c0c320a7 Fix formatting 2026-02-05 12:28:43 -05:00
Ed Hennis
d57e37c34b Fix renaming 2026-02-05 12:28:43 -05:00
Ed Hennis
154bb65c35 Merge remote-tracking branch 'upstream/develop' into ximinez/number-maxint-range
* upstream/develop:
  chore: Update secp256k1 and openssl (6327)
  chore: Remove unnecessary script (6326)
  refactor: Replace include guards by '#pragma once' (6322)
  chore: Remove unity builds (6300)
  refactor: Add ServiceRegistry to help modularization (6222)
  fix: Deletes expired NFToken offers from ledger (5707)
  chore: Add .zed editor config directory to .gitignore (6317)
  docs: Update API changelog, add APIv2+APIv3 version documentation (6308)
  fix: Restore config changes that broke standalone mode (6301)
  chore: Add upper-case match for ARM64 in CompilationEnv (6315)
  ci: Update hashes of XRPLF/actions (6316)
  chore: Format all cmake files without comments (6294)
  chore: Add cmake-format pre-commit hook (6279)
  chore: Remove unnecessary `boost::system` requirement from conanfile (6290)
2026-02-04 21:10:15 -05:00
Ed Hennis
111eda22e9 Merge commit '5f638f55536def0d88b970d1018a465a238e55f4' into ximinez/number-maxint-range
* commit '5f638f55536def0d88b970d1018a465a238e55f4':
  chore: Set ColumnLimit to 120 in clang-format (6288)
2026-02-04 21:09:02 -05:00
Ed Hennis
f7b6834d2a Add unit tests for normalizeToRange
- Steal changes from @pratik's #6150 to avoid UB
2026-02-04 21:08:48 -05:00
Ed Hennis
e464adaee6 Clean-ups and tweaks 2026-02-04 21:08:48 -05:00
Ed Hennis
cca92dedca Reduce expensive(?) accesses to thread_local MantissaRange 2026-02-04 21:08:48 -05:00
Ed Hennis
3d6f57a4df Fix bugs
- Simplify shiftExponent().
- Clean up to_string() to prevent integers from including "e0".
- Fix root() and root2() computations by ensuring the mantissas have
  a consistent length.
2026-02-04 21:08:46 -05:00
Ed Hennis
fc29fbe946 Convert "bool negative_ & uint64_t mantissa_" combo back to "rep mantissa_" 2026-02-04 21:08:34 -05:00
Ed Hennis
5e0a8d5c8a Remove the _ suffixes from doNormalize function parameters 2026-02-04 21:08:33 -05:00
Ed Hennis
d27788f12a Use 2^63-1 as maxMantissa for large range
- That makes minMantissa 2^63/10+1.
- Simplifies many of the existing operations, and removes the need for
  the accessors (mantissa() & exponent()) to do any math.
2026-02-04 21:08:33 -05:00
558 changed files with 15429 additions and 6713 deletions

View File

@@ -191,11 +191,14 @@ CheckOptions:
readability-identifier-naming.ParameterCase: camelBack
readability-identifier-naming.FunctionCase: camelBack
readability-identifier-naming.MemberCase: camelBack
readability-identifier-naming.PrivateMemberCase: camelBack
readability-identifier-naming.PrivateMemberSuffix: _
readability-identifier-naming.ProtectedMemberCase: camelBack
readability-identifier-naming.ProtectedMemberSuffix: _
readability-identifier-naming.PublicMemberCase: camelBack
readability-identifier-naming.PublicMemberSuffix: ""
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)$'
WarningsAsErrors: "*"

View File

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

View File

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

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`.
SED_COMMAND=sed
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'."
exit 1
fi

View File

@@ -8,12 +8,12 @@ set -e
SED_COMMAND=sed
HEAD_COMMAND=head
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'."
exit 1
fi
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'."
exit 1
fi
@@ -74,10 +74,10 @@ if grep -q '"xrpld"' cmake/XrplCore.cmake; then
# The script has been rerun, so just restore the name of the binary.
${SED_COMMAND} -i 's/"xrpld"/"rippled"/' cmake/XrplCore.cmake
elif ! grep -q '"rippled"' cmake/XrplCore.cmake; then
${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 ' set_target_properties(xrpld PROPERTIES OUTPUT_NAME "rippled")' >> cmake.tmp
tail -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 ' set_target_properties(xrpld PROPERTIES OUTPUT_NAME "rippled")' >>cmake.tmp
tail -1 cmake/XrplCore.cmake >>cmake.tmp
mv cmake.tmp cmake/XrplCore.cmake
fi

View File

@@ -6,7 +6,7 @@ set -e
# On MacOS, ensure that GNU sed is installed and available as `gsed`.
SED_COMMAND=sed
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'."
exit 1
fi

View File

@@ -6,7 +6,7 @@ set -e
# On MacOS, ensure that GNU sed is installed and available as `gsed`.
SED_COMMAND=sed
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'."
exit 1
fi
@@ -62,37 +62,37 @@ done
# restoring the verbiage that is already present in LICENSE.md. Ensure that if
# the script is run multiple times, duplicate notices are not added.
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
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
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
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
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
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
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
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
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
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
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
# 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`.
SED_COMMAND=sed
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'."
exit 1
fi

View File

@@ -6,7 +6,7 @@ set -e
# On MacOS, ensure that GNU sed is installed and available as `gsed`.
SED_COMMAND=sed
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'."
exit 1
fi

View File

@@ -6,7 +6,7 @@ set -e
# On MacOS, ensure that GNU sed is installed and available as `gsed`.
SED_COMMAND=sed
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'."
exit 1
fi

View File

@@ -6,14 +6,16 @@ on:
- develop
paths:
- ".github/workflows/build-nix-image.yml"
- "docker/nix.Dockerfile"
- ".github/workflows/reusable-build-docker-image.yml"
- "docker/**"
- "flake.nix"
- "flake.lock"
- "nix/**"
pull_request:
paths:
- ".github/workflows/build-nix-image.yml"
- "docker/nix.Dockerfile"
- ".github/workflows/reusable-build-docker-image.yml"
- "docker/**"
- "flake.nix"
- "flake.lock"
- "nix/**"
@@ -27,75 +29,81 @@ 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 }})
name: Build ${{ matrix.distro.name }} (${{ matrix.target.platform }})
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: rhel
base_image: registry.access.redhat.com/ubi9/ubi:latest
- name: debian
base_image: debian:bookworm
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: ghcr.io/xrplf/xrpld/nix-${{ matrix.distro.name }}
dockerfile: docker/nix.Dockerfile
base_image: ${{ matrix.distro.base_image }}
platform: ${{ matrix.target.platform }}
runner: ${{ matrix.target.runner }}
push: ${{ github.repository == 'XRPLF/rippled' && github.event_name == 'push' }}
merge:
name: Merge ${{ matrix.distro }} manifest
needs: build
if: ${{ github.repository == 'XRPLF/rippled' && github.event_name == 'push' }}
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
strategy:
fail-fast: false
matrix:
include:
- distro: nixos
- distro: ubuntu
- distro: rhel
- distro: debian
distro: [nixos, ubuntu, rhel, debian]
env:
IMAGE_NAME: ghcr.io/xrplf/xrpld/nix-${{ matrix.distro }}
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
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0
- name: Docker metadata
id: meta
uses: docker/metadata-action@80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9 # v6.1.0
with:
images: ${{ env.IMAGE_NAME }}
tags: |
type=sha,prefix=sha-,format=short
type=raw,value=latest
- name: Login to GitHub Container Registry
if: github.event_name == 'push'
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
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@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: Create multi-arch manifests
run: |
for tag in $(jq -cr '.tags[]' <<<"$DOCKER_METADATA_OUTPUT_JSON"); do
docker buildx imagetools create -t "$tag" "${tag}-amd64" "${tag}-arm64"
done
- 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 }}
- name: Inspect image
run: |
docker buildx imagetools inspect "${IMAGE_NAME}:${{ steps.meta.outputs.version }}"

View File

@@ -5,8 +5,17 @@ on:
types:
- checks_requested
pull_request:
types: [opened, edited, reopened, synchronize, ready_for_review]
branches: [develop]
types:
- opened
- edited
- reopened
- synchronize
- ready_for_review
branches:
- develop
- "release-*"
- "release/*"
- "staging/*"
jobs:
check_description:
@@ -20,11 +29,11 @@ jobs:
env:
PR_BODY: ${{ github.event.pull_request.body }}
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
if: ${{ github.event_name == 'pull_request' }}
run: >
python .github/scripts/check-pr-description.py
--template-file .github/pull_request_template.md
--pr-body-file pr_body.md
run: |
python .github/scripts/check-pr-description.py \
--template-file .github/pull_request_template.md \
--pr-body-file pr_body.md

View File

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

View File

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

View File

@@ -98,7 +98,7 @@ jobs:
READY: ${{ contains(github.event.pull_request.labels.*.name, 'Ready to merge') }}
MERGE: ${{ github.event_name == 'merge_group' }}
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}"
outputs:
go: ${{ steps.go.outputs.go == 'true' }}
@@ -168,9 +168,9 @@ jobs:
PR_URL: ${{ github.event.pull_request.html_url }}
run: |
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" \
-F "client_payload[ref]=${{ needs.upload-recipe.outputs.recipe_ref }}" \
-F "client_payload[pr_url]=${PR_URL}"
/repos/xrplf/clio/dispatches -f "event_type=check_libxrpl" \
-F "client_payload[ref]=${{ needs.upload-recipe.outputs.recipe_ref }}" \
-F "client_payload[pr_url]=${PR_URL}"
passed:
if: failure() || cancelled()

View File

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

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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- 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

@@ -113,7 +113,7 @@ jobs:
- name: Set ccache log file
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
uses: XRPLF/actions/print-build-env@59dec886e4afb05a1724443af08baccbc045b574
@@ -146,11 +146,11 @@ jobs:
CMAKE_ARGS: ${{ inputs.cmake_args }}
run: |
cmake \
-G '${{ runner.os == 'Windows' && 'Visual Studio 17 2022' || 'Ninja' }}' \
-DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake \
-DCMAKE_BUILD_TYPE="${BUILD_TYPE}" \
${CMAKE_ARGS} \
..
-G '${{ runner.os == 'Windows' && 'Visual Studio 17 2022' || 'Ninja' }}' \
-DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake \
-DCMAKE_BUILD_TYPE="${BUILD_TYPE}" \
${CMAKE_ARGS} \
..
- name: Check protocol autogen files are up-to-date
working-directory: ${{ env.BUILD_DIR }}
@@ -172,32 +172,32 @@ jobs:
cmake --build . --target code_gen
DIFF=$(git -C .. status --porcelain -- include/xrpl/protocol_autogen src/tests/libxrpl/protocol_autogen)
if [ -n "${DIFF}" ]; then
echo "::error::Generated protocol files are out of date"
git -C .. diff -- include/xrpl/protocol_autogen src/tests/libxrpl/protocol_autogen
echo "${MESSAGE}"
exit 1
echo "::error::Generated protocol files are out of date"
git -C .. diff -- include/xrpl/protocol_autogen src/tests/libxrpl/protocol_autogen
echo "${MESSAGE}"
exit 1
fi
- name: Build the binary
working-directory: ${{ env.BUILD_DIR }}
env:
BUILD_NPROC: ${{ runner.os == 'Linux' && '16' || steps.nproc.outputs.nproc }}
BUILD_NPROC: ${{ steps.nproc.outputs.nproc }}
BUILD_TYPE: ${{ inputs.build_type }}
CMAKE_TARGET: ${{ inputs.cmake_target }}
run: |
cmake \
--build . \
--config "${BUILD_TYPE}" \
--parallel "${BUILD_NPROC}" \
--target "${CMAKE_TARGET}"
--build . \
--config "${BUILD_TYPE}" \
--parallel "${BUILD_NPROC}" \
--target "${CMAKE_TARGET}"
- name: Show ccache statistics
if: ${{ inputs.ccache_enabled }}
run: |
ccache --show-stats -vv
if [ '${{ runner.debug }}' = '1' ]; then
cat "${CCACHE_LOGFILE}"
curl ${CCACHE_REMOTE_STORAGE%|*}/status || true
cat "${CCACHE_LOGFILE}"
curl ${CCACHE_REMOTE_STORAGE%|*}/status || true
fi
- name: Upload the binary (Linux)
@@ -214,7 +214,7 @@ jobs:
working-directory: ${{ env.BUILD_DIR }}
run: |
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
if: ${{ github.event.repository.visibility == 'public' && inputs.config_name == 'debian-bookworm-gcc-13-amd64-release' }}
@@ -231,10 +231,10 @@ jobs:
run: |
ldd ./xrpld
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
echo 'The binary is dynamically linked.'
exit 1
echo 'The binary is dynamically linked.'
exit 1
fi
- name: Verify presence of instrumentation (Linux)
@@ -250,12 +250,12 @@ jobs:
run: |
ASAN_OPTS="include=${GITHUB_WORKSPACE}/sanitizers/suppressions/runtime-asan-options.txt:suppressions=${GITHUB_WORKSPACE}/sanitizers/suppressions/asan.supp"
if [[ "${CONFIG_NAME}" == *gcc* ]]; then
ASAN_OPTS="${ASAN_OPTS}:alloc_dealloc_mismatch=0"
ASAN_OPTS="${ASAN_OPTS}:alloc_dealloc_mismatch=0"
fi
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 "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 "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 "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}
- name: Run the separate tests
if: ${{ !inputs.build_only }}
@@ -266,9 +266,9 @@ jobs:
PARALLELISM: ${{ runner.os == 'Windows' && '1' || steps.nproc.outputs.nproc }}
run: |
ctest \
--output-on-failure \
-C "${BUILD_TYPE}" \
-j "${PARALLELISM}"
--output-on-failure \
-C "${BUILD_TYPE}" \
-j "${PARALLELISM}"
- name: Run the embedded tests
if: ${{ !inputs.build_only }}
@@ -278,7 +278,7 @@ jobs:
run: |
set -o pipefail
# 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
- name: Show test failure summary
@@ -287,19 +287,19 @@ jobs:
WORKING_DIR: ${{ runner.os == 'Windows' && format('{0}\{1}', env.BUILD_DIR, inputs.build_type) || env.BUILD_DIR }}
run: |
if [ ! -d "${WORKING_DIR}" ]; then
echo "Working directory '${WORKING_DIR}' does not exist."
exit 0
echo "Working directory '${WORKING_DIR}' does not exist."
exit 0
fi
cd "${WORKING_DIR}"
if [ ! -f unittest.log ]; then
echo "unittest.log not found; embedded tests may not have run."
exit 0
echo "unittest.log not found; embedded tests may not have run."
exit 0
fi
if ! grep -E "failed" unittest.log; then
echo "Log present but no failure lines found in unittest.log."
echo "Log present but no failure lines found in unittest.log."
fi
- name: Debug failure (Linux)
if: ${{ failure() && runner.os == 'Linux' && !inputs.build_only }}
@@ -317,14 +317,14 @@ jobs:
BUILD_TYPE: ${{ inputs.build_type }}
run: |
cmake \
--build . \
--config "${BUILD_TYPE}" \
--parallel "${BUILD_NPROC}" \
--target coverage
--build . \
--config "${BUILD_TYPE}" \
--parallel "${BUILD_NPROC}" \
--target coverage
- name: Upload coverage report
if: ${{ github.repository == 'XRPLF/rippled' && !inputs.build_only && env.COVERAGE_ENABLED == 'true' }}
uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0
uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6.0.1
with:
disable_search: true
disable_telem: true

View File

@@ -38,9 +38,9 @@ jobs:
run: |
DIFF=$(git status --porcelain)
if [ -n "${DIFF}" ]; then
# Print the differences to give the contributor a hint about what to
# expect when running levelization on their own machine.
git diff
echo "${MESSAGE}"
exit 1
# Print the differences to give the contributor a hint about what to
# expect when running levelization on their own machine.
git diff
echo "${MESSAGE}"
exit 1
fi

View File

@@ -48,9 +48,9 @@ jobs:
run: |
DIFF=$(git status --porcelain)
if [ -n "${DIFF}" ]; then
# Print the differences to give the contributor a hint about what to
# expect when running the renaming scripts on their own machine.
git diff
echo "${MESSAGE}"
exit 1
# Print the differences to give the contributor a hint about what to
# expect when running the renaming scripts on their own machine.
git diff
echo "${MESSAGE}"
exit 1
fi

View File

@@ -70,13 +70,13 @@ jobs:
working-directory: ${{ env.BUILD_DIR }}
run: |
cmake \
-G 'Ninja' \
-DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake \
-DCMAKE_BUILD_TYPE="${BUILD_TYPE}" \
-Dtests=ON \
-Dwerr=ON \
-Dxrpld=ON \
..
-G 'Ninja' \
-DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake \
-DCMAKE_BUILD_TYPE="${BUILD_TYPE}" \
-Dtests=ON \
-Dwerr=ON \
-Dxrpld=ON \
..
# clang-tidy needs headers generated from proto files
- name: Build libxrpl.libpb
@@ -133,7 +133,7 @@ jobs:
- name: Write issue header
if: ${{ steps.run_clang_tidy.outcome != 'success' }}
run: |
cat > "${ISSUE_FILE}" <<EOF
cat >"${ISSUE_FILE}" <<EOF
## Clang-tidy Check Failed
### Clang-tidy Output:
@@ -144,30 +144,30 @@ jobs:
if: ${{ steps.run_clang_tidy.outcome != 'success' }}
run: |
if [ -f "${OUTPUT_FILE}" ]; then
# Extract lines containing 'error:', 'warning:', or 'note:'
grep -E '(error:|warning:|note:)' "${OUTPUT_FILE}" > filtered-output.txt || true
# Extract lines containing 'error:', 'warning:', or 'note:'
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 [ ! -s filtered-output.txt ]; then
cp "${OUTPUT_FILE}" filtered-output.txt
fi
# If filtered output is empty, use original (might be a different error format)
if [ ! -s filtered-output.txt ]; then
cp "${OUTPUT_FILE}" filtered-output.txt
fi
# Truncate if too large
head -c 60000 filtered-output.txt >> "${ISSUE_FILE}"
if [ "$(wc -c < filtered-output.txt)" -gt 60000 ]; then
echo "" >> "${ISSUE_FILE}"
echo "... (output truncated, see artifacts for full output)" >> "${ISSUE_FILE}"
fi
# Truncate if too large
head -c 60000 filtered-output.txt >>"${ISSUE_FILE}"
if [ "$(wc -c <filtered-output.txt)" -gt 60000 ]; then
echo "" >>"${ISSUE_FILE}"
echo "... (output truncated, see artifacts for full output)" >>"${ISSUE_FILE}"
fi
rm filtered-output.txt
rm filtered-output.txt
else
echo "No output file found" >> "${ISSUE_FILE}"
echo "No output file found" >>"${ISSUE_FILE}"
fi
- name: Append issue footer
if: ${{ steps.run_clang_tidy.outcome != 'success' }}
run: |
cat >> "${ISSUE_FILE}" <<EOF
cat >>"${ISSUE_FILE}" <<EOF
\`\`\`
---
@@ -176,7 +176,7 @@ jobs:
- name: Create issue
if: ${{ steps.run_clang_tidy.outcome != 'success' && inputs.create_issue_on_failure }}
uses: XRPLF/actions/create-issue@36d450d12d301e8410c1b7936e5de70c291cbe36
uses: XRPLF/actions/create-issue@2b8bc36af85b88bca0dd7bfac2e2dc05f94ad712
with:
title: "Clang-tidy check failed"
body_file: ${{ env.ISSUE_FILE }}

View File

@@ -39,7 +39,7 @@ jobs:
id: generate
working-directory: .github/scripts/strategy-matrix
run: |
./generate.py --packaging --config=linux.json >> "${GITHUB_OUTPUT}"
./generate.py --packaging --config=linux.json >>"${GITHUB_OUTPUT}"
generate-version:
runs-on: ubuntu-latest

View File

@@ -42,4 +42,4 @@ jobs:
env:
GENERATE_CONFIG: ${{ inputs.os != '' && format('--config={0}.json', inputs.os) || '' }}
GENERATE_OPTION: ${{ inputs.strategy_matrix == 'all' && '--all' || '' }}
run: ./generate.py ${GENERATE_OPTION} ${GENERATE_CONFIG} >> "${GITHUB_OUTPUT}"
run: ./generate.py ${GENERATE_OPTION} ${GENERATE_CONFIG} >>"${GITHUB_OUTPUT}"

View File

@@ -37,37 +37,50 @@ repos:
exclude: ^include/xrpl/protocol_autogen/(transactions|ledger_entries)/
- repo: https://github.com/pre-commit/mirrors-clang-format
rev: cd481d7b0bfb5c7b3090c21846317f9a8262e891 # frozen: v22.1.0
rev: dd18dad857d6133e90bbe478f4f2f22ec0030269 # frozen: v22.1.5
hooks:
- id: clang-format
args: [--style=file]
"types_or": [c++, c, proto]
exclude: ^include/xrpl/protocol_autogen/(transactions|ledger_entries)/
- repo: https://github.com/BlankSpruce/gersemi
rev: 0.26.0
- repo: https://github.com/BlankSpruce/gersemi-pre-commit
rev: faadd6a9d852369ca94f4d15b2404c967ba8cb01 # frozen: 0.27.6
hooks:
- id: gersemi
- repo: https://github.com/rbubley/mirrors-prettier
rev: c2bc67fe8f8f549cc489e00ba8b45aa18ee713b1 # frozen: v3.8.1
rev: 515f543f5718ebfd6ce22e16708bb32c68ff96e1 # frozen: v3.8.3
hooks:
- id: prettier
args: [--end-of-line=auto]
- repo: https://github.com/psf/black-pre-commit-mirror
rev: ea488cebbfd88a5f50b8bd95d5c829d0bb76feb8 # frozen: 26.1.0
rev: 4160603246a6b365d4a2af661c6d71b0a0f50478 # frozen: 26.5.1
hooks:
- id: black
- repo: https://github.com/openstack/bashate
rev: 5798d24d571676fc407e81df574c1ef57b520f23 # frozen: 2.1.1
- repo: https://github.com/scop/pre-commit-shfmt
rev: 05c1426671b9237fb5e1444dd63aa5731bec0dfb # frozen: v3.13.1-1
hooks:
- id: bashate
args: ["--ignore=E006"]
- id: shfmt
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
rev: a42085ade523f591dca134379a595e7859986445 # frozen: v9.7.0
rev: 4643f154907327ee0a2c7038f0296e0dd77d9776 # frozen: v10.0.0
hooks:
- id: cspell # Spell check changed files
exclude: |

View File

@@ -151,8 +151,8 @@ git init
git remote add origin git@github.com:XRPLF/conan-center-index.git
git sparse-checkout init
for recipe in "${recipes[@]}"; do
echo "Checking out recipe '${recipe}'..."
git sparse-checkout add recipes/${recipe}
echo "Checking out recipe '${recipe}'..."
git sparse-checkout add recipes/${recipe}
done
git fetch origin 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`:
```bash
```text
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',
'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:
```
cmake --build .
cmake --build . --parallel N
```
Multi-config generators:
```
cmake --build . --config Release
cmake --build . --config Debug
cmake --build . --config Release --parallel N
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.
Single-config generators:

View File

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

View File

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

View File

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

View File

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

View File

@@ -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
#
# 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
# This file was autogenerated by uv via the following command:
# uv pip compile requirements.in --generate-hashes --output-file requirements.txt
mako==1.3.12 \
--hash=sha256:8f61569480282dbf557145ce441e4ba888be453c30989f879f0d652e39f53ea9 \
--hash=sha256:9f778e93289bd410bb35daadeb4fc66d95a746f0b75777b942088b7fd7af550a
# via -r requirements.in
markupsafe==3.0.3 \
--hash=sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f \
--hash=sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a \
--hash=sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf \
--hash=sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19 \
--hash=sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf \
--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.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
explicit ${name}(std::shared_ptr<SLE const> sle)
explicit ${name}(SLE::const_pointer sle)
: LedgerEntryBase(std::move(sle))
{
// Verify ledger entry type
@@ -168,7 +168,7 @@ ${field['typeData']['setter_type']} ${field['paramName']}${',' if i < len(requir
* @param sle The existing ledger entry to copy from.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
${name}Builder(std::shared_ptr<SLE const> sle)
${name}Builder(SLE::const_pointer sle)
{
if (sle->at(sfLedgerEntryType) != ${tag})
{

View File

@@ -93,6 +93,7 @@ words:
- daria
- dcmake
- dearmor
- dedented
- deleteme
- demultiplexer
- deserializaton
@@ -199,11 +200,13 @@ words:
- nonxrp
- noreplace
- noripple
- nostdinc
- notifempty
- nudb
- nullptr
- nunl
- Nyffenegger
- onlatest
- ostr
- pargs
- partitioner
@@ -254,6 +257,7 @@ words:
- sfields
- shamap
- shamapitem
- shfmt
- shlibs
- sidechain
- SIGGOOD
@@ -298,6 +302,7 @@ words:
- unauthorizing
- unergonomic
- unfetched
- unfindable
- unflatten
- unfund
- unimpair

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

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

View File

@@ -27,7 +27,9 @@ RUN mkdir /tmp/nix-store-closure && \
cp -R $(nix-store -qR result/) /tmp/nix-store-closure
# Final image
FROM ${BASE_IMAGE}
FROM ${BASE_IMAGE} AS final
ARG BASE_IMAGE
# bash is not located at /bin/bash in nixos/nix, so we need to create a symlink to it.
RUN if [ -d /nix ]; then \
@@ -43,10 +45,30 @@ ENTRYPOINT ["/bin/bash"]
COPY --from=builder /tmp/nix-store-closure /nix/store
COPY --from=builder /tmp/build/result /nix/ci-env
ENV PATH="/nix/ci-env/bin:$PATH"
ENV PATH="/nix/ci-env/bin:${PATH}"
# Externally-built dynamically-linked ELF binaries hard-code the loader path
# (e.g. /lib64/ld-linux-x86-64.so.2) in their PT_INTERP header. Install it
# from the Nix store when the base image doesn't already provide one.
COPY docker/loader-path.sh /tmp/loader-path.sh
RUN <<EOF
target="$(/tmp/loader-path.sh)"
if [ ! -e "${target}" ]; then
# Use the loader from the same glibc that gcc links libc against, so
# ld-linux and libc/libpthread share GLIBC_PRIVATE symbols at runtime.
src="$(dirname "$(gcc -print-file-name=libc.so.6)")/$(basename "${target}")"
[ -e "${src}" ] || { echo "ld-linux not found at ${src}" >&2; exit 1; }
mkdir -p "$(dirname "${target}")"
cp "${src}" "${target}"
fi
EOF
RUN <<EOF
ccache --version
clang --version
clang++ --version
clang-format --version
cmake --version
conan --version
@@ -64,3 +86,17 @@ python3 --version
run-clang-tidy --help
vim --version
EOF
# Sanity-check that the sanitizer runtimes shipped with g++/clang++ are able to build binaries
COPY docker/test_files/cpp_sources/ /tmp/cpp_sources/
COPY docker/test_files/compile-cpp-sources.sh /tmp/compile-cpp-sources.sh
RUN /tmp/compile-cpp-sources.sh /tmp/cpp_sources /tmp/bins
# Sanity-check that the built binaries are able to run.
# We only support running the test binaries on Ubuntu and NixOS right now (will be fixed in the future)
#
# When build and test images will be separate, we will be to run on vanilla images.
COPY docker/test_files/run-test-binaries.sh /tmp/run-test-binaries.sh
RUN if echo "${BASE_IMAGE}" | grep -qiE '(ubuntu|nixos)'; then \
/tmp/run-test-binaries.sh /tmp/bins; \
fi

View File

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

View File

@@ -0,0 +1,28 @@
#include <atomic>
#include <cstddef>
#include <iostream>
#if defined(__clang__) || defined(__GNUC__)
__attribute__((noinline))
#elif defined(_MSC_VER)
__declspec(noinline)
#endif
int
read_after_free(volatile int* array, std::size_t index)
{
std::atomic_signal_fence(std::memory_order_seq_cst);
int value = array[index];
std::atomic_signal_fence(std::memory_order_seq_cst);
return value;
}
int
main()
{
int* array = new int[5]{10, 20, 30, 40, 50};
delete[] array;
std::cout << "Value at index 2: " << read_after_free(array, 2) << std::endl;
return 0;
}

View File

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

View File

@@ -0,0 +1,26 @@
#include <iostream>
#include <thread>
static int kCounter = 0;
void
increment()
{
for (int i = 0; i < 100'000; ++i)
{
++kCounter;
}
}
int
main()
{
std::thread t1(increment);
std::thread t2(increment);
t1.join();
t2.join();
std::cout << "Final counter value: " << kCounter << std::endl;
return 0;
}

View File

@@ -0,0 +1,13 @@
#include <iostream>
#include <limits>
int
main()
{
int maxInt = std::numeric_limits<int>::max();
int volatile one = 1;
std::cout << "Current max: " << maxInt << std::endl;
int overflowed = maxInt + one;
std::cout << "Overflowed result: " << overflowed << std::endl;
return 0;
}

View File

@@ -0,0 +1,62 @@
#!/bin/bash
# Run pre-compiled sanitizer binaries and confirm each emits its expected diagnostic.
# Binaries must already exist in <bins_dir> with the layout:
# <name>-g++ and <name>-clang++ for name in {regular,asan,tsan,ubsan}
set -eo pipefail
bins_dir="${1:?usage: $0 <bins_dir>}"
# Run a binary and verify its exit code and output.
# Usage: run <binary> <expected_output> <expected_rc>
function run() {
local binary="${1}"
local expected_output="${2}"
local expected_rc="${3}"
local out_file
out_file="$(mktemp)"
echo "=== Run ${binary} ==="
local rc=0
"${binary}" >"${out_file}" 2>&1 || rc=$?
cat "${out_file}"
if [ "${expected_rc}" = "nonzero" ]; then
if [ "${rc}" -eq 0 ]; then
echo "ERROR: expected non-zero exit code from ${binary}, got ${rc}" >&2
exit 1
fi
elif [ "${rc}" -ne "${expected_rc}" ]; then
echo "ERROR: expected exit code ${expected_rc} from ${binary}, got ${rc}" >&2
exit 1
fi
grep -q "${expected_output}" "${out_file}" ||
{
echo "ERROR: expected '${expected_output}' from ${binary}" >&2
exit 1
}
echo "OK: '${expected_output}' detected"
}
declare -A expect=(
[regular]="Hello from main thread"
[asan]="heap-use-after-free"
[tsan]="data race"
[ubsan]="signed integer overflow"
)
for compiler in g++ clang++; do
for name in regular asan tsan ubsan; do
binary="${bins_dir}/${name}-${compiler}"
if [ "${name}" = "regular" ]; then
expected_rc=0
else
expected_rc=nonzero
fi
run "${binary}" "${expect[$name]}" "${expected_rc}"
done
done

4
flake.lock generated
View File

@@ -15,7 +15,7 @@
"type": "indirect"
}
},
"nixpkgs-glibc231": {
"nixpkgs-custom-glibc": {
"flake": false,
"locked": {
"lastModified": 1593520194,
@@ -35,7 +35,7 @@
"root": {
"inputs": {
"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
# manually (flake = false) because this revision predates nixpkgs'
# own flake.nix.
nixpkgs-glibc231 = {
nixpkgs-custom-glibc = {
url = "github:NixOS/nixpkgs/9cd98386a38891d1074fc18036b842dc4416f562";
flake = false;
};
};
outputs =
{ nixpkgs, nixpkgs-glibc231, ... }:
{ nixpkgs, nixpkgs-custom-glibc, ... }:
let
forEachSystem = import ./nix/utils.nix { inherit nixpkgs nixpkgs-glibc231; };
forEachSystem = import ./nix/utils.nix { inherit nixpkgs nixpkgs-custom-glibc; };
in
{
devShells = forEachSystem (import ./nix/devshell.nix);

View File

@@ -2,12 +2,21 @@
#include <xrpl/beast/utility/instrumentation.h>
#include <array>
#include <concepts>
#include <cstdint>
#include <functional>
#include <limits>
#include <optional>
#include <ostream>
#include <set>
#include <stdexcept>
#include <string>
#include <unordered_map>
#ifdef _MSC_VER
#include <boost/multiprecision/cpp_int.hpp>
#endif // !defined(_MSC_VER)
namespace xrpl {
@@ -16,18 +25,39 @@ class Number;
std::string
to_string(Number const& amount);
/** Returns a rough estimate of log10(value).
*
* The return value is a pair (log, rem), where log is the estimated
* base-10 logarithm (roughly floor(log10(value))), and rem is value with
* all trailing 0s removed (i.e., divided by the largest power of 10 that
* evenly divides value). If rem is 1, then value is an exact power of ten, and
* log is the exact log10(value).
*
* This function only works for positive values.
*/
template <std::unsigned_integral T>
constexpr std::pair<int, T>
logTenEstimate(T value)
{
int log = 0;
T remainder = value;
while (value >= 10)
{
if (value % 10 == 0)
remainder = remainder / 10;
value /= 10;
++log;
}
return {log, remainder};
}
template <typename T>
constexpr std::optional<int>
logTen(T value)
{
int log = 0;
while (value >= 10 && value % 10 == 0)
{
value /= 10;
++log;
}
if (value == 1)
return log;
auto const est = logTenEstimate(value);
if (est.second == 1)
return est.first;
return std::nullopt;
}
@@ -38,17 +68,55 @@ isPowerOfTen(T value)
return logTen(value).has_value();
}
namespace detail {
/** Builds a table of the powers of 10
*
* This function is marked consteval, so it can only be run in
* a constexpr context. This assures that it is and can only be run at
* compile time. Doing it at runtime would be pretty wasteful and
* inefficient.
*/
constexpr std::size_t kInt64Digits = 20;
consteval std::array<std::uint64_t, kInt64Digits>
buildPowersOfTen()
{
std::array<std::uint64_t, kInt64Digits> result{};
std::uint64_t power = 1;
std::size_t exponent = 0;
// end the loop early so it doesn't overflow;
for (; exponent < result.size() - 1; ++exponent, power *= 10)
{
result[exponent] = power;
if (power > std::numeric_limits<std::uint64_t>::max() / 10)
throw std::logic_error("Power of 10 table is too big");
}
result[exponent] = power;
if (power < std::numeric_limits<std::uint64_t>::max() / 10)
throw std::logic_error("Power of 10 table is not big enough for the uint64_t type");
return result;
}
} // namespace detail
constexpr std::array<std::uint64_t, detail::kInt64Digits> kPowerOfTen = detail::buildPowersOfTen();
static_assert(kPowerOfTen[0] == 1);
static_assert(kPowerOfTen[1] == 10);
static_assert(kPowerOfTen[10] == 10'000'000'000);
static_assert(
isPowerOfTen(kPowerOfTen.back()) && *logTen(kPowerOfTen.back()) == detail::kInt64Digits - 1);
/** MantissaRange defines a range for the mantissa of a normalized Number.
*
* The mantissa is in the range [min, max], where
* * min is a power of 10, and
* * max = min * 10 - 1.
*
* The mantissa_scale enum indicates whether the range is "small" or "large".
* This intentionally restricts the number of MantissaRanges that can be
* instantiated to two: one for each scale.
* The MantissaScale enum indicates properties of the range: size, and some behavioral options.
* This intentionally prevents the creation of any MantissaRanges representing other values.
*
* 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
* uses before Lending Protocol was implemented, mostly related to AMM.
*
@@ -59,59 +127,181 @@ isPowerOfTen(T value)
* STNumber field type, and for internal calculations. That necessitated the
* "large" scale.
*
* The "large" scale is 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
* value of 10^19-1.
* The "Large" scales are intended to represent all values that can be represented
* by an STAmount - IOUs, XRP, and MPTs.
*
* They have a min value of 2^63/10+1 (truncated), and a max value of 2^63-1.
*
* "LargeLegacy" is like "Large", but preserves a rounding error when
* a computation results in a mantissa of Number::kLargestMantissa 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
* 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.
*/
struct MantissaRange
struct MantissaRange final
{
using rep = std::uint64_t;
enum class MantissaScale { Small, Large };
explicit constexpr MantissaRange(MantissaScale scale)
: min(getMin(scale)), log(logTen(min).value_or(-1)), scale(scale)
enum class MantissaScale {
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)
{
// Keep the error messages terse. Since this is constexpr, if any of these throw, it won't
// compile, so there's no real need to worry about runtime exceptions here.
if (min * 10 <= max)
throw std::out_of_range("Invalid mantissa range: min * 10 <= max");
if (max / 10 >= min)
throw std::out_of_range("Invalid mantissa range: max / 10 >= min");
if ((min - 1) * 10 > max)
throw std::out_of_range("Invalid mantissa range: (min - 1) * 10 > max");
// This is a little hacky
if ((max + 10) / 10 < min)
throw std::out_of_range("Invalid mantissa range: (max + 10) / 10 < min");
if (internalMin != kPowerOfTen[log])
throw std::out_of_range("Invalid mantissa range: internalMin != kPowersOfTen[log]");
}
rep min;
rep max{(min * 10) - 1};
int log;
MantissaScale scale;
// Explicitly delete copy and move operations
MantissaRange(MantissaRange const&) = delete;
MantissaRange(MantissaRange&&) = delete;
MantissaRange&
operator=(MantissaRange const&) = delete;
MantissaRange&
operator=(MantissaRange&&) = delete;
MantissaScale const scale;
int const log{getExponent(scale)};
rep const max{getMax(scale, log)};
rep const min{computeMin(max)};
/* Used to determine if mantissas are in range, but have fewer digits than max.
*
* Unlike min, internalMin is always an exact power of 10, so a mantissa in the internal
* representation will always have a consistent number of digits.
*/
rep const internalMin{getInternalMin(scale, log)};
CuspRoundingFix const cuspRoundingFixEnabled{isCuspFixEnabled(scale)};
static MantissaRange const&
getMantissaRange(MantissaScale scale);
static std::set<MantissaScale> const&
getAllScales();
private:
static constexpr rep
getMin(MantissaScale scale)
static constexpr int
getExponent(MantissaScale scale)
{
switch (scale)
{
case MantissaScale::Small:
return 1'000'000'000'000'000ULL;
return 15;
case MantissaScale::LargeLegacy:
case MantissaScale::Large:
return 1'000'000'000'000'000'000ULL;
return 18;
// LCOV_EXCL_START
default:
// Since this can never be called outside a non-constexpr
// context, this throw assures that the build fails if an
// 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_STOP
}
}
static constexpr rep
getMax(MantissaScale scale, int log)
{
switch (scale)
{
case MantissaScale::Small:
return kPowerOfTen[log + 1] - 1;
case MantissaScale::LargeLegacy:
case MantissaScale::Large:
return std::numeric_limits<std::int64_t>::max();
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_STOP
}
}
static constexpr rep
computeMin(rep max)
{
return (max / 10) + 1;
}
static constexpr rep
getInternalMin(MantissaScale scale, int exponent)
{
if (exponent < 0 || exponent >= kPowerOfTen.size())
{
// If called in a constexpr context, this throw assures that the build fails if an
// invalid exponent is used.
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.
template <class T>
concept Integral64 = std::is_same_v<T, std::int64_t> || std::is_same_v<T, std::uint64_t>;
namespace detail {
#ifdef _MSC_VER
using uint128_t = boost::multiprecision::uint128_t;
using int128_t = boost::multiprecision::int128_t;
#else // !defined(_MSC_VER)
using uint128_t = __uint128_t;
using int128_t = __int128_t;
#endif // !defined(_MSC_VER)
template <class T>
concept UnsignedMantissa = std::is_unsigned_v<T> || std::is_same_v<T, uint128_t>;
} // namespace detail
/** Number is a floating point type that can represent a wide range of values.
*
* It can represent all values that can be represented by an STAmount -
* regardless of asset type - XRPAmount, MPTAmount, and IOUAmount, with at least
* as much precision as those types require.
*
* ---- Internal Representation ----
* ---- Internal Operational Representation ----
*
* Internally, Number is represented with three values:
* 1. a bool sign flag,
@@ -120,40 +310,45 @@ concept Integral64 = std::is_same_v<T, std::int64_t> || std::is_same_v<T, std::u
*
* The internal mantissa is an unsigned integer in the range defined by the
* current MantissaRange. The exponent is an integer in the range
* [minExponent, maxExponent].
* [kMinExponent, kMaxExponent].
*
* See the description of MantissaRange for more details on the ranges.
*
* A non-zero mantissa is (almost) always normalized, meaning it and the
* exponent are grown or shrunk until the mantissa is in the range
* [MantissaRange.min, MantissaRange.max].
* [MantissaRange.internalMin, MantissaRange.internalMin * 10 - 1].
*
* This internal representation is only used during some operations to ensure
* that the mantissa is a known, predictable size. The class itself stores the
* values using the external representation described below.
*
* Note:
* 1. Normalization can be disabled by using the "unchecked" ctor tag. This
* should only be used at specific conversion points, some constexpr
* values, and in unit tests.
* 2. The max of the "large" range, 10^19-1, is the largest 10^X-1 value that
* fits in an unsigned 64-bit number. (10^19-1 < 2^64-1 and
* 10^20-1 > 2^64-1). This avoids under- and overflows.
* 2. Unlike MantissaRange.min, internalMin is always an exact power of 10,
* so a mantissa in the internal representation will always have a
* consistent number of digits.
* 3. The functions toInternal() and fromInternal() are used to convert
* between the two representations.
*
* ---- External Interface ----
*
* The external interface of Number consists of a std::int64_t mantissa, which
* is restricted to 63-bits, and an int exponent, which must be in the range
* [minExponent, maxExponent]. The range of the mantissa depends on which
* [kMinExponent, kMaxExponent]. The range of the mantissa depends on which
* MantissaRange is currently active. For the "short" range, the mantissa will
* be between 10^15 and 10^16-1. For the "large" range, the mantissa will be
* between -(2^63-1) and 2^63-1. As noted above, the "large" range is needed to
* represent the full range of valid XRP and MPT integer values accurately.
*
* Note:
* 1. 2^63-1 is between 10^18 and 10^19-1, which are the limits of the "large"
* mantissa range.
* 1. The "large" mantissa range is (2^63/10+1) to 2^63-1. 2^63-1 is between
* 10^18 and 10^19-1, and (2^63/10+1) is between 10^17 and 10^18-1. Thus,
* the mantissa may have 18 or 19 digits. This value will be modified to
* always have 19 digits before some operations to ensure consistency.
* 2. The functions mantissa() and exponent() return the external view of the
* Number value, specifically using a signed 63-bit mantissa. This may
* require altering the internal representation to fit into that range
* before the value is returned. The interface guarantees consistency of
* the two values.
* Number value, specifically using a signed 63-bit mantissa.
* 3. Number cannot represent -2^63 (std::numeric_limits<std::int64_t>::min())
* as an exact integer, but it doesn't need to, because all asset values
* on-ledger are non-negative. This is due to implementation details of
@@ -203,13 +398,12 @@ 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.
*
*/
class Number
class Number final
{
using rep = std::int64_t;
using internalrep = MantissaRange::rep;
bool negative_{false};
internalrep mantissa_{0};
rep mantissa_{0};
int exponent_{std::numeric_limits<int>::lowest()};
public:
@@ -217,10 +411,6 @@ public:
static constexpr int kMinExponent = -32768;
static constexpr int kMaxExponent = 32768;
static constexpr internalrep kMaxRep = std::numeric_limits<rep>::max();
static_assert(kMaxRep == 9'223'372'036'854'775'807);
static_assert(-kMaxRep == std::numeric_limits<rep>::min() + 1);
// May need to make unchecked private
struct Unchecked
{
@@ -298,8 +488,7 @@ public:
friend constexpr bool
operator==(Number const& x, Number const& y) noexcept
{
return x.negative_ == y.negative_ && x.mantissa_ == y.mantissa_ &&
x.exponent_ == y.exponent_;
return x.mantissa_ == y.mantissa_ && x.exponent_ == y.exponent_;
}
friend constexpr bool
@@ -313,8 +502,8 @@ public:
{
// If the two amounts have different signs (zero is treated as positive)
// then the comparison is true iff the left is negative.
bool const lneg = x.negative_;
bool const rneg = y.negative_;
bool const lneg = x.mantissa_ < 0;
bool const rneg = y.mantissa_ < 0;
if (lneg != rneg)
return lneg;
@@ -342,9 +531,11 @@ public:
[[nodiscard]] constexpr int
signum() const noexcept
{
if (negative_)
if (mantissa_ < 0)
{
return -1;
return (mantissa_ != 0u) ? 1 : 0;
}
return (mantissa_ != 0 ? 1 : 0);
}
[[nodiscard]] Number
@@ -383,6 +574,9 @@ public:
friend Number
root2(Number f);
friend Number
power(Number const& f, unsigned n, unsigned d);
// Thread local rounding control. Default is to_nearest
enum class RoundingMode { ToNearest, TowardsZero, Downward, Upward };
@@ -424,49 +618,48 @@ public:
return kRange.get().log;
}
/// oneSmall is needed because the ranges are private
static constexpr Number
oneSmall();
/// oneLarge is needed because the ranges are private
static constexpr Number
oneLarge();
// And one is needed because it needs to choose between oneSmall and
// oneLarge based on the current range
static Number
one();
template <
auto MinMantissa,
auto MaxMantissa,
Integral64 T = std::decay_t<decltype(MinMantissa)>>
[[nodiscard]]
std::pair<T, int>
normalizeToRange() const;
private:
/** May use ranges that don't fit the restrictions of the "real"
* normalizeToRange().
*
*/
template <Integral64 T>
[[nodiscard]]
std::pair<T, int>
normalizeToRange(T minMantissa, T maxMantissa) const;
normalizeToRangeImpl(T minMantissa, T maxMantissa, MantissaRange::CuspRoundingFix fix) const;
// Number_test needs to use normalizeToRangeImpl
friend class Number_test;
private:
static thread_local RoundingMode mode;
// The available ranges for mantissa
static constexpr MantissaRange kSmallRange{MantissaRange::MantissaScale::Small};
static_assert(isPowerOfTen(kSmallRange.min));
static_assert(kSmallRange.min == 1'000'000'000'000'000LL);
static_assert(kSmallRange.max == 9'999'999'999'999'999LL);
static_assert(kSmallRange.log == 15);
static_assert(kSmallRange.min < kMaxRep);
static_assert(kSmallRange.max < kMaxRep);
static constexpr MantissaRange kLargeRange{MantissaRange::MantissaScale::Large};
static_assert(isPowerOfTen(kLargeRange.min));
static_assert(kLargeRange.min == 1'000'000'000'000'000'000ULL);
static_assert(kLargeRange.max == internalrep(9'999'999'999'999'999'999ULL));
static_assert(kLargeRange.log == 18);
static_assert(kLargeRange.min < kMaxRep);
static_assert(kLargeRange.max > kMaxRep);
// The range for the mantissa when normalized.
// Use reference_wrapper to avoid making copies, and prevent accidentally
// changing the values inside the range.
static thread_local std::reference_wrapper<MantissaRange const> kRange;
// And one is needed because it needs to choose between oneSmall and
// oneLarge based on the current range
static Number
one(MantissaRange const& range);
static Number
root(MantissaRange const& range, Number f, unsigned d);
void
normalize();
normalize(MantissaRange const& range);
/** Normalize Number components to an arbitrary range.
*
@@ -481,7 +674,8 @@ private:
T& mantissa,
int& exponent,
internalrep const& minMantissa,
internalrep const& maxMantissa);
internalrep const& maxMantissa,
MantissaRange::CuspRoundingFix cuspRoundingFixEnabled);
template <class T>
friend void
@@ -490,7 +684,13 @@ private:
T& mantissa,
int& exponent,
MantissaRange::rep const& minMantissa,
MantissaRange::rep const& maxMantissa);
MantissaRange::rep const& maxMantissa,
MantissaRange::CuspRoundingFix cuspRoundingFixEnabled,
bool dropped);
[[nodiscard]]
bool
isnormal(MantissaRange const& range) const noexcept;
[[nodiscard]] bool
isnormal() const noexcept;
@@ -501,18 +701,66 @@ private:
[[nodiscard]] Number
shiftExponent(int exponentDelta) const;
// Safely convert rep (int64) mantissa to internalrep (uint64). If the rep
// is negative, returns the positive value. This takes a little extra work
// because converting std::numeric_limits<std::int64_t>::min() flirts with
// UB, and can vary across compilers.
// Safely return the absolute value of a rep (int64) mantissa as an internalrep (uint64).
static internalrep
externalToInternal(rep mantissa);
/** Breaks down the number into components, potentially de-normalizing it.
*
* Ensures that the mantissa always has kRange.log + 1 digits.
*
*/
template <detail::UnsignedMantissa Rep = internalrep>
std::tuple<bool, Rep, int>
toInternal(MantissaRange const& range) const;
/** Breaks down the number into components, potentially de-normalizing it.
*
* Ensures that the mantissa always has kRange.log + 1 digits.
*
*/
template <detail::UnsignedMantissa Rep = internalrep>
std::tuple<bool, Rep, int>
toInternal() const;
/** Rebuilds the number from components.
*
* If "expectNormal" is true, the values are expected to be normalized - all
* in their valid ranges.
*
* If "expectNormal" is false, the values are expected to be "near
* normalized", meaning that the mantissa has to be modified at most once to
* bring it back into range.
*
*/
template <bool ExpectNormal = true, detail::UnsignedMantissa Rep = internalrep>
void
fromInternal(bool negative, Rep mantissa, int exponent, MantissaRange const* pRange);
/** Rebuilds the number from components.
*
* If "expectNormal" is true, the values are expected to be normalized - all
* in their valid ranges.
*
* If "expectNormal" is false, the values are expected to be "near
* normalized", meaning that the mantissa has to be modified at most once to
* bring it back into range.
*
*/
template <bool ExpectNormal = true, detail::UnsignedMantissa Rep = internalrep>
void
fromInternal(bool negative, Rep mantissa, int exponent);
class Guard;
public:
constexpr static internalrep kLargestMantissa =
MantissaRange{MantissaRange::MantissaScale::Large}.max;
};
constexpr Number::Number(bool negative, internalrep mantissa, int exponent, Unchecked) noexcept
: negative_(negative), mantissa_{mantissa}, exponent_{exponent}
: mantissa_{negative ? -static_cast<rep>(mantissa) : static_cast<rep>(mantissa)}
, exponent_{exponent}
{
}
@@ -523,12 +771,6 @@ constexpr Number::Number(internalrep mantissa, int exponent, Unchecked) noexcept
static constexpr Number kNumZero{};
inline Number::Number(bool negative, internalrep mantissa, int exponent, Normalized)
: Number(negative, mantissa, exponent, Unchecked{})
{
normalize();
}
inline Number::Number(internalrep mantissa, int exponent, Normalized)
: Number(false, mantissa, exponent, Normalized{})
{
@@ -551,17 +793,7 @@ inline Number::Number(rep mantissa) : Number{mantissa, 0}
constexpr Number::rep
Number::mantissa() const noexcept
{
auto m = mantissa_;
if (m > kMaxRep)
{
XRPL_ASSERT_PARTS(
!isnormal() || (m % 10 == 0 && m / 10 <= kMaxRep),
"xrpl::Number::mantissa",
"large normalized mantissa has no remainder");
m /= 10;
}
auto const sign = negative_ ? -1 : 1;
return sign * static_cast<Number::rep>(m);
return mantissa_;
}
/** Returns the exponent of the external view of the Number.
@@ -572,16 +804,7 @@ Number::mantissa() const noexcept
constexpr int
Number::exponent() const noexcept
{
auto e = exponent_;
if (mantissa_ > kMaxRep)
{
XRPL_ASSERT_PARTS(
!isnormal() || (mantissa_ % 10 == 0 && mantissa_ / 10 <= kMaxRep),
"xrpl::Number::exponent",
"large normalized mantissa has no remainder");
++e;
}
return e;
return exponent_;
}
constexpr Number
@@ -596,7 +819,7 @@ Number::operator-() const noexcept
if (mantissa_ == 0)
return Number{};
auto x = *this;
x.negative_ = !x.negative_;
x.mantissa_ = -x.mantissa_;
return x;
}
@@ -677,31 +900,64 @@ Number::min() noexcept
inline Number
Number::max() noexcept
{
return Number{false, std::min(kRange.get().max, kMaxRep), kMaxExponent, Unchecked{}};
return Number{false, kRange.get().max, kMaxExponent, Unchecked{}};
}
inline Number
Number::lowest() noexcept
{
return Number{true, std::min(kRange.get().max, kMaxRep), kMaxExponent, Unchecked{}};
return Number{true, kRange.get().max, kMaxExponent, Unchecked{}};
}
inline bool
Number::isnormal(MantissaRange const& range) const noexcept
{
auto const absM = externalToInternal(mantissa_);
return *this == Number{} ||
(range.min <= absM && absM <= range.max && //
kMinExponent <= exponent_ && exponent_ <= kMaxExponent);
}
inline bool
Number::isnormal() const noexcept
{
MantissaRange const& range = kRange;
auto const absM = mantissa_;
return *this == Number{} ||
(range.min <= absM && absM <= range.max && (absM <= kMaxRep || absM % 10 == 0) &&
kMinExponent <= exponent_ && exponent_ <= kMaxExponent);
return isnormal(kRange);
}
template <Integral64 T>
template <auto MinMantissa, auto MaxMantissa, Integral64 T>
std::pair<T, int>
Number::normalizeToRange(T minMantissa, T maxMantissa) const
Number::normalizeToRange() const
{
bool negative = negative_;
internalrep mantissa = mantissa_;
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(static_cast<std::make_unsigned_t<T>>(kMIN)));
static_assert(kMAX % 10 == 9);
static_assert((kMAX + 1) / 10 == kMIN);
// 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.
return normalizeToRangeImpl(kMIN, kMAX, MantissaRange::CuspRoundingFix::Disabled);
}
/** Only intended to be used in tests
*
* May use ranges that don't fit the restrictions of the "real"
* normalizeToRange().
*
*/
template <Integral64 T>
[[nodiscard]]
std::pair<T, int>
Number::normalizeToRangeImpl(T minMantissa, T maxMantissa, MantissaRange::CuspRoundingFix fix) const
{
bool negative = mantissa_ < 0;
internalrep mantissa = externalToInternal(mantissa_);
int exponent = exponent_;
if constexpr (std::is_unsigned_v<T>)
@@ -710,11 +966,21 @@ Number::normalizeToRange(T minMantissa, T maxMantissa) const
!negative,
"xrpl::Number::normalizeToRange",
"Number is non-negative for unsigned range.");
// To avoid logical errors in release builds, throw if the Number is
// negative for an unsigned range.
if (negative)
{
throw std::runtime_error(
"Number::normalizeToRange: Number is negative for "
"unsigned range.");
}
}
Number::normalize(negative, mantissa, exponent, minMantissa, maxMantissa);
Number::normalize(negative, mantissa, exponent, minMantissa, maxMantissa, fix);
auto const sign = negative ? -1 : 1;
return std::make_pair(static_cast<T>(sign * mantissa), exponent);
// Cast mantissa to signed type first (if T is a signed type) to avoid
// unsigned integer overflow when multiplying by negative sign
T signedMantissa = negative ? -static_cast<T>(mantissa) : static_cast<T>(mantissa);
return std::make_pair(signedMantissa, exponent);
}
constexpr Number
@@ -763,6 +1029,8 @@ to_string(MantissaRange::MantissaScale const& scale)
{
case MantissaRange::MantissaScale::Small:
return "small";
case MantissaRange::MantissaScale::LargeLegacy:
return "largeLegacy";
case MantissaRange::MantissaScale::Large:
return "large";
default:

View File

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

View File

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

View File

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

View File

@@ -77,8 +77,8 @@ private:
std::ostream& os_;
Results results_;
SuiteResults suite_results_;
CaseResults case_results_;
SuiteResults suiteResults_;
CaseResults caseResults_;
public:
Reporter(Reporter const&) = delete;
@@ -196,22 +196,22 @@ template <class Unused>
void
Reporter<Unused>::onSuiteBegin(SuiteInfo const& info)
{
suite_results_ = SuiteResults{info.fullName()};
suiteResults_ = SuiteResults{info.fullName()};
}
template <class Unused>
void
Reporter<Unused>::onSuiteEnd()
{
results_.add(suite_results_);
results_.add(suiteResults_);
}
template <class Unused>
void
Reporter<Unused>::onCaseBegin(std::string const& name)
{
case_results_ = CaseResults(name);
os_ << suite_results_.name << (case_results_.name.empty() ? "" : (" " + case_results_.name))
caseResults_ = CaseResults(name);
os_ << suiteResults_.name << (caseResults_.name.empty() ? "" : (" " + caseResults_.name))
<< std::endl;
}
@@ -219,23 +219,23 @@ template <class Unused>
void
Reporter<Unused>::onCaseEnd()
{
suite_results_.add(case_results_);
suiteResults_.add(caseResults_);
}
template <class Unused>
void
Reporter<Unused>::onPass()
{
++case_results_.total;
++caseResults_.total;
}
template <class Unused>
void
Reporter<Unused>::onFail(std::string const& reason)
{
++case_results_.failed;
++case_results_.total;
os_ << "#" << case_results_.total << " failed" << (reason.empty() ? "" : ": ") << reason
++caseResults_.failed;
++caseResults_.total;
os_ << "#" << caseResults_.total << " failed" << (reason.empty() ? "" : ": ") << reason
<< std::endl;
}

View File

@@ -47,7 +47,7 @@ inline bool
JobQueue::Coro::post()
{
{
std::scoped_lock const lk(mutex_run_);
std::scoped_lock const lk(mutexRun_);
running_ = true;
}
@@ -58,7 +58,7 @@ JobQueue::Coro::post()
}
// The coroutine will not run. Clean up running_.
std::scoped_lock const lk(mutex_run_);
std::scoped_lock const lk(mutexRun_);
running_ = false;
cv_.notify_all();
return false;
@@ -68,7 +68,7 @@ inline void
JobQueue::Coro::resume()
{
{
std::scoped_lock const lk(mutex_run_);
std::scoped_lock const lk(mutexRun_);
running_ = true;
}
{
@@ -92,7 +92,7 @@ JobQueue::Coro::resume()
}
detail::getLocalValues().release();
detail::getLocalValues().reset(saved);
std::scoped_lock const lk(mutex_run_);
std::scoped_lock const lk(mutexRun_);
running_ = false;
cv_.notify_all();
}
@@ -127,7 +127,7 @@ JobQueue::Coro::expectEarlyExit()
inline void
JobQueue::Coro::join()
{
std::unique_lock<std::mutex> lk(mutex_run_);
std::unique_lock<std::mutex> lk(mutexRun_);
cv_.wait(lk, [this]() { return !running_; });
}

View File

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

View File

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

View File

@@ -161,7 +161,7 @@ public:
* While the JSON spec doesn't explicitly disallow this, you should avoid
* 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.
*/
template <typename Type>

View File

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

View File

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

View File

@@ -9,15 +9,15 @@ class BookDirs
private:
ReadView const* view_ = nullptr;
uint256 const root_;
uint256 const next_quality_;
uint256 const nextQuality_;
uint256 const key_;
std::shared_ptr<SLE const> sle_ = nullptr;
SLE::const_pointer sle_ = nullptr;
unsigned int entry_ = 0;
uint256 index_;
public:
class const_iterator; // NOLINT(readability-identifier-naming)
using value_type = std::shared_ptr<SLE const>;
using value_type = SLE::const_pointer;
BookDirs(ReadView const&, Book const&);
@@ -67,16 +67,16 @@ private:
friend class BookDirs;
const_iterator(ReadView const& view, uint256 const& root, uint256 const& dirKey)
: view_(&view), root_(root), key_(dirKey), cur_key_(dirKey)
: view_(&view), root_(root), key_(dirKey), curKey_(dirKey)
{
}
ReadView const* view_ = nullptr;
uint256 root_;
uint256 next_quality_;
uint256 nextQuality_;
uint256 key_;
uint256 cur_key_;
std::shared_ptr<SLE const> sle_;
uint256 curKey_;
SLE::const_pointer sle_;
unsigned int entry_ = 0;
uint256 index_;
std::optional<value_type> mutable cache_;

View File

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

View File

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

View File

@@ -166,7 +166,7 @@ public:
std::optional<uint256>
succ(uint256 const& key, std::optional<uint256> const& last = std::nullopt) const override;
std::shared_ptr<SLE const>
SLE::const_pointer
read(Keylet const& k) const override;
std::unique_ptr<SlesType::iter_base>
@@ -202,16 +202,16 @@ public:
//
void
rawErase(std::shared_ptr<SLE> const& sle) override;
rawErase(SLE::ref sle) override;
void
rawInsert(std::shared_ptr<SLE> const& sle) override;
rawInsert(SLE::ref sle) override;
void
rawErase(uint256 const& key);
void
rawReplace(std::shared_ptr<SLE> const& sle) override;
rawReplace(SLE::ref sle) override;
void
rawDestroyXRP(XRPAmount const& fee) override
@@ -361,7 +361,7 @@ public:
bool
isVotingLedger() const;
std::shared_ptr<SLE>
SLE::pointer
peek(Keylet const& k) const;
private:

View File

@@ -76,7 +76,7 @@ private:
// monotonic_resource_ must outlive `items_`. Make a pointer so it may be
// easily moved.
std::unique_ptr<boost::container::pmr::monotonic_buffer_resource> monotonic_resource_;
std::unique_ptr<boost::container::pmr::monotonic_buffer_resource> monotonicResource_;
txs_map txs_;
Rules rules_;
LedgerHeader header_;
@@ -197,7 +197,7 @@ public:
std::optional<key_type>
succ(key_type const& key, std::optional<key_type> const& last = std::nullopt) const override;
std::shared_ptr<SLE const>
SLE::const_pointer
read(Keylet const& k) const override;
std::unique_ptr<SlesType::iter_base>
@@ -224,13 +224,13 @@ public:
// RawView
void
rawErase(std::shared_ptr<SLE> const& sle) override;
rawErase(SLE::ref sle) override;
void
rawInsert(std::shared_ptr<SLE> const& sle) override;
rawInsert(SLE::ref sle) override;
void
rawReplace(std::shared_ptr<SLE> const& sle) override;
rawReplace(SLE::ref sle) override;
void
rawDestroyXRP(XRPAmount const& fee) override;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -22,14 +22,14 @@ public:
static constexpr size_t kInitialBufferSize = kilobytes(256);
RawStateTable()
: monotonic_resource_{std::make_unique<boost::container::pmr::monotonic_buffer_resource>(
: monotonicResource_{std::make_unique<boost::container::pmr::monotonic_buffer_resource>(
kInitialBufferSize)}
, items_{monotonic_resource_.get()} {};
, items_{monotonicResource_.get()} {};
RawStateTable(RawStateTable const& rhs)
: monotonic_resource_{std::make_unique<boost::container::pmr::monotonic_buffer_resource>(
: monotonicResource_{std::make_unique<boost::container::pmr::monotonic_buffer_resource>(
kInitialBufferSize)}
, items_{rhs.items_, monotonic_resource_.get()}
, items_{rhs.items_, monotonicResource_.get()}
, dropsDestroyed_{rhs.dropsDestroyed_} {};
RawStateTable(RawStateTable&&) = default;
@@ -49,15 +49,15 @@ public:
succ(ReadView const& base, key_type const& key, std::optional<key_type> const& last) const;
void
erase(std::shared_ptr<SLE> const& sle);
erase(SLE::ref sle);
void
insert(std::shared_ptr<SLE> const& sle);
insert(SLE::ref sle);
void
replace(std::shared_ptr<SLE> const& sle);
replace(SLE::ref sle);
[[nodiscard]] std::shared_ptr<SLE const>
[[nodiscard]] SLE::const_pointer
read(ReadView const& base, Keylet const& k) const;
void
@@ -84,10 +84,10 @@ private:
struct SleAction
{
Action action;
std::shared_ptr<SLE> sle;
SLE::pointer sle;
// Constructor needed for emplacement in std::map
SleAction(Action action, std::shared_ptr<SLE> const& sle) : action(action), sle(sle)
SleAction(Action action, SLE::pointer sle) : action(action), sle(std::move(sle))
{
}
};
@@ -101,7 +101,7 @@ private:
boost::container::pmr::polymorphic_allocator<std::pair<key_type const, SleAction>>>;
// monotonic_resource_ must outlive `items_`. Make a pointer so it may be
// easily moved.
std::unique_ptr<boost::container::pmr::monotonic_buffer_resource> monotonic_resource_;
std::unique_ptr<boost::container::pmr::monotonic_buffer_resource> monotonicResource_;
items_t items_;
XRPAmount dropsDestroyed_{0};

View File

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

View File

@@ -9,7 +9,6 @@
#include <xrpl/protocol/STLedgerEntry.h>
#include <xrpl/protocol/TER.h>
#include <memory>
#include <set>
#include <vector>
@@ -36,11 +35,7 @@ xrpLiquid(ReadView const& view, AccountID const& id, std::int32_t ownerCountAdj,
/** Adjust the owner count up or down. */
void
adjustOwnerCount(
ApplyView& view,
std::shared_ptr<SLE> const& sle,
std::int32_t amount,
beast::Journal j);
adjustOwnerCount(ApplyView& view, SLE::ref sle, std::int32_t amount, beast::Journal j);
/** Returns IOU issuer transfer fee as Rate. Rate specifies
* the fee as fractions of 1 billion. For example, 1% transfer rate
@@ -76,9 +71,7 @@ getPseudoAccountFields();
- null pointer
*/
[[nodiscard]] bool
isPseudoAccount(
std::shared_ptr<SLE const> sleAcct,
std::set<SField const*> const& pseudoFieldFilter = {});
isPseudoAccount(SLE::const_pointer sleAcct, std::set<SField const*> const& pseudoFieldFilter = {});
/** Convenience overload that reads the account from the view. */
[[nodiscard]] inline bool
@@ -98,15 +91,8 @@ isPseudoAccount(
* before using a field. The amendment check is **not** performed in
* createPseudoAccount.
*/
[[nodiscard]] Expected<std::shared_ptr<SLE>, TER>
createPseudoAccount(
ApplyView& view,
uint256 const& pseudoOwnerKey,
SField const& ownerField,
std::uint32_t additionalFlags = 0);
[[nodiscard]] bool
isBlackholed(ReadView const& view, std::shared_ptr<SLE const> const& sle);
[[nodiscard]] Expected<SLE::pointer, TER>
createPseudoAccount(ApplyView& view, uint256 const& pseudoOwnerKey, SField const& ownerField);
/** Checks the destination and tag.

View File

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

View File

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

View File

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

View File

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

View File

@@ -4,8 +4,38 @@
#include <xrpl/protocol/Rules.h>
#include <xrpl/protocol/st.h>
#include <string_view>
namespace xrpl {
/**
* Broker cover preclaim precision guard (fixCleanup3_2_0).
*
* Prevents a "silent sub-ULP no-op" where a deposit, withdrawal, or clawback
* amount is so small that it rounds to zero at `sfCoverAvailable`'s scale.
* Without this guard, both the pseudo trust-line and `sfCoverAvailable` would
* identically absorb the rounded zero, resulting in a successful transaction
* (tesSUCCESS) where no funds actually moved.
*
* @param view Read view (rules used for amendment gating).
* @param sleBroker The loan broker SLE (read-only).
* @param vaultAsset The underlying vault asset (the broker's cover asset).
* @param amount The effective subtraction/addition amount.
* @param j Journal for logging.
* @param logPrefix Transactor name for log diagnostics.
*
* @return `tecPRECISION_LOSS` if the request rounds to zero at cover scale.
* `tesSUCCESS` if the amendment is disabled or the request is safely supra-ULP.
*/
[[nodiscard]] TER
canApplyToBrokerCover(
ReadView const& view,
SLE::const_ref sleBroker,
Asset const& vaultAsset,
STAmount const& amount,
beast::Journal j,
std::string_view logPrefix);
// Lending protocol has dependencies, so capture them here.
bool
checkLendingProtocolDependencies(Rules const& rules, STTx const& tx);
@@ -173,6 +203,21 @@ getAssetsTotalScale(SLE::const_ref vaultSle)
return scale(vaultSle->at(sfAssetsTotal), vaultSle->at(sfAsset));
}
// Compute the minimum required broker cover, rounded consistently.
// DebtTotal is a broker-level aggregate maintained at vault scale, so the
// rounding must also use vault scale — never an individual loan's scale.
inline Number
minimumBrokerCover(Number const& debtTotal, TenthBips32 coverRateMinimum, SLE::const_ref vaultSle)
{
XRPL_ASSERT(
vaultSle && vaultSle->getType() == ltVAULT, "xrpl::minimumBrokerCover : valid Vault sle");
NumberRoundModeGuard const mg(Number::RoundingMode::Upward);
return roundToAsset(
vaultSle->at(sfAsset),
tenthBipsOfValue(debtTotal, coverRateMinimum),
getAssetsTotalScale(vaultSle));
}
TER
checkLoanGuards(
Asset const& vaultAsset,
@@ -416,6 +461,7 @@ loanAccruedInterest(
ExtendedPaymentComponents
computeOverpaymentComponents(
Rules const& rules,
Asset const& asset,
int32_t const loanScale,
Number const& overpayment,

View File

@@ -27,14 +27,18 @@ isGlobalFrozen(ReadView const& view, MPTIssue const& mptIssue);
isIndividualFrozen(ReadView const& view, AccountID const& account, MPTIssue const& mptIssue);
[[nodiscard]] bool
isFrozen(ReadView const& view, AccountID const& account, MPTIssue const& mptIssue, int depth = 0);
isFrozen(
ReadView const& view,
AccountID const& account,
MPTIssue const& mptIssue,
std::uint8_t depth = 0);
[[nodiscard]] bool
isAnyFrozen(
ReadView const& view,
std::initializer_list<AccountID> const& accounts,
MPTIssue const& mptIssue,
int depth = 0);
std::uint8_t depth = 0);
//------------------------------------------------------------------------------
//
@@ -88,7 +92,7 @@ requireAuth(
MPTIssue const& mptIssue,
AccountID const& account,
AuthType authType = AuthType::Legacy,
int depth = 0);
std::uint8_t depth = 0);
/** Enforce account has MPToken to match its authorization.
*
@@ -104,22 +108,77 @@ enforceMPTokenAuthorization(
XRPAmount const& priorBalance,
beast::Journal j);
/** Check if the destination account is allowed
* to receive MPT. Return tecNO_AUTH if it doesn't
* and tesSUCCESS otherwise.
/** Resolve the underlying asset of a vault share.
*
* Reads sfReferenceHolding from @p sleShareIssuance to determine which
* asset the vault wraps. @p sleHolding must be the SLE that
* sfReferenceHolding points to — either an ltMPTOKEN (returns its
* MPTIssue) or an ltRIPPLE_STATE (returns its low/high Issue).
*
* @pre Both SLEs must exist and @p sleHolding must be of type ltMPTOKEN
* or ltRIPPLE_STATE. Passing any other type is undefined behaviour.
* @param sleShareIssuance MPTokenIssuance SLE for the vault share token.
* @param sleHolding SLE referenced by sfReferenceHolding.
* @return The underlying Asset (MPTIssue or Issue).
*/
[[nodiscard]] Asset
assetOfHolding(SLE const& sleShareIssuance, SLE const& sleHolding);
/** Check whether @p to may receive the given MPT from @p from.
*
* The check passes when any of the following is true:
* - @p waive is WaiveMPTCanTransfer::Yes (recovery-path exemption), or
* - @p from or @p to is the issuer, or
* - lsfMPTCanTransfer is set on the MPTokenIssuance.
*
* For vault shares (MPTokenIssuances that carry sfReferenceHolding) the
* check recurses into the underlying asset's transferability. This
* recursion is defensive; vault-of-vault-shares is rejected at vault
* creation, so in practice depth never exceeds 1.
*
* @param view Ledger state to read from.
* @param mptIssue The MPT issuance being transferred.
* @param from Sending account.
* @param to Receiving account.
* @param waive WaiveMPTCanTransfer::Yes skips the lsfMPTCanTransfer
* check. Use for recovery paths (e.g. unwinding SAV or
* Lending Protocol positions after an issuer revokes
* transferability).
* @param depth Recursion depth; bounded at kMaxAssetCheckDepth.
* @return tesSUCCESS if the transfer is allowed, tecNO_AUTH otherwise.
*/
[[nodiscard]] TER
canTransfer(
ReadView const& view,
MPTIssue const& mptIssue,
AccountID const& from,
AccountID const& to);
AccountID const& to,
WaiveMPTCanTransfer waive = WaiveMPTCanTransfer::No,
std::uint8_t depth = 0);
/** Check if Asset can be traded on DEX. return tecNO_PERMISSION
* if it doesn't and tesSUCCESS otherwise.
/** Check whether @p asset may be traded on the DEX.
*
* For IOU assets the check delegates to the existing offer/AMM freeze
* logic. For MPT assets it checks lsfMPTCanTrade on the MPTokenIssuance.
* Vault shares recurse into the underlying asset's tradability via
* sfReferenceHolding; depth is bounded at kMaxAssetCheckDepth.
*
* @param view Ledger state to read from.
* @param asset The asset to check.
* @param depth Recursion depth; bounded at kMaxAssetCheckDepth.
* @return tesSUCCESS if trading is allowed, tecNO_PERMISSION otherwise.
*/
[[nodiscard]] TER
canTrade(ReadView const& view, Asset const& asset);
canTrade(ReadView const& view, Asset const& asset, std::uint8_t depth = 0);
/** Convenience to combine canTrade/Transfer. Returns tesSUCCESS if Asset is Issue.
*/
[[nodiscard]] TER
canMPTTradeAndTransfer(
ReadView const& v,
Asset const& asset,
AccountID const& from,
AccountID const& to);
//------------------------------------------------------------------------------
//
@@ -227,17 +286,4 @@ issuerFundsToSelfIssue(ReadView const& view, MPTIssue const& issue);
void
issuerSelfDebitHookMPT(ApplyView& view, MPTIssue const& issue, std::uint64_t amount);
//------------------------------------------------------------------------------
//
// MPT DEX
//
//------------------------------------------------------------------------------
/* Return true if a transaction is allowed for the specified MPT/account. The
* function checks MPTokenIssuance and MPToken objects flags to determine if the
* transaction is allowed.
*/
TER
checkMPTTxAllowed(ReadView const& v, TxType tx, Asset const& asset, AccountID const& accountID);
} // namespace xrpl

View File

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

View File

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

View File

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

View File

@@ -93,7 +93,7 @@ isFrozen(ReadView const& view, AccountID const& account, Issue const& issue)
// Overload with depth parameter for uniformity with MPTIssue version.
// The depth parameter is ignored for IOUs since they don't have vault recursion.
[[nodiscard]] inline bool
isFrozen(ReadView const& view, AccountID const& account, Issue const& issue, int /*depth*/)
isFrozen(ReadView const& view, AccountID const& account, Issue const& issue, std::uint8_t /*depth*/)
{
return isFrozen(view, account, issue);
}
@@ -110,7 +110,7 @@ isDeepFrozen(
ReadView const& view,
AccountID const& account,
Issue const& issue,
int = 0 /*ignored*/)
std::uint8_t = 0 /*ignored*/)
{
return isDeepFrozen(view, account, issue.currency, issue.account);
}
@@ -154,7 +154,7 @@ trustCreate(
[[nodiscard]] TER
trustDelete(
ApplyView& view,
std::shared_ptr<SLE> const& sleRippleState,
SLE::ref sleRippleState,
AccountID const& uLowAccountID,
AccountID const& uHighAccountID,
beast::Journal j);
@@ -248,7 +248,7 @@ removeEmptyHolding(
[[nodiscard]] TER
deleteAMMTrustLine(
ApplyView& view,
std::shared_ptr<SLE> sleState,
SLE::pointer sleState,
std::optional<AccountID> const& ammAccountID,
beast::Journal j);
@@ -258,7 +258,7 @@ deleteAMMTrustLine(
[[nodiscard]] TER
deleteAMMMPToken(
ApplyView& view,
std::shared_ptr<SLE> sleMPT,
SLE::pointer sleMPT,
AccountID const& ammAccountID,
beast::Journal j);

View File

@@ -34,6 +34,15 @@ enum class WaiveTransferFee : bool { No = false, Yes };
/** Controls whether accountSend is allowed to overflow OutstandingAmount **/
enum class AllowMPTOverflow : bool { No = false, Yes };
/** Controls whether canTransfer enforces lsfMPTCanTransfer on MPTs.
*
* Default is No (enforce). Use Yes at call sites that must remain available
* even when an MPT issuer has cleared lsfMPTCanTransfer - for example,
* unwinding existing positions in SAV or the Lending Protocol. Has no
* effect on the IOU branch of canTransfer.
*/
enum class WaiveMPTCanTransfer : bool { No = false, Yes };
/* Check if MPToken (for MPT) or trust line (for IOU) exists:
* - StrongAuth - before checking if authorization is required
* - WeakAuth
@@ -54,16 +63,26 @@ enum class AuthType { StrongAuth, WeakAuth, Legacy };
[[nodiscard]] bool
isGlobalFrozen(ReadView const& view, Asset const& asset);
[[nodiscard]] TER
checkGlobalFrozen(ReadView const& view, Asset const& asset);
[[nodiscard]] bool
isIndividualFrozen(ReadView const& view, AccountID const& account, Asset const& asset);
[[nodiscard]] TER
checkIndividualFrozen(ReadView const& view, AccountID const& account, Asset const& asset);
/**
* isFrozen check is recursive for MPT shares in a vault, descending to
* assets in the vault, up to maxAssetCheckDepth recursion depth. This is
* purely defensive, as we currently do not allow such vaults to be created.
*/
[[nodiscard]] bool
isFrozen(ReadView const& view, AccountID const& account, Asset const& asset, int depth = 0);
isFrozen(
ReadView const& view,
AccountID const& account,
Asset const& asset,
std::uint8_t depth = 0);
[[nodiscard]] TER
checkFrozen(ReadView const& view, AccountID const& account, Issue const& issue);
@@ -85,14 +104,14 @@ isAnyFrozen(
ReadView const& view,
std::initializer_list<AccountID> const& accounts,
Asset const& asset,
int depth = 0);
std::uint8_t depth = 0);
[[nodiscard]] bool
isDeepFrozen(
ReadView const& view,
AccountID const& account,
MPTIssue const& mptIssue,
int depth = 0);
std::uint8_t depth = 0);
/**
* isFrozen check is recursive for MPT shares in a vault, descending to
@@ -100,7 +119,11 @@ isDeepFrozen(
* purely defensive, as we currently do not allow such vaults to be created.
*/
[[nodiscard]] bool
isDeepFrozen(ReadView const& view, AccountID const& account, Asset const& asset, int depth = 0);
isDeepFrozen(
ReadView const& view,
AccountID const& account,
Asset const& asset,
std::uint8_t depth = 0);
[[nodiscard]] TER
checkDeepFrozen(ReadView const& view, AccountID const& account, MPTIssue const& mptIssue);
@@ -234,7 +257,13 @@ requireAuth(
AuthType authType = AuthType::Legacy);
[[nodiscard]] TER
canTransfer(ReadView const& view, Asset const& asset, AccountID const& from, AccountID const& to);
canTransfer(
ReadView const& view,
Asset const& asset,
AccountID const& from,
AccountID const& to,
WaiveMPTCanTransfer waive = WaiveMPTCanTransfer::No,
std::uint8_t depth = 0);
//------------------------------------------------------------------------------
//

View File

@@ -1,9 +1,10 @@
#pragma once
#include <xrpl/ledger/ReadView.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/STAmount.h>
#include <xrpl/protocol/STLedgerEntry.h>
#include <memory>
#include <optional>
namespace xrpl {
@@ -19,10 +20,7 @@ namespace xrpl {
@return The number of shares, or nullopt on error.
*/
[[nodiscard]] std::optional<STAmount>
assetsToSharesDeposit(
std::shared_ptr<SLE const> const& vault,
std::shared_ptr<SLE const> const& issuance,
STAmount const& assets);
assetsToSharesDeposit(SLE::const_ref vault, SLE::const_ref issuance, STAmount const& assets);
/** From the perspective of a vault, return the number of assets to take from
depositor when they receive a fixed amount of shares. Note, since shares are
@@ -35,14 +33,19 @@ assetsToSharesDeposit(
@return The number of assets, or nullopt on error.
*/
[[nodiscard]] std::optional<STAmount>
sharesToAssetsDeposit(
std::shared_ptr<SLE const> const& vault,
std::shared_ptr<SLE const> const& issuance,
STAmount const& shares);
sharesToAssetsDeposit(SLE::const_ref vault, SLE::const_ref issuance, STAmount const& shares);
/** Controls whether to truncate shares instead of rounding. */
enum class TruncateShares : bool { No = false, Yes = true };
/** Controls whether the withdraw conversion helpers
(assetsToSharesWithdraw and sharesToAssetsWithdraw) subtract
sfLossUnrealized from sfAssetsTotal before computing the exchange rate.
The default (No) applies the standard discounted rate; Yes is used when
the redeemer is the sole remaining shareholder.
*/
enum class WaiveUnrealizedLoss : bool { No = false, Yes = true };
/** From the perspective of a vault, return the number of shares to demand from
the depositor when they ask to withdraw a fixed amount of assets. Since
shares are MPT this number is integral, and it will be rounded to nearest
@@ -52,15 +55,18 @@ enum class TruncateShares : bool { No = false, Yes = true };
@param issuance The MPTokenIssuance SLE for the vault's shares.
@param assets The amount of assets to convert.
@param truncate Whether to truncate instead of rounding.
@param waive Whether to waive the unrealized-loss discount when computing
the exchange rate.
@return The number of shares, or nullopt on error.
*/
[[nodiscard]] std::optional<STAmount>
assetsToSharesWithdraw(
std::shared_ptr<SLE const> const& vault,
std::shared_ptr<SLE const> const& issuance,
SLE::const_ref vault,
SLE::const_ref issuance,
STAmount const& assets,
TruncateShares truncate = TruncateShares::No);
TruncateShares truncate = TruncateShares::No,
WaiveUnrealizedLoss waive = WaiveUnrealizedLoss::No);
/** From the perspective of a vault, return the number of assets to give the
depositor when they redeem a fixed amount of shares. Note, since shares are
@@ -69,13 +75,28 @@ assetsToSharesWithdraw(
@param vault The vault SLE.
@param issuance The MPTokenIssuance SLE for the vault's shares.
@param shares The amount of shares to convert.
@param waive Whether to waive (i.e. not subtract) the vault's unrealized
loss when computing the exchange rate.
@return The number of assets, or nullopt on error.
*/
[[nodiscard]] std::optional<STAmount>
sharesToAssetsWithdraw(
std::shared_ptr<SLE const> const& vault,
std::shared_ptr<SLE const> const& issuance,
STAmount const& shares);
SLE::const_ref vault,
SLE::const_ref issuance,
STAmount const& shares,
WaiveUnrealizedLoss waive = WaiveUnrealizedLoss::No);
/** Returns true iff `account` holds all of the vault's outstanding shares —
i.e. is the sole remaining shareholder. Returns false if the account
holds no shares or fewer than the total outstanding.
@param view The ledger view.
@param account The candidate sole shareholder.
@param issuance The MPTokenIssuance SLE for the vault's shares; provides
both the share MPTID and the outstanding-amount total.
*/
[[nodiscard]] bool
isSoleShareholder(ReadView const& view, AccountID const& account, SLE::const_ref issuance);
} // namespace xrpl

View File

@@ -21,13 +21,13 @@ public:
bool sslVerify,
beast::Journal j,
boost::asio::ssl::context_base::method method = boost::asio::ssl::context::sslv23)
: ssl_context_{method}, j_(j), verify_{sslVerify}
: sslContext_{method}, j_(j), verify_{sslVerify}
{
boost::system::error_code ec;
if (sslVerifyFile.empty())
{
registerSSLCerts(ssl_context_, ec, j_);
registerSSLCerts(sslContext_, ec, j_);
if (ec && sslVerifyDir.empty())
{
@@ -37,12 +37,12 @@ public:
}
else
{
ssl_context_.load_verify_file(sslVerifyFile);
sslContext_.load_verify_file(sslVerifyFile);
}
if (!sslVerifyDir.empty())
{
ssl_context_.add_verify_path(sslVerifyDir, ec);
sslContext_.add_verify_path(sslVerifyDir, ec);
if (ec)
{
@@ -55,7 +55,7 @@ public:
boost::asio::ssl::context&
context()
{
return ssl_context_;
return sslContext_;
}
[[nodiscard]] bool
@@ -153,7 +153,7 @@ public:
}
private:
boost::asio::ssl::context ssl_context_;
boost::asio::ssl::context sslContext_;
beast::Journal const j_;
bool const verify_;
};

View File

@@ -83,10 +83,6 @@ public:
virtual Status
fetch(uint256 const& hash, std::shared_ptr<NodeObject>* pObject) = 0;
/** Fetch a batch synchronously. */
virtual std::pair<std::vector<std::shared_ptr<NodeObject>>, Status>
fetchBatch(std::vector<uint256> const& hashes) = 0;
/** Store a single object.
Depending on the implementation this may happen immediately
or deferred using a scheduled task.

View File

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

View File

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

View File

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

View File

@@ -140,8 +140,8 @@ private:
using issue_hasher = std::hash<xrpl::Issue>;
using mptissue_hasher = std::hash<xrpl::MPTIssue>;
issue_hasher m_issue_hasher_;
mptissue_hasher m_mptissue_hasher_;
issue_hasher mIssueHasher_;
mptissue_hasher mMptissueHasher_;
public:
explicit hash() = default;
@@ -151,11 +151,11 @@ public:
{
return asset.visit(
[&](xrpl::Issue const& issue) {
value_type const result(m_issue_hasher_(issue));
value_type const result(mIssueHasher_(issue));
return result;
},
[&](xrpl::MPTIssue const& issue) {
value_type const result(m_mptissue_hasher_(issue));
value_type const result(mMptissueHasher_(issue));
return result;
});
}
@@ -170,8 +170,8 @@ private:
using asset_hasher = std::hash<xrpl::Asset>;
using uint256_hasher = xrpl::uint256::hasher;
asset_hasher issue_hasher_;
uint256_hasher uint256_hasher_;
asset_hasher issueHasher_;
uint256_hasher uint256Hasher_;
public:
hash() = default;
@@ -182,11 +182,11 @@ public:
value_type
operator()(argument_type const& value) const
{
value_type result(issue_hasher_(value.in));
boost::hash_combine(result, issue_hasher_(value.out));
value_type result(issueHasher_(value.in));
boost::hash_combine(result, issueHasher_(value.out));
if (value.domain)
boost::hash_combine(result, uint256_hasher_(*value.domain));
boost::hash_combine(result, uint256Hasher_(*value.domain));
return result;
}

View File

@@ -172,24 +172,24 @@ struct ErrorInfo
{
// Default ctor needed to produce an empty std::array during constexpr eval.
constexpr ErrorInfo()
: code(RpcUnknown), token("unknown"), message("An unknown error code."), http_status(200)
: code(RpcUnknown), token("unknown"), message("An unknown error code."), httpStatus(200)
{
}
constexpr ErrorInfo(ErrorCodeI code, char const* token, char const* message)
: code(code), token(token), message(message), http_status(200)
: code(code), token(token), message(message), httpStatus(200)
{
}
constexpr ErrorInfo(ErrorCodeI code, char const* token, char const* message, int httpStatus)
: code(code), token(token), message(message), http_status(httpStatus)
: code(code), token(token), message(message), httpStatus(httpStatus)
{
}
ErrorCodeI code;
json::StaticString token;
json::StaticString message;
int http_status;
int httpStatus;
};
/** Returns an ErrorInfo that reflects the error code. */

View File

@@ -231,8 +231,8 @@ constexpr std::size_t kMaxPermissionedDomainCredentialsArraySize = 10;
constexpr std::size_t kMaxMpTokenMetadataLength = 1024;
/** The maximum amount of MPTokenIssuance */
constexpr std::uint64_t kMaxMpTokenAmount = 0x7FFF'FFFF'FFFF'FFFFull;
static_assert(Number::kMaxRep >= kMaxMpTokenAmount);
std::uint64_t constexpr kMaxMpTokenAmount = 0x7FFF'FFFF'FFFF'FFFFull;
static_assert(Number::kLargestMantissa >= kMaxMpTokenAmount);
/** The maximum length of Data payload */
constexpr std::size_t kMaxDataPayloadLength = 256;

View File

@@ -122,4 +122,17 @@ private:
std::optional<Rules> saved_;
};
class NumberSO;
class NumberMantissaScaleGuard;
bool
useRulesGuards(Rules const& rules);
void
createGuards(
Rules const& rules,
std::optional<NumberSO>& stNumberSO,
std::optional<CurrentTransactionRulesGuard>& rulesGuard,
std::optional<NumberMantissaScaleGuard>& mantissaScaleGuard);
} // namespace xrpl

View File

@@ -365,8 +365,8 @@ using SF_XCHAIN_BRIDGE = TypedField<STXChainBridge>;
#define UNTYPED_SFIELD(sfName, stiSuffix, fieldValue, ...) extern SField const sfName;
#define TYPED_SFIELD(sfName, stiSuffix, fieldValue, ...) extern SF_##stiSuffix const sfName;
extern SField const kSfInvalid;
extern SField const kSfGeneric;
extern SField const sfInvalid; // NOLINT(readability-identifier-naming)
extern SField const sfGeneric; // NOLINT(readability-identifier-naming)
#include <xrpl/protocol/detail/sfields.macro>

View File

@@ -3,11 +3,13 @@
#include <xrpl/basics/CountedObject.h>
#include <xrpl/basics/LocalValue.h>
#include <xrpl/basics/Number.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/protocol/Asset.h>
#include <xrpl/protocol/IOUAmount.h>
#include <xrpl/protocol/Issue.h>
#include <xrpl/protocol/MPTAmount.h>
#include <xrpl/protocol/Protocol.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/STBase.h>
#include <xrpl/protocol/Serializer.h>
@@ -184,6 +186,23 @@ public:
[[nodiscard]] STAmount const&
value() const noexcept;
/**
* Checks if this amount evaluates to zero when constrained to a specific
* accounting scale.
* For XRP and MPT `roundToScale` is a no-op, returns true only when the amount itself is zero.
* The `scale` argument is ignored in that case.
* For IOU, the amount is rounded to the given scale using Number::RoundingMode::ToNearest mode
* and the result is checked for zero; if `scale <= exponent()`, `roundToScale` short-circuits
* and returns the value unchanged, so this returns false for any non-zero amount.
*
* @param scale The target accounting scale to evaluate against.
* @return `true` if this amount rounds to zero at the given scale, `false` otherwise.
*
* @see roundToScale
*/
[[nodiscard]] bool
isZeroAtScale(int scale) const;
//--------------------------------------------------------------------------
//
// Operators
@@ -540,7 +559,9 @@ STAmount::fromNumber(A const& a, Number const& number)
return STAmount{asset, intValue, 0, negative};
}
auto const [mantissa, exponent] = working.normalizeToRange(kMinValue, kMaxValue);
XRPL_ASSERT_PARTS(
working.signum() >= 0, "xrpl::STAmount::fromNumber", "non-negative Number to normalize");
auto const [mantissa, exponent] = working.normalizeToRange<kMinValue, kMaxValue>();
return STAmount{asset, mantissa, exponent, negative};
}
@@ -575,12 +596,25 @@ STAmount::value() const noexcept
return *this;
}
inline bool
[[nodiscard]] inline bool
isLegalNet(STAmount const& value)
{
return !value.native() || (value.mantissa() <= STAmount::kMaxNativeN);
}
[[nodiscard]] inline bool
isLegalMPT(STAmount const& value)
{
return !value.holds<MPTIssue>() ||
(!value.negative() && value.exponent() == 0 && value.mantissa() <= kMaxMpTokenAmount);
}
/* Check recursively if an object has invalid MPTAmount or XRPAmount in STAmount field.
* Calls isLegalNet() and isLegalMPT().
*/
[[nodiscard]] bool
hasInvalidAmount(STBase const& field, beast::Journal j);
//------------------------------------------------------------------------------
//
// Operators

View File

@@ -24,7 +24,7 @@ public:
STBlob(SField const& f, void const* data, std::size_t size);
STBlob(SField const& f, Buffer&& b);
STBlob(SField const& n);
STBlob(SerialIter&, SField const& name = kSfGeneric);
STBlob(SerialIter&, SField const& name = sfGeneric);
[[nodiscard]] std::size_t
size() const;

View File

@@ -21,8 +21,8 @@ class STPathElement final : public CountedObject<STPathElement>
PathAsset assetID_;
AccountID issuerID_;
bool is_offer_;
std::size_t hash_value_;
bool isOffer_;
std::size_t hashValue_;
public:
// Bitwise values (typeCurrency | typeMPT)
@@ -235,9 +235,9 @@ private:
// ------------ STPathElement ------------
inline STPathElement::STPathElement() : type_(TypeNone), is_offer_(true)
inline STPathElement::STPathElement() : type_(TypeNone), isOffer_(true)
{
hash_value_ = getHash(*this);
hashValue_ = getHash(*this);
}
inline STPathElement::STPathElement(
@@ -248,11 +248,11 @@ inline STPathElement::STPathElement(
{
if (!account)
{
is_offer_ = true;
isOffer_ = true;
}
else
{
is_offer_ = false;
isOffer_ = false;
accountID_ = *account;
type_ |= TypeAccount;
XRPL_ASSERT(
@@ -272,7 +272,7 @@ inline STPathElement::STPathElement(
XRPL_ASSERT(issuerID_ != noAccount(), "xrpl::STPathElement::STPathElement : issuer is set");
}
hash_value_ = getHash(*this);
hashValue_ = getHash(*this);
}
inline STPathElement::STPathElement(
@@ -284,9 +284,9 @@ inline STPathElement::STPathElement(
, accountID_(account)
, assetID_(asset)
, issuerID_(issuer)
, is_offer_(isXRP(accountID_))
, isOffer_(isXRP(accountID_))
{
if (!is_offer_)
if (!isOffer_)
type_ |= TypeAccount;
if (forceAsset || !isXRP(assetID_))
@@ -295,7 +295,7 @@ inline STPathElement::STPathElement(
if (!isXRP(issuer))
type_ |= TypeIssuer;
hash_value_ = getHash(*this);
hashValue_ = getHash(*this);
}
inline STPathElement::STPathElement(
@@ -307,12 +307,12 @@ inline STPathElement::STPathElement(
, accountID_(account)
, assetID_(asset)
, issuerID_(issuer)
, is_offer_(isXRP(accountID_))
, isOffer_(isXRP(accountID_))
{
assetID_.visit(
[&](Currency const&) { type_ = type_ & (~Type::TypeMpt); },
[&](MPTID const&) { type_ = type_ & (~Type::TypeCurrency); });
hash_value_ = getHash(*this);
hashValue_ = getHash(*this);
}
inline auto
@@ -324,7 +324,7 @@ STPathElement::getNodeType() const
inline bool
STPathElement::isOffer() const
{
return is_offer_;
return isOffer_;
}
inline bool
@@ -404,7 +404,7 @@ STPathElement::getIssuerID() const
inline bool
STPathElement::operator==(STPathElement const& t) const
{
return (type_ & TypeAccount) == (t.type_ & TypeAccount) && hash_value_ == t.hash_value_ &&
return (type_ & TypeAccount) == (t.type_ & TypeAccount) && hashValue_ == t.hashValue_ &&
accountID_ == t.accountID_ && assetID_ == t.assetID_ && issuerID_ == t.issuerID_;
}

View File

@@ -27,7 +27,7 @@ enum class TxnSql : char {
class STTx final : public STObject, public CountedObject<STTx>
{
uint256 tid_;
TxType tx_type_;
TxType txType_;
public:
static constexpr std::size_t kMinMultiSigners = 1;
@@ -187,7 +187,7 @@ inline STTx::STTx(SerialIter&& sit) // NOLINT(cppcoreguidelines-rvalue-referenc
inline TxType
STTx::getTxnType() const
{
return tx_type_;
return txType_;
}
inline Blob

View File

@@ -23,7 +23,7 @@ systemName()
/** Number of drops in the genesis account. */
constexpr XRPAmount kInitialXrp{100'000'000'000 * kDropsPerXrp};
static_assert(kInitialXrp.drops() == 100'000'000'000'000'000);
static_assert(Number::kMaxRep >= kInitialXrp.drops());
static_assert(Number::kLargestMantissa >= kInitialXrp.drops());
/** Returns true if the amount does not exceed the initial XRP in existence. */
inline bool

View File

@@ -15,8 +15,7 @@
// Add new amendments to the top of this list.
// Keep it sorted in reverse chronological order.
XRPL_FIX (TokenEscrowV1_1, Supported::No, VoteBehavior::DefaultNo)
XRPL_FIX (Cleanup3_2_0, Supported::No, VoteBehavior::DefaultNo)
XRPL_FIX (Cleanup3_2_0, Supported::Yes, VoteBehavior::DefaultNo)
XRPL_FEATURE(MPTokensV2, Supported::No, VoteBehavior::DefaultNo)
XRPL_FIX (Cleanup3_1_3, Supported::Yes, VoteBehavior::DefaultYes)
XRPL_FIX (BatchInnerSigs, Supported::No, VoteBehavior::DefaultNo)

View File

@@ -400,6 +400,7 @@ LEDGER_ENTRY(ltMPTOKEN_ISSUANCE, 0x007e, MPTokenIssuance, mpt_issuance, ({
{sfPreviousTxnLgrSeq, SoeRequired},
{sfDomainID, SoeOptional},
{sfMutableFlags, SoeDefault},
{sfReferenceHolding, SoeOptional},
}))
/** A ledger object which tracks MPToken
@@ -591,7 +592,7 @@ LEDGER_ENTRY(ltLOAN, 0x0089, Loan, loan, ({
// LoanBroker.ManagementFeeRate
// The unrounded true total fee still owed to the broker.
//
// Note the the "True" values may differ significantly from the tracked
// Note the "True" values may differ significantly from the tracked
// rounded values.
{sfPaymentRemaining, SoeDefault},
{sfPeriodicPayment, SoeRequired},

View File

@@ -205,6 +205,7 @@ TYPED_SFIELD(sfParentBatchID, UINT256, 36)
TYPED_SFIELD(sfLoanBrokerID, UINT256, 37,
SField::kSmdPseudoAccount | SField::kSmdDefault)
TYPED_SFIELD(sfLoanID, UINT256, 38)
TYPED_SFIELD(sfReferenceHolding, UINT256, 39)
// number (common)
TYPED_SFIELD(sfNumber, NUMBER, 1)

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