Compare commits

..

138 Commits

Author SHA1 Message Date
Vito
f42a5aa698 Merge branch 'tapanito/sav-fixed-precision-loanbroker' into tapanito/sav-fixed-precision-loanset 2026-10-09 17:48:10 +02:00
Vito
bdf89b1b8e Merge branch 'tapanito/sav-fixed-precision-vault-transactors' into tapanito/sav-fixed-precision-loanbroker 2026-10-09 17:48:07 +02:00
Vito
5a91f9b9ea test: Include Feature.h in LoanPermissionedDomain test 2026-10-09 17:48:02 +02:00
Vito
d61a683241 Merge branch 'tapanito/sav-fixed-precision-loanbroker' into tapanito/sav-fixed-precision-loanset 2026-10-09 17:21:54 +02:00
Vito
72cfefc781 Merge branch 'tapanito/sav-fixed-precision-vault-transactors' into tapanito/sav-fixed-precision-loanbroker 2026-10-09 17:14:59 +02:00
Vito
3b6f78630c test: Enable LendingProtocolV1_2 for Loan Broker domain cases
DomainID and private Loan Brokers require featureLendingProtocolV1_2,
which this stack leaves out of the default test amendments until the
LoanManage PR. Enable it explicitly in the permissioned-domain cases of
LoanPermissionedDomain, LoanBroker, InvariantsPseudoAccount and
InvariantsMisc.
2026-10-09 17:12:36 +02:00
Vito
d1e597962f Merge branch 'tapanito/sav-fixed-precision-loanbroker' into tapanito/sav-fixed-precision-loanset 2026-10-09 16:39:15 +02:00
Vito
62da67d9fd Merge branch 'tapanito/sav-fixed-precision-vault-transactors' into tapanito/sav-fixed-precision-loanbroker 2026-10-09 16:39:15 +02:00
Vito
e4b0c5406e Merge branch 'tapanito/sav-fixed-precision-vault-rounding' into tapanito/sav-fixed-precision-vault-transactors 2026-10-09 16:39:15 +02:00
Vito
64092e8b24 Merge remote-tracking branch 'origin/develop' into tapanito/sav-fixed-precision-vault-rounding 2026-10-09 16:39:04 +02:00
Shawn Xie
3857ce21cd fix: Change mpt subscription msg type back to transaction (#8539) 2026-10-09 13:33:13 +00:00
Vito
62df379d07 Merge branch 'tapanito/sav-fixed-precision-loanbroker' into tapanito/sav-fixed-precision-loanset 2026-10-09 13:38:11 +02:00
Vito
d92c817942 Merge branch 'tapanito/sav-fixed-precision-vault-transactors' into tapanito/sav-fixed-precision-loanbroker 2026-10-09 13:38:07 +02:00
Vito
4c0081a8ef Merge branch 'tapanito/sav-fixed-precision-vault-rounding' into tapanito/sav-fixed-precision-vault-transactors 2026-10-09 13:38:04 +02:00
Vito
c25312570d docs: Fix adjustVaultBalances contract for negative YieldUnrealized
A negative YieldUnrealized is rejected with tefBAD_LEDGER, not clamped.
2026-10-09 13:37:58 +02:00
Vito
10fcaa9f87 Merge branch 'tapanito/sav-fixed-precision-loanbroker' into tapanito/sav-fixed-precision-loanset 2026-10-09 12:51:00 +02:00
Vito
ef203f6010 Merge branch 'tapanito/sav-fixed-precision-vault-transactors' into tapanito/sav-fixed-precision-loanbroker 2026-10-09 12:47:51 +02:00
Vito
1c6f3a7eef test: Skip FixedPrecision lending cases in LendingBatch until LoanManage
With featureLendingProtocolV1_1 and featureLendingProtocolV1_2 enabled,
new Vaults are FixedPrecision, whose lending transactions are enabled
later in the stack. Run only the Vault-only cases under that feature
set; the LoanManage PR restores the rest.
2026-10-09 12:47:37 +02:00
Ayaz Salikhov
aa490df46b chore: Update clang-tidy image to v23 (#8536) 2026-10-09 10:19:07 +00:00
Jingchen
88c1f1e7ac feat: Integrate Permissioned Domain & Credential Checks for Lending Protocol (#6517)
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
Co-authored-by: Vito <5780819+Tapanito@users.noreply.github.com>
Co-authored-by: Ed Hennis <ed@ripple.com>
2026-10-09 10:18:31 +00:00
Vito Tumas
919565be21 Merge branch 'tapanito/sav-fixed-precision-loanbroker' into tapanito/sav-fixed-precision-loanset 2026-10-08 16:38:01 +02:00
Vito Tumas
d6de322a86 Merge branch 'tapanito/sav-fixed-precision-vault-transactors' into tapanito/sav-fixed-precision-loanbroker 2026-10-08 16:37:47 +02:00
Vito Tumas
313251bcb6 Merge branch 'tapanito/sav-fixed-precision-vault-rounding' into tapanito/sav-fixed-precision-vault-transactors 2026-10-08 16:35:49 +02:00
Vito
e7067d0cd6 fix: Restore NOLINT placement in VaultHelpers test
The previous clang-tidy pass split the initializer so the NOLINT no
longer covered the optional access, failing CI clang-tidy.
2026-10-08 15:25:20 +02:00
Vito Tumas
f9619235ec Merge branch 'develop' into tapanito/sav-fixed-precision-vault-rounding 2026-10-08 15:23:51 +02:00
Ayaz Salikhov
ede8af8191 refactor: Group binaries in subdirectories (#8535)
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-10-08 12:34:06 +00:00
Vito
e56eedd808 chore: Apply clang-tidy fixes to Vault grid and balance tests 2026-10-08 14:10:28 +02:00
Vito
87e1568016 Merge remote-tracking branch 'origin/develop' into tapanito/sav-fixed-precision-vault-rounding 2026-10-08 13:55:25 +02:00
Alex Kremer
3c24b605a1 chore: Split multiple-in-one into individual tests (#8025) 2026-10-08 09:57:38 +00:00
Alex Kremer
d343b542f1 refactor: Migrate handlers to rpc-spec (B) (#8484) 2026-10-07 13:46:37 +00:00
Ayaz Salikhov
7acd719bf7 build: Use images with Clang 23 except for clang-tidy (#8530) 2026-10-07 13:08:20 +00:00
Ayaz Salikhov
b4564d5301 chore: Update pre-commit hooks and image (#8528) 2026-10-07 10:59:37 +00:00
Vito
e624889f5d Merge remote-tracking branch 'origin/develop' into tapanito/sav-fixed-precision-vault-rounding 2026-10-07 11:02:28 +02:00
Vito
928ea60765 chore: Clarify LoanBroker cover deposit and clawback diagnostics
Fix the CoverDeposit comment on why the zero check covers
FixedPrecision, and log the error code when the cover clawback amount
cannot be determined, since it may now be tecPRECISION_LOSS.
2026-10-07 11:00:18 +02:00
Vito
00d154c62f test: Cover FixedPrecision Vault invariants without lending
Move the lending-free FixedPrecision rows of InvariantsVault into this
PR: the VaultCreate AssetsDeployed and YieldUnrealized rows, the XRP
AssetsDeployed rows, the YieldUnrealized rows and the AssetsAvailable
off-by-one row. They enable featureLendingProtocolV1_2 explicitly, since
testableAmendments() leaves it off until the LoanManage PR.
2026-10-07 11:00:16 +02:00
Vito
e1f18dea4a fix: Floor Vault credits in the requested rounding mode
Compute reference + raw under the caller's rounding mode in
creditToPosteriorScale, so the ambient mode cannot round the sum up
before the floor and credit more than raw.

Reject a negative YieldUnrealized with tefBAD_LEDGER like the other
Vault balances instead of clamping it to zero.

Add grid tests for the credit repro and isOnVaultBaseGrid, and fix the
amendment named for the 19-digit Number range.
2026-10-07 11:00:04 +02:00
Shawn Xie
60195e6d37 fix: Fix MPT partial payment overflow (#8302) 2026-10-06 23:16:13 +00:00
Ayaz Salikhov
3d526d456e build: Use LLVM 23 (#8522) 2026-10-06 21:19:57 +00:00
Denis Angell
f05c9f7913 refactor: Extract escrow lock helpers and paychan test helpers (#7882)
Co-authored-by: Mayukha Vadari <mvadari@ripple.com>
2026-10-06 19:58:52 +00:00
Harshit Gupta
c2a4bc3aa1 fix: Validate vetoed parameter type in feature RPC (#7583)
Co-authored-by: Mayukha Vadari <mvadari@ripple.com>
2026-10-06 19:44:56 +00:00
Mayukha Vadari
718185e3b2 refactor: Use CheckEntry everywhere (#8349) 2026-10-06 19:26:35 +00:00
Ayaz Salikhov
1d7783bb86 build: Make conan retry with Conan Center's source backups (#8524) 2026-10-06 19:23:38 +00:00
Mayukha Vadari
9fd2c552f5 refactor: Use AmendmentsEntry everywhere (#8368) 2026-10-06 17:59:44 +00:00
Ayaz Salikhov
70b8fd301b chore: Update docker images; link Conan-built tools with a static runtime (#8520) 2026-10-06 16:47:35 +00:00
Mayukha Vadari
e6564f553d refactor: Use NegativeUNLEntry everywhere (#8365) 2026-10-06 14:23:24 +00:00
Ayaz Salikhov
ed96e60ce3 build: Make clang-tools custom in Nix, to match what's being built (#8521) 2026-10-06 13:59:12 +00:00
Alex Kremer
2ebd745a1b refactor: Migrate handlers to rpc-spec (A) (#8345) 2026-10-06 13:19:20 +00:00
Mayukha Vadari
cfcbe45b60 test: Declare, not define, entry instantiations in SLEBase test (#8357) 2026-10-06 12:12:22 +00:00
yinyiqian1
9cbf78ba99 test: Add more tests for granular permissions (#8459)
Co-authored-by: Bart <bthomee@users.noreply.github.com>
2026-10-05 23:18:58 +00:00
Timur Yalymov
b8d8738f81 fix: Enforce that MPT issuance flags are never cleared (#8152) 2026-10-05 23:17:36 +00:00
Timur Yalymov
63c97e719f feat: Allow lending transactions in Batch (#8244)
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Vito Tumas <5780819+Tapanito@users.noreply.github.com>
2026-10-05 23:17:26 +00:00
Mayukha Vadari
3ac26f23c7 feat: Add full support for all objects in ledger_entry (#6319)
Co-authored-by: Timur Yalymov <36795566+tyalymov@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Vito Tumas <5780819+Tapanito@users.noreply.github.com>
Co-authored-by: Ayaz Salikhov <mathbunnyru@users.noreply.github.com>
2026-10-05 23:17:14 +00:00
Bart
ff9410bc56 build: Define XRPL_ASAN, XRPL_TSAN, and XRPL_UBSAN compile definitions (#8483)
Co-authored-by: Bart <11445373+bthomee@users.noreply.github.com>
2026-10-05 23:15:08 +00:00
Vito
21d778849a Merge branch 'tapanito/sav-fixed-precision-vault-transactors' into tapanito/sav-fixed-precision-loanbroker 2026-10-05 23:51:09 +02:00
Vito
e5e1fab26c refactor: Share Vault cash and dust-debit handling across transactors
Add adjustVaultCash, which applies a signed cash movement to a Vault of any version, and checkDebitNotDust, which rejects a dust outflow and maps Number overflow to tecPATH_DRY. VaultDeposit, VaultWithdraw and VaultClawback use them instead of repeating the version branch and the dust check. debitIsNonZeroDust now picks its reference balance from the Vault itself, replacing vaultDebitDustReference. No behavior change.
2026-10-05 23:50:52 +02:00
Mayukha Vadari
1798262d7a refactor: Use LedgerHashesEntry everywhere (#8369) 2026-10-05 18:15:02 +00:00
Mayukha Vadari
cd633b9ac9 refactor: Use EscrowEntry everywhere (#8354) 2026-10-05 17:51:18 +00:00
Ayaz Salikhov
5c5f7d315a chore: Update nix flake file (#8479) 2026-10-05 16:58:41 +00:00
Mayukha Vadari
0f7493ce50 refactor: Use FeeSettingsEntry everywhere (#8370) 2026-10-05 16:56:41 +00:00
Harshit Gupta
40f61f828a fix: Add string type validation for channel_id and signature (#7582) 2026-10-05 16:55:14 +00:00
Mayukha Vadari
108277f4b7 test: Migrate three beast suites from beast::unit_test to gtest (#7993) 2026-10-05 15:28:05 +00:00
Jingchen
4bff29e39b Merge branch 'tapanito/sav-fixed-precision-loanbroker' into tapanito/sav-fixed-precision-loanset 2026-10-05 09:58:31 +01:00
Jingchen
29ff8282ba Merge branch 'tapanito/sav-fixed-precision-vault-transactors' into tapanito/sav-fixed-precision-loanbroker 2026-10-05 09:58:18 +01:00
Jingchen
af321df56e Merge branch 'tapanito/sav-fixed-precision-vault-rounding' into tapanito/sav-fixed-precision-vault-transactors 2026-10-05 09:58:05 +01:00
Jingchen
d26e61b516 Merge branch 'develop' into tapanito/sav-fixed-precision-vault-rounding 2026-10-05 09:57:48 +01:00
Vito
0271003597 test: Drop the FixedPrecision LoanSet refusal test
LoanSet now supports FixedPrecision Vaults, so the temporary tecNO_PERMISSION gate and its test go away.
2026-10-02 17:05:22 +02:00
Vito
1dadfd7405 Merge branch 'tapanito/sav-fixed-precision-loanbroker' into tapanito/sav-fixed-precision-loanset 2026-10-02 17:02:43 +02:00
Vito
5cd5241dee Merge branch 'tapanito/sav-fixed-precision-vault-transactors' into tapanito/sav-fixed-precision-loanbroker 2026-10-02 17:02:36 +02:00
Vito
0b8336bde8 fix: Check a cover withdrawal's destination against the sent amount
On FixedPrecision Vaults LoanBrokerCoverWithdraw sends the amount rounded at the broker's posterior grid, but the third-party destination check used sfAmount. A request that rounds down could be refused even though the destination has room for the amount actually sent. Check roundedAmount, as VaultWithdraw does.
2026-10-02 17:02:29 +02:00
Vito
9f7993f7d0 Merge remote-tracking branch 'origin/tapanito/sav-fixed-precision-vault-rounding' into tapanito/sav-fixed-precision-vault-transactors 2026-10-02 17:01:48 +02:00
Vito
3a0b7b69da test: Cover the FixedPrecision LoanSet refusal
A valid LoanSet against a FixedPrecision Vault returns tecNO_PERMISSION until LoanSet supports these Vaults.
2026-10-02 17:01:46 +02:00
Vito
052bfc7310 refactor: improve tests 2026-10-02 12:24:42 +02:00
Vito Tumas
565f3e2787 Merge branch 'develop' into tapanito/sav-fixed-precision-vault-rounding 2026-10-02 12:20:40 +02:00
Vito
2930bab1c3 refactor: Reject origination on a coarsened Vault in LoanSet preclaim
Move the coarsened FixedPrecision Vault check from doApply to preclaim, read
the Vault version once, and move the DebtTotal rounding comment into
adjustBrokerDebtTotal.
2026-10-02 12:01:51 +02:00
Vito
21031eb05a refactor: Pass the LoanBroker to adjustBrokerDebtTotal in LoanSet 2026-10-02 11:34:58 +02:00
Vito
d8b3f54713 Merge branch 'tapanito/sav-fixed-precision-loanbroker' into tapanito/sav-fixed-precision-loanset 2026-10-02 11:34:49 +02:00
Vito
69e5a8b92e refactor: Pass the LoanBroker to adjustBrokerDebtTotal
Take the LoanBroker SLE instead of a DebtTotal proxy, and pass the proxy only
to adjustImpreciseNumber. Move the definition out of the header.
2026-10-02 11:34:41 +02:00
Vito
ef780fe257 Merge branch 'tapanito/sav-fixed-precision-loanbroker' into tapanito/sav-fixed-precision-loanset 2026-10-02 11:05:07 +02:00
Vito
bf906c52e8 Merge branch 'tapanito/sav-fixed-precision-vault-transactors' into tapanito/sav-fixed-precision-loanbroker 2026-10-02 11:05:07 +02:00
Vito
2fa2239cb2 fix: Check AssetsMaximum grid on every Vault under LendingProtocolV1_2
FixedPrecision now requires LendingProtocolV1_1, closed-ended creation stays
V1_1-only, and fixCleanup3_2_0 is no longer checked. VaultSet checks the cap
through the new checkAssetsMaximum helper, and VaultCreate checks it at the end
of preclaim. Add a test that an existing Vault with an off-grid cap can replace
it after V1_2.
2026-10-02 11:05:00 +02:00
Vito
5b273138f5 Merge tapanito/sav-fixed-precision-loanbroker into tapanito/sav-fixed-precision-loanset 2026-10-02 10:13:57 +02:00
Vito
f6290acf6d Merge tapanito/sav-fixed-precision-vault-transactors into tapanito/sav-fixed-precision-loanbroker 2026-10-02 10:13:56 +02:00
Vito
9b3512707b fix: Address review comments on the FixedPrecision Vault transactors
- Check for burning every share while AssetsDeployed is non-zero inside
  VaultClawback::assetsToClawback, after the clamp to AssetsAvailable.
- Gate VaultSet's AssetsMaximum representability check on
  featureLendingProtocolV1_2, so existing Vaults get the same check.
- Restore the LCOV exclusion on the VaultWithdraw clamp error return.
- Add a test for an unrepresentable AssetsMaximum on an existing Vault after
  V1_2 is enabled, and fix two comments.
2026-10-02 10:13:54 +02:00
Vito
8968c892bf test: Drop the fixCleanup3_1_3-disabled clawback run
fixCleanup3_1_3 is enabled on the network, so a FixedPrecision Vault never runs without it.
2026-10-02 10:10:01 +02:00
Vito
a335d6d9fc fix: Address review comments on FixedPrecision LoanSet
Reword the DebtTotal comment in LoanSet, and run the full-clawback test also without fixCleanup3_1_3.
2026-10-02 09:28:27 +02:00
Vito
2fbe48d2a6 Merge tapanito/sav-fixed-precision-vault-transactors into tapanito/sav-fixed-precision-loanbroker 2026-10-02 09:27:59 +02:00
Vito
49d3763295 Merge tapanito/sav-fixed-precision-vault-rounding into tapanito/sav-fixed-precision-vault-transactors 2026-10-02 09:27:59 +02:00
Vito
f307a9bccc Merge tapanito/sav-fixed-precision-loanbroker into tapanito/sav-fixed-precision-loanset 2026-10-02 09:27:59 +02:00
Vito
1f0915bd46 refactor: Assert the VaultVersion declaration order relied on by comparisons 2026-10-02 09:27:57 +02:00
Vito
e5fb5afa5e Merge tapanito/sav-fixed-precision-loanbroker into tapanito/sav-fixed-precision-loanset 2026-10-02 09:27:29 +02:00
Vito
af9a2efc18 fix: Address review comments on the FixedPrecision broker cover helpers
- Take the exact raw amount as a Number in creditToPosteriorBrokerCoverScale
  and getPosteriorBrokerCoverScale.
- checkOptionalBrokerCoverInflow checks the effective credit it is given
  instead of rounding it again as a standalone delta.
2026-10-02 09:27:27 +02:00
Vito
9fc908aa34 Merge tapanito/sav-fixed-precision-vault-transactors into tapanito/sav-fixed-precision-loanbroker 2026-10-02 09:26:34 +02:00
Vito
8098f6de1d fix: Require zero YieldUnrealized on FixedPrecision Vault creation
ValidVault now checks YieldUnrealized as well as AssetsDeployed when a
FixedPrecision Vault is created. Also correct the VaultClawback_test comment
about which Vault the pre-fixCleanup3_1_3 case needs.
2026-10-02 09:26:32 +02:00
Vito
1c8322853e Merge tapanito/sav-fixed-precision-vault-rounding into tapanito/sav-fixed-precision-vault-transactors 2026-10-02 09:25:47 +02:00
Vito
a5a112f646 fix: Address review comments on the FixedPrecision Vault helpers
- Keep the ToNearest guard through scale() in posteriorAssetScale, as the
  Legacy/CashBasis clamp did.
- Take the exact raw amount as a Number in the credit helpers, so the sum is
  floored before any 16-digit rounding of the raw amount.
- Reject a negative amount in checkOptionalVaultInflow at runtime too.
- Use one namespace detail block in VaultHelpers.h and VaultHelpers.cpp.
- Seed AssetsAvailable in the FixedPrecision VaultHelpers_test rows.
- Add gtests for creditToPosteriorAvailableScale.
2026-10-02 09:25:32 +02:00
Vito
0a78cfb4d3 test: Drop the unused TxFlags.h include from LoanSetFixedPrecision_test 2026-10-01 18:17:51 +02:00
Vito
1b45e6bf76 test: Move the coarsened-vault origination test to the LoanPay suite
It coarsens the Vault with a late LoanPay, which needs FixedPrecision LoanPay.
2026-10-01 18:00:22 +02:00
Vito
7005ca4815 Merge tapanito/sav-fixed-precision-loanbroker into tapanito/sav-fixed-precision-loanset (history only) 2026-10-01 17:47:28 +02:00
Vito
9083442c02 Merge tapanito/sav-fixed-precision-loanbroker into tapanito/sav-fixed-precision-loanset 2026-10-01 17:47:09 +02:00
Vito
425fec2f51 Merge tapanito/sav-fixed-precision-vault-transactors into tapanito/sav-fixed-precision-loanbroker 2026-10-01 17:47:08 +02:00
Vito
cd396fce37 Merge tapanito/sav-fixed-precision-loanbroker into tapanito/sav-fixed-precision-loanbroker 2026-10-01 17:46:55 +02:00
Vito
6078cae6ad test: Build the Env features bitset from two features, not their bitwise OR
FeatureBitset{featureDynamicMPT | featureTokenEscrow} ORs the two IDs into an unregistered one. The test only reaches this line when testableAmendments() has an unsupported feature.
2026-10-01 17:46:53 +02:00
Vito
6fd5ece5c3 Merge tapanito/sav-fixed-precision-loanbroker into tapanito/sav-fixed-precision-loanset 2026-10-01 17:07:44 +02:00
Vito
18e66bb98d test: Use snake_case gtest case names in LoanBrokerCoverTests 2026-10-01 17:07:42 +02:00
Vito
ed5ec1e554 Merge tapanito/sav-fixed-precision-vault-rounding into tapanito/sav-fixed-precision-vault-transactors 2026-10-01 17:07:42 +02:00
Vito
3728d76c68 Merge tapanito/sav-fixed-precision-vault-transactors into tapanito/sav-fixed-precision-loanbroker 2026-10-01 17:07:42 +02:00
Vito
301675ac13 test: Use snake_case gtest case names in VaultGridTests 2026-10-01 17:07:40 +02:00
Vito
7a0229c9f5 Merge tapanito/sav-fixed-precision-loanbroker into tapanito/sav-fixed-precision-loanset 2026-10-01 17:01:38 +02:00
Vito
c29cbaec9d style: Fix clang-tidy findings in FixedPrecision headers 2026-10-01 17:01:37 +02:00
Vito
acdb754728 Merge tapanito/sav-fixed-precision-vault-transactors into tapanito/sav-fixed-precision-loanbroker 2026-10-01 17:01:35 +02:00
Vito
ade43a4b9e style: Fix clang-tidy findings in FixedPrecision headers 2026-10-01 17:01:33 +02:00
Vito
47294b5ae8 style: Fix clang-tidy findings in FixedPrecision headers 2026-10-01 17:01:30 +02:00
Vito
1ebe5078fa Merge tapanito/sav-fixed-precision-loanbroker into tapanito/sav-fixed-precision-loanset
Brings in develop. Switch this PR's code to the SLE::ConstRef / SLE::Ref aliases and gtest naming introduced on develop.
2026-10-01 16:59:54 +02:00
Vito
f0eacbad31 Merge tapanito/sav-fixed-precision-vault-transactors into tapanito/sav-fixed-precision-loanbroker
Brings in develop. Switch this PR's code to the SLE::ConstRef / SLE::Ref aliases and gtest naming introduced on develop.
2026-10-01 16:59:52 +02:00
Vito
7450b3d299 Merge tapanito/sav-fixed-precision-vault-rounding into tapanito/sav-fixed-precision-vault-transactors
Brings in develop. Switch this PR's code to the SLE::ConstRef / SLE::Ref aliases and gtest naming introduced on develop.
2026-10-01 16:59:15 +02:00
Vito
4a5257443c Merge develop into tapanito/sav-fixed-precision-vault-rounding
Resolve the VaultHelpers.cpp conflict and switch the FixedPrecision code to the SLE::ConstRef / SLE::Ref aliases and gtest naming introduced on develop.
2026-10-01 16:58:37 +02:00
Vito
6d54abf904 Merge tapanito/sav-fixed-precision-loanbroker into tapanito/sav-fixed-precision-loanset (stack history only, tree unchanged) 2026-10-01 16:56:11 +02:00
Vito
c32202999a Merge tapanito/sav-fixed-precision-vault-transactors into tapanito/sav-fixed-precision-loanbroker (stack history only, tree unchanged) 2026-10-01 16:56:10 +02:00
Vito
7a38dd8869 Merge tapanito/sav-fixed-precision-vault-rounding into tapanito/sav-fixed-precision-vault-transactors (stack history only, tree unchanged) 2026-10-01 16:56:10 +02:00
Vito
6a5b12bc2d refactor: Reuse fix340Enabled in VaultClawback::assetsToClawback 2026-10-01 16:50:52 +02:00
Vito
92726e1b10 refactor: Reuse fix340Enabled in VaultClawback::assetsToClawback 2026-10-01 16:50:52 +02:00
Vito
5ec8f37bb7 refactor: Reuse fix340Enabled in VaultClawback::assetsToClawback 2026-10-01 16:50:50 +02:00
Vito
a60b5596fe docs: Clarify the FixedPrecision live exponent in getVaultScale 2026-10-01 16:49:58 +02:00
Vito
a58a692383 docs: Clarify the FixedPrecision live exponent in getVaultScale 2026-10-01 16:49:58 +02:00
Vito
533dfdddbd docs: Clarify the FixedPrecision live exponent in getVaultScale 2026-10-01 16:49:58 +02:00
Vito
a5bf7c08fd docs: Clarify the FixedPrecision live exponent in getVaultScale 2026-10-01 16:49:56 +02:00
Vito
25cb86143a feat: Use FixedPrecision accounting in Vault transactors
VaultCreate creates FixedPrecision Vaults under featureLendingProtocolV1_2.
Vault deposit, withdraw, clawback, set and delete use adjustVaultBalances
and the AssetsAvailable grid, and ValidVault checks the FixedPrecision
balance identities.

Until the lending PRs land, LoanSet, LoanPay and LoanManage return
tecNO_PERMISSION for FixedPrecision Vaults, and jtx::testableAmendments()
excludes featureLendingProtocolV1_2.
2026-10-01 16:43:13 +02:00
Vito
b32aca2e59 feat: Book FixedPrecision LoanSet through AssetsDeployed
LoanSet on a FixedPrecision Vault moves principal from AssetsAvailable to
AssetsDeployed and books scheduled interest in YieldUnrealized. Origination
is refused on a coarsened Vault or outside the Open zone. Removes the
temporary LoanSet guard.
2026-10-01 16:41:54 +02:00
Vito
01ab57caee feat: Round LoanBroker cover on the FixedPrecision grid
LoanBroker cover deposit, withdraw and clawback round on the posterior
CoverAvailable grid for brokers on FixedPrecision Vaults, and LoanBrokerSet
rejects a DebtMaximum that is not on the Vault grid.
2026-10-01 16:41:48 +02:00
Vito
bd31dbcc48 feat: Add FixedPrecision Vault grid and balance helpers
Add VaultVersion::FixedPrecision, the YieldUnrealized and AssetsDeployed
Vault fields, and the VaultHelpers grid and balance helpers used by
FixedPrecision Vaults. VaultCreate does not create FixedPrecision Vaults
yet, so no transaction behaviour changes.
2026-10-01 16:41:23 +02:00
Vito
5157a2866b feat: Apply FixedPrecision Open-zone admission to LoanSet
Origination on LEVersion 2 vaults uses the vault base scale, rejects coarsened vaults and InterestDue that would leave the Open zone, and books accepted InterestDue into YieldUnrealized.
2026-09-22 16:37:54 +02:00
Vito
663229cfdf fix: Rename LendingHelpers' liveScale to avoid unity-build clash
VaultHelpers.cpp defines its own file-local liveScale with the same
signature. Under -Dunity=ON the ledger module batches sources in
groups of 15, so the two anonymous-namespace helpers can land in the
same translation unit and collide.
2026-09-22 16:30:59 +02:00
Vito
89028a2ec6 style: Fix clang-tidy include-cleaner, braces, and return-move warnings 2026-09-22 15:48:40 +02:00
Vito
bb820683cb feat: Apply FixedPrecision cover grid to LoanBroker first-loss capital
Cover deposit, withdraw, and clawback round at the posterior CoverAvailable exponent so optional inflows cannot coarsen past the Open zone, while outflows may re-fine. DebtMaximum and minimum cover use the vault base scale, and FixedPrecision withdraw/clawback skip the live-scale canApplyToBrokerCover guard that would reject a valid re-fine.
2026-09-22 15:48:40 +02:00
Vito
5e0e36f87d Apply FixedPrecision rounding clamp to Deposit/Withdraw/Clawback; fix vault gate/test gaps
VaultDeposit/VaultWithdraw/VaultClawback now apply the fixCleanup3_4_0
posterior-scale rounding clamp unconditionally for FixedPrecision vaults,
not only when fix340Enabled. VaultCreate's featureLendingProtocolV1_1 gate
check now also accepts V1_2, matching the "V1.2 implies V1.1" semantics
already encoded in doApply.

Test changes:
- VaultHelpers_test: add a FixedPrecision-tagged clamp table to
  clampToAssetsTotalScale coverage; previously only Legacy/CashBasis was
  exercised.
- VaultClosedEnded_test: fix the closed-ended gate test, which asserted
  temDISABLED after subtracting only V1_1 even though V1_2 alone already
  satisfies the gate; add a case proving V1_2-only still opens it.
- VaultFixedPrecision_test: dedupe repeated scaled-vault setup into a
  shared helper.
- VaultTestBase: keep V1_2 excluded from all_ with a comment explaining
  why VaultBugs_test's precision-boundary scenarios are structurally
  unreachable under FixedPrecision's Open-zone cap, not just deferred.
2026-09-22 15:39:12 +02:00
Vito
9ae863d89e docs: Clarify LEVersion and deprecate kVaultMaximumIouScale.
Split the pre-V1.2 Scale cap to kVaultMaximumLegacyIouScale so the old name can warn without breaking V1.2 call sites.
2026-09-22 13:41:10 +02:00
Vito
b17c737e74 Merge remote-tracking branch 'origin/develop' into tapanito/sav-fixed-precision-vault-rounding 2026-09-22 12:41:17 +02:00
Vito
71d271ebed feat: Add FixedPrecision vault scale helpers and Open-zone deposit checks
New vaults created under V1.2 stay on a lifetime base grid so optional inflows cannot coarsen AssetsTotal, while pre-V1.2 vaults keep the dynamic scale they were created with.
2026-09-22 11:58:18 +02:00
360 changed files with 16215 additions and 7092 deletions

View File

@@ -5,7 +5,10 @@ Checks: "-*,
-bugprone-exception-escape,
-bugprone-implicit-widening-of-multiplication-result,
-bugprone-narrowing-conversions,
-bugprone-signed-bitwise,
-bugprone-std-exception-baseclass,
-bugprone-throwing-static-initialization,
-bugprone-unhandled-code-paths,
cppcoreguidelines-*,
-cppcoreguidelines-avoid-c-arrays,
@@ -14,6 +17,7 @@ Checks: "-*,
-cppcoreguidelines-avoid-magic-numbers,
-cppcoreguidelines-avoid-non-const-global-variables,
-cppcoreguidelines-c-copy-assignment-signature,
-cppcoreguidelines-explicit-constructor,
-cppcoreguidelines-interfaces-global-init,
-cppcoreguidelines-macro-usage,
-cppcoreguidelines-missing-std-forward,
@@ -32,6 +36,7 @@ Checks: "-*,
llvm-namespace-comment,
misc-*,
-misc-explicit-constructor,
-misc-multiple-inheritance,
-misc-no-recursion,
-misc-non-private-member-variables-in-classes,
@@ -45,6 +50,8 @@ Checks: "-*,
-modernize-avoid-c-style-cast,
-modernize-return-braced-init-list,
-modernize-use-integer-sign-comparison,
-modernize-use-string-view,
-modernize-use-structured-binding,
-modernize-use-trailing-return-type,
performance-*,
@@ -53,6 +60,7 @@ Checks: "-*,
-performance-noexcept-move-constructor,
-performance-unnecessary-copy-initialization,
-performance-unnecessary-value-param,
-performance-use-std-move,
readability-*,
-readability-avoid-const-params-in-decls,
@@ -65,7 +73,12 @@ Checks: "-*,
-readability-named-parameter,
-readability-qualified-auto,
-readability-redundant-access-specifiers,
-readability-redundant-lambda-parameter-list,
-readability-redundant-nested-if,
-readability-redundant-qualified-alias,
-readability-static-accessed-through-instance,
-readability-trailing-comma,
-readability-trivial-switch,
-readability-uppercase-literal-suffix
"
# ---
@@ -81,6 +94,10 @@ CheckOptions:
bugprone-unsafe-functions.ReportMoreUnsafeFunctions: true
bugprone-unused-return-value.CheckedReturnTypes: ::std::error_code;::std::error_condition;::std::errc
# New in clang-tidy 23; disabled until the code is updated
misc-const-correctness.AnalyzeAutoVariables: false
misc-const-correctness.AnalyzeLambdas: false
misc-const-correctness.AnalyzeParameters: false
misc-include-cleaner.IgnoreHeaders: ".*/(detail|impl)/.*;.*fwd\\.h(pp)?;time.h;stdlib.h;sqlite3.h;netinet/in\\.h;sys/resource\\.h;sys/sysinfo\\.h;linux/sysinfo\\.h;__chrono/.*;bits/.*;_abort\\.h;boost/.*;openssl/obj_mac\\.h"
readability-braces-around-statements.ShortStatementLines: 2

View File

@@ -108,3 +108,75 @@ endfunction()
function(patch_nix_binary target)
endfunction()
function(rpcspec_generate_instantiations)
set(options)
set(oneValueArgs OUT_VAR VALUE_TYPE VIEW_HEADER INCLUDE_DIR)
set(multiValueArgs HANDLERS)
cmake_parse_arguments(
THIS_FUNCTION_PREFIX
"${options}"
"${oneValueArgs}"
"${multiValueArgs}"
${ARGN}
)
endfunction()
function(corrosion_import_crate)
set(options
ALL_FEATURES
NO_DEFAULT_FEATURES
NO_STD
NO_LINKER_OVERRIDE
NO_USES_TERMINAL
LOCKED
FROZEN
)
set(oneValueArgs MANIFEST_PATH PROFILE IMPORTED_CRATES)
set(multiValueArgs
CRATE_TYPES
CRATES
FEATURES
FLAGS
OVERRIDE_CRATE_TYPE
)
cmake_parse_arguments(
THIS_FUNCTION_PREFIX
"${options}"
"${oneValueArgs}"
"${multiValueArgs}"
${ARGN}
)
endfunction()
function(corrosion_set_env_vars target_name env_var)
endfunction()
function(corrosion_add_cxxbridge cxx_target)
set(options)
set(oneValueArgs CRATE)
set(multiValueArgs FILES)
cmake_parse_arguments(
THIS_FUNCTION_PREFIX
"${options}"
"${oneValueArgs}"
"${multiValueArgs}"
${ARGN}
)
endfunction()
function(_unlink_libgcc_s crate)
endfunction()
function(add_xrpl_crate name)
set(options)
set(oneValueArgs CRATE)
set(multiValueArgs FILES)
cmake_parse_arguments(
THIS_FUNCTION_PREFIX
"${options}"
"${oneValueArgs}"
"${multiValueArgs}"
${ARGN}
)
endfunction()

View File

@@ -44,4 +44,12 @@ runs:
--conf:all tools.build:jobs=${BUILD_NPROC} \
--conf:all tools.build:verbosity="${LOG_VERBOSITY}" \
--conf:all tools.compilation:verbosity="${LOG_VERBOSITY}" \
.
--format=json \
. >"${RUNNER_TEMP}/conan-graph.json"
# Tools that run during the build may only load glibc from the Nix store,
# as their package ID survives a GCC runtime update.
- name: Check build-context packages for Nix store dependencies (Linux)
if: ${{ runner.os == 'Linux' }}
shell: bash
run: ./bin/nix/check-build-context-runtime.sh "${RUNNER_TEMP}/conan-graph.json"

View File

@@ -1,5 +1,5 @@
{
"image_tag": "sha-060957e",
"image_tag": "sha-3d526d4",
"configs": {
"ubuntu": [
{
@@ -74,7 +74,7 @@
"extra_cmake_args": "-Dvalidator_keys=ON",
"package": {
"type": "deb",
"image": "ghcr.io/xrplf/xrpld/packaging-debian:sha-3a2d19f"
"image": "ghcr.io/xrplf/xrpld/packaging-debian:sha-e6055dd"
}
},
{
@@ -86,7 +86,7 @@
"extra_cmake_args": "-Dvalidator_keys=ON -Dassert=ON",
"package": {
"type": "deb",
"image": "ghcr.io/xrplf/xrpld/packaging-debian:sha-3a2d19f",
"image": "ghcr.io/xrplf/xrpld/packaging-debian:sha-e6055dd",
"variant": "assert"
}
}
@@ -101,7 +101,7 @@
"extra_cmake_args": "-Dvalidator_keys=ON",
"package": {
"type": "rpm",
"image": "ghcr.io/xrplf/xrpld/packaging-rhel:sha-3a2d19f"
"image": "ghcr.io/xrplf/xrpld/packaging-rhel:sha-e6055dd"
}
}
]

View File

@@ -12,8 +12,7 @@ on:
- "!nix/docker/README.md"
- "!nix/devshell.nix"
- "!nix/check-tools/**"
- "bin/default-loader-path.sh"
- "bin/install-sanitizer-libs.sh"
- "bin/nix/default-loader-path.sh"
pull_request:
paths:
- ".github/workflows/build-nix-images.yml"
@@ -25,8 +24,8 @@ on:
- "!nix/devshell.nix"
- "!nix/check-tools/**"
- "bin/check-tools.sh"
- "bin/default-loader-path.sh"
- "bin/install-sanitizer-libs.sh"
- "bin/nix/default-loader-path.sh"
- "bin/install/sanitizer-libs.sh"
workflow_dispatch:
concurrency:

View File

@@ -5,13 +5,12 @@ on:
branches:
- develop
paths:
- ".github/workflows/build-packaging-images.yml"
- "bin/install-packaging-tools.sh"
- "bin/install/packaging-tools.sh"
- "package/images/packaging/**"
pull_request:
paths:
- ".github/workflows/build-packaging-images.yml"
- "bin/install-packaging-tools.sh"
- "bin/install/packaging-tools.sh"
- "package/images/packaging/**"
workflow_dispatch:

View File

@@ -5,7 +5,6 @@ on:
branches:
- develop
paths:
- ".github/workflows/build-pre-commit-image.yml"
- "bin/pre-commit/Dockerfile"
- "rust-toolchain.toml"
pull_request:

View File

@@ -34,7 +34,7 @@ permissions:
jobs:
audit:
runs-on: ubuntu-latest
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-060957e
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-3d526d4
permissions:
contents: read
# Needed to open an issue on scheduled failures.

View File

@@ -93,9 +93,8 @@ jobs:
.github/workflows/reusable-upload-recipe.yml
.clang-tidy
.codecov.yml
bin/check-nix-store-refs.sh
bin/check-tools.sh
bin/default-loader-path.sh
bin/nix/**
cfg/**
cmake/**
conan/**

View File

@@ -31,9 +31,8 @@ on:
- ".github/workflows/reusable-upload-recipe.yml"
- ".clang-tidy"
- ".codecov.yml"
- "bin/check-nix-store-refs.sh"
- "bin/check-tools.sh"
- "bin/default-loader-path.sh"
- "bin/nix/**"
- "cfg/**"
- "cmake/**"
- "conan/**"

View File

@@ -17,4 +17,4 @@ jobs:
uses: XRPLF/actions/.github/workflows/pre-commit.yml@279ec358f4a1be4088be3e024b07916fa97c75b6
with:
runs_on: ubuntu-latest
container: '{ "image": "ghcr.io/xrplf/xrpld/pre-commit:sha-473fe44" }'
container: '{ "image": "ghcr.io/xrplf/xrpld/pre-commit:sha-70b8fd3" }'

View File

@@ -41,7 +41,7 @@ env:
jobs:
build:
runs-on: ubuntu-latest
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-060957e
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-3d526d4
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

View File

@@ -257,20 +257,20 @@ jobs:
# cache included, since what it holds is what gets uploaded and reused.
- name: Check the build output for Nix store references (Nix toolchain)
if: ${{ inputs.toolchain == 'nix' }}
run: ./bin/check-nix-store-refs.sh "${BUILD_DIR}"
run: ./bin/nix/check-nix-store-refs.sh "${BUILD_DIR}"
- name: Check the Conan cache for Nix store references (Nix toolchain)
if: ${{ inputs.toolchain == 'nix' }}
run: ./bin/check-nix-store-refs.sh "${CONAN_HOME}"
run: ./bin/nix/check-nix-store-refs.sh "${CONAN_HOME}"
# Only what PatchNixBinary.cmake retargets: the toolchain in the Linux
# images always references the store. Same condition it uses.
- name: Check for Nix store references (Linux)
if: ${{ runner.os == 'Linux' && env.SANITIZERS_ENABLED == 'false' }}
run: |
./bin/check-nix-store-refs.sh "${BUILD_DIR}/xrpld"
./bin/check-nix-store-refs.sh "${BUILD_DIR}/xrpl_tests"
./bin/check-nix-store-refs.sh "${BUILD_DIR}/xrpld_tests"
./bin/nix/check-nix-store-refs.sh "${BUILD_DIR}/xrpld"
./bin/nix/check-nix-store-refs.sh "${BUILD_DIR}/xrpl_tests"
./bin/nix/check-nix-store-refs.sh "${BUILD_DIR}/xrpld_tests"
- name: Show ccache statistics
if: ${{ inputs.ccache_enabled }}

View File

@@ -34,7 +34,7 @@ jobs:
needs: [determine-files]
if: ${{ needs.determine-files.outputs.cpp_changed_files != '' || needs.determine-files.outputs.need_full_run == 'true' }}
runs-on: ["self-hosted", "Linux", "X64", "heavy"]
container: "ghcr.io/xrplf/xrpld/nix-debian:sha-060957e"
container: "ghcr.io/xrplf/xrpld/nix-debian:sha-3d526d4"
permissions:
contents: read
issues: write

View File

@@ -28,7 +28,7 @@ permissions:
jobs:
clippy:
runs-on: ubuntu-latest
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-060957e
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-3d526d4
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
@@ -41,7 +41,7 @@ jobs:
coverage:
runs-on: ubuntu-latest
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-060957e
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-3d526d4
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
@@ -70,7 +70,7 @@ jobs:
doc:
runs-on: ubuntu-latest
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-060957e
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-3d526d4
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

View File

@@ -40,7 +40,7 @@ defaults:
jobs:
upload:
runs-on: ubuntu-latest
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-060957e
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-3d526d4
env:
REMOTE_NAME: ${{ inputs.remote_name }}
CONAN_LOGIN_USERNAME_XRPLF: ${{ secrets.remote_username }}

View File

@@ -115,7 +115,7 @@ jobs:
- name: Check the Conan cache for Nix store references (Nix toolchain)
if: ${{ matrix.toolchain == 'nix' }}
run: ./bin/check-nix-store-refs.sh "${CONAN_HOME}"
run: ./bin/nix/check-nix-store-refs.sh "${CONAN_HOME}"
- name: Log into Conan remote
if: ${{ github.repository == 'XRPLF/rippled' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') }}

View File

@@ -60,7 +60,7 @@ repos:
types_or: [c++, c]
- repo: https://github.com/pre-commit/mirrors-clang-format
rev: e2b496dc2bd8340c2524cb9a2d2a943cde1bb6df # frozen: v23.1.1
rev: a9a8a861f30ed207ead7d5a3b7e8032283ba5da7 # frozen: v23.1.2
hooks:
- id: clang-format
args: [--style=file]
@@ -82,9 +82,10 @@ repos:
files: ^crates/.*\.rs$
- repo: https://github.com/BlankSpruce/gersemi-pre-commit
rev: f1c4833f8cf23c6d952673abc73525411a5719e8 # frozen: 0.29.1
rev: 28010ddd6016e1a0f7bd232acb6536ef996ae897 # frozen: 0.29.2
hooks:
- id: gersemi
args: [-i, --warnings-as-errors]
- repo: https://github.com/rbubley/mirrors-prettier
rev: ef4a397f916211b4a39ccf9d3d9cbb6562157251 # frozen: v3.9.9
@@ -95,19 +96,19 @@ repos:
# Scoped to package/: the rest of the repo's Python has pre-existing findings,
# so widening these is its own change.
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: a56c0b927e6465d37cae3e97d35d4d18ab2b96cd # frozen: v0.16.9
rev: f12be1ebaa5351c1fc76472de98db2c3446c8253 # frozen: v0.16.10
hooks:
- id: ruff-check
args: [--fix]
files: ^package/.*\.py$
- repo: https://github.com/psf/black-pre-commit-mirror
rev: 4160603246a6b365d4a2af661c6d71b0a0f50478 # frozen: 26.5.1
rev: 96ae3e5802f3fe2d551e703e18f0a367d1a81ac2 # frozen: 26.10.0
hooks:
- id: black
- repo: https://github.com/pre-commit/mirrors-mypy
rev: 7ff8d35ae36a7d2b968f2f90b4c723e292e594ee # frozen: v2.3.1
rev: 2834ec6639549dd6796205c8f011dedcd587288b # frozen: v2.4.0
hooks:
- id: mypy
args: [--strict]

View File

@@ -28,7 +28,17 @@ Version 3.5.0 is not yet released.
### Additions in 3.5.0
- `subscribe`, `unsubscribe`: Added an optional `mpt_issuances` request field, an array of MPT issuance IDs (hex strings). Subscribers receive a message with `type` `mptTransaction` for each validated transaction whose metadata affects a subscribed issuance; the message has the same fields as the `transactions` stream. MPT issuance subscriptions count toward the per-connection subscription limit. An empty array, a non-array value, or an invalid ID returns `invalidParams`. ([#5671](https://github.com/XRPLF/rippled/pull/5671))
- `subscribe`, `unsubscribe`: Added an optional `mpt_issuances` request field, an array of MPT issuance IDs (hex strings). Subscribers receive the same `transaction` message as the `transactions` stream for each validated transaction whose metadata affects a subscribed issuance. MPT issuance subscriptions count toward the per-connection subscription limit. An empty array, a non-array value, or an invalid ID returns `invalidParams`. ([#5671](https://github.com/XRPLF/rippled/pull/5671))
- `ledger_entry`: Add full support for checks, NFT offers, payment channels, and signer lists. ([#6319](https://github.com/XRPLF/rippled/pull/6319))
### Bugfixes in 3.5.0
- `channel_authorize`: The `channel_id` field now returns an `invalidParams` error if the value is not a string. [#7582](https://github.com/XRPLF/rippled/pull/7582)
- `channel_verify`: The `channel_id` and `signature` fields now return an `invalidParams` error if the value is not a string. [#7582](https://github.com/XRPLF/rippled/pull/7582)
### Bugfixes in 3.5.0
- `feature`: The admin-only `vetoed` field now returns `invalidParams` unless its value is a boolean. [#7583](https://github.com/XRPLF/rippled/pull/7583)
## XRP Ledger server version 3.4.0
@@ -50,6 +60,7 @@ Version 3.4.0 is not yet released. These changes are available in the 3.4.0 beta
- `account_lines`: The `peer` field now returns an error if the value is not a string. [#7728](https://github.com/XRPLF/rippled/pull/7728)
- `ledger`: `delivered_amount` is now included in the metadata of successful `AccountDelete` transactions when transactions are expanded (`expand`, or admin-only `full`). Previously it was only added for `Payment` and `CheckCash`, which made `ledger` inconsistent with `tx` and `account_tx`. [#5706](https://github.com/XRPLF/rippled/pull/5706)
- `noripple_check`: The `transactions` field is no longer included in error responses; it is still returned (possibly as an empty array) whenever `transactions` is `true` and the request succeeds. A malformed `account` is now rejected before the ledger is looked up, so that error response no longer carries the `ledger_hash`, `ledger_index`, and `validated` fields ([#6303](https://github.com/XRPLF/rippled/pull/6303)).
- `transaction_entry`: An object or an array in `tx_hash` now returns `malformedRequest`, like any other value that is not a hex hash, instead of an `internal` error.
## XRP Ledger server version 3.3.0

View File

@@ -20,9 +20,11 @@
# development setups, but not in the macOS CI environment. They are checked
# everywhere except when running in CI on macOS.
#
# Tools that Nix also exposes under a version-suffixed name (`clang-tidy-22`,
# `g++-15`, ...) are probed under both names: a suffixed name can break while
# the plain one still works (see mkVersionedToolLinks in nix/packages.nix).
# Tools that Nix also exposes under a version-suffixed name
# (`clang-tidy-<v>`, `g++-<v>`, ...) are probed under both names:
# a suffixed name can break while the plain one still works
# (see mkVersionedToolLinks in nix/packages.nix).
# The suffix is the major version of the plain `clang` / `gcc` on PATH.
#
# Tools scoped to a single dev shell rather than to commonPackages are checked
# only in that shell, keyed off XRPL_DEVSHELL.
@@ -34,9 +36,16 @@
set -uo pipefail
# Version suffixes of the Nix tool links, tracking nix/packages.nix.
gcc_version=15
llvm_version=22
# major_version <compiler>
# Major version of a compiler on PATH, or "unknown" when it isn't there.
major_version() {
local version
version="$("$1" -dumpversion 2>/dev/null)" || version=""
version="${version%%.*}"
printf '%s' "${version:-unknown}"
}
llvm_version="$(major_version clang)"
missing=()
checked=0
@@ -112,6 +121,7 @@ if [ "${os}" = "linux" ] || [ "${os}" = "macos" ]; then
check ClangBuildAnalyzer
check curl
check file
check jq
check less
check make
# net-tools netstat reports "net-tools X.Y"; macOS ships BSD netstat with no
@@ -180,6 +190,7 @@ fi
if [ "${os}" = "linux" ]; then
echo
echo "GCC toolchain:"
gcc_version="$(major_version gcc)"
check gcc
check "gcc-${gcc_version}"
check g++

View File

@@ -0,0 +1,65 @@
#!/usr/bin/env bash
# Fail if a binary of a build-context Conan package loads anything from the Nix
# store other than glibc, or cannot resolve a library at all.
#
# Only binaries linked by the Nix toolchain are checked, i.e. those recording a
# store path as their interpreter or RUNPATH. Prebuilt upstream binaries (such
# as the ones the cmake package ships) use the system loader instead.
#
# Build-context packages provide the tools that run during the build (protoc,
# grpc_cpp_plugin, ...). Their package ID does not change when a Nix toolchain
# update moves the GCC runtime to a new store path, so a cached binary has to
# get by with the pinned glibc alone. See docs/build/nix.md.
#
# Usage: bin/nix/check-build-context-runtime.sh <graph.json>
# <graph.json> is the output of `conan install --format=json`.
set -euo pipefail
if [ "$#" -ne 1 ]; then
echo "usage: $0 <graph.json>" >&2
exit 2
fi
if [ "$(uname -s)" != "Linux" ]; then
echo "$0: Linux only" >&2
exit 2
fi
folders="$(jq -r '.graph.nodes[] | select(.context == "build" and .package_folder) | .package_folder' "$1" | sort -u)"
checked=0
failed=0
while IFS= read -r file; do
case "$(file -b "${file}")" in
ELF*) ;;
*) continue ;;
esac
[[ "$(readelf -ldW "${file}")" == */nix/store/* ]] || continue
checked=$((checked + 1))
# `ldd` lists the interpreter and every library as the loader resolves them.
if deps="$(ldd "${file}" 2>&1)"; then
bad="$(printf '%s\n' "${deps}" |
grep -E 'not found|/nix/store/' |
grep -vE '/nix/store/[^/]+-glibc-[^/]+/' || true)"
else
case "${deps}" in
*"not a dynamic executable"*) continue ;;
esac
bad="${deps}"
fi
if [ -n "${bad}" ]; then
failed=$((failed + 1))
echo "::error file=${file}::loads a library from the Nix store other than glibc"
echo "${file}"
echo "${bad}" | sed 's/^/ /'
fi
done < <(
# shellcheck disable=SC2086 # one folder per line, no spaces in Conan paths
[ -z "${folders}" ] || find ${folders} -type f \( -perm -u+x -o -name '*.so*' \)
)
echo "Build-context packages: checked ${checked} binaries, ${failed} failed."
[ "${failed}" -eq 0 ]

View File

@@ -10,7 +10,7 @@
# alone; the scripts in a Conan cache are all git hook samples and autotools
# scratch, 36 false positives to 0 real.
#
# Usage: bin/check-nix-store-refs.sh <path>
# Usage: bin/nix/check-nix-store-refs.sh <path>
set -euo pipefail

View File

@@ -23,7 +23,7 @@ apt-get clean
rm -rf /var/lib/apt/lists/*
EOF
ARG PRE_COMMIT_VERSION=4.6.0
ARG PRE_COMMIT_VERSION=4.6.2
RUN pip install --no-cache --break-system-packages \
pre-commit==${PRE_COMMIT_VERSION}

View File

@@ -26,8 +26,6 @@ import sys
import tempfile
from pathlib import Path
CLANG_TIDY_VERSION = 22
# Extensions run-clang-tidy can analyse: `.cpp` translation units and, thanks to
# the `verify_headers` build option, `.h`/`.hpp` headers (each has its own
# compile_commands.json entry). `.ipp` fragments have no entry and are skipped.
@@ -39,8 +37,21 @@ TIDY_EXTENSIONS = {".cpp", ".h", ".hpp"}
FILEPATH_RE = re.compile(r"^(\s*(?:-\s+)?FilePath:\s*)'((?:[^']|'')*)'\s*$")
def find_tool(name: str) -> str | None:
for candidate in (f"{name}-{CLANG_TIDY_VERSION}", name):
def clang_tidy_major() -> str | None:
"""Major version of the `clang-tidy` on PATH, which run-clang-tidy invokes."""
if not (clang_tidy := shutil.which("clang-tidy")):
return None
output = subprocess.run(
[clang_tidy, "--version"], capture_output=True, text=True
).stdout
m = re.search(r"LLVM version (\d+)", output)
return m.group(1) if m else None
def find_tool(name: str, version: str | None) -> str | None:
"""Prefer `<name>-<version>`, so a host tool of another version can't win."""
candidates = ([f"{name}-{version}"] if version else []) + [name]
for candidate in candidates:
if path := shutil.which(candidate):
return path
return None
@@ -103,8 +114,9 @@ def main():
if not files:
return 0
run_clang_tidy = find_tool("run-clang-tidy")
clang_apply_replacements = find_tool("clang-apply-replacements")
version = clang_tidy_major()
run_clang_tidy = find_tool("run-clang-tidy", version)
clang_apply_replacements = find_tool("clang-apply-replacements", version)
missing = [
name
for name, path in (
@@ -114,9 +126,10 @@ def main():
if not path
]
if missing:
tried = f" (tried the '-{version}' suffix too)" if version else ""
print(
f"clang-tidy check failed: TIDY is enabled but {' and '.join(missing)} "
f"was not found in PATH (tried the '-{CLANG_TIDY_VERSION}' suffix too).",
f"was not found in PATH{tried}.",
file=sys.stderr,
)
return 1

View File

@@ -17,7 +17,7 @@
(runtime libraries resolved through the rpath) are skipped too.
Everywhere else `patch_nix_binary` is a no-op.
The default loader is resolved by bin/default-loader-path.sh.
The default loader is resolved by bin/nix/default-loader-path.sh.
#]===================================================================]
include_guard(GLOBAL)
@@ -25,7 +25,7 @@ include_guard(GLOBAL)
include(CompilationEnv)
# Resolves the system default ELF loader path for the current architecture.
set(_loader_path_script "${CMAKE_SOURCE_DIR}/bin/default-loader-path.sh")
set(_loader_path_script "${CMAKE_SOURCE_DIR}/bin/nix/default-loader-path.sh")
if(
is_linux

View File

@@ -292,6 +292,14 @@ if(xrpld)
)
target_sources(xrpld PRIVATE ${sources})
rpcspec_generate_instantiations(
OUT_VAR rpcspec_instantiations
VALUE_TYPE "::json::Value"
VIEW_HEADER "xrpld/rpc/detail/JsonObjectView.hpp"
HANDLERS book_changes ledger transaction_entry
)
target_sources(xrpld PRIVATE ${rpcspec_instantiations})
if(tests)
file(
GLOB_RECURSE sources
@@ -322,6 +330,7 @@ if(xrpld)
# antithesis_instrumentation.h, which is not exported as INTERFACE
target_include_directories(
xrpld
SYSTEM
PRIVATE ${CMAKE_SOURCE_DIR}/external/antithesis-sdk
)
endif()

View File

@@ -77,19 +77,24 @@ if(is_clang)
message(STATUS " Ignorelist: ${ignorelist_path}")
endif()
# Define SANITIZERS macro for BuildInfo.cpp
# Define the SANITIZERS macro for BuildInfo.cpp, plus one of XRPL_ASAN,
# XRPL_TSAN and XRPL_UBSAN per active sanitizer, so that code can test for a
# specific one with #ifdef instead of parsing the dot-joined SANITIZERS string.
set(sanitizers_list)
if(SANITIZERS MATCHES "address")
set(enable_asan ON)
list(APPEND sanitizers_list "ASAN")
target_compile_definitions(common INTERFACE XRPL_ASAN)
endif()
if(SANITIZERS MATCHES "thread")
set(enable_tsan ON)
list(APPEND sanitizers_list "TSAN")
target_compile_definitions(common INTERFACE XRPL_TSAN)
endif()
if(SANITIZERS MATCHES "undefinedbehavior")
set(enable_ubsan ON)
list(APPEND sanitizers_list "UBSAN")
target_compile_definitions(common INTERFACE XRPL_UBSAN)
endif()
if(sanitizers_list)

View File

@@ -3,7 +3,7 @@
"requires": [
"zlib/1.3.2#1cb806da49011867778ffb6ac7190fcb%1782392402.122708",
"xxhash/0.8.3#681d36a0a6111fc56e5e45ea182c19cc%1782392402.420688",
"xrpl-rpc-spec/0.1.19#870b2d3abcfbbf13b61c2d3c69495060%1790348286.187549",
"xrpl-rpc-spec/0.1.21#d536f87a2ae7d313452746cfa3ac4404%1790869005.122975",
"sqlite3/3.53.0#324ada52333108388a9a6108bfa96734%1782392403.185447",
"soci/4.0.3#e726491a03468795453f7c83fc924a96%1782392402.679521",
"snappy/1.1.10#968fef506ff261592ec30c574d4a7809%1782307151.633168",
@@ -20,7 +20,7 @@
"libarchive/3.8.7#c446109bd1f1d8ba7936c94189bc50e6%1782392403.066892",
"jemalloc/5.3.1#1fc58d55316041f10fbc1e8a2eae632a%1776700028.228",
"gtest/1.17.0#5224b3b3ff3b4ce1133cbdd27d53ee7d%1782392402.791979",
"grpc/1.81.1#b87796a4269034856cbc1a2522db16eb%1788275071.530512",
"grpc/1.81.1#aaa93ab6cda2f2baa6a84490582c8adf%1791284951.826256",
"fast_float/8.2.10#f6f28d6bb22112078e7dbda611caf681%1785888854.601666",
"ed25519/2015.03#ae761bdc52730a843f0809bdf6c1b1f6%1782307148.15562",
"date/3.0.4#862e11e80030356b53c2c38599ceb32b%1782392402.538492",
@@ -34,11 +34,15 @@
"build_requires": [
"zlib/1.3.2#1cb806da49011867778ffb6ac7190fcb%1782392402.122708",
"strawberryperl/5.32.1.1#8d114504d172cfea8ea1662d09b6333e%1782395692.540639",
"re2/20251105#8579cfd0bda4daf0683f9e3898f964b4%1782392402.431897",
"protobuf/6.33.5#ff253ead763bd8d9904a52979cd21e81%1782392410.233933",
"openssl/3.6.3#f806de8933e3bf6f01016c6a888cee2e%1783945160.863288",
"nasm/2.16.01#31e26f2ee3c4346ecd347911bd126904%1782395690.33162",
"msys2/cci.latest#d22fe7b2808f5fd34d0a7923ace9c54f%1770657326.649",
"m4/1.4.19#1727f439cf74e83826ec96d0b4904eee%1784541921.659",
"grpc/1.81.1#aaa93ab6cda2f2baa6a84490582c8adf%1791284951.826256",
"cmake/4.3.3#840cf00ea09777e05c2050a50a82c722%1782392418.696091",
"c-ares/1.34.6#545240bb1c40e2cacd4362d6b8967650%1782392402.681654",
"b2/5.4.2#ffd6084a119587e70f11cd45d1a386e2%1782392402.624226",
"automake/1.16.5#b91b7c384c3deaa9d535be02da14d04f%1755524470.56",
"autoconf/2.71#51077f068e61700d65bb05541ea1e4b0%1731054366.86",

View File

@@ -3,5 +3,13 @@
core:non_interactive=True
core.download:parallel={{ os.cpu_count() }}
core.upload:parallel={{ os.cpu_count() }}
tools.files.download:retry=5
# Fall back to Conan Center's source backups when a recipe's upstream URL is down
# (e.g. the GNU FTP mirrors), see
# https://github.com/conan-io/conan-center-index/issues/28147#issuecomment-3183544772
# The backups are only tried once every upstream URL has used up its retries,
# so keep the retries low.
core.sources:download_urls=["origin", "https://c3i.jfrog.io/artifactory/conan-center-backup-sources"]
tools.files.download:retry=1
tools.files.download:retry_wait=10
# Fail fast on unreachable hosts (default connect timeout is 30s), keep the 60s read timeout.
core.net.http:timeout=(5, 60)

View File

@@ -29,9 +29,9 @@ os.version={{ min_macos_version }}
[conf]
{# The Boost recipe builds with b2, which doesn't use Conan's toolchain files. #}
{# Instead it hand-rolls the compiler for user-config.jam, #}
{# and its fallback probes a version-suffixed binary (e.g. `g++-15`) before plain `g++`. #}
{# Inside the Nix shell the wrapper only provides `g++`/`gcc` (no `-15` suffix), #}
{# so on a host that also has a system `g++-15` the probe escapes Nix #}
{# and its fallback probes a version-suffixed binary (e.g. `g++-<major>`) before plain `g++`. #}
{# Inside the Nix shell the wrapper only provides `g++`/`gcc` (no `-<major>` suffix), #}
{# so on a host that also has a system `g++-<major>` the probe escapes Nix #}
{# and picks the system compiler, which is mismatched with the Nix libraries #}
{# and breaks the build (e.g. Boost.Stacktrace link checks fail). #}
{# Pinning the executables here short-circuits that probe so Boost (and the rest of the toolchain) #}
@@ -49,6 +49,17 @@ tools.build:compiler_executables={'c':'{{ cc_exe }}','cpp':'{{ cxx_exe }}'}
user.package:cppstd_version=23
tools.info.package_id:confs+=["user.package:cppstd_version"]
{% if os == "Linux" and context == "build" %}
{# Build-context executables (protoc, grpc_cpp_plugin, build tools) run during the build #}
{# and would otherwise load libstdc++/libgcc from a Nix store path #}
{# that might change with a Nix toolchain update. #}
{# --as-needed drops the ones they link but don't use, #}
{# such as libatomic for grpc_cpp_plugin on arm64. #}
{% set static_runtime_flags = ["-static-libstdc++", "-static-libgcc", "-Wl,--as-needed"] %}
tools.build:exelinkflags+={{ static_runtime_flags }}
tools.info.package_id:confs+=["tools.build:exelinkflags"]
{% endif %}
{% if os == "Macos" %}
[buildenv]
{# os.version adds -mmacosx-version-min to compiler command lines, #}
@@ -58,3 +69,13 @@ tools.info.package_id:confs+=["user.package:cppstd_version"]
{# Scoped to boost/* since it is the only gap. #}
boost/*:MACOSX_DEPLOYMENT_TARGET={{ min_macos_version }}
{% endif %}
{% if os == "Linux" and context == "build" %}
{# b2 links itself with its own script, which ignores exelinkflags #}
{# and only takes CXXFLAGS when use_cxx_env is set. #}
[options]
b2/*:use_cxx_env=True
[buildenv]
b2/*:CXXFLAGS={{ static_runtime_flags | join(" ") }}
{% endif %}

View File

@@ -5,6 +5,9 @@ include(default)
{% if not sanitizers %}
{# Sanitizers not configured; no additional settings needed #}
{% elif context == "build" %}
{# Build-context packages are tools we run, not code we test, #}
{# so don't instrument them #}
{% else %}
{% if compiler == "msvc" %}

View File

@@ -40,7 +40,7 @@ class Xrpl(ConanFile):
"nudb/2.0.9",
"openssl/3.6.3",
"soci/4.0.3",
"xrpl-rpc-spec/0.1.19",
"xrpl-rpc-spec/0.1.21",
"zlib/1.3.2",
]
@@ -49,7 +49,8 @@ class Xrpl(ConanFile):
]
tool_requires = [
"protobuf/6.33.5",
"grpc/<host_version>",
"protobuf/<host_version>",
]
default_options = {
@@ -123,6 +124,10 @@ class Xrpl(ConanFile):
"xxhash/*:shared": False,
}
# default_options only reach the host context;
# give tool_requires (and their dependencies) the same dependency options.
default_build_options = {k: v for k, v in default_options.items() if "/" in k}
def set_version(self):
self.version = self.version or DEV_VERSION
@@ -149,7 +154,7 @@ class Xrpl(ConanFile):
self.requires("xxhash/0.8.3", transitive_headers=True)
exports_sources = (
"bin/default-loader-path.sh",
"bin/nix/default-loader-path.sh",
"CMakeLists.txt",
"cfg/*",
"cmake/*",

View File

@@ -80,13 +80,12 @@ function(add_xrpl_crate name)
# `cc` picks its runtime flag from `crt-static` alone, so it compiles a
# crate's C++ with `-MT`; Debug needs `-MTd` (to match cmake/XrplCompiler.cmake).
if(is_msvc)
corrosion_set_env_vars(
${ARG_CRATE}
"$<$<CONFIG:Debug>:CXXFLAGS=-MTd>"
)
corrosion_set_env_vars(${ARG_CRATE} "$<$<CONFIG:Debug>:CXXFLAGS=-MTd>")
endif()
corrosion_add_cxxbridge(${name}_cxxbridge CRATE ${ARG_CRATE} FILES
${ARG_FILES}
corrosion_add_cxxbridge(
${name}_cxxbridge
CRATE ${ARG_CRATE}
FILES ${ARG_FILES}
)
# Generated cxxbridge headers don't exist at configure time; CMake 3.28+
# validates INTERFACE_SOURCES on consuming targets. Clear it to skip the

View File

@@ -10,14 +10,15 @@ This document explains how to set one up.
support it — see [compiler support for C++23][cpp23-support].
The versions currently tested in CI are:
| Compiler | Version |
| ----------- | ------------------ |
| GCC | 15.2 |
| Clang | 22 |
| Apple Clang | 21 |
| MSVC | Visual Studio 2026 |
| Compiler | Version |
| ----------- | ------------------------------- |
| GCC | `gccVersion` in [packages.nix] |
| Clang | `llvmVersion` in [packages.nix] |
| Apple Clang | 21 |
| MSVC | Visual Studio 2026 |
LLVM tools (`clang-tidy` and `clang-format`) are also pinned to version 22.
LLVM tools (`clang-tidy` and `clang-format`)
come from the same LLVM release as Clang.
### Older compilers
@@ -156,3 +157,4 @@ version out of the box — run it via `run-clang-tidy`. No separate installation
is needed.
[cpp23-support]: https://en.cppreference.com/w/cpp/compiler_support/23
[packages.nix]: ../../nix/packages.nix

30
docs/build/nix.md vendored
View File

@@ -183,24 +183,36 @@ at link or run time.
> configuration CI covers, and no dependency binaries are published for it.
This is checked rather than assumed.
[`bin/check-nix-store-refs.sh`](../../bin/check-nix-store-refs.sh) takes one file
or directory and fails if a binary under it resolves a store path at run time.
[`bin/nix/check-nix-store-refs.sh`](../../bin/nix/check-nix-store-refs.sh) takes one
file or directory and fails if a binary under it resolves a store path at run time.
CI runs it over the build output and the Conan cache, and again in the upload job
before anything is published. You can run it yourself:
```bash
bin/check-nix-store-refs.sh build
bin/check-nix-store-refs.sh ~/.conan2-nix
bin/nix/check-nix-store-refs.sh build
bin/nix/check-nix-store-refs.sh ~/.conan2-nix
```
It works on Linux too, but asserts something narrower there: the toolchain always
writes the store into `PT_INTERP` and `RUNPATH`, and CI builds inside an image
whose store is fixed for its lifetime, so that is fine. Only the binaries
[`PatchNixBinary.cmake`](../../cmake/PatchNixBinary.cmake) retargets to the
system loader have to be clean, and those are what CI checks:
writes the store into `PT_INTERP` and `RUNPATH`. That is fine for the pinned
glibc, whose path does not move, but not for the GCC runtime, which moves with
every GCC update. So [`conan/profiles/default`](../../conan/profiles/default)
links build-context packages, whose executables run during the build, with
`-static-libstdc++ -static-libgcc -Wl,--as-needed`, and
[`conan/profiles/sanitizers`](../../conan/profiles/sanitizers) does not
instrument them. CI checks that they load nothing from the store but glibc, from
the graph `conan install --format=json` writes:
```bash
bin/check-nix-store-refs.sh build/xrpld
bin/nix/check-build-context-runtime.sh graph.json
```
Only the binaries [`PatchNixBinary.cmake`](../../cmake/PatchNixBinary.cmake)
retargets to the system loader have to be fully clean, and those are what CI
checks:
```bash
bin/nix/check-nix-store-refs.sh build/xrpld
```
### The libresolv stub

View File

@@ -178,11 +178,11 @@ A binary stops starting after a `nix flake update`, or after
dyld[57271]: Library not loaded: /nix/store/…-libresolv-93/lib/libresolv.9.dylib
```
[`bin/check-nix-store-refs.sh`](../../bin/check-nix-store-refs.sh) finds the same
thing without having to run anything, and names the file:
[`bin/nix/check-nix-store-refs.sh`](../../bin/nix/check-nix-store-refs.sh) finds the
same thing without having to run anything, and names the file:
```
$ bin/check-nix-store-refs.sh ~/.conan2-nix
$ bin/nix/check-nix-store-refs.sh ~/.conan2-nix
::error file=/Users/you/.conan2-nix/p/b/c-area24ded30c388c/p/bin/adig::references the Nix store at run time
/Users/you/.conan2-nix/p/b/c-area24ded30c388c/p/bin/adig
/nix/store/p4lp3xq4imd1qzqh08x8vcq2zfhi7rca-libresolv-93/lib/libresolv.9.dylib

View File

@@ -6,7 +6,7 @@ project(antithesis-sdk-cpp VERSION 0.4.4 LANGUAGES CXX)
add_library(antithesis-sdk-cpp INTERFACE antithesis_sdk.h)
# Note, both sections below created by xrpld project
target_include_directories(antithesis-sdk-cpp INTERFACE
target_include_directories(antithesis-sdk-cpp SYSTEM INTERFACE
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
)

12
flake.lock generated
View File

@@ -2,11 +2,11 @@
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1781173989,
"narHash": "sha256-fnzKKPvS+oieI/pTzotA5tkoM47EB1NpaBcgk4R97hE=",
"lastModified": 1791130267,
"narHash": "sha256-1sjwcQMcgAbmiip/VivBSiK8p2bTkQGOvCuO7vnwfx4=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "8c91a71d13451abc40eb9dae8910f972f979852f",
"rev": "9013764fcc0ea99fa16cf7aa7decf8a5c3889dd2",
"type": "github"
},
"original": {
@@ -47,11 +47,11 @@
]
},
"locked": {
"lastModified": 1784611586,
"narHash": "sha256-OfqgY+0hp/zseZB7uyH0U8kIDPS4scZZCyAurEplvG0=",
"lastModified": 1791189933,
"narHash": "sha256-Y8eN7ki0Urx4Ojf4w1xSpWg8uk/3lJqK+E0Oth77rH0=",
"owner": "oxalica",
"repo": "rust-overlay",
"rev": "14f58845249f3552a89b07772626b8d3c632fa86",
"rev": "e60029353d0c48d216bc4b065168ccd4079c166f",
"type": "github"
},
"original": {

View File

@@ -17,7 +17,7 @@
namespace xrpl {
template <typename Key>
static std::size_t
std::size_t
extract(Key const& key)
{
return key;

View File

@@ -1604,7 +1604,7 @@ AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::erase(
beast::detail::AgedContainerIterator<IsConst, Iterator> pos)
requires(!IsBoostReverseIterator<Iterator>::value)
{
unlinkAndDeleteElement(&*((pos++).iterator()));
unlinkAndDeleteElement(&*(pos++).iterator());
return beast::detail::AgedContainerIterator<false, Iterator>(pos.iterator());
}
@@ -1617,7 +1617,7 @@ AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::erase(
requires(!IsBoostReverseIterator<Iterator>::value)
{
for (; first != last;)
unlinkAndDeleteElement(&*((first++).iterator()));
unlinkAndDeleteElement(&*(first++).iterator());
return beast::detail::AgedContainerIterator<false, Iterator>(first.iterator());
}

View File

@@ -2404,7 +2404,7 @@ beast::detail::AgedContainerIterator<false, Iterator>
AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>::erase(
beast::detail::AgedContainerIterator<IsConst, Iterator> pos)
{
unlinkAndDeleteElement(&*((pos++).iterator()));
unlinkAndDeleteElement(&*(pos++).iterator());
return beast::detail::AgedContainerIterator<false, Iterator>(pos.iterator());
}
@@ -2424,7 +2424,7 @@ AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>
beast::detail::AgedContainerIterator<IsConst, Iterator> last)
{
for (; first != last;)
unlinkAndDeleteElement(&*((first++).iterator()));
unlinkAndDeleteElement(&*(first++).iterator());
return beast::detail::AgedContainerIterator<false, Iterator>(first.iterator());
}

View File

@@ -390,7 +390,7 @@ void
hash_append(Hasher& h, boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept
requires(IsContiguouslyHashable<Key, Hasher>::value)
{
h(&(v.begin()), v.size() * sizeof(Key));
h(&v.begin(), v.size() * sizeof(Key));
}
// tuple

View File

@@ -8,7 +8,7 @@ namespace beast::insight {
class HookImpl : public std::enable_shared_from_this<HookImpl>
{
public:
using HandlerType = std::function<void(void)>;
using HandlerType = std::function<void()>;
virtual ~HookImpl() = 0;
};

View File

@@ -61,7 +61,7 @@ isMulticast(Address const& addr)
inline bool
isPrivate(Address const& addr)
{
return (addr.is_v4()) ? isPrivate(addr.to_v4()) : isPrivate(addr.to_v6());
return addr.is_v4() ? isPrivate(addr.to_v4()) : isPrivate(addr.to_v6());
}
/**
@@ -70,7 +70,7 @@ isPrivate(Address const& addr)
inline bool
isPublic(Address const& addr)
{
return (addr.is_v4()) ? isPublic(addr.to_v4()) : isPublic(addr.to_v6());
return addr.is_v4() ? isPublic(addr.to_v4()) : isPublic(addr.to_v6());
}
} // namespace ip

View File

@@ -34,7 +34,7 @@ typeName()
name += " volatile";
if (std::is_lvalue_reference_v<T>)
{
name += "&";
name += '&';
}
else if (std::is_rvalue_reference_v<T>)
{

View File

@@ -20,7 +20,7 @@ namespace beast::unit_test {
namespace detail {
template <class String>
static std::string
std::string
makeReason(String const& reason, char const* file, int line)
{
std::string s(reason);

View File

@@ -47,8 +47,8 @@ public:
template <class F, class... Args>
explicit Thread(Suite& s, F&& f, Args&&... args) : s_(&s)
{
std::function<void(void)> b = [f = std::forward<F>(f),
... args = std::forward<Args>(args)]() mutable {
std::function<void()> b = [f = std::forward<F>(f),
... args = std::forward<Args>(args)]() mutable {
std::invoke(f, args...);
};
t_ = std::thread(&Thread::run, this, std::move(b));
@@ -94,7 +94,7 @@ public:
private:
void
run(std::function<void(void)> f)
run(std::function<void()> f)
{
try
{

View File

@@ -5,7 +5,6 @@
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/AccountRootEntry.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Asset.h>
#include <xrpl/protocol/Keylet.h>
@@ -212,7 +211,7 @@ canWithdraw(
ReadView const& view,
AccountID const& from,
AccountID const& to,
AccountRootEntryR const& toSle,
SLE::ConstRef toSle,
STAmount const& amount,
bool hasDestinationTag,
std::optional<std::vector<UInt256>> const& credentialIDs = std::nullopt);

View File

@@ -7,20 +7,9 @@
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/TER.h>
#include <xrpl/protocol/XRPAmount.h>
#include <cstdint>
#include <optional>
namespace xrpl {
struct Adjustment
{
std::int32_t ownerCountDelta = 0;
std::int32_t accountCountDelta = 0;
};
template <typename ViewT>
class AccountRootEntry : public SLEBase<ViewT, ltACCOUNT_ROOT>
{
@@ -38,123 +27,6 @@ public:
: Base(keylet::account(id), view, j)
{
}
/**
* Returns the account reserve, in drops.
*
* Actual owner count can be adjusted by delta in ownerCountAdj
* Actual reserve count can be adjusted by delta in accountCountAdj
* The reserve is calculated as:
* (ownerCount + "sponsoring object count" - "sponsored object count" + additionalOwnerCount) *
* increment + (1 if not sponsored account + sponsoringAccountCount) * "reserve base"
*
* @param adj Adjustment to the owner/account count (default: 0/0). Positive to add, negative
* to subtract.
* @return The account reserve amount in drops
*/
[[nodiscard]] XRPAmount
reserve(Adjustment adj = {}) const;
/**
* Return number of the objects which reserve is covered by the account (so called "owner
* count"). Actual owner count can be adjusted by delta in ownerCountAdj.
*
* @param ownerCountAdj Adjustment to the owner count (default: 0)
* @return The adjusted owner count
*/
[[nodiscard]] std::uint32_t
ownerCount(std::int32_t ownerCountAdj = 0) const;
/**
* Check if this account has sufficient reserve.
*
* @param ctx The apply-view context (view + tx)
* @param accBalance The account's balance
* @param sponsorSle The sponsor's ledger entry (if applicable)
* @param adj Adjustment to the owner/account count (default: 0/0). Positive to add, negative
* to subtract.
* @param insufReserveCode The transaction result code to return if the reserve is
* insufficient (default: tecINSUFFICIENT_RESERVE).
* @return Transaction result code
*/
[[nodiscard]] TER
checkReserve(
ApplyViewContext ctx,
XRPAmount accBalance,
std::optional<AccountRootEntry<ReadView>> const& sponsorSle,
Adjustment adj,
TER insufReserveCode = tecINSUFFICIENT_RESERVE) const;
/**
* Check if this account has sufficient reserve, deriving the sponsor internally.
*
* Equivalent to the overload above, but resolves the sponsor via
* getEffectiveTxReserveSponsor(ctx, *this) instead of taking it explicitly. Use this
* in the common case where the sponsor is simply the transaction's reserve
* sponsor for this account. Callers that must force the account's-own-reserve branch
* (passing a null sponsor) or supply a different sponsor should use the
* explicit overload above.
*
* @param ctx The apply-view context (view + tx)
* @param accBalance The account's balance
* @param adj Reserve adjustments (owner/account count deltas)
* @return Transaction result code
*/
[[nodiscard]] TER
checkReserve(ApplyViewContext ctx, XRPAmount accBalance, Adjustment adj) const;
/**
* Increase owner-count fields when the caller supplies the sponsor.
*
* This helper does not create a ledger object. It updates reserve accounting
* after the caller has created/updated an object.
* If sponsorSle is provided, this also adjusts the account's sponsored count
* and the sponsor's sponsoring count.
*
* @param sponsorSle The sponsor's ledger entry (if applicable)
* @param count Amount to add to the owner count
*/
void
increaseOwnerCount(std::optional<AccountRootEntry<ApplyView>>& sponsorSle, std::uint32_t count)
requires Base::kIsWritable;
/**
* Increase owner-count fields, deriving the tx reserve sponsor internally.
*
* Equivalent to the overload above, but resolves the sponsor via
* getEffectiveTxReserveSponsor(ctx, *this) instead of taking it explicitly. Use
* this when the sponsor is the transaction's reserve sponsor for this account
* (the common create path). Deletion paths, which derive the sponsor from an
* object's sfSponsor field, should keep using the explicit overload.
*
* @param ctx The apply-view context (view + tx)
* @param count Amount to add to the owner count
*/
void
increaseOwnerCount(ApplyViewContext ctx, std::uint32_t count)
requires Base::kIsWritable;
/**
* Decrease owner-count fields when the caller supplies the sponsor.
*
* This helper does not delete a ledger object. It updates reserve accounting
* after the caller has removed an owner-counted reserve, or for special
* owner-count changes whose sponsor cannot be derived from an object's
* sfSponsor field.
*
* @param sponsorSle The sponsor's ledger entry (if applicable)
* @param count Amount to remove from the owner count
*/
void
decreaseOwnerCount(std::optional<AccountRootEntry<ApplyView>>& sponsorSle, std::uint32_t count)
requires Base::kIsWritable;
private:
void
adjustOwnerCountSigned(
std::optional<AccountRootEntry<ApplyView>>& sponsorSle,
std::int32_t adjustment)
requires Base::kIsWritable;
};
using AccountRootEntryR = AccountRootEntry<ReadView>;

View File

@@ -1,11 +1,17 @@
#pragma once
#include <xrpl/basics/base_uint.h>
#include <xrpl/basics/chrono.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/SLEBase.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/SField.h>
#include <map>
#include <set>
namespace xrpl {
@@ -25,6 +31,52 @@ public:
: Base(keylet::amendments(), view, j)
{
}
/**
* Returns the set of amendments this entry reports as enabled.
*
* @return the set of enabled amendments.
*/
[[nodiscard]] std::set<UInt256>
enabledAmendments() const
{
std::set<UInt256> amendments;
if (this->exists() && (*this)->isFieldPresent(sfAmendments))
{
auto const& v = (*this)->getFieldV256(sfAmendments);
amendments.insert_range(v);
}
return amendments;
}
/**
* Returns a map of amendments that have achieved majority, to the time
* majority was reached.
*
* @return a map of amendment to the time majority was reached.
*/
[[nodiscard]] std::map<UInt256, NetClock::time_point>
majorityAmendments() const
{
std::map<UInt256, NetClock::time_point> ret;
if (this->exists() && (*this)->isFieldPresent(sfMajorities))
{
using TimePoint = NetClock::time_point;
using Duration = TimePoint::duration;
auto const majorities = (*this)->getFieldArray(sfMajorities);
for (auto const& m : majorities)
{
ret[m.getFieldH256(sfAmendment)] = TimePoint(Duration(m.getFieldU32(sfCloseTime)));
}
}
return ret;
}
};
using AmendmentsEntryR = AmendmentsEntry<ReadView>;

View File

@@ -1,11 +1,17 @@
#pragma once
#include <xrpl/basics/base_uint.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/SLEBase.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/STVector256.h>
#include <cstddef>
#include <optional>
namespace xrpl {
@@ -25,6 +31,31 @@ public:
: Base(keylet::skip(), view, j)
{
}
/**
* Looks up a hash `diff` slots back from the most recent entry in the
* sfHashes vector (diff == 0 is the most recent entry).
*
* Callers decide which skip list entry to read and how to translate a
* target ledger sequence into `diff`; this only does the bounds check
* and vector indexing shared by both the recent (stride 1) and distant
* (stride 256) skip lists.
*
* @param diff how many slots back from the most recent hash to look up;
* 0 is the most recent hash.
* @return the hash at that slot, or std::nullopt if the entry does not
* exist or `diff` is out of range.
*/
[[nodiscard]] std::optional<UInt256>
hashAt(std::size_t diff) const
{
if (!this->exists())
return std::nullopt;
STVector256 const vec = (*this)->getFieldV256(sfHashes);
if (vec.size() > diff)
return vec[vec.size() - diff - 1];
return std::nullopt;
}
};
using LedgerHashesEntryR = LedgerHashesEntry<ReadView>;

View File

@@ -372,8 +372,8 @@ changeSpotPriceQuality(
auto const takerPays =
toAmount<TIn>(getAsset(pool.in), nTakerPays, Number::RoundingMode::Upward);
// should not fail
if (auto amounts = TAmounts<TIn, TOut>{takerPays, swapAssetIn(pool, takerPays, tfee)};
Quality{amounts} < quality &&
auto amounts = TAmounts<TIn, TOut>{takerPays, swapAssetIn(pool, takerPays, tfee)};
if (Quality{amounts} < quality &&
!withinRelativeDistance(Quality{amounts}, quality, Number(1, -7)))
{
JLOG(j.error()) << "changeSpotPriceQuality failed: " << to_string(pool.in) << " "
@@ -382,14 +382,12 @@ changeSpotPriceQuality(
<< " " << to_string(amounts.out);
Throw<std::runtime_error>("changeSpotPriceQuality failed");
}
else
{
JLOG(j.trace()) << "changeSpotPriceQuality succeeded: " << to_string(pool.in) << " "
<< to_string(pool.out) << " "
<< " " << quality << " " << tfee << " " << to_string(amounts.in)
<< " " << to_string(amounts.out);
return amounts;
}
JLOG(j.trace()) << "changeSpotPriceQuality succeeded: " << to_string(pool.in) << " "
<< to_string(pool.out) << " "
<< " " << quality << " " << tfee << " " << to_string(amounts.in) << " "
<< to_string(amounts.out);
return amounts;
}
JLOG(j.trace()) << "changeSpotPriceQuality calc failed: " << to_string(pool.in) << " "
<< to_string(pool.out) << " " << quality << " " << tfee;

View File

@@ -4,8 +4,8 @@
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/AccountRootEntry.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/Rate.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/STLedgerEntry.h>
@@ -46,55 +46,30 @@ isGlobalFrozen(ReadView const& view, AccountID const& issuer);
[[nodiscard]] XRPAmount
xrpLiquid(ReadView const& view, AccountID const& id, std::int32_t ownerCountAdj, beast::Journal j);
namespace detail {
struct Adjustment
{
std::int32_t ownerCountDelta = 0;
std::int32_t accountCountDelta = 0;
};
/**
* An owner count cannot be negative. If adjustment would cause a negative
* owner count, clamp the owner count at 0. Similarly for overflow. This
* adjustment allows the ownerCount to be adjusted up or down in multiple steps.
* If id != std::nullopt, then do error reporting.
* Returns the account reserve, in drops.
*
* Shared by AccountRootEntry::ownerCount() and the owner-count helpers.
* Actual owner count can be adjusted by delta in ownerCountAdj
* Actual reserve count can be adjusted by delta in accountCountAdj
* The reserve is calculated as:
* (ownerCount + "sponsoring object count" - "sponsored object count" + additionalOwnerCount) *
* increment + (1 if not sponsored account + sponsoringAccountCount) * "reserve base"
*
* @param currentOwnerCount The owner count before adjustment
* @param ownerCountAdj Positive to add to count, negative to reduce count
* @param id The account ID to use for error reporting, or std::nullopt to
* skip error reporting
* @param view The ledger view to read from
* @param sle The ledger entry for the account
* @param j Journal for logging
* @return The adjusted owner count
* @param adj Adjustment to the owner/account count (default: 0/0). Positive to add, negative to
* subtract.
* @return The account reserve amount in drops
*/
std::uint32_t
confineOwnerCount(
std::uint32_t currentOwnerCount,
std::int32_t ownerCountAdj,
std::optional<AccountID> const& id = std::nullopt,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()});
/**
* Clamps and writes an owner-count field of sle, then updates sle in view.
*
* Shared by AccountRootEntry and adjustLoanBrokerOwnerCount().
*
* @return The adjusted owner count
*/
std::uint32_t
adjustOwnerCountImpl(
ApplyView& view,
SLE::Ref sle,
SF_UINT32 const& sfield,
AccountID const& accID,
std::int32_t ownerCountAdj,
beast::Journal j);
/**
* Returns the number of account reserves funded by this account: 1 for itself
* (0 if sponsored by another account) plus the count of accounts it sponsors.
* Shared by AccountRootEntry::reserve() and xrpLiquid().
*/
std::uint32_t
accountCountImpl(AccountRootEntryR const& sle, std::int32_t accountCountAdj, beast::Journal j);
} // namespace detail
[[nodiscard]] XRPAmount
accountReserve(ReadView const& view, SLE::ConstRef sle, beast::Journal j, Adjustment adj = {});
/**
* Convenience overload that accepts AccountID instead of SLE.
@@ -109,9 +84,114 @@ accountCountImpl(AccountRootEntryR const& sle, std::int32_t accountCountAdj, bea
[[nodiscard]] inline XRPAmount
accountReserve(ReadView const& view, AccountID const& id, beast::Journal j, Adjustment adj = {})
{
return AccountRootEntryR(id, view, j).reserve(adj);
return accountReserve(view, view.read(keylet::account(id)), j, adj);
}
/**
* Check if an account has sufficient reserve.
*
* @param view The ledger view to read from
* @param tx The transaction being processed
* @param accSle The account's ledger entry
* @param accBalance The account's balance
* @param sponsorSle The sponsor's ledger entry (if applicable)
* @param adj Adjustment to the owner/account count (default: 0/0). Positive to add, negative to
* subtract.
* @param j Journal for logging (default: null sink)
* @param insufReserveCode The transaction result code to return if the reserve is insufficient
* (default: tecINSUFFICIENT_RESERVE).
* @return Transaction result code
*/
[[nodiscard]] TER
checkReserve(
ApplyViewContext ctx,
SLE::ConstRef accSle,
XRPAmount accBalance,
SLE::ConstRef sponsorSle,
Adjustment adj,
beast::Journal j,
TER insufReserveCode = tecINSUFFICIENT_RESERVE);
/**
* Check if an account has sufficient reserve, deriving the sponsor internally.
*
* Equivalent to the overload above, but resolves the sponsor via
* getEffectiveTxReserveSponsor(ctx, accSle) instead of taking it explicitly. Use this
* in the common case where the sponsor is simply the transaction's reserve
* sponsor for accSle. Callers that must force the account's-own-reserve branch
* (passing a null sponsor) or supply a different sponsor should use the
* explicit overload above.
*
* @param ctx The apply-view context (view + tx)
* @param accSle The account's ledger entry
* @param accBalance The account's balance
* @param adj Reserve adjustments (owner/account count deltas)
* @param j Journal for logging (default: null sink)
* @return Transaction result code
*/
[[nodiscard]] TER
checkReserve(
ApplyViewContext ctx,
SLE::ConstRef accSle,
XRPAmount accBalance,
Adjustment adj,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()});
/**
* Return number of the objects which reserve is covered by the account(sle) (so called "owner
* count"). Actual owner count can be adjusted by delta in ownerCountAdj.
*
* @param sle The account's ledger entry
* @param j Journal for logging
* @param ownerCountAdj Adjustment to the owner count (default: 0)
* @return The adjusted owner count
*/
std::uint32_t
ownerCount(SLE::ConstRef sle, beast::Journal j, std::int32_t ownerCountAdj = 0);
/**
* Increase owner-count fields when the caller supplies the sponsor.
*
* This helper does not create a ledger object. It updates reserve accounting
* after the caller has created/updated an object.
* If sponsorSle is provided, this also adjusts the account's sponsored count
* and the sponsor's sponsoring count.
*
* @param view The apply view for making changes
* @param accountSle The account's ledger entry
* @param sponsorSle The sponsor's ledger entry (if applicable)
* @param count Amount to add to the owner count
* @param j Journal for logging
*/
void
increaseOwnerCount(
ApplyView& view,
SLE::Ref accountSle,
SLE::Ref sponsorSle,
std::uint32_t count,
beast::Journal j);
/**
* Increase owner-count fields, deriving the tx reserve sponsor internally.
*
* Equivalent to the overload above, but resolves the sponsor via
* getEffectiveTxReserveSponsor(ctx, accountSle) instead of taking it explicitly. Use
* this when the sponsor is the transaction's reserve sponsor for accountSle
* (the common create path). Deletion paths, which derive the sponsor from an
* object's sfSponsor field, should keep using the explicit overload.
*
* @param ctx The apply-view context (view + tx)
* @param accountSle The account's ledger entry
* @param count Amount to add to the owner count
* @param j Journal for logging
*/
void
increaseOwnerCount(
ApplyViewContext ctx,
SLE::Ref accountSle,
std::uint32_t count,
beast::Journal j);
/**
* Convenience overload that accepts AccountID instead of SLE references.
*
@@ -129,13 +209,36 @@ increaseOwnerCount(
std::uint32_t count,
beast::Journal j)
{
AccountRootEntryW accountSle(account, view, j);
std::optional<AccountRootEntryW> sponsorSle;
if (sponsor)
sponsorSle.emplace(*sponsor, view);
accountSle.increaseOwnerCount(sponsorSle, count);
increaseOwnerCount(
view,
view.peek(keylet::account(account)),
sponsor ? view.peek(keylet::account(*sponsor)) : SLE::pointer(),
count,
j);
}
/**
* Decrease owner-count fields when the caller supplies the sponsor.
*
* This helper does not delete a ledger object. It updates reserve accounting
* after the caller has removed an owner-counted reserve, or for special
* owner-count changes whose sponsor cannot be derived from an object's
* sfSponsor field.
*
* @param view The apply view for making changes
* @param accountSle The account's ledger entry
* @param sponsorSle The sponsor's ledger entry (if applicable)
* @param count Amount to remove from the owner count
* @param j Journal for logging
*/
void
decreaseOwnerCount(
ApplyView& view,
SLE::Ref accountSle,
SLE::Ref sponsorSle,
std::uint32_t count,
beast::Journal j);
/**
* Convenience overload that accepts AccountID instead of SLE references.
*
@@ -153,11 +256,12 @@ decreaseOwnerCount(
std::uint32_t count,
beast::Journal j)
{
AccountRootEntryW accountSle(account, view, j);
std::optional<AccountRootEntryW> sponsorSle;
if (sponsor)
sponsorSle.emplace(*sponsor, view);
accountSle.decreaseOwnerCount(sponsorSle, count);
decreaseOwnerCount(
view,
view.peek(keylet::account(account)),
sponsor ? view.peek(keylet::account(*sponsor)) : SLE::pointer(),
count,
j);
}
/**
@@ -177,7 +281,7 @@ decreaseOwnerCount(
void
decreaseOwnerCountForObject(
ApplyView& view,
AccountRootEntryW& accountSle,
SLE::Ref accountSle,
SLE::Ref objectSle,
std::uint32_t count,
beast::Journal j);
@@ -199,7 +303,7 @@ decreaseOwnerCountForObject(
std::uint32_t count,
beast::Journal j)
{
AccountRootEntryW accountSle(account, view);
SLE::Ref accountSle = view.peek(keylet::account(account));
decreaseOwnerCountForObject(view, accountSle, objectSle, count, j);
}
@@ -263,7 +367,7 @@ getPseudoAccountFields();
* - null pointer
*/
[[nodiscard]] bool
isPseudoAccount(AccountRootEntryR const& sleAcct);
isPseudoAccount(SLE::const_pointer sleAcct);
/**
* Convenience overload that reads the account from the view.
@@ -271,7 +375,7 @@ isPseudoAccount(AccountRootEntryR const& sleAcct);
[[nodiscard]] inline bool
isPseudoAccount(ReadView const& view, AccountID const& accountId)
{
return isPseudoAccount(AccountRootEntryR(accountId, view));
return isPseudoAccount(view.read(keylet::account(accountId)));
}
/**
@@ -292,6 +396,6 @@ createPseudoAccount(ApplyView& view, UInt256 const& pseudoOwnerKey, SField const
* - If the SLE requires a destination tag, checks that there is a tag.
*/
[[nodiscard]] TER
checkDestinationAndTag(AccountRootEntryR const& toSle, bool hasDestinationTag);
checkDestinationAndTag(SLE::ConstRef toSle, bool hasDestinationTag);
} // namespace xrpl

View File

@@ -2,9 +2,11 @@
#include <xrpl/basics/Log.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/beast/utility/Zero.h>
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/entries/AccountRootEntry.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
#include <xrpl/ledger/helpers/RippleStateHelpers.h>
#include <xrpl/ledger/helpers/SponsorHelpers.h>
@@ -27,31 +29,290 @@
namespace xrpl {
namespace detail {
/**
* Before fixCleanup3_2_0, EscrowCancel passes the escrow SLE as sleDest.
* Return what the old reserve check returned for it, without adopting a
* non-AccountRoot SLE into an AccountRootEntry: the tx reserve sponsor's
* error if the escrow owner submitted the tx, else tefINTERNAL.
* Validate that @p account may lock @p amount of a token for later delivery
* to @p dest.
*
* @param ctx the apply view context for the escrow transaction.
* @param sleDest the non-AccountRoot SLE that was passed as the destination.
* @return the tx reserve sponsor's error code if the escrow owner submitted
* the tx, else tefINTERNAL.
* The lock-side counterpart of escrowUnlockPreclaimHelper: every issuer
* control (locking opt-in, authorization, freeze/lock, transferability,
* spendable balance) that gates locking token value lives here, so any
* transactor that locks funds applies the same rules. The signature is
* view-based rather than PreclaimContext-based so it can also run from
* doApply.
*/
template <ValidIssueType T>
TER
escrowLockPreclaimHelper(
ReadView const& view,
AccountID const& account,
AccountID const& dest,
STAmount const& amount,
beast::Journal j);
template <>
inline TER
escrowDestNotAccountResult(ApplyViewContext ctx, SLE::ConstRef sleDest)
escrowLockPreclaimHelper<Issue>(
ReadView const& view,
AccountID const& account,
AccountID const& dest,
STAmount const& amount,
beast::Journal j)
{
if (sleDest->getAccountID(sfAccount) == ctx.tx[sfAccount])
{
if (auto const sponsor = getTxReserveSponsor(ctx); !sponsor)
return sponsor.error(); // LCOV_EXCL_LINE
}
return tefINTERNAL;
auto const& issue = amount.get<Issue>();
auto const& issuer = amount.getIssuer();
// If the issuer is the same as the account, return tecNO_PERMISSION
if (issuer == account)
return tecNO_PERMISSION;
// If the lsfAllowTrustLineLocking is not enabled, return tecNO_PERMISSION
auto const sleIssuer = view.read(keylet::account(issuer));
if (!sleIssuer)
return tecNO_ISSUER;
if (!sleIssuer->isFlag(lsfAllowTrustLineLocking))
return tecNO_PERMISSION;
// If the account does not have a trustline to the issuer, return tecNO_LINE
auto const sleRippleState = view.read(keylet::trustLine(account, issuer, issue.currency));
if (!sleRippleState)
return tecNO_LINE;
STAmount const balance = (*sleRippleState)[sfBalance];
// If balance is positive, issuer must have higher address than account
if (balance > beast::kZero && issuer < account)
return tecNO_PERMISSION; // LCOV_EXCL_LINE
// If balance is negative, issuer must have lower address than account
if (balance < beast::kZero && issuer > account)
return tecNO_PERMISSION; // LCOV_EXCL_LINE
// If the issuer has requireAuth set, check if the account is authorized
if (auto const ter = requireAuth(view, issue, account); !isTesSuccess(ter))
return ter;
// If the issuer has requireAuth set, check if the destination is authorized
if (auto const ter = requireAuth(view, issue, dest); !isTesSuccess(ter))
return ter;
// If the issuer has frozen the account, return tecFROZEN
if (isFrozen(view, account, issue))
return tecFROZEN;
// If the issuer has frozen the destination, return tecFROZEN
if (isFrozen(view, dest, issue))
return tecFROZEN;
STAmount const spendableAmount =
accountHolds(view, account, issue.currency, issuer, FreezeHandling::IgnoreFreeze, j);
// If the balance is less than or equal to 0, return tecINSUFFICIENT_FUNDS
if (spendableAmount <= beast::kZero)
return tecINSUFFICIENT_FUNDS;
// If the spendable amount is less than the amount, return
// tecINSUFFICIENT_FUNDS
if (spendableAmount < amount)
return tecINSUFFICIENT_FUNDS;
// If the amount is not addable to the balance, return tecPRECISION_LOSS
if (!canAdd(spendableAmount, amount))
return tecPRECISION_LOSS;
return tesSUCCESS;
}
} // namespace detail
template <>
inline TER
escrowLockPreclaimHelper<MPTIssue>(
ReadView const& view,
AccountID const& account,
AccountID const& dest,
STAmount const& amount,
beast::Journal j)
{
AccountID const issuer = amount.getIssuer();
// If the issuer is the same as the account, return tecNO_PERMISSION
if (issuer == account)
return tecNO_PERMISSION;
// If the mpt does not exist, return tecOBJECT_NOT_FOUND
auto const issuanceKey = keylet::mptokenIssuance(amount.get<MPTIssue>().getMptID());
auto const sleIssuance = view.read(issuanceKey);
if (!sleIssuance)
return tecOBJECT_NOT_FOUND;
// If the lsfMPTCanEscrow is not enabled, return tecNO_PERMISSION
if (!sleIssuance->isFlag(lsfMPTCanEscrow))
return tecNO_PERMISSION;
// If the issuer is not the same as the issuer of the mpt, return
// tecNO_PERMISSION
if (sleIssuance->getAccountID(sfIssuer) != issuer)
return tecNO_PERMISSION; // LCOV_EXCL_LINE
// If the account does not have the mpt, return tecOBJECT_NOT_FOUND
if (!view.exists(keylet::mptoken(issuanceKey.key, account)))
return tecOBJECT_NOT_FOUND;
// If the issuer has requireAuth set, check if the account is
// authorized
auto const& mptIssue = amount.get<MPTIssue>();
if (auto const ter = requireAuth(view, mptIssue, account, AuthType::WeakAuth);
!isTesSuccess(ter))
return ter;
// If the issuer has requireAuth set, check if the destination is
// authorized
if (auto const ter = requireAuth(view, mptIssue, dest, AuthType::WeakAuth); !isTesSuccess(ter))
return ter;
// If the issuer has frozen the account, return tecLOCKED
if (isFrozen(view, account, *sleIssuance))
return tecLOCKED;
// If the issuer has frozen the destination, return tecLOCKED
if (isFrozen(view, dest, *sleIssuance))
return tecLOCKED;
// If the mpt cannot be transferred, return tecNO_AUTH
if (auto const ter = canTransfer(view, mptIssue, account, dest); !isTesSuccess(ter))
return ter;
STAmount const spendableAmount = accountHolds(
view,
account,
amount.get<MPTIssue>(),
FreezeHandling::IgnoreFreeze,
AuthHandling::IgnoreAuth,
j);
// If the balance is less than or equal to 0, return tecINSUFFICIENT_FUNDS
if (spendableAmount <= beast::kZero)
return tecINSUFFICIENT_FUNDS;
// If the spendable amount is less than the amount, return
// tecINSUFFICIENT_FUNDS
if (spendableAmount < amount)
return tecINSUFFICIENT_FUNDS;
return tesSUCCESS;
}
template <ValidIssueType T>
TER
escrowLockApplyHelper(
ApplyView& view,
AccountID const& issuer,
AccountID const& sender,
STAmount const& amount,
beast::Journal journal);
template <>
inline TER
escrowLockApplyHelper<Issue>(
ApplyView& view,
AccountID const& issuer,
AccountID const& sender,
STAmount const& amount,
beast::Journal journal)
{
// Defensive: Issuer cannot create an escrow
if (issuer == sender)
return tecINTERNAL; // LCOV_EXCL_LINE
auto const ter =
directSendNoFee(view, sender, issuer, amount, !amount.holds<MPTIssue>(), journal);
if (!isTesSuccess(ter))
return ter; // LCOV_EXCL_LINE
return tesSUCCESS;
}
template <>
inline TER
escrowLockApplyHelper<MPTIssue>(
ApplyView& view,
AccountID const& issuer,
AccountID const& sender,
STAmount const& amount,
beast::Journal journal)
{
// Defensive: Issuer cannot create an escrow
if (issuer == sender)
return tecINTERNAL; // LCOV_EXCL_LINE
auto const ter = lockEscrowMPT(view, sender, amount, journal);
if (!isTesSuccess(ter))
return ter; // LCOV_EXCL_LINE
return tesSUCCESS;
}
template <ValidIssueType T>
TER
escrowUnlockPreclaimHelper(
ReadView const& view,
AccountID const& account,
STAmount const& amount,
bool checkFreeze = true);
template <>
inline TER
escrowUnlockPreclaimHelper<Issue>(
ReadView const& view,
AccountID const& account,
STAmount const& amount,
bool checkFreeze)
{
AccountID const& issuer = amount.getIssuer();
// If the issuer is the same as the account, return tesSUCCESS
if (issuer == account)
return tesSUCCESS;
// If the issuer has requireAuth set, check if the destination is authorized
if (auto const ter = requireAuth(view, amount.get<Issue>(), account); !isTesSuccess(ter))
return ter;
// If the issuer has deep frozen the destination, return tecFROZEN
if (checkFreeze &&
isDeepFrozen(view, account, amount.get<Issue>().currency, amount.getIssuer()))
return tecFROZEN;
return tesSUCCESS;
}
template <>
inline TER
escrowUnlockPreclaimHelper<MPTIssue>(
ReadView const& view,
AccountID const& account,
STAmount const& amount,
bool checkFreeze)
{
AccountID const& issuer = amount.getIssuer();
// If the issuer is the same as the account, return tesSUCCESS
if (issuer == account)
return tesSUCCESS;
// If the mpt does not exist, return tecOBJECT_NOT_FOUND
auto const issuanceKey = keylet::mptokenIssuance(amount.get<MPTIssue>().getMptID());
auto const sleIssuance = view.read(issuanceKey);
if (!sleIssuance)
return tecOBJECT_NOT_FOUND;
// If the issuer has requireAuth set, check if the account is
// authorized
auto const& mptIssue = amount.get<MPTIssue>();
if (auto const ter = requireAuth(view, mptIssue, account, AuthType::WeakAuth);
!isTesSuccess(ter))
return ter;
// If the issuer has frozen the account, return tecLOCKED
if (checkFreeze && isFrozen(view, account, *sleIssuance))
return tecLOCKED;
return tesSUCCESS;
}
//------------------------------------------------------------------------------
template <ValidIssueType T>
TER
@@ -81,9 +342,6 @@ escrowUnlockApplyHelper<Issue>(
bool createAsset,
beast::Journal journal)
{
auto const& issue = amount.get<Issue>();
Keylet const trustLineKey = keylet::trustLine(receiver, issue);
bool const recvLow = issuer > receiver;
bool const senderIssuer = issuer == sender;
bool const receiverIssuer = issuer == receiver;
@@ -93,20 +351,25 @@ escrowUnlockApplyHelper<Issue>(
if (receiverIssuer)
return tesSUCCESS;
auto const& issue = amount.get<Issue>();
Keylet const trustLineKey = keylet::trustLine(receiver, issue);
bool const recvLow = issuer > receiver;
if (!ctx.view.exists(trustLineKey) && createAsset)
{
// Can the account cover the trust line's reserve?
if (sleDest->getType() != ltACCOUNT_ROOT)
return detail::escrowDestNotAccountResult(ctx, sleDest);
auto const destSle = AccountRootEntryR(sleDest, ctx.view, journal);
auto sponsorSle = getEffectiveTxReserveSponsor(ctx, destSle);
auto const sponsorSle = getEffectiveTxReserveSponsor(ctx, sleDest);
if (!sponsorSle)
return sponsorSle.error(); // LCOV_EXCL_LINE
auto& sponsor = *sponsorSle;
if (auto const ret = destSle.checkReserve(
ctx, xrpBalance, sponsor, {.ownerCountDelta = 1}, tecNO_LINE_INSUF_RESERVE);
if (auto const ret = checkReserve(
ctx,
sleDest,
xrpBalance,
*sponsorSle,
{.ownerCountDelta = 1},
journal,
tecNO_LINE_INSUF_RESERVE);
!isTesSuccess(ret))
{
JLOG(journal.trace()) << "Trust line does not exist. "
@@ -119,22 +382,22 @@ escrowUnlockApplyHelper<Issue>(
initialBalance.get<Issue>().account = noAccount();
if (TER const ter = trustCreate(
ctx.view, // payment sandbox
recvLow, // is dest low?
issuer, // source
receiver, // destination
trustLineKey.key, // ledger index
sleDest, // Account to add to
false, // authorize account
!sleDest->isFlag(lsfDefaultRipple), //
false, // freeze trust line
false, // deep freeze trust line
initialBalance, // zero initial balance
Issue(currency, receiver), // limit of zero
0, // quality in
0, // quality out
sponsor ? sponsor->mutableRawSle() : SLE::pointer(), // sponsor
journal); // journal
ctx.view, // payment sandbox
recvLow, // is dest low?
issuer, // source
receiver, // destination
trustLineKey.key, // ledger index
sleDest, // Account to add to
false, // authorize account
!sleDest->isFlag(lsfDefaultRipple), //
false, // freeze trust line
false, // deep freeze trust line
initialBalance, // zero initial balance
Issue(currency, receiver), // limit of zero
0, // quality in
0, // quality out
*sponsorSle, // sponsor
journal); // journal
!isTesSuccess(ter))
{
return ter; // LCOV_EXCL_LINE
@@ -229,29 +492,23 @@ escrowUnlockApplyHelper<MPTIssue>(
auto const mptKeylet = keylet::mptoken(issuanceKey.key, receiver);
if (!ctx.view.exists(mptKeylet) && createAsset && !receiverIssuer)
{
if (sleDest->getType() != ltACCOUNT_ROOT)
return detail::escrowDestNotAccountResult(ctx, sleDest);
auto const destSle = AccountRootEntryR(sleDest, ctx.view, journal);
auto sponsorSle = getEffectiveTxReserveSponsor(ctx, destSle);
auto const sponsorSle = getEffectiveTxReserveSponsor(ctx, sleDest);
if (!sponsorSle)
return sponsorSle.error(); // LCOV_EXCL_LINE
auto& sponsor = *sponsorSle;
if (auto const ret = destSle.checkReserve(ctx, xrpBalance, sponsor, {.ownerCountDelta = 1});
if (auto const ret = checkReserve(
ctx, sleDest, xrpBalance, *sponsorSle, {.ownerCountDelta = 1}, journal);
!isTesSuccess(ret))
return ret;
if (auto const ter = createMPToken(
ctx.view, mptID, receiver, sponsor ? sponsor->mutableRawSle() : SLE::pointer(), 0);
if (auto const ter = createMPToken(ctx.view, mptID, receiver, *sponsorSle, 0);
!isTesSuccess(ter))
{
return ter; // LCOV_EXCL_LINE
}
// update owner count.
AccountRootEntryW receiverSle(receiver, ctx.view, journal);
receiverSle.increaseOwnerCount(sponsor, 1);
increaseOwnerCount(ctx.view, sleDest, *sponsorSle, 1, journal);
}
if (!ctx.view.exists(mptKeylet) && !receiverIssuer)

View File

@@ -7,10 +7,10 @@
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/helpers/VaultHelpers.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Asset.h>
#include <xrpl/protocol/LedgerFormats.h> // IWYU pragma: keep
#include <xrpl/protocol/Protocol.h>
#include <xrpl/protocol/Rules.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/STAmount.h>
@@ -31,9 +31,9 @@ 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
* 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.
*
@@ -44,8 +44,8 @@ namespace xrpl {
* @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.
* @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(
@@ -56,6 +56,82 @@ canApplyToBrokerCover(
beast::Journal j,
std::string_view logPrefix);
namespace detail {
/**
* Return a LoanBroker's posterior live cover exponent after applying an
* unrounded delta.
*/
[[nodiscard]] int
getPosteriorBrokerCoverScale(SLE::ConstRef vault, SLE::ConstRef broker, Number const& delta);
/**
* Round a cover outflow delta (cover withdraw, cover clawback, the
* broker-side decrease of a default's cover credit) at the LoanBroker's
* posterior live exponent. Safe to round the delta directly for an outflow:
* amount on the posterior grid of CoverAvailable always leaves CoverAvailable
* minus amount representable, since the posterior grid is exactly the grid
* CoverAvailable itself will canonicalize to after the subtraction.
*/
[[nodiscard]] STAmount
roundToPosteriorBrokerCoverScale(
SLE::ConstRef vault,
SLE::ConstRef broker,
STAmount const& delta,
Number::RoundingMode roundingMode);
} // namespace detail
/**
* Round a cover debit (cover withdraw, cover clawback, the broker-side
* decrease of a default's cover credit): amount is the non-negative
* magnitude leaving CoverAvailable. Negates so the posterior is computed for
* CoverAvailable minus amount, then negates the result back to a
* non-negative magnitude, per roundToPosteriorBrokerCoverScale's outflow
* rationale above. Magnitude in, magnitude out -- unlike the vault-side
* outflow dispatcher (clampVaultOutflow), which takes and returns a negative
* delta; callers on each side already hold the value in that side's native
* form.
*/
[[nodiscard]] STAmount
debitToPosteriorBrokerCoverScale(
SLE::ConstRef vault,
SLE::ConstRef broker,
STAmount const& amount,
Number::RoundingMode roundingMode);
/**
* Round a cover inflow (cover deposit, LoanPay's fee redirect into cover)
* into CoverAvailable by flooring the sum rather than the delta:
* credit = floor16(CoverAvailable + raw) - CoverAvailable, never finer
* than the Vault's base exponent (-Scale). See
* creditToPosteriorAvailableScale's doc for why the sum, not the delta,
* must be floored; the same reasoning applies to CoverAvailable.
*/
[[nodiscard]] STAmount
creditToPosteriorBrokerCoverScale(
SLE::ConstRef vault,
SLE::ConstRef broker,
Number const& raw,
Number::RoundingMode roundingMode);
/**
* Check whether amount is an admissible optional cover inflow.
*
* Legacy and CashBasis Vaults always succeed. A LoanBroker attached to a
* FixedPrecision Vault must remain at the Vault's base scale after applying
* the rounded amount, and its posterior CoverAvailable must stay within the
* Open zone.
*
* LoanPay's fee redirect into cover is a mandatory inflow and does not call
* this check, so it can push CoverAvailable past the Open zone limit this
* check enforces. Once that happens, every subsequent LoanBrokerCoverDeposit
* returns tecLIMIT_EXCEEDED until the owner withdraws cover back under the
* limit; LoanBrokerCoverWithdraw and LoanBrokerCoverClawback are unaffected.
*/
[[nodiscard]] TER
checkOptionalBrokerCoverInflow(SLE::ConstRef vault, SLE::ConstRef broker, STAmount const& amount);
// Lending protocol has dependencies, so capture them here.
bool
checkLendingProtocolDependencies(Rules const& rules, STTx const& tx);
@@ -64,13 +140,13 @@ checkLendingProtocolDependencies(Rules const& rules, STTx const& tx);
* The accounts and asset that LoanManage::defaultLoan's fixCleanup3_4_0
* freeze/lock exemption applies to.
*
* `defaultLoan` moves funds from the LoanBroker pseudo-account to the Vault
* pseudo-account via `accountSend`. Since neither is the vault asset's
* defaultLoan moves funds from the LoanBroker pseudo-account to the Vault
* pseudo-account via accountSend. Since neither is the vault asset's
* issuer, this is a third-party transfer that transits through the issuer in
* two hops (broker -> issuer, issuer -> vault; see
* `directSendNoLimitIOU`/`directSendNoLimitMPT`), so the exemption must cover
* directSendNoLimitIOU/directSendNoLimitMPT), so the exemption must cover
* both the issuer/broker and issuer/vault pairs, not a direct broker/vault
* pair. `asset` scopes it further to the vault's own currency/MPT issuance,
* pair. asset scopes it further to the vault's own currency/MPT issuance,
* so an unrelated one the same accounts happen to hold is still protected.
*/
struct LoanDefaultFreezeExemptAccounts
@@ -88,10 +164,10 @@ struct LoanDefaultFreezeExemptAccounts
* @param view Ledger view used to resolve the Loan -> LoanBroker -> Vault
* chain.
* @param tx The transaction under invariant review.
* @return The exempt accounts and asset if `tx` is a `ttLOAN_MANAGE`
* transaction with the `tfLoanDefault` flag set, `fixCleanup3_4_0` is
* @return The exempt accounts and asset if tx is a ttLOAN_MANAGE
* transaction with the tfLoanDefault flag set, fixCleanup3_4_0 is
* enabled, and the loan/broker/vault objects it references can all be
* resolved; `std::nullopt` otherwise.
* resolved; std::nullopt otherwise.
*/
[[nodiscard]] std::optional<LoanDefaultFreezeExemptAccounts>
getLoanDefaultFreezeExemptAccounts(ReadView const& view, STTx const& tx);
@@ -262,20 +338,38 @@ getAssetsTotalScale(SLE::ConstRef 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::ConstRef 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));
}
/**
* Apply a signed delta to a LoanBroker's DebtTotal: on FixedPrecision Vaults,
* add the exact delta (DebtTotal moves by exactly the same amount as the
* Vault's AssetsDeployed, never re-rounded); on Legacy/CashBasis Vaults,
* round through adjustImpreciseNumber at vaultScale. Shared by LoanSet
* (origination) and LoanPay (payment, where delta is negative).
*
* @param brokerSle The LoanBroker whose DebtTotal is adjusted.
* @param vaultSle The LoanBroker's Vault.
* @param delta The signed change to DebtTotal.
* @param vaultScale The Vault scale the caller captured before changing
* AssetsTotal. Legacy/CashBasis round DebtTotal at that scale, not at
* the scale after this transaction's AssetsTotal change. Unused on
* FixedPrecision Vaults.
*/
void
adjustBrokerDebtTotal(
SLE::Ref brokerSle,
SLE::ConstRef vaultSle,
Number const& delta,
int vaultScale);
/**
* Minimum required broker cover, rounded up.
*
* DebtTotal is a broker-level aggregate, never rounded at an individual
* loan's scale. Legacy and CashBasis Vaults round at the live AssetsTotal
* exponent. FixedPrecision Vaults round at the Vault's base exponent
* (-Scale, or 0 for integral assets).
*/
Number
minimumBrokerCover(Number const& debtTotal, TenthBips32 coverRateMinimum, SLE::ConstRef vaultSle);
TER
checkLoanGuards(
@@ -379,10 +473,10 @@ loanPaymentDeltas(LoanPaymentParts const& parts);
} // namespace cash_basis
// Public dispatchers: pick cash_basis:: if featureLendingProtocolV1_1 is
// enabled AND the Vault's LEVersion (VaultHelpers::getVaultVersion) is
// VaultVersion::CashBasis, else instant_recognition::. These are the only entry points
// transactors call.
// Public dispatchers: pick cash_basis:: if the Vault's LEVersion
// (VaultHelpers::getVaultVersion) is CashBasis or later (CashBasis or
// FixedPrecision), else instant_recognition::. These are the only entry
// points transactors call.
AccountingDeltas
loanOriginationDeltas(
SLE::ConstRef vaultSle,

View File

@@ -2,7 +2,6 @@
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/AccountRootEntry.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/STLedgerEntry.h>
@@ -55,11 +54,11 @@ getTxReserveSponsorID(STTx const& tx);
* Return a mutable SLE for the transaction's reserve sponsor account.
*
* @param ctx The apply-view context (view + tx)
* @return The sponsor account entry, nullopt if the tx is not
* @return The sponsor account SLE, a null pointer if the tx is not
* reserve-sponsored, or tecINTERNAL if the sponsor account cannot
* be loaded (an already-checked invariant).
*/
std::expected<std::optional<AccountRootEntryW>, TER>
std::expected<SLE::pointer, TER>
getTxReserveSponsor(ApplyViewContext ctx);
/**
@@ -67,29 +66,29 @@ getTxReserveSponsor(ApplyViewContext ctx);
*
* @param view The ledger read view
* @param tx The transaction to inspect
* @return The sponsor account entry, nullopt if the tx is not
* @return The sponsor account SLE, a null pointer if the tx is not
* reserve-sponsored, or tecINTERNAL if the sponsor account cannot
* be loaded (an already-checked invariant).
*/
std::expected<std::optional<AccountRootEntryR>, TER>
std::expected<SLE::const_pointer, TER>
getTxReserveSponsor(ReadView const& view, STTx const& tx);
/**
* The transaction's reserve sponsor for the given account, if applicable.
*
* A reserve sponsor only covers the transaction submitter's own objects, so
* this returns the tx reserve sponsor entry only when accountSle is the tx's
* own (non-pseudo) account; otherwise it returns nullopt. This is
* this returns the tx reserve sponsor SLE only when accountSle is the tx's own
* (non-pseudo) account; otherwise it returns a null sponsor pointer. This is
* the single source of truth for the "sponsor applies to tx.Account only" rule
* that the sponsor-deriving helper overloads in AccountRootHelpers rely on.
*
* @param ctx The apply-view context (view + tx)
* @param accountSle The account whose sponsor is being resolved
* @return The sponsor entry (nullopt if unsponsored), or tecINTERNAL if the
* @return The sponsor SLE (nullptr if unsponsored), or tecINTERNAL if the
* sponsor account cannot be loaded (an already-checked invariant)
*/
[[nodiscard]] std::expected<std::optional<AccountRootEntryW>, TER>
getEffectiveTxReserveSponsor(ApplyViewContext ctx, AccountRootEntryR const& accountSle);
[[nodiscard]] std::expected<SLE::pointer, TER>
getEffectiveTxReserveSponsor(ApplyViewContext ctx, SLE::ConstRef accountSle);
/**
* Return the AccountID stored in the given sponsor field of a ledger entry, or nullopt if absent.
@@ -106,9 +105,9 @@ getLedgerEntryReserveSponsorID(SLE::ConstRef sle, SF_ACCOUNT const& field = sfSp
* @param view The mutable apply view
* @param sle The ledger entry whose sponsor field is inspected
* @param field The field that holds the sponsor AccountID (defaults to sfSponsor)
* @return The sponsor account entry, or nullopt if the entry is unsponsored.
* @return The sponsor account SLE, or a null pointer if the entry is unsponsored.
*/
std::optional<AccountRootEntryW>
SLE::pointer
getLedgerEntryReserveSponsor(
ApplyView& view,
SLE::ConstRef sle,

View File

@@ -1,10 +1,12 @@
#pragma once
#include <xrpl/basics/Number.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Asset.h>
#include <xrpl/protocol/Protocol.h>
#include <xrpl/protocol/Rules.h>
#include <xrpl/protocol/STAmount.h>
#include <xrpl/protocol/STLedgerEntry.h>
#include <xrpl/protocol/TER.h>
@@ -12,11 +14,237 @@
#include <cstdint>
#include <expected>
#include <optional>
#include <string_view>
namespace xrpl {
class STTx;
/**
* @brief Return the Vault's current assets total.
*
* FixedPrecision Vaults return AssetsAvailable plus AssetsDeployed, with no
* rounding to the asset's 16-digit precision: the sum is exact at Number's
* active 19-digit mantissa width (the large mantissa range, enabled by
* featureSingleAssetVault or featureLendingProtocol), rounds Downward regardless of the
* caller's ambient mode beyond that, and is not rounded to match the cached
* sfAssetsTotal field. Legacy and CashBasis Vaults return the stored
* AssetsTotal.
*
* @param vault The vault SLE.
* @return The current assets total.
*/
[[nodiscard]] Number
getAssetsTotal(SLE::ConstRef vault);
/**
* @brief A change to a FixedPrecision Vault's balances.
*/
struct VaultBalanceChange
{
/**
* Signed change to AssetsAvailable. Must be the exact amount moved on the
* Vault pseudo-account in the same transaction. Absent means no cash
* moved; adjustVaultBalances then uses zero of the Vault's own asset.
*/
std::optional<STAmount> cash = std::nullopt;
/**
* Signed change to AssetsDeployed: open Loan principal, exact.
*/
Number deployed = 0;
/**
* Signed change to scheduled, unpaid interest (YieldUnrealized), exact.
*/
Number yield = 0;
/**
* Signed change to impaired principal (LossUnrealized), exact.
*/
Number loss = 0;
};
/**
* @brief Apply a balance change to a FixedPrecision Vault. The only writer of
* AssetsAvailable, AssetsDeployed, AssetsTotal, YieldUnrealized and
* LossUnrealized on these Vaults after creation.
*
* @param vault The vault SLE. Must be FixedPrecision.
* @param change The balance change to apply.
* @param j Journal for logging the fatal (tefBAD_LEDGER) case.
*
* @return tesSUCCESS; tecLIMIT_EXCEEDED if LossUnrealized would exceed
* AssetsDeployed; tefBAD_LEDGER if AssetsAvailable, AssetsDeployed,
* LossUnrealized or YieldUnrealized would become negative.
*/
[[nodiscard]] TER
adjustVaultBalances(SLE::Ref vault, VaultBalanceChange const& change, beast::Journal j);
/**
* @brief Apply a signed cash movement to a Vault of any version. FixedPrecision
* Vaults go through adjustVaultBalances; Legacy and CashBasis Vaults add the
* amount to both AssetsTotal and AssetsAvailable.
*
* @param vault The vault SLE.
* @param delta Signed change to AssetsAvailable; the exact amount moved on the
* Vault pseudo-account.
* @param j Journal passed through to adjustVaultBalances.
*
* @return tesSUCCESS, or the adjustVaultBalances error for FixedPrecision Vaults.
*/
[[nodiscard]] TER
adjustVaultCash(SLE::Ref vault, STAmount const& delta, beast::Journal j);
/**
* Return the Vault's current live exponent.
*
* Legacy and CashBasis Vaults use the exponent of AssetsTotal. FixedPrecision
* Vaults use max(base exponent, exponent of AssetsTotal): the grid is never
* finer than -Scale and coarsens once AssetsTotal outgrows 16 digits there.
*/
[[nodiscard]] int
getVaultScale(SLE::ConstRef vault);
/**
* Return the Vault's base exponent.
*
* Legacy and CashBasis Vaults use their current live exponent. FixedPrecision
* Vaults use -Scale, or 0 for integral assets.
*/
[[nodiscard]] int
getVaultBaseScale(SLE::ConstRef vault);
/**
* Round an amount at the Vault's posterior live exponent.
*/
[[nodiscard]] STAmount
roundToPosteriorVaultScale(
SLE::ConstRef vault,
STAmount const& amount,
Number::RoundingMode roundingMode);
namespace detail {
/**
* Return the Vault's posterior live exponent after applying an unrounded delta.
*/
[[nodiscard]] int
getPosteriorVaultScale(SLE::ConstRef vault, STAmount const& delta);
/**
* Shared grid-floor core of getVaultScale / getPosteriorVaultScale /
* getPosteriorBrokerCoverScale: baseScale when reference is zero, otherwise
* max(baseScale, scale(reference, asset)), rounded Downward regardless of
* the caller's ambient rounding mode.
*/
[[nodiscard]] int
liveScale(Number const& reference, Asset const& asset, int baseScale);
/**
* Shared core of getPosteriorVaultScale and getPosteriorBrokerCoverScale:
* the exponent reference + delta would have under version's live-scale rule
* (floored at baseScale for FixedPrecision, unbounded for Legacy/CashBasis).
*
* @param version The Vault's LEVersion.
* @param asset The Vault's underlying asset.
* @param baseScale The Vault's base exponent; unused outside the
* FixedPrecision case.
* @param reference The balance the delta is applied to (AssetsAvailable,
* AssetsTotal, or a LoanBroker's CoverAvailable).
* @param delta The unrounded change to reference.
*/
[[nodiscard]] int
posteriorAssetScale(
VaultVersion version,
Asset const& asset,
int baseScale,
Number const& reference,
Number const& delta);
/**
* Shared core of creditToPosteriorAvailableScale and
* creditToPosteriorBrokerCoverScale: floors reference + raw at scale and
* returns the difference from reference, so the delta applied is exactly
* what moves reference onto the floored sum. See
* creditToPosteriorAvailableScale's doc for why the sum, not raw alone,
* must be floored. raw is the exact amount; it is not rounded on its own
* before being added to reference.
*/
[[nodiscard]] STAmount
creditToPosteriorScale(
Asset const& asset,
Number const& reference,
int atScale,
Number const& raw,
Number::RoundingMode roundingMode);
} // namespace detail
/**
* Round a FixedPrecision cash inflow (LoanPay's credit, LoanManage's
* default cover credit) into AssetsAvailable, never AssetsTotal, which is
* a derived cache, by flooring the sum rather than the delta:
* credit equals floor16(AssetsAvailable + raw) minus AssetsAvailable, never
* finer than the Vault's base exponent (-Scale).
*
* Flooring only the delta at its own posterior grid is not enough: the sum
* can still need a 17th digit when AssetsAvailable is off the coarser grid
* right after crossing a power of ten. Example at Scale 6: AssetsAvailable
* equals 9999999999.999999 (16 digits already) and a credit of 0.000011
* floors to 0.00001 on its own (finer) grid, but 9999999999.999999 plus
* 0.00001 equals 10000000000.000009, which still needs 17 digits. Flooring
* the sum instead, floor16(9999999999.999999 + 0.000011) minus
* 9999999999.999999, is exact by construction, since STAmount's own
* 16-digit canonical form of the sum is what gets subtracted from.
*
* raw is taken as an exact Number: rounding it to 16 digits before adding
* it to AssetsAvailable could drop a tail that moves the floored sum.
*/
[[nodiscard]] STAmount
creditToPosteriorAvailableScale(
SLE::ConstRef vault,
Number const& raw,
Number::RoundingMode roundingMode);
/**
* Open-zone capacity ceiling: 9 * 10^(15 + baseScale).
*
* Defined only for FixedPrecision Vaults, where this is 9 * 10^(15 - P).
*/
[[nodiscard]] Number
getVaultOpenLimit(SLE::ConstRef vault);
/**
* Check whether amount is an admissible optional inflow.
*
* Legacy and CashBasis Vaults always succeed. FixedPrecision Vaults must
* remain at their base scale after applying the rounded amount, and the
* posterior capacity (AssetsTotal + YieldUnrealized + rounded amount) must
* stay within the Open zone.
*
* The amount is rounded toward zero at the posterior live exponent.
*/
[[nodiscard]] TER
checkOptionalVaultInflow(SLE::ConstRef vault, STAmount const& amount);
/**
* Open-zone capacity after adding roundedAmount: AssetsTotal + YieldUnrealized
* + roundedAmount, computed TowardsZero regardless of the caller's ambient
* rounding mode. Defined only for FixedPrecision Vaults.
*
* Shared by checkOptionalVaultInflow and LoanSet's loan-origination capacity
* check, which pair this formula with different scale checks (posterior vs.
* current), so only the capacity formula itself -- not the whole check -- is
* shared here.
*
* @param vault The vault SLE. Must be FixedPrecision.
* @param roundedAmount The amount to add, already rounded to the relevant
* posterior or base scale by the caller.
*/
[[nodiscard]] Number
vaultOpenZoneCapacity(SLE::ConstRef vault, Number const& roundedAmount);
/**
* From the perspective of a vault, return the number of shares to give
* depositor when they offer a fixed amount of assets. Note, since shares are
@@ -46,31 +274,92 @@ assetsToSharesDeposit(SLE::ConstRef vault, SLE::ConstRef issuance, STAmount cons
sharesToAssetsDeposit(SLE::ConstRef vault, SLE::ConstRef issuance, STAmount const& shares);
/**
* Adjusts a requested asset change (`delta`) to match the decimal scale of the
* updated total vault assets. This ensures `sfAssetsTotal`, `sfAssetsAvailable`,
* Adjusts a requested asset change (delta) to match the decimal scale of the
* updated total vault assets. This ensures sfAssetsTotal, sfAssetsAvailable,
* and the actual asset transfer change by the exact same representable amount.
*
* Rounding strategy:
* - Debits (withdrawals): Rounds down `|delta|` on the new scale to prevent
* paying out more than requested.
* - Credits (deposits): Floors the resulting total asset balance and returns the
* difference from the current total. This prevents crediting the vault with
* more assets than the user deposited.
* - Legacy/CashBasis debits (withdrawals): rounds down the magnitude of delta
* on the new scale to prevent paying out more than requested.
* - Legacy/CashBasis credits: floors the resulting total asset balance and
* returns the difference from the current total.
* - FixedPrecision credits only (VaultDeposit): rounds the delta toward zero
* at the scale getAssetsTotal (AssetsAvailable + AssetsDeployed, derived,
* not the stored AssetsTotal cache) would have after applying delta.
* FixedPrecision outflows (VaultWithdraw, VaultClawback) never call this;
* they use clampVaultOutflow instead.
*
* Key rules:
* - The returned magnitude never exceeds `|delta|`.
* - Returns `tecPRECISION_LOSS` if the change is smaller than 1 ULP of the target scale
* - The returned magnitude never exceeds the magnitude of delta.
* - Returns tecPRECISION_LOSS if the change is smaller than 1 ULP of the target scale
* (prevents share operations when totals cannot change).
* - For integer assets (XRP, MPT), rounding is a no-op.
*
* @param vault The vault ledger entry.
* @param delta The requested signed change to sfAssetsTotal.
* @return The rounded, positive magnitude, or `tecPRECISION_LOSS` if the
* @return The rounded, positive magnitude, or tecPRECISION_LOSS if the
* change is below representable precision.
*/
[[nodiscard]] std::expected<STAmount, TER>
clampToAssetsTotalScale(SLE::ConstRef vault, STAmount const& delta);
/**
* Outflow clamp dispatcher for VaultWithdraw and VaultClawback: rounds a
* negative delta to the scale appropriate for the Vault's version -- for
* FixedPrecision, at AssetsAvailable's own posterior scale (the balance the
* cash actually leaves); for Legacy/CashBasis, clampToAssetsTotalScale --
* so both call sites share one dispatch point. Same tecPRECISION_LOSS and
* integral-asset and magnitude-never-exceeds-delta rules as
* clampToAssetsTotalScale.
*
* @param vault The vault ledger entry.
* @param delta The requested signed outflow (negative).
* @return The rounded, positive magnitude, or tecPRECISION_LOSS if the
* change is below representable precision.
*/
[[nodiscard]] std::expected<STAmount, TER>
clampVaultOutflow(SLE::ConstRef vault, STAmount const& delta);
/**
* Returns the Vault's base exponent for asset at scale, before a Vault
* object exists to read it from: 0 for an integral asset, -scale otherwise.
* Used by VaultCreate::preclaim, which only has the proposed Scale field,
* not yet a Vault SLE; getVaultBaseScale is the post-creation equivalent.
*
* @param asset The (prospective) Vault's underlying asset.
* @param scale The (prospective) Vault's sfScale value, ignored for
* integral assets.
*/
[[nodiscard]] int
vaultBaseScale(Asset const& asset, std::uint8_t scale);
/**
* Returns true iff value is exactly representable both as an STAmount of
* asset and on the base grid at baseScale (no precision lost rounding
* TowardsZero at baseScale). Shared representability check for
* VaultCreate::preclaim, VaultSet::preclaim and LoanBrokerSet::preclaim's
* AssetsMaximum / DebtMaximum / cover-rate field checks.
*
* @param asset The vault's underlying asset.
* @param value The value to check.
* @param baseScale The vault's base exponent (see vaultBaseScale /
* getVaultBaseScale).
*/
[[nodiscard]] bool
isOnVaultBaseGrid(Asset const& asset, Number const& value, int baseScale);
/**
* Checks that a requested AssetsMaximum is exactly representable on the
* Vault's base grid, otherwise associateAsset would silently round the cap
* the owner asked for. Used by VaultSet::preclaim on an existing Vault.
*
* @param vault The vault ledger entry.
* @param amount The requested AssetsMaximum.
* @return tesSUCCESS, or tecPRECISION_LOSS if amount is not representable.
*/
[[nodiscard]] TER
checkAssetsMaximum(SLE::ConstRef vault, Number const& amount);
/**
* Controls whether to truncate shares instead of rounding.
*/
@@ -98,21 +387,24 @@ enum class WaiveUnrealizedLoss : bool { No = false, Yes = true };
assetsTotalForWithdrawal(SLE::ConstRef vault, WaiveUnrealizedLoss waive);
/**
* Returns true if debiting `amount` from `total` (the current value of a
* vault's sfAssetsTotal or sfAssetsAvailable) would canonicalize to the
* same STAmount value. This happens when `amount` is non-zero but too small
* to change the stored total at STAmount's precision. Shares would still
* move, so the ValidVault invariant would fail after apply; callers use
* this to reject the transaction upfront instead.
* Reject a cash outflow that is dust (see debitIsNonZeroDust) or whose check
* overflows Number, which is easy to hit with a large Scale.
*
* @param asset The vault's underlying asset, used to canonicalize both
* sides the same way the ledger will when the field is stored.
* @param total The field's current value.
* @param amount The amount to debit. Zero always returns false; that case
* is rejected separately.
* @param vault The vault SLE.
* @param amount The amount to debit.
* @param j Journal for the debug log.
* @param name Transaction name used as the log prefix.
*
* @return tesSUCCESS; tecPRECISION_LOSS if amount is dust; tecPATH_DRY if the
* check overflows. Overflow means the transaction cannot apply, but
* ledger state is still consistent.
*/
[[nodiscard]] bool
debitIsNonZeroDust(Asset const& asset, Number const& total, Number const& amount);
[[nodiscard]] TER
checkDebitNotDust(
SLE::ConstRef vault,
Number const& amount,
beast::Journal j,
std::string_view name);
/**
* From the perspective of a vault, return the number of shares to demand from
@@ -158,7 +450,7 @@ sharesToAssetsWithdraw(
WaiveUnrealizedLoss waive = WaiveUnrealizedLoss::No);
/**
* Returns true iff `account` holds all of the vault's outstanding shares —
* 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.
*
@@ -171,11 +463,13 @@ sharesToAssetsWithdraw(
isSoleShareholder(ReadView const& view, AccountID const& account, SLE::ConstRef issuance);
/**
* Resolves a Vault's LEVersion, the single point every accounting touch
* point should call to determine which recognition model (instant interest
* recognition vs. cash-basis) a Vault uses. Vaults created before featureLendingProtocolV1_1
* activated never have sfLEVersion set, which resolves here to
* VaultVersion::Legacy.
* Resolves a Vault's LEVersion.
*
* LEVersion is the single point every accounting and rounding helper
* should call to decide which protocol a Vault follows. It is written
* at VaultCreate and is not updated afterwards, so a Vault created
* under an older amendment keeps that behaviour after later amendments
* activate. Absent sfLEVersion resolves to VaultVersion::Legacy.
*
* @param vault The vault SLE.
*
@@ -185,6 +479,34 @@ isSoleShareholder(ReadView const& view, AccountID const& account, SLE::ConstRef
[[nodiscard]] VaultVersion
getVaultVersion(SLE::ConstRef vault);
/**
* Decodes an already-extracted sfLEVersion value with the same range check as
* getVaultVersion. Usable from contexts, such as an invariant's ledger-entry
* snapshot, that keep the field value but not the owning SLE.
*
* @param leVersion The value of sfLEVersion, or nullopt if absent.
*
* @return The decoded LEVersion, or VaultVersion::Legacy if absent.
*/
[[nodiscard]] VaultVersion
decodeVaultVersion(std::optional<std::uint8_t> leVersion);
/**
* Resolves which LEVersion a newly-created Vault should get under the
* currently active amendments. This is the only place that decides Vault
* version policy; VaultCreate calls it instead of checking amendments
* directly.
*
* @param rules The active ledger rules.
*
* @return VaultVersion::FixedPrecision once featureLendingProtocolV1_1,
* featureLendingProtocolV1_2 and fixCleanup3_4_0 are all enabled;
* VaultVersion::CashBasis
* once featureLendingProtocolV1_1 is enabled; VaultVersion::Legacy otherwise.
*/
[[nodiscard]] VaultVersion
vaultVersionFor(Rules const& rules);
/**
* Resolves the VaultKind of a vault SLE. Returns VaultKind::ClosedEnded when
* sfVaultKind is present and equal to that value; anything else (including an

View File

@@ -103,7 +103,7 @@ public:
void
asyncHandshake(HandshakeType type, Callback cbFunc)
{
if ((type == SslSocket::client) || (secure_))
if ((type == SslSocket::client) || secure_)
{
// must be ssl
secure_ = true;

View File

@@ -55,7 +55,7 @@ hash_append(Hasher& h, Book const& b)
using beast::hash_append;
hash_append(h, b.in, b.out);
if (b.domain)
hash_append(h, *(b.domain));
hash_append(h, *b.domain);
}
Book

View File

@@ -208,7 +208,10 @@ enum LedgerEntryType : std::uint16_t {
\
LEDGER_OBJECT(Sponsorship, \
LSF_FLAG(lsfSponsorshipRequireSignForFee, 0x00010000) \
LSF_FLAG(lsfSponsorshipRequireSignForReserve, 0x00020000))
LSF_FLAG(lsfSponsorshipRequireSignForReserve, 0x00020000)) \
\
LEDGER_OBJECT(LoanBroker, \
LSF_FLAG(lsfLoanBrokerPrivate, 0x00010000))
// clang-format on

View File

@@ -1,28 +0,0 @@
#pragma once
namespace xrpl {
/**
* @brief Enumeration of ledger shortcuts for specifying which ledger to use.
*
* These shortcuts provide a convenient way to reference commonly used ledgers
* without needing to specify their exact hash or sequence number.
*/
enum class LedgerShortcut {
/**
* The current working ledger (open, not yet closed)
*/
Current,
/**
* The most recently closed ledger (may not be validated)
*/
Closed,
/**
* The most recently validated ledger
*/
Validated
};
} // namespace xrpl

View File

@@ -311,24 +311,46 @@ constexpr std::uint8_t kVaultStrategyFirstComeFirstServe = 1;
* Default IOU scale factor for a Vault
*/
constexpr std::uint8_t kVaultDefaultIouScale = 6;
/**
* Maximum scale factor for a Vault. The number is chosen to ensure that
* 1 IOU can be always converted to shares.
* 10^19 > maxMPTokenAmount (2^64-1) > 10^18
*/
constexpr std::uint8_t kVaultMaximumIouScale = 18;
/**
* Vault ledger-entry schema versions. Assigned to newly created
* Vaults once featureLendingProtocolV1_1 is enabled. Vaults created before
* activation are left without LEVersion (implicit legacy version 0,
* instant interest recognition).
* Maximum Scale for a Vault created before featureLendingProtocolV1_2.
* Chosen so 1 IOU can always convert to shares:
* 10^19 > maxMPTokenAmount (2^64-1) > 10^18.
*/
constexpr std::uint8_t kVaultMaximumLegacyIouScale = 18;
/**
* Maximum Scale for a Vault created under featureLendingProtocolV1_2.
*/
constexpr std::uint8_t kVaultMaximumFixedPrecisionIouScale = 10;
/**
* Vault ledger-entry schema versions, persisted as sfLEVersion.
*
* LEVersion records which protocol a Vault was created under so later
* amendments can change the rules for new Vaults without rewriting
* existing ones. VaultCreate writes it from the then-active lending
* amendments; later transactions do not update it. A Vault created
* under an older amendment keeps that amendment's behaviour for its
* lifetime, even after a newer lending amendment activates.
*
* Absent sfLEVersion is implicit Legacy (version 0): instant interest
* recognition and a dynamic AssetsTotal scale. CashBasis (V1.1) uses
* cash-basis recognition on the same dynamic scale. FixedPrecision
* (V1.2) keeps cash-basis recognition and adds the lifetime base grid.
*/
enum class VaultVersion : uint8_t {
Legacy = 0,
CashBasis,
FixedPrecision,
};
// Code compares VaultVersion values with < and >= (e.g. "CashBasis or later"),
// so each later version must stay numerically larger than the one before.
static_assert(
VaultVersion::Legacy < VaultVersion::CashBasis &&
VaultVersion::CashBasis < VaultVersion::FixedPrecision);
/**
* Vault kind. Distinguishes closed-ended vaults from the default open-ended
* kind. Persisted as sfVaultKind (UINT8); absent means OpenEnded.

View File

@@ -457,9 +457,7 @@ private:
// The remove_cv and remove_reference are necessitated by the STBitString
// types. Their value() returns by const ref. We return those types
// by value.
template <
typename T,
typename V = std::remove_cv_t<std::remove_reference_t<decltype(std::declval<T>().value())>>>
template <typename T, typename V = std::remove_cvref_t<decltype(std::declval<T>().value())>>
V
getFieldByValue(SField const& field) const;

View File

@@ -252,7 +252,7 @@ public:
{
auto success = (offset + (Bits / 8)) <= data_.size();
if (success)
memcpy(data.begin(), &(data_.front()) + offset, (Bits / 8));
memcpy(data.begin(), &data_.front() + offset, (Bits / 8));
return success;
}

View File

@@ -449,7 +449,7 @@ public:
// Trait tells the requires-clause which types are allowed for construction.
template <typename T>
constexpr TERSubset(T rhs)
requires(Trait<std::remove_cv_t<std::remove_reference_t<T>>>::value)
requires(Trait<std::remove_cvref_t<T>>::value)
: code_(TERtoInt(rhs))
{
}

View File

@@ -226,6 +226,10 @@ inline constexpr FlagValue tfUniversalMask = ~tfUniversal;
TF_FLAG(tfLoanUnimpair, 0x00040000), \
MASK_ADJ(0)) \
\
TRANSACTION(LoanBrokerSet, \
TF_FLAG(tfLoanBrokerPrivate, 0x00010000), \
MASK_ADJ(0)) \
\
TRANSACTION(SponsorshipSet, \
TF_FLAG(tfSponsorshipSetRequireSignForFee, 0x00010000) \
TF_FLAG(tfSponsorshipClearRequireSignForFee, 0x00020000) \

View File

@@ -17,6 +17,7 @@
XRPL_FEATURE(Cosign, Supported::No, VoteBehavior::DefaultNo)
XRPL_FEATURE(SmartEscrow, Supported::No, VoteBehavior::DefaultNo)
// Requires LendingProtocolV1_1. New vaults take FixedPrecision plus cash-basis.
XRPL_FEATURE(LendingProtocolV1_2, Supported::No, VoteBehavior::DefaultNo)
XRPL_FIX (Cleanup3_5_0, Supported::Yes, VoteBehavior::DefaultNo)
XRPL_FEATURE(ConfidentialMPTKeyRotation, Supported::No, VoteBehavior::DefaultNo)

View File

@@ -514,6 +514,8 @@ LEDGER_ENTRY(ltVAULT, 0x0084, Vault, vault, ({
{sfAssetsAvailable, SoeDefault},
{sfAssetsMaximum, SoeDefault},
{sfLossUnrealized, SoeDefault},
{sfYieldUnrealized, SoeDefault},
{sfAssetsDeployed, SoeDefault},
{sfShareMPTID, SoeRequired},
{sfWithdrawalPolicy, SoeRequired},
{sfScale, SoeDefault},
@@ -549,6 +551,7 @@ LEDGER_ENTRY(ltLOAN_BROKER, 0x0088, LoanBroker, loan_broker, ({
{sfCoverAvailable, SoeDefault},
{sfCoverRateMinimum, SoeDefault},
{sfCoverRateLiquidation, SoeDefault},
{sfDomainID, SoeOptional},
}))
/** A ledger object representing a loan between a Borrower and a Loan Broker

View File

@@ -240,6 +240,8 @@ TYPED_SFIELD(sfPrincipalRequested, NUMBER, 14)
TYPED_SFIELD(sfTotalValueOutstanding, NUMBER, 15, SField::kSmdNeedsAsset | SField::kSmdDefault)
TYPED_SFIELD(sfPeriodicPayment, NUMBER, 16)
TYPED_SFIELD(sfManagementFeeOutstanding, NUMBER, 17, SField::kSmdNeedsAsset | SField::kSmdDefault)
TYPED_SFIELD(sfYieldUnrealized, NUMBER, 18, SField::kSmdNeedsAsset | SField::kSmdDefault)
TYPED_SFIELD(sfAssetsDeployed, NUMBER, 19, SField::kSmdNeedsAsset | SField::kSmdDefault)
// 32-bit signed (common)
TYPED_SFIELD(sfLoanScale, INT32, 1)

View File

@@ -900,6 +900,7 @@ TRANSACTION(ttLOAN_BROKER_SET, 74, LoanBrokerSet,
{sfDebtMaximum, SoeOptional},
{sfCoverRateMinimum, SoeOptional},
{sfCoverRateLiquidation, SoeOptional},
{sfDomainID, SoeOptional},
}))
/** This transaction deletes a Loan Broker */

View File

@@ -335,6 +335,30 @@ public:
{
return this->sle_->isFieldPresent(sfCoverRateLiquidation);
}
/**
* @brief Get sfDomainID (SoeOptional)
* @return The field value, or std::nullopt if not present.
*/
[[nodiscard]]
protocol_autogen::Optional<SF_UINT256::type::value_type>
getDomainID() const
{
if (hasDomainID())
return this->sle_->at(sfDomainID);
return std::nullopt;
}
/**
* @brief Check if sfDomainID is present.
* @return True if the field is present, false otherwise.
*/
[[nodiscard]]
bool
hasDomainID() const
{
return this->sle_->isFieldPresent(sfDomainID);
}
};
/**
@@ -578,6 +602,17 @@ public:
return *this;
}
/**
* @brief Set sfDomainID (SoeOptional)
* @return Reference to this builder for method chaining.
*/
LoanBrokerBuilder&
setDomainID(std::decay_t<typename SF_UINT256::type::value_type> const& value)
{
object_[sfDomainID] = value;
return *this;
}
/**
* @brief Build and return the completed LoanBroker wrapper.
* @param index The ledger entry index.

View File

@@ -242,6 +242,54 @@ public:
return this->sle_->isFieldPresent(sfLossUnrealized);
}
/**
* @brief Get sfYieldUnrealized (SoeDefault)
* @return The field value, or std::nullopt if not present.
*/
[[nodiscard]]
protocol_autogen::Optional<SF_NUMBER::type::value_type>
getYieldUnrealized() const
{
if (hasYieldUnrealized())
return this->sle_->at(sfYieldUnrealized);
return std::nullopt;
}
/**
* @brief Check if sfYieldUnrealized is present.
* @return True if the field is present, false otherwise.
*/
[[nodiscard]]
bool
hasYieldUnrealized() const
{
return this->sle_->isFieldPresent(sfYieldUnrealized);
}
/**
* @brief Get sfAssetsDeployed (SoeDefault)
* @return The field value, or std::nullopt if not present.
*/
[[nodiscard]]
protocol_autogen::Optional<SF_NUMBER::type::value_type>
getAssetsDeployed() const
{
if (hasAssetsDeployed())
return this->sle_->at(sfAssetsDeployed);
return std::nullopt;
}
/**
* @brief Check if sfAssetsDeployed is present.
* @return True if the field is present, false otherwise.
*/
[[nodiscard]]
bool
hasAssetsDeployed() const
{
return this->sle_->isFieldPresent(sfAssetsDeployed);
}
/**
* @brief Get sfShareMPTID (SoeRequired)
* @return The field value.
@@ -571,6 +619,28 @@ public:
return *this;
}
/**
* @brief Set sfYieldUnrealized (SoeDefault)
* @return Reference to this builder for method chaining.
*/
VaultBuilder&
setYieldUnrealized(std::decay_t<typename SF_NUMBER::type::value_type> const& value)
{
object_[sfYieldUnrealized] = value;
return *this;
}
/**
* @brief Set sfAssetsDeployed (SoeDefault)
* @return Reference to this builder for method chaining.
*/
VaultBuilder&
setAssetsDeployed(std::decay_t<typename SF_NUMBER::type::value_type> const& value)
{
object_[sfAssetsDeployed] = value;
return *this;
}
/**
* @brief Set sfShareMPTID (SoeRequired)
* @return Reference to this builder for method chaining.

View File

@@ -213,6 +213,32 @@ public:
{
return this->tx_->isFieldPresent(sfCoverRateLiquidation);
}
/**
* @brief Get sfDomainID (SoeOptional)
* @return The field value, or std::nullopt if not present.
*/
[[nodiscard]]
protocol_autogen::Optional<SF_UINT256::type::value_type>
getDomainID() const
{
if (hasDomainID())
{
return this->tx_->at(sfDomainID);
}
return std::nullopt;
}
/**
* @brief Check if sfDomainID is present.
* @return True if the field is present, false otherwise.
*/
[[nodiscard]]
bool
hasDomainID() const
{
return this->tx_->isFieldPresent(sfDomainID);
}
};
/**
@@ -336,6 +362,17 @@ public:
return *this;
}
/**
* @brief Set sfDomainID (SoeOptional)
* @return Reference to this builder for method chaining.
*/
LoanBrokerSetBuilder&
setDomainID(std::decay_t<typename SF_UINT256::type::value_type> const& value)
{
object_[sfDomainID] = value;
return *this;
}
/**
* @brief Build and return the LoanBrokerSet wrapper.
* @param publicKey The public key for signing.

View File

@@ -9,7 +9,6 @@
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/ErrorCodes.h>
#include <xrpl/protocol/LedgerHeader.h>
#include <xrpl/protocol/LedgerShortcut.h>
#include <xrpl/protocol/Protocol.h>
#include <xrpl/protocol/TxMeta.h>
#include <xrpl/protocol/TxSearched.h>
@@ -105,21 +104,6 @@ public:
using TxnMetaLedgerType = std::tuple<Blob, Blob, std::uint32_t>;
using MetaTxsList = std::vector<TxnMetaLedgerType>;
using LedgerSequence = uint32_t;
using LedgerHash = UInt256;
using LedgerSpecifier = std::variant<LedgerRange, LedgerShortcut, LedgerSequence, LedgerHash>;
struct AccountTxArgs
{
AccountID account;
std::optional<LedgerSpecifier> ledger;
bool binary = false;
bool forward = false;
uint32_t limit = 0;
std::optional<AccountTxMarker> marker;
std::optional<DelegateFilter> delegate;
};
struct AccountTxResult
{
std::variant<AccountTxs, MetaTxsList> transactions;

View File

@@ -279,7 +279,7 @@ public:
virtual bool
unsubPeerStatus(std::uint64_t uListener) = 0;
virtual void
pubPeerStatus(std::function<json::Value(void)> const&) = 0;
pubPeerStatus(std::function<json::Value()> const&) = 0;
virtual bool
subConsensus(Ref ispListener) = 0;

View File

@@ -41,7 +41,7 @@ public:
}
bool
prepare(std::size_t bytes, std::function<void(void)>) override
prepare(std::size_t bytes, std::function<void()>) override
{
return true;
}

View File

@@ -47,7 +47,7 @@ public:
* empty vector.
*/
virtual std::pair<boost::tribool, std::vector<boost::asio::const_buffer>>
prepare(std::size_t bytes, std::function<void(void)> resume) = 0;
prepare(std::size_t bytes, std::function<void()> resume) = 0;
};
template <class Streambuf>
@@ -62,7 +62,7 @@ public:
}
std::pair<boost::tribool, std::vector<boost::asio::const_buffer>>
prepare(std::size_t bytes, std::function<void(void)>) override
prepare(std::size_t bytes, std::function<void()>) override
{
if (sb_.size() == 0)
return {true, {}};

View File

@@ -34,7 +34,7 @@ public:
* @return `true` if the writer is ready to provide more data.
*/
virtual bool
prepare(std::size_t bytes, std::function<void(void)> resume) = 0;
prepare(std::size_t bytes, std::function<void()> resume) = 0;
/**
* Returns a ConstBufferSequence representing the input sequence.

View File

@@ -342,10 +342,10 @@ BaseHTTPPeer<Handler, Impl>::doWriter(
bool keepAlive,
YieldContext doYield)
{
std::function<void(void)> resume;
std::function<void()> resume;
{
auto const p = impl().shared_from_this();
resume = std::function<void(void)>([this, p, writer, keepAlive]() {
resume = std::function<void()>([this, p, writer, keepAlive]() {
util::spawn(strand_, [p, writer, keepAlive](YieldContext doYield) {
p->doWriter(writer, keepAlive, doYield);
});

View File

@@ -99,7 +99,7 @@ private:
port_.protocol.contains("wss2") || port_.protocol.contains("peer")};
bool plain_{
port_.protocol.contains("http") || port_.protocol.contains("ws") ||
(port_.protocol.contains("ws2"))};
port_.protocol.contains("ws2")};
static constexpr std::chrono::milliseconds kInitialAcceptDelay{50};
static constexpr std::chrono::milliseconds kMaxAcceptDelay{2000};
std::chrono::milliseconds acceptDelay_{kInitialAcceptDelay};

View File

@@ -60,7 +60,7 @@ private:
bool closed_ = false;
std::condition_variable cv_;
boost::container::flat_map<Work*, std::weak_ptr<Work>> map_;
std::function<void(void)> f_;
std::function<void()> f_;
public:
IOList() = default;
@@ -171,7 +171,7 @@ IOList::Work::destroy()
{
if (!ios_)
return;
std::function<void(void)> f;
std::function<void()> f;
{
std::scoped_lock const lock(ios_->m_);
ios_->map_.erase(this);

View File

@@ -27,18 +27,6 @@
namespace xrpl {
/**
* Returns true if sleAcct is an AccountRoot carrying a pseudo-account field.
*
* isPseudoAccount() takes a view-bound AccountRootEntry, which is not
* available while visiting entries, so invariant checks use this instead.
*
* @param sleAcct the SLE to check.
* @return true if sleAcct is an AccountRoot carrying a pseudo-account field.
*/
[[nodiscard]] bool
isPseudoAccountSle(SLE::ConstRef sleAcct);
#if GENERATING_DOCS
/**
* @brief Prototype for invariant check implementations.

View File

@@ -42,6 +42,14 @@ class ValidMPTIssuance
*/
bool referenceHoldingMutated_ = false;
/**
* Flags cleared on an existing MPTokenIssuance, except lsfMPTLocked,
* which tfMPTUnlock clears legitimately. Every other issuance flag is
* fixed at creation or set-once via MPTokenIssuanceSet, so any bit
* accumulated here is a bug. Enforced post-fixCleanup3_5_0.
*/
std::uint32_t issuanceFlagsCleared_ = 0;
/**
* MPTokens and RippleStates deleted during apply. finalize() checks each
* holder's AccountRoot to detect vault pseudo-account holdings deleted

View File

@@ -8,6 +8,7 @@
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Asset.h>
#include <xrpl/protocol/MPTIssue.h>
#include <xrpl/protocol/Protocol.h>
#include <xrpl/protocol/Rules.h>
#include <xrpl/protocol/STLedgerEntry.h>
#include <xrpl/protocol/STTx.h>
@@ -29,7 +30,7 @@ namespace xrpl {
* - vault must have MPTokenIssuance for shares
* - vault without shares outstanding must have no shares
* - loss unrealized does not exceed the difference between assets total and
* assets available
* assets available (Legacy/CashBasis), or AssetsDeployed (FixedPrecision)
* - assets available do not exceed assets total
* - vault deposit increases assets and share issuance, and adds to:
* total assets, assets available, shares outstanding
@@ -46,6 +47,14 @@ namespace xrpl {
* - vault withdrawal may not succeed when the vault phase is Investment
* - closed-ended loan origination (ttLOAN_SET) may only succeed when the
* vault phase is Investment
* - FixedPrecision only: AssetsDeployed is non-negative and exactly
* representable at the asset's precision; AssetsDeployed changes only for
* ttLOAN_SET, ttLOAN_PAY and ttLOAN_MANAGE; AssetsDeployed is zero right
* after ttVAULT_CREATE and whenever shares outstanding return to zero; the
* stored AssetsTotal cache equals AssetsAvailable + AssetsDeployed, rounded
* Downward to the asset's precision
* - FixedPrecision only: YieldUnrealized is non-negative; YieldUnrealized
* changes only for ttLOAN_SET, ttLOAN_PAY and ttLOAN_MANAGE
*
* Immutability of VaultKind, SubscriptionDate and RedemptionDate is enforced
* by NoModifiedUnmodifiableFields (see InvariantCheck.cpp). From
@@ -68,6 +77,9 @@ class ValidVault
Number assetsAvailable = 0;
Number assetsMaximum = 0;
Number lossUnrealized = 0;
Number assetsDeployed = 0;
Number yieldUnrealized = 0;
VaultVersion version = VaultVersion::Legacy;
std::optional<std::uint8_t> vaultKind;
std::optional<std::uint32_t> subscriptionDate;
std::optional<std::uint32_t> redemptionDate;
@@ -217,6 +229,39 @@ private:
[[nodiscard]] bool
finalizeLoanSet(ReadView const& view, beast::Journal const& j) const;
/**
* @brief Check that a vault's AssetsTotal and AssetsAvailable deltas add
* up against the real transfer, for deposit/withdraw/clawback.
*
* Shared body of the ttVAULT_DEPOSIT, ttVAULT_WITHDRAW and
* ttVAULT_CLAWBACK "assets outstanding"/"assets available" add-up checks,
* which differ only in the rounded/exact deltas plugged in and the verb
* used in the log message.
*
* @param afterVault Snapshot of the vault after the transaction.
* @param beforeVault Snapshot of the vault before the transaction.
* @param vaultAsset The vault's underlying asset.
* @param fix340Enabled Whether fixCleanup3_4_0 is enabled.
* @param minScale The posterior scale computed by computeVaultMinScale.
* @param roundedVaultDelta The real transfer's delta, rounded to minScale.
* @param exactVaultDelta The real transfer's exact (unrounded) delta.
* @param verb The transaction name used in the log message ("deposit",
* "withdrawal" or "clawback").
* @param j Journal for logging.
* @return false if either add-up check fails.
*/
[[nodiscard]] static bool
checkTotalsAddUp(
Vault const& afterVault,
Vault const& beforeVault,
Asset const& vaultAsset,
bool fix340Enabled,
std::int32_t minScale,
Number const& roundedVaultDelta,
Number const& exactVaultDelta,
char const* verb,
beast::Journal const& j);
public:
// Compute the coarsest scale required to represent all numbers
[[nodiscard]] static std::int32_t

View File

@@ -5,7 +5,6 @@
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/entries/AccountRootEntry.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Indexes.h>
@@ -26,7 +25,7 @@ checkFreeze(
XRPL_ASSERT(src != dst, "xrpl::checkFreeze : unequal input accounts");
// check freeze
if (auto sle = AccountRootEntryR(dst, view))
if (auto sle = view.read(keylet::account(dst)))
{
if (sle->isFlag(lsfGlobalFreeze))
{
@@ -50,7 +49,7 @@ checkFreeze(
if (view.rules().enabled(fixFrozenLPTokenTransfer))
{
if (auto const sleDst = AccountRootEntryR(dst, view);
if (auto const sleDst = view.read(keylet::account(dst));
sleDst && sleDst->isFieldPresent(sfAMMID))
{
auto const sleAmm = view.read(keylet::amm((*sleDst)[sfAMMID]));

View File

@@ -10,6 +10,7 @@
#include <xrpl/tx/ApplyContext.h>
#include <xrpl/tx/Transactor.h>
#include <cstdint>
#include <vector>
namespace xrpl {
@@ -32,6 +33,9 @@ public:
static std::vector<OptionaledField<STNumber>> const&
getValueFields();
static std::uint32_t
getFlagsMask(PreflightContext const& ctx);
static TER
preclaim(PreclaimContext const& ctx);

View File

@@ -2,7 +2,6 @@
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/AccountRootEntry.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Keylet.h>
#include <xrpl/protocol/STLedgerEntry.h>
@@ -13,7 +12,6 @@
#include <xrpl/tx/Transactor.h>
#include <cstdint>
#include <optional>
namespace xrpl {
@@ -58,8 +56,8 @@ private:
Keylet const& sponsorshipKeylet,
AccountID const& sponsorID,
AccountID const& sponseeID,
AccountRootEntryW& sponsorAccSle,
std::optional<AccountRootEntryW>& reserveSponsorAccSle);
SLE::Ref sponsorAccSle,
SLE::Ref reserveSponsorAccSle);
};
} // namespace xrpl

View File

@@ -57,6 +57,12 @@ public:
ReadView const& view,
beast::Journal const& j) override;
/**
* Inner transaction types that preflight rejects before LendingProtocolV1_2.
*
* Once the amendment is enabled the list only matters when replaying older
* ledgers. Remove it when LendingProtocolV1_2 is retired.
*/
static constexpr auto kDisabledTxTypes = std::to_array<TxType>({
ttVAULT_CREATE,
ttVAULT_SET,

View File

@@ -2,145 +2,148 @@ Detected OS: macos (Darwin arm64)
Core build tools:
✅ cmake
cmake version 4.1.2
/nix/store/gvabsb4yqb5xsqzqph54rijnn4zpihnp-cmake-4.1.2/bin/cmake
cmake version 4.4.3
/nix/store/q85csxf4s4shx89zif097h1ql4ax1rrz-cmake-4.4.3/bin/cmake
✅ conan
Conan version 2.28.1
/nix/store/9jiyxmkpwmn6dcqs0765s83riw3l5ail-conan-2.28.1/bin/conan
Conan version 2.33.0
/nix/store/rp0zf22rx3iwnhxp4d53ncirn4lzg68j-conan-2.33.0/bin/conan
✅ git
git version 2.54.0
/nix/store/a14yxcqvv9x2l9mllgpirzhvz93pgprg-git-2.54.0/bin/git
git version 2.55.0
/nix/store/gw7c7m0dwca5lg4152x9lpmxpj171bzw-git-2.55.0/bin/git
✅ python3
Python 3.13.13
/nix/store/ygxqin6ydzjfawywqpp5pal8wv6sf5bh-python3-3.13.13/bin/python3.13
Python 3.14.7
/nix/store/0kcws5blwbdyxqxjd1w8hjipz61xny3k-python3-3.14.7/bin/python3.14
Development tooling:
✅ ccache
ccache version 4.13.6
/nix/store/57davyvs6p6dkrl3svzwg1ph18wsy4cz-ccache-4.13.6/bin/ccache
/nix/store/ydr5nlzxp1djb5256y0zzqa87vz55gsk-ccache-4.13.6/bin/ccache
✅ clang
clang version 22.1.7
/nix/store/192glrb2cldvziyf3378mzjqbzx3ih4g-clang-wrapper-22.1.7/bin/clang
✅ clang-22
clang version 22.1.7
/nix/store/rbap7zqq7mw00fyqa02p5rj7gqjp4w5i-clang-22/bin/clang-22
clang version 23.1.0
/nix/store/2c16z6akvv65znb8330sl5qpklaf3194-clang-wrapper-23.1.0/bin/clang
✅ clang-23
clang version 23.1.0
/nix/store/vfd0q2395vyn0bsjsh1b4068icy1x9ph-clang-23/bin/clang-23
✅ clang++
clang version 22.1.7
/nix/store/192glrb2cldvziyf3378mzjqbzx3ih4g-clang-wrapper-22.1.7/bin/clang++
✅ clang++-22
clang version 22.1.7
/nix/store/v9haf787f7bcz0mq1sad4bpyx21pj6li-clang++-22/bin/clang++-22
clang version 23.1.0
/nix/store/2c16z6akvv65znb8330sl5qpklaf3194-clang-wrapper-23.1.0/bin/clang++
✅ clang++-23
clang version 23.1.0
/nix/store/0i6kfnif2v4sqyv5fzfg8a9n09rw9lkp-clang++-23/bin/clang++-23
✅ ClangBuildAnalyzer
ClangBuildAnalyzer 1.6.0
/nix/store/4l50ds9fa2mkvh7wg8qzrlbmjs12sb8l-clangbuildanalyzer-1.6.0/bin/ClangBuildAnalyzer
/nix/store/c7jjnw29ra78jdlzjww2m374izhy05n8-clangbuildanalyzer-1.6.0/bin/ClangBuildAnalyzer
✅ curl
curl 8.20.0 (aarch64-apple-darwin25.3.0) libcurl/8.20.0 OpenSSL/3.6.2 zlib/1.3.2 libssh2/1.11.1 nghttp2/1.69.0 mit-krb5/1.22.1
/nix/store/kclq0czaxvsgh4ym9ld7b6iwy50l1snk-curl-8.20.0-bin/bin/curl
curl 8.22.0 (aarch64-apple-darwin25.6.0) libcurl/8.22.0 OpenSSL/3.5.8 zlib/1.3.2 libssh2/1.11.1 nghttp2/1.70.0 mit-krb5/1.22.2
/nix/store/pq1h17abqy6q5y6k5dn9qj0fwb89flba-curl-8.22.0-bin/bin/curl
✅ file
file-5.47
/nix/store/dax63li7wwcbqxxkkgzc4g2rx7d4w86x-file-5.47/bin/file
file-5.48
/nix/store/y44vpziwbzfm8020dzlqqbybyyy7lb6g-file-5.48/bin/file
✅ jq
jq-1.8.2
/nix/store/wm7v59a2lhj1w2k8jz53spcs1iizm9lv-jq-1.8.2-bin/bin/jq
✅ less
less 692 (PCRE2 regular expressions)
/nix/store/lvr16y75r1pdxpdv0aph5ak2yd0hkvqm-less-692/bin/less
less 710 (PCRE2 regular expressions)
/nix/store/3yn3dx5fwg5i0inqqzwnxq7f6lwhpjqa-less-710/bin/less
✅ make
GNU Make 4.4.1
/nix/store/8wwiw8pwyhrkzyq28hqzxfl4z84lks81-gnumake-4.4.1/bin/make
/nix/store/8l4wgxmhdxfvc9g18y76bnxl1ghgcp7n-gnumake-4.4.1/bin/make
✅ netstat
present
/nix/store/qsd1kzqb0ahrk433vmyl245gp623j19s-network_cmds-730.80.3/bin/netstat
/nix/store/57fqvgdav8lrmzndkwm7qrgksl01yj23-network_cmds-741.100.2/bin/netstat
✅ ninja
1.13.2
/nix/store/bqykhrblarkj4fl0hz2mf8ngwfv6x6bz-ninja-1.13.2/bin/ninja
/nix/store/infm4vlx71q83bqz0k559w1gn4b0rq4i-ninja-1.13.2/bin/ninja
✅ perl
v5.42.0
/nix/store/js13ri9fvm0ajk1fpd3acigys2a9whdv-perl-5.42.0/bin/perl
v5.42.3
/nix/store/7rvr6qjfzk2ybzn1imjw6c6qq1n1a9cr-perl-5.42.3/bin/perl
✅ pkg-config
0.29.2
/nix/store/lzrwr375jqhhbca116kja96xf1md83l8-pkg-config-wrapper-0.29.2/bin/pkg-config
/nix/store/nhgylvj98klqggy54h7gbc3b2ia4a00y-pkg-config-wrapper-0.29.2/bin/pkg-config
✅ vim
VIM - Vi IMproved 9.2 (2026 Feb 14, compiled Jan 01 1980 00:00:00)
/nix/store/6vbkykg92w603c0sw3mkk7p7mfaawbns-vim-9.2.0389/bin/vim
/nix/store/akaa9kqm3b8rlkv61kvsqr2l2j70rvxb-vim-9.2.1001/bin/vim
✅ zip
Zip 3.0
/nix/store/z6ph729vcakbvz3wh8ln1wk6mi06w487-zip-3.0/bin/zip
/nix/store/dvawr36npnad4xa6dxi2ss0fw44aa82r-zip-3.0/bin/zip
✅ clang-apply-replacements
clang-apply-replacements version 22.1.7
/nix/store/vzyyjf3cm1hbj9wcr2qcb66x6j98zpy7-clang-tools-22.1.7/bin/clang-apply-replacements
✅ clang-apply-replacements-22
clang-apply-replacements version 22.1.7
/nix/store/m3ii69rca4077lf4wlk7m3jcag1fs577-clang-apply-replacements-22/bin/clang-apply-replacements-22
clang-apply-replacements version 23.1.0
/nix/store/mva6ngy45m9in3m2lsfccj1y0z6n1f5s-clang-tools-23.1.0/bin/clang-apply-replacements
✅ clang-apply-replacements-23
clang-apply-replacements version 23.1.0
/nix/store/872k02mqr21hxwcpfwaqkxljfj60aak0-clang-apply-replacements-23/bin/clang-apply-replacements-23
✅ clang-format
clang-format version 22.1.7
/nix/store/vzyyjf3cm1hbj9wcr2qcb66x6j98zpy7-clang-tools-22.1.7/bin/clang-format
✅ clang-format-22
clang-format version 22.1.7
/nix/store/4fawqy6ngqcsqd2ygyyzm93q0xy3f5gs-clang-format-22/bin/clang-format-22
clang-format version 23.1.0
/nix/store/mva6ngy45m9in3m2lsfccj1y0z6n1f5s-clang-tools-23.1.0/bin/clang-format
✅ clang-format-23
clang-format version 23.1.0
/nix/store/wf30x6lcya44n2y1fagd6q7x7p4gyl6f-clang-format-23/bin/clang-format-23
✅ clang-tidy
LLVM version 22.1.7
/nix/store/vzyyjf3cm1hbj9wcr2qcb66x6j98zpy7-clang-tools-22.1.7/bin/clang-tidy
✅ clang-tidy-22
LLVM version 22.1.7
/nix/store/jqw4280saixaxxihwdba9ldm2fsm6dr3-clang-tidy-22/bin/clang-tidy-22
LLVM version 23.1.0
/nix/store/mva6ngy45m9in3m2lsfccj1y0z6n1f5s-clang-tools-23.1.0/bin/clang-tidy
✅ clang-tidy-23
LLVM version 23.1.0
/nix/store/kgx00aass66g02p1s4gqqf65kq39m4ci-clang-tidy-23/bin/clang-tidy-23
✅ dot
dot - graphviz version 12.2.1 (0)
/nix/store/ijb4fbnqa6wzlpqnhb6q9knqpf7qqn5z-graphviz-12.2.1/bin/dot
dot - graphviz version 15.1.1 (0)
/nix/store/mc99a6bpbk2waym2cnw6ifmxli4ndb4x-graphviz-15.1.1/bin/dot
✅ doxygen
1.16.1
/nix/store/kbryjdpq9jizjb0ws0nzbf2h2ymbdiwm-doxygen-1.16.1/bin/doxygen
1.17.0
/nix/store/kz43yaj0wg6fx6cbrcmi2442z1ramy0c-doxygen-1.17.0/bin/doxygen
✅ gcovr
gcovr 8.4
/nix/store/wn8jiyh9p0bybs96s4163qp3k8vfmczx-python3.13-gcovr-8.4/bin/gcovr
/nix/store/czj1vxsizrbba280gg22cys40qxkqjgr-python3.14-gcovr-8.4/bin/gcovr
✅ gh
gh version 2.94.0 (nixpkgs)
/nix/store/fhnpw0hs0gjms1ha6ap02jq7rx13gkbp-gh-2.94.0/bin/gh
gh version 2.102.0 (2026-09-30)
/nix/store/s8bahl6zssvry93ihivfmk1l6c58byrr-gh-2.102.0/bin/gh
✅ git-cliff
git-cliff 2.13.1
/nix/store/cy0wwhgxa7yvrz97zydbq6sqmixc90fq-git-cliff-2.13.1/bin/git-cliff
git-cliff 2.14.2
/nix/store/k4m5yk0qb7hfslwsq1zjajz1d94j12bj-git-cliff-2.14.2/bin/git-cliff
✅ git-lfs
git-lfs/3.7.1 (3.7.1; darwin arm64; go 1.26.3)
/nix/store/k9r7zjfjplqa4d5s71cqvf2iv73jd9mc-git-lfs-3.7.1/bin/git-lfs
git-lfs/3.8.0 (3.8.0; darwin arm64; go 1.26.8)
/nix/store/wzixjr3yb40a13m2q654hm3bdjn6sal3-git-lfs-3.8.0/bin/git-lfs
✅ gpg
gpg (GnuPG) 2.4.9
/nix/store/cgh6iwzz5jgx9z5whka4vgj210i6npc6-gnupg-2.4.9/bin/gpg
/nix/store/0ldfwnwx385i5kh7cyvxx4mkvgjhs5rh-gnupg-2.4.9/bin/gpg
✅ pre-commit
pre-commit 4.5.1
/nix/store/z3cca68620w0w10f090szgzdnmh1waf2-pre-commit-4.5.1/bin/pre-commit
pre-commit 4.6.2
/nix/store/ivh54xypg9qvd3ha9lis0i8p4nkf8n7a-pre-commit-4.6.2/bin/pre-commit
✅ run-clang-tidy
usage: run-clang-tidy [-h] [-allow-enabling-alpha-checkers]
/nix/store/4x28x911z2f9y7adqlh3qspp4a16dig7-run-clang-tidy/bin/run-clang-tidy
✅ run-clang-tidy-22
/nix/store/zjbzr154xan5xg9pmjiv0zkwklyb94wv-run-clang-tidy/bin/run-clang-tidy
✅ run-clang-tidy-23
usage: run-clang-tidy [-h] [-allow-enabling-alpha-checkers]
/nix/store/x8iymrh76sk5q91ryg5pa7i32s6gfh34-run-clang-tidy-22/bin/run-clang-tidy-22
/nix/store/svhfrpgx2j581brsqmkpav9b286v22yy-run-clang-tidy-23/bin/run-clang-tidy-23
Rust toolchain:
✅ cargo
cargo 1.97.1 (c980f4866 2026-06-30)
/nix/store/bnfk1sl4s9angb0vj1cj9a5y5zvqinwy-rust-minimal-1.97.1/bin/cargo
/nix/store/gklji8yq8yrx1k039c10kwz60vqf2dxj-rust-minimal-1.97.1/bin/cargo
✅ cargo-audit
cargo-audit-audit 0.22.1
/nix/store/snwkga2f5gyf404h7mmp9wriwxb8v65f-cargo-audit-0.22.1/bin/cargo-audit
cargo-audit-audit 0.22.2
/nix/store/7jgrwj557l91940aj0ag4i924ima1cqn-cargo-audit-0.22.2/bin/cargo-audit
✅ cargo-llvm-cov
cargo-llvm-cov 0.8.5
/nix/store/fpiqdh91gwyxalqp409ynm0s0g086w7w-cargo-llvm-cov-0.8.5/bin/cargo-llvm-cov
cargo-llvm-cov 0.9.0
/nix/store/5q1h285z8zzkw2qxig9a0b1avcsk1cf0-cargo-llvm-cov-0.9.0/bin/cargo-llvm-cov
✅ cargo-nextest
cargo-nextest 0.9.137
/nix/store/ylz7m947mhkgsp6i7611id3s3gcd58nq-cargo-nextest-0.9.137/bin/cargo-nextest
cargo-nextest 0.9.146
/nix/store/69v3hx3k597hcxd2zy7yad7fg0aw5yxd-cargo-nextest-0.9.146/bin/cargo-nextest
✅ clippy-driver
clippy 0.1.97 (8bab26f4f6 2026-07-14)
/nix/store/bnfk1sl4s9angb0vj1cj9a5y5zvqinwy-rust-minimal-1.97.1/bin/clippy-driver
/nix/store/gklji8yq8yrx1k039c10kwz60vqf2dxj-rust-minimal-1.97.1/bin/clippy-driver
✅ rust-analyzer
rust-analyzer 1.97.1 (8bab26f4 2026-07-14)
/nix/store/j6apc5pmd0giy15da9p650r8zklslmvi-rust-analyzer-preview-1.97.1-aarch64-apple-darwin/bin/rust-analyzer
/nix/store/30rbyk8gx7v53fxqhs4pp0fvxfjycspr-rust-analyzer-preview-1.97.1-aarch64-apple-darwin/bin/rust-analyzer
✅ rust-nightly
rustc 1.99.0-nightly (87e5904f5 2026-07-20)
/nix/store/fqpjz4l0nsnji8b2pz57mnj0akbp6hcl-rust-nightly/bin/rust-nightly
rustc 1.101.0-nightly (282215592 2026-10-04)
/nix/store/a9552rf3pylcnkijc1z0hf1lcnv50djq-rust-nightly/bin/rust-nightly
✅ rustc
rustc 1.97.1 (8bab26f4f 2026-07-14)
/nix/store/bnfk1sl4s9angb0vj1cj9a5y5zvqinwy-rust-minimal-1.97.1/bin/rustc
/nix/store/gklji8yq8yrx1k039c10kwz60vqf2dxj-rust-minimal-1.97.1/bin/rustc
✅ rustfmt
rustfmt 1.9.0-stable (8bab26f4f6 2026-07-14)
/nix/store/5ymwgr9jqjz7zzbmj0j5vqbwcd3kp0vm-rustfmt-preview-1.97.1-aarch64-apple-darwin/bin/rustfmt
/nix/store/0jmdipyn8266j9kqx2xxm2qkxlrlrjfc-rustfmt-preview-1.97.1-aarch64-apple-darwin/bin/rustfmt
Skipping git-over-HTTPS check (CHECK_TOOLS_SKIP_CLONE is set).
✅ All 45 checked tools are present and runnable.
✅ All 46 checked tools are present and runnable.

View File

@@ -2,173 +2,176 @@ Detected OS: linux (Linux x86_64)
Core build tools:
✅ cmake
cmake version 4.1.2
/nix/store/r9941n32g4wyvggz2703dlplbdq8a6rd-cmake-4.1.2/bin/cmake
cmake version 4.4.3
/nix/store/jcvvpih1046akxcwh9hdiak5q24jqcf0-cmake-4.4.3/bin/cmake
✅ conan
Conan version 2.28.1
/nix/store/lxny9y4jvjdws7hgz1mygvb7hjrpmna5-conan-2.28.1/bin/conan
Conan version 2.33.0
/nix/store/b4lnzrqc60glhl9al1nakfc0vd20kdna-conan-2.33.0/bin/conan
✅ git
git version 2.54.0
/nix/store/bcnisk3ydfgv26v2gw3zlky24g00yww2-git-2.54.0/bin/git
git version 2.55.0
/nix/store/lg46w7hrjx7kylsh6645c9l975i8h43b-git-2.55.0/bin/git
✅ python3
Python 3.13.13
/nix/store/60m4rxhg2fldqaak400c0lry96ijrzqn-python3-3.13.13/bin/python3.13
Python 3.14.7
/nix/store/lb41b0anx1f98y9y5s9mdv97gjgsq740-python3-3.14.7/bin/python3.14
Development tooling:
✅ ccache
ccache version 4.13.6
/nix/store/c9wwl7s5i6rsfwvf4v0xbbmzx5m6jgfr-ccache-4.13.6/bin/ccache
/nix/store/p1a1s700dqsw1b3b8d2ba64nqw68zgpy-ccache-4.13.6/bin/ccache
✅ clang
clang version 22.1.7
/nix/store/ff0hrp9r9i3pa5arkdw0sgmzp8d576qi-clang-wrapper-22.1.7/bin/clang
✅ clang-22
clang version 22.1.7
/nix/store/dagc2rq44gfbr7w7yvvqca3yqpc9gqbq-clang-22/bin/clang-22
clang version 23.1.0
/nix/store/mlqh1xrp0zi3i5g9b0zjcz6zlbbzdgb8-clang-wrapper-23.1.0/bin/clang
✅ clang-23
clang version 23.1.0
/nix/store/xgi7q1bady9dk89zvjmiicjzzp1gvm7x-clang-23/bin/clang-23
✅ clang++
clang version 22.1.7
/nix/store/ff0hrp9r9i3pa5arkdw0sgmzp8d576qi-clang-wrapper-22.1.7/bin/clang++
✅ clang++-22
clang version 22.1.7
/nix/store/l5m8clin1npl605wdkd8mr18ggxww3z4-clang++-22/bin/clang++-22
clang version 23.1.0
/nix/store/mlqh1xrp0zi3i5g9b0zjcz6zlbbzdgb8-clang-wrapper-23.1.0/bin/clang++
✅ clang++-23
clang version 23.1.0
/nix/store/4slsaz29v72xgc4g36cp94f0p41a81pv-clang++-23/bin/clang++-23
✅ ClangBuildAnalyzer
ClangBuildAnalyzer 1.6.0
/nix/store/bshlmn8fqw55nsnm581xqlfbahfkykxx-clangbuildanalyzer-1.6.0/bin/ClangBuildAnalyzer
/nix/store/gvx8im1c89vspwb8ixa91lr1dagbi241-clangbuildanalyzer-1.6.0/bin/ClangBuildAnalyzer
✅ curl
curl 8.20.0 (x86_64-pc-linux-gnu) libcurl/8.20.0 OpenSSL/3.6.2 zlib/1.3.2 libssh2/1.11.1 nghttp2/1.69.0 mit-krb5/1.22.1
/nix/store/zbwymrp4lcfjc4kkk0n4779v0kjjz58z-curl-8.20.0-bin/bin/curl
curl 8.22.0 (x86_64-pc-linux-gnu) libcurl/8.22.0 OpenSSL/3.5.8 zlib/1.3.2 libssh2/1.11.1 nghttp2/1.70.0 mit-krb5/1.22.2
/nix/store/305w9ipyg497mz9dq31abdf61qk58k29-curl-8.22.0-bin/bin/curl
✅ file
file-5.47
/nix/store/bizyfqdw0h67wzqmp10knmf9s2pqahdb-file-5.47/bin/file
file-5.48
/nix/store/g0fbnccaan8q0rxlw43xnbyb90i94vlc-file-5.48/bin/file
✅ jq
jq-1.8.2
/nix/store/m3y7hqmy20nd1ps6qy8410a326255bf0-jq-1.8.2-bin/bin/jq
✅ less
less 692 (PCRE2 regular expressions)
/nix/store/c6bacbn93qg4a7g9n4czww8rg24dvysr-less-692/bin/less
less 710 (PCRE2 regular expressions)
/nix/store/zi4d0awnc6crz18s177bv9y2yz9al3lq-less-710/bin/less
✅ make
GNU Make 4.4.1
/nix/store/d3bwqm6bymhy3pdgbvf7vxjqfp31m3j1-gnumake-4.4.1/bin/make
/nix/store/z565rgmn9vccv2h0g87z725pw610jmm8-gnumake-4.4.1/bin/make
✅ netstat
net-tools 2.10
/nix/store/jmyzqvgflnswmws7rnxx6g3zbj680xvd-net-tools-2.10/bin/netstat
/nix/store/9i6j9lrsliyz1ww2f8xx18z36wc9n38a-net-tools-2.10/bin/netstat
✅ ninja
1.13.2
/nix/store/7a235m7crqbb4h49sak20fqxpw3n7hr0-ninja-1.13.2/bin/ninja
/nix/store/4nsdla28c4177ssp0hlyv5l2yzj8wcba-ninja-1.13.2/bin/ninja
✅ perl
v5.42.0
/nix/store/6plwsm6pkq79yjv4xvy8csk2pd4hzr67-perl-5.42.0/bin/perl
v5.42.3
/nix/store/8g4dmf7l8q1mf9w4wfmlcl8gvdgmhb8v-perl-5.42.3/bin/perl
✅ pkg-config
0.29.2
/nix/store/1m05k7xgfnw6jc21xxk5681ni3ar97wf-pkg-config-wrapper-0.29.2/bin/pkg-config
/nix/store/b9izmrfjp0qnnyahdwwrzdwi87s1h179-pkg-config-wrapper-0.29.2/bin/pkg-config
✅ vim
VIM - Vi IMproved 9.2 (2026 Feb 14, compiled Jan 01 1980 00:00:00)
/nix/store/hvyqx52g4g2fxhgpans3fksjj6lmlyaw-vim-9.2.0389/bin/vim
/nix/store/9swnd5pf8p8w1gwcbhdpm2yx705kbp38-vim-9.2.1001/bin/vim
✅ zip
Zip 3.0
/nix/store/qnd2ag67hrjj0b6vbmisdshf50r6s72n-zip-3.0/bin/zip
/nix/store/5ypvkry3qra47dylc9kfk36r1q9vha80-zip-3.0/bin/zip
✅ clang-apply-replacements
clang-apply-replacements version 22.1.7
/nix/store/4zp1rjpj2xijrv4kqpwsy3ixwb2r6nlk-clang-tools-22.1.7/bin/clang-apply-replacements
✅ clang-apply-replacements-22
clang-apply-replacements version 22.1.7
/nix/store/py2wihg0a96qcppv4hjmww547xabr0fb-clang-apply-replacements-22/bin/clang-apply-replacements-22
clang-apply-replacements version 23.1.0
/nix/store/ipnj8b3s6f00ngi26fi7p5h9lxv6a3s3-clang-tools-23.1.0/bin/clang-apply-replacements
✅ clang-apply-replacements-23
clang-apply-replacements version 23.1.0
/nix/store/lbyc9hrkkymybah7b6n8c7sijlgldfz0-clang-apply-replacements-23/bin/clang-apply-replacements-23
✅ clang-format
clang-format version 22.1.7
/nix/store/4zp1rjpj2xijrv4kqpwsy3ixwb2r6nlk-clang-tools-22.1.7/bin/clang-format
✅ clang-format-22
clang-format version 22.1.7
/nix/store/kz820ccifjlwqnwqjsx7kbiajrgsmbrh-clang-format-22/bin/clang-format-22
clang-format version 23.1.0
/nix/store/ipnj8b3s6f00ngi26fi7p5h9lxv6a3s3-clang-tools-23.1.0/bin/clang-format
✅ clang-format-23
clang-format version 23.1.0
/nix/store/40w351b7i7aqhpl5wmicfnp2ij8k12g9-clang-format-23/bin/clang-format-23
✅ clang-tidy
LLVM version 22.1.7
/nix/store/4zp1rjpj2xijrv4kqpwsy3ixwb2r6nlk-clang-tools-22.1.7/bin/clang-tidy
✅ clang-tidy-22
LLVM version 22.1.7
/nix/store/gdrkvpw846lkyzh8y9p3zx50g6ml2v84-clang-tidy-22/bin/clang-tidy-22
LLVM version 23.1.0
/nix/store/ipnj8b3s6f00ngi26fi7p5h9lxv6a3s3-clang-tools-23.1.0/bin/clang-tidy
✅ clang-tidy-23
LLVM version 23.1.0
/nix/store/40rj38k5ygq7sawkiv0cdaljclbspwz9-clang-tidy-23/bin/clang-tidy-23
✅ dot
dot - graphviz version 12.2.1 (0)
/nix/store/12rgns2296s4qcja778gvcbx61z77rc4-graphviz-12.2.1/bin/dot
dot - graphviz version 15.1.1 (0)
/nix/store/f7r47nc0d13xa4c2xaaxa6dp3pzm9sp1-graphviz-15.1.1/bin/dot
✅ doxygen
1.16.1
/nix/store/k0vzr5lvgq1byraknzwvk51wcgpnsrkh-doxygen-1.16.1/bin/doxygen
1.17.0
/nix/store/q6yx2nsimj9xmckmgw4br2cnapbgnqpk-doxygen-1.17.0/bin/doxygen
✅ gcovr
gcovr 8.4
/nix/store/iyzi7fpyclqrha054adnizvif02lg49x-python3.13-gcovr-8.4/bin/gcovr
/nix/store/shx7mfl8n4kx11icvwyj5x7cmf6z5ahq-python3.14-gcovr-8.4/bin/gcovr
✅ gh
gh version 2.94.0 (nixpkgs)
/nix/store/pidh15szlsb1vc41xdsa3xbdghdazvby-gh-2.94.0/bin/gh
gh version 2.102.0 (2026-09-30)
/nix/store/66h5dr9v94x04myh2kabx06rq9763jfc-gh-2.102.0/bin/gh
✅ git-cliff
git-cliff 2.13.1
/nix/store/1q851fs62shgjhc03fxxdkpzxdjg7k11-git-cliff-2.13.1/bin/git-cliff
git-cliff 2.14.2
/nix/store/sl19b42d69b3w2vb9pxp6jbqk841z8vj-git-cliff-2.14.2/bin/git-cliff
✅ git-lfs
git-lfs/3.7.1 (3.7.1; linux amd64; go 1.26.3)
/nix/store/6ljwpal7b1756708m33vj0crpral7mvl-git-lfs-3.7.1/bin/git-lfs
git-lfs/3.8.0 (3.8.0; linux amd64; go 1.26.8)
/nix/store/rp9ld1f6h83xmf2rb5fpib5wmr46fy9f-git-lfs-3.8.0/bin/git-lfs
✅ gpg
gpg (GnuPG) 2.4.9
/nix/store/wx7vk8babxkgy813r70yc67vcwnmagbx-gnupg-2.4.9/bin/gpg
/nix/store/8gm9aq3sspqmvvh7c0x7djcivj2x7yvn-gnupg-2.4.9/bin/gpg
✅ pre-commit
pre-commit 4.5.1
/nix/store/bj6i9vl34cij5h0r165y40hrjqak0bmz-pre-commit-4.5.1/bin/pre-commit
pre-commit 4.6.2
/nix/store/6blf72f7sdmlrqjggxvk5ij4cxb7fk4c-pre-commit-4.6.2/bin/pre-commit
✅ run-clang-tidy
usage: run-clang-tidy [-h] [-allow-enabling-alpha-checkers]
/nix/store/sbg911hs9dbclrzlp04br3iyfpgnaj6r-run-clang-tidy/bin/run-clang-tidy
✅ run-clang-tidy-22
/nix/store/y7isn3dr8bildnp78vk5nhcav63g80dz-run-clang-tidy/bin/run-clang-tidy
✅ run-clang-tidy-23
usage: run-clang-tidy [-h] [-allow-enabling-alpha-checkers]
/nix/store/n8yak1ap308gvi7gmrniw0ybsx80fjws-run-clang-tidy-22/bin/run-clang-tidy-22
/nix/store/pm5a8465hs9zb5i116b39i0y3xfpw6n3-run-clang-tidy-23/bin/run-clang-tidy-23
Rust toolchain:
✅ cargo
cargo 1.97.1 (c980f4866 2026-06-30)
/nix/store/88abzp43ywyzql1rhf8jh5aj5n5j7xzr-cargo-1.97.1-x86_64-unknown-linux-gnu/bin/cargo
/nix/store/60b0cz400q34wj2gzav5a41i7y6jzlw3-cargo-1.97.1-x86_64-unknown-linux-gnu/bin/cargo
✅ cargo-audit
cargo-audit-audit 0.22.1
/nix/store/2w9if868piw98xz057sz97jnjvf7hnvf-cargo-audit-0.22.1/bin/cargo-audit
cargo-audit-audit 0.22.2
/nix/store/kksgynfwir3pfii9qkbj3gcc61an0d4s-cargo-audit-0.22.2/bin/cargo-audit
✅ cargo-llvm-cov
cargo-llvm-cov 0.8.5
/nix/store/jjpdf1l6izz6607a346ykra9sndzaw7h-cargo-llvm-cov-0.8.5/bin/cargo-llvm-cov
cargo-llvm-cov 0.9.0
/nix/store/4y8qxx0mlm22hnxlw2cmbcwpxispw02h-cargo-llvm-cov-0.9.0/bin/cargo-llvm-cov
✅ cargo-nextest
cargo-nextest 0.9.137
/nix/store/jhkr7gwyrchkml33gyns9cy0yn7b57qc-cargo-nextest-0.9.137/bin/cargo-nextest
cargo-nextest 0.9.146
/nix/store/q0anzqrazmdr8n1049ca28098q6lv2y8-cargo-nextest-0.9.146/bin/cargo-nextest
✅ clippy-driver
clippy 0.1.97 (8bab26f4f6 2026-07-14)
/nix/store/40d3mzka7r1ps71l0yv2fs6616nbw85m-rust-minimal-1.97.1/bin/clippy-driver
/nix/store/kk0kqdc4f7am21yp30rr8jcrnib5xqzy-rust-minimal-1.97.1/bin/clippy-driver
✅ rust-analyzer
rust-analyzer 1.97.1 (8bab26f 2026-07-14)
/nix/store/lr3m97p3hx1k22a7c44pb0wa7rbayhfi-rust-analyzer-preview-1.97.1-x86_64-unknown-linux-gnu/bin/rust-analyzer
/nix/store/4mglk7qw9jqbv5nwlx9ahdnpcn5sz70r-rust-analyzer-preview-1.97.1-x86_64-unknown-linux-gnu/bin/rust-analyzer
✅ rust-nightly
rustc 1.99.0-nightly (87e5904f5 2026-07-20)
/nix/store/j7kf7a5h4xypzp6x1skg4dsdx2k4fwb3-rust-nightly/bin/rust-nightly
rustc 1.101.0-nightly (282215592 2026-10-04)
/nix/store/qwyzkvba3f9569wjj45b4iyb7nz7qbnr-rust-nightly/bin/rust-nightly
✅ rustc
rustc 1.97.1 (8bab26f4f 2026-07-14)
/nix/store/40d3mzka7r1ps71l0yv2fs6616nbw85m-rust-minimal-1.97.1/bin/rustc
/nix/store/kk0kqdc4f7am21yp30rr8jcrnib5xqzy-rust-minimal-1.97.1/bin/rustc
✅ rustfmt
rustfmt 1.9.0-stable (8bab26f4f6 2026-07-14)
/nix/store/6f1icmb2za20kxn30pgmbv5jq9fnbf4z-rustfmt-preview-1.97.1-x86_64-unknown-linux-gnu/bin/rustfmt
/nix/store/y5gf8a3hix7pnwzdwcfpf3acqhzv3xy6-rustfmt-preview-1.97.1-x86_64-unknown-linux-gnu/bin/rustfmt
GCC toolchain:
✅ gcc
gcc (GCC) 15.2.0
/nix/store/3dd6y3pq00i3r85l45jvz63wjya403nl-gcc-wrapper-15.2.0/bin/gcc
gcc (GCC) 15.3.0
/nix/store/bslmkbaiymxxdc6lwcdb1qyw745nds5j-gcc-wrapper-15.3.0/bin/gcc
✅ gcc-15
gcc (GCC) 15.2.0
/nix/store/d6iri2s6bzqq5ac3fg25j6hgnn1lz44f-gcc-15/bin/gcc-15
gcc (GCC) 15.3.0
/nix/store/h6f2qc8kgwf7r81gwb10csvpjqfc2404-gcc-15/bin/gcc-15
✅ g++
g++ (GCC) 15.2.0
/nix/store/3dd6y3pq00i3r85l45jvz63wjya403nl-gcc-wrapper-15.2.0/bin/g++
g++ (GCC) 15.3.0
/nix/store/bslmkbaiymxxdc6lwcdb1qyw745nds5j-gcc-wrapper-15.3.0/bin/g++
✅ g++-15
g++ (GCC) 15.2.0
/nix/store/gm3msmmxq055lm9gprkfjj9d2gdz1mpg-g++-15/bin/g++-15
g++ (GCC) 15.3.0
/nix/store/jwncv76v61ld9l99v0b1dkmf810if65s-g++-15/bin/g++-15
✅ cpp
cpp (GCC) 15.2.0
/nix/store/3dd6y3pq00i3r85l45jvz63wjya403nl-gcc-wrapper-15.2.0/bin/cpp
cpp (GCC) 15.3.0
/nix/store/bslmkbaiymxxdc6lwcdb1qyw745nds5j-gcc-wrapper-15.3.0/bin/cpp
✅ cpp-15
cpp (GCC) 15.2.0
/nix/store/bn3gmn0m7g4gn2i0yml46fljc7mghiq5-cpp-15/bin/cpp-15
cpp (GCC) 15.3.0
/nix/store/jmi558xj8v7lz2fm6wrradh40dp48zx9-cpp-15/bin/cpp-15
✅ gcov
gcov (GCC) 15.2.0
/nix/store/xvv5sm5i8x0ks6ypfkzl7c4j9srnxz7k-gcc-15.2.0/bin/gcov
gcov (GCC) 15.3.0
/nix/store/n2ab7kf7mm84hna35x463mizcy52pf1h-gcc-15.3.0/bin/gcov
Mold:
✅ mold
mold 2.41.0 (compatible with GNU ld)
/nix/store/2w6fpgxjzzyqmd25wzplm23dfa49a0p2-mold-unwrapped-wrapper-2.41.0/bin/mold
mold 2.42.1 (compatible with GNU ld)
/nix/store/9dcddrfxlfl9n3wfibi5jkmp22bjkvkh-mold-unwrapped-wrapper-2.42.1/bin/mold
Skipping git-over-HTTPS check (CHECK_TOOLS_SKIP_CLONE is set).
✅ All 53 checked tools are present and runnable.
✅ All 54 checked tools are present and runnable.

View File

@@ -2,173 +2,176 @@ Detected OS: linux (Linux aarch64)
Core build tools:
✅ cmake
cmake version 4.1.2
/nix/store/nkcpxjifkambzlrwh27a8igvhnbchibg-cmake-4.1.2/bin/cmake
cmake version 4.4.3
/nix/store/39cq2g3d3flq2lmb6hc09grxs4xaax8p-cmake-4.4.3/bin/cmake
✅ conan
Conan version 2.28.1
/nix/store/8i2gyqgc00xvxg9xm6y7n0ilncdv8imw-conan-2.28.1/bin/conan
Conan version 2.33.0
/nix/store/grz6a77mllqzzmg198qagx1r9zhvfijw-conan-2.33.0/bin/conan
✅ git
git version 2.54.0
/nix/store/ixp98f9avf8ikpdrmp40cj33g0dazyp9-git-2.54.0/bin/git
git version 2.55.0
/nix/store/kj6aff4gmz3snpp35rl3gysbl9srd81a-git-2.55.0/bin/git
✅ python3
Python 3.13.13
/nix/store/lqn6mbgzzdrqq2qkwddcmxj9z6amdd86-python3-3.13.13/bin/python3.13
Python 3.14.7
/nix/store/81ag9nxz1flw3xjkv1vvqg8y2ipx2ins-python3-3.14.7/bin/python3.14
Development tooling:
✅ ccache
ccache version 4.13.6
/nix/store/2q39xi2kbi04ibga7635f2sl148d1mzv-ccache-4.13.6/bin/ccache
/nix/store/nzb1lir9sw06fn4635kfx055myqanaz8-ccache-4.13.6/bin/ccache
✅ clang
clang version 22.1.7
/nix/store/xjqffrq9i7la058s9865ig71l9sp1ys5-clang-wrapper-22.1.7/bin/clang
✅ clang-22
clang version 22.1.7
/nix/store/vcf6ilfwn57828hwzyp6zlyr24j9j6yw-clang-22/bin/clang-22
clang version 23.1.0
/nix/store/g8sc13kz6jarzip643hk01832x40v8ms-clang-wrapper-23.1.0/bin/clang
✅ clang-23
clang version 23.1.0
/nix/store/j8qvcg9150s5n09qg8p62q5z3ci02hd9-clang-23/bin/clang-23
✅ clang++
clang version 22.1.7
/nix/store/xjqffrq9i7la058s9865ig71l9sp1ys5-clang-wrapper-22.1.7/bin/clang++
✅ clang++-22
clang version 22.1.7
/nix/store/xby0f6gamr7m27zp5cndsvghbp9lgb3c-clang++-22/bin/clang++-22
clang version 23.1.0
/nix/store/g8sc13kz6jarzip643hk01832x40v8ms-clang-wrapper-23.1.0/bin/clang++
✅ clang++-23
clang version 23.1.0
/nix/store/n62cn5w7fgbslamy3dgm8zhl5yly7zq0-clang++-23/bin/clang++-23
✅ ClangBuildAnalyzer
ClangBuildAnalyzer 1.6.0
/nix/store/h893hd4q1bb6ily2lby5dzyfrrzd2nvj-clangbuildanalyzer-1.6.0/bin/ClangBuildAnalyzer
/nix/store/ml2991pbdhh0qcxqj9331lhpsg449vky-clangbuildanalyzer-1.6.0/bin/ClangBuildAnalyzer
✅ curl
curl 8.20.0 (aarch64-unknown-linux-gnu) libcurl/8.20.0 OpenSSL/3.6.2 zlib/1.3.2 libssh2/1.11.1 nghttp2/1.69.0 mit-krb5/1.22.1
/nix/store/i1s0lqwlrmjd2dxzgy2p84cxqqsb0bmk-curl-8.20.0-bin/bin/curl
curl 8.22.0 (aarch64-unknown-linux-gnu) libcurl/8.22.0 OpenSSL/3.5.8 zlib/1.3.2 libssh2/1.11.1 nghttp2/1.70.0 mit-krb5/1.22.2
/nix/store/94c2x2bl3xb7mx43sg1bs1hd7pnw83ac-curl-8.22.0-bin/bin/curl
✅ file
file-5.47
/nix/store/dx973zg9km2w9albsib2vw9wyvacfrlw-file-5.47/bin/file
file-5.48
/nix/store/66sd1x1hls0yijibn00iz08jh4fnas9z-file-5.48/bin/file
✅ jq
jq-1.8.2
/nix/store/kr5py0dcqc9f3l9148qd1axh0z77lld3-jq-1.8.2-bin/bin/jq
✅ less
less 692 (PCRE2 regular expressions)
/nix/store/1blb3s7hhsr77wqi598m6k1qkfp3ms0w-less-692/bin/less
less 710 (PCRE2 regular expressions)
/nix/store/n6z9dv3yjlgvfx1nmrx6qzyv8vzim1l2-less-710/bin/less
✅ make
GNU Make 4.4.1
/nix/store/9ngw1ippk25jjj5fjxv36xbp6iq7rxdx-gnumake-4.4.1/bin/make
/nix/store/q07jxvck60qgrg4p1ywypddh5zz6i9s2-gnumake-4.4.1/bin/make
✅ netstat
net-tools 2.10
/nix/store/7vdsz21f0s499s5yyqzp5s4676q4yxdd-net-tools-2.10/bin/netstat
/nix/store/rfmhd3f8drg3wqyr2mhyrlkd7vyp2pxv-net-tools-2.10/bin/netstat
✅ ninja
1.13.2
/nix/store/8ksx98gsbn5lmlizcmw57yd4sg0k2p58-ninja-1.13.2/bin/ninja
/nix/store/lfkdyggn1ffslfd830l35jrvapr5lzri-ninja-1.13.2/bin/ninja
✅ perl
v5.42.0
/nix/store/5wnly69vv1i3y97al4v3xrqymf9hlzgq-perl-5.42.0/bin/perl
v5.42.3
/nix/store/nyp5q4d2cb0pghi4i7nscb97bqkb6kp3-perl-5.42.3/bin/perl
✅ pkg-config
0.29.2
/nix/store/c7vwy0gl1q0agl2h22gi0m9dg7xxad2l-pkg-config-wrapper-0.29.2/bin/pkg-config
/nix/store/h82n3d0wdrgskdc3yvmz5l3c50h2snvp-pkg-config-wrapper-0.29.2/bin/pkg-config
✅ vim
VIM - Vi IMproved 9.2 (2026 Feb 14, compiled Jan 01 1980 00:00:00)
/nix/store/v8c7pvx26irvy9k5sbwd183cyvckzzb3-vim-9.2.0389/bin/vim
/nix/store/h39h0qq4i80sp3yd7sxjn2wf497v5rln-vim-9.2.1001/bin/vim
✅ zip
Zip 3.0
/nix/store/5mh19mvbv9ym2sm9vymyyaac5l2cj2jq-zip-3.0/bin/zip
/nix/store/lfwhq17wfcmjy823fldhlhxj1hjchdzc-zip-3.0/bin/zip
✅ clang-apply-replacements
clang-apply-replacements version 22.1.7
/nix/store/s53p2m776iqaz7acgr5csgpsd18w15h7-clang-tools-22.1.7/bin/clang-apply-replacements
✅ clang-apply-replacements-22
clang-apply-replacements version 22.1.7
/nix/store/bg4kn8z81hk7b9284rjqvr51wpfjqc24-clang-apply-replacements-22/bin/clang-apply-replacements-22
clang-apply-replacements version 23.1.0
/nix/store/jh9xhz6gwxyz3rfx7vy5g4j5d71w940r-clang-tools-23.1.0/bin/clang-apply-replacements
✅ clang-apply-replacements-23
clang-apply-replacements version 23.1.0
/nix/store/1ajzrfr62m3cianfh9i97r30a7vp1xmb-clang-apply-replacements-23/bin/clang-apply-replacements-23
✅ clang-format
clang-format version 22.1.7
/nix/store/s53p2m776iqaz7acgr5csgpsd18w15h7-clang-tools-22.1.7/bin/clang-format
✅ clang-format-22
clang-format version 22.1.7
/nix/store/79v57mzcw8ng8kl7p961ck08ymhp31v7-clang-format-22/bin/clang-format-22
clang-format version 23.1.0
/nix/store/jh9xhz6gwxyz3rfx7vy5g4j5d71w940r-clang-tools-23.1.0/bin/clang-format
✅ clang-format-23
clang-format version 23.1.0
/nix/store/5nfddq7xgbp4zmj8jn7xk1pxyyn5wiwl-clang-format-23/bin/clang-format-23
✅ clang-tidy
LLVM version 22.1.7
/nix/store/s53p2m776iqaz7acgr5csgpsd18w15h7-clang-tools-22.1.7/bin/clang-tidy
✅ clang-tidy-22
LLVM version 22.1.7
/nix/store/wdyd6cb9z1lyi37lbzvwldgcc7yv1n5c-clang-tidy-22/bin/clang-tidy-22
LLVM version 23.1.0
/nix/store/jh9xhz6gwxyz3rfx7vy5g4j5d71w940r-clang-tools-23.1.0/bin/clang-tidy
✅ clang-tidy-23
LLVM version 23.1.0
/nix/store/cawfgsx0vsslc1f007cavmy8md9drb1r-clang-tidy-23/bin/clang-tidy-23
✅ dot
dot - graphviz version 12.2.1 (0)
/nix/store/58rrk4yzwpmyxvl8cqm18h3dhv24zf00-graphviz-12.2.1/bin/dot
dot - graphviz version 15.1.1 (0)
/nix/store/vz4zb8d1rfigzzdn3i0hd4kff28vk02l-graphviz-15.1.1/bin/dot
✅ doxygen
1.16.1
/nix/store/hq32kzwpl89wgr49iq0gmqn9r5n072zq-doxygen-1.16.1/bin/doxygen
1.17.0
/nix/store/6q4z332wc9jnvad71wjj87lgjxidhgzl-doxygen-1.17.0/bin/doxygen
✅ gcovr
gcovr 8.4
/nix/store/sml3xbbfhhlhk6h7jnlg19pdbx9b764b-python3.13-gcovr-8.4/bin/gcovr
/nix/store/v548fjz51k2nmr257vjnd0zp3bxpc2r1-python3.14-gcovr-8.4/bin/gcovr
✅ gh
gh version 2.94.0 (nixpkgs)
/nix/store/7hh2qi0gj2ifbxbl56cjzbiyfc379bji-gh-2.94.0/bin/gh
gh version 2.102.0 (2026-09-30)
/nix/store/vgg6gnq74h76b4r2ac2q9366f2s5qxwx-gh-2.102.0/bin/gh
✅ git-cliff
git-cliff 2.13.1
/nix/store/bidn3pz53yd6qlg711917xx0q10hqmqv-git-cliff-2.13.1/bin/git-cliff
git-cliff 2.14.2
/nix/store/hrlgliq7l3fl2qrdlc197mvscs4n03rd-git-cliff-2.14.2/bin/git-cliff
✅ git-lfs
git-lfs/3.7.1 (3.7.1; linux arm64; go 1.26.3)
/nix/store/4rsklvkbac5bayy0zv12kxyvspi4sshd-git-lfs-3.7.1/bin/git-lfs
git-lfs/3.8.0 (3.8.0; linux arm64; go 1.26.8)
/nix/store/pa2g4xdvr4a73m6mv4cqs0pik1ka1xp5-git-lfs-3.8.0/bin/git-lfs
✅ gpg
gpg (GnuPG) 2.4.9
/nix/store/ka4i8zz5ni3rzqnzcxbfvwr95fk8pn6q-gnupg-2.4.9/bin/gpg
/nix/store/3qc90b7qkxz7na3xnpd2qb8yvcq8zdp6-gnupg-2.4.9/bin/gpg
✅ pre-commit
pre-commit 4.5.1
/nix/store/n981w6hjfar2l81kxbxs2wxl64vwa5kj-pre-commit-4.5.1/bin/pre-commit
pre-commit 4.6.2
/nix/store/5f3av75nc7n7xbf2hlvlagzpp2g8g562-pre-commit-4.6.2/bin/pre-commit
✅ run-clang-tidy
usage: run-clang-tidy [-h] [-allow-enabling-alpha-checkers]
/nix/store/4z2fyklg78klallr7x9j02kz92hnxp4m-run-clang-tidy/bin/run-clang-tidy
✅ run-clang-tidy-22
/nix/store/nlg35d9ccslsq5qny7raxyyyrxgk7vsq-run-clang-tidy/bin/run-clang-tidy
✅ run-clang-tidy-23
usage: run-clang-tidy [-h] [-allow-enabling-alpha-checkers]
/nix/store/f8m0p9ad40brp9ahy4i0h27kqjkya1j9-run-clang-tidy-22/bin/run-clang-tidy-22
/nix/store/a50nf8hp8p8l8pgcf9fs0j25hij5acw3-run-clang-tidy-23/bin/run-clang-tidy-23
Rust toolchain:
✅ cargo
cargo 1.97.1 (c980f4866 2026-06-30)
/nix/store/6hch2qrr86n2sa2m90lrpxrfxxwbkayl-cargo-1.97.1-aarch64-unknown-linux-gnu/bin/cargo
/nix/store/nci0zxxj2fiq0dlkpqzbnqfh27wz4sq4-cargo-1.97.1-aarch64-unknown-linux-gnu/bin/cargo
✅ cargo-audit
cargo-audit-audit 0.22.1
/nix/store/9rxbrn9aa2r1z96186s69pc7vzizyfch-cargo-audit-0.22.1/bin/cargo-audit
cargo-audit-audit 0.22.2
/nix/store/zldaj03mfz9f21yiby5yymq7v8vqygd7-cargo-audit-0.22.2/bin/cargo-audit
✅ cargo-llvm-cov
cargo-llvm-cov 0.8.5
/nix/store/vwjsi159n89szrx4yh5pc3jlf2gp4fld-cargo-llvm-cov-0.8.5/bin/cargo-llvm-cov
cargo-llvm-cov 0.9.0
/nix/store/iwpcfjah31fgn99ph32ajzz7i22j6al5-cargo-llvm-cov-0.9.0/bin/cargo-llvm-cov
✅ cargo-nextest
cargo-nextest 0.9.137
/nix/store/qb6bcg2fjvm3r9s9j98nmffmf9xwh45s-cargo-nextest-0.9.137/bin/cargo-nextest
cargo-nextest 0.9.146
/nix/store/p5svqr8x1rr7b1i8595pr8qafsr7s6fm-cargo-nextest-0.9.146/bin/cargo-nextest
✅ clippy-driver
clippy 0.1.97 (8bab26f4f6 2026-07-14)
/nix/store/a6p27cg6b8szfixfyvkssx6l0c345zw8-rust-minimal-1.97.1/bin/clippy-driver
/nix/store/ny64zks16ms5d70jk1qsiwsk0fr33ipp-rust-minimal-1.97.1/bin/clippy-driver
✅ rust-analyzer
rust-analyzer 1.97.1 (8bab26f 2026-07-14)
/nix/store/262830dlw2517lnagfx7i7agqgl4fmsd-rust-analyzer-preview-1.97.1-aarch64-unknown-linux-gnu/bin/rust-analyzer
/nix/store/d9s5skhvi1qxj940mylwym2rjicnc2kq-rust-analyzer-preview-1.97.1-aarch64-unknown-linux-gnu/bin/rust-analyzer
✅ rust-nightly
rustc 1.99.0-nightly (87e5904f5 2026-07-20)
/nix/store/c59pxk1yikdlf129qwyg4fplmxcrha0k-rust-nightly/bin/rust-nightly
rustc 1.101.0-nightly (282215592 2026-10-04)
/nix/store/rbsf1gr6f9ikv2izlyh8im117w6hs7h5-rust-nightly/bin/rust-nightly
✅ rustc
rustc 1.97.1 (8bab26f4f 2026-07-14)
/nix/store/a6p27cg6b8szfixfyvkssx6l0c345zw8-rust-minimal-1.97.1/bin/rustc
/nix/store/ny64zks16ms5d70jk1qsiwsk0fr33ipp-rust-minimal-1.97.1/bin/rustc
✅ rustfmt
rustfmt 1.9.0-stable (8bab26f4f6 2026-07-14)
/nix/store/nd8g81wv1smnvdpy4whpcyv2siwjmaan-rustfmt-preview-1.97.1-aarch64-unknown-linux-gnu/bin/rustfmt
/nix/store/dplvgjikmv8909rk0dkqr90ryjg7xn0j-rustfmt-preview-1.97.1-aarch64-unknown-linux-gnu/bin/rustfmt
GCC toolchain:
✅ gcc
gcc (GCC) 15.2.0
/nix/store/rn6svg593xsmn8qcjzk8x9pa1i62c4kb-gcc-wrapper-15.2.0/bin/gcc
gcc (GCC) 15.3.0
/nix/store/g7z555pl99vnwif4jxa05nk1qdc33i1n-gcc-wrapper-15.3.0/bin/gcc
✅ gcc-15
gcc (GCC) 15.2.0
/nix/store/h489d1rmjisfbxh5kmsb0a7c35j8qsdf-gcc-15/bin/gcc-15
gcc (GCC) 15.3.0
/nix/store/vbdsfjk3j1xy5z329sl2d8vp6mq6x09i-gcc-15/bin/gcc-15
✅ g++
g++ (GCC) 15.2.0
/nix/store/rn6svg593xsmn8qcjzk8x9pa1i62c4kb-gcc-wrapper-15.2.0/bin/g++
g++ (GCC) 15.3.0
/nix/store/g7z555pl99vnwif4jxa05nk1qdc33i1n-gcc-wrapper-15.3.0/bin/g++
✅ g++-15
g++ (GCC) 15.2.0
/nix/store/9ywmhz8bmzknrn3pn84g46z8hj3vrmw5-g++-15/bin/g++-15
g++ (GCC) 15.3.0
/nix/store/9ghl998ry4cxlsg6hnq5rn2iipnlkccm-g++-15/bin/g++-15
✅ cpp
cpp (GCC) 15.2.0
/nix/store/rn6svg593xsmn8qcjzk8x9pa1i62c4kb-gcc-wrapper-15.2.0/bin/cpp
cpp (GCC) 15.3.0
/nix/store/g7z555pl99vnwif4jxa05nk1qdc33i1n-gcc-wrapper-15.3.0/bin/cpp
✅ cpp-15
cpp (GCC) 15.2.0
/nix/store/vmjilh1b830qz9yh0a1jj5ads0jxizdk-cpp-15/bin/cpp-15
cpp (GCC) 15.3.0
/nix/store/wj0mv2fv2lhglvpjzhscqpbigkvik6br-cpp-15/bin/cpp-15
✅ gcov
gcov (GCC) 15.2.0
/nix/store/rmwf5hpi1y2m1wpnfvlxmrhksm4djk2j-gcc-15.2.0/bin/gcov
gcov (GCC) 15.3.0
/nix/store/mszfsj00qnv9ygqcqz3w02qzxxskhvlb-gcc-15.3.0/bin/gcov
Mold:
✅ mold
mold 2.41.0 (compatible with GNU ld)
/nix/store/f5qh5a0bx1dslmnf5n5gx0s6aljbswq3-mold-unwrapped-wrapper-2.41.0/bin/mold
mold 2.42.1 (compatible with GNU ld)
/nix/store/gbq334xbibaz4gn184j7gs58m2spgwi7-mold-unwrapped-wrapper-2.42.1/bin/mold
Skipping git-over-HTTPS check (CHECK_TOOLS_SKIP_CLONE is set).
✅ All 53 checked tools are present and runnable.
✅ All 54 checked tools are present and runnable.

View File

@@ -7,7 +7,7 @@
...
}:
let
inherit (import ./packages.nix { inherit pkgs; }) commonPackages;
inherit (import ./packages.nix { inherit pkgs customGlibc; }) commonPackages;
# Each forces something absent on the other platform, so both stay lazy.
linux = import ./linux.nix { inherit pkgs customGlibc; };
@@ -21,7 +21,8 @@ let
)
);
toolchain = if pkgs.stdenv.isLinux then linux.toolchain else (darwin.toolchain ++ [ darwinEnv ]);
toolchain =
if pkgs.stdenv.hostPlatform.isLinux then linux.toolchain else (darwin.toolchain ++ [ darwinEnv ]);
in
{
default = pkgs.buildEnv {

View File

@@ -20,15 +20,19 @@ let
# Custom-glibc stdenvs, matching the CI environment. darwin has no custom
# glibc, so there they fall back to the plain nixpkgs stdenvs.
customGccStdenv = if pkgs.stdenv.isLinux then linux.gccStdenv else plainGccStdenv;
customClangStdenv = if pkgs.stdenv.isLinux then linux.clangStdenv else plainClangStdenv;
customGccStdenv = if pkgs.stdenv.hostPlatform.isLinux then linux.gccStdenv else plainGccStdenv;
customClangStdenv =
if pkgs.stdenv.hostPlatform.isLinux then linux.clangStdenv else plainClangStdenv;
# gcov matching each gcc shell, so `-Dcoverage=ON` builds work in the shell.
plainGcov = mkGcov {
name = "plain";
cc = gccPackage.cc;
};
customGccGcov = if pkgs.stdenv.isLinux then linux.gcov else plainGcov;
customGccGcov = if pkgs.stdenv.hostPlatform.isLinux then linux.gcov else plainGcov;
# commonPackages whose clang tools parse with the custom toolchain's headers.
customCommonPackages = (import ./packages.nix { inherit pkgs customGlibc; }).commonPackages;
# Whole directory: init.sh locates the profiles relative to itself.
conanDir = ../conan;
@@ -51,7 +55,7 @@ let
# Not sdkEnv: a shell's stdenv already sets that up. Prepended so the stub
# beats the nixpkgs libresolv this shell's tooling drags in.
darwinLibresolvHook = pkgs.lib.optionalString pkgs.stdenv.isDarwin (
darwinLibresolvHook = pkgs.lib.optionalString pkgs.stdenv.hostPlatform.isDarwin (
pkgs.lib.concatLines (
pkgs.lib.mapAttrsToList (
name: value: ''export ${name}="${value} ''${${name}:-}"''
@@ -85,11 +89,11 @@ let
version ? null,
versionedTools ? [ ],
extraPackages ? [ ],
warningHook ? "",
# Opt out of PatchNixBinary.cmake retargeting binaries to the system
# loader. The plain toolchain links a newer glibc, so it must not be
# patched; the custom toolchain patches by default.
noPatchNixBinary ? false,
# The stock nixpkgs toolchain: warn that it doesn't match CI, keep the
# clang tools off the custom toolchain, and opt out of PatchNixBinary.cmake
# retargeting binaries to the system loader (the plain toolchain links a
# newer glibc, so it must not be patched).
plain ? false,
}:
let
compilerVersionHook =
@@ -109,7 +113,8 @@ let
in
(pkgs.mkShell.override { inherit stdenv; }) (
{
packages = commonPackages ++ versionedLinks ++ extraPackages;
packages =
(if plain then commonPackages else customCommonPackages) ++ versionedLinks ++ extraPackages;
# Marks a managed dev shell, so the build (XrplSanity.cmake) can tell an
# intentional Nix toolchain from one leaked into a bare shell.
XRPL_DEVSHELL = shellName;
@@ -118,15 +123,15 @@ let
${compilerVersionHook}
${darwinLibresolvHook}
${conanHook}
${warningHook}
${pkgs.lib.optionalString plain plainWarningHook}
'';
}
// pkgs.lib.optionalAttrs noPatchNixBinary { XRPLD_NO_PATCH_NIX_BINARY = "1"; }
// pkgs.lib.optionalAttrs plain { XRPLD_NO_PATCH_NIX_BINARY = "1"; }
);
in
rec {
# macOS: Nix Clang. Linux: Nix GCC.
default = if pkgs.stdenv.isDarwin then clang else gcc;
default = if pkgs.stdenv.hostPlatform.isDarwin then clang else gcc;
# gcc/clang use the custom-glibc toolchain, matching CI. On darwin there is no
# custom glibc, so they fall back to the plain nixpkgs toolchain.
@@ -171,7 +176,7 @@ rec {
# The *-plain shells (stock nixpkgs toolchain) exist only on Linux: on darwin
# gcc/clang are already plain, so these would be redundant and are omitted, which
# makes `nix develop .#gcc-plain` fail there rather than silently aliasing gcc.
// pkgs.lib.optionalAttrs pkgs.stdenv.isLinux {
// pkgs.lib.optionalAttrs pkgs.stdenv.hostPlatform.isLinux {
gcc-plain = makeShell {
shellName = "gcc-plain";
stdenv = plainGccStdenv;
@@ -179,8 +184,7 @@ rec {
version = gccVersion;
versionedTools = gccVersionedTools;
extraPackages = [ plainGcov ];
warningHook = plainWarningHook;
noPatchNixBinary = true;
plain = true;
};
clang-plain = makeShell {
@@ -189,7 +193,6 @@ rec {
compilerName = "clang";
version = llvmVersion;
versionedTools = clangVersionedTools;
warningHook = plainWarningHook;
noPatchNixBinary = true;
plain = true;
};
}

View File

@@ -60,10 +60,10 @@ ENV GIT_SSL_CAINFO="/nix/ci-env/etc/ssl/certs/ca-bundle.crt"
# 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 bin/default-loader-path.sh /tmp/loader-path.sh
COPY bin/nix/default-loader-path.sh /usr/local/bin/default-loader-path.sh
RUN <<EOF
target="$(/tmp/loader-path.sh)"
target="$(/usr/local/bin/default-loader-path.sh)"
if [ ! -e "${target}" ]; then
# Use the loader from the same glibc that gcc links libc against, so
@@ -101,7 +101,7 @@ RUN if echo "${BASE_IMAGE}" | grep -qiE 'nixos'; then \
SHELL ["/bin/bash", "-e", "-o", "pipefail", "-c"]
# Sanity-check that the built binaries run correctly in the vanilla base image, with the necessary sanitizer runtime libraries installed.
COPY bin/install-sanitizer-libs.sh /tmp/install-sanitizer-libs.sh
COPY bin/install/sanitizer-libs.sh /tmp/install-sanitizer-libs.sh
COPY nix/docker/test_files/cpp/run-binaries.sh /tmp/test_files/cpp/run-binaries.sh
COPY nix/docker/test_files/rust/run-binaries.sh /tmp/test_files/rust/run-binaries.sh
COPY --from=final /tmp/cpp-bins /tmp/cpp-bins

View File

@@ -52,10 +52,10 @@ work without `ca-certificates` being installed in the base image.
workspace with `cargo` to exercise proc-macro dylib loading.
3. **`tester`** — Start again from a clean `BASE_IMAGE` (no Nix toolchain),
install only the sanitizer runtime libraries
([`install-sanitizer-libs.sh`](./install-sanitizer-libs.sh)), and run the
binaries compiled in `final`. This proves the binaries built with the Nix
toolchain actually run on a vanilla base image. On `nixos/nix` this step is
skipped (the binaries are patched for a conventional FHS loader).
([`bin/install/sanitizer-libs.sh`](../../bin/install/sanitizer-libs.sh)),
and run the binaries compiled in `final`. This proves the binaries built with
the Nix toolchain actually run on a vanilla base image. On `nixos/nix` this
step is skipped (the binaries are patched for a conventional FHS loader).
4. **Output** — The final image is gated on the tester succeeding: it copies a
sentinel file out of `tester`, so a failed test run fails the whole build.
@@ -75,9 +75,10 @@ toolchain being present at runtime. Two pieces make that work:
- **An expected dynamic linker in the image.**
Binaries built in Nix environments reference a dynamic linker from Nix store paths, which won't be present in the base image. However,
[`bin/default-loader-path.sh`](../../bin/default-loader-path.sh) reports the
[`bin/nix/default-loader-path.sh`](../../bin/nix/default-loader-path.sh) reports the
expected loader path for the current architecture, so we can patch the binaries
to use the correct loader.
to use the correct loader. The image ships it as
`/usr/local/bin/default-loader-path.sh`.
The build then verifies all of this end to end, and the C++ and Rust programs
go through the same pipeline: each is compiled in `final`, has its `PT_INTERP`
@@ -91,11 +92,11 @@ whose resulting binary is patched and run like the others.
## Files
| File | Purpose |
| ----------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
| [`./Dockerfile`](./Dockerfile) | Multi-stage build described above. |
| [`./test_files/cpp/`](./test_files/cpp) | C++ sanitizer smoke test: sources + compile/run scripts. |
| [`./test_files/rust/`](./test_files/rust) | Rust smoke test: rustc sources + a cargo proc-macro workspace + compile/run scripts. |
| [`/bin/check-tools.sh`](../../bin/check-tools.sh) | Verify every expected tools are present and runnable. |
| [`/bin/default-loader-path.sh`](../../bin/default-loader-path.sh) | Print the dynamic-linker (`PT_INTERP`) path for the current architecture. |
| [`/bin/install-sanitizer-libs.sh`](../../bin/install-sanitizer-libs.sh) | Install `libasan`/`libtsan`/`libubsan` runtimes on the supported base images. |
| File | Purpose |
| ------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
| [`./Dockerfile`](./Dockerfile) | Multi-stage build described above. |
| [`./test_files/cpp/`](./test_files/cpp) | C++ sanitizer smoke test: sources + compile/run scripts. |
| [`./test_files/rust/`](./test_files/rust) | Rust smoke test: rustc sources + a cargo proc-macro workspace + compile/run scripts. |
| [`/bin/check-tools.sh`](../../bin/check-tools.sh) | Verify every expected tools are present and runnable. |
| [`/bin/nix/default-loader-path.sh`](../../bin/nix/default-loader-path.sh) | Print the dynamic-linker (`PT_INTERP`) path for the current architecture. |
| [`/bin/install/sanitizer-libs.sh`](../../bin/install/sanitizer-libs.sh) | Install `libasan`/`libtsan`/`libubsan` runtimes on the supported base images. |

View File

@@ -8,7 +8,7 @@ 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)"
loader="$(/usr/local/bin/default-loader-path.sh)"
mkdir -p "${dst_dir}"

View File

@@ -8,7 +8,7 @@ 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)"
loader="$(/usr/local/bin/default-loader-path.sh)"
mkdir -p "${dst_dir}"

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