Compare commits

...

129 Commits

Author SHA1 Message Date
Pratik Mankawde
66eb04171a Merge develop into pratik/ranged-normalize-number-at-construction 2026-10-02 09:17:53 +01:00
Ayaz Salikhov
97fbea23cc build: Determine version based on tags only (#8457) 2026-10-01 20:52:53 +00:00
Ayaz Salikhov
e6055ddbe1 build: Push docker image for antithesis with voidstar (#8341) 2026-10-01 19:12:36 +00:00
Ayaz Salikhov
a5c76fde2d ci: Add guardrails for release backporting (#8449) 2026-10-01 13:35:58 +00:00
Ayaz Salikhov
eed6527946 style: Update pre-commit hooks (#8456) 2026-10-01 13:35:37 +00:00
Alex Kremer
ddbc5f1a24 fix: Resolve IntrusivePointer leak (#8328)
Co-authored-by: Valentin Balaschenko <13349202+vlntb@users.noreply.github.com>
2026-09-30 15:51:25 +00:00
Alex Kremer
97a1824537 chore: CamelCase for typedef/using in clang-tidy (#8177) 2026-09-30 15:17:18 +00:00
Ayaz Salikhov
b44c87613c release: Merge release/3.4.x into develop
Content was already merged via #8239 (rebased); this records the merge so future release/3.4.x merges don't replay it.
2026-09-30 14:08:23 +01:00
Bart
b3bbf50d40 refactor: Make the config name constants constexpr string views (#8332)
Co-authored-by: Bart <11445373+bthomee@users.noreply.github.com>
2026-09-30 10:50:18 +00:00
Bart
53246e5b15 fix: Count cluster traffic only from cluster members (#8319)
Co-authored-by: Bart <11445373+bthomee@users.noreply.github.com>
2026-09-30 10:32:25 +00:00
Bart
7e82b0660f fix: Queue a transaction hash only for peers that asked for it (#8309) 2026-09-30 10:31:21 +00:00
rachelflynn
8ef1bdd346 docs: Add notes about common acronyms (#8298) 2026-09-29 19:04:55 +00:00
Ayaz Salikhov
3a2d19f980 build: Support custom release channel (#8326) 2026-09-29 18:16:15 +00:00
Gregory Tsipenyuk
04eca6d6c3 fix: Round up MPT owner cost in book_offers running balance (#8213) 2026-09-29 13:59:37 +00:00
Bart
768aef30dc fix: Count cluster messages as cluster traffic (#8308) 2026-09-29 12:30:58 +00:00
Ayaz Salikhov
97cddd6721 build: Publish a Docker image from GitHub (#8322) 2026-09-28 20:14:48 +00:00
Alex Kremer
e4dbd7de3a refactor: Add initial integration of rpc-spec (#8284) 2026-09-28 18:22:04 +00:00
Kassaking7
646d2ce620 feat: Introduce Cosign v1 amendment with TransactionProposalCreate (#8205)
Co-authored-by: Shawn Xie <35279399+shawnxie999@users.noreply.github.com>
Co-authored-by: Shawn Xie <shawnxie@live.ca>
2026-09-28 16:25:19 +00:00
dependabot[bot]
6641896e9f chore: [DEPENDABOT] bump cxx from 1.0.199 to 1.0.202 in /crates in the rust-dependencies group across 1 directory (#8224)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-28 10:00:47 +00:00
Olek
d6df33ff03 test: Add source location to MPTTester (#8275) 2026-09-25 06:35:38 +00:00
Bart
1d7669f528 refactor: Unify upperBound and lowerBound into boundHelper (#7943)
Co-authored-by: Bart <11445373+bthomee@users.noreply.github.com>
Co-authored-by: vlntb <13349202+vlntb@users.noreply.github.com>
2026-09-24 12:48:25 +00:00
Pratik Mankawde
09b9cf8d6a docs: Cut the unverifiable clauses from normalizeToRange
The @note comparing this overload to the two-pass path stated where the two
diverge and called the first range "strictly wider". Both were wrong: they also
diverge below kMinExponent, and MantissaScale::Small is the IOU range exactly,
not wider. The comparison is not a contract a caller needs, so drop it rather
than reword it, and state only what the function returns.
2026-09-23 18:22:35 +01:00
yinyiqian1
30640a626f test: Clean up ConfidentialTransfer test helpers (#8265) 2026-09-23 16:24:41 +00:00
Pratik Mankawde
2c2b747881 fix: Correct the zero sentinel and narrow the equivalence claim
Two review findings on the static normalizeToRange documentation, both
confirmed against the code.

The documented zero result was wrong. doNormalize copies the canonical zero
out of a default-constructed Number, and Number's exponent_ is initialised to
std::numeric_limits<int>::lowest(), not 0. normalizeToRangeImpl returns that
exponent unchanged, so a zero mantissa yields {0, lowest()}.

The "bit-identical to the two-pass path" note was unconditionally false. At
exponent == kMinExponent the scale-up loop cannot run, so a mantissa below the
wider range's minimum falls into doNormalize's zero branch: building a Number
first collapses 10^17e-32768 to zero, while normalizing straight to the IOU
range scales down and returns {10^15, kMinExponent + 2}. The single pass is the
more accurate of the two, so the note is narrowed to the exponents IOUAmount
can actually reach rather than the code changed to reproduce the loss.

Add tests pinning both, since nothing covered a zero mantissa or the exponent
floor.
2026-09-23 15:41:00 +01:00
Pratik Mankawde
b41e92f7b3 chore: Satisfy pre-commit hooks on ranged normalizeToRange
Two hooks were failing the run-hooks job.

fix-gtest-names requires a CamelCase suite and a snake_case test case, so
rename the four new test cases. They also sat on a `Number` suite of their
own while the rest of the file uses `NumberTest`, which meant a
`--gtest_filter=NumberTest.*` run silently skipped them; move them onto
`NumberTest` so one filter selects all 35.

clang-format reflowed the `@return` text of the static normalizeToRange
because the zero-mantissa sentence ran to 104 columns, over the 100-column
limit. Wrap that sentence by hand instead, and restore the `@note` line
recording that the result is bit-identical to the two-pass path: an earlier
edit replaced two lines with one and dropped it, leaving its continuation
"pass to a strictly wider range ..." as a sentence fragment with no subject.
2026-09-23 14:54:13 +01:00
Pratik Mankawde
d188083da3 Update documentation for mantissa and exponent return values
Clarified documentation regarding zero mantissa handling.

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-09-23 14:35:33 +01:00
Pratik Mankawde
5b17c3369d Merge branch 'develop' into pratik/ranged-normalize-number-at-construction 2026-09-23 14:31:09 +01:00
Alex Kremer
5a5ad8673a style: Precommit hook for gtest naming (#8026)
Co-authored-by: Bart <bthomee@users.noreply.github.com>
2026-09-22 22:39:23 +00:00
Copilot
8f4e9c25d8 fix: Add CTID to ledger command expanded transactions (#6401)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Mayukha Vadari <mvadari@gmail.com>
Co-authored-by: Mayukha Vadari <mvadari@ripple.com>
Co-authored-by: xrplf-ai-reviewer[bot] <266832837+xrplf-ai-reviewer[bot]@users.noreply.github.com>
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-09-22 20:19:05 +00:00
Bart
d8870162eb test: Share peer test doubles across the overlay and app suites (#8246)
Co-authored-by: Bart <11445373+bthomee@users.noreply.github.com>
2026-09-22 20:03:55 +00:00
yinyiqian1
8b1a2282c3 feat: Support ConfidentialMPTMirrorUpdate (#8192) 2026-09-22 17:56:52 +00:00
yinyiqian1
0219c01b33 fix: Check zero object id in SponsorshipTransfer preflight (#8254)
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-09-22 17:02:59 +00:00
Bart
00606bec1a fix: Derive traversal node IDs from the branch actually descended (#7942)
Co-authored-by: Bart <11445373+bthomee@users.noreply.github.com>
2026-09-22 14:02:11 +00:00
Mayukha Vadari
2bc17c3e73 refactor: Add initial wrapper classes for all SLEs (#7886) 2026-09-21 19:47:23 +00:00
dependabot[bot]
0229c294a9 ci: [DEPENDABOT] bump codecov/codecov-action from 7.0.0 to 7.1.1 in the github-actions group across 1 directory (#8251)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-21 12:09:57 +00:00
Bart
184fe173fb refactor: Remove a dead unwrap from the WebSocket success path (#8252)
Co-authored-by: Bart <11445373+bthomee@users.noreply.github.com>
2026-09-21 11:23:31 +00:00
Bart
16f7b263fd docs: Correct three comments about null-terminated views (#8253)
Co-authored-by: Bart <11445373+bthomee@users.noreply.github.com>
2026-09-21 11:12:09 +00:00
Bart
f6b51f0b8b ci: Say when a package publish is a dry run (#8247)
Co-authored-by: Bart <11445373+bthomee@users.noreply.github.com>
2026-09-18 18:31:07 +00:00
Denis Angell
07b36871c7 ci: Publish packages through packages-upload.xrplf.org (#8241) 2026-09-17 18:05:51 +00:00
Bart
638ae08eeb chore: Bump version to 3.5.0-b0 2026-09-17 13:33:08 +02:00
yinyiqian1
24be48ee84 fix: Reject PaymentBurn payments that cross zero balance 2026-09-17 13:33:08 +02:00
Pratik Mankawde
e20f448a71 fix: Reject variable-length prefixes the encoder cannot write 2026-09-17 13:33:07 +02:00
Vito Tumas
f6c80fef68 fix: Relax MPT authorize cap for LoanSet and VaultWithdraw 2026-09-17 13:33:07 +02:00
Gregory Tsipenyuk
a0c12420b5 fix: Skip CheckCash limit waiver for the issuer 2026-09-17 13:33:06 +02:00
Ayaz Salikhov
1245254cac build: Add missing script to conan package 2026-09-17 13:33:06 +02:00
Jingchen
b60636169a fix: Make calculateBaseFee exception-safe 2026-09-17 13:33:06 +02:00
Ayaz Salikhov
d6022fbc4d build: Fix test installation on debian:11 due to EOL 2026-09-17 13:33:06 +02:00
Ayaz Salikhov
295b74da1c build: Add assert-enabled builds and packages 2026-09-17 13:33:05 +02:00
Timothy Banks
faa2bf583f fix: Cap TMTransactions list size and charge fee for undeserializable transactions 2026-09-17 13:33:04 +02:00
Vito Tumas
da260fa42b fix: Relax Loan Invariants to allow zero-principal LoanPay transaction 2026-09-17 13:33:04 +02:00
Timothy Banks
53788b193d test: Add ProtocolMessage harness for testing TMPing 2026-09-17 13:33:03 +02:00
Timothy Banks
227f1b4d9c fix: Unbounded Database Seek via TMGetLedger 2026-09-17 13:33:03 +02:00
Ed Hennis
26b66957ec fix: Trim unknown fields when parsing incoming peer protobuf messages 2026-09-17 13:33:02 +02:00
Mayukha Vadari
54e62a621f fix: Prevent simulate from updating the orderbook db 2026-09-17 13:33:02 +02:00
Timothy Banks
53628b70c0 fix: Use a hardened hash on the STPathElement 2026-09-17 13:33:01 +02:00
Vito Tumas
6fec2c11bf refactor: Rename vault accrual accounting to instant interest recognition (#8237) 2026-09-17 10:27:44 +00:00
Bart
04108a030c refactor: Build the RPC dispatch and command-line tables at compile time (#8006)
Co-authored-by: Bart <11445373+bthomee@users.noreply.github.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 10:01:28 +00:00
Bart
4a4fded2eb chore: Bump version to 3.4.0 2026-09-16 18:23:54 +02:00
yinyiqian1
c8e767afa4 fix: Reject PaymentBurn payments that cross zero balance 2026-09-16 18:23:28 +02:00
Pratik Mankawde
00eeb0a005 fix: Reject variable-length prefixes the encoder cannot write 2026-09-16 18:23:28 +02:00
Vito Tumas
a18839d92d fix: Relax MPT authorize cap for LoanSet and VaultWithdraw 2026-09-16 18:23:28 +02:00
Gregory Tsipenyuk
8c594c7ed9 fix: Skip CheckCash limit waiver for the issuer 2026-09-16 18:22:39 +02:00
Ayaz Salikhov
ebd810b184 build: Add missing script to conan package 2026-09-16 18:22:26 +02:00
Jingchen
3e4e56d6bb fix: Make calculateBaseFee exception-safe 2026-09-16 18:22:26 +02:00
Ayaz Salikhov
76da5d4475 build: Fix test installation on debian:11 due to EOL 2026-09-16 18:22:26 +02:00
Ayaz Salikhov
c0d0fd0d97 build: Add assert-enabled builds and packages 2026-09-16 18:22:26 +02:00
Timothy Banks
9aebb5ebea fix: Cap TMTransactions list size and charge fee for undeserializable transactions 2026-09-16 18:22:26 +02:00
Vito Tumas
796f2f8f1e fix: Relax Loan Invariants to allow zero-principal LoanPay transaction 2026-09-16 18:22:26 +02:00
Timothy Banks
b190f2b14f test: Add ProtocolMessage harness for testing TMPing 2026-09-16 18:22:25 +02:00
Bart
551a19b10d refactor: Add Cluster::isMember, a membership query that copies nothing (#8221)
Co-authored-by: Bart <11445373+bthomee@users.noreply.github.com>
2026-09-15 20:40:29 +00:00
Peter Chen
b0a940a383 refactor: Extract common tx-building helpers for ConfidentialMPT in MPTTester (#8135) 2026-09-15 17:13:44 +00:00
Bart
e302e4eeed fix: Set the peer limit total when per-direction limits are configured (#8220)
Co-authored-by: Bart <11445373+bthomee@users.noreply.github.com>
Co-authored-by: Vito Tumas <5780819+Tapanito@users.noreply.github.com>
2026-09-15 13:14:12 +00:00
Mayukha Vadari
1a4a40ebb8 fix: Update noripple_check to exclude transactions field on error responses (#6303)
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-09-15 00:21:57 +00:00
yinyiqian1
7f55dd390c feat: Support mirror key epochs in confidential MPT transactions for Key Rotation amendment (#8210) 2026-09-14 18:23:38 +00:00
Sergey Kuznetsov
9403736199 ci: Exclude Rust unit tests from code coverage (#8203) 2026-09-10 11:38:25 +00:00
Mayukha Vadari
028783661d feat: Apply .macro changes from ripple/smart-escrow (#8157)
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-09-09 20:05:58 +00:00
Vito Tumas
21890d9daf feat: Register featureLendingProtocolV1_2 amendment (#8185)
Co-authored-by: Bart <bthomee@users.noreply.github.com>
2026-09-09 10:01:32 +00:00
Sergey Kuznetsov
060957ed39 ci: Add nightly Rust toolchain to the CI image (#8182)
Co-authored-by: Bart <bthomee@users.noreply.github.com>
2026-09-09 01:24:28 +00:00
Ayaz Salikhov
1381483c7a build: Fix test installation on debian:11 due to EOL (#8200) 2026-09-08 22:49:16 +00:00
dependabot[bot]
3e4bdf2782 ci: [DEPENDABOT] bump actions/deploy-pages from 5.0.0 to 5.0.1 in the github-actions group across 1 directory (#8180)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-07 16:07:56 +00:00
Mayukha Vadari
e3c8996e44 feat: Add fixCleanup3_5_0 amendment placeholder (#8174) 2026-09-05 00:06:14 +00:00
Timothy Banks
6099940c2c fix: Unbounded Database Seek via TMGetLedger 2026-09-04 15:32:36 +01:00
Ed Hennis
0db7b766e6 fix: Trim unknown fields when parsing incoming peer protobuf messages 2026-09-04 10:32:08 +00:00
Mayukha Vadari
ea6226b8b9 fix: Prevent simulate from updating the orderbook db 2026-09-04 06:17:43 -04:00
yinyiqian1
d5bfe94f15 feat: Support key rotation in MPTokenIssuanceSet (#7915) 2026-09-03 21:13:06 +00:00
Timothy Banks
eae0a35415 fix: Use a hardened hash on the STPathElement 2026-09-03 17:06:27 -04:00
Bart
2ad4def35f chore: Bump version to 3.4.0-rc1 (#8171)
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-09-03 20:07:24 +00:00
Mayukha Vadari
f7f50caa6e docs: Backfill API-CHANGELOG.md for 3.1.1 through 3.3.0 (#8159) 2026-09-03 19:48:15 +00:00
Ayaz Salikhov
3e54e7d00b fix: Don't use github.workspace as it slow downs gcovr (#8173) 2026-09-03 19:20:38 +00:00
Valentin Balaschenko
827b50f169 fix: Flaky online delete tests, and cover the health checks added in #5531 (#8137) 2026-09-03 18:56:30 +00:00
Mayukha Vadari
58a59c37ed fix: Add signature prefixes for sfCounterpartySignature and sfSponsorSignature (#8162) 2026-09-03 17:19:07 +00:00
Ayaz Salikhov
986065c16f build: Verify glibc version was determined in debian package (#8170) 2026-09-03 16:54:54 +00:00
Denis Angell
37cb4cdbe3 fix: Recycle the escrow reserve in EscrowCancel and EscrowFinish (#8142) 2026-09-03 16:27:45 +00:00
Bart
2ddf6ee148 ci: Update pre-commit SHA (#8169)
Co-authored-by: Bart <11445373+bthomee@users.noreply.github.com>
2026-09-03 14:52:42 +00:00
Pratik Mankawde
8ce4f71427 docs: Use consistent heading levels in PR template (#8155) 2026-09-03 14:48:32 +00:00
Bart
6e1eb88e6e ci: Update prepare-runner SHA (#8168)
Co-authored-by: Bart <11445373+bthomee@users.noreply.github.com>
2026-09-03 11:52:08 +00:00
Ayaz Salikhov
49cdc105de fix: Correct and simplify Linux packaging (#8165) 2026-09-02 21:18:13 +00:00
Chenna Keshava B S
636d2d4851 fix: Reinforce the priority of AMMClawback in case of insufficient reserves (#7796)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-09-02 20:48:53 +00:00
Kassaking7
7d7275847d fix: PermissionedDEX (CreateOffer/Payment) never deletes expired credentials (#6827) 2026-09-02 19:38:01 +00:00
Bart
f0fd6ad85e fix: Clamp the depth used to index selectBranch's key byte (#7941)
Co-authored-by: Bart <11445373+bthomee@users.noreply.github.com>
2026-09-02 18:06:48 +00:00
Timur Yalymov
5d8fd9824e fix: Revert credential cleanup for pseudo-accounts (#8161) 2026-09-02 15:00:50 +00:00
Vito Tumas
346ea40f69 fix: Allow zero-value MPT vault withdraw when the asset holding is missing (#8153) 2026-09-02 13:45:52 +00:00
Vito Tumas
8809bdf3f0 fix: Treat an existing IOU line as a no-op in addEmptyHolding (#8154) 2026-09-02 12:15:29 +00:00
Mayukha Vadari
deaf596494 docs: Add AGENTS.md/CLAUDE.md for AI coding agent guidance (#8067) 2026-09-01 21:57:34 +00:00
Vito Tumas
7863ac8cf6 fix: Add 60s buffer before closed-ended vault redemption (#8151) 2026-09-01 18:27:05 +00:00
Vito Tumas
b3b38e4416 fix: Correct fee-payer XRP delta in ValidVault for sponsored VaultWithdraw (#8141) 2026-09-01 14:43:11 +00:00
Vito Tumas
ccd5dc5e06 fix: Keep LoanBrokerDelete valid for auth-required MPT cover (#8144) 2026-09-01 14:40:53 +00:00
Vito Tumas
b2453b626e fix: Unblock VaultSet and cash-basis LoanSet at AssetsMaximum (#8143) 2026-09-01 14:06:17 +00:00
Vito Tumas
de6e5d3a94 fix: Keep VaultDeposit share count after the assetsTotal clamp (#8140) 2026-09-01 13:51:39 +00:00
Copilot
fac20a06f3 refactor: Add common helper function for injected metadata fields in RPCs (#5706)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Mayukha Vadari <mvadari@gmail.com>
Co-authored-by: Mayukha Vadari <mvadari@ripple.com>
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-08-31 17:21:25 +00:00
Ayaz Salikhov
9a7c5ea593 chore: Bump version to 3.4.0-b3 (#8132) 2026-08-27 17:26:55 +00:00
Jingchen
7281e0606a feat: Add vault invariants (#7732)
Co-authored-by: Vito Tumas <5780819+Tapanito@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-08-27 17:15:17 +00:00
Jingchen
71f5555873 feat: Remove pseudo account field filter (#8042)
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-08-27 13:52:23 +00:00
Ayaz Salikhov
3967ed6d54 build: Update release-info to get better pkg_release (#8131) 2026-08-27 13:34:38 +00:00
Vito Tumas
e0151229b6 fix: Waive unrealized-loss discount on sole-holder VaultClawback (#8119) 2026-08-27 08:15:38 +00:00
Ayaz Salikhov
b6a899583b build: Make packaging reusable (#8126) 2026-08-26 19:44:31 +00:00
Gregory Tsipenyuk
dc3bd9cf00 fix: Fix MPT/DEX Audit/Attackathon reports (Phase 1) (#7334) 2026-08-26 18:09:46 +00:00
Vito Tumas
1e8b136bfb feat: Enable LendingProtocolV1_1 amendment (#8125) 2026-08-26 17:35:54 +00:00
Vito Tumas
3c47af779c fix: Clamp Vault Deposit, Withdraw, and Clawback to assetsTotal grid (#8057)
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-08-26 17:02:05 +00:00
Ayaz Salikhov
c28d389e0e build: Refactor generate.py to make packaging_config part of config (#8115) 2026-08-26 14:04:58 +00:00
Pratik Mankawde
54e052d8bb refactor: extract IOUAmount exponent bounds check into a helper
The exponent bounds check appeared verbatim in both normalize() and
IOUAmount(Number const&). Extract it into a private
enforceExponentBounds() and call it from both.

Named "enforce" rather than "check" because the function acts on the
value as well as inspecting it: it throws above the range and truncates
to zero below it. That matches the codebase precedent of requireAuth
(a pure predicate) versus enforceMPTokenAuthorization (which mutates).

Defined out of line because a header inline would need STAmount's
offset constants, and STAmount.h already includes IOUAmount.h.

No behavior change: the extracted body is identical to both original
blocks, and the Number constructor still applies it after delegating
construction completes.
2026-07-29 13:11:51 +01:00
Pratik Mankawde
b292d11797 minor missed check
Signed-off-by: Pratik Mankawde <3397372+pratikmankawde@users.noreply.github.com>
2026-07-27 15:55:20 +01:00
Pratik Mankawde
b0c9ef48d1 Merge branch 'develop' into pratik/ranged-normalize-number-at-construction
Signed-off-by: Pratik Mankawde <3397372+pratikmankawde@users.noreply.github.com>
2026-07-27 15:11:31 +01:00
Pratik Mankawde
fb75b4f70c code review comments
Signed-off-by: Pratik Mankawde <3397372+pratikmankawde@users.noreply.github.com>
2026-06-09 16:57:23 +01:00
Pratik Mankawde
809b617bb7 Merge branch 'develop' into pratik/ranged-normalize-number-at-construction 2026-06-09 16:50:02 +01:00
Pratik Mankawde
0480d951e6 micro benchmark tests
Signed-off-by: Pratik Mankawde <3397372+pratikmankawde@users.noreply.github.com>
2026-06-03 13:23:15 +01:00
Pratik Mankawde
14fef306dd clang-tidy fixes
Signed-off-by: Pratik Mankawde <3397372+pratikmankawde@users.noreply.github.com>
2026-06-03 11:30:40 +01:00
Pratik Mankawde
d3d2cf0c9a Merge branch 'develop' into pratik/ranged-normalize-number-at-construction 2026-06-02 19:03:00 +01:00
Pratik Mankawde
87eb3fcf3b perf: Add single-pass ranged normalization to Number
IOUAmount::normalize() previously built a Number (one normalize pass to
the default Large range) and then re-normalized down to the narrower IOU
range via fromNumber (a second pass) -- two full passes where one would
do.

Add a static Number::normalizeToRange<Min,Max>(mantissa, exponent) that
normalizes raw integers straight to a target range in a single pass,
building no intermediate Number. Refactor the existing const member
overload to share one implementation, so both paths have a single source
of truth. Rewire the getSTNumberSwitchover()-true branch of
IOUAmount::normalize() to call the new primitive.

The result is bit-identical to the old two-pass path: an intermediate
pass to a strictly wider range cannot change the final narrower-range
result. Equivalence is proven by new GTests that sweep mantissa/exponent
boundaries, negatives, int64 extremes, rounding cusps, and all four
rounding modes against the prior two-pass result, plus exact-value
assertions on hand-computed cases.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 18:56:06 +01:00
1167 changed files with 41285 additions and 11872 deletions

View File

@@ -90,6 +90,13 @@ CheckOptions:
readability-identifier-naming.ClassCase: CamelCase
readability-identifier-naming.StructCase: CamelCase
readability-identifier-naming.UnionCase: CamelCase
readability-identifier-naming.TypeAliasCase: CamelCase
readability-identifier-naming.TypedefCase: CamelCase
# Member type names mandated by std/Boost concepts. Subtrees that need more
# than these carry their own .clang-tidy (include/xrpl/{beast,basics,protocol,
# peerfinder}, src/test/beast); one-off cases use an inline NOLINT.
readability-identifier-naming.TypeAliasIgnoredRegexp: "^(const_iterator|const_reference|difference_type|duration|iterator|iterator_category|key_type|mapped_type|period|pointer|reference|rep|result_type|size_type|time_point|value_type)$"
readability-identifier-naming.TypedefIgnoredRegexp: "^(const_iterator|const_reference|difference_type|duration|iterator|iterator_category|key_type|mapped_type|period|pointer|reference|rep|result_type|size_type|time_point|value_type)$"
readability-identifier-naming.EnumCase: CamelCase
readability-identifier-naming.EnumConstantCase: CamelCase
readability-identifier-naming.ScopedEnumConstantCase: CamelCase
@@ -122,5 +129,5 @@ CheckOptions:
readability-identifier-naming.GlobalFunctionIgnoredRegexp: "^(to_string|hash_append|tuple_hash)$"
HeaderFilterRegex: '^.*/(tests?|xrpl|xrpld)/.*\.(h|hpp|ipp)$'
ExcludeHeaderFilterRegex: '^.*/protocol_autogen/.*\.(h|hpp)$'
ExcludeHeaderFilterRegex: '^.*/protocol_autogen/.*\.(h|hpp)$|^.*\.pb\.h$'
WarningsAsErrors: "*"

View File

@@ -64,6 +64,7 @@ words:
- blindings
- bookdir
- Bougalis
- bthomee
- Britto
- Btrfs
- Buildx
@@ -141,6 +142,7 @@ words:
- hwrap
- ifndef
- inequation
- Injectivity
- insuf
- insuff
- invasively
@@ -366,7 +368,6 @@ words:
- venv
- vfalco
- vinnie
- vkeylet
- wasmi
- wextra
- wptr
@@ -387,3 +388,4 @@ words:
- xxhasher
- zstdio
- CGNAT
- ungated

View File

@@ -7,84 +7,33 @@ outputs:
value: ${{ steps.version.outputs.version }}
channel:
description: "The release channel this build belongs to."
value: ${{ steps.channel.outputs.channel }}
value: ${{ steps.release_info.outputs.channel }}
pkg_release:
description: "The package release number: 1 for a tag, the run number otherwise."
value: ${{ steps.pkg_release.outputs.pkg_release }}
description: "The package release number: 1 for a tag, <run number>.<commit date>git<short commit hash> otherwise."
value: ${{ steps.release_info.outputs.pkg_release }}
runs:
using: composite
steps:
# A tag names its own version. Anything else takes it from BuildInfo.cpp and
# appends the commit hash as build metadata, joined with a plus sign because a
# Conan version cannot contain two hyphens.
# A tag names its own version. Anything else is a development build named by
# its commit hash, matching what cmake/XrplVersion.cmake derives: the head of
# a pull request rather than the merge commit GitHub creates for it.
- name: Determine version
id: version
shell: bash
env:
IS_TAG: ${{ startsWith(github.ref, 'refs/tags/') }}
REF_NAME: ${{ github.ref_name }}
SHA: ${{ github.sha }}
SHA: ${{ github.event.pull_request.head.sha || github.sha }}
run: |
if [[ "${IS_TAG}" == "true" ]]; then
version="${REF_NAME}"
else
version="$(awk -F'"' '/versionString =/ { print $2 }' src/libxrpl/protocol/BuildInfo.cpp)"
if [[ -z "${version}" ]]; then
echo "Unable to read versionString from BuildInfo.cpp." >&2
exit 1
fi
version="${version}+${SHA:0:7}"
version="0.0.0-dev+${SHA:0:7}"
fi
echo "version=${version}" | tee -a "${GITHUB_OUTPUT}"
# Only a tag says how mature a build is: a push is a develop build whatever
# its version, and a non-public codebase keeps its packages to itself.
- name: Determine release channel
id: channel
shell: bash
env:
IS_TAG: ${{ startsWith(github.ref, 'refs/tags/') }}
REF_NAME: ${{ github.ref_name }}
VISIBILITY: ${{ github.event.repository.visibility }}
run: |
pre_release=""
if [[ "${REF_NAME}" == *-* ]]; then
pre_release="${REF_NAME#*-}"
fi
if [[ "${VISIBILITY}" != "public" ]]; then
channel=private
elif [[ "${IS_TAG}" != "true" ]]; then
channel=develop
elif [[ -z "${pre_release}" ]]; then
channel=stable
elif [[ "${pre_release}" =~ ^rc[0-9]+(\+.*)?$ ]]; then
channel=rc
elif [[ "${pre_release}" =~ ^b(0|[1-9][0-9]*)(\+.*)?$ ]]; then
channel=beta
else
echo "Unsupported pre-release in tag '${REF_NAME}'. Use bN or rcN." >&2
exit 1
fi
echo "channel=${channel}" | tee -a "${GITHUB_OUTPUT}"
# A tag is packaged once, so its release number is fixed at 1. Develop builds
# repeat the same version, so the run number is what makes each push an
# upgrade rather than a reinstall.
- name: Determine package release
id: pkg_release
shell: bash
env:
IS_TAG: ${{ startsWith(github.ref, 'refs/tags/') }}
RUN_NUMBER: ${{ github.run_number }}
run: |
if [[ "${IS_TAG}" == "true" ]]; then
pkg_release=1
else
pkg_release="${RUN_NUMBER}"
fi
echo "pkg_release=${pkg_release}" | tee -a "${GITHUB_OUTPUT}"
- name: Determine release channel and package release
id: release_info
uses: XRPLF/actions/release-info@ebcf6cea14eee258697308a51fea55cad777581b

View File

@@ -40,10 +40,11 @@ runs:
# Unlike the Linux nix images, macOS needs no SSL_CERT_FILE: it has its
# own trust store, and pinning would break TLS to hosts relying on it.
# Workspace-local, so `cleanup-workspace` clears it, but not the
# `.conan2` prepare-runner hands the system toolchain: that Conan is a
# different version, and the two would migrate each other's cache.
echo "CONAN_HOME=${{ github.workspace }}/.conan2-nix" >>"${GITHUB_ENV}"
# In RUNNER_TEMP, which the runner empties per job, like the `.conan2`
# prepare-runner hands the system toolchain - but under its own name:
# that Conan is a different version, and the two would migrate each
# other's cache.
echo "CONAN_HOME=${RUNNER_TEMP}/.conan2-nix" >>"${GITHUB_ENV}"
# Config, profiles and remote, exactly as the dev shell sets them up on
# entry; the `setup-conan` action is skipped for this toolchain.

View File

@@ -18,7 +18,7 @@ If too broad, please consider splitting into multiple PRs.
If there is a relevant task or issue, please link it here.
-->
### Context of Change
## Context of Change
<!--
Please include the context of a change.
@@ -29,7 +29,7 @@ If a refactor, how is this better than the previous implementation?
If there is a spec or design document for this feature, please link it here.
-->
### API Impact
## API Impact
<!--
Please check [x] relevant options, delete irrelevant ones.

View File

@@ -82,7 +82,6 @@ test.app > xrpl.tx
test.basics > test.jtx
test.basics > xrpl.basics
test.basics > xrpl.core
test.basics > xrpld.rpc
test.basics > xrpl.json
test.basics > xrpl.protocol
test.beast > xrpl.basics
@@ -113,6 +112,7 @@ test.jtx > xrpl.config
test.jtx > xrpl.core
test.jtx > xrpld.app
test.jtx > xrpld.core
test.jtx > xrpld.overlay
test.jtx > xrpld.rpc
test.jtx > xrpl.json
test.jtx > xrpl.ledger
@@ -194,6 +194,9 @@ tests.libxrpl > xrpl.resource
tests.libxrpl > xrpl.server
tests.libxrpl > xrpl.shamap
tests.libxrpl > xrpl.tx
tests.xrpld > xrpld.rpc
tests.xrpld > xrpl.json
tests.xrpld > xrpl.protocol
xrpl.conditions > xrpl.basics
xrpl.conditions > xrpl.protocol
xrpl.config > xrpl.basics
@@ -286,10 +289,10 @@ xrpld.perflog > xrpl.basics
xrpld.perflog > xrpl.config
xrpld.perflog > xrpl.core
xrpld.perflog > xrpld.app
xrpld.perflog > xrpld.rpc
xrpld.perflog > xrpl.json
xrpld.perflog > xrpl.nodestore
xrpld.perflog > xrpl.protocol
xrpld.perflog > xrpl.server
xrpld.rpc > xrpl.basics
xrpld.rpc > xrpl.config
xrpld.rpc > xrpl.core

View File

@@ -0,0 +1,47 @@
#!/bin/bash
# Exit the script as soon as an error occurs.
set -euo pipefail
# This script fails if the commits in <base>..<head> copy commits from a release or staging branch
# (e.g. by rebasing or cherry-picking them) instead of merging that branch, see RELEASING.md.
# Commits are compared by patch-id,
# and only against release and staging commits that <head> does not already contain.
# Usage: .github/scripts/releasing/check-no-copied-release-commits.sh <base> <head>
if [ "$#" -ne 2 ]; then
echo "Usage: $0 <base> <head>"
exit 1
fi
BASE=$1
HEAD=$2
patch_ids() {
git log --no-merges --patch --no-color --no-ext-diff "$@" | git patch-id --stable | sort
}
mapfile -t BRANCHES < <(git for-each-ref --format='%(refname)' 'refs/remotes/*/release/*' 'refs/remotes/*/staging/*')
if [ "${#BRANCHES[@]}" -eq 0 ]; then
echo "Error: No release or staging branches found."
exit 1
fi
# Each line is "<patch-id> <commit>".
RELEASE_PATCHES=$(patch_ids "${BRANCHES[@]}" --not "${HEAD}")
PR_PATCHES=$(patch_ids "${BASE}..${HEAD}")
# Each line is "<patch-id> <release commit> <PR commit>".
COPIES=$(join <(echo "${RELEASE_PATCHES}") <(echo "${PR_PATCHES}"))
if [ -z "${COPIES}" ]; then
echo "No copied release commits found."
exit 0
fi
echo "These commits copy release commits instead of merging them:"
while read -r _ RELEASE_COMMIT PR_COMMIT; do
echo " $(git log -1 --format='%h %s' "${PR_COMMIT}") (copies ${RELEASE_COMMIT:0:10})"
done <<<"${COPIES}"
echo
echo "Merge the release tag (or branch) instead, see RELEASING.md."
exit 1

View File

@@ -0,0 +1,46 @@
#!/bin/bash
# Exit the script as soon as an error occurs.
set -euo pipefail
# This script fails if a final release (a tag like 3.4.0) on a release branch
# is not merged back into <develop> within a few days, see RELEASING.md.
# Usage: .github/scripts/releasing/check-releases-merged.sh <develop>
if [ "$#" -ne 1 ]; then
echo "Usage: $0 <develop>"
exit 1
fi
DEVELOP=$1
GRACE_DAYS=3
mapfile -t MERGED_ARGS < <(git for-each-ref --format='--merged=%(refname)' 'refs/remotes/*/release/*')
if [ "${#MERGED_ARGS[@]}" -eq 0 ]; then
echo "Error: No release branches found."
exit 1
fi
# Tags on a release branch that <develop> does not contain.
TAGS=$(git for-each-ref --format='%(refname:short) %(creatordate:unix)' \
"${MERGED_ARGS[@]}" --no-merged="${DEVELOP}" 'refs/tags/[0-9]*')
MISSING=0
while read -r TAG CREATED; do
if ! [[ "${TAG}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
continue
fi
if (($(date +%s) - CREATED < GRACE_DAYS * 86400)); then
echo "${TAG}: not merged yet, still within the ${GRACE_DAYS}-day grace period."
else
echo "${TAG}: not merged into develop."
MISSING=1
fi
done <<<"${TAGS}"
if [ "${MISSING}" -ne 0 ]; then
echo
echo "Merge the missing releases back into develop, see RELEASING.md."
exit 1
fi
echo "No releases past the grace period are missing from develop."

View File

@@ -62,7 +62,7 @@ ${SED_COMMAND} -i 's@ripple/@xrpld/@g' src/test/core/Config_test.cpp
${SED_COMMAND} -i 's/Rippled/File/g' src/test/core/Config_test.cpp
# Restore the old config file name in the code that maintains support for now.
${SED_COMMAND} -i 's/kConfigLegacyName = "xrpld.cfg"/kConfigLegacyName = "rippled.cfg"/g' src/xrpld/core/detail/Config.cpp
${SED_COMMAND} -i 's/kConfigLegacyName = "xrpld.cfg"/kConfigLegacyName = "rippled.cfg"/g' src/xrpld/core/Config.h
# Restore an URL.
${SED_COMMAND} -i 's/connect-your-xrpld-to-the-xrp-test-net.html/connect-your-rippled-to-the-xrp-test-net.html/g' cfg/xrpld-example.cfg

View File

@@ -90,7 +90,7 @@ ${SED_COMMAND} -i 's/www.ripple.com/www.xrpl.org/g' src/test/protocol/Seed_test.
# Restore specific changes.
${SED_COMMAND} -i 's@b5efcc/src/xrpld@b5efcc/src/ripple@' include/xrpl/protocol/README.md
${SED_COMMAND} -i 's/dbPrefix_ = "xrpldb"/dbPrefix_ = "rippledb"/' src/xrpld/app/misc/SHAMapStoreImp.h # cspell: disable-line
${SED_COMMAND} -i 's/kConfigLegacyName = "xrpld.cfg"/kConfigLegacyName = "rippled.cfg"/' src/xrpld/core/detail/Config.cpp
${SED_COMMAND} -i 's/kConfigLegacyName = "xrpld.cfg"/kConfigLegacyName = "rippled.cfg"/' src/xrpld/core/Config.h
popd
echo "Renaming complete."

View File

@@ -15,6 +15,14 @@ _BASE_CMAKE_ARGS = [
"-Drust=ON",
]
# The package formats a config can be packaged as, each with its own
# install-test job in reusable-package.yml.
PACKAGE_TYPES = ("deb", "rpm")
# The package name a variant suffixes, as build_pkg.py's BASE_NAME spells it:
# the two have to agree, or the artifact globs miss what was built.
BASE_NAME = "xrpld"
# Maps sanitizer names (as used in cmake) to short config-name suffixes.
_SANITIZER_SUFFIX: dict[str, str] = {
"address": "asan",
@@ -23,6 +31,19 @@ _SANITIZER_SUFFIX: dict[str, str] = {
}
def config_name(
distro: str,
compiler: str,
build_type: str,
arch: str,
suffix: str = "",
sanitizer: str = "",
) -> str:
"""Name a config. Its artifacts are named after it, so packaging reuses this."""
parts = [s for s in [suffix, _SANITIZER_SUFFIX.get(sanitizer, "")] if s]
return "-".join([f"{distro}-{compiler}-{build_type.lower()}-{arch}", *parts])
def get_cmake_args(build_type: str, extra_args: str) -> str:
"""Get the full list of CMake arguments for a config."""
args = _BASE_CMAKE_ARGS.copy()
@@ -37,17 +58,37 @@ def get_cmake_args(build_type: str, extra_args: str) -> str:
# Every config must declare 'minimal'. Minimal configs form the reduced matrix
# built for pull requests by default; the full matrix adds the rest. Packaging
# configs declare it too, but packaging is gated in the workflow, not by it.
# built for pull requests by default; the full matrix adds the rest.
#
# Configs may also opt into 'benchmark' to smoke-run the benchmarks. Note that
# the flag applies to every entry a config expands into, so only set it on
# configs that expand to a single combination.
# Configs may also opt into 'benchmark' to smoke-run the benchmarks, or carry a
# 'package' map to be packaged as well. Note that either applies to every entry
# a config expands into, so only set them on configs that expand to a single
# combination.
@dataclasses.dataclass
class PackageConfig:
"""The 'package' map of a config whose binaries are also packaged."""
type: str # has to match what the image provides
# The packaging container image: a vanilla distro image, not the nix image
# the config itself builds in.
image: str
# A flavour of the package, named xrpld-<variant>, for a config whose
# binaries are not the plain release build. A variant needs no counterpart
# in the other format.
variant: str = ""
def __post_init__(self) -> None:
assert self.type in PACKAGE_TYPES, (
f"unsupported package type {self.type!r}: "
f"use one of {', '.join(PACKAGE_TYPES)}."
)
@dataclasses.dataclass
class LinuxConfig:
"""One entry in linux.json's 'configs' or 'package_configs' arrays."""
"""One entry in a linux.json 'configs' array."""
compiler: list[str]
build_type: list[str]
@@ -57,9 +98,11 @@ class LinuxConfig:
sanitizers: list[str] = dataclasses.field(default_factory=list)
suffix: str = ""
extra_cmake_args: str = ""
# The two below are only used by package_configs entries.
image: str = ""
package_type: str = "" # "deb" or "rpm"; has to match what image provides
package: PackageConfig | None = None # set to also package this config
def __post_init__(self) -> None:
if isinstance(self.package, dict):
self.package = PackageConfig(**self.package)
@dataclasses.dataclass
@@ -68,22 +111,16 @@ class LinuxFile:
image_tag: str
configs: dict[str, list[LinuxConfig]] # distro → configs
package_configs: dict[str, list[LinuxConfig]] # distro → packaging configs
@classmethod
def load(cls, path: Path) -> "LinuxFile":
data = json.loads(path.read_text())
def parse(section: dict) -> dict[str, list[LinuxConfig]]:
return {
distro: [LinuxConfig(**c) for c in cfgs]
for distro, cfgs in section.items()
}
return cls(
image_tag=data["image_tag"],
configs=parse(data["configs"]),
package_configs=parse(data.get("package_configs", {})),
configs={
distro: [LinuxConfig(**c) for c in cfgs]
for distro, cfgs in data["configs"].items()
},
)
@@ -159,6 +196,8 @@ class PackagingEntry:
validator_keys_artifact_name: str
image: str
package_type: str # "deb" or "rpm"; drives the format-specific steps
package_variant: str # passed to build_pkg.py --variant; empty for xrpld
package_name: str # the name it builds under, which the artifact globs use
# ---------------------------------------------------------------------------
@@ -199,13 +238,9 @@ def expand_linux_matrix(linux: LinuxFile, minimal: bool) -> list[MatrixEntry]:
effective_sanitizers,
effective_archs.items(),
):
name = f"{distro}-{compiler}-{build_type.lower()}-{arch}"
suffix_parts = [
s for s in [cfg.suffix, _SANITIZER_SUFFIX.get(sanitizer, "")] if s
]
if suffix_parts:
name += "-" + "-".join(suffix_parts)
name = config_name(
distro, compiler, build_type, arch, cfg.suffix, sanitizer
)
entries.append(
MatrixEntry(
config_name=name,
@@ -225,33 +260,59 @@ def expand_linux_matrix(linux: LinuxFile, minimal: bool) -> list[MatrixEntry]:
def expand_linux_packaging(linux: LinuxFile) -> list[PackagingEntry]:
"""Generate the packaging matrix from a LinuxFile's package_configs section.
"""Generate the packaging matrix from the configs that carry a 'package' map.
Packaging uses vanilla distro images (debian:bookworm, almalinux:9) instead of
the nix-based build images, because deb/rpm tooling (debhelper, rpm-build)
is taken from the distro's archive rather than from nixpkgs. Each config
entry carries its own 'image'.
Packaging consumes the binaries that config's build job uploaded, so the
artifact names come from the same config name, and a packaged config is one
that passes -Dvalidator_keys=ON.
The artifact names must match what the build job uploads: one artifact per
binary, each named after the build config.
Packaging itself runs in vanilla distro images (debian:trixie, almalinux:10)
instead of the nix-based build images, because deb/rpm tooling (debhelper,
rpm-build) is taken from the distro's archive rather than from nixpkgs.
"""
entries = []
for distro, configs in linux.package_configs.items():
for distro, configs in linux.configs.items():
for cfg in configs:
for compiler, build_type in itertools.product(cfg.compiler, cfg.build_type):
config_name = f"{distro}-{compiler}-{build_type.lower()}-amd64"
if cfg.package is None:
continue
for compiler, build_type, arch in itertools.product(
cfg.compiler, cfg.build_type, cfg.arch
):
# The packaging workflow hardcodes an amd64 runner.
assert arch == "amd64", f"cannot package {distro} on {arch}"
name = config_name(distro, compiler, build_type, arch, cfg.suffix)
entries.append(
PackagingEntry(
xrpld_artifact_name=f"xrpld-{config_name}",
validator_keys_artifact_name=f"validator-keys-{config_name}",
image=cfg.image,
package_type=cfg.package_type,
xrpld_artifact_name=f"xrpld-{name}",
validator_keys_artifact_name=f"validator-keys-{name}",
image=cfg.package.image,
package_type=cfg.package.type,
package_variant=cfg.package.variant,
package_name=(
f"{BASE_NAME}-{cfg.package.variant}"
if cfg.package.variant
else BASE_NAME
),
)
)
return entries
def package_names_by_type(entries: list[PackagingEntry]) -> dict[str, list[str]]:
"""The names of the packages in 'entries', keyed by format.
Derived from the packaging matrix rather than listed again, so the packages
the install-test jobs look for are the packages that were built.
"""
return {
package_type: sorted(
{e.package_name for e in entries if e.package_type == package_type}
)
for package_type in PACKAGE_TYPES
}
def expand_platform_matrix(pf: PlatformFile, minimal: bool) -> list[MatrixEntry]:
"""Expand a PlatformFile (macOS or Windows) into matrix entries.
@@ -320,6 +381,10 @@ if __name__ == "__main__":
if args.packaging:
matrix = expand_linux_packaging(LinuxFile.load(THIS_DIR / "linux.json"))
# One list per format, so each install-test job installs the packages its
# own format produced.
for package_type, names in package_names_by_type(matrix).items():
print(f"{package_type}_package_names={json.dumps(names)}")
else:
if args.config in ("linux", None):
matrix += expand_linux_matrix(

View File

@@ -1,5 +1,5 @@
{
"image_tag": "sha-473fe44",
"image_tag": "sha-060957e",
"configs": {
"ubuntu": [
{
@@ -71,7 +71,24 @@
"build_type": ["Release"],
"arch": ["amd64"],
"minimal": false,
"extra_cmake_args": "-Dvalidator_keys=ON"
"extra_cmake_args": "-Dvalidator_keys=ON",
"package": {
"type": "deb",
"image": "ghcr.io/xrplf/xrpld/packaging-debian:sha-3a2d19f"
}
},
{
"compiler": ["gcc"],
"build_type": ["Release"],
"arch": ["amd64"],
"minimal": false,
"suffix": "assert",
"extra_cmake_args": "-Dvalidator_keys=ON -Dassert=ON",
"package": {
"type": "deb",
"image": "ghcr.io/xrplf/xrpld/packaging-debian:sha-3a2d19f",
"variant": "assert"
}
}
],
@@ -81,30 +98,11 @@
"build_type": ["Release"],
"arch": ["amd64"],
"minimal": false,
"extra_cmake_args": "-Dvalidator_keys=ON"
}
]
},
"package_configs": {
"debian": [
{
"compiler": ["gcc"],
"build_type": ["Release"],
"arch": ["amd64"],
"minimal": false,
"image": "ghcr.io/xrplf/xrpld/packaging-debian:sha-45e4b88",
"package_type": "deb"
}
],
"rhel": [
{
"compiler": ["gcc"],
"build_type": ["Release"],
"arch": ["amd64"],
"minimal": false,
"image": "ghcr.io/xrplf/xrpld/packaging-rhel:sha-45e4b88",
"package_type": "rpm"
"extra_cmake_args": "-Dvalidator_keys=ON",
"package": {
"type": "rpm",
"image": "ghcr.io/xrplf/xrpld/packaging-rhel:sha-3a2d19f"
}
}
]
}

View File

@@ -5,15 +5,13 @@ on:
branches:
- develop
paths:
- ".github/workflows/build-nix-images.yml"
- "flake.nix"
- "flake.lock"
- "rust-toolchain.toml"
- "nix/**"
- "!nix/docker/README.md"
- "!nix/devshell.nix"
- "!nix/check-tools/*.txt"
- "bin/check-tools.sh"
- "!nix/check-tools/**"
- "bin/default-loader-path.sh"
- "bin/install-sanitizer-libs.sh"
pull_request:
@@ -25,7 +23,7 @@ on:
- "nix/**"
- "!nix/docker/README.md"
- "!nix/devshell.nix"
- "!nix/check-tools/*.txt"
- "!nix/check-tools/**"
- "bin/check-tools.sh"
- "bin/default-loader-path.sh"
- "bin/install-sanitizer-libs.sh"
@@ -60,7 +58,7 @@ jobs:
base_image: debian:bookworm
- name: rhel
base_image: registry.access.redhat.com/ubi9/ubi:latest
uses: XRPLF/actions/.github/workflows/build-multiarch-image.yml@65d5a0bd72be4ecea95cff0673a6e0672ab5243a
uses: XRPLF/actions/.github/workflows/build-multiarch-image.yml@696384b292577293292daed06af0306d1b83bd7d
with:
image_name: xrpld/nix-${{ matrix.distro.name }}
dockerfile: nix/docker/Dockerfile

View File

@@ -6,13 +6,13 @@ on:
- develop
paths:
- ".github/workflows/build-packaging-images.yml"
- "package/Dockerfile"
- "package/install-packaging-tools.sh"
- "bin/install-packaging-tools.sh"
- "package/images/packaging/**"
pull_request:
paths:
- ".github/workflows/build-packaging-images.yml"
- "package/Dockerfile"
- "package/install-packaging-tools.sh"
- "bin/install-packaging-tools.sh"
- "package/images/packaging/**"
workflow_dispatch:
concurrency:
@@ -41,9 +41,9 @@ jobs:
# AlmaLinux rather than UBI, which does not ship rpm-sign.
- name: rhel
base_image: almalinux:10
uses: XRPLF/actions/.github/workflows/build-multiarch-image.yml@65d5a0bd72be4ecea95cff0673a6e0672ab5243a
uses: XRPLF/actions/.github/workflows/build-multiarch-image.yml@696384b292577293292daed06af0306d1b83bd7d
with:
image_name: xrpld/packaging-${{ matrix.distro.name }}
dockerfile: package/Dockerfile
dockerfile: package/images/packaging/Dockerfile
base_image: ${{ matrix.distro.base_image }}
push: ${{ github.event_name == 'push' }}

View File

@@ -30,7 +30,7 @@ jobs:
permissions:
contents: read
packages: write
uses: XRPLF/actions/.github/workflows/build-multiarch-image.yml@65d5a0bd72be4ecea95cff0673a6e0672ab5243a
uses: XRPLF/actions/.github/workflows/build-multiarch-image.yml@696384b292577293292daed06af0306d1b83bd7d
with:
image_name: xrpld/pre-commit
dockerfile: bin/pre-commit/Dockerfile

View File

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

View File

@@ -13,7 +13,6 @@ on:
- ready_for_review
branches:
- develop
- "release-*"
- "release/*"
- "staging/*"

View File

@@ -13,7 +13,6 @@ on:
- ready_for_review
branches:
- develop
- "release-*"
- "release/*"
- "staging/*"

View File

@@ -0,0 +1,60 @@
# This workflow checks that every final release on a release branch
# has been merged back into develop, see RELEASING.md.
name: Check releases merged
on:
schedule:
# 06:47 UTC every Monday.
- cron: "47 6 * * 1"
push:
branches:
- "develop"
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
defaults:
run:
shell: bash
env:
OUTPUT_FILE: /tmp/releases-merged.txt
ISSUE_FILE: /tmp/releases-merged-issue.md
jobs:
releases-merged:
runs-on: ubuntu-latest
permissions:
contents: read
# Needed to open an issue on scheduled failures.
issues: write
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
# The check needs the full history of develop, the release branches and tags.
fetch-depth: 0
- name: Check releases are merged into develop
run: |
set -o pipefail
.github/scripts/releasing/check-releases-merged.sh origin/develop | tee "${OUTPUT_FILE}"
- name: Prepare issue body
if: ${{ failure() && github.event_name == 'schedule' && github.repository == 'XRPLF/rippled' }}
run: |
{
echo '```'
cat "${OUTPUT_FILE}"
echo '```'
} >"${ISSUE_FILE}"
- name: Create issue
if: ${{ failure() && github.event_name == 'schedule' && github.repository == 'XRPLF/rippled' }}
uses: XRPLF/actions/create-issue@2b8bc36af85b88bca0dd7bfac2e2dc05f94ad712
with:
title: "Releases not merged back into develop"
body_file: ${{ env.ISSUE_FILE }}
labels: "Bug"

View File

@@ -79,7 +79,7 @@ jobs:
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Prepare runner
uses: XRPLF/actions/prepare-runner@7bf7ceca5932114abdd0d43493c3c30c5a654e13
uses: XRPLF/actions/prepare-runner@b3e255d74d785d053e4903da8ac90983cd7d9e82
with:
enable_ccache: false

View File

@@ -85,6 +85,7 @@ jobs:
.github/workflows/reusable-build-test.yml
.github/workflows/reusable-check-autogen.yml
.github/workflows/reusable-clang-tidy.yml
.github/workflows/reusable-package-test-install.yml
.github/workflows/reusable-package.yml
.github/workflows/reusable-rust.yml
.github/workflows/reusable-strategy-matrix.yml
@@ -149,6 +150,27 @@ jobs:
if: ${{ needs.should-run.outputs.go == 'true' }}
uses: ./.github/workflows/reusable-check-rename.yml
# Runs regardless of the changed files.
# PRs into staging branches are skipped, since fixes may be cherry-picked between release lines.
check-release-commits:
needs: should-run
if: ${{ github.event.pull_request.base.ref == 'develop' || github.event.merge_group.base_ref == 'refs/heads/develop' }}
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
# The check needs the full history of the release and staging branches.
fetch-depth: 0
persist-credentials: false
- name: Check for copied release commits
env:
BASE: ${{ github.event.pull_request.base.sha || github.event.merge_group.base_sha }}
HEAD: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }}
run: .github/scripts/releasing/check-no-copied-release-commits.sh "${BASE}" "${HEAD}"
clang-tidy:
needs: should-run
if: ${{ needs.should-run.outputs.go == 'true' }}
@@ -189,6 +211,12 @@ jobs:
# matrix (i.e. not yet labeled "Ready to merge" or "Full CI build").
if: ${{ needs.should-run.outputs.go == 'true' && (github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'Ready to merge') || contains(github.event.pull_request.labels.*.name, 'Full CI build')) }}
uses: ./.github/workflows/reusable-package.yml
with:
# A pull request builds packages to prove they still build, and publishes
# nothing. Stated rather than left to the input's default, so that changing
# that default cannot start publishing from pull requests. No secrets are
# passed either, which is the second reason a publish here cannot succeed.
publish: false
upload-recipe:
needs:
@@ -223,6 +251,7 @@ jobs:
- check-autogen
- check-levelization
- check-rename
- check-release-commits
- clang-tidy
- build-test
- rust

View File

@@ -1,9 +1,12 @@
# When a versioned tag is pushed, this workflow:
#
# - uploads the libxrpl recipe to the Conan remote
# - builds and tests the release binaries
# - uploads the libxrpl recipe to the Conan remote
# - builds the DEB and RPM packages
# - publishes those packages to the XRPLF package repositories
#
# Nothing is published unless the build passes, which is also where CMake
# rejects a tag that is not a valid version, e.g. 3.2.01.
name: Tag
on:
@@ -22,6 +25,7 @@ defaults:
jobs:
upload-recipe:
if: ${{ github.repository == 'XRPLF/rippled' }}
needs: build-test
uses: ./.github/workflows/reusable-upload-recipe.yml
secrets:
remote_username: ${{ secrets.NEXUS_REMOTE_USERNAME }}
@@ -50,3 +54,7 @@ jobs:
remote_username: ${{ secrets.NEXUS_REMOTE_USERNAME }}
remote_password: ${{ secrets.NEXUS_REMOTE_PASSWORD }}
signing_key: ${{ secrets.NEXUS_PACKAGES_PRIVATE_KEY }}
dockerhub_token: ${{ secrets.DOCKERHUB_TOKEN }}
antithesis_docker_host: ${{ secrets.ANTITHESIS_DOCKER_HOST }}
antithesis_docker_path: ${{ secrets.ANTITHESIS_DOCKER_PATH }}
antithesis_docker_credentials: ${{ secrets.ANTITHESIS_DOCKER_CREDENTIALS }}

View File

@@ -23,6 +23,7 @@ on:
- ".github/workflows/reusable-build-test.yml"
- ".github/workflows/reusable-check-autogen.yml"
- ".github/workflows/reusable-clang-tidy.yml"
- ".github/workflows/reusable-package-test-install.yml"
- ".github/workflows/reusable-package.yml"
- ".github/workflows/reusable-rust.yml"
- ".github/workflows/reusable-strategy-matrix.yml"
@@ -128,3 +129,7 @@ jobs:
remote_username: ${{ secrets.NEXUS_REMOTE_USERNAME }}
remote_password: ${{ secrets.NEXUS_REMOTE_PASSWORD }}
signing_key: ${{ secrets.NEXUS_PACKAGES_PRIVATE_KEY }}
dockerhub_token: ${{ secrets.DOCKERHUB_TOKEN }}
antithesis_docker_host: ${{ secrets.ANTITHESIS_DOCKER_HOST }}
antithesis_docker_path: ${{ secrets.ANTITHESIS_DOCKER_PATH }}
antithesis_docker_credentials: ${{ secrets.ANTITHESIS_DOCKER_CREDENTIALS }}

View File

@@ -14,7 +14,7 @@ on:
jobs:
# Call the workflow in the XRPLF/actions repo that runs the pre-commit hooks.
run-hooks:
uses: XRPLF/actions/.github/workflows/pre-commit.yml@f1952595d212e86169935135efc66294b4574131
uses: XRPLF/actions/.github/workflows/pre-commit.yml@279ec358f4a1be4088be3e024b07916fa97c75b6
with:
runs_on: ubuntu-latest
container: '{ "image": "ghcr.io/xrplf/xrpld/pre-commit:sha-473fe44" }'

View File

@@ -41,13 +41,13 @@ env:
jobs:
build:
runs-on: ubuntu-latest
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-473fe44
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-060957e
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Prepare runner
uses: XRPLF/actions/prepare-runner@7bf7ceca5932114abdd0d43493c3c30c5a654e13
uses: XRPLF/actions/prepare-runner@b3e255d74d785d053e4903da8ac90983cd7d9e82
with:
enable_ccache: false
@@ -91,4 +91,4 @@ jobs:
steps:
- name: Deploy to GitHub Pages
id: deploy
uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5.0.0
uses: actions/deploy-pages@368f82528645a54fb793d4d04e342629a3f51346 # v5.0.1

View File

@@ -129,7 +129,7 @@ jobs:
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Prepare runner
uses: XRPLF/actions/prepare-runner@7bf7ceca5932114abdd0d43493c3c30c5a654e13
uses: XRPLF/actions/prepare-runner@b3e255d74d785d053e4903da8ac90983cd7d9e82
with:
enable_ccache: ${{ inputs.ccache_enabled }}
@@ -196,6 +196,19 @@ jobs:
env:
BUILD_TYPE: ${{ inputs.build_type }}
CMAKE_ARGS: ${{ inputs.cmake_args }}
# GitHub creates a merge commit for a PR
# https://www.kenmuse.com/blog/the-many-shas-of-a-github-pull-request/
#
# We:
# - explicitly provide branch name
# - use `github.event.pull_request.head.sha` to get the SHA of last commit in the PR branch
#
# This way it works both for PRs and pushes to branches.
GITHUB_BRANCH_NAME: "${{ github.head_ref || github.ref_name }}"
GITHUB_HEAD_SHA: "${{ github.event.pull_request.head.sha || github.sha }}"
#
# If tag is being pushed, we use that version.
FORCE_XRPLD_VERSION: ${{ startsWith(github.ref, 'refs/tags/') && github.ref_name || '' }}
run: |
cmake \
-G '${{ runner.os == 'Windows' && 'Visual Studio 18 2026' || 'Ninja' }}' \
@@ -257,6 +270,7 @@ jobs:
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"
- name: Show ccache statistics
if: ${{ inputs.ccache_enabled }}
@@ -338,7 +352,9 @@ jobs:
- name: Run the separate tests
if: ${{ !inputs.build_only }}
working-directory: ${{ runner.os == 'Windows' && format('{0}/{1}', env.BUILD_DIR, inputs.build_type) || env.BUILD_DIR }}
run: ./xrpl_tests
run: |
./xrpl_tests
./xrpld_tests
- name: Run the embedded tests
if: ${{ !inputs.build_only }}
@@ -439,7 +455,7 @@ jobs:
- name: Upload coverage report
if: ${{ github.repository_owner == 'XRPLF' && !inputs.build_only && env.COVERAGE_ENABLED == 'true' }}
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
uses: codecov/codecov-action@303a32d7a59b442fa8d48b6a1cc6825c09c847a5 # v7.1.1
with:
disable_search: true
disable_telem: true

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-473fe44"
container: "ghcr.io/xrplf/xrpld/nix-debian:sha-060957e"
permissions:
contents: read
issues: write
@@ -43,7 +43,7 @@ jobs:
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Prepare runner
uses: XRPLF/actions/prepare-runner@7bf7ceca5932114abdd0d43493c3c30c5a654e13
uses: XRPLF/actions/prepare-runner@b3e255d74d785d053e4903da8ac90983cd7d9e82
with:
enable_ccache: false

View File

@@ -0,0 +1,120 @@
# Install one package format on every distro family it targets, one job per
# package name and image, and run the binaries there. Called once per format by
# reusable-package.yml, which owns the names and the image lists.
name: Install packages
on:
workflow_call:
inputs:
package_type:
description: 'The package format to install ("deb" or "rpm").'
required: true
type: string
package_names:
description: "JSON array of package names built for this format."
required: true
type: string
images:
description: "JSON array of container images to install in."
required: true
type: string
defaults:
run:
shell: bash
env:
PACKAGE_DIR: packages
jobs:
install:
strategy:
fail-fast: false
matrix:
package_name: ${{ fromJson(inputs.package_names) }}
image: ${{ fromJson(inputs.images) }}
name: "${{ matrix.package_name }} on ${{ matrix.image }}"
permissions:
contents: read
runs-on: ubuntu-latest
container: ${{ matrix.image }}
timeout-minutes: 5
steps:
# Every package lands in one directory; the step below picks its own,
# which keeps this independent of the artifact names.
- name: Download package artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
pattern: "*-pkg"
merge-multiple: true
path: ${{ env.PACKAGE_DIR }}
- name: Find the package
id: find
env:
PACKAGE_NAME: ${{ matrix.package_name }}
PACKAGE_TYPE: ${{ inputs.package_type }}
run: |
# The version follows the name, separated by '_' in a DEB and '-' in an
# RPM. Requiring a digit after it is what keeps 'xrpld' from picking up
# another package, such as 'xrpld-assert'.
pattern="${PACKAGE_NAME}[_-][0-9]*.${PACKAGE_TYPE}"
package="$(find "${PACKAGE_DIR}" -type f -name "${pattern}" -print -quit)"
test -n "${package}" || {
echo "no ${pattern} found in ${PACKAGE_DIR}" >&2
exit 1
}
echo "package=${package}" >>"${GITHUB_OUTPUT}"
# Debian 11 went end-of-life on 2026-08-31
# (https://www.debian.org/News/2026/20260831) and its packages are
# already partly gone from deb.debian.org, so switch to the
# snapshot.debian.org entries the image ships commented out in its
# sources.list: they are pinned to the snapshot the image was built
# from, so they serve every version it needs and never go away.
# Snapshots keep their original, long-passed Valid-Until, hence the
# disabled check; the retries absorb snapshot.debian.org's throttling.
- name: Switch Debian 11 to snapshot.debian.org
if: ${{ matrix.image == 'debian:11' }}
run: |
sed -i 's|^deb |# deb |; s|^# deb http://snapshot|deb http://snapshot|' /etc/apt/sources.list
printf '%s\n' \
'Acquire::Check-Valid-Until "false";' \
'Acquire::Retries "3";' \
>/etc/apt/apt.conf.d/99snapshot
- name: Install the DEB
if: ${{ inputs.package_type == 'deb' }}
env:
DEBIAN_FRONTEND: noninteractive
PACKAGE: ${{ steps.find.outputs.package }}
run: |
# Stock Debian and Ubuntu images carry no package lists, so apt has
# nothing to resolve the systemd dependency from until it fetches them.
apt-get update -qq
apt-get install -y "./${PACKAGE}"
- name: Install the RPM
if: ${{ inputs.package_type == 'rpm' }}
env:
PACKAGE: ${{ steps.find.outputs.package }}
run: dnf install -y "./${PACKAGE}"
- name: Run xrpld
run: xrpld --version
- name: Run validator-keys
run: validator-keys --version
- name: Run rippled, the legacy compatibility symlink
run: rippled --version
- name: Check the service account
run: id xrpld
- name: Check the state directory
run: test -d /var/lib/xrpld
- name: Check the log directory
run: test -d /var/log/xrpld

View File

@@ -1,11 +1,19 @@
# Build Linux packages from the pre-built xrpld and validator-keys artifacts:
# Build, verify and publish Linux packages from the pre-built xrpld and
# validator-keys artifacts, in these stages:
#
# - one job per distro, taken from "package_configs" in linux.json
# - each entry names its container image and the format it builds there
# - with 'publish: true' a job also uploads what it built
# (see package/publish_pkg.py)
# - 'package' builds and signs one format per config that carries a "package"
# map in linux.json; that map names the container image and the format
# - 'test-install-deb' and 'test-install-rpm' call
# reusable-package-test-install.yml to install what was built on a range of
# distros and run the binaries there, so a package that cannot be installed
# never reaches Nexus
# - 'publish' uploads with the image's publish_pkg.py, doing a --dry-run
# unless 'publish: true'
# - 'docker' builds an Ubuntu image from the tested DEB, and one with the
# voidstar binary for Antithesis, pushing them to Docker Hub and to the
# Antithesis registry only with 'publish: true'
#
# Only linux/amd64 is supported; the runner is hardcoded in the job below.
# Only linux/amd64 is supported; the runner is hardcoded in the jobs below.
name: Package
on:
@@ -20,7 +28,7 @@ on:
description: "The base URL of the Nexus instance hosting the deb and rpm repositories."
required: false
type: string
default: https://packages.xrplf.org
default: https://packages-upload.xrplf.org
secrets:
remote_username:
@@ -30,7 +38,19 @@ on:
description: "The password or token for that Nexus account."
required: false
signing_key:
description: "Armoured PGP private key used to sign the RPMs. Required when publishing."
description: "Armoured PGP private key used to sign the RPMs."
required: false
dockerhub_token:
description: "A Docker Hub organization access token for xrplf, with push access to xrplf/xrpld."
required: false
antithesis_docker_host:
description: "The host of the Antithesis container registry, e.g. us-central1-docker.pkg.dev."
required: false
antithesis_docker_path:
description: "The repository path in that registry, the image name excluded."
required: false
antithesis_docker_credentials:
description: "The JSON key of a service account with push access to that repository."
required: false
defaults:
@@ -39,12 +59,15 @@ defaults:
env:
BUILD_DIR: build
PACKAGE_DIR: packages
jobs:
generate-matrix:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.generate.outputs.matrix }}
deb_package_names: ${{ steps.generate.outputs.deb_package_names }}
rpm_package_names: ${{ steps.generate.outputs.rpm_package_names }}
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
@@ -70,12 +93,17 @@ jobs:
contents: read
runs-on: ["self-hosted", "Linux", "X64", "heavy"]
container: ${{ matrix.image }}
timeout-minutes: 30
timeout-minutes: 10
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Prepare runner
uses: XRPLF/actions/prepare-runner@b3e255d74d785d053e4903da8ac90983cd7d9e82
with:
enable_ccache: false
- name: Download pre-built xrpld binary
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
@@ -98,6 +126,7 @@ jobs:
- name: Build package
env:
PACKAGE_TYPE: ${{ matrix.package_type }}
PACKAGE_VARIANT: ${{ matrix.package_variant }}
PKG_RELEASE: ${{ steps.release_info.outputs.pkg_release }}
CHANNEL: ${{ steps.release_info.outputs.channel }}
run: |
@@ -105,35 +134,206 @@ jobs:
--package-type "${PACKAGE_TYPE}" \
--build-dir "${BUILD_DIR}" \
--pkg-release "${PKG_RELEASE}" \
--variant "${PACKAGE_VARIANT}" \
--channel "${CHANNEL}"
# Before the upload, so the artifact and the published package are the
# same bytes. DEBs are not signed, so the key is never set on that job.
# Before the upload, so the artifact, the tested package and the published
# package are the same bytes.
- name: Sign RPM
if: ${{ inputs.publish && matrix.package_type == 'rpm' }}
env:
PKG_SIGNING_KEY: ${{ secrets.signing_key }}
run: ./package/sign_rpm.py --package-dir "${BUILD_DIR}"
# Split from the debug symbols, which are an order of magnitude larger, so
# that test-install downloads only what it installs. In the globs below the
# version follows the name, separated by '_' in a DEB and '-' in an RPM. A
# version starts with a digit and a longer name does not, so that one digit
# is what tells 'xrpld-3.4.1-...' from 'xrpld-assert-3.4.1-...'.
- name: Upload package artifact
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: ${{ matrix.xrpld_artifact_name }}-pkg
path: |
${{ env.BUILD_DIR }}/debbuild/*.deb
${{ env.BUILD_DIR }}/debbuild/*.ddeb
${{ env.BUILD_DIR }}/rpmbuild/RPMS/**/*.rpm
${{ env.BUILD_DIR }}/debbuild/${{ matrix.package_name }}_[0-9]*.deb
${{ env.BUILD_DIR }}/rpmbuild/RPMS/**/${{ matrix.package_name }}-[0-9]*.rpm
if-no-files-found: error
- name: Upload debug symbol artifact
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: ${{ matrix.xrpld_artifact_name }}-pkg-debug
path: |
${{ env.BUILD_DIR }}/debbuild/${{ matrix.package_name }}-dbgsym_[0-9]*.deb
${{ env.BUILD_DIR }}/debbuild/${{ matrix.package_name }}-dbgsym_[0-9]*.ddeb
${{ env.BUILD_DIR }}/rpmbuild/RPMS/**/${{ matrix.package_name }}-debuginfo-[0-9]*.rpm
if-no-files-found: error
# One call per format, so a variant packaged for one format is installed for
# that format alone. The images are every distro family that format targets,
# oldest release first, so both ends of the dependency range the packages
# declare are exercised.
test-install-deb:
needs: [generate-matrix, package]
name: install deb
uses: ./.github/workflows/reusable-package-test-install.yml
with:
package_type: deb
package_names: ${{ needs.generate-matrix.outputs.deb_package_names }}
images: |
[
"debian:11",
"debian:12",
"debian:13",
"ubuntu:20.04",
"ubuntu:22.04",
"ubuntu:24.04",
"ubuntu:26.04"
]
test-install-rpm:
needs: [generate-matrix, package]
name: install rpm
uses: ./.github/workflows/reusable-package-test-install.yml
with:
package_type: rpm
package_names: ${{ needs.generate-matrix.outputs.rpm_package_names }}
images: |
[
"almalinux:9",
"almalinux:10",
"rockylinux/rockylinux:9",
"rockylinux/rockylinux:10",
"registry.access.redhat.com/ubi9/ubi",
"registry.access.redhat.com/ubi10/ubi"
]
publish:
needs: [generate-matrix, package, test-install-deb, test-install-rpm]
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.generate-matrix.outputs.matrix) }}
name: "publish ${{ matrix.xrpld_artifact_name }}${{ !inputs.publish && ' (dry run)' || '' }}"
permissions:
contents: read
runs-on: ["self-hosted", "Linux", "X64", "heavy"]
container: ${{ matrix.image }}
timeout-minutes: 30
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Prepare runner
uses: XRPLF/actions/prepare-runner@b3e255d74d785d053e4903da8ac90983cd7d9e82
with:
enable_ccache: false
# Both artifacts, so the debug symbols are published alongside the package.
- name: Download package artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
pattern: ${{ matrix.xrpld_artifact_name }}-pkg*
merge-multiple: true
path: ${{ env.PACKAGE_DIR }}
- name: Determine release info
id: release_info
uses: ./.github/actions/release-info
- name: Publish package
if: ${{ inputs.publish }}
env:
CHANNEL: ${{ steps.release_info.outputs.channel }}
DRY_RUN_OPTION: ${{ !inputs.publish && '--dry-run' || '' }}
NEXUS_URL: ${{ inputs.nexus_url }}
NEXUS_USERNAME: ${{ secrets.remote_username }}
NEXUS_PASSWORD: ${{ secrets.remote_password }}
NEXUS_USERNAME: ${{ inputs.publish && secrets.remote_username || '' }}
NEXUS_PASSWORD: ${{ inputs.publish && secrets.remote_password || '' }}
run: |
./package/publish_pkg.py \
publish_pkg.py \
--channel "${CHANNEL}" \
--package-dir "${BUILD_DIR}" \
--nexus-url "${NEXUS_URL}"
--package-dir "${PACKAGE_DIR}" \
--nexus-url "${NEXUS_URL}" \
${DRY_RUN_OPTION}
docker:
needs: [test-install-deb, test-install-rpm]
strategy:
fail-fast: false
matrix:
target: [xrpld, voidstar]
name: "docker ${{ matrix.target }}${{ !inputs.publish && ' (dry run)' || '' }}"
permissions:
contents: read
runs-on: ubuntu-latest
timeout-minutes: 15
env:
CONTEXT: image-context
IMAGE: ${{ matrix.target == 'voidstar' && 'xrpld-voidstar' || 'xrplf/xrpld' }}:${{ github.ref_type == 'tag' && github.ref_name || 'develop' }}
# Docker Hub is public, so a private build never reaches it;
# the Antithesis registry is not.
PUSH: ${{ inputs.publish && (matrix.target == 'voidstar' || github.event.repository.visibility == 'public') }}
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Download package artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
pattern: "*-pkg"
merge-multiple: true
path: ${{ env.PACKAGE_DIR }}
- name: Download voidstar binary
if: ${{ matrix.target == 'voidstar' }}
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: xrpld-ubuntu-clang-debug-amd64-voidstar
path: ${{ env.CONTEXT }}
- name: Build image
env:
TARGET: ${{ matrix.target }}
run: |
mkdir -p "${CONTEXT}"
find "${PACKAGE_DIR}" -type f -name 'xrpld_[0-9]*.deb' -exec cp {} "${CONTEXT}/" \;
docker build --pull --file package/images/xrpld/Dockerfile --target "${TARGET}" --tag "${IMAGE}" "${CONTEXT}"
- name: Start the server
run: |
container="$(docker run --detach "${IMAGE}" --standalone --silent --conf /etc/xrpld/xrpld.cfg)"
trap 'docker rm --force "${container}" >/dev/null' EXIT
for _ in $(seq 30); do
output="$(docker exec "${container}" xrpld --conf /etc/xrpld/xrpld.cfg server_info || true)"
if [[ "${output}" == *'"status" : "success"'* ]]; then
exit 0
fi
sleep 2
done
docker logs "${container}"
exit 1
- name: Log in to Docker Hub
if: ${{ env.PUSH == 'true' && matrix.target == 'xrpld' }}
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
with:
username: xrplf
password: ${{ secrets.dockerhub_token }}
- name: Log in to the Antithesis registry
if: ${{ env.PUSH == 'true' && matrix.target == 'voidstar' }}
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
with:
registry: ${{ secrets.antithesis_docker_host }}
username: _json_key
password: ${{ secrets.antithesis_docker_credentials }}
- name: Push image
if: ${{ env.PUSH == 'true' }}
env:
REGISTRY: ${{ matrix.target == 'voidstar' && format('{0}/{1}/', secrets.antithesis_docker_host, secrets.antithesis_docker_path) || '' }}
run: |
docker tag "${IMAGE}" "${REGISTRY}${IMAGE}"
docker push "${REGISTRY}${IMAGE}"

View File

@@ -1,8 +1,9 @@
# Clippy, coverage and documentation for the Rust crates in crates/. Each runs
# as an independent job on a GitHub-hosted runner, but inside the same container
# image used to build the crates in the C++/Corrosion path, so the toolchain
# (and therefore the lints, coverage instrumentation and the cargo cache) matches
# what production builds use.
# (and therefore the lints and the cargo cache) matches what production builds
# use. Coverage is the exception: it needs the nightly rustc that honours
# #[coverage(off)], which the image carries alongside the pinned stable.
#
# Rust unit tests are deliberately NOT run here. They run as part of the C++
# build (reusable-build-test-config.yml), which already compiles the crates on a
@@ -27,7 +28,7 @@ permissions:
jobs:
clippy:
runs-on: ubuntu-latest
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-473fe44
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-060957e
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
@@ -40,11 +41,14 @@ jobs:
coverage:
runs-on: ubuntu-latest
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-473fe44
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-060957e
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Use the nightly Rust toolchain
run: rust-nightly path >>"${GITHUB_PATH}"
- name: Use cargo artifacts cache
uses: ./.github/actions/cargo-cache
@@ -53,7 +57,7 @@ jobs:
- name: Upload coverage report
if: ${{ github.repository == 'XRPLF/rippled' }}
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
uses: codecov/codecov-action@303a32d7a59b442fa8d48b6a1cc6825c09c847a5 # v7.1.1
with:
disable_search: true
disable_telem: true
@@ -66,7 +70,7 @@ jobs:
doc:
runs-on: ubuntu-latest
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-473fe44
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-060957e
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-473fe44
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-060957e
env:
REMOTE_NAME: ${{ inputs.remote_name }}
CONAN_LOGIN_USERNAME_XRPLF: ${{ secrets.remote_username }}
@@ -49,6 +49,11 @@ jobs:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Prepare runner
uses: XRPLF/actions/prepare-runner@b3e255d74d785d053e4903da8ac90983cd7d9e82
with:
enable_ccache: false
- name: Determine release info
id: release_info
uses: ./.github/actions/release-info
@@ -63,33 +68,17 @@ jobs:
run: conan remote login "${REMOTE_NAME}" "${CONAN_LOGIN_USERNAME_XRPLF}" --password "${CONAN_PASSWORD_XRPLF}"
- name: Upload Conan recipe (version)
env:
VERSION: ${{ steps.release_info.outputs.version }}
run: |
conan export . --version=${{ steps.release_info.outputs.version }}
conan upload --confirm --check --remote="${REMOTE_NAME}" xrpl/${{ steps.release_info.outputs.version }}
conan export . --version="${VERSION}"
conan upload --confirm --check --remote="${REMOTE_NAME}" "xrpl/${VERSION}"
# When this workflow is triggered by a push event, it will always be when merging into the
# 'develop' branch, see on-trigger.yml.
- name: Upload Conan recipe (develop)
if: ${{ github.event_name == 'push' }}
if: ${{ github.ref == 'refs/heads/develop' }}
run: |
conan export . --version=develop
conan upload --confirm --check --remote="${REMOTE_NAME}" xrpl/develop
# When this workflow is triggered by a pull request event, it will always be when merging into
# one of the 'release' branches, see on-pr.yml.
- name: Upload Conan recipe (rc)
if: ${{ github.event_name == 'pull_request' }}
run: |
conan export . --version=rc
conan upload --confirm --check --remote="${REMOTE_NAME}" xrpl/rc
# When this workflow is triggered by a push event, it will always be when tagging a final
# release, see on-tag.yml.
- name: Upload Conan recipe (release)
if: ${{ startsWith(github.ref, 'refs/tags/') }}
run: |
conan export . --version=release
conan upload --confirm --check --remote="${REMOTE_NAME}" xrpl/release
outputs:
ref: xrpl/${{ steps.release_info.outputs.version }}

View File

@@ -68,7 +68,7 @@ jobs:
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Prepare runner
uses: XRPLF/actions/prepare-runner@7bf7ceca5932114abdd0d43493c3c30c5a654e13
uses: XRPLF/actions/prepare-runner@b3e255d74d785d053e4903da8ac90983cd7d9e82
with:
enable_ccache: false

9
.gitignore vendored
View File

@@ -72,11 +72,16 @@ DerivedData
/.zed/
# AI tools.
# Shared/committable AI agent config (AGENTS.md, CLAUDE.md, GEMINI.md, .claude/settings.json,
# tool-specific rules files, etc.) should be checked in — see CONTRIBUTING.md. Only the
# personal/local variants below are ignored.
/.agent
/.agents
/.augment
/.claude
/CLAUDE.md
/.claude/settings.local.json
AGENTS.override.md
CLAUDE.local.md
GEMINI.local.md
# Python
__pycache__

View File

@@ -53,9 +53,14 @@ repos:
entry: ./bin/pre-commit/check_doxygen_style.py
language: python
types_or: [c++, c]
- id: fix-gtest-names
name: "fix gtest names: CamelCase suite, snake_case test case"
entry: ./bin/pre-commit/fix_gtest_names.py
language: python
types_or: [c++, c]
- repo: https://github.com/pre-commit/mirrors-clang-format
rev: f4d7745e17a28aad7eed2f4874ca8d1568c11c4c # frozen: v22.1.8
rev: e2b496dc2bd8340c2524cb9a2d2a943cde1bb6df # frozen: v23.1.1
hooks:
- id: clang-format
args: [--style=file]
@@ -70,14 +75,19 @@ repos:
language: system
types: [rust]
pass_filenames: false # rustfmt formats the whole workspace
- id: check-coverage-attrs
name: check Rust coverage attributes
entry: ./bin/pre-commit/check_rust_coverage_attrs.py
language: python
files: ^crates/.*\.rs$
- repo: https://github.com/BlankSpruce/gersemi-pre-commit
rev: e98930bdc210d3387007f9252d8c1694ea7e410f # frozen: 0.27.7
rev: f1c4833f8cf23c6d952673abc73525411a5719e8 # frozen: 0.29.1
hooks:
- id: gersemi
- repo: https://github.com/rbubley/mirrors-prettier
rev: 9337a74165b178ae2c766f60bee7252a0f06f3e8 # frozen: v3.9.5
rev: ef4a397f916211b4a39ccf9d3d9cbb6562157251 # frozen: v3.9.9
hooks:
- id: prettier
args: [--end-of-line=auto]
@@ -85,7 +95,7 @@ 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: 7c55798a78262d14b2074abf623d8a992ebb70d4 # frozen: v0.16.2
rev: a56c0b927e6465d37cae3e97d35d4d18ab2b96cd # frozen: v0.16.9
hooks:
- id: ruff-check
args: [--fix]
@@ -97,14 +107,14 @@ repos:
- id: black
- repo: https://github.com/pre-commit/mirrors-mypy
rev: 41e691678310dfd3833f7ab4e180ddb014310356 # frozen: v2.3.0
rev: 7ff8d35ae36a7d2b968f2f90b4c723e292e594ee # frozen: v2.3.1
hooks:
- id: mypy
args: [--strict]
files: ^package/.*\.py$
- repo: https://github.com/scop/pre-commit-shfmt
rev: 05c1426671b9237fb5e1444dd63aa5731bec0dfb # frozen: v3.13.1-1
rev: 479be5958357ba5ab65ce47172117348516860e9 # frozen: v3.14.1-1
hooks:
- id: shfmt
args: [--write, --indent=4, --case-indent=true]
@@ -123,7 +133,7 @@ repos:
files: \.md$
- repo: https://github.com/streetsidesoftware/cspell-cli
rev: ea11f9efc0bec520073405bc30552da887ba71bc # frozen: v10.0.1
rev: f5c5d72342f35643988a9ffa0705c05bd3ff8383 # frozen: v10.3.0
hooks:
- id: cspell
name: check changed files spelling

42
AGENTS.md Normal file
View File

@@ -0,0 +1,42 @@
# AGENTS.md
This file provides guidance to AI coding agents (Claude Code, and other AGENTS.md-compatible tools) when working with code in this repository.
## Build
Required on Linux/macOS: use the Nix devshell, which sets up the compiler, Conan, ccache, and (optionally) Rust automatically.
```bash
nix develop
```
For alternate devshell variants (specific compiler, no-compiler, coverage), see [docs/build/nix.md](./docs/build/nix.md). For the manual build steps, CMake options, and protocol codegen commands, see [BUILD.md](./BUILD.md) (`## Steps`, `## Options`, `## Code generation`).
Rust crate tests (independent of the CMake build): `cargo test --manifest-path crates/Cargo.toml --workspace` (CI uses `cargo nextest`).
## Testing
Unit tests are a custom framework built into the `xrpld` binary itself (not Boost.Test/GTest/Catch); see [CONTRIBUTING.md](./CONTRIBUTING.md#unit-tests) for the basic invocation. Notes not covered there:
- A suite's `--unittest` name is built from the arguments to its `BEAST_DEFINE_TESTSUITE`/`BEAST_DEFINE_TESTSUITE_PRIO` macro (usually at the bottom of the test file), in reverse order and joined with `.`: `BEAST_DEFINE_TESTSUITE(Credentials, app, xrpl)` → `xrpl.app.Credentials`.
- `--unittest-arg` does nothing — don't use it.
- Tests that run offline in under a minute should be automatic `--unittest` suites; anything else is a manual/integration test.
- New tests should be written using `gtest` under `src/tests/` unless that isn't possible, in which case fall back to the legacy Beast framework under `src/test/`. `tests/` (top-level) holds integration tests exercised against `libxrpl`/`xrpld`.
## Lint/Format
See [CONTRIBUTING.md](./CONTRIBUTING.md#pre-commit-hooks) for `pre-commit` setup and [CONTRIBUTING.md](./CONTRIBUTING.md#clang-tidy) for `clang-tidy` (opt-in, needs local `clang-tidy` and generated headers).
## Code Style
New file placement and header levelization: see [CONTRIBUTING.md](./CONTRIBUTING.md#before-making-a-pull-request). Braces, whitespace, member order, and other conventions: see [docs/CodingStyle.md](./docs/CodingStyle.md). `XRPL_ASSERT`/`UNREACHABLE` contracts: see [CONTRIBUTING.md](./CONTRIBUTING.md#contracts-and-instrumentation). Commit messages: see [CONTRIBUTING.md](./CONTRIBUTING.md#good-commit-messages).
## Architecture
Paths below reflect the current layout; update this section if modularization moves a subsystem to a different directory.
- `include/xrpl/` + `src/libxrpl/` — the core protocol library: ledger, shamap, consensus, crypto, json, resource, nodestore, rdb, peerfinder, and `tx/` (transaction application: `Transactor.cpp`, `applySteps.cpp`, invariants, payment paths). `tx/transactors/` has one file per transaction type, grouped by subsystem: `escrow/`, `vault/`, `lending/`, `sponsor/`, `nft/`, `token/` (MPT), `payment_channel/`, `permissioned_domain/`, `dex/`, `oracle/`, `did/`, `credentials/`, `bridge/`, `check/`, `delegate/`, `account/`, `system/`. Any change to transaction-processing behavior must be gated behind an Amendment.
- `src/xrpld/` — the server application built on top of `libxrpl`: `app`, `core`, `overlay` (P2P networking), `peerfinder`, `perflog`, `rpc`, `shamap`. `main` builds an `ApplicationImp` implementing `Application`; most components hold a reference to it (`app_`), giving broad cross-component access — expect to trace call chains through `Application&`.
- `src/test/` — unit tests mirroring the subsystems above, plus `jtx/` (the transaction-building test DSL — e.g. `jtx/escrow.h`, `jtx/vault.h`, `jtx/sponsor.h`, `jtx/permissioned_dex.h`) and `unit_test/` (the custom test framework itself, derived from Beast).
- `src/tests/` — unit tests for `libxrpl` written in `gtest`, gradually replacing the `src/test` equivalents.
- `crates/` — a Rust workspace (only built with `-Dxrpld -Drust=ON`) bridged into C++ via `cxxbridge`/the `cxx` crate; currently just a `hello_world` interop scaffold. Requires the Rust toolchain pinned in `rust-toolchain.toml` (the Nix devshell provides it automatically).

View File

@@ -22,17 +22,48 @@ API version 2 is available in `xrpld` version 2.0.0 and later. See [API-VERSION-
This version is supported by all `xrpld` versions. For WebSocket and HTTP JSON-RPC requests, it is currently the default API version used when no `api_version` is specified.
## Unreleased
## XRP Ledger server version 3.4.0
This section contains changes targeting a future version.
Version 3.4.0 is not yet released. These changes are available in the 3.4.0 beta releases.
### Additions
### Additions in 3.4.0
- `account_tx`: Added an optional `delegate` request object to filter delegated transactions. The object requires `delegate_filter`, which must be either `actor` for transactions owned by the requested account but signed by another account, or `authorizer` for transactions signed by the requested account on behalf of another account. The optional `counter_party` account narrows the results to a specific signer/delegate for `actor` or a specific owner/delegator for `authorizer`. Malformed `delegate`, `delegate_filter`, and `counter_party` values return standard invalid field errors, and invalid account IDs return `actMalformed`.
When paginating delegate-filtered queries, a marker from a delegate-filtered query includes a `delegate` flag and is only valid for follow-up requests that also supply `delegate` (mixing marker conventions returns `invalidParams`). Because filtering is applied after the ledger scan, a page may contain fewer results than `limit` (possibly zero) while still returning a marker, so callers must continue until no marker is present.
- `ledger`: `nftoken_id`, `nftoken_ids`, and `offer_id` are now included in transaction metadata when transactions are expanded (`expand`, or admin-only `full`), matching the `tx`, `account_tx`, and `subscribe` (`transactions` stream) responses. ([#5706](https://github.com/XRPLF/rippled/pull/5706))
### Bugfixes in 3.4.0
- `sign`, `sign_for`, `submit`: `signature_target` now returns `invalidParams` unless it names `CounterpartySignature` or `SponsorSignature`. It previously accepted any inner object field, such as `Book` or `NFToken`, and signed into it.
- `sign`, `sign_for`, `submit`, `submit_multisigned`: With `fixCleanup3_4_0` enabled, a signature in `CounterpartySignature` or `SponsorSignature` covers a different prefix than the transaction's own signature, so a signature can no longer be moved from one of those roles into another. Clients that build these signatures themselves must use the new prefixes: `CPT` and `CPM` (single- and multi-signing) for `CounterpartySignature`, and `SPN` and `SPM` for `SponsorSignature`.
- `get_aggregate_price`: Duplicate entries in the `oracles` request array are now ignored. [#6586](https://github.com/XRPLF/rippled/pull/6586)
- `vault_info`: Errors now identify what the request got wrong instead of reporting every failure as the unregistered token `malformedRequest`, and the `error`, `error_code` and `error_message` fields now agree with each other. An invalid `vault_id` or `seq` returns `invalidParams`, an invalid `owner` returns `actMalformed`, and a request that mixes `vault_id` with `owner`/`seq` or supplies neither returns `invalidParams` with a message naming the accepted combinations. [#8015](https://github.com/XRPLF/rippled/pull/8015)
- `vault_info`: A well-formed all-zero `vault_id` now returns `entryNotFound` instead of being rejected as malformed, and `entryNotFound` responses now include `error_code` and `error_message`. Clients that request `ripplerpc` 3.0 or above therefore receive HTTP 400 with that error rather than HTTP 200. [#8015](https://github.com/XRPLF/rippled/pull/8015)
- `vault_info`: `vault_id` and `owner` must now be strings, matching how `ledger_entry` reads the same fields. An object or an array in either field previously produced an internal error, and a number was silently converted to its decimal text; `vault_id` now returns `invalidParams` and `owner` returns `actMalformed`. [#8015](https://github.com/XRPLF/rippled/pull/8015)
- `gateway_balances`: The `account` and `ident` fields now return an `invalidParams` error if the value is not a string, instead of an `internal` error. [#7655](https://github.com/XRPLF/rippled/pull/7655)
- `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)).
## XRP Ledger server version 3.3.0
[Version 3.3.0](https://github.com/XRPLF/rippled/releases/tag/3.3.0) was released on Aug 6, 2026.
### Additions in 3.3.0
- `account_tx`: Added an optional `delegate` request object to filter delegated transactions. The object requires `delegate_filter`, which must be either `actor` for transactions owned by the requested account but signed by another account, or `authorizer` for transactions signed by the requested account on behalf of another account. The optional `counter_party` account narrows the results to a specific signer/delegate for `actor` or a specific owner/delegator for `authorizer`. Malformed `delegate`, `delegate_filter`, and `counter_party` values return standard invalid field errors, and invalid account IDs return `actMalformed`. When paginating delegate-filtered queries, a marker from a delegate-filtered query includes a `delegate` flag and is only valid for follow-up requests that also supply `delegate` (mixing marker conventions returns `invalidParams`). Because filtering is applied after the ledger scan, a page may contain fewer results than `limit` (possibly zero) while still returning a marker, so callers must continue until no marker is present. ([#6126](https://github.com/XRPLF/rippled/pull/6126))
## XRP Ledger server version 3.2.1
[Version 3.2.1](https://github.com/XRPLF/rippled/releases/tag/3.2.1) was released on Aug 1, 2026.
This release contains bug fixes only and no API changes.
## XRP Ledger server version 3.2.0
[Version 3.2.0](https://github.com/XRPLF/rippled/releases/tag/3.2.0) was released on Jun 16, 2026.
### Additions in 3.2.0
- `ledger_entry`, `account_objects`: The `Delegate` ledger entry now includes an optional `DestinationNode` field, which stores the index into the authorized account's owner directory. This field is present on entries created after bidirectional directory tracking was introduced and may appear in RPC responses for those entries. ([#6681](https://github.com/XRPLF/rippled/pull/6681))
- `server_definitions`: Added the following new sections to the response ([#6321](https://github.com/XRPLF/rippled/pull/6321)):
- `TRANSACTION_FORMATS`: Describes the fields and their optionality for each transaction type, including common fields shared across all transactions.
- `LEDGER_ENTRY_FORMATS`: Describes the fields and their optionality for each ledger entry type, including common fields shared across all ledger entries.
@@ -40,9 +71,8 @@ This section contains changes targeting a future version.
- `LEDGER_ENTRY_FLAGS`: Maps ledger entry type names to their flags and flag values.
- `ACCOUNT_SET_FLAGS`: Maps AccountSet flag names (asf flags) to their numeric values.
### Bugfixes
### Bugfixes in 3.2.0
- `get_aggregate_price`: Duplicate entries in the `oracles` request array are now ignored. [#6586](https://github.com/XRPLF/rippled/pull/6586)
- Peer Crawler: The `port` field in `overlay.active[]` now consistently returns an integer instead of a string for outbound peers. [#6318](https://github.com/XRPLF/rippled/pull/6318)
- `ping`: The `ip` field is no longer returned as an empty string for proxied connections without a forwarded-for header. It is now omitted, consistent with the behavior for identified connections. [#6730](https://github.com/XRPLF/rippled/pull/6730)
- gRPC `GetLedgerDiff`: Fixed error message that incorrectly said "base ledger not validated" when the desired ledger was not validated. [#6730](https://github.com/XRPLF/rippled/pull/6730)
@@ -54,11 +84,24 @@ This section contains changes targeting a future version.
- `submit`: The `fail_hard` field now returns an error if the value is not a boolean. [#6529](https://github.com/XRPLF/rippled/pull/6529)
- `subscribe`: The `taker` field in the `books` array now returns `actMalformed` instead of `badIssuer` if the value is not a valid account. [#6529](https://github.com/XRPLF/rippled/pull/6529)
- Fixed a bug in `Forwarded` HTTP header parsing where the extracted IP address could be incorrect when no comma or semicolon delimiter follows the address. This could cause the server to misidentify a client's IP address when operating behind a reverse proxy. [#6529](https://github.com/XRPLF/rippled/pull/6529)
- `vault_info`: Errors now identify what the request got wrong instead of reporting every failure as the unregistered token `malformedRequest`, and the `error`, `error_code` and `error_message` fields now agree with each other. An invalid `vault_id` or `seq` returns `invalidParams`, an invalid `owner` returns `actMalformed`, and a request that mixes `vault_id` with `owner`/`seq` or supplies neither returns `invalidParams` with a message naming the accepted combinations. [#8015](https://github.com/XRPLF/rippled/pull/8015)
- `vault_info`: A well-formed all-zero `vault_id` now returns `entryNotFound` instead of being rejected as malformed, and `entryNotFound` responses now include `error_code` and `error_message`. Clients that request `ripplerpc` 3.0 or above therefore receive HTTP 400 with that error rather than HTTP 200. [#8015](https://github.com/XRPLF/rippled/pull/8015)
- `vault_info`: `vault_id` and `owner` must now be strings, matching how `ledger_entry` reads the same fields. An object or an array in either field previously produced an internal error, and a number was silently converted to its decimal text; `vault_id` now returns `invalidParams` and `owner` returns `actMalformed`. [#8015](https://github.com/XRPLF/rippled/pull/8015)
- `gateway_balances`: The `account` and `ident` fields now return an `invalidParams` error if the value is not a string, instead of an `internal` error. [#7655](https://github.com/XRPLF/rippled/pull/7655)
- `account_lines`: The `peer` field now returns an error if the value is not a string. [#7728](https://github.com/XRPLF/rippled/pull/7728)
## XRP Ledger server version 3.1.3
[Version 3.1.3](https://github.com/XRPLF/rippled/releases/tag/3.1.3) was released on May 8, 2026.
This release contains bug fixes only and no API changes.
## XRP Ledger server version 3.1.2
[Version 3.1.2](https://github.com/XRPLF/rippled/releases/tag/3.1.2) was released on Mar 12, 2026.
This release contains bug fixes only and no API changes.
## XRP Ledger server version 3.1.1
[Version 3.1.1](https://github.com/XRPLF/rippled/releases/tag/3.1.1) was released on Feb 23, 2026.
This release contains bug fixes only and no API changes.
## XRP Ledger server version 3.1.0

View File

@@ -51,6 +51,12 @@ git checkout release/3.2.x
For a stable release, choose one of the [tagged
releases](https://github.com/XRPLF/rippled/releases).
A build reports `0.0.0-dev` with its short commit hash as build metadata, e.g.
`0.0.0-dev+0123abc`. Only builds of a release, from a tag in CI or a versioned
Conan reference, report a release version. To use another version, set the
`FORCE_XRPLD_VERSION` environment variable when running CMake, e.g.
`FORCE_XRPLD_VERSION=3.4.0`.
### Set Up Conan
Once your [development environment](./docs/build/environment.md) is ready, set

1
CLAUDE.md Symbolic link
View File

@@ -0,0 +1 @@
AGENTS.md

View File

@@ -77,7 +77,6 @@ endif()
include(PatchNixBinary)
include(XrplSanity)
include(XrplVersion)
include(XrplSettings)
# this check has to remain in the top-level cmake because of the early return statement
if(packages_only)
@@ -115,6 +114,7 @@ find_package(secp256k1 REQUIRED)
find_package(SOCI REQUIRED)
find_package(SQLite3 REQUIRED)
find_package(xxHash REQUIRED)
find_package(xrpl-rpc-spec REQUIRED)
target_link_libraries(
xrpl_libs
@@ -175,6 +175,7 @@ include(XrplPackaging)
if(tests)
include(CTest)
add_subdirectory(src/tests/libxrpl)
add_subdirectory(src/tests/xrpld)
endif()
if(benchmark)

View File

@@ -59,6 +59,17 @@ to an existing XLS. Neither change will be released (in an amendment's
case, marked as `Supported::yes`) until the corresponding XLS's status
is `Final`.
## AI coding agents
[`AGENTS.md`](./AGENTS.md) (and its `CLAUDE.md` symlink, for Claude Code) holds shared, checked-in guidance for AI coding agents working in this repository — build/test/lint commands and architecture notes. Additional `AGENTS.md` files may exist in subdirectories to give agents context specific to that part of the codebase; whenever you add one, also add a `CLAUDE.md` symlink pointing to it (`ln -s AGENTS.md CLAUDE.md`) so Claude Code picks it up too.
If you want to give an agent personal instructions that shouldn't be shared with other contributors (e.g. your own workflow preferences), those are gitignored, not checked in:
- `CLAUDE.local.md` — read by Claude Code alongside `CLAUDE.md`.
- `AGENTS.override.md` — read by AGENTS.md-compatible tools that support a personal override file layered on top of `AGENTS.md`.
Likewise, `.claude/settings.local.json` is for personal, untracked Claude Code settings, while `.claude/settings.json` is shared.
## Before making a pull request
(Or marking a draft pull request as ready.)
@@ -82,7 +93,7 @@ If you create new source files, they must be organized as follows:
under `include/xrpl`, and source (`.cpp`) files must go under
`src/libxrpl`.
- All other non-test files must go under `src/xrpld`.
- All test source files must go under `src/test`.
- New test source files should use `gtest` and go under `src/tests`, unless that isn't possible, in which case they should use our legacy test framework and go under `src/test`.
- All benchmark source files must go under `src/benchmarks`.
The source must be formatted according to the style guide below. The easiest
@@ -468,8 +479,12 @@ exists, then no other unit test will be executed, apart from `TestSuiteName`.
elsewhere in the codebase.
12. Use clear and self-explanatory names for functions, variables,
structs and classes.
13. Use TitleCase for classes, structs and filenames, camelCase for
function and variable names, lower case for namespaces and folders.
13. Use TitleCase for classes, structs, type aliases and filenames,
camelCase for function and variable names, lower case for namespaces and
folders. The exception is a type alias that generic code looks up by name
(`value_type`, `iterator`, `result_type`, and the rest of the standard
container, hash and clock members), which keeps its snake_case spelling;
`.clang-tidy` lists the names that are allowed.
14. Provide as many comments as you feel that a competent programmer
would need to understand what your code does.

View File

@@ -158,6 +158,7 @@ if [ "${os}" = "linux" ] || [ "${os}" = "macos" ]; then
check cargo-nextest cargo nextest --version
check clippy-driver
check rust-analyzer
check rust-nightly rust-nightly run rustc --version
check rustc
check rustfmt
fi

View File

@@ -1,56 +0,0 @@
#!/bin/bash
if [[ $# -ne 3 || "$1" == "--help" || "$1" = "-h" ]]; then
name=$(basename $0)
cat <<-USAGE
Usage: $name workbranch base/branch version
* workbranch will be created locally from base/branch. If it exists,
it will be reused, so make sure you don't overwrite any work.
* base/branch may be specified as user:branch to allow easy copying
from Github PRs.
USAGE
exit 0
fi
work="$1"
shift
base=$(echo "$1" | sed "s/:/\//")
shift
version=$1
shift
set -e
git fetch upstreams
git checkout -B "${work}" --no-track "${base}"
push=$(git rev-parse --abbrev-ref --symbolic-full-name '@{push}' \
2>/dev/null) || true
if [[ "${push}" != "" ]]; then
echo "Warning: ${push} may already exist."
fi
build=$(find -name BuildInfo.cpp)
sed 's/\(^.*versionString =\).*$/\1 "'${version}'"/' ${build} >version.cpp &&
diff "${build}" version.cpp && exit 1 ||
mv -vi version.cpp ${build}
git diff
git add ${build}
git commit -S -m "Set version to ${version}"
git log --oneline --first-parent ${base}^..
cat <<PUSH
-------------------------------------------------------------------
This script will not push. Verify everything is correct, then push
to your repo, and create a PR as described in CONTRIBUTING.md.
-------------------------------------------------------------------
PUSH

View File

@@ -25,7 +25,9 @@ esac
# Packaging runs in a vanilla distro image, so the tooling comes from the distro's
# archive rather than from nixpkgs:
#
# - debhelper and dpkg-dev build the DEB
# - debhelper and dpkg-dev build the DEB, and lintian checks it
# - binutils gives debian/rules the readelf its glibc-floor check runs; it
# already arrives via dpkg-dev, but that tool is called directly
# - rpm-build builds the RPM, with systemd-rpm-macros and redhat-rpm-config
# supplying the systemd and find-debuginfo macros the spec uses
# - rpm-sign and gnupg2 sign the built RPM
@@ -37,11 +39,13 @@ function install() {
debian | ubuntu)
apt-get update -y
apt-get install -y --no-install-recommends \
binutils \
ca-certificates \
debhelper \
debhelper-compat \
dpkg-dev \
git \
lintian \
python3
;;

View File

@@ -0,0 +1,149 @@
#!/usr/bin/env python3
"""
Check that Rust unit tests stay out of the coverage report.
cargo-llvm-cov instruments the test code along with everything else, so a test
module that is not excluded counts its own body as covered and inflates the
reported number. Excluding it takes two attributes:
* every `#[cfg(test)]` module carries
`#[cfg_attr(coverage_nightly, coverage(off))]`;
* every crate root (lib.rs, main.rs) carries
`#![cfg_attr(coverage_nightly, feature(coverage_attribute))]`, which the
attribute above needs in order to compile.
Both are inert outside the coverage job: cargo-llvm-cov defines
`coverage_nightly` only when it runs on a nightly toolchain.
The crate-root gate is checked even in a crate that has no tests yet, because
that is what lets the first test module added later carry the attribute without
a build failure. Missing it is a hard error, so it cannot go unnoticed; a
missing `coverage(off)` fails open, which is why this check exists.
Matching is on exact attribute text, which works because `cargo fmt` runs over
the whole workspace in the hook ahead of this one: rustfmt puts every attribute
on its own line and normalizes what is inside it, turning `#[cfg( test )]`
and `#[cfg(test,)]` alike into `#[cfg(test)]`. So there is nothing here that
parses Rust. The price is that a cfg this file does not spell out literally --
`all(test, ...)`, `any(test, ...)`, `not(test)` -- is reported rather than
classified, on the grounds that guessing at coverage semantics is how a check
like this ends up quietly wrong.
Usage: ./bin/pre-commit/check_rust_coverage_attrs.py <file1> <file2> ...
Exit status is non-zero if any violation is found.
"""
import re
import sys
from dataclasses import dataclass
from pathlib import Path
CRATE_ROOTS = {"lib.rs", "main.rs"}
FEATURE_ATTR = "#![cfg_attr(coverage_nightly, feature(coverage_attribute))]"
COVERAGE_OFF_ATTR = "#[cfg_attr(coverage_nightly, coverage(off))]"
CFG_TEST_ATTR = "#[cfg(test)]"
# Any other cfg that mentions `test`. String literals are blanked before this
# runs, so `feature = "test"` does not read as the `test` cfg.
RE_CFG_MENTIONS_TEST = re.compile(r"^#\[cfg\(.*\btest\b.*\)\]$")
RE_STRING = re.compile(r'"(?:[^"\\]|\\.)*"')
RE_MOD = re.compile(r"^(?:pub(?:\([^)]*\))?\s+)?mod\s+([A-Za-z_]\w*)")
@dataclass(frozen=True)
class Finding:
line: int
label: str
message: str
def _check_module(attrs: list[str], line: int, name: str) -> list[Finding]:
"""Findings for one module, given the attributes attached to it."""
if COVERAGE_OFF_ATTR in attrs:
return [] # excluded from coverage; which cfg gates it does not matter
if CFG_TEST_ATTR in attrs:
return [
Finding(
line,
"missing-coverage-off",
f"`mod {name}` is #[cfg(test)] but not excluded from coverage; "
f"add {COVERAGE_OFF_ATTR}",
)
]
unclassified = [
attr for attr in attrs if RE_CFG_MENTIONS_TEST.match(RE_STRING.sub('""', attr))
]
if unclassified:
return [
Finding(
line,
"unclassified-cfg",
f"`mod {name}` is gated on {unclassified[0]}, which this check "
f"cannot tell apart from a module that ships in the library; "
f"add {COVERAGE_OFF_ATTR} if it is test-only, or teach this "
f"check the cfg if it is not",
)
]
return []
def _check_test_modules(lines: list[str]) -> list[Finding]:
"""Findings for every test module that is not excluded from coverage."""
findings: list[Finding] = []
attrs: list[str] = []
attrs_line = 0
for number, raw in enumerate(lines, start=1):
stripped = raw.strip()
# Blank lines and comments are allowed between an attribute and its item.
if not stripped or stripped.startswith("//"):
continue
if stripped.startswith("#["):
if not attrs:
attrs_line = number
attrs.append(stripped)
continue
module = RE_MOD.match(stripped)
if module is not None and attrs:
findings += _check_module(attrs, attrs_line, module.group(1))
attrs = []
return findings
def _check_crate_root(name: str, lines: list[str]) -> list[Finding]:
"""A finding if a crate root is missing the coverage_attribute feature gate."""
if name not in CRATE_ROOTS:
return []
if any(line.strip() == FEATURE_ATTR for line in lines):
return []
return [
Finding(
1,
"missing-feature-gate",
f"crate root is missing {FEATURE_ATTR}",
)
]
def check_source(name: str, text: str) -> list[Finding]:
"""Findings for one file's contents; `name` is its base name (lib.rs, ...)."""
lines = text.splitlines()
return _check_crate_root(name, lines) + _check_test_modules(lines)
def check_file(path: Path) -> list[Finding]:
return check_source(path.name, path.read_text(encoding="utf-8"))
def main() -> int:
total = 0
for path in (Path(name) for name in sys.argv[1:]):
for finding in check_file(path):
total += 1
print(f"{path}:{finding.line}: {finding.label}: {finding.message}")
return 1 if total else 0
if __name__ == "__main__":
sys.exit(main())

144
bin/pre-commit/fix_gtest_names.py Executable file
View File

@@ -0,0 +1,144 @@
#!/usr/bin/env python3
"""
Rewrites gtest names to the required style in this project: the suite name is
CamelCase, the test-case name is snake_case.
TEST(SuiteName, test_case_name)
The gtest `DISABLED_` prefix is kept verbatim on either name.
Both conversions fold acronyms the way a reader expects:
`SetAndResetAccountTxnID` -> `set_and_reset_account_txn_id`, not
`set_and_reset_account_txn_i_d`.
The first argument of `TEST_F`, `TEST_P`, `TYPED_TEST` and `TYPED_TEST_P` is a
fixture class rather than a free identifier, so rewriting it here would leave
the class it names behind. Those are reported for a human to rename (clang-tidy
checks the class declaration itself, via readability-identifier-naming).
Usage: ./bin/pre-commit/fix_gtest_names.py <file1> <file2> ...
"""
import re
import sys
from collections import Counter
from pathlib import Path
# A test-case definition, `MACRO(SuiteOrFixture, TestName)`, anchored at the
# start of a line so that commented-out definitions and project macros that
# merely look similar (`TEST_EXPECT(...)`) are left alone. The `\s*` between
# arguments allows for a definition clang-format wrapped over several lines.
PATTERN = re.compile(
r"(?P<head>^[ \t]*(?P<macro>TYPED_TEST_P|TYPED_TEST|TEST_F|TEST_P|TEST)\s*\(\s*)"
r"(?P<suite>\w+)(?P<mid>\s*,\s*)(?P<name>\w+)(?P<tail>\s*\))",
re.MULTILINE,
)
# The macros whose first argument names a fixture class, not a free identifier.
FIXTURE_MACROS = ("TEST_F", "TEST_P", "TYPED_TEST", "TYPED_TEST_P")
DISABLED = "DISABLED_"
ACRONYM_BOUNDARY = re.compile(r"([A-Z]+)([A-Z][a-z])")
WORD_BOUNDARY = re.compile(r"([a-z\d])([A-Z])")
def _split_disabled(name: str) -> tuple[str, str]:
"""Splits off gtest's `DISABLED_` prefix, which is kept verbatim."""
if name.startswith(DISABLED):
return DISABLED, name[len(DISABLED) :]
return "", name
def snake_case(name: str) -> str:
"""Returns the name in snake_case, leaving acronyms whole.
`SetAndResetAccountTxnID` -> `set_and_reset_account_txn_id`,
`parseStatRSSkB` -> `parse_stat_rs_sk_b`.
"""
prefix, core = _split_disabled(name)
core = ACRONYM_BOUNDARY.sub(r"\1_\2", core)
return prefix + WORD_BOUNDARY.sub(r"\1_\2", core).lower()
def camel_case(name: str) -> str:
"""Returns the name in CamelCase, capitalizing each underscored word.
Only the letters that have to change are touched, so acronyms survive: a
conversion that went via snake_case would turn `SHAMapTest` into
`ShaMapTest`, whereas here it is already CamelCase and stays put.
`json_value` -> `JsonValue`, `parseStatRSSkB` -> `ParseStatRSSkB`.
"""
prefix, core = _split_disabled(name)
return prefix + "".join(w[:1].upper() + w[1:] for w in core.split("_") if w)
def _corrected(match: re.Match) -> tuple[str, str]:
"""Returns the suite and test-case names this definition should end up with."""
suite = match["suite"]
return (
suite if match["macro"] in FIXTURE_MACROS else camel_case(suite),
snake_case(match["name"]),
)
def fix_source(text: str) -> tuple[str, list[str]]:
"""Returns the corrected text and one `line: message` report per bad name."""
# gtest joins the suite and test names into one class name, so two test
# cases whose joined names agree cannot coexist: `TEST(a, b_c)` and
# `TEST(a_b, c)` both define `a_b_c_Test`. A rename that would introduce
# such a clash is reported for a human instead of applied.
joined = Counter("_".join(_corrected(m)) for m in PATTERN.finditer(text))
reports = []
def rewrite(match: re.Match) -> str:
suite, name = match["suite"], match["name"]
new_suite, new_name = _corrected(match)
line = text.count("\n", 0, match.start()) + 1
if match["macro"] in FIXTURE_MACROS and camel_case(suite) != suite:
reports.append(
f"{line}: fixture '{suite}' is not CamelCase: rename the class "
f"to '{camel_case(suite)}' by hand"
)
if (new_suite, new_name) == (suite, name):
return match[0]
if joined[f"{new_suite}_{new_name}"] > 1:
reports.append(
f"{line}: cannot rename '{suite}, {name}' to '{new_suite}, "
f"{new_name}': another test case already generates that name"
)
return match[0]
if new_suite != suite:
reports.append(f"{line}: renamed suite '{suite}' to '{new_suite}'")
if new_name != name:
reports.append(f"{line}: renamed test case '{name}' to '{new_name}'")
return match["head"] + new_suite + match["mid"] + new_name + match["tail"]
return PATTERN.sub(rewrite, text), reports
def fix_names(path: Path) -> bool:
"""Corrects one file's gtest names, reporting each on stdout."""
original = path.read_text(encoding="utf-8")
fixed, reports = fix_source(original)
for report in reports:
print(f"{path}:{report}")
if fixed != original:
path.write_text(fixed, encoding="utf-8")
return not reports
def main() -> int:
files = [Path(f) for f in sys.argv[1:]]
success = True
for path in files:
success &= fix_names(path)
return 0 if success else 1
if __name__ == "__main__":
sys.exit(main())

View File

@@ -0,0 +1,259 @@
#!/usr/bin/env python3
"""
Tests for fix_gtest_names.py.
Run directly (no test framework needed):
./bin/pre-commit/test_fix_gtest_names.py
or under pytest:
pytest bin/pre-commit/test_fix_gtest_names.py
"""
import sys
import textwrap
from fix_gtest_names import camel_case, fix_source, snake_case
def dedent(text: str) -> str:
"""Removes a fixture's common indentation and its leading newline.
Lets fixtures be written as indented triple-quoted here-docs while keeping
honest 1-based line numbers.
"""
return textwrap.dedent(text).lstrip("\n")
def fixed(text: str) -> str:
return fix_source(dedent(text))[0]
def reports(text: str) -> list[str]:
return fix_source(dedent(text))[1]
# --- conversion --------------------------------------------------------------
def test_snake_case_conversion() -> None:
assert snake_case("BadInputs") == "bad_inputs"
assert snake_case("mulDiv") == "mul_div"
assert snake_case("already_snake") == "already_snake"
assert snake_case("base64") == "base64"
def test_snake_case_keeps_acronyms_whole() -> None:
assert snake_case("SetAndResetAccountTxnID") == "set_and_reset_account_txn_id"
assert snake_case("XRPToIOU") == "xrp_to_iou"
assert snake_case("STAmountMath") == "st_amount_math"
def test_camel_case_conversion() -> None:
assert camel_case("json_value") == "JsonValue"
assert camel_case("mulDiv") == "MulDiv"
assert camel_case("scope") == "Scope"
assert camel_case("base64") == "Base64"
def test_camel_case_leaves_acronyms_alone() -> None:
# A snake_case round-trip would give `ShaMapTest` / `ParseStatmRsSkB` here.
assert camel_case("SHAMapTest") == "SHAMapTest"
assert camel_case("parseStatmRSSkB") == "ParseStatmRSSkB"
assert camel_case("XRPAmount") == "XRPAmount"
assert camel_case("CSPRNG") == "CSPRNG"
def test_disabled_prefix_preserved() -> None:
assert snake_case("DISABLED_FooBar") == "DISABLED_foo_bar"
assert snake_case("DISABLED_foo_bar") == "DISABLED_foo_bar"
assert snake_case("DISABLED_") == "DISABLED_"
assert camel_case("DISABLED_foo_bar") == "DISABLED_FooBar"
assert camel_case("DISABLED_") == "DISABLED_"
# --- what counts as a test definition ---------------------------------------
def test_all_macros_recognized() -> None:
code = """
TEST(Suite, oneName)
TEST_F(Fixture, twoName)
TEST_P(Fixture, threeName)
TYPED_TEST(Fixture, fourName)
TYPED_TEST_P(Fixture, fiveName)
"""
assert fixed(code) == dedent("""
TEST(Suite, one_name)
TEST_F(Fixture, two_name)
TEST_P(Fixture, three_name)
TYPED_TEST(Fixture, four_name)
TYPED_TEST_P(Fixture, five_name)
""")
def test_conforming_definitions_untouched() -> None:
code = """
TEST(AccountSet, bad_inputs)
TEST_F(MutexMakeTest, default_constructor)
TEST(SHAMap, DISABLED_slow_path)
"""
assert reports(code) == []
assert fixed(code) == dedent(code)
def test_lookalikes_ignored() -> None:
code = """
// TEST(Suite, notATest)
TEST_EXPECT(someCall())
TEST_EXPECTS(amount == value, amount.getText())
INSTANTIATE_TEST_SUITE_P(Prefix, Fixture, testValues());
auto x = TEST(Suite, notATest);
TYPED_TEST_SUITE(Fixture, MyTypes);
"""
assert reports(code) == []
assert fixed(code) == dedent(code)
def test_indented_and_wrapped_definitions() -> None:
code = """
namespace ripple {
TEST(Suite, indentedName)
}
TEST_F(
SomeVeryLongFixtureName,
wrappedName)
"""
assert fixed(code) == dedent("""
namespace ripple {
TEST(Suite, indented_name)
}
TEST_F(
SomeVeryLongFixtureName,
wrapped_name)
""")
# --- rewriting --------------------------------------------------------------
def test_only_the_two_names_are_rewritten() -> None:
code = """
TEST(mulDiv, mulDiv)
{
auto const mulDiv = 1; // mulDiv stays
}
"""
assert fixed(code) == dedent("""
TEST(MulDiv, mul_div)
{
auto const mulDiv = 1; // mulDiv stays
}
""")
def test_suite_name_camel_cased() -> None:
code = """
TEST(json_value, limits)
TEST(scope, ScopeExit)
"""
assert reports(code) == [
"1: renamed suite 'json_value' to 'JsonValue'",
"2: renamed suite 'scope' to 'Scope'",
"2: renamed test case 'ScopeExit' to 'scope_exit'",
]
assert fixed(code) == dedent("""
TEST(JsonValue, limits)
TEST(Scope, scope_exit)
""")
def test_fixture_reported_but_not_renamed() -> None:
# The first argument names a class, so only a human (or clang-tidy) can
# rename it; the test-case name is still fixed.
code = """
TEST_F(my_fixture, someTest)
"""
assert reports(code) == [
"1: fixture 'my_fixture' is not CamelCase: rename the class to "
"'MyFixture' by hand",
"1: renamed test case 'someTest' to 'some_test'",
]
assert fixed(code) == dedent("""
TEST_F(my_fixture, some_test)
""")
def test_reports_carry_line_numbers() -> None:
code = """
#include <foo.h>
TEST(Suite, firstName)
TEST(Suite, secondName)
"""
assert reports(code) == [
"3: renamed test case 'firstName' to 'first_name'",
"5: renamed test case 'secondName' to 'second_name'",
]
# --- collisions -------------------------------------------------------------
def test_collision_reported_and_not_applied() -> None:
# Both would define `Suite_mul_div_Test`.
code = """
TEST(Suite, mulDiv)
TEST(Suite, mul_div)
"""
assert reports(code) == [
"1: cannot rename 'Suite, mulDiv' to 'Suite, mul_div': another test "
"case already generates that name"
]
assert fixed(code) == dedent(code)
def test_collision_between_converging_suites() -> None:
# Both suites camel-case to `SuiteA`, so both would define
# `SuiteA_one_test_Test`.
code = """
TEST(SuiteA, oneTest)
TEST(Suite_a, one_test)
"""
assert [r.split(":")[1].strip() for r in reports(code)] == [
"cannot rename 'SuiteA, oneTest' to 'SuiteA, one_test'",
"cannot rename 'Suite_a, one_test' to 'SuiteA, one_test'",
]
assert fixed(code) == dedent(code)
def test_same_name_in_different_suites_is_not_a_collision() -> None:
code = """
TEST(SuiteOne, mulDiv)
TEST(SuiteTwo, mulDiv)
"""
assert fixed(code) == dedent("""
TEST(SuiteOne, mul_div)
TEST(SuiteTwo, mul_div)
""")
def main() -> int:
tests = sorted(
(name, fn)
for name, fn in globals().items()
if name.startswith("test_") and callable(fn)
)
failed = 0
for name, fn in tests:
try:
fn()
print(f"PASS {name}")
except AssertionError as exc:
failed += 1
print(f"FAIL {name}: {exc!r}")
print(f"\n{len(tests) - failed}/{len(tests)} passed")
return 1 if failed else 0
if __name__ == "__main__":
sys.exit(main())

View File

@@ -1,28 +0,0 @@
include_guard()
set(GIT_BUILD_BRANCH "")
set(GIT_COMMIT_HASH "")
find_package(Git)
if(NOT Git_FOUND)
message(WARNING "Git not found. Git branch and commit hash will be empty.")
return()
endif()
set(GIT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/.git)
execute_process(
COMMAND
${GIT_EXECUTABLE} --git-dir=${GIT_DIRECTORY} rev-parse --abbrev-ref HEAD
OUTPUT_STRIP_TRAILING_WHITESPACE
OUTPUT_VARIABLE GIT_BUILD_BRANCH
)
execute_process(
COMMAND ${GIT_EXECUTABLE} --git-dir=${GIT_DIRECTORY} rev-parse HEAD
OUTPUT_STRIP_TRAILING_WHITESPACE
OUTPUT_VARIABLE GIT_COMMIT_HASH
)
message(STATUS "Git branch: ${GIT_BUILD_BRANCH}")
message(STATUS "Git commit hash: ${GIT_COMMIT_HASH}")

View File

@@ -81,7 +81,7 @@ include(target_link_modules)
add_module(xrpl beast)
target_link_libraries(xrpl.libxrpl.beast PUBLIC xrpl.imports.main)
include(GitInfo)
include(XrplVersion)
add_module(xrpl git)
target_compile_definitions(
xrpl.libxrpl.git
@@ -111,6 +111,11 @@ target_link_libraries(
xrpl.libxrpl.protocol
PUBLIC xrpl.libxrpl.crypto xrpl.libxrpl.git xrpl.libxrpl.json
)
# Only on BuildInfo.cpp, so a new version does not rebuild the whole module.
set_source_files_properties(
${CMAKE_CURRENT_SOURCE_DIR}/src/libxrpl/protocol/BuildInfo.cpp
PROPERTIES COMPILE_DEFINITIONS XRPLD_VERSION="${XRPLD_VERSION}"
)
# Level 05
add_module(xrpl protocol_autogen)
@@ -296,7 +301,14 @@ if(xrpld)
target_sources(xrpld PRIVATE ${sources})
endif()
target_link_libraries(xrpld Xrpl::boost Xrpl::opts Xrpl::libs xrpl.libxrpl)
target_link_libraries(
xrpld
Xrpl::boost
Xrpl::opts
Xrpl::libs
xrpl.libxrpl
rpcspec::rpcspec
)
exclude_if_included(xrpld)
# define a macro for tests that might need to
# be excluded or run differently in CI environment

View File

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

View File

@@ -44,12 +44,18 @@ else()
set(pkg_type rpm)
endif()
# Unquoted below, so an empty value adds no argument at all.
set(pkg_variant_option "")
if(assert)
set(pkg_variant_option --variant=assert)
endif()
add_custom_target(
package
COMMAND
${CMAKE_SOURCE_DIR}/package/build_pkg.py --package-type=${pkg_type}
--build-dir=${CMAKE_BINARY_DIR} --pkg-release=${pkg_release}
--channel=UNRELEASED
${pkg_variant_option} --channel=UNRELEASED
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
DEPENDS xrpld validator-keys
COMMENT "Building Linux ${pkg_type} package"

View File

@@ -1,15 +1,75 @@
#[===================================================================[
read version from source
#]===================================================================]
find_package(Git)
file(STRINGS src/libxrpl/protocol/BuildInfo.cpp BUILD_INFO)
foreach(line_ ${BUILD_INFO})
if(line_ MATCHES "versionString[ ]*=[ ]*\"(.+)\"")
set(xrpld_version ${CMAKE_MATCH_1})
endif()
endforeach()
if(xrpld_version)
message(STATUS "xrpld version: ${xrpld_version}")
else()
message(FATAL_ERROR "unable to determine xrpld version")
set(GIT_BUILD_BRANCH "")
set(GIT_COMMIT_HASH "")
if(DEFINED ENV{GITHUB_BRANCH_NAME})
set(GIT_BUILD_BRANCH $ENV{GITHUB_BRANCH_NAME})
set(GIT_COMMIT_HASH $ENV{GITHUB_HEAD_SHA})
elseif(Git_FOUND AND EXISTS "${CMAKE_CURRENT_LIST_DIR}/../.git")
execute_process(
COMMAND ${GIT_EXECUTABLE} rev-parse --abbrev-ref HEAD
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/..
OUTPUT_VARIABLE GIT_BUILD_BRANCH
OUTPUT_STRIP_TRAILING_WHITESPACE
COMMAND_ERROR_IS_FATAL ANY
)
execute_process(
COMMAND ${GIT_EXECUTABLE} rev-parse HEAD
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/..
OUTPUT_VARIABLE GIT_COMMIT_HASH
OUTPUT_STRIP_TRAILING_WHITESPACE
COMMAND_ERROR_IS_FATAL ANY
)
endif()
message(STATUS "Git branch: ${GIT_BUILD_BRANCH}")
message(STATUS "Git commit hash: ${GIT_COMMIT_HASH}")
if(
DEFINED ENV{FORCE_XRPLD_VERSION}
AND NOT "$ENV{FORCE_XRPLD_VERSION}" STREQUAL ""
)
message(
STATUS
"Using explicitly provided '$ENV{FORCE_XRPLD_VERSION}' as xrpld version"
)
set(XRPLD_VERSION "$ENV{FORCE_XRPLD_VERSION}")
# The rules beast::SemanticVersion::parse applies, so that an invalid version
# fails here rather than when xrpld starts. It reads each number as an int.
set(SEMVER_NUMBER "(0|[1-9][0-9]*)")
set(SEMVER_PRE_RELEASE "[A-Za-z1-9-][A-Za-z0-9-]*")
set(SEMVER_METADATA "[A-Za-z0-9-]+")
set(SEMVER_NUMBER_MAX 2147483647)
if(
NOT XRPLD_VERSION
MATCHES
"^${SEMVER_NUMBER}\\.${SEMVER_NUMBER}\\.${SEMVER_NUMBER}(-${SEMVER_PRE_RELEASE}(\\.${SEMVER_PRE_RELEASE})*)?(\\+${SEMVER_METADATA}(\\.${SEMVER_METADATA})*)?$"
OR CMAKE_MATCH_1 GREATER SEMVER_NUMBER_MAX
OR CMAKE_MATCH_2 GREATER SEMVER_NUMBER_MAX
OR CMAKE_MATCH_3 GREATER SEMVER_NUMBER_MAX
)
message(
FATAL_ERROR
"FORCE_XRPLD_VERSION '${XRPLD_VERSION}' is not a semantic version xrpld accepts, see https://semver.org"
)
endif()
else()
message(STATUS "Using '0.0.0-dev+<git short rev>' as xrpld version")
if(GIT_COMMIT_HASH STREQUAL "")
message(
FATAL_ERROR
"Unable to determine xrpld version without git, set FORCE_XRPLD_VERSION"
)
endif()
string(SUBSTRING ${GIT_COMMIT_HASH} 0 7 GIT_COMMIT_HASH_SHORT)
set(XRPLD_VERSION "0.0.0-dev+${GIT_COMMIT_HASH_SHORT}")
endif()
message(STATUS "Build version: ${XRPLD_VERSION}")

View File

@@ -59,7 +59,7 @@ def create_transaction_parser():
# the members that differ from these.
SETTING_DEFAULTS = {
"delegable": "Delegation::NotDelegable",
"amendment": "uint256{}",
"amendment": "UInt256{}",
"privileges": "Privilege::NoPriv",
}

View File

@@ -209,7 +209,7 @@ ${field['typeData']['setter_type']} ${field['paramName']}${',' if i < len(requir
* @return The constructed ledger entry wrapper.
*/
${name}
build(uint256 const& index)
build(UInt256 const& index)
{
return ${name}{std::make_shared<SLE>(std::move(object_), index)};
}

View File

@@ -31,7 +31,7 @@ namespace xrpl::ledger_entries {
// builder's STObject and the wrapper's SLE.
TEST(${name}Tests, BuilderSettersRoundTrip)
{
uint256 const index{1u};
UInt256 const index{1u};
% for field in fields:
auto const ${field["paramName"]}Value = ${canonical_expr(field)};
@@ -85,7 +85,7 @@ TEST(${name}Tests, BuilderSettersRoundTrip)
// from that SLE, build a new wrapper, and verify all fields (and validate()).
TEST(${name}Tests, BuilderFromSleRoundTrip)
{
uint256 const index{2u};
UInt256 const index{2u};
% for field in fields:
auto const ${field["paramName"]}Value = ${canonical_expr(field)};
@@ -146,7 +146,7 @@ TEST(${name}Tests, BuilderFromSleRoundTrip)
// 3) Verify wrapper throws when constructed from wrong ledger entry type.
TEST(${name}Tests, WrapperThrowsOnWrongEntryType)
{
uint256 const index{3u};
UInt256 const index{3u};
// Build a valid ledger entry of a different type
// Ticket requires: Account, OwnerNode, TicketSequence, PreviousTxnID, PreviousTxnLgrSeq
@@ -177,7 +177,7 @@ TEST(${name}Tests, WrapperThrowsOnWrongEntryType)
// 4) Verify builder throws when constructed from wrong ledger entry type.
TEST(${name}Tests, BuilderThrowsOnWrongEntryType)
{
uint256 const index{4u};
UInt256 const index{4u};
// Build a valid ledger entry of a different type
% if wrong_le_include == "Ticket":
@@ -207,7 +207,7 @@ TEST(${name}Tests, BuilderThrowsOnWrongEntryType)
// 5) Build with only required fields and verify optional fields return nullopt.
TEST(${name}Tests, OptionalFieldsReturnNullopt)
{
uint256 const index{3u};
UInt256 const index{3u};
% for field in required_fields:
auto const ${field["paramName"]}Value = ${canonical_expr(field)};

View File

@@ -3,6 +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",
"sqlite3/3.53.0#324ada52333108388a9a6108bfa96734%1782392403.185447",
"soci/4.0.3#e726491a03468795453f7c83fc924a96%1782392402.679521",
"snappy/1.1.10#968fef506ff261592ec30c574d4a7809%1782307151.633168",
@@ -19,8 +20,8 @@
"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#f729f6d75992d20f9c72828e9142d62f%1783945160.094135",
"fast_float/8.2.10#f6f28d6bb22112078e7dbda611caf681%1782494504.298",
"grpc/1.81.1#b87796a4269034856cbc1a2522db16eb%1788275071.530512",
"fast_float/8.2.10#f6f28d6bb22112078e7dbda611caf681%1785888854.601666",
"ed25519/2015.03#ae761bdc52730a843f0809bdf6c1b1f6%1782307148.15562",
"date/3.0.4#862e11e80030356b53c2c38599ceb32b%1782392402.538492",
"corrosion/0.6.1#bfa292df0a957bc70a450ff316cd9435%1786119416.131296",
@@ -45,6 +46,10 @@
],
"python_requires": [],
"overrides": {
"boost/1.91.0#ea540ca2133d831b560036aa24dece3c": [
null,
"boost/1.91.0#ea540ca2133d831b560036aa24dece3c"
],
"protobuf/[>=5.27.0 <7]": [
"protobuf/6.33.5"
],

View File

@@ -1,9 +1,13 @@
import os
import re
from conan.tools.cmake import CMake, CMakeToolchain, cmake_layout
from conan.tools.env import Environment
from conan import ConanFile
DEV_VERSION = "0.0.0-dev"
class Xrpl(ConanFile):
name = "xrpl"
@@ -36,6 +40,7 @@ class Xrpl(ConanFile):
"nudb/2.0.9",
"openssl/3.6.3",
"soci/4.0.3",
"xrpl-rpc-spec/0.1.19",
"zlib/1.3.2",
]
@@ -114,17 +119,12 @@ class Xrpl(ConanFile):
"soci/*:shared": False,
"soci/*:with_sqlite3": True,
"soci/*:with_boost": True,
"xrpl-rpc-spec/*:server": "xrpld",
"xxhash/*:shared": False,
}
def set_version(self):
if self.version is None:
path = f"{self.recipe_folder}/src/libxrpl/protocol/BuildInfo.cpp"
regex = r"versionString\s?=\s?\"(.*)\""
with open(path, encoding="utf-8") as file:
matches = (re.search(regex, line) for line in file)
match = next(m for m in matches if m)
self.version = match.group(1)
self.version = self.version or DEV_VERSION
def configure(self):
if self.settings.compiler == "apple-clang":
@@ -149,6 +149,7 @@ class Xrpl(ConanFile):
self.requires("xxhash/0.8.3", transitive_headers=True)
exports_sources = (
"bin/default-loader-path.sh",
"CMakeLists.txt",
"cfg/*",
"cmake/*",
@@ -166,6 +167,17 @@ class Xrpl(ConanFile):
generators = "CMakeDeps"
def generate(self):
# The sources in the Conan cache have no git history, so the version
# comes from the reference, unless it is not one, like 'develop'.
if not os.path.exists(os.path.join(self.source_folder, ".git")):
version = str(self.version)
env = Environment()
env.define(
"FORCE_XRPLD_VERSION",
version if re.match(r"\d+\.\d+\.\d+", version) else DEV_VERSION,
)
env.vars(self).save_script("xrpld_version")
tc = CMakeToolchain(self)
tc.variables["tests"] = self.options.tests
tc.variables["benchmark"] = self.options.benchmark

20
crates/Cargo.lock generated
View File

@@ -57,9 +57,9 @@ dependencies = [
[[package]]
name = "cxx"
version = "1.0.199"
version = "1.0.202"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "824894a4a85dca76d4c95c2b9098c036f5a29f627b30c12780774f6654e60974"
checksum = "13f6de320895f42e6e081abb5c7983bedcf0b6d0ff9323de0d33f620c8ac1199"
dependencies = [
"cc",
"cxx-build",
@@ -72,9 +72,9 @@ dependencies = [
[[package]]
name = "cxx-build"
version = "1.0.199"
version = "1.0.202"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1ae0b651ea5b0000b19513aef5a03f194d7e3486f2d9258b658da8677fe9036"
checksum = "4fde53ca86b9704a943fef0f1e1d836239a6aedca5de3c65fa9f97ec0bd46d39"
dependencies = [
"cc",
"codespan-reporting",
@@ -87,9 +87,9 @@ dependencies = [
[[package]]
name = "cxxbridge-cmd"
version = "1.0.199"
version = "1.0.202"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb05f91d3fb8435d9bab6ac5ce6ac1868be774325fb7fb2a91be39393b21388e"
checksum = "07bae89236c811fd4d08ed3441759ac4ac98d752cbfd3de341315ba16ad20ec3"
dependencies = [
"clap",
"codespan-reporting",
@@ -101,15 +101,15 @@ dependencies = [
[[package]]
name = "cxxbridge-flags"
version = "1.0.199"
version = "1.0.202"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf293202e0e3e98495785745389e8d0755b217e66f19194a5c695c25e03282ef"
checksum = "49045042e5fced01b80742aba5508de82aa4f13677ed3fa2b4cda709c40c5918"
[[package]]
name = "cxxbridge-macro"
version = "1.0.199"
version = "1.0.202"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca001d746947c7249ed9d332a10f7a59daedbafeb0ec68c5c18a7db7a93f6ccc"
checksum = "b181252e2e3d3b5d183afbdc033a3958b445eb3e1a0ae65fc3d4f5259f5da6fd"
dependencies = [
"indexmap",
"proc-macro2",

View File

@@ -8,6 +8,9 @@ cxx = { version = "1.0.198", features = ["c++20"] }
[workspace.package]
edition = "2024"
[workspace.lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = [ 'cfg(coverage)', 'cfg(coverage_nightly)' ] }
[profile.release]
opt-level = 3
overflow-checks = true

View File

@@ -8,3 +8,6 @@ crate-type = ["staticlib"]
[dependencies]
cxx.workspace = true
[lints]
workspace = true

View File

@@ -1,3 +1,5 @@
#![cfg_attr(coverage_nightly, feature(coverage_attribute))]
#[cxx::bridge(namespace = "rs::hello_world")]
mod ffi {
extern "Rust" {
@@ -8,3 +10,14 @@ mod ffi {
pub fn hello_world() -> String {
"hello_world".to_string()
}
#[cfg(test)]
#[cfg_attr(coverage_nightly, coverage(off))]
mod tests {
use super::*;
#[test]
fn hello_world_returns_hello_world() {
assert_eq!(hello_world(), "hello_world")
}
}

View File

@@ -1,5 +1,19 @@
# `xrpld` Docker Image
- Some info relating to Docker containers can be found here: [../Builds/containers](../Builds/containers)
- Images for building and testing xrpld can be found here: [thejohnfreeman/rippled-docker](https://github.com/thejohnfreeman/rippled-docker/)
- These images do not have xrpld. They have all the tools necessary to build xrpld.
`xrpld` is published to Docker Hub as [`xrplf/xrpld`](https://hub.docker.com/r/xrplf/xrpld):
the `xrpld` DEB package installed on Ubuntu 26.04, running as the `xrpld` user.
Each release is tagged with its version, `xrplf/xrpld:<version>`, and
`xrplf/xrpld:develop` follows the `develop` branch.
See [`package/README.md`](../package/README.md#docker-images) for how it is built
and tagged.
```bash
docker run --detach --name xrpld \
--volume xrpld-db:/var/lib/xrpld \
--publish 2459:2459 \
xrplf/xrpld:develop
```
The admin ports (5005, 6006 and 50051) listen on `127.0.0.1` in the shipped
configuration; to reach them from outside the container, mount your own over
`/etc/xrpld/xrpld.cfg`.

View File

@@ -6,14 +6,15 @@
`xrpld` is published as DEB and RPM packages for 64-bit x86 Linux.
Use APT on Debian-based distributions such as Debian and Ubuntu,
and YUM on Red Hat-based distributions such as RHEL, AlmaLinux, and Rocky Linux.
and DNF on Red Hat-based distributions such as RHEL, AlmaLinux, and Rocky Linux,
where `yum` is a symlink to `dnf`.
To build from source instead, see [BUILD.md](../BUILD.md).
## Release channels
Packages are published to four channels:
- `stable` - the latest production release
- `stable` - production releases
- `rc` - release candidates
- `beta` - beta builds
- `develop` - every push to the [`develop` branch](https://github.com/XRPLF/rippled/tree/develop)
@@ -81,7 +82,7 @@ wherever it appears in the repository configuration.
sudo apt -y install xrpld
```
### With the YUM package manager
### With the DNF package manager
1. Add the XRPL Foundation package-signing key:
@@ -109,9 +110,23 @@ wherever it appears in the repository configuration.
3. Install the `xrpld` package:
```bash
sudo yum install -y xrpld
sudo dnf install -y xrpld
```
### Optional: the assert-enabled build
Every channel also carries `xrpld-assert` as a DEB, the same build with assertions
enabled, for diagnosing a problem on a non-production server.
It installs the same files as `xrpld` and replaces it, so install one or the other:
```bash
sudo apt -y install xrpld-assert # APT removes xrpld itself
```
Switching stops the service, since it is a removal and an installation rather than an upgrade,
and APT starts it again.
Install `xrpld` the same way to switch back.
## The xrpld service
Both package managers install a systemd unit and enable it, so `xrpld` starts on boot.
@@ -121,7 +136,7 @@ Check whether it is already running:
systemctl status xrpld.service
```
The APT packages start it immediately as well; the YUM packages do not, so start it yourself:
The DEB packages start it immediately as well; the RPM packages do not, so start it yourself:
```bash
sudo systemctl start xrpld.service

View File

@@ -0,0 +1,11 @@
# basics' container adapters (TaggedCache, partitioned_unordered_map,
# base_uint) model std concepts, which mandate
# snake_case member type names.
#
# clang-tidy replaces rather than merges this option, so the list is the
# top-level one restated plus the 6 name(s) needed only here:
# allocator_type const_pointer const_reverse_iterator hasher key_equal reverse_iterator
InheritParentConfig: true
CheckOptions:
readability-identifier-naming.TypeAliasIgnoredRegexp: "^(allocator_type|const_iterator|const_pointer|const_reference|const_reverse_iterator|difference_type|duration|hasher|iterator|iterator_category|key_equal|key_type|mapped_type|period|pointer|reference|rep|result_type|reverse_iterator|size_type|time_point|value_type)$"
readability-identifier-naming.TypedefIgnoredRegexp: "^(allocator_type|const_iterator|const_pointer|const_reference|const_reverse_iterator|difference_type|duration|hasher|iterator|iterator_category|key_equal|key_type|mapped_type|period|pointer|reference|rep|result_type|reverse_iterator|size_type|time_point|value_type)$"

View File

@@ -618,13 +618,16 @@ SharedWeakUnion<T>::convertToWeak()
unsafeSetRawPtr(nullptr);
return true; // Should never happen
// LCOV_EXCL_STOP
case PartialDestroy:
// This is a weird case. We just converted the last strong
// pointer to a weak pointer.
case PartialDestroy: {
// We just converted the last strong pointer to a weak pointer.
// The weak ref we now hold keeps the object from being fully
// destroyed, so `p` stays valid; only the copy passed to
// `partialDestructorFinished` is nulled.
p->partialDestructor();
partialDestructorFinished(&p);
// p is null and may no longer be used
auto finished = p;
partialDestructorFinished(&finished);
break;
}
}
unsafeSetRawPtr(p, RefStrength::Weak);
return true;

View File

@@ -77,21 +77,13 @@ struct IntrusiveRefCounts
std::size_t
useCount() const noexcept;
// This function MUST be called after a partial destructor finishes running.
// Calling this function may cause other threads to delete the object
// pointed to by `o`, so `o` should never be used after calling this
// function. The parameter will be set to a `nullptr` after calling this
// function to emphasize that it should not be used.
// Note: This is intentionally NOT called at the end of `partialDestructor`.
// The reason for this is if new classes are written to support this smart
// pointer class, they need to write their own `partialDestructor` function
// and ensure `partialDestructorFinished` is called at the end. Putting this
// call inside the smart pointer class itself is expected to be less error
// prone.
// Note: The "two-star" programming is intentional. It emphasizes that `o`
// may be deleted and the unergonomic API is meant to signal the special
// nature of this function call to callers.
// Note: This is a template to support incompletely defined classes.
// MUST be called after `partialDestructor` returns. Another thread may
// then delete the object, so `*o` is nulled and must not be used after
// (unless the caller holds its own weak ref, e.g.
// SharedWeakUnion::convertToWeak). Called by the smart pointers, not
// `partialDestructor`, so custom partial destructors can't forget it.
// The two-star API signals that `*o` may be deleted. Templated to
// support incomplete types.
template <class T>
friend void
partialDestructorFinished(T** o);
@@ -334,15 +326,11 @@ IntrusiveRefCounts::addWeakReleaseStrongRef() const
ReleaseStrongRefAction action = NoOp;
if (prevVal.strong == 1)
{
if (prevVal.weak == 0)
{
action = NoOp;
}
else
{
nextIntVal |= kPartialDestroyStartedMask;
action = PartialDestroy;
}
// The weak ref added here keeps the weak count non-zero, so
// releasing the last strong ref always starts a partial destroy,
// regardless of the previous weak count.
nextIntVal |= kPartialDestroyStartedMask;
action = PartialDestroy;
}
if (refCounts_.compare_exchange_weak(prevIntVal, nextIntVal, std::memory_order_acq_rel))
{
@@ -358,24 +346,26 @@ IntrusiveRefCounts::addWeakReleaseStrongRef() const
inline ReleaseWeakRefAction
IntrusiveRefCounts::releaseWeakRef() const
{
auto prevIntVal = refCounts_.fetch_sub(kWeakDelta, std::memory_order_acq_rel);
RefCountPair prev = prevIntVal;
auto const prevIntVal = refCounts_.fetch_sub(kWeakDelta, std::memory_order_acq_rel);
RefCountPair const prev = prevIntVal;
if (prev.weak == 1 && prev.strong == 0)
{
// `wait` blocks while the value equals its argument, so it must be
// given the value as it is after the decrement above.
auto curIntVal = prevIntVal - kWeakDelta;
if (prev.partialDestroyStartedBit == 0u)
{
// This case should only be hit if the partialDestroyStartedBit is
// set non-atomically (and even then very rarely). The code is kept
// in case we need to set the flag non-atomically for perf reasons.
refCounts_.wait(prevIntVal, std::memory_order_acquire);
prevIntVal = refCounts_.load(std::memory_order_acquire);
prev = RefCountPair{prevIntVal};
refCounts_.wait(curIntVal, std::memory_order_acquire);
curIntVal = refCounts_.load(std::memory_order_acquire);
}
if (prev.partialDestroyFinishedBit == 0u)
if (RefCountPair{curIntVal}.partialDestroyFinishedBit == 0u)
{
// partial destroy MUST finish before running a full destroy (when
// using weak pointers)
refCounts_.wait(prevIntVal - kWeakDelta, std::memory_order_acquire);
refCounts_.wait(curIntVal, std::memory_order_acquire);
}
return ReleaseWeakRefAction::Destroy;
}

View File

@@ -5,6 +5,6 @@
namespace xrpl {
using KeyCache = TaggedCache<uint256, int, true>;
using KeyCache = TaggedCache<UInt256, int, true>;
} // namespace xrpl

View File

@@ -350,10 +350,10 @@ concept Integral64 = std::is_same_v<T, std::int64_t> || std::is_same_v<T, std::u
class Number final
{
using rep = std::int64_t;
using internalrep = MantissaRange::rep;
using InternalRep = MantissaRange::rep;
bool negative_{false};
internalrep mantissa_{0};
InternalRep mantissa_{0};
int exponent_{std::numeric_limits<int>::lowest()};
public:
@@ -361,10 +361,10 @@ public:
static constexpr int kMinExponent = -32768;
static constexpr int kMaxExponent = 32768;
static constexpr internalrep kMaxRep = std::numeric_limits<rep>::max();
static constexpr InternalRep kMaxRep = std::numeric_limits<rep>::max();
static_assert(kMaxRep == 9'223'372'036'854'775'807);
static_assert(-kMaxRep == std::numeric_limits<rep>::min() + 1);
static constexpr internalrep kMaxRepUp = ((kMaxRep / 10) + 1) * 10;
static constexpr InternalRep kMaxRepUp = ((kMaxRep / 10) + 1) * 10;
static_assert(kMaxRepUp == 9'223'372'036'854'775'810ULL);
// May need to make unchecked private
@@ -388,15 +388,15 @@ public:
explicit Number(rep mantissa, int exponent);
explicit constexpr Number(
bool negative,
internalrep mantissa,
InternalRep mantissa,
int exponent,
Unchecked) noexcept;
// Assume unsigned values are... unsigned. i.e. positive
explicit constexpr Number(internalrep mantissa, int exponent, Unchecked) noexcept;
explicit constexpr Number(InternalRep mantissa, int exponent, Unchecked) noexcept;
// Only unit tests are expected to use this ctor
explicit Number(bool negative, internalrep mantissa, int exponent, Normalized);
explicit Number(bool negative, InternalRep mantissa, int exponent, Normalized);
// Assume unsigned values are... unsigned. i.e. positive
explicit Number(internalrep mantissa, int exponent, Normalized);
explicit Number(InternalRep mantissa, int exponent, Normalized);
[[nodiscard]] constexpr rep
mantissa() const noexcept;
@@ -558,13 +558,13 @@ public:
static void
setMantissaScale(MantissaRange::MantissaScale scale);
static internalrep
static InternalRep
minMantissa()
{
return kRange.get().min;
}
static internalrep
static InternalRep
maxMantissa()
{
return kRange.get().max;
@@ -591,10 +591,64 @@ public:
// is negative, returns the positive value. This takes a little extra work
// because converting std::numeric_limits<std::int64_t>::min() flirts with
// UB, and can vary across compilers.
static internalrep
static InternalRep
externalToInternal(rep mantissa);
/**
* Normalize raw (mantissa, exponent) integers directly to a target range.
*
* This is the construction-time counterpart of the member overload above.
* Callers that hold raw integers (e.g. IOUAmount) and want them in a
* narrow range would otherwise build a Number (one normalize pass to the
* default kRange) and then call the member normalizeToRange (a second pass
* down to the narrow range). This overload does a single pass: it converts
* the signed mantissa to its internal magnitude and normalizes straight to
* [MinMantissa, MaxMantissa], building no intermediate Number.
*
* Data flow (single pass), contrasted with the old two-pass path:
*
* two-pass: (m,e) --build Number--> [kRange/Large] --member--> [Min,Max]
* one-pass: (m,e) -------------- normalize --------------> [Min,Max]
*
* @tparam MinMantissa Lower bound of the target mantissa range; must be a
* positive power of ten.
* @tparam MaxMantissa Upper bound; must equal MinMantissa * 10 - 1.
* @tparam T Result mantissa type, int64_t or uint64_t. Defaults
* to the type of MinMantissa.
* @param mantissa Raw signed mantissa (sign is extracted internally).
* @param exponent Raw exponent.
* @return The normalized (mantissa, exponent) pair in the target range.
* A zero mantissa returns {0, std::numeric_limits<int>::lowest()};
* the sign of a zero is not preserved.
* @note Thread-safety: reads the thread-local rounding mode only; holds no
* shared state of its own. Safe to call concurrently.
*
* Example (IOU range, 10^15 .. 10^16-1):
* @code
* auto [m, e] = Number::normalizeToRange<1'000'000'000'000'000,
* 9'999'999'999'999'999>(1, 0);
* // m == 1'000'000'000'000'000, e == -15
* @endcode
*/
template <
auto MinMantissa,
auto MaxMantissa,
Integral64 T = std::decay_t<decltype(MinMantissa)>>
[[nodiscard]]
static std::pair<T, int>
normalizeToRange(rep mantissa, int exponent);
private:
// Shared implementation for both normalizeToRange overloads. Takes the sign
// and internal (uint64) magnitude already separated, normalizes in place to
// [MinMantissa, MaxMantissa], and returns the signed (mantissa, exponent).
template <
auto MinMantissa,
auto MaxMantissa,
Integral64 T = std::decay_t<decltype(MinMantissa)>>
static std::pair<T, int>
normalizeToRangeImpl(bool negative, InternalRep mantissa, int exponent);
static thread_local RoundingMode mode;
// The available ranges for mantissa
@@ -625,8 +679,8 @@ private:
bool& negative,
T& mantissa,
int& exponent,
internalrep const& minMantissa,
internalrep const& maxMantissa,
InternalRep const& minMantissa,
InternalRep const& maxMantissa,
MantissaRange::CuspRoundingFix cuspRoundingFix);
template <class T>
@@ -650,25 +704,25 @@ private:
shiftExponent(int exponentDelta) const;
};
constexpr Number::Number(bool negative, internalrep mantissa, int exponent, Unchecked) noexcept
constexpr Number::Number(bool negative, InternalRep mantissa, int exponent, Unchecked) noexcept
: negative_(negative), mantissa_{mantissa}, exponent_{exponent}
{
}
constexpr Number::Number(internalrep mantissa, int exponent, Unchecked) noexcept
constexpr Number::Number(InternalRep mantissa, int exponent, Unchecked) noexcept
: Number(false, mantissa, exponent, Unchecked{})
{
}
static constexpr Number kNumZero{};
inline Number::Number(bool negative, internalrep mantissa, int exponent, Normalized)
inline Number::Number(bool negative, InternalRep mantissa, int exponent, Normalized)
: Number(negative, mantissa, exponent, Unchecked{})
{
normalize(kRange);
}
inline Number::Number(internalrep mantissa, int exponent, Normalized)
inline Number::Number(InternalRep mantissa, int exponent, Normalized)
: Number(false, mantissa, exponent, Normalized{})
{
}
@@ -839,7 +893,7 @@ Number::isnormal() const noexcept
template <auto MinMantissa, auto MaxMantissa, Integral64 T>
std::pair<T, int>
Number::normalizeToRange() const
Number::normalizeToRangeImpl(bool negative, InternalRep mantissa, int exponent)
{
static_assert(std::is_same_v<T, std::uint64_t> || std::is_same_v<T, std::int64_t>);
static_assert(std::is_same_v<T, std::decay_t<decltype(MinMantissa)>>);
@@ -852,10 +906,6 @@ Number::normalizeToRange() const
static_assert(kMAX % 10 == 9);
static_assert((kMAX + 1) / 10 == kMIN);
bool negative = negative_;
internalrep mantissa = mantissa_;
int exponent = exponent_;
if constexpr (std::is_unsigned_v<T>)
{
XRPL_ASSERT_PARTS(
@@ -872,6 +922,26 @@ Number::normalizeToRange() const
return std::make_pair(static_cast<T>(sign * mantissa), exponent);
}
template <auto MinMantissa, auto MaxMantissa, Integral64 T>
std::pair<T, int>
Number::normalizeToRange() const
{
// Forward this Number's already-separated internal components to the shared
// implementation. Passing mantissa_ (which may exceed kMaxRep in the Large
// range) through unchanged keeps the result byte-identical to before.
return normalizeToRangeImpl<MinMantissa, MaxMantissa, T>(negative_, mantissa_, exponent_);
}
template <auto MinMantissa, auto MaxMantissa, Integral64 T>
std::pair<T, int>
Number::normalizeToRange(rep mantissa, int exponent)
{
// Separate sign and magnitude from the raw signed mantissa, then normalize
// straight to the target range in a single pass (no intermediate Number).
return normalizeToRangeImpl<MinMantissa, MaxMantissa, T>(
mantissa < 0, externalToInternal(mantissa), exponent);
}
constexpr Number
abs(Number x) noexcept
{

View File

@@ -21,11 +21,11 @@ The module xrpl/basics should contain no dependencies on other modules.
- `std::set`
- For sorted containers.
- `xrpl::hash_set`
- `xrpl::HashSet`
- Where inserts and contains need to be O(1).
- For "small" sets, `std::set` might be faster and smaller.
- `xrpl::hardened_hash_set`
- `xrpl::HardenedHashSet`
- For data sets where the key could be manipulated by an attacker
in an attempt to mount an algorithmic complexity attack: see
http://en.wikipedia.org/wiki/Algorithmic_complexity_attack
@@ -33,5 +33,5 @@ The module xrpl/basics should contain no dependencies on other modules.
The following container is deprecated
- `std::unordered_set`
- Use `xrpl::hash_set` instead, which uses a better hashing algorithm.
- Or use `xrpl::hardened_hash_set` to prevent algorithmic complexity attacks.
- Use `xrpl::HashSet` instead, which uses a better hashing algorithm.
- Or use `xrpl::HardenedHashSet` to prevent algorithmic complexity attacks.

View File

@@ -14,20 +14,20 @@ namespace xrpl {
class SHAMapHash
{
uint256 hash_;
UInt256 hash_;
public:
SHAMapHash() = default;
explicit SHAMapHash(uint256 const& hash) : hash_(hash)
explicit SHAMapHash(UInt256 const& hash) : hash_(hash)
{
}
[[nodiscard]] uint256 const&
[[nodiscard]] UInt256 const&
asUInt256() const
{
return hash_;
}
uint256&
UInt256&
asUInt256()
{
return hash_;

View File

@@ -162,4 +162,89 @@ toUInt64(std::string const& s);
bool
isProperlyFormedTomlDomain(std::string_view domain);
/**
* Whether a view can be passed on as a C string.
*
* A reader given only data() stops at the first null, so the view must reach the
* terminating null. The test rebuilds the view from data() and compares: a view
* that stops earlier rebuilds longer, and so compares unequal.
*
* consteval because reading the byte after the view is only defined when @p str
* points into storage holding a null at or after its end, such as a string
* literal. An unterminated view is then a compile error, not an out-of-bounds
* read.
*
* @param str The view to test.
* @return Whether @p str is null-terminated. A view with no data is not.
*/
consteval bool
isNullTerminated(std::string_view str)
{
if (str.data() == nullptr)
return false;
// Reading past the view is the point, so the usual data() warning does not
// apply.
// NOLINTNEXTLINE(bugprone-suspicious-stringview-data-usage)
return std::string_view{str.data()} == str;
}
/**
* A string that is known to reach its terminating null.
*
* Converts to std::string_view, so it compares and hashes as one. Unlike a
* view, asCString() may be handed to a reader that expects a C string, such
* as json::StaticString.
*
* The only constructor is consteval and rejects a view that stops before the
* null, so the property holds by construction and no caller asserts it.
*/
class NullTerminatedView
{
public:
/**
* Build a view from one that reaches its terminating null.
*
* Explicit, so that a plain view cannot become a proof of termination by
* accident. The conversion the other way stays implicit.
*
* @param view The string to hold. Rejected at compile time if it stops
* before its terminating null, or has no data.
*/
explicit consteval NullTerminatedView(std::string_view view)
: data_(view.data()), size_(view.size())
{
if (!isNullTerminated(view))
throw "xrpl::NullTerminatedView : view does not reach a null";
}
constexpr
operator std::string_view() const noexcept
{
return view();
}
/**
* @return The string as a view.
*/
[[nodiscard]] constexpr std::string_view
view() const noexcept
{
return {data_, size_};
}
/**
* @return The string as a C string. Never null.
*/
[[nodiscard]] constexpr char const*
asCString() const noexcept
{
return data_;
}
private:
char const* data_;
std::size_t size_;
};
} // namespace xrpl

View File

@@ -59,34 +59,34 @@ template <
class T,
bool IsKeyCache = false,
class SharedWeakUnionPointerType = SharedWeakCachePointer<T>,
class SharedPointerType = std::shared_ptr<T>,
class SharedPointer = std::shared_ptr<T>,
class Hash = HardenedHash<>,
class KeyEqual = std::equal_to<Key>,
class Mutex = std::recursive_mutex>
class TaggedCache
{
public:
using mutex_type = Mutex;
using MutexType = Mutex;
using key_type = Key;
using mapped_type = T;
using clock_type = beast::AbstractClock<std::chrono::steady_clock>;
using shared_weak_combo_pointer_type = SharedWeakUnionPointerType;
using shared_pointer_type = SharedPointerType;
using ClockType = beast::AbstractClock<std::chrono::steady_clock>;
using SharedWeakComboPointerType = SharedWeakUnionPointerType;
using SharedPointerType = SharedPointer;
public:
TaggedCache(
std::string const& name,
int size,
clock_type::duration expiration,
clock_type& clock,
ClockType::duration expiration,
ClockType& clock,
beast::Journal journal,
beast::insight::Collector::ptr const& collector = beast::insight::NullCollector::make());
beast::insight::Collector::Ptr const& collector = beast::insight::NullCollector::make());
public:
/**
* Return the clock associated with the cache.
*/
clock_type&
ClockType&
clock();
/**
@@ -239,7 +239,7 @@ public:
bool
retrieve(key_type const& key, T& data);
mutex_type&
MutexType&
peekMutex();
std::vector<key_type>
@@ -265,7 +265,7 @@ public:
private:
SharedPointerType
initialFetch(key_type const& key, std::scoped_lock<mutex_type> const& l);
initialFetch(key_type const& key, std::scoped_lock<MutexType> const& l);
void
collectMetrics();
@@ -277,7 +277,7 @@ private:
Stats(
std::string const& prefix,
Handler const& handler,
beast::insight::Collector::ptr const& collector)
beast::insight::Collector::Ptr const& collector)
: hook(collector->makeHook(handler))
, size(collector->makeGauge(prefix, "size"))
, hitRate(collector->makeGauge(prefix, "hit_rate"))
@@ -296,14 +296,14 @@ private:
class KeyOnlyEntry
{
public:
clock_type::time_point lastAccess;
ClockType::time_point lastAccess;
explicit KeyOnlyEntry(clock_type::time_point const& lastAccess) : lastAccess(lastAccess)
explicit KeyOnlyEntry(ClockType::time_point const& lastAccess) : lastAccess(lastAccess)
{
}
void
touch(clock_type::time_point const& now)
touch(ClockType::time_point const& now)
{
lastAccess = now;
}
@@ -312,10 +312,10 @@ private:
class ValueEntry
{
public:
shared_weak_combo_pointer_type ptr;
clock_type::time_point lastAccess;
SharedWeakComboPointerType ptr;
ClockType::time_point lastAccess;
ValueEntry(clock_type::time_point const& lastAccess, shared_pointer_type const& ptr)
ValueEntry(ClockType::time_point const& lastAccess, SharedPointerType const& ptr)
: ptr(ptr), lastAccess(lastAccess)
{
}
@@ -343,7 +343,7 @@ private:
return ptr.lock();
}
void
touch(clock_type::time_point const& now)
touch(ClockType::time_point const& now)
{
lastAccess = now;
}
@@ -351,35 +351,35 @@ private:
using Entry = std::conditional_t<IsKeyCache, KeyOnlyEntry, ValueEntry>;
using KeyOnlyCacheType = hardened_partitioned_hash_map<key_type, KeyOnlyEntry, Hash, KeyEqual>;
using KeyOnlyCacheType = HardenedPartitionedHashMap<key_type, KeyOnlyEntry, Hash, KeyEqual>;
using KeyValueCacheType = hardened_partitioned_hash_map<key_type, ValueEntry, Hash, KeyEqual>;
using KeyValueCacheType = HardenedPartitionedHashMap<key_type, ValueEntry, Hash, KeyEqual>;
using cache_type = hardened_partitioned_hash_map<key_type, Entry, Hash, KeyEqual>;
using CacheType = HardenedPartitionedHashMap<key_type, Entry, Hash, KeyEqual>;
[[nodiscard]] std::thread
sweepHelper(
clock_type::time_point const& whenExpire,
[[maybe_unused]] clock_type::time_point const& now,
KeyValueCacheType::map_type& partition,
ClockType::time_point const& whenExpire,
[[maybe_unused]] ClockType::time_point const& now,
KeyValueCacheType::MapType& partition,
SweptPointersVector& stuffToSweep,
std::atomic<int>& allRemovals,
std::scoped_lock<std::recursive_mutex> const&);
[[nodiscard]] std::thread
sweepHelper(
clock_type::time_point const& whenExpire,
clock_type::time_point const& now,
KeyOnlyCacheType::map_type& partition,
ClockType::time_point const& whenExpire,
ClockType::time_point const& now,
KeyOnlyCacheType::MapType& partition,
SweptPointersVector&,
std::atomic<int>& allRemovals,
std::scoped_lock<std::recursive_mutex> const&);
beast::Journal journal_;
clock_type& clock_;
ClockType& clock_;
Stats stats_;
mutex_type mutable mutex_;
MutexType mutable mutex_;
// Used for logging
std::string name_;
@@ -388,11 +388,11 @@ private:
int const targetSize_;
// Desired maximum cache age
clock_type::duration const targetAge_;
ClockType::duration const targetAge_;
// Number of items cached
int cacheCount_{0};
cache_type cache_; // Hold strong reference to recent objects
CacheType cache_; // Hold strong reference to recent objects
std::uint64_t hits_{0};
std::uint64_t misses_{0};
};

View File

@@ -54,10 +54,10 @@ inline TaggedCache<
TaggedCache(
std::string const& name,
int size,
clock_type::duration expiration,
clock_type& clock,
ClockType::duration expiration,
ClockType& clock,
beast::Journal journal,
beast::insight::Collector::ptr const& collector)
beast::insight::Collector::Ptr const& collector)
: journal_(journal)
, clock_(clock)
, stats_(
@@ -81,7 +81,7 @@ template <
class Mutex>
inline auto
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::
clock() -> clock_type&
clock() -> ClockType&
{
return clock_;
}
@@ -237,8 +237,8 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
// is destroyed but still within the main cache lock.
std::vector<SweptPointersVector> allStuffToSweep(cache_.partitions());
clock_type::time_point const now(clock_.now());
clock_type::time_point whenExpire;
ClockType::time_point const now(clock_.now());
ClockType::time_point whenExpire;
auto const start = std::chrono::steady_clock::now();
{
@@ -252,7 +252,7 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
{
whenExpire = now - (targetAge_ * targetSize_ / cache_.size());
clock_type::duration const minimumAge(std::chrono::seconds(1));
ClockType::duration const minimumAge(std::chrono::seconds(1));
if (whenExpire > (now - minimumAge))
whenExpire = now - minimumAge;
@@ -487,7 +487,7 @@ inline SharedPointerType
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::
fetch(key_type const& key)
{
std::scoped_lock<mutex_type> const l(mutex_);
std::scoped_lock<MutexType> const l(mutex_);
auto ret = initialFetch(key, l);
if (!ret)
++misses_;
@@ -541,7 +541,7 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
requires IsKeyCache
{
std::scoped_lock const lock(mutex_);
clock_type::time_point const now(clock_.now());
ClockType::time_point const now(clock_.now());
auto [it, inserted] = cache_.emplace(
std::piecewise_construct, std::forward_as_tuple(key), std::forward_as_tuple(now));
if (!inserted)
@@ -583,7 +583,7 @@ template <
class Mutex>
inline auto
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::
peekMutex() -> mutex_type&
peekMutex() -> MutexType&
{
return mutex_;
}
@@ -711,7 +711,7 @@ template <
class Mutex>
inline SharedPointerType
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::
initialFetch(key_type const& key, std::scoped_lock<mutex_type> const& l)
initialFetch(key_type const& key, std::scoped_lock<MutexType> const& l)
{
auto cit = cache_.find(key);
if (cit == cache_.end())
@@ -776,9 +776,9 @@ template <
inline std::thread
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::
sweepHelper(
clock_type::time_point const& whenExpire,
[[maybe_unused]] clock_type::time_point const& now,
KeyValueCacheType::map_type& partition,
ClockType::time_point const& whenExpire,
[[maybe_unused]] ClockType::time_point const& now,
KeyValueCacheType::MapType& partition,
SweptPointersVector& stuffToSweep,
std::atomic<int>& allRemovals,
std::scoped_lock<std::recursive_mutex> const&)
@@ -856,9 +856,9 @@ template <
inline std::thread
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::
sweepHelper(
clock_type::time_point const& whenExpire,
clock_type::time_point const& now,
KeyOnlyCacheType::map_type& partition,
ClockType::time_point const& whenExpire,
ClockType::time_point const& now,
KeyOnlyCacheType::MapType& partition,
SweptPointersVector&,
std::atomic<int>& allRemovals,
std::scoped_lock<std::recursive_mutex> const&)

View File

@@ -33,7 +33,7 @@ template <
class Hash = beast::Uhash<>,
class Pred = std::equal_to<Key>,
class Allocator = std::allocator<std::pair<Key const, Value>>>
using hash_map = std::unordered_map<Key, Value, Hash, Pred, Allocator>;
using HashMap = std::unordered_map<Key, Value, Hash, Pred, Allocator>;
template <
class Key,
@@ -41,62 +41,62 @@ template <
class Hash = beast::Uhash<>,
class Pred = std::equal_to<Key>,
class Allocator = std::allocator<std::pair<Key const, Value>>>
using hash_multimap = std::unordered_multimap<Key, Value, Hash, Pred, Allocator>;
using HashMultimap = std::unordered_multimap<Key, Value, Hash, Pred, Allocator>;
template <
class Value,
class Hash = beast::Uhash<>,
class Pred = std::equal_to<Value>,
class Allocator = std::allocator<Value>>
using hash_set = std::unordered_set<Value, Hash, Pred, Allocator>;
using HashSet = std::unordered_set<Value, Hash, Pred, Allocator>;
template <
class Value,
class Hash = beast::Uhash<>,
class Pred = std::equal_to<Value>,
class Allocator = std::allocator<Value>>
using hash_multiset = std::unordered_multiset<Value, Hash, Pred, Allocator>;
using HashMultiset = std::unordered_multiset<Value, Hash, Pred, Allocator>;
// hardened_hash containers
using strong_hash = beast::Xxhasher;
using StrongHash = beast::Xxhasher;
template <
class Key,
class Value,
class Hash = HardenedHash<strong_hash>,
class Hash = HardenedHash<StrongHash>,
class Pred = std::equal_to<Key>,
class Allocator = std::allocator<std::pair<Key const, Value>>>
using hardened_hash_map = std::unordered_map<Key, Value, Hash, Pred, Allocator>;
using HardenedHashMap = std::unordered_map<Key, Value, Hash, Pred, Allocator>;
template <
class Key,
class Value,
class Hash = HardenedHash<strong_hash>,
class Hash = HardenedHash<StrongHash>,
class Pred = std::equal_to<Key>,
class Allocator = std::allocator<std::pair<Key const, Value>>>
using hardened_partitioned_hash_map = PartitionedUnorderedMap<Key, Value, Hash, Pred, Allocator>;
using HardenedPartitionedHashMap = PartitionedUnorderedMap<Key, Value, Hash, Pred, Allocator>;
template <
class Key,
class Value,
class Hash = HardenedHash<strong_hash>,
class Hash = HardenedHash<StrongHash>,
class Pred = std::equal_to<Key>,
class Allocator = std::allocator<std::pair<Key const, Value>>>
using hardened_hash_multimap = std::unordered_multimap<Key, Value, Hash, Pred, Allocator>;
using HardenedHashMultimap = std::unordered_multimap<Key, Value, Hash, Pred, Allocator>;
template <
class Value,
class Hash = HardenedHash<strong_hash>,
class Hash = HardenedHash<StrongHash>,
class Pred = std::equal_to<Value>,
class Allocator = std::allocator<Value>>
using hardened_hash_set = std::unordered_set<Value, Hash, Pred, Allocator>;
using HardenedHashSet = std::unordered_set<Value, Hash, Pred, Allocator>;
template <
class Value,
class Hash = HardenedHash<strong_hash>,
class Hash = HardenedHash<StrongHash>,
class Pred = std::equal_to<Value>,
class Allocator = std::allocator<Value>>
using hardened_hash_multiset = std::unordered_multiset<Value, Hash, Pred, Allocator>;
using HardenedHashMultiset = std::unordered_multiset<Value, Hash, Pred, Allocator>;
} // namespace xrpl

View File

@@ -111,7 +111,7 @@ public:
using const_iterator = const_pointer;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
using tag_type = Tag;
using TagType = Tag;
pointer
data()
@@ -518,7 +518,7 @@ public:
* The input must be precisely `2 * bytes` hexadecimal characters
* long, with one exception: the value '0'.
*
* @param sv A null-terminated string of hexadecimal characters
* @param sv A string of hexadecimal characters
* @return true if the input was parsed properly; false otherwise.
*/
[[nodiscard]] constexpr bool
@@ -575,10 +575,16 @@ public:
}
};
using uint128 = BaseUInt<128>;
using uint160 = BaseUInt<160>;
using uint256 = BaseUInt<256>;
using uint192 = BaseUInt<192>;
using UInt128 = BaseUInt<128>;
using UInt160 = BaseUInt<160>;
using UInt256 = BaseUInt<256>;
using UInt192 = BaseUInt<192>;
// TODO [#8340]: Legacy names still used by external consumers of libxrpl (e.g. rpc-spec).
// Do not use in new code; remove once those consumers have migrated.
using uint160 = UInt160; // NOLINT(readability-identifier-naming)
using uint256 = UInt256; // NOLINT(readability-identifier-naming)
using uint192 = UInt192; // NOLINT(readability-identifier-naming)
template <std::size_t Bits, class Tag>
[[nodiscard]] constexpr std::strong_ordering
@@ -670,7 +676,7 @@ operator<<(std::ostream& out, BaseUInt<Bits, Tag> const& u)
template <>
inline std::size_t
extract(uint256 const& key)
extract(UInt256 const& key)
{
std::size_t result = 0;
// Use memcpy to avoid unaligned UB
@@ -680,10 +686,10 @@ extract(uint256 const& key)
}
#ifndef __INTELLISENSE__
static_assert(sizeof(uint128) == 128 / 8, "There should be no padding bytes");
static_assert(sizeof(uint160) == 160 / 8, "There should be no padding bytes");
static_assert(sizeof(uint192) == 192 / 8, "There should be no padding bytes");
static_assert(sizeof(uint256) == 256 / 8, "There should be no padding bytes");
static_assert(sizeof(UInt128) == 128 / 8, "There should be no padding bytes");
static_assert(sizeof(UInt160) == 160 / 8, "There should be no padding bytes");
static_assert(sizeof(UInt192) == 192 / 8, "There should be no padding bytes");
static_assert(sizeof(UInt256) == 256 / 8, "There should be no padding bytes");
#endif
} // namespace xrpl

View File

@@ -16,10 +16,10 @@ namespace xrpl {
// A few handy aliases
using days =
using Days =
std::chrono::duration<int, std::ratio_multiply<std::chrono::hours::period, std::ratio<24>>>;
using weeks = std::chrono::duration<int, std::ratio_multiply<days::period, std::ratio<7>>>;
using Weeks = std::chrono::duration<int, std::ratio_multiply<Days::period, std::ratio<7>>>;
/**
* Clock for measuring the network time.

View File

@@ -11,10 +11,10 @@ namespace xrpl {
namespace detail {
using seed_pair = std::pair<std::uint64_t, std::uint64_t>;
using SeedPair = std::pair<std::uint64_t, std::uint64_t>;
template <bool = true>
seed_pair
SeedPair
makeSeedPair() noexcept
{
struct StateT
@@ -71,7 +71,7 @@ template <class HashAlgorithm = beast::Xxhasher>
class HardenedHash
{
private:
detail::seed_pair seeds_{detail::makeSeedPair<>()};
detail::SeedPair seeds_{detail::makeSeedPair<>()};
public:
using result_type = HashAlgorithm::result_type;

View File

@@ -53,19 +53,19 @@ public:
using const_reference = value_type const&;
using pointer = value_type*;
using const_pointer = value_type const*;
using map_type = std::unordered_map<key_type, mapped_type, hasher, key_equal, allocator_type>;
using partition_map_type = std::vector<map_type>;
using MapType = std::unordered_map<key_type, mapped_type, hasher, key_equal, allocator_type>;
using PartitionMapType = std::vector<MapType>;
struct Iterator
{
using iterator_category = std::forward_iterator_tag;
partition_map_type* map{nullptr};
partition_map_type::iterator ait{};
map_type::iterator mit;
PartitionMapType* map{nullptr};
PartitionMapType::iterator ait{};
MapType::iterator mit;
Iterator() = default;
Iterator(partition_map_type* m) : map(m)
Iterator(PartitionMapType* m) : map(m)
{
}
@@ -122,13 +122,13 @@ public:
{
using iterator_category = std::forward_iterator_tag;
partition_map_type* map{nullptr};
partition_map_type::iterator ait{};
map_type::iterator mit;
PartitionMapType* map{nullptr};
PartitionMapType::iterator ait{};
MapType::iterator mit;
ConstIterator() = default;
ConstIterator(partition_map_type* m) : map(m)
ConstIterator(PartitionMapType* m) : map(m)
{
}
@@ -234,7 +234,7 @@ public:
return partitions_;
}
partition_map_type&
PartitionMapType&
map()
{
return map_;
@@ -377,7 +377,7 @@ public:
}
private:
mutable partition_map_type map_{};
mutable PartitionMapType map_{};
};
} // namespace xrpl

View File

@@ -14,13 +14,13 @@ namespace xrpl {
#ifndef __INTELLISENSE__
static_assert(
// NOLINTNEXTLINE(misc-redundant-expression)
std::is_integral_v<beast::xor_shift_engine::result_type> &&
std::is_unsigned_v<beast::xor_shift_engine::result_type>,
std::is_integral_v<beast::XorShiftEngine::result_type> &&
std::is_unsigned_v<beast::XorShiftEngine::result_type>,
"The XRPL default PRNG engine must return an unsigned integral type.");
static_assert(
// NOLINTNEXTLINE(misc-redundant-expression)
std::numeric_limits<beast::xor_shift_engine::result_type>::max() >=
std::numeric_limits<beast::XorShiftEngine::result_type>::max() >=
std::numeric_limits<std::uint64_t>::max(),
"The XRPL default PRNG engine return must be at least 64 bits wide.");
#endif
@@ -30,7 +30,7 @@ namespace detail {
// Determines if a type can be called like an Engine
// NOLINTNEXTLINE(readability-redundant-typename): typename required by MSVC
template <class Engine, class Result = typename Engine::result_type>
using is_engine = std::is_invocable_r<Result, Engine>;
using IsEngine = std::is_invocable_r<Result, Engine>;
} // namespace detail
/**
@@ -44,28 +44,28 @@ using is_engine = std::is_invocable_r<Result, Engine>;
* Each thread gets its own instance of the engine which
* will be randomly seeded.
*/
inline beast::xor_shift_engine&
inline beast::XorShiftEngine&
defaultPrng()
{
// This is used to seed the thread-specific PRNGs on demand
static beast::xor_shift_engine kSeeder = [] {
static beast::XorShiftEngine kSeeder = [] {
std::random_device rng;
std::uniform_int_distribution<std::uint64_t> distribution{1};
return beast::xor_shift_engine(distribution(rng));
return beast::XorShiftEngine(distribution(rng));
}();
// This protects the seeder
static std::mutex kM;
// The thread-specific PRNGs:
thread_local beast::xor_shift_engine kEngine = [] {
thread_local beast::XorShiftEngine kEngine = [] {
std::uint64_t seed = 0;
{
std::scoped_lock const lk(kM);
std::uniform_int_distribution<std::uint64_t> distribution{1};
seed = distribution(kSeeder);
}
return beast::xor_shift_engine{seed};
return beast::XorShiftEngine{seed};
}();
return kEngine;
@@ -95,7 +95,7 @@ defaultPrng()
template <class Engine, class Integral>
Integral
randInt(Engine& engine, Integral min, Integral max)
requires(std::is_integral_v<Integral> && detail::is_engine<Engine>::value)
requires(std::is_integral_v<Integral> && detail::IsEngine<Engine>::value)
{
XRPL_ASSERT(max > min, "xrpl::randInt : max over min inputs");
@@ -116,7 +116,7 @@ randInt(Integral min, Integral max)
template <class Engine, class Integral>
Integral
randInt(Engine& engine, Integral max)
requires(std::is_integral_v<Integral> && detail::is_engine<Engine>::value)
requires(std::is_integral_v<Integral> && detail::IsEngine<Engine>::value)
{
return randInt(engine, Integral(0), max);
}
@@ -132,7 +132,7 @@ randInt(Integral max)
template <class Integral, class Engine>
Integral
randInt(Engine& engine)
requires(std::is_integral_v<Integral> && detail::is_engine<Engine>::value)
requires(std::is_integral_v<Integral> && detail::IsEngine<Engine>::value)
{
return randInt(engine, std::numeric_limits<Integral>::max());
}
@@ -155,7 +155,7 @@ Byte
randByte(Engine& engine)
requires(
(std::is_same_v<Byte, unsigned char> || std::is_same_v<Byte, std::uint8_t>) &&
detail::is_engine<Engine>::value)
detail::IsEngine<Engine>::value)
{
return static_cast<Byte>(randInt<Engine, std::uint32_t>(
engine, std::numeric_limits<Byte>::min(), std::numeric_limits<Byte>::max()));

View File

@@ -40,7 +40,7 @@ private:
public:
using value_type = Int;
using tag_type = Tag;
using TagType = Tag;
TaggedInteger() = default;

View File

@@ -0,0 +1,10 @@
# beast's containers, clocks and Journal streambuf model std concepts, which mandate
# snake_case member type names.
#
# clang-tidy replaces rather than merges this option, so the list is the
# top-level one restated plus the 20 name(s) needed only here:
# allocator_type argument_type char_type const_local_iterator const_pointer const_reverse_iterator first_argument_type hasher int_type key_compare key_equal local_iterator native_handle_type off_type pos_type reverse_iterator second_argument_type traits_type type value_compare
InheritParentConfig: true
CheckOptions:
readability-identifier-naming.TypeAliasIgnoredRegexp: "^(allocator_type|argument_type|char_type|const_iterator|const_local_iterator|const_pointer|const_reference|const_reverse_iterator|difference_type|duration|first_argument_type|hasher|int_type|iterator|iterator_category|key_compare|key_equal|key_type|local_iterator|mapped_type|native_handle_type|off_type|period|pointer|pos_type|reference|rep|result_type|reverse_iterator|second_argument_type|size_type|time_point|traits_type|type|value_compare|value_type)$"
readability-identifier-naming.TypedefIgnoredRegexp: "^(allocator_type|argument_type|char_type|const_iterator|const_local_iterator|const_pointer|const_reference|const_reverse_iterator|difference_type|duration|first_argument_type|hasher|int_type|iterator|iterator_category|key_compare|key_equal|key_type|local_iterator|mapped_type|native_handle_type|off_type|period|pointer|pos_type|reference|rep|result_type|reverse_iterator|second_argument_type|size_type|time_point|traits_type|type|value_compare|value_type)$"

View File

@@ -9,7 +9,7 @@ namespace beast {
* an instance of the class can be dependency injected, facilitating
* unit tests where time may be controlled.
*
* An abstract_clock inherits all the nested types of the Clock
* An AbstractClock inherits all the nested types of the Clock
* template parameter.
*
* Example:
@@ -18,9 +18,9 @@ namespace beast {
*
* struct Implementation
* {
* using clock_type = abstract_clock <std::chrono::steady_clock>;
* clock_type& clock_;
* explicit Implementation (clock_type& clock)
* using ClockType = AbstractClock<std::chrono::steady_clock>;
* ClockType& clock_;
* explicit Implementation(ClockType& clock)
* : clock_(clock)
* {
* }
@@ -39,7 +39,7 @@ public:
using period = Clock::period;
using duration = Clock::duration;
using time_point = Clock::time_point;
using clock_type = Clock;
using ClockType = Clock;
static bool const is_steady = Clock::is_steady; // NOLINT(readability-identifier-naming)

View File

@@ -15,6 +15,6 @@ template <
class Clock = std::chrono::steady_clock,
class Compare = std::less<Key>,
class Allocator = std::allocator<std::pair<Key const, T>>>
using aged_map = detail::AgedOrderedContainer<false, true, Key, T, Clock, Compare, Allocator>;
using AgedMap = detail::AgedOrderedContainer<false, true, Key, T, Clock, Compare, Allocator>;
} // namespace beast

View File

@@ -15,6 +15,6 @@ template <
class Clock = std::chrono::steady_clock,
class Compare = std::less<Key>,
class Allocator = std::allocator<std::pair<Key const, T>>>
using aged_multimap = detail::AgedOrderedContainer<true, true, Key, T, Clock, Compare, Allocator>;
using AgedMultimap = detail::AgedOrderedContainer<true, true, Key, T, Clock, Compare, Allocator>;
} // namespace beast

View File

@@ -13,7 +13,7 @@ template <
class Clock = std::chrono::steady_clock,
class Compare = std::less<Key>,
class Allocator = std::allocator<Key>>
using aged_multiset =
using AgedMultiset =
detail::AgedOrderedContainer<true, false, Key, void, Clock, Compare, Allocator>;
} // namespace beast

View File

@@ -13,6 +13,6 @@ template <
class Clock = std::chrono::steady_clock,
class Compare = std::less<Key>,
class Allocator = std::allocator<Key>>
using aged_set = detail::AgedOrderedContainer<false, false, Key, void, Clock, Compare, Allocator>;
using AgedSet = detail::AgedOrderedContainer<false, false, Key, void, Clock, Compare, Allocator>;
} // namespace beast

View File

@@ -16,7 +16,7 @@ template <
class Hash = std::hash<Key>,
class KeyEqual = std::equal_to<Key>,
class Allocator = std::allocator<std::pair<Key const, T>>>
using aged_unordered_map =
using AgedUnorderedMap =
detail::AgedUnorderedContainer<false, true, Key, T, Clock, Hash, KeyEqual, Allocator>;
} // namespace beast

View File

@@ -16,7 +16,7 @@ template <
class Hash = std::hash<Key>,
class KeyEqual = std::equal_to<Key>,
class Allocator = std::allocator<std::pair<Key const, T>>>
using aged_unordered_multimap =
using AgedUnorderedMultimap =
detail::AgedUnorderedContainer<true, true, Key, T, Clock, Hash, KeyEqual, Allocator>;
} // namespace beast

View File

@@ -14,7 +14,7 @@ template <
class Hash = std::hash<Key>,
class KeyEqual = std::equal_to<Key>,
class Allocator = std::allocator<Key>>
using aged_unordered_multiset =
using AgedUnorderedMultiset =
detail::AgedUnorderedContainer<true, false, Key, void, Clock, Hash, KeyEqual, Allocator>;
} // namespace beast

View File

@@ -14,7 +14,7 @@ template <
class Hash = std::hash<Key>,
class KeyEqual = std::equal_to<Key>,
class Allocator = std::allocator<Key>>
using aged_unordered_set =
using AgedUnorderedSet =
detail::AgedUnorderedContainer<false, false, Key, void, Clock, Hash, KeyEqual, Allocator>;
} // namespace beast

View File

@@ -4,12 +4,7 @@
#include <type_traits>
#include <utility>
namespace beast {
template <bool, bool, class, class, class, class, class>
class aged_ordered_container;
namespace detail {
namespace beast::detail {
// If Iterator is SCARY then this iterator will be as well.
template <bool IsConst, class Iterator>
@@ -144,6 +139,4 @@ private:
Iterator iter_;
};
} // namespace detail
} // namespace beast
} // namespace beast::detail

View File

@@ -54,7 +54,7 @@ struct IsBoostReverseIterator<boost::intrusive::reverse_iterator<It>> : std::tru
* whose items expire after a certain amount of time. The chronological
* iterators allow for fully customizable expiration strategies.
*
* @see aged_set, aged_multiset, aged_map, aged_multimap
* @see AgedSet, AgedMultiset, AgedMap, AgedMultimap
*/
template <
bool IsMulti,
@@ -67,9 +67,9 @@ template <
class AgedOrderedContainer
{
public:
using clock_type = AbstractClock<Clock>;
using time_point = clock_type::time_point;
using duration = clock_type::duration;
using ClockType = AbstractClock<Clock>;
using time_point = ClockType::time_point;
using duration = ClockType::duration;
using key_type = Key;
using mapped_type = T;
using value_type = std::conditional_t<IsMap, std::pair<Key const, T>, Key>;
@@ -77,9 +77,9 @@ public:
using difference_type = std::ptrdiff_t;
// Introspection (for unit tests)
using is_unordered = std::false_type;
using is_multi = std::integral_constant<bool, IsMulti>;
using is_map = std::integral_constant<bool, IsMap>;
using IsUnorderedType = std::false_type;
using IsMultiType = std::integral_constant<bool, IsMulti>;
using IsMapType = std::integral_constant<bool, IsMap>;
private:
static Key const&
@@ -127,8 +127,8 @@ private:
class PairValueCompare : public Compare
{
public:
using first_argument = value_type;
using second_argument = value_type;
using FirstArgument = value_type;
using SecondArgument = value_type;
using result_type = bool;
bool
@@ -156,8 +156,8 @@ private:
class KeyValueCompare : public Compare
{
public:
using first_argument = Key;
using second_argument = Element;
using FirstArgument = Key;
using SecondArgument = Element;
using result_type = bool;
KeyValueCompare() = default;
@@ -197,10 +197,10 @@ private:
}
};
using list_type =
using ListType =
boost::intrusive::make_list<Element, boost::intrusive::constant_time_size<false>>::type;
using cont_type = std::conditional_t<
using ContType = std::conditional_t<
IsMulti,
typename boost::intrusive::make_multiset<
Element,
@@ -219,20 +219,20 @@ private:
public beast::detail::EmptyBaseOptimization<ElementAllocator>
{
public:
explicit ConfigT(clock_type& clock) : clock(clock)
explicit ConfigT(ClockType& clock) : clock(clock)
{
}
ConfigT(clock_type& clock, Compare const& comp) : KeyValueCompare(comp), clock(clock)
ConfigT(ClockType& clock, Compare const& comp) : KeyValueCompare(comp), clock(clock)
{
}
ConfigT(clock_type& clock, Allocator const& alloc)
ConfigT(ClockType& clock, Allocator const& alloc)
: beast::detail::EmptyBaseOptimization<ElementAllocator>(alloc), clock(clock)
{
}
ConfigT(clock_type& clock, Compare const& comp, Allocator const& alloc)
ConfigT(ClockType& clock, Compare const& comp, Allocator const& alloc)
: KeyValueCompare(comp)
, beast::detail::EmptyBaseOptimization<ElementAllocator>(alloc)
, clock(clock)
@@ -328,7 +328,7 @@ private:
return beast::detail::EmptyBaseOptimization<ElementAllocator>::member();
}
std::reference_wrapper<clock_type> clock;
std::reference_wrapper<ClockType> clock;
};
template <class... Args>
@@ -383,12 +383,12 @@ public:
// A set iterator (IsMap==false) is always const
// because the elements of a set are immutable.
using iterator = beast::detail::AgedContainerIterator<!IsMap, typename cont_type::iterator>;
using const_iterator = beast::detail::AgedContainerIterator<true, typename cont_type::iterator>;
using iterator = beast::detail::AgedContainerIterator<!IsMap, typename ContType::iterator>;
using const_iterator = beast::detail::AgedContainerIterator<true, typename ContType::iterator>;
using reverse_iterator =
beast::detail::AgedContainerIterator<!IsMap, typename cont_type::reverse_iterator>;
beast::detail::AgedContainerIterator<!IsMap, typename ContType::reverse_iterator>;
using const_reverse_iterator =
beast::detail::AgedContainerIterator<true, typename cont_type::reverse_iterator>;
beast::detail::AgedContainerIterator<true, typename ContType::reverse_iterator>;
//--------------------------------------------------------------------------
//
@@ -406,13 +406,13 @@ public:
public:
// A set iterator (IsMap==false) is always const
// because the elements of a set are immutable.
using iterator = beast::detail::AgedContainerIterator<!IsMap, typename list_type::iterator>;
using iterator = beast::detail::AgedContainerIterator<!IsMap, typename ListType::iterator>;
using const_iterator =
beast::detail::AgedContainerIterator<true, typename list_type::iterator>;
beast::detail::AgedContainerIterator<true, typename ListType::iterator>;
using reverse_iterator =
beast::detail::AgedContainerIterator<!IsMap, typename list_type::reverse_iterator>;
beast::detail::AgedContainerIterator<!IsMap, typename ListType::reverse_iterator>;
using const_reverse_iterator =
beast::detail::AgedContainerIterator<true, typename list_type::reverse_iterator>;
beast::detail::AgedContainerIterator<true, typename ListType::reverse_iterator>;
iterator
begin()
@@ -509,7 +509,7 @@ public:
private:
friend class AgedOrderedContainer;
list_type mutable list_;
ListType mutable list_;
} chronological;
//--------------------------------------------------------------------------
@@ -520,28 +520,28 @@ public:
AgedOrderedContainer() = delete;
explicit AgedOrderedContainer(clock_type& clock);
explicit AgedOrderedContainer(ClockType& clock);
AgedOrderedContainer(clock_type& clock, Compare const& comp);
AgedOrderedContainer(ClockType& clock, Compare const& comp);
AgedOrderedContainer(clock_type& clock, Allocator const& alloc);
AgedOrderedContainer(ClockType& clock, Allocator const& alloc);
AgedOrderedContainer(clock_type& clock, Compare const& comp, Allocator const& alloc);
AgedOrderedContainer(ClockType& clock, Compare const& comp, Allocator const& alloc);
template <class InputIt>
AgedOrderedContainer(InputIt first, InputIt last, clock_type& clock);
AgedOrderedContainer(InputIt first, InputIt last, ClockType& clock);
template <class InputIt>
AgedOrderedContainer(InputIt first, InputIt last, clock_type& clock, Compare const& comp);
AgedOrderedContainer(InputIt first, InputIt last, ClockType& clock, Compare const& comp);
template <class InputIt>
AgedOrderedContainer(InputIt first, InputIt last, clock_type& clock, Allocator const& alloc);
AgedOrderedContainer(InputIt first, InputIt last, ClockType& clock, Allocator const& alloc);
template <class InputIt>
AgedOrderedContainer(
InputIt first,
InputIt last,
clock_type& clock,
ClockType& clock,
Compare const& comp,
Allocator const& alloc);
@@ -556,21 +556,21 @@ public:
AgedOrderedContainer&& other,
Allocator const& alloc);
AgedOrderedContainer(std::initializer_list<value_type> init, clock_type& clock);
AgedOrderedContainer(std::initializer_list<value_type> init, ClockType& clock);
AgedOrderedContainer(
std::initializer_list<value_type> init,
clock_type& clock,
ClockType& clock,
Compare const& comp);
AgedOrderedContainer(
std::initializer_list<value_type> init,
clock_type& clock,
ClockType& clock,
Allocator const& alloc);
AgedOrderedContainer(
std::initializer_list<value_type> init,
clock_type& clock,
ClockType& clock,
Compare const& comp,
Allocator const& alloc);
@@ -591,13 +591,13 @@ public:
return config_.alloc();
}
clock_type&
ClockType&
clock()
{
return config_.clock;
}
clock_type const&
ClockType const&
clock() const
{
return config_.clock;
@@ -820,7 +820,7 @@ public:
template <class P, bool MaybeMap = IsMap>
std::conditional_t<IsMulti, iterator, std::pair<iterator, bool>>
insert(P&& value)
requires(MaybeMap && std::is_constructible_v<value_type, P &&>)
requires(MaybeMap && std::is_constructible_v<value_type, P&&>)
{
return emplace(std::forward<P>(value));
}
@@ -829,7 +829,7 @@ public:
template <class P, bool MaybeMap = IsMap>
std::conditional_t<IsMulti, iterator, std::pair<iterator, bool>>
insert(const_iterator hint, P&& value)
requires(MaybeMap && std::is_constructible_v<value_type, P &&>)
requires(MaybeMap && std::is_constructible_v<value_type, P&&>)
{
return emplaceHint(hint, std::forward<P>(value));
}
@@ -1121,7 +1121,7 @@ private:
void
touch(
beast::detail::AgedContainerIterator<IsConst, Iterator> pos,
clock_type::time_point const& now)
ClockType::time_point const& now)
requires(!IsBoostReverseIterator<Iterator>::value);
template <
@@ -1138,21 +1138,21 @@ private:
private:
ConfigT config_;
cont_type mutable cont_;
ContType mutable cont_;
};
//------------------------------------------------------------------------------
template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::AgedOrderedContainer(
clock_type& clock)
ClockType& clock)
: config_(clock)
{
}
template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::AgedOrderedContainer(
clock_type& clock,
ClockType& clock,
Compare const& comp)
: config_(clock, comp), cont_(comp)
{
@@ -1160,7 +1160,7 @@ AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::AgedOrd
template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::AgedOrderedContainer(
clock_type& clock,
ClockType& clock,
Allocator const& alloc)
: config_(clock, alloc)
{
@@ -1168,7 +1168,7 @@ AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::AgedOrd
template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::AgedOrderedContainer(
clock_type& clock,
ClockType& clock,
Compare const& comp,
Allocator const& alloc)
: config_(clock, comp, alloc), cont_(comp)
@@ -1180,7 +1180,7 @@ template <class InputIt>
AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::AgedOrderedContainer(
InputIt first,
InputIt last,
clock_type& clock)
ClockType& clock)
: config_(clock)
{
insert(first, last);
@@ -1191,7 +1191,7 @@ template <class InputIt>
AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::AgedOrderedContainer(
InputIt first,
InputIt last,
clock_type& clock,
ClockType& clock,
Compare const& comp)
: config_(clock, comp), cont_(comp)
{
@@ -1203,7 +1203,7 @@ template <class InputIt>
AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::AgedOrderedContainer(
InputIt first,
InputIt last,
clock_type& clock,
ClockType& clock,
Allocator const& alloc)
: config_(clock, alloc)
{
@@ -1215,7 +1215,7 @@ template <class InputIt>
AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::AgedOrderedContainer(
InputIt first,
InputIt last,
clock_type& clock,
ClockType& clock,
Compare const& comp,
Allocator const& alloc)
: config_(clock, comp, alloc), cont_(comp)
@@ -1261,7 +1261,7 @@ AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::AgedOrd
template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::AgedOrderedContainer(
std::initializer_list<value_type> init,
clock_type& clock)
ClockType& clock)
: config_(clock)
{
insert(init.begin(), init.end());
@@ -1270,7 +1270,7 @@ AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::AgedOrd
template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::AgedOrderedContainer(
std::initializer_list<value_type> init,
clock_type& clock,
ClockType& clock,
Compare const& comp)
: config_(clock, comp), cont_(comp)
{
@@ -1280,7 +1280,7 @@ AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::AgedOrd
template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::AgedOrderedContainer(
std::initializer_list<value_type> init,
clock_type& clock,
ClockType& clock,
Allocator const& alloc)
: config_(clock, alloc)
{
@@ -1290,7 +1290,7 @@ AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::AgedOrd
template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::AgedOrderedContainer(
std::initializer_list<value_type> init,
clock_type& clock,
ClockType& clock,
Compare const& comp,
Allocator const& alloc)
: config_(clock, comp, alloc), cont_(comp)
@@ -1372,7 +1372,7 @@ std::conditional_t<IsMap, T, void*>&
AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::operator[](Key const& key)
requires(MaybeMap && !MaybeMulti)
{
typename cont_type::insert_commit_data d;
typename ContType::insert_commit_data d;
auto const result(cont_.insert_check(key, std::cref(config_.keyCompare()), d));
if (result.second)
{
@@ -1391,7 +1391,7 @@ std::conditional_t<IsMap, T, void*>&
AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::operator[](Key&& key)
requires(MaybeMap && !MaybeMulti)
{
typename cont_type::insert_commit_data d;
typename ContType::insert_commit_data d;
auto const result(cont_.insert_check(key, std::cref(config_.keyCompare()), d));
if (result.second)
{
@@ -1426,7 +1426,7 @@ AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::insert(
value_type const& value) -> std::pair<iterator, bool>
requires(!MaybeMulti)
{
typename cont_type::insert_commit_data d;
typename ContType::insert_commit_data d;
auto const result(cont_.insert_check(extract(value), std::cref(config_.keyCompare()), d));
if (result.second)
{
@@ -1461,7 +1461,7 @@ AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::insert(
-> std::pair<iterator, bool>
requires(!MaybeMulti && !MaybeMap)
{
typename cont_type::insert_commit_data d;
typename ContType::insert_commit_data d;
auto const result(cont_.insert_check(extract(value), std::cref(config_.keyCompare()), d));
if (result.second)
{
@@ -1499,7 +1499,7 @@ AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::insert(
value_type const& value) -> iterator
requires(!MaybeMulti)
{
typename cont_type::insert_commit_data d;
typename ContType::insert_commit_data d;
auto const result(
cont_.insert_check(hint.iterator(), extract(value), std::cref(config_.keyCompare()), d));
if (result.second)
@@ -1521,7 +1521,7 @@ AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::insert(
value_type&& value) -> iterator
requires(!MaybeMulti)
{
typename cont_type::insert_commit_data d;
typename ContType::insert_commit_data d;
auto const result(
cont_.insert_check(hint.iterator(), extract(value), std::cref(config_.keyCompare()), d));
if (result.second)
@@ -1545,7 +1545,7 @@ AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::emplace
// VFALCO NOTE Its unfortunate that we need to
// construct element here
Element* const p(newElement(std::forward<Args>(args)...));
typename cont_type::insert_commit_data d;
typename ContType::insert_commit_data d;
auto const result(cont_.insert_check(extract(p->value), std::cref(config_.keyCompare()), d));
if (result.second)
{
@@ -1584,7 +1584,7 @@ AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::emplace
// VFALCO NOTE Its unfortunate that we need to
// construct element here
Element* const p(newElement(std::forward<Args>(args)...));
typename cont_type::insert_commit_data d;
typename ContType::insert_commit_data d;
auto const result(
cont_.insert_check(hint.iterator(), extract(p->value), std::cref(config_.keyCompare()), d));
if (result.second)
@@ -1721,7 +1721,7 @@ template <bool IsConst, class Iterator>
void
AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::touch(
beast::detail::AgedContainerIterator<IsConst, Iterator> pos,
clock_type::time_point const& now)
ClockType::time_point const& now)
requires(!IsBoostReverseIterator<Iterator>::value)
{
auto& e(*pos.iterator());

View File

@@ -59,8 +59,8 @@ namespace detail {
* whose items expire after a certain amount of time. The chronological
* iterators allow for fully customizable expiration strategies.
*
* @see aged_unordered_set, aged_unordered_multiset
* @see aged_unordered_map, aged_unordered_multimap
* @see AgedUnorderedSet, AgedUnorderedMultiset
* @see AgedUnorderedMap, AgedUnorderedMultimap
*/
template <
bool IsMulti,
@@ -74,9 +74,9 @@ template <
class AgedUnorderedContainer
{
public:
using clock_type = AbstractClock<Clock>;
using time_point = clock_type::time_point;
using duration = clock_type::duration;
using ClockType = AbstractClock<Clock>;
using time_point = ClockType::time_point;
using duration = ClockType::duration;
using key_type = Key;
using mapped_type = T;
using value_type = std::conditional_t<IsMap, std::pair<Key const, T>, Key>;
@@ -84,9 +84,9 @@ public:
using difference_type = std::ptrdiff_t;
// Introspection (for unit tests)
using is_unordered = std::true_type;
using is_multi = std::integral_constant<bool, IsMulti>;
using is_map = std::integral_constant<bool, IsMap>;
using IsUnorderedType = std::true_type;
using IsMultiType = std::integral_constant<bool, IsMulti>;
using IsMapType = std::integral_constant<bool, IsMap>;
private:
static Key const&
@@ -208,10 +208,10 @@ private:
}
};
using list_type =
using ListType =
boost::intrusive::make_list<Element, boost::intrusive::constant_time_size<false>>::type;
using cont_type = std::conditional_t<
using ContType = std::conditional_t<
IsMulti,
typename boost::intrusive::make_unordered_multiset<
Element,
@@ -226,8 +226,8 @@ private:
boost::intrusive::equal<KeyValueEqual>,
boost::intrusive::cache_begin<true>>::type>;
using bucket_type = cont_type::bucket_type;
using bucket_traits = cont_type::bucket_traits;
using BucketType = ContType::bucket_type;
using BucketTraits = ContType::bucket_traits;
using ElementAllocator = std::allocator_traits<Allocator>::template rebind_alloc<Element>;
@@ -242,36 +242,36 @@ private:
private beast::detail::EmptyBaseOptimization<ElementAllocator>
{
public:
explicit ConfigT(clock_type& clock) : clock(clock)
explicit ConfigT(ClockType& clock) : clock(clock)
{
}
ConfigT(clock_type& clock, Hash const& hash) : ValueHash(hash), clock(clock)
ConfigT(ClockType& clock, Hash const& hash) : ValueHash(hash), clock(clock)
{
}
ConfigT(clock_type& clock, KeyEqual const& keyEqual) : KeyValueEqual(keyEqual), clock(clock)
ConfigT(ClockType& clock, KeyEqual const& keyEqual) : KeyValueEqual(keyEqual), clock(clock)
{
}
ConfigT(clock_type& clock, Allocator const& alloc)
ConfigT(ClockType& clock, Allocator const& alloc)
: beast::detail::EmptyBaseOptimization<ElementAllocator>(alloc), clock(clock)
{
}
ConfigT(clock_type& clock, Hash const& hash, KeyEqual const& keyEqual)
ConfigT(ClockType& clock, Hash const& hash, KeyEqual const& keyEqual)
: ValueHash(hash), KeyValueEqual(keyEqual), clock(clock)
{
}
ConfigT(clock_type& clock, Hash const& hash, Allocator const& alloc)
ConfigT(ClockType& clock, Hash const& hash, Allocator const& alloc)
: ValueHash(hash)
, beast::detail::EmptyBaseOptimization<ElementAllocator>(alloc)
, clock(clock)
{
}
ConfigT(clock_type& clock, KeyEqual const& keyEqual, Allocator const& alloc)
ConfigT(ClockType& clock, KeyEqual const& keyEqual, Allocator const& alloc)
: KeyValueEqual(keyEqual)
, beast::detail::EmptyBaseOptimization<ElementAllocator>(alloc)
, clock(clock)
@@ -279,7 +279,7 @@ private:
}
ConfigT(
clock_type& clock,
ClockType& clock,
Hash const& hash,
KeyEqual const& keyEqual,
Allocator const& alloc)
@@ -405,29 +405,29 @@ private:
return beast::detail::EmptyBaseOptimization<ElementAllocator>::member();
}
std::reference_wrapper<clock_type> clock;
std::reference_wrapper<ClockType> clock;
};
class Buckets
{
public:
using vec_type = std::vector<
bucket_type,
typename std::allocator_traits<Allocator>::template rebind_alloc<bucket_type>>;
using VecType = std::vector<
BucketType,
typename std::allocator_traits<Allocator>::template rebind_alloc<BucketType>>;
Buckets() : maxLoadFactor_(1.f), vec_()
{
vec_.resize(cont_type::suggested_upper_bucket_count(0));
vec_.resize(ContType::suggested_upper_bucket_count(0));
}
Buckets(Allocator const& alloc) : maxLoadFactor_(1.f), vec_(alloc)
{
vec_.resize(cont_type::suggested_upper_bucket_count(0));
vec_.resize(ContType::suggested_upper_bucket_count(0));
}
operator bucket_traits()
operator BucketTraits()
{
return bucket_traits(&vec_[0], vec_.size());
return BucketTraits(&vec_[0], vec_.size());
}
void
@@ -466,10 +466,10 @@ private:
{
// Need two vectors otherwise we
// will destroy non-empty buckets.
vec_type vec(vec_.get_allocator());
VecType vec(vec_.get_allocator());
std::swap(vec_, vec);
vec_.resize(count);
c.rehash(bucket_traits(&vec_[0], vec_.size()));
c.rehash(BucketTraits(&vec_[0], vec_.size()));
return;
}
// Rehash in place.
@@ -478,12 +478,12 @@ private:
// This should not reallocate since
// we checked capacity earlier.
vec_.resize(count);
c.rehash(bucket_traits(&vec_[0], count));
c.rehash(BucketTraits(&vec_[0], count));
return;
}
// Resize must happen after rehash otherwise
// we might destroy non-empty buckets.
c.rehash(bucket_traits(&vec_[0], count));
c.rehash(BucketTraits(&vec_[0], count));
vec_.resize(count);
}
@@ -492,13 +492,13 @@ private:
void
resize(size_type n, Container& c)
{
size_type const suggested(cont_type::suggested_upper_bucket_count(n));
size_type const suggested(ContType::suggested_upper_bucket_count(n));
rehash(suggested, c);
}
private:
float maxLoadFactor_;
vec_type vec_;
VecType vec_;
};
template <class... Args>
@@ -553,13 +553,13 @@ public:
// A set iterator (IsMap==false) is always const
// because the elements of a set are immutable.
using iterator = beast::detail::AgedContainerIterator<!IsMap, typename cont_type::iterator>;
using const_iterator = beast::detail::AgedContainerIterator<true, typename cont_type::iterator>;
using iterator = beast::detail::AgedContainerIterator<!IsMap, typename ContType::iterator>;
using const_iterator = beast::detail::AgedContainerIterator<true, typename ContType::iterator>;
using local_iterator =
beast::detail::AgedContainerIterator<!IsMap, typename cont_type::local_iterator>;
beast::detail::AgedContainerIterator<!IsMap, typename ContType::local_iterator>;
using const_local_iterator =
beast::detail::AgedContainerIterator<true, typename cont_type::local_iterator>;
beast::detail::AgedContainerIterator<true, typename ContType::local_iterator>;
//--------------------------------------------------------------------------
//
@@ -575,13 +575,13 @@ public:
public:
// A set iterator (IsMap==false) is always const
// because the elements of a set are immutable.
using iterator = beast::detail::AgedContainerIterator<!IsMap, typename list_type::iterator>;
using iterator = beast::detail::AgedContainerIterator<!IsMap, typename ListType::iterator>;
using const_iterator =
beast::detail::AgedContainerIterator<true, typename list_type::iterator>;
beast::detail::AgedContainerIterator<true, typename ListType::iterator>;
using reverse_iterator =
beast::detail::AgedContainerIterator<!IsMap, typename list_type::reverse_iterator>;
beast::detail::AgedContainerIterator<!IsMap, typename ListType::reverse_iterator>;
using const_reverse_iterator =
beast::detail::AgedContainerIterator<true, typename list_type::reverse_iterator>;
beast::detail::AgedContainerIterator<true, typename ListType::reverse_iterator>;
iterator
begin()
@@ -679,7 +679,7 @@ public:
private:
friend class AgedUnorderedContainer;
list_type mutable list_;
ListType mutable list_;
} chronological;
//--------------------------------------------------------------------------
@@ -690,43 +690,43 @@ public:
AgedUnorderedContainer() = delete;
explicit AgedUnorderedContainer(clock_type& clock);
explicit AgedUnorderedContainer(ClockType& clock);
AgedUnorderedContainer(clock_type& clock, Hash const& hash);
AgedUnorderedContainer(ClockType& clock, Hash const& hash);
AgedUnorderedContainer(clock_type& clock, KeyEqual const& keyEq);
AgedUnorderedContainer(ClockType& clock, KeyEqual const& keyEq);
AgedUnorderedContainer(clock_type& clock, Allocator const& alloc);
AgedUnorderedContainer(ClockType& clock, Allocator const& alloc);
AgedUnorderedContainer(clock_type& clock, Hash const& hash, KeyEqual const& keyEq);
AgedUnorderedContainer(ClockType& clock, Hash const& hash, KeyEqual const& keyEq);
AgedUnorderedContainer(clock_type& clock, Hash const& hash, Allocator const& alloc);
AgedUnorderedContainer(ClockType& clock, Hash const& hash, Allocator const& alloc);
AgedUnorderedContainer(clock_type& clock, KeyEqual const& keyEq, Allocator const& alloc);
AgedUnorderedContainer(ClockType& clock, KeyEqual const& keyEq, Allocator const& alloc);
AgedUnorderedContainer(
clock_type& clock,
ClockType& clock,
Hash const& hash,
KeyEqual const& keyEq,
Allocator const& alloc);
template <class InputIt>
AgedUnorderedContainer(InputIt first, InputIt last, clock_type& clock);
AgedUnorderedContainer(InputIt first, InputIt last, ClockType& clock);
template <class InputIt>
AgedUnorderedContainer(InputIt first, InputIt last, clock_type& clock, Hash const& hash);
AgedUnorderedContainer(InputIt first, InputIt last, ClockType& clock, Hash const& hash);
template <class InputIt>
AgedUnorderedContainer(InputIt first, InputIt last, clock_type& clock, KeyEqual const& keyEq);
AgedUnorderedContainer(InputIt first, InputIt last, ClockType& clock, KeyEqual const& keyEq);
template <class InputIt>
AgedUnorderedContainer(InputIt first, InputIt last, clock_type& clock, Allocator const& alloc);
AgedUnorderedContainer(InputIt first, InputIt last, ClockType& clock, Allocator const& alloc);
template <class InputIt>
AgedUnorderedContainer(
InputIt first,
InputIt last,
clock_type& clock,
ClockType& clock,
Hash const& hash,
KeyEqual const& keyEq);
@@ -734,7 +734,7 @@ public:
AgedUnorderedContainer(
InputIt first,
InputIt last,
clock_type& clock,
ClockType& clock,
Hash const& hash,
Allocator const& alloc);
@@ -742,7 +742,7 @@ public:
AgedUnorderedContainer(
InputIt first,
InputIt last,
clock_type& clock,
ClockType& clock,
KeyEqual const& keyEq,
Allocator const& alloc);
@@ -750,7 +750,7 @@ public:
AgedUnorderedContainer(
InputIt first,
InputIt last,
clock_type& clock,
ClockType& clock,
Hash const& hash,
KeyEqual const& keyEq,
Allocator const& alloc);
@@ -766,44 +766,44 @@ public:
AgedUnorderedContainer&& other,
Allocator const& alloc);
AgedUnorderedContainer(std::initializer_list<value_type> init, clock_type& clock);
AgedUnorderedContainer(std::initializer_list<value_type> init, ClockType& clock);
AgedUnorderedContainer(
std::initializer_list<value_type> init,
clock_type& clock,
ClockType& clock,
Hash const& hash);
AgedUnorderedContainer(
std::initializer_list<value_type> init,
clock_type& clock,
ClockType& clock,
KeyEqual const& keyEq);
AgedUnorderedContainer(
std::initializer_list<value_type> init,
clock_type& clock,
ClockType& clock,
Allocator const& alloc);
AgedUnorderedContainer(
std::initializer_list<value_type> init,
clock_type& clock,
ClockType& clock,
Hash const& hash,
KeyEqual const& keyEq);
AgedUnorderedContainer(
std::initializer_list<value_type> init,
clock_type& clock,
ClockType& clock,
Hash const& hash,
Allocator const& alloc);
AgedUnorderedContainer(
std::initializer_list<value_type> init,
clock_type& clock,
ClockType& clock,
KeyEqual const& keyEq,
Allocator const& alloc);
AgedUnorderedContainer(
std::initializer_list<value_type> init,
clock_type& clock,
ClockType& clock,
Hash const& hash,
KeyEqual const& keyEq,
Allocator const& alloc);
@@ -825,13 +825,13 @@ public:
return config_.alloc();
}
clock_type&
ClockType&
clock()
{
return config_.clock;
}
clock_type const&
ClockType const&
clock() const
{
return config_.clock;
@@ -1028,7 +1028,7 @@ public:
template <class P, bool MaybeMap = IsMap>
std::conditional_t<IsMulti, iterator, std::pair<iterator, bool>>
insert(P&& value)
requires(MaybeMap && std::is_constructible_v<value_type, P &&>)
requires(MaybeMap && std::is_constructible_v<value_type, P&&>)
{
return emplace(std::forward<P>(value));
}
@@ -1037,7 +1037,7 @@ public:
template <class P, bool MaybeMap = IsMap>
std::conditional_t<IsMulti, iterator, std::pair<iterator, bool>>
insert(const_iterator hint, P&& value)
requires(MaybeMap && std::is_constructible_v<value_type, P &&>)
requires(MaybeMap && std::is_constructible_v<value_type, P&&>)
{
return emplaceHint(hint, std::forward<P>(value));
}
@@ -1399,7 +1399,7 @@ private:
void
touch(
beast::detail::AgedContainerIterator<IsConst, Iterator> pos,
clock_type::time_point const& now)
ClockType::time_point const& now)
{
auto& e(*pos.iterator());
e.when = now;
@@ -1433,7 +1433,7 @@ private:
private:
ConfigT config_;
Buckets buck_;
cont_type mutable cont_;
ContType mutable cont_;
};
//------------------------------------------------------------------------------
@@ -1448,7 +1448,7 @@ template <
class KeyEqual,
class Allocator>
AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>::
AgedUnorderedContainer(clock_type& clock)
AgedUnorderedContainer(ClockType& clock)
: config_(clock)
, cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
{
@@ -1464,7 +1464,7 @@ template <
class KeyEqual,
class Allocator>
AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>::
AgedUnorderedContainer(clock_type& clock, Hash const& hash)
AgedUnorderedContainer(ClockType& clock, Hash const& hash)
: config_(clock, hash)
, cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
{
@@ -1480,7 +1480,7 @@ template <
class KeyEqual,
class Allocator>
AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>::
AgedUnorderedContainer(clock_type& clock, KeyEqual const& keyEq)
AgedUnorderedContainer(ClockType& clock, KeyEqual const& keyEq)
: config_(clock, keyEq)
, cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
{
@@ -1496,7 +1496,7 @@ template <
class KeyEqual,
class Allocator>
AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>::
AgedUnorderedContainer(clock_type& clock, Allocator const& alloc)
AgedUnorderedContainer(ClockType& clock, Allocator const& alloc)
: config_(clock, alloc)
, buck_(alloc)
, cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
@@ -1513,7 +1513,7 @@ template <
class KeyEqual,
class Allocator>
AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>::
AgedUnorderedContainer(clock_type& clock, Hash const& hash, KeyEqual const& keyEq)
AgedUnorderedContainer(ClockType& clock, Hash const& hash, KeyEqual const& keyEq)
: config_(clock, hash, keyEq)
, cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
{
@@ -1529,7 +1529,7 @@ template <
class KeyEqual,
class Allocator>
AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>::
AgedUnorderedContainer(clock_type& clock, Hash const& hash, Allocator const& alloc)
AgedUnorderedContainer(ClockType& clock, Hash const& hash, Allocator const& alloc)
: config_(clock, hash, alloc)
, buck_(alloc)
, cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
@@ -1546,7 +1546,7 @@ template <
class KeyEqual,
class Allocator>
AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>::
AgedUnorderedContainer(clock_type& clock, KeyEqual const& keyEq, Allocator const& alloc)
AgedUnorderedContainer(ClockType& clock, KeyEqual const& keyEq, Allocator const& alloc)
: config_(clock, keyEq, alloc)
, buck_(alloc)
, cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
@@ -1564,7 +1564,7 @@ template <
class Allocator>
AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>::
AgedUnorderedContainer(
clock_type& clock,
ClockType& clock,
Hash const& hash,
KeyEqual const& keyEq,
Allocator const& alloc)
@@ -1585,7 +1585,7 @@ template <
class Allocator>
template <class InputIt>
AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>::
AgedUnorderedContainer(InputIt first, InputIt last, clock_type& clock)
AgedUnorderedContainer(InputIt first, InputIt last, ClockType& clock)
: config_(clock)
, cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
{
@@ -1603,7 +1603,7 @@ template <
class Allocator>
template <class InputIt>
AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>::
AgedUnorderedContainer(InputIt first, InputIt last, clock_type& clock, Hash const& hash)
AgedUnorderedContainer(InputIt first, InputIt last, ClockType& clock, Hash const& hash)
: config_(clock, hash)
, cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
{
@@ -1621,7 +1621,7 @@ template <
class Allocator>
template <class InputIt>
AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>::
AgedUnorderedContainer(InputIt first, InputIt last, clock_type& clock, KeyEqual const& keyEq)
AgedUnorderedContainer(InputIt first, InputIt last, ClockType& clock, KeyEqual const& keyEq)
: config_(clock, keyEq)
, cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
{
@@ -1639,7 +1639,7 @@ template <
class Allocator>
template <class InputIt>
AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>::
AgedUnorderedContainer(InputIt first, InputIt last, clock_type& clock, Allocator const& alloc)
AgedUnorderedContainer(InputIt first, InputIt last, ClockType& clock, Allocator const& alloc)
: config_(clock, alloc)
, buck_(alloc)
, cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
@@ -1661,7 +1661,7 @@ AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>
AgedUnorderedContainer(
InputIt first,
InputIt last,
clock_type& clock,
ClockType& clock,
Hash const& hash,
KeyEqual const& keyEq)
: config_(clock, hash, keyEq)
@@ -1684,7 +1684,7 @@ AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>
AgedUnorderedContainer(
InputIt first,
InputIt last,
clock_type& clock,
ClockType& clock,
Hash const& hash,
Allocator const& alloc)
: config_(clock, hash, alloc)
@@ -1708,7 +1708,7 @@ AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>
AgedUnorderedContainer(
InputIt first,
InputIt last,
clock_type& clock,
ClockType& clock,
KeyEqual const& keyEq,
Allocator const& alloc)
: config_(clock, keyEq, alloc)
@@ -1732,7 +1732,7 @@ AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>
AgedUnorderedContainer(
InputIt first,
InputIt last,
clock_type& clock,
ClockType& clock,
Hash const& hash,
KeyEqual const& keyEq,
Allocator const& alloc)
@@ -1829,7 +1829,7 @@ template <
class KeyEqual,
class Allocator>
AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>::
AgedUnorderedContainer(std::initializer_list<value_type> init, clock_type& clock)
AgedUnorderedContainer(std::initializer_list<value_type> init, ClockType& clock)
: config_(clock)
, cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
{
@@ -1848,7 +1848,7 @@ template <
AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>::
AgedUnorderedContainer(
std::initializer_list<value_type> init,
clock_type& clock,
ClockType& clock,
Hash const& hash)
: config_(clock, hash)
, cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
@@ -1868,7 +1868,7 @@ template <
AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>::
AgedUnorderedContainer(
std::initializer_list<value_type> init,
clock_type& clock,
ClockType& clock,
KeyEqual const& keyEq)
: config_(clock, keyEq)
, cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
@@ -1888,7 +1888,7 @@ template <
AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>::
AgedUnorderedContainer(
std::initializer_list<value_type> init,
clock_type& clock,
ClockType& clock,
Allocator const& alloc)
: config_(clock, alloc)
, buck_(alloc)
@@ -1909,7 +1909,7 @@ template <
AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>::
AgedUnorderedContainer(
std::initializer_list<value_type> init,
clock_type& clock,
ClockType& clock,
Hash const& hash,
KeyEqual const& keyEq)
: config_(clock, hash, keyEq)
@@ -1930,7 +1930,7 @@ template <
AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>::
AgedUnorderedContainer(
std::initializer_list<value_type> init,
clock_type& clock,
ClockType& clock,
Hash const& hash,
Allocator const& alloc)
: config_(clock, hash, alloc)
@@ -1952,7 +1952,7 @@ template <
AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>::
AgedUnorderedContainer(
std::initializer_list<value_type> init,
clock_type& clock,
ClockType& clock,
KeyEqual const& keyEq,
Allocator const& alloc)
: config_(clock, keyEq, alloc)
@@ -1974,7 +1974,7 @@ template <
AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>::
AgedUnorderedContainer(
std::initializer_list<value_type> init,
clock_type& clock,
ClockType& clock,
Hash const& hash,
KeyEqual const& keyEq,
Allocator const& alloc)
@@ -2127,7 +2127,7 @@ AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>
requires(MaybeMap && !MaybeMulti)
{
maybeRehash(1);
typename cont_type::insert_commit_data d;
typename ContType::insert_commit_data d;
auto const result(cont_.insert_check(
key, std::cref(config_.hashFunction()), std::cref(config_.keyValueEqual()), d));
if (result.second)
@@ -2157,7 +2157,7 @@ AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>
requires(MaybeMap && !MaybeMulti)
{
maybeRehash(1);
typename cont_type::insert_commit_data d;
typename ContType::insert_commit_data d;
auto const result(cont_.insert_check(
key, std::cref(config_.hashFunction()), std::cref(config_.keyValueEqual()), d));
if (result.second)
@@ -2211,7 +2211,7 @@ AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>
requires(!MaybeMulti)
{
maybeRehash(1);
typename cont_type::insert_commit_data d;
typename ContType::insert_commit_data d;
auto const result(cont_.insert_check(
extract(value), std::cref(config_.hashFunction()), std::cref(config_.keyValueEqual()), d));
if (result.second)
@@ -2264,7 +2264,7 @@ AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>
requires(!MaybeMulti && !MaybeMap)
{
maybeRehash(1);
typename cont_type::insert_commit_data d;
typename ContType::insert_commit_data d;
auto const result(cont_.insert_check(
extract(value), std::cref(config_.hashFunction()), std::cref(config_.keyValueEqual()), d));
if (result.second)
@@ -2374,7 +2374,7 @@ AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>
// VFALCO NOTE Its unfortunate that we need to
// construct element here
Element* const p(newElement(std::forward<Args>(args)...));
typename cont_type::insert_commit_data d;
typename ContType::insert_commit_data d;
auto const result(cont_.insert_check(
extract(p->value),
std::cref(config_.hashFunction()),
@@ -2611,7 +2611,7 @@ AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>
value_type const& value) -> std::pair<iterator, bool>
requires(!MaybeMulti)
{
typename cont_type::insert_commit_data d;
typename ContType::insert_commit_data d;
auto const result(cont_.insert_check(
extract(value), std::cref(config_.hashFunction()), std::cref(config_.keyValueEqual()), d));
if (result.second)

View File

@@ -26,7 +26,7 @@ namespace beast::insight {
class Collector
{
public:
using ptr = std::shared_ptr<Collector>;
using Ptr = std::shared_ptr<Collector>;
virtual ~Collector() = 0;

View File

@@ -13,7 +13,7 @@ namespace beast::insight {
class Group : public Collector
{
public:
using ptr = std::shared_ptr<Group>;
using Ptr = std::shared_ptr<Group>;
/**
* Returns the name of this group, for diagnostics.

View File

@@ -20,10 +20,10 @@ public:
* Find or create a new collector with a given name.
*/
/** @{ */
virtual Group::ptr const&
virtual Group::Ptr const&
get(std::string const& name) = 0;
Group::ptr const&
Group::Ptr const&
operator[](std::string const& name)
{
return get(name);
@@ -35,6 +35,6 @@ public:
* Create a group container that uses the specified collector.
*/
std::unique_ptr<Groups>
makeGroups(Collector::ptr const& collector);
makeGroups(Collector::Ptr const& collector);
} // namespace beast::insight

View File

@@ -108,12 +108,12 @@ Result
split(FwdIt first, FwdIt last, Char delim)
{
using namespace detail;
using string = Result::value_type;
using String = Result::value_type;
Result result;
FwdIt iter = first;
string e;
String e;
while (iter != last)
{
if (*iter == '"')
@@ -205,10 +205,10 @@ splitCommas(std::string_view s)
*/
class ListIterator
{
using iter_type = boost::string_ref::const_iterator;
using IterType = boost::string_ref::const_iterator;
iter_type it_;
iter_type end_;
IterType it_;
IterType end_;
boost::string_ref value_;
public:
@@ -218,7 +218,7 @@ public:
using difference_type = std::ptrdiff_t;
using iterator_category = std::forward_iterator_tag;
ListIterator(iter_type begin, iter_type end) : it_(begin), end_(end)
ListIterator(IterType begin, IterType end) : it_(begin), end_(end)
{
if (it_ != end_)
increment();

View File

@@ -42,7 +42,7 @@ public:
/**
* The type of yield context passed to functions.
*/
using yield_context = boost::asio::yield_context;
using YieldContext = boost::asio::yield_context;
explicit EnableYieldTo(std::size_t concurrency = 1) : work_(boost::asio::make_work_guard(ios_))
{
@@ -120,7 +120,7 @@ EnableYieldTo::spawn(F0&& f, FN&&... fn)
ios_,
boost::allocator_arg,
boost::context::fixedsize_stack(2 * 1024 * 1024),
[&](yield_context yield) {
[&](YieldContext yield) {
f(yield);
std::scoped_lock const lock{m_};
if (--running_ == 0)

View File

@@ -15,29 +15,29 @@ template <class Container>
class ConstContainer
{
private:
using cont_type = Container;
using ContType = Container;
cont_type cont_;
ContType cont_;
protected:
cont_type&
ContType&
cont()
{
return cont_;
}
[[nodiscard]] cont_type const&
[[nodiscard]] ContType const&
cont() const
{
return cont_;
}
public:
using value_type = cont_type::value_type;
using size_type = cont_type::size_type;
using difference_type = cont_type::difference_type;
using iterator = cont_type::const_iterator;
using const_iterator = cont_type::const_iterator;
using value_type = ContType::value_type;
using size_type = ContType::size_type;
using difference_type = ContType::difference_type;
using iterator = ContType::const_iterator;
using const_iterator = ContType::const_iterator;
/**
* Returns `true` if the container is empty.

View File

@@ -32,7 +32,7 @@ template <class = void>
class Reporter : public Runner
{
private:
using clock_type = std::chrono::steady_clock;
using ClockType = std::chrono::steady_clock;
struct CaseResults
{
@@ -51,7 +51,7 @@ private:
std::size_t cases = 0;
std::size_t total = 0;
std::size_t failed = 0;
clock_type::time_point start = clock_type::now();
ClockType::time_point start = ClockType::now();
explicit SuiteResults(std::string name = "") : name(std::move(name))
{
@@ -63,7 +63,7 @@ private:
struct Results
{
using run_time = std::pair<std::string, clock_type::duration>;
using RunTime = std::pair<std::string, ClockType::duration>;
static constexpr auto kMaxTop = 10;
@@ -71,8 +71,8 @@ private:
std::size_t cases = 0;
std::size_t total = 0;
std::size_t failed = 0;
std::vector<run_time> top;
clock_type::time_point start = clock_type::now();
std::vector<RunTime> top;
ClockType::time_point start = ClockType::now();
void
add(SuiteResults const& r);
@@ -94,7 +94,7 @@ public:
private:
static std::string
fmtdur(clock_type::duration const& d);
fmtdur(ClockType::duration const& d);
void
onSuiteBegin(SuiteInfo const& info) override;
@@ -137,14 +137,13 @@ Reporter<Unused>::Results::add(SuiteResults const& r)
total += r.total;
cases += r.cases;
failed += r.failed;
auto const elapsed = clock_type::now() - r.start;
auto const elapsed = ClockType::now() - r.start;
if (elapsed >= std::chrono::seconds{1})
{
auto const iter = std::lower_bound(
top.begin(),
top.end(),
elapsed,
[](run_time const& t1, clock_type::duration const& t2) { return t1.second > t2; });
top.begin(), top.end(), elapsed, [](RunTime const& t1, ClockType::duration const& t2) {
return t1.second > t2;
});
if (iter != top.end())
{
if (top.size() == kMaxTop)
@@ -174,7 +173,7 @@ Reporter<Unused>::~Reporter()
for (auto const& i : results_.top)
os_ << std::setw(8) << fmtdur(i.second) << " " << i.first << '\n';
}
auto const elapsed = clock_type::now() - results_.start;
auto const elapsed = ClockType::now() - results_.start;
os_ << fmtdur(elapsed) << ", " << Amount{results_.suites, "suite"} << ", "
<< Amount{results_.cases, "case"} << ", " << Amount{results_.total, "test"} << " total, "
<< Amount{results_.failed, "failure"} << std::endl;
@@ -182,7 +181,7 @@ Reporter<Unused>::~Reporter()
template <class Unused>
std::string
Reporter<Unused>::fmtdur(clock_type::duration const& d)
Reporter<Unused>::fmtdur(ClockType::duration const& d)
{
using namespace std::chrono;
auto const ms = duration_cast<milliseconds>(d);
@@ -249,6 +248,10 @@ Reporter<Unused>::onLog(std::string const& s)
} // namespace detail
using reporter = detail::Reporter<>;
using Reporter = detail::Reporter<>;
// TODO [#8340]: Legacy name still used by external consumers of libxrpl (e.g. validator-keys-tool).
// Do not use in new code; remove once those consumers have migrated.
using reporter = Reporter; // NOLINT(readability-identifier-naming)
} // namespace beast::unit_test

View File

@@ -643,12 +643,12 @@ Suite::run(Runner& r)
* Library Identifies the library.
*
* The declaration for the class implementing the test should be the same
* as Class ## _test. For example, if Class is aged_ordered_container, the
* as Class ## _test. For example, if Class is AgedOrderedContainer, the
* test class must be declared as:
*
* @code
*
* struct aged_ordered_container_test : beast::unit_test::suite
* struct AgedOrderedContainer_test : beast::unit_test::suite
* {
* //...
* };

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