Compare commits

..
Author SHA1 Message Date
Bart 1218e75e03 feat: Accept a JSON-RPC 2.0 batch from API version 3
A top-level JSON array is the batch form the specification defines, accepted
from API version 3. Each entry is a request in its own right, nesting its
parameters as a lone request does and correlating by its own `id`. The
answer is an array of one reply per entry at HTTP 200, as the `method:
"batch"` form answers. All entries of one body must name the same
`api_version`, or name none and inherit the body's, and a body whose entries
disagree is refused whole. For a top-level array the first entry to name a
served version of 3 or above decides, and for a `method: "batch"` body the
first entry to name a version the server serves does, wherever that entry
sits, so the order of the entries does not matter; a `method: "batch"` body
naming a version the server cannot serve at its own top level is refused
rather than served at version 1. A body refused before it has named a
version is answered as version 1, so neither a malformed `params` nor the
first entry decides the shape of the refusal. One body then has one version.
A `method: "batch"` body holding more than 100 entries is refused at every
API version, after the version scan, so the refusal takes the shape the
body's version selects: a version 3 body answers the error object and an
earlier version the plain text `Batch has too many entries`. The top-level
array form takes the same limit, checked before its entries are read.

Refusing a mixed body is a break a version 1 or 2 client can see, recorded
as such in `API-CHANGELOG.md`. A `method: "batch"` body whose entries name
different versions is served today, each entry at its own version, and is
refused from now on, as is one whose top level names a version its entries
disagree with, where the top-level value was ignored; one whose entries
agree, with each other and with any top-level version, keeps working when it
holds 100 entries or fewer, and one holding more is refused at every
version.

Five conditions reject a whole array: empty, over the cap, holding nothing
that could be a request, naming no served version of 3 or above, and
naming two different served versions across its entries. Four answer one
specification error object with a null `id`, an array naming none; an array
holding nothing that could be a request answers one such object per entry,
as the specification shows. Each reaches every API version, since no earlier
version accepts an array.
2026-10-25 13:28:03 -04:00
Bart 1b16b17364 feat: Return the JSON-RPC 2.0 envelope on the WebSocket transport
The specification envelope reaches only the JSON-RPC transport, so API
version 3 answers in two shapes depending on which transport carried the
request. Shape the WebSocket reply the same way, reading `id` from the flat
message object rather than from `params`. The reply keeps one extra member,
`"type": "response"`, since a session also receives server-initiated
messages on the same connection and `type` is how a client tells the two
apart. The load notice is written inside the result at this version, which
`shapeSpecReply` hoists back to the top level.

Six conditions reject a request before it reaches a handler, and from
version 3 five answer in the specification envelope under the code the
JSON-RPC transport reports for the same condition: a request naming no
method, one naming a method that is not a string, one whose `command` is
not a string, and one naming two different methods are each an invalid
request, and a role the server refuses is forbidden. Those first four
collapse into one bare `missingCommand` token today, so a client naming two
methods is told the command entry is missing. An `id` that is neither a
string, a number nor null is rejected here too, answered with a null `id`
and judged before the role, as on the JSON-RPC transport.

The sixth condition, an unsupported `api_version`, keeps the legacy shape,
since the server cannot know which envelope such a client speaks. Below
version 3 all six are unchanged. The jtx WebSocket client gains `invokeRaw`,
which returns a reply as it arrived, and `invoke` rewrites a version 3 reply
into the legacy shape so a test can assert one shape across versions.
2026-10-25 13:28:02 -04:00
Bart a9241a02f0 feat: Return a JSON-RPC 2.0 envelope from API version 3
API version 3 answers the JSON-RPC 2.0 specification's shape on the
JSON-RPC transport: `jsonrpc` and the request's `id` at the top level, the
payload under `result`, and a failure under `error` as {code, message,
data}. Three helpers write it, one for the members every reply carries, one
for a pre-dispatch rejection and one for a handler result, so a completed
request and a rejection name the protocol and correlate with their request
the same way. A rejection reports one of the specification's codes. For the
three codes whose message the specification fixes, Invalid Request, Method
not found and Invalid params, `message` is that text and `data` carries the
server's reason as a string; the other codes, which the specification does
not define, report the reason as the message and write no `data`.

An XRPL error is an application-level failure of a well-formed call, so it
reports the reserved implementation-defined code and carries its own token
and code inside `data`, with the handler's text as the message. A method the
server does not have is the exception: the specification defines a code and
a message for that condition, so the token selects the code, `message` is
the fixed text, and the handler's text sits under `data.error_message`. From
version 3 a present `params` must be an object or an array: `null`, a
string, a number or a boolean answers Invalid params with `params
unparsable`, where earlier versions read `null` and an empty string as an
empty parameter object and still do. An `id` the specification does not
allow is answered with a null one rather than echoed, and is judged before
the role and method checks, so a client is told about its id whatever it
asked for. `reject` charges the fee itself, and the two rejections that must
not charge say so. `removeMember` moves the erased value out rather than
copying it, which `hoistNotices` relies on for every notice it moves.

Versions 1 and 2 are untouched, the envelope being selected by
`api_version` and version 3 needing `[beta_rpc_api]`. Four jtx helpers let
a test assert one payload shape across every version, and
`xrpl.jtx.TestHelpers` pins them.
2026-10-25 13:28:02 -04:00
Bart e18621e923 feat: Read a request's version at its top level from API version 3
The version a request asks for is read from its parameters, where a client
puts it, and for a `method: "batch"` entry from the entry's own top level
too, since that form carries it beside its method. The JSON-RPC 2.0
specification puts a request's own members beside `method`, so a lone
request may spell `api_version` there as well. One helper states where a
request keeps its version, so the two reads share one answer. The sign and
submit paths that read the version out of the parameters again take the
one already selected instead, so a handler and its checks agree.

Two things a client can observe. A lone request's top-level `api_version`
is now honored, but only from version 3 up: a top-level `api_version: 2`
answers as version 1, as does one the server cannot serve, so honoring
either would change a shipped reply shape. And for a `method: "batch"`
entry, the one shape whose top-level version was already read, the
precedence reverses: the value with the parameters now decides, where the
top-level one previously decided whenever the nested one resolved to
version 1.
2026-10-25 13:28:02 -04:00
Bart e6971b9eab fix: Serve every subscription on a connection at one API version
`InfoSub` holds one `apiVersion_` field and every `subscribe` or
`path_find` call overwrites it, so a connection subscribing two streams in
two calls at two `api_version`s has both served at whichever ran last. A
webhook subscriber is keyed on its url alone, so two admins naming one url
share one `InfoSub` and each call reselects the other's content. Two changes
together: a subscription records the version its `subscribe` named, so no
publisher reads a version off a shared object, and `doSubscribe` refuses a
`subscribe` naming a version different from the one this connection
established, answering `apiVersionConflict`, at HTTP 400 where the envelope
derives the status from the error, and registering nothing.

Refusing removes an impossible choice at publish time: one message can reach
a connection through several of its subscriptions, and one message has one
shape. The version is established and compared inside `doSubscribe` and
nowhere else, so a check in the general request path would pin every request
a connection sends. The check runs before any stream is registered, so a
`subscribe` refused further down, for a stream name the server does not
have, still fixes the version; the refusal message speaks of what the
subscriber is served at rather than of what it holds. `path_find` records
its version on the `PathRequest` instead; nothing reads that record until a
later commit shapes the update. `InfoSub::assignId` returns the 64-bit
counter it reads, where it narrowed the value to `int`.

A client sees a second `subscribe` at another version refused where it used
to succeed and reshape the first subscription, and a shared webhook url is
now first-writer-wins. An ordinary request is unaffected, naming its own
version and being answered at it.
2026-10-25 13:28:01 -04:00
Bart 4251071ef1 refactor: Take an ErrorCodeI in LedgerEntryHelpers, not a token string
The `ledger_entry` helpers report a `malformed*` token as a bare string a
caller types by hand, so a typo compiles cleanly and is caught only at run
time, by a `LedgerEntry_test.cpp` case that reaches that site. Take an
`ErrorCodeI` and derive the token from it through `getErrorInfo`, so a
token cannot be misspelled and comes from one table rather than a literal
per call site. Choosing the wrong code remains the caller's
responsibility, the parameter being the whole unscoped enum, and the token
a test expects is what catches it.

No reply changes. These helpers still report `RpcInvalidParams` (31) for
every token they name, because a version 1 or 2 client has read 31 for all
of them for years. Reconciling a token with the code that belongs to it
will be the version 3 envelope's job, through `codeForToken`, which a
later branch gives its first caller.

The three helpers that build an error and the eight that forward to them
gain docstrings, replacing the block comment that covered the family. The
guard on `parseDirectoryNode`'s `owner` arm goes: the check above it
requires exactly one of `owner` and `dir_root` and the `dir_root` arm
returns, so the guard was always true and the error after it unreachable.
2026-10-25 13:28:01 -04:00
Bart 6823a9c729 feat: Look up the error code that owns a token
One handler reports an error token whose own code it cannot use, because
changing `error_code` breaks clients matching on the old value: the
`ledger_entry` helpers name fifteen `malformed*` tokens and report
`invalidParams` (31) for all of them. Reconciling that at the reply
envelope needs the reverse of `getErrorInfo`, and fourteen of the fifteen
have no `ErrorCodeI` entry at all, so `getErrorInfo` resolves none of them.
`malformedRequest` is the exception, already holding 107.

Add a code for each of the fourteen, alphabetical by token, since an
append-only enum can only be ordered at introduction. Then add
`codeForToken`, which scans the table and answers `RpcUnknown` for a token
no entry names. The scan compares against views measured at compile time
rather than the table's own `char const*`, since comparing a view with a
pointer measures the pointer first and would call strlen on every entry it
passes. A compile-time assertion makes a duplicate token a build error
rather than a lookup reporting one of two codes. Four comments in the two
files spelled `rpcLAST`, `rpcSUCCESS` and `rpcUNKNOWN` where the
enumerators are `RpcLast`, `RpcSuccess` and `RpcUnknown`; they spell the
enumerators now.

Nothing on the wire changes: the helpers still report `invalidParams`, so
this only reserves the numbers a later API version reports. The first
caller of `codeForToken` is the version 3 reply envelope, which a later
branch adds.
2026-10-25 13:28:01 -04:00
Bart dcf03f9d2d fix: Charge for a request the server rejects before it can read it
Seven conditions reject a request without charging for it. Five reject a
whole body before the server reads a request out of it: over the size
limit, unparsable, carrying no document, not a JSON object, or a
`method: "batch"` naming no entry array. Two sit inside the batch loop: an
entry that is not an object, and one naming an API version the server does
not serve. Free is what makes a rejection worth repeating, so a client can
send nothing else and never exhaust its allowance. The WebSocket transport
has the same hole for a frame that does not parse, which is answered before
`processSession`, where every other frame is charged.

Charge all of them what a malformed request costs: the HTTP conditions
through two helpers over a third naming the resource entry a request pays
from before its role is read, and the WebSocket frame where it is answered.
The role comes from whatever credentials the request presents, so a
privileged connection stays unlimited. Only one helper reports whether the
charge crossed the drop threshold, and it asks only where its caller can
act on the answer: `disconnect` is a mutator that charges the drop fee and
counts a drop on every call made while the balance is at or above the drop
threshold.

The answer to each rejection is unchanged, except that a WebSocket
connection over the drop threshold is closed rather than answered. What
changes is that a `method: "batch"` body now stops at the first entry the
connection is too loaded to serve, where it previously answered every
entry, so the reply array can be shorter than the request array.
2026-10-25 13:28:00 -04:00
Bart 4a0d2e74a5 fix: Accept a request's parameters by name
A JSON-RPC 2.0 request names its parameters in one of two ways: by
position, where `params` is an array holding the one object a handler
reads, and by name, where `params` is that object itself. Only the
positional form is accepted, so the named form is rejected with HTTP 400
and `params unparsable`. Accept both. One helper states where a request
keeps its parameters, so the version read, the role check and the handler
share one answer.

Two things a client can observe. The named `params` form is served, at
every API version, and the `api_version` and credentials it carries are
read as the positional form's are. And a `method: "batch"` entry carrying
a `params` member is read for its version and credentials from that
object and dispatched on it, exactly as a lone request is; an entry
naming no `params` is dispatched as before. Before, only its
`api_version` was read from the entry's top level and its credentials
were ignored.
2026-10-25 13:28:00 -04:00
Bart acbaadbb62 fix: Keep the connection's identity for every entry of a batch
`X-User` and the forwarded-for address are assigned by the connection's
header, so they belong to the connection rather than to one entry of a
`method: "batch"` body. The loop clears them in place for an entry whose
own role is neither identified nor proxied, and a `std::string_view`
shortened in place stays shortened, so the first such entry decides them
for every entry after it. A later entry's role is read from that same
value, so it is demoted along with the username.

Read them into two entry-scoped views instead and hand those to the
handler's context, so the clearing reaches only the entry it belongs to. A
lone request is unaffected, there being no entry after it.

What a client can observe: a body whose first entry presents admin
credentials made the second report no username, where the same entry sent
alone reports the connection's. Every entry of one body now reports the
role and username it would report alone.
2026-10-25 12:06:15 -04:00
Bart cf268a8a61 fix: Name the reason a body is rejected before it is read
Four conditions reject a request body before the server reads a request out
of it, and all four answer `Unable to parse request: ` followed by whatever
the reader recorded. Only one is a parse failure, so for the other three
the reader recorded nothing, the text ends at the colon, and the reply
names a cause that is not theirs while giving no reason at all.

Answer each with its own reason instead. A body over the size limit answers
`Request is too large`, a body that does not parse keeps the parse heading
and the reader's reason after it, a body that parses but carries no
document answers `Request is empty`, and a document that is not a JSON
object answers `Request is not a JSON object`. The status stays 400 for all
four, and this reaches every API version, an unreadable body naming none.

Splitting one condition into four also makes the existing order visible:
the size is checked before the parse, so an oversized body is rejected
without being read.
2026-10-25 12:06:14 -04:00
Bart b6531dd532 fix: Select the reply envelope from a ripplerpc the server supports
The `ripplerpc` version is read in three places: twice inside the dispatch
loop to pick the error shape, and once after it to derive the HTTP status
by re-reading the version off the finished reply. Replace all three with
one `shapeReply` keyed by an `RpcVersion` enum naming the three envelopes.
The version is read once per request and passed in, and the status is
returned rather than read back, since only the function that wrote the
shape knows where the code went.

The version is now matched exactly against the three valid spellings, where
the `ripplerpc` string was compared with `>=` against "2.0" and "3.0", so
"abc" read as version 3 and "10.0" as version 1. Junk from an
unauthenticated client therefore chose an envelope, and at version 3 chose
real HTTP error codes. Anything but the three exact values is rejected with
a 400, the malformed-RPC fee and -32602, which is a break for API versions
1 and 2 on the JSON-RPC transport, listed under a breaking-changes heading
of its own in the changelog. The JSON reader now refuses a string holding
a NUL, escaped or raw: `json::Value` keeps a string only through its first
NUL, so "3.0\u0000junk" would otherwise match as "3.0". That reaches every
string field on every transport, so the changelog lists it as well.

Hoisting the log statement above the shape branch fixes a second defect. It
read `error_message` after the version 2 and 3 branch renamed that member
to `message`, and reading a missing member non-const puts it back as an
explicit null, so an error reply carried `"error_message": null` exactly
when the `Server` log partition wrote at debug.
2026-10-25 12:06:14 -04:00
Bart ed9f859059 refactor: Answer every pre-dispatch rejection through one helper
Nine conditions reject a request before it reaches a handler, and seven
of them write their reply twice over: once as a plain-text body with an
HTTP status for a lone request, and once as an error object appended to
the reply array for a batch entry. The same fix has to be made seven
times, and another condition means another copy. Collapse them into one
`reject` helper that answers either shape and reports whether the loop has
more to do, so a caller reads `if (!reject(...)) return; continue;`.

Each shape is preserved exactly, including the asymmetry. Two of the nine
return the entry under `request`: the one naming an `api_version` the
server cannot serve, which asks for that shape through `wrapRequest`, and
an entry that is not an object, which stays inline, having no members to
carry an error. Six carry the error beside the entry's own members, and
`params unparsable` reaches a lone request only, that form's entries being
flat.

No reply changes. The codes these paths report are declared in
protocol/JsonRpc.h beside the protocol version, so the four file-local
copies go. The header declares every JSON-RPC error code this server
reports as one set, so three of them, `kJsonRpcInvalidRequest`,
`kJsonRpcInvalidParams` and `kJsonRpcServerError`, have no user until a
later branch reports them. The consumer now comes from
`requestInboundEndpoint`, which the WebSocket upgrade path already uses,
leaving the overload check as a condition beside the others rather than
nested inside endpoint construction. Two tests pin the shape a rejected
batch entry keeps: a null `method` reports `-32601` with `Null method`,
and an entry that is not an object is echoed under `request`. The suite
gains `overloadEndpoint`, which charges an address past the drop
threshold, for the privileged-request case.
2026-10-25 12:06:13 -04:00
Bart efad8c63b9 fix: Write a status line for every HTTP status a reply can report
`httpReply` names each status in a switch with no `default:` arm, and the
error table names two statuses that switch does not spell out: 402 for
`highFee` and 502 for `dbDeserialization`. A reply reporting either writes
no status line at all, so its first line is a header and the whole thing
is not an HTTP response. A client parsing it reads a protocol error rather
than the error the server meant to report.

Add the arm, taking the reason phrase from beast, which knows the whole
status registry, and drop the `bugprone-switch-missing-default-case`
suppression the omission needed. Eight of the arms above it then spell out
exactly what that arm produces, so they go. Three stay: 401 and 503 report
a phrase of this server's own, and 200 is what every successful reply
carries, so its line stays a compile-time literal rather than a
`std::format` call on the server's most common path.

Both statuses are reachable today through the `ripplerpc: "3.0"` envelope,
which derives the status from the error code. A gtest pins the status line
for every status this server sends, walks the error table, and reads the
placeholder line for a number the registry does not know, so a row added
with a new status cannot reintroduce the defect. A `sign` request whose
fee ceiling is zero reports `highFee` through that envelope, so the server
suite reads the 402 line end to end.
2026-10-25 12:06:13 -04:00
Bart f4473147b7 fix: Give handler-specific RPC errors a code and message
Thirteen sites across five handlers assign `jss::error` a bare token,
skipping the `error_code`/`error_message` pair `rpc::injectError` sets.
Both consequences are visible on the wire: with no `error_code` the HTTP
status defaults to 200, so a load balancer sees success for a failed
request, and the version 2 envelope copies the pair unconditionally, so a
missing source produces an explicit `"code":null`/`"message":null`. Give
those tokens rows of their own, codes 100 to 109, and route every site
through `injectError`, preserving the `error_exception` detail `submit`
and `simulate` attach. `transaction_entry` keeps its four errors in the
handler's output as an rpc-spec `Status`, and `writeResult` reports each
through the status bridge, so the code and message land beside the ledger
fields the reply carries.

The `ledger_entry` helpers still report `invalidParams` (31) rather than
each token's own code. A version 1 or 2 client has read 31 for those tokens
for years, so changing it would break a client matching on the old value; a
comment on the helpers says so. Every test that expected one of the thirteen
sites to report no code, among them each `submit` test that reads
`invalidTransaction`, now expects the new code and message. The server test
reaches a coded error on four of the five handlers. `ledger_accept` reports
`notStandAlone` only on a networked server, which no test harness provides,
so that arm is excluded from coverage with a comment saying why. The
`submit` arm that checked `Transaction::getStatus` after construction is
removed: the constructor sets the status to NEW unless
`STTx::getTransactionID` throws, and that function returns a cached member,
so the arm could not be reached.

The `submit` and `simulate` arms reporting an internal error take no
coverage exclusion. `internalSubmit` is reached through a test-owned
`NetworkOPs` double whose `processTransaction` throws, handed to the handler
through the context it already takes. The two remaining catch blocks,
`internalJson` in `submit` and `internalSimulate`, are live, reached once
`Transaction::getJson` or the simulation throws, and no injection seam
exists for them today, so that gap belongs in the test list rather than
behind a marker that hides it. Two more exclusions in `Simulate.cpp` go, on
arms that are live as well: the `Account` type check, which a numeric
`Account` reaches and a new `simulate` case sends, and the fallback
`engine_result` arm, which gets a comment saying why it stays.
2026-10-25 12:06:12 -04:00
Bart fabd2070bd fix: Give every error code an HTTP status
Four rows of the error table name no HTTP status, so the `ErrorInfo`
constructor defaults them to 200. The `ripplerpc: "3.0"` envelope derives
the status from the code, so a reply reporting an error claims success
and anything reading the status, a load balancer above all, reads success
too. Give all four one: `actNotFound` answers 404, matching every
`*NotFound` sibling but `entryNotFound`, and `actMalformed`,
`alreadyMultisig` and `alreadySingleSig` answer 400. Then drop the
constructor that defaulted a status, so no row can omit one again. A gtest
lists by hand the codes that have no row, so an enumerator added without
one fails it, and asserts that every other code names a status other than
200.

No client reads a new status here. `legacyHttpStatus` reports 200 for
exactly those four rows, so the 3.0 envelope answers what it always has.
That list is closed, naming the rows that had no status of their own, so
a row added later reports whatever the table says. The test suite names
the two statuses it compares against most, 200 and 400, as `kOk` and
`kBadRequest`, and every existing assertion on them uses the name.
2026-10-25 12:06:11 -04:00
Bart 1f2a0d7991 style: Realign the error table
The columns of the error table had drifted apart as rows were added, so a reader scanning it follows a ragged edge and a new row has no alignment to copy. Realign all four columns on one set of widths inside the existing `clang-format off` guard, changing no row's content.
2026-10-25 12:06:11 -04:00
Bart 73611f8b20 fix: Mask every credential the server echoes, logs or prints
An error reply echoes the request that caused it, and masking covers four
fields at the top level of an object only. A `secret` nested inside
`params`, where the JSON-RPC transport puts it, comes back in the clear,
as does every other credential field at any depth, and only two sites
mask at all. Collect the names in one list and mask recursively, so
nesting stops mattering and a new field is added once. The list covers
the six names only a reply carries, which is how `wallet_propose` and
`validation_create` wrote a live key to the log; `validation_key` is the
same seed as `validation_seed` in RFC1751 words.

A log is an echo that outlives the reply, so one `loggable()` helper
masks and truncates together and every site that writes a request or a
reply out uses it, the `[rpc_startup]` command and its result included,
and the command line client logs the reply it receives parsed and
masked where it wrote the raw body, a `validation_create` answer among
them, and caps a body it cannot parse at the same length. An
`[rpc_startup]` line that does not parse was echoed raw at fatal, the
one case masking cannot reach, and then run as whatever the parser had
left; it is now reported by position only, since the parser's message
can quote a rejected number verbatim, and skipped. The `HTTP Reply` trace line in libxrpl, which cannot reach the
masker, now carries the status only; the body is logged beside it at
debug, masked when it carries a credential and otherwise as the string
already built for the wire, so a reply with no credential is serialized
once. No site logs an inbound request body at full length, so the method name,
at most the request size limit long, is the one thing a client chooses the
length of in the log. The request-duration line used to climb to warn
and error for a slow request with the request in it; the duration alone
still climbs, and the request stays at debug, so the duration line never
lifts text an anonymous client wrote to the default severity.

Three changes are visible to a caller. A credential in an echoed request
reads `<masked>` wherever it appears, nested inside `params` or a batch
entry too. The command line client masks `request_sent`, which carries
the `admin_password` it copies out of the config, so a failing
`./xrpld account_info rBogus` no longer prints a credential the operator
never typed. And a WebSocket frame that does not parse is answered with
its `size` rather than its body.
2026-10-25 12:06:10 -04:00
Bart 297f255988 refactor: Declare the JSON-RPC and ripplerpc version constants
`ripplerpc`, which selects the reply envelope and accepts three values,
and `jsonrpc`, which names the JSON-RPC protocol version, are spelled as
literals at every call site, so neither field has one place stating what
it accepts. Declare `kRippleRpcVersion1/2/3` beside the `api_version`
constants in ApiVersion.h and `kJsonRpcVersion` in a new
protocol/JsonRpc.h, and use them at every production site that reads
a value: the one in RPCCall.cpp that reads the pair, and the three in
ServerHandler.cpp that default, compare and gate on `ripplerpc`. Every
test site spelling a value as a C++ expression follows. A literal inside
a JSON string fixture is left alone, since substituting there means
assembling the JSON by concatenation. The three `ripplerpc` constants
are declared as one set, so the header states every value the field
accepts, and each has a production user in ServerHandler.cpp.

The two fields keep separate constants and separate headers although
both spell "2.0" today. The specification fixes `jsonrpc` at that value
while `ripplerpc` accepts three, and the `ripplerpc` constants go when
support for API versions 1 and 2 goes, where JSON-RPC is a protocol this
server keeps speaking.

ApiVersion.h's header comment named five constants by unprefixed
spellings that no longer exist, and read as a complete map of the file's
version constants, which it stops being here. Two jtx helpers,
`hasEnvelope2` and `setEnvelope2` in TestHelpers.h, replace the
assertion pair and the request pair that every rewritten test site
repeated. No value changes, on the wire or in a test.
2026-10-24 08:49:56 -04:00
Bart 89c01342c5 refactor: Let json::Value be compared and constructed from a string view
`json::Value` accepts `char const*`, `std::string` and
`json::StaticString`, so a caller holding a `std::string_view` has to
materialize a `std::string` whose characters are then copied a second
time into the value's own storage. Add the missing constructor, which
the `std::string` one delegates to, and an `operator==` that reads the
value's characters in place.

The comparison is constrained to `std::string_view` exactly rather than
taking a view by plain overload. A string literal converts equally well
to a view and to a Value, so a plain overload makes every
`value == "literal"` ambiguous, and a literal `0`, which converts to a
view through `char const*` as well as to a Value, with it.

No reply changes. The two spellings differ only for a view holding an
embedded NUL, which the Value comparison stops at. The `method: "batch"`
check in `ServerHandler.cpp` is the operator's first production user, so
that comparison stops building a `Value` from the literal on every
request.
2026-10-24 08:49:55 -04:00
Bart 8f49ff629d refactor: Remove a publish loop nothing can enter
`pubProposedAccountTransaction` declares an `accountHistoryNotify` vector,
never inserts into it, and then tests it and iterates it. The vector is a
local, so the proof is the function itself: between the declaration and the
loop there are exactly two mentions of it, the condition and the loop, and
neither adds an element. Its sibling `pubAccountTransaction` fills its own
copy, which is what makes the empty one here read as live code.

The compiler corroborates it: with the loop gone the message becomes
`MultiApiJson const`, which is possible only because that loop was its sole
mutator. Nothing is lost with the assertion above the loop either. It held
that a `transJson` result carries no member named `account_history_tx_stream`.
No code writes one: outside the two assertions, the token appears in the
`subscribe` and `unsubscribe` request handlers only. The identical assertion
stays where the loop it guards is live.

No subscriber sees a difference. An account-history subscription is
registered in `subAccountHistory_` alone, so it was never in the map this
function reads, and it receives its transactions from
`pubAccountTransaction`. The same function's guard on three subscription maps
also goes: an earlier return leaves `subRTAccount_` non-empty, so the
condition cannot be false.
2026-10-24 08:49:54 -04:00
Ayaz Salikhov 1f46f75318 build: Don't apply clang-tidy fixes twice via header symlinks (#8636) 2026-10-23 19:28:52 +00:00
Ayaz Salikhov 097cb5e89b fix: Update images/prepare-runner to not trust eMudhra certs (#8631) 2026-10-22 18:05:38 +00:00
a818f25203 refactor: Retire XRPFees amendment (#7349)
Co-authored-by: Mayukha Vadari <[email protected]>
Co-authored-by: Valentin Balaschenko <[email protected]>
Co-authored-by: Ayaz Salikhov <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-22 17:11:24 +00:00
3fa2accfdf refactor: Retire AMM amendment and AMMOverflowOffer fix (#7357)
Co-authored-by: Bart <[email protected]>
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
2026-10-22 15:27:46 +00:00
Ayaz Salikhov d3a71b2b42 fix: Don't trust eMudhra certificates (#8629) 2026-10-22 15:01:37 +00:00
Timothy Banks 025aa71930 refactor: Retire FillOrKill fix (#7366) 2026-10-21 16:12:29 +00:00
Mayukha Vadari ef5064eeb9 feat: Remove XChainBridge feature (#8255) 2026-10-20 20:37:02 +00:00
Alex KremerandAyaz Salikhov c2e739f670 refactor: Migrate handlers to rpc-spec (E) (#8613)
Co-authored-by: Ayaz Salikhov <[email protected]>
2026-10-20 15:39:27 +00:00
Alex Kremer 15fac6250d chore: Simplify account and ident checks via rpc-spec (#8620) 2026-10-20 13:25:47 +00:00
Alex KremerandAyaz Salikhov 3608433514 test: Check error consistently in rpc handlers (#8604)
Co-authored-by: Ayaz Salikhov <[email protected]>
2026-10-19 16:17:30 +00:00
Nik Bougalis 7939339a65 chore: Fix an issue that breaks CLion (#8619) 2026-10-17 22:43:53 +00:00
4ea2db2eda feat: Add TransactionProposal invariants for Cosign (#8130)
Co-authored-by: Shawn Xie <[email protected]>
Co-authored-by: Kassaking7 <[email protected]>
Co-authored-by: Shawn Xie <[email protected]>
Co-authored-by: Zhiyuan Wang <[email protected]>
Co-authored-by: Claude Fable 5.1 <[email protected]>
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
2026-10-16 20:59:53 +00:00
Ayaz Salikhov d4ffe32534 ci: Fix release/staging branches running conditions (#8615) 2026-10-16 17:06:19 +00:00
Gregory Tsipenyuk 7354816f65 fix: Assorted MPT/DEX offer related fixes - 1 (#8468) 2026-10-16 16:28:05 +00:00
Gregory Tsipenyuk 12cb3932f3 fix: Check vault share freeze at MPT strand endpoints (#8478) 2026-10-16 15:26:00 +00:00
Gregory Tsipenyuk dc64a8daac fix: Allow IOU rounding in Clawback invariant balance check (#8475) 2026-10-16 15:25:03 +00:00
Nik Bougalis dc524e9cc6 refactor: Optimize the binary layout of Number (#8550) 2026-10-16 15:20:01 +00:00
Alex KremerandAyaz Salikhov 4060b1bcd4 refactor: Migrate handlers to rpc-spec (D) (#8573)
Co-authored-by: Ayaz Salikhov <[email protected]>
2026-10-16 14:06:30 +00:00
Mayukha Vadari bfbb440fc2 feat: Handle Smart Escrow's Bytecode, Data and Gas fields (#8215) 2026-10-16 13:03:48 +00:00
BartandBart 4087861411 fix: Refuse to walk an invalid SHAMap in getMissingNodes (#8086)
Co-authored-by: Bart <[email protected]>
2026-10-16 05:47:08 +00:00
BartandBart dc43faafed fix: Refuse to make an invalid SHAMap or Ledger immutable (#8085)
Co-authored-by: Bart <[email protected]>
2026-10-16 05:47:07 +00:00
6af97c07d9 fix: Report a node the sync path refuses as invalid data (#8084)
Co-authored-by: Bart <[email protected]>
Co-authored-by: Claude Fable 5.1 <[email protected]>
2026-10-16 05:47:06 +00:00
4c7d920e66 fix: Make the SHAMap sync-path state atomic (#8083)
Co-authored-by: Bart <[email protected]>
Co-authored-by: Claude Fable 5.1 <[email protected]>
2026-10-16 05:47:06 +00:00
yinyiqian1 8b59d9d307 docs: Add todo comment for key rotation zkproof (#8589) 2026-10-16 00:11:06 +00:00
b0fa295595 fix: Judge a header's account hash on both acquisition routes (#8476)
Co-authored-by: Bart <[email protected]>
Co-authored-by: Claude Fable 5.1 <[email protected]>
2026-10-15 21:00:21 +00:00
BartandBart 9af432cb0e fix: Signal every InboundLedger failure found in local data (#8082)
Co-authored-by: Bart <[email protected]>
2026-10-15 21:00:20 +00:00
BartandBart 4435ca4cbf refactor: Add a reusable peer harness for acquisition tests (#8310)
Co-authored-by: Bart <[email protected]>
2026-10-15 21:00:19 +00:00
Olek cd72a11786 refactor: TxQ (#8064) 2026-10-15 18:11:46 +00:00
Peter Chen b398b88385 fix: Reject a zero credential ID in deposit_authorized (#8533) 2026-10-15 18:11:18 +00:00
Olek 31f6f90206 feat: Add IssuerMirrorEncryptionKey and InitialIssuerEncryptionKey (#8325) 2026-10-15 18:04:29 +00:00
Olek 1d8c2f9172 test: Sponsor checkSign additional tests (#8331) 2026-10-15 18:03:48 +00:00
f105418bdb feat: Book FixedPrecision LoanPay and LoanManage (#8271)
Co-authored-by: Jingchen <[email protected]>
Co-authored-by: Alex Kremer <[email protected]>
2026-10-15 18:02:36 +00:00
Ayaz Salikhov 4a134eb883 docs: Clarify OS and toolchain requirements (#8588) 2026-10-15 17:58:11 +00:00
Ayaz Salikhov ec3f251ad8 ci: Fix running pre-commit after clang-tidy (#8601) 2026-10-15 16:15:35 +00:00
Mayukha Vadari 5faa861226 feat: Add Smart Escrow fee voting (#8214) 2026-10-15 15:50:16 +00:00
Jingchen 88fd1222d6 build: Fix unity build by addressing name clashes (#8599) 2026-10-15 12:59:20 +00:00
Ayaz SalikhovandEd Hennis f1ce9449f2 fix: Skip bootstrap DNS lookups in standalone mode (#8583)
Co-authored-by: Ed Hennis <[email protected]>
2026-10-14 21:02:45 +00:00
Timur Yalymov 7237b3321c fix: Charge transfer fee on third-party vault withdrawals (#8267) 2026-10-14 16:35:42 +00:00
Timur Yalymov 84d980d883 fix: Reject VaultClawback with a nonexistent holder (#8470) 2026-10-14 14:29:05 +00:00
Timur YalymovandVito Tumas 791c96faad fix: Enforce pseudo-account directory contents with an invariant (#8181)
Co-authored-by: Vito Tumas <[email protected]>
2026-10-14 13:51:24 +00:00
Ayaz Salikhov 31473e7e6d build: Unify clang variables (#8581) 2026-10-14 13:51:05 +00:00
Timur YalymovandVito Tumas aa70b368b5 fix: Enforce asset authorization on LoanBrokerDelete (#8204)
Co-authored-by: Vito Tumas <[email protected]>
2026-10-14 13:51:05 +00:00
Vito TumasandJingchen d3db569b34 feat: Book FixedPrecision LoanSet through AssetsDeployed (#8260)
Co-authored-by: Jingchen <[email protected]>
2026-10-14 13:20:58 +00:00
Vito TumasandJingchen 94d6b7daf8 feat: Round LoanBroker cover on the FixedPrecision grid (#8258)
Co-authored-by: Jingchen <[email protected]>
2026-10-14 12:59:39 +00:00
Vito TumasandJingchen e089abe982 feat: Use FixedPrecision accounting in Vault transactors (#8460)
Co-authored-by: Jingchen <[email protected]>
2026-10-14 12:52:25 +00:00
Alex Kremer 33289e882b refactor: Migrate handlers to rpc-spec (C) (#8561) 2026-10-14 10:15:32 +00:00
1ed0bccb07 fix: Clamp invalid XRP amounts in Quality::ceilOut & getBookPage (#8480)
Co-authored-by: Claude Opus 5.5 <[email protected]>
Co-authored-by: Ed Hennis <[email protected]>
2026-10-14 07:49:27 +00:00
Gregory TsipenyukandEd Hennis 1da55e3989 fix: Waive CanTransfer on loan default and broker delete (#8231)
Co-authored-by: Ed Hennis <[email protected]>
2026-10-14 07:49:12 +00:00
Valentin Balaschenkoandxrplf-ai-reviewer[bot] 166e97e12b refactor: Decouple LedgerHistory from TaggedCache internals (#5874)
Co-authored-by: xrplf-ai-reviewer[bot] <266832837+xrplf-ai-reviewer[bot]@users.noreply.github.com>
2026-10-13 23:33:32 +00:00
33e5a6fa7c feat: Add TransactionProposalCancel & Cosign Ticket reservation (#8538)
Co-authored-by: Shawn Xie <[email protected]>
Co-authored-by: Kassaking7 <[email protected]>
Co-authored-by: Shawn Xie <[email protected]>
Co-authored-by: Zhiyuan Wang <[email protected]>
Co-authored-by: Claude Fable 5 <[email protected]>
2026-10-13 19:07:45 +00:00
Ayaz Salikhov b1f9dc6919 ci: Fix rpm installation problems (#8575) 2026-10-13 18:46:41 +00:00
Ayaz Salikhov 38965af055 docs: Clarify freeze on large changes 2 weeks before first RC (#8574) 2026-10-13 18:43:24 +00:00
Gregory TsipenyukandEd Hennis b010d4a563 refactor: Retire fixAMMv1_1 amendment (#8226)
Co-authored-by: Ed Hennis <[email protected]>
2026-10-13 18:03:10 +00:00
dependabot[bot] eedd6604d1 chore: [DEPENDABOT] bump pyparsing from 3.3.2 to 3.3.3 in /cmake/scripts/codegen in the codegen-dependencies group (#8572)
Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-13 17:48:57 +00:00
Mayukha Vadari 59ff04b648 fix: Allow WASM transactions in simulate only in admin mode (#8568) 2026-10-13 17:39:32 +00:00
Gregory TsipenyukandEd Hennis fcb3ee6425 fix: Detect int64 overflow in XRPAmount and MPTAmount (#8453)
Co-authored-by: Ed Hennis <[email protected]>
2026-10-13 17:35:35 +00:00
Gregory TsipenyukandEd Hennis 77eacbb52c fix: Assorted MPT/DEX offer related fixes (#8211)
Co-authored-by: Ed Hennis <[email protected]>
2026-10-13 17:18:47 +00:00
Vito TumasandJingchen 5ce85b2799 feat: Add FixedPrecision Vault grid and balance helpers (#8257)
Co-authored-by: Jingchen <[email protected]>
2026-10-13 16:19:08 +00:00
Ayaz Salikhov 4538d198e1 build: Update codegen requirements (#8570) 2026-10-13 14:29:59 +00:00
4c39b05f94 fix: Reject vault and lending amounts out of range for the asset (#8527)
Co-authored-by: Vito Tumas <[email protected]>
Co-authored-by: Ayaz Salikhov <[email protected]>
Co-authored-by: Ed Hennis <[email protected]>
2026-10-13 08:46:55 +00:00
BartandBart c2478f509c refactor: Open the acquisition seams its tests need (#8081)
Co-authored-by: Bart <[email protected]>
2026-10-13 03:51:12 +00:00
Mayukha Vadari c908ed7839 fix: Reject malformed conditions in EscrowFinish preflight (#8523) 2026-10-12 20:48:55 +00:00
BartandBart fc57311c81 refactor: Expose a SHAMapAddNode verdict as counts (#8080)
Co-authored-by: Bart <[email protected]>
2026-10-12 20:02:36 +00:00
Mayukha Vadari 818de49264 refactor: Use DepositPreauthEntry everywhere (#8364) 2026-10-12 18:56:14 +00:00
dependabot[bot] 1318b1e58b chore: [DEPENDABOT] bump cxx from 1.0.202 to 1.0.203 in /crates in the rust-dependencies group (#8564)
Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-12 17:23:41 +00:00
Ayaz Salikhov 617c816ec8 chore: Fix readability-trailing-comma (#8545) 2026-10-12 13:57:24 +00:00
dependabot[bot] 34fc86f585 ci: [DEPENDABOT] bump the github-actions group across 1 directory with 2 updates (#8562)
Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-12 12:59:39 +00:00
Ayaz Salikhov e071f0a28d chore: Fix misc-const-correctness (#8546) 2026-10-12 11:44:06 +00:00
Ayaz Salikhov 8faa624ade chore: Update XRPLF/actions to use pip from python3.14 explicitly (#8560) 2026-10-12 10:06:06 +00:00
Ayaz Salikhov 6d6ab2d067 Merge remote-tracking branch 'upstream/release/3.4.x' into develop 2026-10-10 00:20:39 +01:00
Ayaz Salikhov 00e6407514 chore: Bump version to 3.4.1 and make pkg_release 2 2026-10-09 23:50:58 +01:00
Ayaz Salikhov 00c06edffb Merge remote-tracking branch 'upstream/release/3.4.x' into develop 2026-10-09 22:45:18 +01:00
Ayaz Salikhov de5053ae0d build: Reduce number of conan logs (#8548) 2026-10-09 16:33:41 +00:00
Ayaz Salikhov 1940ec5c2a chore: Fix readability-redundant-lambda-parameter-list (#8544) 2026-10-09 16:20:45 +00:00
Denis Angell 19c94c73f4 fix: Reject Batch inner txs with the wrong wrapper (fixBatchV1_2) 2026-10-09 16:04:36 +01:00
Bart cd005ff60d ci: Update Nexus packaging URL 2026-10-09 16:04:36 +01:00
Gregory Tsipenyuk 578224f2e6 fix: Assorted integer-arithmetic hardening in the payment engine and ledger helpers 2026-10-09 16:04:35 +01:00
Shawn Xie 3857ce21cd fix: Change mpt subscription msg type back to transaction (#8539) 2026-10-09 13:33:13 +00:00
Ayaz Salikhov aa490df46b chore: Update clang-tidy image to v23 (#8536) 2026-10-09 10:19:07 +00:00
88c1f1e7ac feat: Integrate Permissioned Domain & Credential Checks for Lending Protocol (#6517)
Signed-off-by: JCW <[email protected]>
Co-authored-by: Vito <[email protected]>
Co-authored-by: Ed Hennis <[email protected]>
2026-10-09 10:18:31 +00:00
Ayaz SalikhovandCopilot Autofix powered by AI ede8af8191 refactor: Group binaries in subdirectories (#8535)
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
2026-10-08 12:34:06 +00:00
Alex Kremer 3c24b605a1 chore: Split multiple-in-one into individual tests (#8025) 2026-10-08 09:57:38 +00:00
Alex Kremer d343b542f1 refactor: Migrate handlers to rpc-spec (B) (#8484) 2026-10-07 13:46:37 +00:00
Ayaz Salikhov 7acd719bf7 build: Use images with Clang 23 except for clang-tidy (#8530) 2026-10-07 13:08:20 +00:00
Ayaz Salikhov b4564d5301 chore: Update pre-commit hooks and image (#8528) 2026-10-07 10:59:37 +00:00
Shawn Xie 60195e6d37 fix: Fix MPT partial payment overflow (#8302) 2026-10-06 23:16:13 +00:00
Ayaz Salikhov 3d526d456e build: Use LLVM 23 (#8522) 2026-10-06 21:19:57 +00:00
Denis AngellandMayukha Vadari f05c9f7913 refactor: Extract escrow lock helpers and paychan test helpers (#7882)
Co-authored-by: Mayukha Vadari <[email protected]>
2026-10-06 19:58:52 +00:00
Harshit GuptaandMayukha Vadari c2a4bc3aa1 fix: Validate vetoed parameter type in feature RPC (#7583)
Co-authored-by: Mayukha Vadari <[email protected]>
2026-10-06 19:44:56 +00:00
Mayukha Vadari 718185e3b2 refactor: Use CheckEntry everywhere (#8349) 2026-10-06 19:26:35 +00:00
Ayaz Salikhov 1d7783bb86 build: Make conan retry with Conan Center's source backups (#8524) 2026-10-06 19:23:38 +00:00
Mayukha Vadari 9fd2c552f5 refactor: Use AmendmentsEntry everywhere (#8368) 2026-10-06 17:59:44 +00:00
Ayaz Salikhov 70b8fd301b chore: Update docker images; link Conan-built tools with a static runtime (#8520) 2026-10-06 16:47:35 +00:00
Mayukha Vadari e6564f553d refactor: Use NegativeUNLEntry everywhere (#8365) 2026-10-06 14:23:24 +00:00
Ayaz Salikhov ed96e60ce3 build: Make clang-tools custom in Nix, to match what's being built (#8521) 2026-10-06 13:59:12 +00:00
Alex Kremer 2ebd745a1b refactor: Migrate handlers to rpc-spec (A) (#8345) 2026-10-06 13:19:20 +00:00
Mayukha Vadari cfcbe45b60 test: Declare, not define, entry instantiations in SLEBase test (#8357) 2026-10-06 12:12:22 +00:00
yinyiqian1andBart 9cbf78ba99 test: Add more tests for granular permissions (#8459)
Co-authored-by: Bart <[email protected]>
2026-10-05 23:18:58 +00:00
Timur Yalymov b8d8738f81 fix: Enforce that MPT issuance flags are never cleared (#8152) 2026-10-05 23:17:36 +00:00
63c97e719f feat: Allow lending transactions in Batch (#8244)
Co-authored-by: Cursor <[email protected]>
Co-authored-by: Vito Tumas <[email protected]>
2026-10-05 23:17:26 +00:00
3ac26f23c7 feat: Add full support for all objects in ledger_entry (#6319)
Co-authored-by: Timur Yalymov <[email protected]>
Co-authored-by: Cursor <[email protected]>
Co-authored-by: Vito Tumas <[email protected]>
Co-authored-by: Ayaz Salikhov <[email protected]>
2026-10-05 23:17:14 +00:00
BartandBart ff9410bc56 build: Define XRPL_ASAN, XRPL_TSAN, and XRPL_UBSAN compile definitions (#8483)
Co-authored-by: Bart <[email protected]>
2026-10-05 23:15:08 +00:00
Mayukha Vadari 1798262d7a refactor: Use LedgerHashesEntry everywhere (#8369) 2026-10-05 18:15:02 +00:00
Mayukha Vadari cd633b9ac9 refactor: Use EscrowEntry everywhere (#8354) 2026-10-05 17:51:18 +00:00
Ayaz Salikhov 5c5f7d315a chore: Update nix flake file (#8479) 2026-10-05 16:58:41 +00:00
Mayukha Vadari 0f7493ce50 refactor: Use FeeSettingsEntry everywhere (#8370) 2026-10-05 16:56:41 +00:00
Harshit Gupta 40f61f828a fix: Add string type validation for channel_id and signature (#7582) 2026-10-05 16:55:14 +00:00
Mayukha Vadari 108277f4b7 test: Migrate three beast suites from beast::unit_test to gtest (#7993) 2026-10-05 15:28:05 +00:00
979 changed files with 69032 additions and 38165 deletions

No files matched your search

+16 -1
View File
@@ -5,7 +5,10 @@ Checks: "-*,
-bugprone-exception-escape, -bugprone-exception-escape,
-bugprone-implicit-widening-of-multiplication-result, -bugprone-implicit-widening-of-multiplication-result,
-bugprone-narrowing-conversions, -bugprone-narrowing-conversions,
-bugprone-signed-bitwise,
-bugprone-std-exception-baseclass,
-bugprone-throwing-static-initialization, -bugprone-throwing-static-initialization,
-bugprone-unhandled-code-paths,
cppcoreguidelines-*, cppcoreguidelines-*,
-cppcoreguidelines-avoid-c-arrays, -cppcoreguidelines-avoid-c-arrays,
@@ -14,6 +17,7 @@ Checks: "-*,
-cppcoreguidelines-avoid-magic-numbers, -cppcoreguidelines-avoid-magic-numbers,
-cppcoreguidelines-avoid-non-const-global-variables, -cppcoreguidelines-avoid-non-const-global-variables,
-cppcoreguidelines-c-copy-assignment-signature, -cppcoreguidelines-c-copy-assignment-signature,
-cppcoreguidelines-explicit-constructor,
-cppcoreguidelines-interfaces-global-init, -cppcoreguidelines-interfaces-global-init,
-cppcoreguidelines-macro-usage, -cppcoreguidelines-macro-usage,
-cppcoreguidelines-missing-std-forward, -cppcoreguidelines-missing-std-forward,
@@ -32,6 +36,7 @@ Checks: "-*,
llvm-namespace-comment, llvm-namespace-comment,
misc-*, misc-*,
-misc-explicit-constructor,
-misc-multiple-inheritance, -misc-multiple-inheritance,
-misc-no-recursion, -misc-no-recursion,
-misc-non-private-member-variables-in-classes, -misc-non-private-member-variables-in-classes,
@@ -45,6 +50,8 @@ Checks: "-*,
-modernize-avoid-c-style-cast, -modernize-avoid-c-style-cast,
-modernize-return-braced-init-list, -modernize-return-braced-init-list,
-modernize-use-integer-sign-comparison, -modernize-use-integer-sign-comparison,
-modernize-use-string-view,
-modernize-use-structured-binding,
-modernize-use-trailing-return-type, -modernize-use-trailing-return-type,
performance-*, performance-*,
@@ -53,6 +60,7 @@ Checks: "-*,
-performance-noexcept-move-constructor, -performance-noexcept-move-constructor,
-performance-unnecessary-copy-initialization, -performance-unnecessary-copy-initialization,
-performance-unnecessary-value-param, -performance-unnecessary-value-param,
-performance-use-std-move,
readability-*, readability-*,
-readability-avoid-const-params-in-decls, -readability-avoid-const-params-in-decls,
@@ -65,7 +73,10 @@ Checks: "-*,
-readability-named-parameter, -readability-named-parameter,
-readability-qualified-auto, -readability-qualified-auto,
-readability-redundant-access-specifiers, -readability-redundant-access-specifiers,
-readability-redundant-nested-if,
-readability-redundant-qualified-alias,
-readability-static-accessed-through-instance, -readability-static-accessed-through-instance,
-readability-trivial-switch,
-readability-uppercase-literal-suffix -readability-uppercase-literal-suffix
" "
# --- # ---
@@ -129,5 +140,9 @@ CheckOptions:
readability-identifier-naming.GlobalFunctionIgnoredRegexp: "^(to_string|hash_append|tuple_hash)$" readability-identifier-naming.GlobalFunctionIgnoredRegexp: "^(to_string|hash_append|tuple_hash)$"
HeaderFilterRegex: '^.*/(tests?|xrpl|xrpld)/.*\.(h|hpp|ipp)$' HeaderFilterRegex: '^.*/(tests?|xrpl|xrpld)/.*\.(h|hpp|ipp)$'
ExcludeHeaderFilterRegex: '^.*/protocol_autogen/.*\.(h|hpp)$|^.*\.pb\.h$' # Skip headers reached via add_module's symlinks (<build-dir>/modules/xrpl.lib*/...).
# verify_headers already checks each one under its real path,
# so reporting it twice would also apply its fixes twice.
# .ipp files are kept: they are only ever reached via the symlink.
ExcludeHeaderFilterRegex: '^.*/protocol_autogen/.*\.(h|hpp)$|^.*\.pb\.h$|^.*/modules/xrpl\.lib[^/]+/.*\.(h|hpp)$'
WarningsAsErrors: "*" WarningsAsErrors: "*"
+3 -2
View File
@@ -103,6 +103,7 @@ words:
- dearmor - dearmor
- decryptor - decryptor
- dedented - dedented
- dedup
- deleteme - deleteme
- demultiplexer - demultiplexer
- deserializaton - deserializaton
@@ -197,6 +198,7 @@ words:
- mptokens - mptokens
- mpts - mpts
- mtgox - mtgox
- mudhra
- multisig - multisig
- multisign - multisign
- multisigned - multisigned
@@ -317,7 +319,6 @@ words:
- sttx - sttx
- stvar - stvar
- stvector - stvector
- stxchainattestations
- summands - summands
- superpeer - superpeer
- superpeers - superpeers
@@ -344,6 +345,7 @@ words:
- unambiguity - unambiguity
- unauthorizes - unauthorizes
- unauthorizing - unauthorizing
- undeserializable
- unergonomic - unergonomic
- unfetched - unfetched
- unfindable - unfindable
@@ -375,7 +377,6 @@ words:
- writeme - writeme
- wsrch - wsrch
- wthread - wthread
- xbridge
- xchain - xchain
- xcrun - xcrun
- ximinez - ximinez
+72
View File
@@ -108,3 +108,75 @@ endfunction()
function(patch_nix_binary target) function(patch_nix_binary target)
endfunction() endfunction()
function(rpcspec_generate_instantiations)
set(options)
set(oneValueArgs OUT_VAR VALUE_TYPE VIEW_HEADER INCLUDE_DIR)
set(multiValueArgs HANDLERS)
cmake_parse_arguments(
THIS_FUNCTION_PREFIX
"${options}"
"${oneValueArgs}"
"${multiValueArgs}"
${ARGN}
)
endfunction()
function(corrosion_import_crate)
set(options
ALL_FEATURES
NO_DEFAULT_FEATURES
NO_STD
NO_LINKER_OVERRIDE
NO_USES_TERMINAL
LOCKED
FROZEN
)
set(oneValueArgs MANIFEST_PATH PROFILE IMPORTED_CRATES)
set(multiValueArgs
CRATE_TYPES
CRATES
FEATURES
FLAGS
OVERRIDE_CRATE_TYPE
)
cmake_parse_arguments(
THIS_FUNCTION_PREFIX
"${options}"
"${oneValueArgs}"
"${multiValueArgs}"
${ARGN}
)
endfunction()
function(corrosion_set_env_vars target_name env_var)
endfunction()
function(corrosion_add_cxxbridge cxx_target)
set(options)
set(oneValueArgs CRATE)
set(multiValueArgs FILES)
cmake_parse_arguments(
THIS_FUNCTION_PREFIX
"${options}"
"${oneValueArgs}"
"${multiValueArgs}"
${ARGN}
)
endfunction()
function(_unlink_libgcc_s crate)
endfunction()
function(add_xrpl_crate name)
set(options)
set(oneValueArgs CRATE)
set(multiValueArgs FILES)
cmake_parse_arguments(
THIS_FUNCTION_PREFIX
"${options}"
"${oneValueArgs}"
"${multiValueArgs}"
${ARGN}
)
endfunction()
+22 -5
View File
@@ -15,9 +15,9 @@ inputs:
required: false required: false
default: "false" default: "false"
log_verbosity: log_verbosity:
description: "The logging verbosity." description: 'The logging verbosity ("quiet", "verbose"), or empty to use the Conan defaults.'
required: false required: false
default: "verbose" default: ""
sanitizers: sanitizers:
description: "The sanitizers to enable." description: "The sanitizers to enable."
required: false required: false
@@ -35,6 +35,16 @@ runs:
LOG_VERBOSITY: ${{ inputs.log_verbosity }} LOG_VERBOSITY: ${{ inputs.log_verbosity }}
SANITIZERS: ${{ inputs.sanitizers }} SANITIZERS: ${{ inputs.sanitizers }}
run: | run: |
# By default, leave the verbosity unset, so CMake configure output is
# shown, but compile commands and Boost's b2 debug output (~85k lines
# when "verbose") are not.
VERBOSITY_ARGS=()
if [[ -n "${LOG_VERBOSITY}" ]]; then
VERBOSITY_ARGS=(
--conf:all tools.build:verbosity="${LOG_VERBOSITY}"
--conf:all tools.compilation:verbosity="${LOG_VERBOSITY}"
)
fi
conan install \ conan install \
--profile:all ci \ --profile:all ci \
--build="${BUILD_OPTION}" \ --build="${BUILD_OPTION}" \
@@ -42,6 +52,13 @@ runs:
--options:host='&:xrpld=True' \ --options:host='&:xrpld=True' \
--settings:all build_type="${BUILD_TYPE}" \ --settings:all build_type="${BUILD_TYPE}" \
--conf:all tools.build:jobs=${BUILD_NPROC} \ --conf:all tools.build:jobs=${BUILD_NPROC} \
--conf:all tools.build:verbosity="${LOG_VERBOSITY}" \ "${VERBOSITY_ARGS[@]}" \
--conf:all tools.compilation:verbosity="${LOG_VERBOSITY}" \ --format=json \
. . >"${RUNNER_TEMP}/conan-graph.json"
# Tools that run during the build may only load glibc from the Nix store,
# as their package ID survives a GCC runtime update.
- name: Check build-context packages for Nix store dependencies (Linux)
if: ${{ runner.os == 'Linux' }}
shell: bash
run: ./bin/nix/check-build-context-runtime.sh "${RUNNER_TEMP}/conan-graph.json"
+15
View File
@@ -36,3 +36,18 @@ updates:
rust-dependencies: rust-dependencies:
patterns: patterns:
- "*" - "*"
- package-ecosystem: uv
directory: /cmake/scripts/codegen
schedule:
interval: weekly
day: monday
time: "04:00"
timezone: Etc/GMT
commit-message:
prefix: "chore: [DEPENDABOT] "
target-branch: develop
groups:
codegen-dependencies:
patterns:
- "*"
@@ -62,6 +62,7 @@ libxrpl.tx > xrpl.protocol
libxrpl.tx > xrpl.server libxrpl.tx > xrpl.server
libxrpl.tx > xrpl.tx libxrpl.tx > xrpl.tx
test.app > test.jtx test.app > test.jtx
test.app > tests.libxrpl
test.app > test.unit_test test.app > test.unit_test
test.app > xrpl.basics test.app > xrpl.basics
test.app > xrpl.config test.app > xrpl.config
@@ -174,8 +175,10 @@ test.server > xrpl.basics
test.server > xrpl.config test.server > xrpl.config
test.server > xrpld.app test.server > xrpld.app
test.server > xrpld.core test.server > xrpld.core
test.server > xrpld.rpc
test.server > xrpl.json test.server > xrpl.json
test.server > xrpl.protocol test.server > xrpl.protocol
test.server > xrpl.resource
test.server > xrpl.server test.server > xrpl.server
test.unit_test > xrpl.basics test.unit_test > xrpl.basics
test.unit_test > xrpl.protocol test.unit_test > xrpl.protocol
+4 -4
View File
@@ -1,5 +1,5 @@
{ {
"image_tag": "sha-060957e", "image_tag": "sha-d3a71b2",
"configs": { "configs": {
"ubuntu": [ "ubuntu": [
{ {
@@ -74,7 +74,7 @@
"extra_cmake_args": "-Dvalidator_keys=ON", "extra_cmake_args": "-Dvalidator_keys=ON",
"package": { "package": {
"type": "deb", "type": "deb",
"image": "ghcr.io/xrplf/xrpld/packaging-debian:sha-3a2d19f" "image": "ghcr.io/xrplf/xrpld/packaging-debian:sha-d3a71b2"
} }
}, },
{ {
@@ -86,7 +86,7 @@
"extra_cmake_args": "-Dvalidator_keys=ON -Dassert=ON", "extra_cmake_args": "-Dvalidator_keys=ON -Dassert=ON",
"package": { "package": {
"type": "deb", "type": "deb",
"image": "ghcr.io/xrplf/xrpld/packaging-debian:sha-3a2d19f", "image": "ghcr.io/xrplf/xrpld/packaging-debian:sha-d3a71b2",
"variant": "assert" "variant": "assert"
} }
} }
@@ -101,7 +101,7 @@
"extra_cmake_args": "-Dvalidator_keys=ON", "extra_cmake_args": "-Dvalidator_keys=ON",
"package": { "package": {
"type": "rpm", "type": "rpm",
"image": "ghcr.io/xrplf/xrpld/packaging-rhel:sha-3a2d19f" "image": "ghcr.io/xrplf/xrpld/packaging-rhel:sha-d3a71b2"
} }
} }
] ]
+4 -4
View File
@@ -12,8 +12,7 @@ on:
- "!nix/docker/README.md" - "!nix/docker/README.md"
- "!nix/devshell.nix" - "!nix/devshell.nix"
- "!nix/check-tools/**" - "!nix/check-tools/**"
- "bin/default-loader-path.sh" - "bin/nix/default-loader-path.sh"
- "bin/install-sanitizer-libs.sh"
pull_request: pull_request:
paths: paths:
- ".github/workflows/build-nix-images.yml" - ".github/workflows/build-nix-images.yml"
@@ -25,8 +24,9 @@ on:
- "!nix/devshell.nix" - "!nix/devshell.nix"
- "!nix/check-tools/**" - "!nix/check-tools/**"
- "bin/check-tools.sh" - "bin/check-tools.sh"
- "bin/default-loader-path.sh" - "bin/check-distrusted-roots.sh"
- "bin/install-sanitizer-libs.sh" - "bin/nix/default-loader-path.sh"
- "bin/install/sanitizer-libs.sh"
workflow_dispatch: workflow_dispatch:
concurrency: concurrency:
+3 -3
View File
@@ -5,13 +5,13 @@ on:
branches: branches:
- develop - develop
paths: paths:
- ".github/workflows/build-packaging-images.yml" - "bin/install/packaging-tools.sh"
- "bin/install-packaging-tools.sh"
- "package/images/packaging/**" - "package/images/packaging/**"
pull_request: pull_request:
paths: paths:
- ".github/workflows/build-packaging-images.yml" - ".github/workflows/build-packaging-images.yml"
- "bin/install-packaging-tools.sh" - "bin/check-distrusted-roots.sh"
- "bin/install/packaging-tools.sh"
- "package/images/packaging/**" - "package/images/packaging/**"
workflow_dispatch: workflow_dispatch:
+1 -1
View File
@@ -5,12 +5,12 @@ on:
branches: branches:
- develop - develop
paths: paths:
- ".github/workflows/build-pre-commit-image.yml"
- "bin/pre-commit/Dockerfile" - "bin/pre-commit/Dockerfile"
- "rust-toolchain.toml" - "rust-toolchain.toml"
pull_request: pull_request:
paths: paths:
- ".github/workflows/build-pre-commit-image.yml" - ".github/workflows/build-pre-commit-image.yml"
- "bin/check-distrusted-roots.sh"
- "bin/pre-commit/Dockerfile" - "bin/pre-commit/Dockerfile"
- "rust-toolchain.toml" - "rust-toolchain.toml"
workflow_dispatch: workflow_dispatch:
+3 -2
View File
@@ -8,6 +8,7 @@ on:
branches: branches:
- "develop" - "develop"
- "release/*" - "release/*"
- "staging/*"
paths: paths:
- "crates/**/Cargo.toml" - "crates/**/Cargo.toml"
- "crates/Cargo.lock" - "crates/Cargo.lock"
@@ -34,7 +35,7 @@ permissions:
jobs: jobs:
audit: audit:
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-060957e container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-d3a71b2
permissions: permissions:
contents: read contents: read
# Needed to open an issue on scheduled failures. # Needed to open an issue on scheduled failures.
@@ -66,7 +67,7 @@ jobs:
- name: Create issue - name: Create issue
if: ${{ steps.audit.outcome != 'success' && github.event_name == 'schedule' }} if: ${{ steps.audit.outcome != 'success' && github.event_name == 'schedule' }}
uses: XRPLF/actions/create-issue@2b8bc36af85b88bca0dd7bfac2e2dc05f94ad712 uses: XRPLF/actions/create-issue@b489c21d53928f7dab4874912fec40e4f6c9e85e
with: with:
title: "cargo audit found vulnerabilities" title: "cargo audit found vulnerabilities"
body_file: /tmp/cargo-audit-issue.md body_file: /tmp/cargo-audit-issue.md
+1 -1
View File
@@ -53,7 +53,7 @@ jobs:
- name: Create issue - name: Create issue
if: ${{ failure() && github.event_name == 'schedule' && github.repository == 'XRPLF/rippled' }} if: ${{ failure() && github.event_name == 'schedule' && github.repository == 'XRPLF/rippled' }}
uses: XRPLF/actions/create-issue@2b8bc36af85b88bca0dd7bfac2e2dc05f94ad712 uses: XRPLF/actions/create-issue@b489c21d53928f7dab4874912fec40e4f6c9e85e
with: with:
title: "Releases not merged back into develop" title: "Releases not merged back into develop"
body_file: ${{ env.ISSUE_FILE }} body_file: ${{ env.ISSUE_FILE }}
+2 -2
View File
@@ -79,7 +79,7 @@ jobs:
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Prepare runner - name: Prepare runner
uses: XRPLF/actions/prepare-runner@b3e255d74d785d053e4903da8ac90983cd7d9e82 uses: XRPLF/actions/prepare-runner@6645b8721d3810be1c59f4180315249e59bf1312
with: with:
enable_ccache: false enable_ccache: false
@@ -108,7 +108,7 @@ jobs:
- name: Upload regenerated snapshot - name: Upload regenerated snapshot
if: failure() if: failure()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with: with:
name: check-tools-${{ runner.os }}-${{ runner.arch }} name: check-tools-${{ runner.os }}-${{ runner.arch }}
path: ${{ matrix.snapshot }} path: ${{ matrix.snapshot }}
+2 -3
View File
@@ -93,9 +93,8 @@ jobs:
.github/workflows/reusable-upload-recipe.yml .github/workflows/reusable-upload-recipe.yml
.clang-tidy .clang-tidy
.codecov.yml .codecov.yml
bin/check-nix-store-refs.sh
bin/check-tools.sh bin/check-tools.sh
bin/default-loader-path.sh bin/nix/**
cfg/** cfg/**
cmake/** cmake/**
conan/** conan/**
@@ -244,7 +243,7 @@ jobs:
- should-run - should-run
- build-test - build-test
# Only run when committing to a PR that targets a release branch. # Only run when committing to a PR that targets a release branch.
if: ${{ github.repository == 'XRPLF/rippled' && needs.should-run.outputs.go == 'true' && github.event_name == 'pull_request' && startsWith(github.event.pull_request.base.ref, 'release') }} if: ${{ github.repository == 'XRPLF/rippled' && needs.should-run.outputs.go == 'true' && github.event_name == 'pull_request' && startsWith(github.event.pull_request.base.ref, 'release/') }}
uses: ./.github/workflows/reusable-upload-recipe.yml uses: ./.github/workflows/reusable-upload-recipe.yml
secrets: secrets:
remote_username: ${{ secrets.NEXUS_REMOTE_USERNAME }} remote_username: ${{ secrets.NEXUS_REMOTE_USERNAME }}
+9 -8
View File
@@ -1,14 +1,16 @@
# This workflow runs all workflows to build and test the code on various Linux # This workflow runs all workflows to build and test the code on various Linux
# flavors, as well as on MacOS and Windows, on a scheduled basis, on merge into # flavors, as well as on MacOS and Windows, on a scheduled basis, on merge into
# the 'develop' or 'release*' branches, or when requested manually. Upon pushes # the 'develop', 'release/*' or 'staging/*' branches, or when requested
# to the develop branch it also uploads the libxrpl recipe to the Conan remote. # manually. Upon pushes to the develop branch, it also uploads the libxrpl
# recipe to the Conan remote.
name: Trigger name: Trigger
on: on:
push: push:
branches: branches:
- "develop" - "develop"
- "release*" - "release/*"
- "staging/*"
paths: paths:
# These paths are unique to `on-trigger.yml`. # These paths are unique to `on-trigger.yml`.
- ".github/workflows/on-trigger.yml" - ".github/workflows/on-trigger.yml"
@@ -31,9 +33,8 @@ on:
- ".github/workflows/reusable-upload-recipe.yml" - ".github/workflows/reusable-upload-recipe.yml"
- ".clang-tidy" - ".clang-tidy"
- ".codecov.yml" - ".codecov.yml"
- "bin/check-nix-store-refs.sh"
- "bin/check-tools.sh" - "bin/check-tools.sh"
- "bin/default-loader-path.sh" - "bin/nix/**"
- "cfg/**" - "cfg/**"
- "cmake/**" - "cmake/**"
- "conan/**" - "conan/**"
@@ -63,9 +64,9 @@ on:
workflow_dispatch: workflow_dispatch:
concurrency: concurrency:
# When a PR is merged into the develop branch it will be assigned a unique # When a PR is merged into the develop branch, it will be assigned a unique
# group identifier, so execution will continue even if another PR is merged # group identifier, so execution will continue even if another PR is merged
# while it is still running. In all other cases the group identifier is shared # while it is still running. In all other cases, the group identifier is shared
# per branch, so that any in-progress runs are cancelled when a new commit is # per branch, so that any in-progress runs are cancelled when a new commit is
# pushed. # pushed.
group: ${{ github.workflow }}-${{ github.event_name == 'push' && github.ref == 'refs/heads/develop' && github.sha || github.ref }} group: ${{ github.workflow }}-${{ github.event_name == 'push' && github.ref == 'refs/heads/develop' && github.sha || github.ref }}
@@ -99,7 +100,7 @@ jobs:
# However, we do not enable ccache for events targeting a release branch, # However, we do not enable ccache for events targeting a release branch,
# to protect against the rare case that the output produced by ccache is # to protect against the rare case that the output produced by ccache is
# not identical to a regular compilation. # not identical to a regular compilation.
ccache_enabled: ${{ github.repository_owner == 'XRPLF' && !startsWith(github.ref, 'refs/heads/release') }} ccache_enabled: ${{ github.repository_owner == 'XRPLF' && !startsWith(github.ref, 'refs/heads/release/') }}
os: ${{ matrix.os }} os: ${{ matrix.os }}
secrets: secrets:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
+4 -3
View File
@@ -8,13 +8,14 @@ on:
push: push:
branches: branches:
- "develop" - "develop"
- "release*" - "release/*"
- "staging/*"
workflow_dispatch: workflow_dispatch:
jobs: jobs:
# Call the workflow in the XRPLF/actions repo that runs the pre-commit hooks. # Call the workflow in the XRPLF/actions repo that runs the pre-commit hooks.
run-hooks: run-hooks:
uses: XRPLF/actions/.github/workflows/pre-commit.yml@279ec358f4a1be4088be3e024b07916fa97c75b6 uses: XRPLF/actions/.github/workflows/pre-commit.yml@6a52459a658649a0aeaab4ebd6a8f25173f6f16f
with: with:
runs_on: ubuntu-latest runs_on: ubuntu-latest
container: '{ "image": "ghcr.io/xrplf/xrpld/pre-commit:sha-473fe44" }' container: '{ "image": "ghcr.io/xrplf/xrpld/pre-commit:sha-d3a71b2" }'
+2 -2
View File
@@ -41,13 +41,13 @@ env:
jobs: jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-060957e container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-d3a71b2
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Prepare runner - name: Prepare runner
uses: XRPLF/actions/prepare-runner@b3e255d74d785d053e4903da8ac90983cd7d9e82 uses: XRPLF/actions/prepare-runner@6645b8721d3810be1c59f4180315249e59bf1312
with: with:
enable_ccache: false enable_ccache: false
@@ -129,7 +129,7 @@ jobs:
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Prepare runner - name: Prepare runner
uses: XRPLF/actions/prepare-runner@b3e255d74d785d053e4903da8ac90983cd7d9e82 uses: XRPLF/actions/prepare-runner@6645b8721d3810be1c59f4180315249e59bf1312
with: with:
enable_ccache: ${{ inputs.ccache_enabled }} enable_ccache: ${{ inputs.ccache_enabled }}
@@ -186,9 +186,6 @@ jobs:
with: with:
build_nproc: ${{ steps.nproc.outputs.nproc }} build_nproc: ${{ steps.nproc.outputs.nproc }}
build_type: ${{ inputs.build_type }} build_type: ${{ inputs.build_type }}
# Set the verbosity to "quiet" for Windows to avoid an excessive
# amount of logs. For other OSes, the "verbose" logs are more useful.
log_verbosity: ${{ runner.os == 'Windows' && 'quiet' || 'verbose' }}
sanitizers: ${{ inputs.sanitizers }} sanitizers: ${{ inputs.sanitizers }}
- name: Configure CMake - name: Configure CMake
@@ -257,20 +254,20 @@ jobs:
# cache included, since what it holds is what gets uploaded and reused. # cache included, since what it holds is what gets uploaded and reused.
- name: Check the build output for Nix store references (Nix toolchain) - name: Check the build output for Nix store references (Nix toolchain)
if: ${{ inputs.toolchain == 'nix' }} if: ${{ inputs.toolchain == 'nix' }}
run: ./bin/check-nix-store-refs.sh "${BUILD_DIR}" run: ./bin/nix/check-nix-store-refs.sh "${BUILD_DIR}"
- name: Check the Conan cache for Nix store references (Nix toolchain) - name: Check the Conan cache for Nix store references (Nix toolchain)
if: ${{ inputs.toolchain == 'nix' }} if: ${{ inputs.toolchain == 'nix' }}
run: ./bin/check-nix-store-refs.sh "${CONAN_HOME}" run: ./bin/nix/check-nix-store-refs.sh "${CONAN_HOME}"
# Only what PatchNixBinary.cmake retargets: the toolchain in the Linux # Only what PatchNixBinary.cmake retargets: the toolchain in the Linux
# images always references the store. Same condition it uses. # images always references the store. Same condition it uses.
- name: Check for Nix store references (Linux) - name: Check for Nix store references (Linux)
if: ${{ runner.os == 'Linux' && env.SANITIZERS_ENABLED == 'false' }} if: ${{ runner.os == 'Linux' && env.SANITIZERS_ENABLED == 'false' }}
run: | run: |
./bin/check-nix-store-refs.sh "${BUILD_DIR}/xrpld" ./bin/nix/check-nix-store-refs.sh "${BUILD_DIR}/xrpld"
./bin/check-nix-store-refs.sh "${BUILD_DIR}/xrpl_tests" ./bin/nix/check-nix-store-refs.sh "${BUILD_DIR}/xrpl_tests"
./bin/check-nix-store-refs.sh "${BUILD_DIR}/xrpld_tests" ./bin/nix/check-nix-store-refs.sh "${BUILD_DIR}/xrpld_tests"
- name: Show ccache statistics - name: Show ccache statistics
if: ${{ inputs.ccache_enabled }} if: ${{ inputs.ccache_enabled }}
@@ -283,7 +280,7 @@ jobs:
- name: Upload the binary (Linux) - name: Upload the binary (Linux)
if: ${{ env.PACKAGING_ARTIFACTS_ENABLED == 'true' && runner.os == 'Linux' }} if: ${{ env.PACKAGING_ARTIFACTS_ENABLED == 'true' && runner.os == 'Linux' }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with: with:
name: xrpld-${{ inputs.config_name }} name: xrpld-${{ inputs.config_name }}
path: ${{ env.BUILD_DIR }}/xrpld path: ${{ env.BUILD_DIR }}/xrpld
@@ -297,7 +294,7 @@ jobs:
- name: Upload the validator-keys binary - name: Upload the validator-keys binary
if: ${{ env.PACKAGING_ARTIFACTS_ENABLED == 'true' && env.VALIDATOR_KEYS_ENABLED == 'true' }} if: ${{ env.PACKAGING_ARTIFACTS_ENABLED == 'true' && env.VALIDATOR_KEYS_ENABLED == 'true' }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with: with:
name: validator-keys-${{ inputs.config_name }} name: validator-keys-${{ inputs.config_name }}
path: | path: |
@@ -308,7 +305,7 @@ jobs:
- name: Upload the test binary (Linux) - name: Upload the test binary (Linux)
if: ${{ github.event.repository.visibility == 'public' && runner.os == 'Linux' }} if: ${{ github.event.repository.visibility == 'public' && runner.os == 'Linux' }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with: with:
name: xrpl_tests-${{ inputs.config_name }} name: xrpl_tests-${{ inputs.config_name }}
path: ${{ env.BUILD_DIR }}/xrpl_tests path: ${{ env.BUILD_DIR }}/xrpl_tests
@@ -324,7 +321,7 @@ jobs:
- name: Upload server definitions - name: Upload server definitions
if: ${{ github.event.repository.visibility == 'public' && inputs.config_name == 'ubuntu-gcc-debug-amd64-coverage' }} if: ${{ github.event.repository.visibility == 'public' && inputs.config_name == 'ubuntu-gcc-debug-amd64-coverage' }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with: with:
name: server-definitions name: server-definitions
path: ${{ env.BUILD_DIR }}/server_definitions.json path: ${{ env.BUILD_DIR }}/server_definitions.json
+13 -8
View File
@@ -34,7 +34,7 @@ jobs:
needs: [determine-files] needs: [determine-files]
if: ${{ needs.determine-files.outputs.cpp_changed_files != '' || needs.determine-files.outputs.need_full_run == 'true' }} if: ${{ needs.determine-files.outputs.cpp_changed_files != '' || needs.determine-files.outputs.need_full_run == 'true' }}
runs-on: ["self-hosted", "Linux", "X64", "heavy"] runs-on: ["self-hosted", "Linux", "X64", "heavy"]
container: "ghcr.io/xrplf/xrpld/nix-debian:sha-060957e" container: "ghcr.io/xrplf/xrpld/nix-debian:sha-d3a71b2"
permissions: permissions:
contents: read contents: read
issues: write issues: write
@@ -43,7 +43,7 @@ jobs:
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Prepare runner - name: Prepare runner
uses: XRPLF/actions/prepare-runner@b3e255d74d785d053e4903da8ac90983cd7d9e82 uses: XRPLF/actions/prepare-runner@6645b8721d3810be1c59f4180315249e59bf1312
with: with:
enable_ccache: false enable_ccache: false
@@ -73,7 +73,6 @@ jobs:
with: with:
build_nproc: ${{ steps.nproc.outputs.nproc }} build_nproc: ${{ steps.nproc.outputs.nproc }}
build_type: ${{ env.BUILD_TYPE }} build_type: ${{ env.BUILD_TYPE }}
log_verbosity: verbose
- name: Configure CMake - name: Configure CMake
working-directory: ${{ env.BUILD_DIR }} working-directory: ${{ env.BUILD_DIR }}
@@ -110,7 +109,7 @@ jobs:
- name: Upload clang-tidy output - name: Upload clang-tidy output
if: ${{ github.event.repository.visibility == 'public' && steps.run_clang_tidy.outcome != 'success' }} if: ${{ github.event.repository.visibility == 'public' && steps.run_clang_tidy.outcome != 'success' }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with: with:
path: ${{ env.OUTPUT_FILE }} path: ${{ env.OUTPUT_FILE }}
archive: false archive: false
@@ -124,17 +123,23 @@ jobs:
- name: Fix style - name: Fix style
if: ${{ steps.files_changed.outcome != 'success' }} if: ${{ steps.files_changed.outcome != 'success' }}
# pre-commit installs every hook's environment, even for hooks that match
# no files, and node-based hooks need libatomic, which this image lacks.
# Exit code 1 just means hooks modified files or found issues.
env:
SKIP: prettier,cspell
run: | run: |
pre-commit run --all-files || true git add --update
pre-commit run || [ $? -eq 1 ]
- name: Generate git diff - name: Generate git diff
if: ${{ steps.files_changed.outcome != 'success' }} if: ${{ steps.files_changed.outcome != 'success' }}
run: | run: |
git diff | tee "${DIFF_FILE}" git diff HEAD | tee "${DIFF_FILE}"
- name: Upload clang-tidy diff output - name: Upload clang-tidy diff output
if: ${{ github.event.repository.visibility == 'public' && steps.files_changed.outcome != 'success' }} if: ${{ github.event.repository.visibility == 'public' && steps.files_changed.outcome != 'success' }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with: with:
path: ${{ env.DIFF_FILE }} path: ${{ env.DIFF_FILE }}
archive: false archive: false
@@ -186,7 +191,7 @@ jobs:
- name: Create issue - name: Create issue
if: ${{ steps.run_clang_tidy.outcome != 'success' && inputs.create_issue_on_failure }} if: ${{ steps.run_clang_tidy.outcome != 'success' && inputs.create_issue_on_failure }}
uses: XRPLF/actions/create-issue@2b8bc36af85b88bca0dd7bfac2e2dc05f94ad712 uses: XRPLF/actions/create-issue@b489c21d53928f7dab4874912fec40e4f6c9e85e
with: with:
title: "Clang-tidy check failed" title: "Clang-tidy check failed"
body_file: ${{ env.ISSUE_FILE }} body_file: ${{ env.ISSUE_FILE }}
@@ -44,7 +44,7 @@ jobs:
# Every package lands in one directory; the step below picks its own, # Every package lands in one directory; the step below picks its own,
# which keeps this independent of the artifact names. # which keeps this independent of the artifact names.
- name: Download package artifacts - name: Download package artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with: with:
pattern: "*-pkg" pattern: "*-pkg"
merge-multiple: true merge-multiple: true
@@ -95,11 +95,15 @@ jobs:
apt-get update -qq apt-get update -qq
apt-get install -y "./${PACKAGE}" apt-get install -y "./${PACKAGE}"
# Rocky Linux and AlmaLinux pick a mirror from a mirrorlist, and now and
# then get one that serves the repository metadata at a few hundred kB/s,
# which alone outlasts the job's timeout. dnf only abandons a mirror below
# 1000 B/s for 30 s, so raise that floor to fail over to the next one fast.
- name: Install the RPM - name: Install the RPM
if: ${{ inputs.package_type == 'rpm' }} if: ${{ inputs.package_type == 'rpm' }}
env: env:
PACKAGE: ${{ steps.find.outputs.package }} PACKAGE: ${{ steps.find.outputs.package }}
run: dnf install -y "./${PACKAGE}" run: dnf install -y --setopt=minrate=1M --setopt=timeout=10 "./${PACKAGE}"
- name: Run xrpld - name: Run xrpld
run: xrpld --version run: xrpld --version
+9 -9
View File
@@ -100,18 +100,18 @@ jobs:
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Prepare runner - name: Prepare runner
uses: XRPLF/actions/prepare-runner@b3e255d74d785d053e4903da8ac90983cd7d9e82 uses: XRPLF/actions/prepare-runner@6645b8721d3810be1c59f4180315249e59bf1312
with: with:
enable_ccache: false enable_ccache: false
- name: Download pre-built xrpld binary - name: Download pre-built xrpld binary
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with: with:
name: ${{ matrix.xrpld_artifact_name }} name: ${{ matrix.xrpld_artifact_name }}
path: ${{ env.BUILD_DIR }} path: ${{ env.BUILD_DIR }}
- name: Download pre-built validator-keys binary - name: Download pre-built validator-keys binary
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with: with:
name: ${{ matrix.validator_keys_artifact_name }} name: ${{ matrix.validator_keys_artifact_name }}
path: ${{ env.BUILD_DIR }} path: ${{ env.BUILD_DIR }}
@@ -151,7 +151,7 @@ jobs:
# version starts with a digit and a longer name does not, so that one digit # 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-...'. # is what tells 'xrpld-3.4.1-...' from 'xrpld-assert-3.4.1-...'.
- name: Upload package artifact - name: Upload package artifact
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with: with:
name: ${{ matrix.xrpld_artifact_name }}-pkg name: ${{ matrix.xrpld_artifact_name }}-pkg
path: | path: |
@@ -160,7 +160,7 @@ jobs:
if-no-files-found: error if-no-files-found: error
- name: Upload debug symbol artifact - name: Upload debug symbol artifact
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with: with:
name: ${{ matrix.xrpld_artifact_name }}-pkg-debug name: ${{ matrix.xrpld_artifact_name }}-pkg-debug
path: | path: |
@@ -225,13 +225,13 @@ jobs:
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Prepare runner - name: Prepare runner
uses: XRPLF/actions/prepare-runner@b3e255d74d785d053e4903da8ac90983cd7d9e82 uses: XRPLF/actions/prepare-runner@6645b8721d3810be1c59f4180315249e59bf1312
with: with:
enable_ccache: false enable_ccache: false
# Both artifacts, so the debug symbols are published alongside the package. # Both artifacts, so the debug symbols are published alongside the package.
- name: Download package artifacts - name: Download package artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with: with:
pattern: ${{ matrix.xrpld_artifact_name }}-pkg* pattern: ${{ matrix.xrpld_artifact_name }}-pkg*
merge-multiple: true merge-multiple: true
@@ -287,7 +287,7 @@ jobs:
run: echo "PUSH=${PUSH}" | tee -a "${GITHUB_ENV}" run: echo "PUSH=${PUSH}" | tee -a "${GITHUB_ENV}"
- name: Download package artifacts - name: Download package artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with: with:
pattern: "*-pkg" pattern: "*-pkg"
merge-multiple: true merge-multiple: true
@@ -295,7 +295,7 @@ jobs:
- name: Download voidstar binary - name: Download voidstar binary
if: ${{ matrix.target == 'voidstar' }} if: ${{ matrix.target == 'voidstar' }}
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with: with:
name: xrpld-ubuntu-clang-debug-amd64-voidstar name: xrpld-ubuntu-clang-debug-amd64-voidstar
path: ${{ env.CONTEXT }} path: ${{ env.CONTEXT }}
+3 -3
View File
@@ -28,7 +28,7 @@ permissions:
jobs: jobs:
clippy: clippy:
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-060957e container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-d3a71b2
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
@@ -41,7 +41,7 @@ jobs:
coverage: coverage:
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-060957e container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-d3a71b2
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
@@ -70,7 +70,7 @@ jobs:
doc: doc:
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-060957e container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-d3a71b2
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
+2 -2
View File
@@ -40,7 +40,7 @@ defaults:
jobs: jobs:
upload: upload:
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-060957e container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-d3a71b2
env: env:
REMOTE_NAME: ${{ inputs.remote_name }} REMOTE_NAME: ${{ inputs.remote_name }}
CONAN_LOGIN_USERNAME_XRPLF: ${{ secrets.remote_username }} CONAN_LOGIN_USERNAME_XRPLF: ${{ secrets.remote_username }}
@@ -50,7 +50,7 @@ jobs:
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Prepare runner - name: Prepare runner
uses: XRPLF/actions/prepare-runner@b3e255d74d785d053e4903da8ac90983cd7d9e82 uses: XRPLF/actions/prepare-runner@6645b8721d3810be1c59f4180315249e59bf1312
with: with:
enable_ccache: false enable_ccache: false
+2 -5
View File
@@ -68,7 +68,7 @@ jobs:
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Prepare runner - name: Prepare runner
uses: XRPLF/actions/prepare-runner@b3e255d74d785d053e4903da8ac90983cd7d9e82 uses: XRPLF/actions/prepare-runner@6645b8721d3810be1c59f4180315249e59bf1312
with: with:
enable_ccache: false enable_ccache: false
@@ -108,14 +108,11 @@ jobs:
build_nproc: ${{ steps.nproc.outputs.nproc }} build_nproc: ${{ steps.nproc.outputs.nproc }}
build_type: ${{ matrix.build_type }} build_type: ${{ matrix.build_type }}
force_build: ${{ github.event_name == 'schedule' || github.event.inputs.force_source_build == 'true' }} force_build: ${{ github.event_name == 'schedule' || github.event.inputs.force_source_build == 'true' }}
# Set the verbosity to "quiet" for Windows to avoid an excessive
# amount of logs. For other OSes, the "verbose" logs are more useful.
log_verbosity: ${{ runner.os == 'Windows' && 'quiet' || 'verbose' }}
sanitizers: ${{ matrix.sanitizers }} sanitizers: ${{ matrix.sanitizers }}
- name: Check the Conan cache for Nix store references (Nix toolchain) - name: Check the Conan cache for Nix store references (Nix toolchain)
if: ${{ matrix.toolchain == 'nix' }} if: ${{ matrix.toolchain == 'nix' }}
run: ./bin/check-nix-store-refs.sh "${CONAN_HOME}" run: ./bin/nix/check-nix-store-refs.sh "${CONAN_HOME}"
- name: Log into Conan remote - name: Log into Conan remote
if: ${{ github.repository == 'XRPLF/rippled' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') }} if: ${{ github.repository == 'XRPLF/rippled' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') }}
+6 -5
View File
@@ -60,7 +60,7 @@ repos:
types_or: [c++, c] types_or: [c++, c]
- repo: https://github.com/pre-commit/mirrors-clang-format - repo: https://github.com/pre-commit/mirrors-clang-format
rev: e2b496dc2bd8340c2524cb9a2d2a943cde1bb6df # frozen: v23.1.1 rev: a9a8a861f30ed207ead7d5a3b7e8032283ba5da7 # frozen: v23.1.2
hooks: hooks:
- id: clang-format - id: clang-format
args: [--style=file] args: [--style=file]
@@ -82,9 +82,10 @@ repos:
files: ^crates/.*\.rs$ files: ^crates/.*\.rs$
- repo: https://github.com/BlankSpruce/gersemi-pre-commit - repo: https://github.com/BlankSpruce/gersemi-pre-commit
rev: f1c4833f8cf23c6d952673abc73525411a5719e8 # frozen: 0.29.1 rev: 28010ddd6016e1a0f7bd232acb6536ef996ae897 # frozen: 0.29.2
hooks: hooks:
- id: gersemi - id: gersemi
args: [-i, --warnings-as-errors]
- repo: https://github.com/rbubley/mirrors-prettier - repo: https://github.com/rbubley/mirrors-prettier
rev: ef4a397f916211b4a39ccf9d3d9cbb6562157251 # frozen: v3.9.9 rev: ef4a397f916211b4a39ccf9d3d9cbb6562157251 # frozen: v3.9.9
@@ -95,19 +96,19 @@ repos:
# Scoped to package/: the rest of the repo's Python has pre-existing findings, # Scoped to package/: the rest of the repo's Python has pre-existing findings,
# so widening these is its own change. # so widening these is its own change.
- repo: https://github.com/astral-sh/ruff-pre-commit - repo: https://github.com/astral-sh/ruff-pre-commit
rev: a56c0b927e6465d37cae3e97d35d4d18ab2b96cd # frozen: v0.16.9 rev: f12be1ebaa5351c1fc76472de98db2c3446c8253 # frozen: v0.16.10
hooks: hooks:
- id: ruff-check - id: ruff-check
args: [--fix] args: [--fix]
files: ^package/.*\.py$ files: ^package/.*\.py$
- repo: https://github.com/psf/black-pre-commit-mirror - repo: https://github.com/psf/black-pre-commit-mirror
rev: 4160603246a6b365d4a2af661c6d71b0a0f50478 # frozen: 26.5.1 rev: 96ae3e5802f3fe2d551e703e18f0a367d1a81ac2 # frozen: 26.10.0
hooks: hooks:
- id: black - id: black
- repo: https://github.com/pre-commit/mirrors-mypy - repo: https://github.com/pre-commit/mirrors-mypy
rev: 7ff8d35ae36a7d2b968f2f90b4c723e292e594ee # frozen: v2.3.1 rev: 2834ec6639549dd6796205c8f011dedcd587288b # frozen: v2.4.0
hooks: hooks:
- id: mypy - id: mypy
args: [--strict] args: [--strict]
+54 -1
View File
@@ -22,13 +22,65 @@ 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. 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
### Breaking changes
- A JSON string holding a NUL character, written as `\u0000` or as a raw byte, now makes the request unparsable, on every transport and at every API version, and is answered as any other body that does not parse. The server stored a string only through its first NUL, so `"ripplerpc": "3.0\u0000junk"` was read as `"3.0"` and any other field was cut short the same way. The two configuration sections read by the same parser, `[rpc_startup]` and `[validator_token]`, refuse it too.
- The `ripplerpc` request field, which selects the shape of the JSON-RPC reply envelope, is now validated, and a value that is not exactly `"1.0"`, `"2.0"` or `"3.0"` is rejected. Two things it does not reach: a WebSocket session, which reads the field only to echo it back, and API version 3, where the field selects nothing and so is neither read nor checked, `ripplerpc: "banana"` and no `ripplerpc` at all being served alike. A request sending `"2"`, `" 2.0"`, `"2.00"`, `"02.0"`, `"2.0.0"`, `"10.0"` or any other text, such as `"abc"` or `"x2"`, gets a working reply today. After this ships, such a request sent alone gets HTTP 400 with `ripplerpc is not a supported version`, charged as a malformed request, and such an entry of a `"method": "batch"` body gets that error in its own reply while the batch answers 200. A client that spells the version loosely must therefore be corrected to one of the three exact values, or omit the field. Previously the value was compared as a string, which both accepted values that name no version and ordered multi-digit versions incorrectly: `"abc"` and `"x2"` sorted above `"3.0"` and so selected version 3, and `"10.0"` sorted below `"2.0"` and so selected version 1. Requests that send one of the three supported values, or omit the field, are unaffected.
- `subscribe`: every subscription a connection holds must name the same `api_version`. The first `subscribe` establishes it, and a later one naming a different version is refused with `apiVersionConflict`, registering nothing; the message names the version the connection's subscriptions are served at. The HTTP status is 400 where the envelope derives it from the error, with `ripplerpc: "3.0"` or at API version 3, and 200 with `ripplerpc` `"1.0"` or `"2.0"`, as for every error; a WebSocket frame carries no status. A `subscribe` refused for another reason, a stream name the server does not have for one, still fixes that version, since the registrations it makes are spread through the handler. A connection that subscribed one stream at `api_version` 2 and another at 1, in two calls, was previously served both at version 1, the later call's, so the first stream's shape changed under it. The version is fixed for the connection's life: a client that wants another version opens another connection. On the webhook path the subscriber is keyed on its `url` alone, so the refusal reaches a second admin because of a first admin's version, and the message names the version the url's subscriptions are served at, and no remedy: releasing a url means unsubscribing its streams, which would remove that first admin's subscription, and the server cannot tell the two callers apart. Naming the url alone does not release it, a subscriber a stream map still holds not being evicted. This reaches every API version, since version 1 and version 2 content is not interchangeable either: version 2 renames `transaction` to `tx_json` and hoists `hash`, so a version 1 client handed version 2 content finds no `transaction` member.
- `batch`: An entry of a `"method": "batch"` request that names `api_version` both inside `params` and at its own top level is now served at the version inside `params`. It was previously served at the top-level version whenever the one inside `params` resolved to version 1, so an entry asking for version 1 explicitly and something else at the top level changes which version answers it. A lone request can name both values too, and for it the version inside `params` has always won; reversing that precedence was confined to a batch entry.
- `batch`: every entry of one batch request is now served at the same API version. An entry may name the version the body names, or name none and inherit it, and a body whose entries name two different versions is refused whole with `Batch entries name different versions` at HTTP 400, charged as a malformed request. **This is visible to a version 1 or 2 client:** a `"method": "batch"` body could mix versions across its entries, each entry being dispatched at its own, and the difference is observable because the reply shape changes with the version. Three bodies change. One whose entries name two different versions is now refused instead of answered. One where some entries name a version and others name none now serves all of them at the named version, where an entry naming none was served at version 1; the same applies to a version named on the request's own top level, which the entries now inherit. One whose top level names a version and whose entries name a different one is now refused, where the top-level value was ignored and each entry was served at the version it named. A body whose top level names no version or the same version as its entries, and whose entries agree with one another or name none at all, is unaffected. A `"method": "batch"` body naming at its own top level a version the server does not serve is refused with `invalid_API_version` at HTTP 400, where it was previously served at version 1 as if it had named none. The line that produced the mixing was a fallback about where the field sits rather than a decision that entries may differ, so this is a correction rather than a removal of a feature. develop's `Version_test` batch case mixed an unversioned entry with a version 2 entry and is rewritten to name one version. One body is answered in one envelope, which a per-entry version leaves no way to choose. The command line client stamps `api_version` 1 into an entry naming none, so a `json2` batch mixing an unversioned entry with a versioned one is refused and must name the version on every entry.
- `batch`: A `"method": "batch"` request holding more than 100 entries is now refused with `Batch has too many entries` at HTTP 400 before any entry is dispatched and before the entries' versions are compared, at every API version. A body served at version 3 answers the JSON-RPC error object and an earlier version the plain text body. The top-level array form, accepted from version 3, takes the same limit.
### Additions
- A JSON-RPC (HTTP) request may send its parameters as an object, `"params": {"account": "r..."}`, as well as the array of one object that was already accepted. This reaches every API version: such a request was previously rejected with HTTP 400 and `params unparsable`, and is now served. A request that already sends the array form is unaffected. An entry of a `"method": "batch"` request that carries a by-name `params` object is read for `api_version` and credentials from that object, and is dispatched on that object, as a lone request is; a one-element array holding the object is unpacked the same way, and any other `params` answers `params unparsable` for that entry, apart from `null`, an empty string, an empty array and an array holding one `null`, which read as an empty parameter object, as they do for a lone request; from API version 3, `null` and an empty string there answer `params unparsable` instead, as the version 3 paragraphs above describe. Such an entry's top-level `jsonrpc`, `ripplerpc` and `id` are read as if they sat inside that object, where the object does not name them itself, so the reply carries the entry's id and takes the envelope it named. An entry naming no `params` is dispatched as before, the entry itself being the object a handler reads. Previously such an entry was dispatched on its own members whatever `params` held, had its `api_version` read from its top level, and had its credentials ignored, since credentials were read only from an array-form `params`.
- A JSON-RPC (HTTP) request may name its `api_version` at its own top level, beside `method` and `id`, as well as inside `params`. The member is an XRPL extension, which the JSON-RPC 2.0 specification does not define; placing it beside the specification's own members is what lets a version 3 client send a specification-shaped request. This is honored from API version 3 up, so it needs `[beta_rpc_api]`; a version below that named at the top level is ignored, exactly as it always has been. Previously only an entry of a `"method": "batch"` request had its own top level read; a WebSocket request, which is one flat object, has always been read there.
### Bugfixes
- Every credential-bearing field is masked wherever a request or a reply is echoed, logged or printed: `admin_password`, `admin_user`, `master_key`, `master_seed`, `master_seed_hex`, `passphrase`, `password`, `secret`, `seed`, `seed_hex`, `url_password`, `url_username`, `username`, `validation_key`, `validation_private_key` and `validation_seed`. The one list applies to a request echoed back in an error reply and to every request and reply written to the log. Nesting no longer matters, so a credential inside `params` is masked too. Six of the sixteen names, `master_key`, `master_seed`, `master_seed_hex`, `validation_key`, `validation_private_key` and `validation_seed`, occur only in a reply, which is how `wallet_propose` and `validation_create` used to write a live private key to the log. The `id`, `jsonrpc`, `ripplerpc` and `api_version` members a legacy reply echoes from the request are masked the same way. The command line client's trace of a reply's header covers the header only, not the body bytes read with it. A request or reply written to the log is truncated at 10,000 characters. An `[rpc_startup]` line that does not parse is reported by its position in the section alone, never by its text or by the parser's message, and no command runs for it.
- The command line client no longer prints a credential the operator did not type. A failing command echoes the request it built under `request_sent`, which carries the `admin_password` the client copies out of `[port_rpc]` in the config, so `./xrpld account_info rBogus` printed that password to stdout and into any captured output. `request_sent` is now masked. The `rpc` member beside it, which echoes the arguments as they were typed, is unchanged. The command line client also no longer writes an unparsed `json` or `ripple_path_find` argument to its trace log before parsing it, where a `secret` inside that argument could not be masked; it logs the parsed request instead, masked. The reply it receives is logged the same way, parsed and masked, where the raw body was written before, a `validation_create` answer included.
- A WebSocket frame that does not parse, or exceeds the request size limit, is answered `{"type": "error", "error": "jsonInvalid", "size": <bytes>}`. The frame's body is reported by size rather than echoed back in a `value` member, since a body that does not parse has no fields to mask. A client that read `value` gets `size` instead.
- Four error codes that named no HTTP status of their own, and so answered 200 on a reply reporting an error, now name one: `actMalformed`, `alreadyMultisig` and `alreadySingleSig` answer 400, and `actNotFound` answers 404. **Only API version 3 reports these four.** A request sending `ripplerpc: "3.0"` at API version 1 or 2 still receives 200 for all four, as it always has, so `account_info` on a malformed account or one the ledger does not hold answers 200 for those clients exactly as before.
- `submit`, `simulate`, `transaction_entry`, `ledger_entry` and `ledger_accept`: Errors from these methods now include `error_code` and `error_message` alongside the `error` token, as every other method already did. Each error now answers the status its code names: 400 for a malformed request, 404 for `transactionNotFound`, 500 for an internal failure, and 501 for `notYetImplemented` and `notStandAlone`. That status change reaches only a request sending `ripplerpc: "3.0"`, or API version 3, which are the envelopes that derive the status from the error. With `ripplerpc` `"1.0"` the status stays 200 and the two new members appear beside `error`; with `"2.0"` the status stays 200, `error_code` appears, and the `code` and `message` members carry the code and the message rather than null, since that envelope copies them from `error_code` and `error_message` and drops `error_message`. From API version 3 the fifteen `malformed*` tokens `ledger_entry` names each report the code they own instead of 31.
- A reply reporting HTTP 402 or 502 now carries a status line. Those two statuses named no case in the switch that writes one, so such a reply began with a header instead and did not parse as an HTTP response at all. Both are reachable at any API version with `ripplerpc: "3.0"`, which derives the status from the error code: 402 through `highFee` from `sign` or `submit` with a low `fee_mult_max`, and 502 through `dbDeserialization` from `tx`. The eleven statuses that already named a case report the same phrase they always have.
- An error reply to a request sending `ripplerpc: "2.0"` or `"3.0"` no longer carries a stray `"error_message": null` beside the error it reports. The member appeared only when the `Server` log partition was set to debug or lower, because the log statement read `error_message` after the reply had renamed it to `message`, and reading it put it back as null. So the reply a client received depended on the server's log level, and the log line itself printed an empty message. Both are fixed.
- A body the server rejects before it reads a request out of it now says what was wrong. A body over the size limit answers `Request is too large`, and a body that parses to `{}` or `null` answers `Request is empty`; both previously answered `Unable to parse request: ` with nothing after the colon, the parser having recorded no error for them. Any other body that is not an array does not parse, which includes one that is only whitespace and one whose top-level value is a string, number or boolean; it answers `Unable to parse request: ` followed by the parser's own reason, as it did before. The status is 400 for all three, as before, and this reaches every API version. The command line client reports `Request is too large` and `Request is empty` as the same class of rejection as an unparsable body, under `invalidParams` with the text in `error_what`. A top-level array, the one other body nothing can read a request from, is answered with a JSON error object instead, which the entry on top-level arrays below describes.
- `batch`: An entry that is not identified through a secure gateway no longer clears the connection's `X-User` and forwarded-for values for the entries after it, so every entry of one body reports the role and username it would have reported on its own.
- `batch`: Every entry of a `"method": "batch"` request is now charged against the sender's resource allowance, including one rejected before it reaches a handler, and the request stops at the first entry the connection is too loaded to serve. A reply array can therefore be shorter than the request array, and its last element depends on where the batch stopped. An entry that is not a JSON object, or names an API version the server does not serve, is charged before its role is known and answered with its own rejection; if that charge took the connection over the drop threshold, the batch stops there and that rejection is the last answer. Every other entry met over the threshold is answered `Server is overloaded` and nothing follows. A client should read any reply array shorter than its request as a connection over the drop threshold, whatever the last element says. A well-behaved client is unaffected; one that sends thousands of entries in a single body no longer gets every one of them answered.
- A body the server rejects before it reads a request out of it is now charged against the sender's resource allowance, as a malformed request already was. Eleven conditions were free: a body over the size limit, one that does not parse, one carrying no document, one that is neither a JSON object nor an array, a `"method": "batch"` naming no entry array, a lone request naming an `api_version` the server does not serve, and six ways a top-level array is not a batch this server can serve. The answer to the first six is unchanged; an array's answer changes as the entry on top-level arrays below describes, the one generic rejection it received having become six. A well-behaved client is unaffected; one that repeats such a body exhausts its allowance and is refused the next request a handler would have served. A WebSocket frame that does not parse, or exceeds the request size limit, is charged the same way, and a connection that sends only such frames is closed once it crosses the drop threshold.
- `subscribe`, `path_find`: A subscription is now served at the API version its own `subscribe` call named, rather than at the version of the most recent `subscribe` or `path_find` on the same connection. A `path_find` no longer changes the version anything that connection has subscribed is served at. An ordinary request is unaffected: it names its own version and is answered at it, so a connection subscribed at `api_version` 3 still calls `account_info` at version 1 and reads the version 1 shape.
- A top-level JSON array, which is the JSON-RPC 2.0 batch form accepted from API version 3, is now rejected with a JSON-RPC error object rather than a plain text body when it cannot be served: when it is empty, holds more than 100 entries, holds nothing that could be a request, names no API version of 3 or above that the server serves, or names two different versions the server serves. An array naming no served version of 3 or above is refused for requiring version 3, or, where every version it names is one the server does not serve, with `invalid_API_version`. One entry naming a version the server does not serve does not reject an array in which another entry names a served version: it is answered on its own, inside the reply array, with the same `-32606` code. This reaches every API version, since no earlier version accepts an array at all: a client that sent one received HTTP 400 with `Unable to parse request: ` and now receives the same status with a JSON body. The message also names the version rather than the shape where the version is what is wrong, which is what a client with `[beta_rpc_api]` disabled receives.
## XRP Ledger server version 3.5.0 ## XRP Ledger server version 3.5.0
Version 3.5.0 is not yet released. Version 3.5.0 is not yet released.
### Breaking changes in 3.5.0
- The `XChainBridge` amendment and its ledger entries and transactions are removed. `XChainBridge` and `fixXChainRewardRounding` are now obsolete and can no longer be voted for; neither was ever enabled on Mainnet. `ledger_entry` no longer accepts `bridge`, `xchain_owned_claim_id`, or `xchain_owned_create_account_claim_id`; `account_objects` no longer accepts those values in `type`; and `server_definitions` no longer lists the removed ledger entry types, transaction types, fields, and the `XChainBridge` serialized type.
- `subscribe` (`ledger` stream): The deprecated `fee_ref` field has been removed unconditionally from both the `subscribe` response and the `ledgerClosed` stream messages. It was previously only omitted when the `XRPFees` amendment was enabled; that amendment has now been retired, so the field is never returned. This applies to all API versions.
### Additions in 3.5.0 ### Additions in 3.5.0
- `subscribe`, `unsubscribe`: Added an optional `mpt_issuances` request field, an array of MPT issuance IDs (hex strings). Subscribers receive a message with `type` `mptTransaction` for each validated transaction whose metadata affects a subscribed issuance; the message has the same fields as the `transactions` stream. MPT issuance subscriptions count toward the per-connection subscription limit. An empty array, a non-array value, or an invalid ID returns `invalidParams`. ([#5671](https://github.com/XRPLF/rippled/pull/5671)) - `subscribe`, `unsubscribe`: Added an optional `mpt_issuances` request field, an array of MPT issuance IDs (hex strings). Subscribers receive the same `transaction` message as the `transactions` stream for each validated transaction whose metadata affects a subscribed issuance. MPT issuance subscriptions count toward the per-connection subscription limit. An empty array, a non-array value, or an invalid ID returns `invalidParams`. ([#5671](https://github.com/XRPLF/rippled/pull/5671))
- `ledger_entry`: Add full support for checks, NFT offers, payment channels, and signer lists. ([#6319](https://github.com/XRPLF/rippled/pull/6319))
### Bugfixes in 3.5.0
- `channel_authorize`: The `channel_id` field now returns an `invalidParams` error if the value is not a string. [#7582](https://github.com/XRPLF/rippled/pull/7582)
- `channel_verify`: The `channel_id` and `signature` fields now return an `invalidParams` error if the value is not a string. [#7582](https://github.com/XRPLF/rippled/pull/7582)
- `account_currencies`, `account_nfts`, `account_offers`: A request with more than one problem may now report a different one of them. An invalid `ledger_hash` or `ledger_index` is reported before an invalid or missing `account`. An invalid `limit` or `marker` is reported before `lgrNotFound` or `actNotFound`, and for `account_offers` also before `actMalformed`. A request with a single problem returns the same error as before. [#8561](https://github.com/XRPLF/rippled/pull/8561)
- `deposit_authorized`: A `credentials` entry that is all zeros (for example `"0"` or 64 `0` characters) now returns a `badCredentials` error instead of looking up a credential that can never exist.
- `account_info`, `account_lines`, `account_channels`: A request with more than one problem may now report a different one of them. An invalid `ledger_hash` or `ledger_index` is reported before a missing or invalid `account`, or `ident` for `account_info`. For `account_lines`, a `peer` that is not a string, or an invalid `limit` or `marker`, is reported before `lgrNotFound`, `actNotFound` or a malformed `account`, and an invalid `limit` or `marker` also before a malformed `peer`. For `account_channels`, a malformed `account` is reported before `lgrNotFound`, and an invalid `destination_account`, `limit` or `marker` before `lgrNotFound` or `actNotFound`. A request with a single problem returns the same error as before. [#8573](https://github.com/XRPLF/rippled/pull/8573)
- `deposit_authorized`, `nft_buy_offers`, `nft_sell_offers`: A request with more than one problem may now report a different one of them. An invalid `ledger_hash` or `ledger_index` is reported before a missing or invalid `source_account`, `destination_account` or `nft_id`, and for `nft_buy_offers` / `nft_sell_offers` also before an invalid `limit`. For `deposit_authorized`, an invalid `credentials` array is reported before `lgrNotFound`, `srcActNotFound`, `dstActNotFound` or `badCredentials`. For `nft_buy_offers` and `nft_sell_offers`, an invalid `marker` is reported before `lgrNotFound` or `objectNotFound`. A request with a single problem returns the same error as before. [#8613](https://github.com/XRPLF/rippled/pull/8613)
- `nft_buy_offers`, `nft_sell_offers`: An `nft_id` that is an array or an object now returns an `invalidParams` error instead of an `internal` error. [#8613](https://github.com/XRPLF/rippled/pull/8613)
### Bugfixes in 3.5.0
- `feature`: The admin-only `vetoed` field now returns `invalidParams` unless its value is a boolean. [#7583](https://github.com/XRPLF/rippled/pull/7583)
## XRP Ledger server version 3.4.0 ## XRP Ledger server version 3.4.0
@@ -50,6 +102,7 @@ Version 3.4.0 is not yet released. These changes are available in the 3.4.0 beta
- `account_lines`: The `peer` field now returns an error if the value is not a string. [#7728](https://github.com/XRPLF/rippled/pull/7728) - `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) - `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)). - `noripple_check`: The `transactions` field is no longer included in error responses; it is still returned (possibly as an empty array) whenever `transactions` is `true` and the request succeeds. A malformed `account` is now rejected before the ledger is looked up, so that error response no longer carries the `ledger_hash`, `ledger_index`, and `validated` fields ([#6303](https://github.com/XRPLF/rippled/pull/6303)).
- `transaction_entry`: An object or an array in `tx_hash` now returns `malformedRequest`, like any other value that is not a hex hash, instead of an `internal` error.
## XRP Ledger server version 3.3.0 ## XRP Ledger server version 3.3.0
+5 -26
View File
@@ -2,33 +2,12 @@
| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| These instructions assume you have a C++ development environment ready with Git, Python, Conan, CMake, and a C++ compiler. For help setting one up on Linux, macOS, or Windows, [see this guide](./docs/build/environment.md).<br><br>These instructions also assume a basic familiarity with Conan and CMake. If you are unfamiliar with Conan, you can read our [crash course](./docs/build/conan.md) or the official [Getting Started][conan-getting-started] walkthrough. | | These instructions assume you have a C++ development environment ready with Git, Python, Conan, CMake, and a C++ compiler. For help setting one up on Linux, macOS, or Windows, [see this guide](./docs/build/environment.md).<br><br>These instructions also assume a basic familiarity with Conan and CMake. If you are unfamiliar with Conan, you can read our [crash course](./docs/build/conan.md) or the official [Getting Started][conan-getting-started] walkthrough. |
## Minimum Requirements ## Supported platforms
For the hardware needed to run a node, see Building and testing are supported on Linux, macOS, and (best effort) Windows;
[System Requirements](https://xrpl.org/system-requirements.html). see [Supported development platforms](./docs/build/environment.md#supported-development-platforms).
Running `xrpld` is officially supported on Linux only;
For the software needed to build xrpld, see the see [Requirements](./docs/install.md#requirements).
[environment setup guide](./docs/build/environment.md).
## Operating Systems
### Linux
The Ubuntu Linux distribution has received the highest level of quality
assurance, testing, and support. We also support Red Hat and use Debian
internally.
Our Linux CI tooling is distro-independent and uses a Nix-based environment, so it should be possible to build on other Linux distributions as well, although we have not tested them.
### macOS
Many `xrpld` engineers use macOS for development.
The minimum supported version is macOS 15 (Sequoia).
CI testing is done in macOS 26 (Tahoe), but the build defaults `CMAKE_OSX_DEPLOYMENT_TARGET` to 15.
### Windows
Windows is used by some engineers for development only, and is not recommended
for production use.
## Steps ## Steps
+1 -1
View File
@@ -42,7 +42,7 @@ if(is_gcc)
# GCC-specific fixes # GCC-specific fixes
add_compile_options(-Wno-unknown-pragmas -Wno-subobject-linkage) add_compile_options(-Wno-unknown-pragmas -Wno-subobject-linkage)
# -Wno-subobject-linkage can be removed when we upgrade GCC version to at least 13.3 # -Wno-subobject-linkage can be removed when we upgrade GCC version to at least 13.3
elseif(is_clang) elseif(is_any_clang)
# Clang-specific fixes # Clang-specific fixes
add_compile_options(-Wno-unknown-warning-option) # Ignore unknown warning options add_compile_options(-Wno-unknown-warning-option) # Ignore unknown warning options
elseif(is_msvc) elseif(is_msvc)
+5 -4
View File
@@ -332,7 +332,7 @@ This ensures that configuration changes don't introduce new warnings across the
### Installing clang-tidy ### Installing clang-tidy
See the [environment setup guide](./docs/build/environment.md#clang-tidy) for how to get clang-tidy. The [Nix development shell](./docs/build/nix.md) provides `clang-tidy` at the [tested version](./docs/build/environment.md#tested-compiler-versions).
### Running clang-tidy locally ### Running clang-tidy locally
@@ -365,14 +365,15 @@ With this set, the hook will run as part of `git commit` alongside the other pre
Then run clang-tidy on your local changes: Then run clang-tidy on your local changes:
``` ```
run-clang-tidy -p build -allow-no-checks src tests run-clang-tidy -p build -allow-no-checks include src tests
``` ```
This will check all source files in the `src`, `include` and `tests` directories using the compile commands from your `build` directory. This will check all source files in the `include`, `src` and `tests` directories using the compile commands from your `build` directory.
Headers are checked on their own, which requires the `verify_headers` CMake option (ON by default).
If you wish to automatically fix whatever clang-tidy finds _and_ is capable of fixing, add `-fix -format` to the above command: If you wish to automatically fix whatever clang-tidy finds _and_ is capable of fixing, add `-fix -format` to the above command:
``` ```
run-clang-tidy -p build -quiet -fix -format -allow-no-checks src tests run-clang-tidy -p build -quiet -fix -format -allow-no-checks include src tests
``` ```
`-format` reformats the fixed code with [`.clang-format`](./.clang-format); without it the fixes are inserted in LLVM style and the `clang-format` hook rewrites them afterwards. `-format` reformats the fixed code with [`.clang-format`](./.clang-format); without it the fixes are inserted in LLVM style and the `clang-format` hook rewrites them afterwards.
+15 -9
View File
@@ -34,7 +34,7 @@ so tools can filter them and protection rules can target `release/*` and `stagin
- **Branches only move forward.** - **Branches only move forward.**
`develop`, `staging/X.Y.x`, and `release/X.Y.x` are never rewritten. `develop`, `staging/X.Y.x`, and `release/X.Y.x` are never rewritten.
- **Cherry-picking only goes from `develop` to a staging branch**, - **Cherry-picking only goes from `develop` to a staging branch**,
for fixes that must get into a release after the code freeze for fixes that must get into a release after the [code freeze](#release-candidates)
(see [Emergency Fixes From `develop`](#emergency-fixes-from-develop)). (see [Emergency Fixes From `develop`](#emergency-fixes-from-develop)).
- **Security fixes are prepared privately and published with the release that contains them**, - **Security fixes are prepared privately and published with the release that contains them**,
so vulnerabilities are not disclosed prematurely. so vulnerabilities are not disclosed prematurely.
@@ -49,6 +49,7 @@ develop staging/X.Y.x & release/X.Y.x
│ │
├── Tag: X.Y.0-b1 ├── Tag: X.Y.0-b1
├── Tag: X.Y.0-bN ├── Tag: X.Y.0-bN
│ (2 weeks before rc1: freeze on large changes starts)
├── Tag: X.Y.0-rc1 ───────────────┐ (branches created) ├── Tag: X.Y.0-rc1 ───────────────┐ (branches created)
│ │ │ │
│ (development continues) ├── Fixes │ (development continues) ├── Fixes
@@ -75,16 +76,20 @@ develop staging/X.Y.x & release/X.Y.x
3. **Branches:** `staging/X.Y.x` and `release/X.Y.x` are created from `develop` 3. **Branches:** `staging/X.Y.x` and `release/X.Y.x` are created from `develop`
at the commit tagged `X.Y.0-rc1`. at the commit tagged `X.Y.0-rc1`.
The first RC also kicks off the QE process. The first RC also kicks off the QE process.
4. **Code freeze:** No new features or unrelated changes are pulled from `develop`
into `staging/X.Y.x` or `release/X.Y.x`. ### Freeze on Large Changes
Only critical stabilization fixes go into the line.
5. **No large changes on `develop`:** Until `X.Y.0` is [merged back](#merging-back-into-develop), From two weeks before `X.Y.0-rc1` until `X.Y.0` is [merged back](#merging-back-into-develop),
large changes (e.g., big refactors, moving or renaming many files, mass reformatting) large changes (e.g., big refactors, moving or renaming many files, mass reformatting)
are not merged into `develop`, are not merged into `develop`.
so that fixes on the line and the merge back don't run into conflicts.
### Release Candidates ### Release Candidates
After branching, the line is in code freeze:
no new features or unrelated changes are pulled from `develop`
into `staging/X.Y.x` or `release/X.Y.x`.
Only critical stabilization fixes go into the line.
1. Fixes are developed against `staging/X.Y.x`. 1. Fixes are developed against `staging/X.Y.x`.
2. When ready, a new RC is created on `staging/X.Y.x`, 2. When ready, a new RC is created on `staging/X.Y.x`,
and `release/X.Y.x` is fast-forwarded to it. and `release/X.Y.x` is fast-forwarded to it.
@@ -106,7 +111,8 @@ one right after the other.
2. `release/X.Y.x` is fast-forwarded to `staging/X.Y.x`, 2. `release/X.Y.x` is fast-forwarded to `staging/X.Y.x`,
and the release is tagged on it. and the release is tagged on it.
3. The release is immediately [merged back into `develop`](#merging-back-into-develop). 3. The release is immediately [merged back into `develop`](#merging-back-into-develop).
For a major-minor release, this lifts the freeze on large changes in `develop`. For a major-minor release, this lifts the [freeze on large changes](#freeze-on-large-changes)
in `develop`.
### Merging Back Into `develop` ### Merging Back Into `develop`
@@ -127,7 +133,7 @@ After the merge, `git log develop..<tag>` must be empty.
### Emergency Fixes From `develop` ### Emergency Fixes From `develop`
If a commit was merged to `develop` If a commit was merged to `develop`
and needs to be included in a release after the code freeze: and needs to be included in a release after the [code freeze](#release-candidates):
1. Create a PR that cherry-picks the commit onto `staging/X.Y.x`. 1. Create a PR that cherry-picks the commit onto `staging/X.Y.x`.
2. Leave `develop` as it is, with no reverts. 2. Leave `develop` as it is, with no reverts.
+60
View File
@@ -0,0 +1,60 @@
#!/bin/bash
#
# check-distrusted-roots.sh — fail if a CA bundle trusts a root of the
# compromised eMudhra intermediates; see https://emudhra.we-have-a-problem.com/.
#
# Usage: check-distrusted-roots.sh [ca-bundle]
# Defaults to the system bundle (Debian or RHEL path).
#
# Roots are matched by SHA-256 fingerprint, needing only bash, base64 and
# sha256sum (nixos/nix has no awk). Only plain CERTIFICATE blocks are checked:
# OpenSSL's TRUSTED CERTIFICATE blocks carry their own trust settings, which is
# how nixpkgs' cacert marks a blacklisted root as rejected.
set -euo pipefail
declare -A ROOTS=(
[d7a7a0fb5d7e2731d771e9484ebcdef71d5f0c3e0a2948782bc83ee0ea699ef4]="AAA Certificate Services"
[86a1ecba089c4a8d3bbe2734c612ba341d813e043cf9e8a862cd5c57a36bbe6b]="emSign ECC Root CA - G3"
)
BUNDLE="${1:-}"
if [ -z "${BUNDLE}" ]; then
for CANDIDATE in /etc/ssl/certs/ca-certificates.crt /etc/pki/tls/certs/ca-bundle.crt; do
if [ -f "${CANDIDATE}" ]; then
BUNDLE="${CANDIDATE}"
break
fi
done
fi
STATUS=0
COUNT=0
PEM=""
while IFS= read -r LINE || [ -n "${LINE}" ]; do
case "${LINE}" in
"-----BEGIN CERTIFICATE-----") PEM="" ;;
"-----END CERTIFICATE-----")
COUNT=$((COUNT + 1))
FINGERPRINT="$(base64 -d <<<"${PEM}" | sha256sum)" || {
echo "ERROR: certificate ${COUNT} in ${BUNDLE} is not valid base64" >&2
exit 1
}
ROOT="${ROOTS[${FINGERPRINT%% *}]:-}"
if [ -n "${ROOT}" ]; then
echo "ERROR: ${BUNDLE} trusts '${ROOT}'" >&2
STATUS=1
fi
;;
# Lines outside a CERTIFICATE block only collect until the next BEGIN.
*) PEM+="${LINE}" ;;
esac
done <"${BUNDLE:?no system CA bundle found}"
# An empty or unparsable bundle would otherwise pass.
if [ "${COUNT}" -eq 0 ]; then
echo "ERROR: ${BUNDLE} has no certificates" >&2
exit 1
fi
echo "${BUNDLE}: checked ${COUNT} certificates"
exit "${STATUS}"
+17 -6
View File
@@ -20,9 +20,11 @@
# development setups, but not in the macOS CI environment. They are checked # development setups, but not in the macOS CI environment. They are checked
# everywhere except when running in CI on macOS. # everywhere except when running in CI on macOS.
# #
# Tools that Nix also exposes under a version-suffixed name (`clang-tidy-22`, # Tools that Nix also exposes under a version-suffixed name
# `g++-15`, ...) are probed under both names: a suffixed name can break while # (`clang-tidy-<v>`, `g++-<v>`, ...) are probed under both names:
# the plain one still works (see mkVersionedToolLinks in nix/packages.nix). # a suffixed name can break while the plain one still works
# (see mkVersionedToolLinks in nix/packages.nix).
# The suffix is the major version of the plain `clang` / `gcc` on PATH.
# #
# Tools scoped to a single dev shell rather than to commonPackages are checked # Tools scoped to a single dev shell rather than to commonPackages are checked
# only in that shell, keyed off XRPL_DEVSHELL. # only in that shell, keyed off XRPL_DEVSHELL.
@@ -34,9 +36,16 @@
set -uo pipefail set -uo pipefail
# Version suffixes of the Nix tool links, tracking nix/packages.nix. # major_version <compiler>
gcc_version=15 # Major version of a compiler on PATH, or "unknown" when it isn't there.
llvm_version=22 major_version() {
local version
version="$("$1" -dumpversion 2>/dev/null)" || version=""
version="${version%%.*}"
printf '%s' "${version:-unknown}"
}
llvm_version="$(major_version clang)"
missing=() missing=()
checked=0 checked=0
@@ -112,6 +121,7 @@ if [ "${os}" = "linux" ] || [ "${os}" = "macos" ]; then
check ClangBuildAnalyzer check ClangBuildAnalyzer
check curl check curl
check file check file
check jq
check less check less
check make check make
# net-tools netstat reports "net-tools X.Y"; macOS ships BSD netstat with no # net-tools netstat reports "net-tools X.Y"; macOS ships BSD netstat with no
@@ -180,6 +190,7 @@ fi
if [ "${os}" = "linux" ]; then if [ "${os}" = "linux" ]; then
echo echo
echo "GCC toolchain:" echo "GCC toolchain:"
gcc_version="$(major_version gcc)"
check gcc check gcc
check "gcc-${gcc_version}" check "gcc-${gcc_version}"
check g++ check g++
@@ -58,6 +58,14 @@ function install() {
rpm-build \ rpm-build \
rpm-sign \ rpm-sign \
systemd-rpm-macros systemd-rpm-macros
# AlmaLinux's ca-certificates still trusts the root of the compromised
# eMudhra intermediates; see https://emudhra.we-have-a-problem.com/.
# TODO: drop once it ships a fix.
trust extract --format=pem-bundle \
--filter="pkcs11:object=emSign%20ECC%20Root%20CA%20-%20G3;type=cert" \
/etc/pki/ca-trust/source/blocklist/emSign_ECC_Root_CA_-_G3.pem
update-ca-trust
;; ;;
esac esac
} }
File renamed without changes.
+65
View File
@@ -0,0 +1,65 @@
#!/usr/bin/env bash
# Fail if a binary of a build-context Conan package loads anything from the Nix
# store other than glibc, or cannot resolve a library at all.
#
# Only binaries linked by the Nix toolchain are checked, i.e. those recording a
# store path as their interpreter or RUNPATH. Prebuilt upstream binaries (such
# as the ones the cmake package ships) use the system loader instead.
#
# Build-context packages provide the tools that run during the build (protoc,
# grpc_cpp_plugin, ...). Their package ID does not change when a Nix toolchain
# update moves the GCC runtime to a new store path, so a cached binary has to
# get by with the pinned glibc alone. See docs/build/nix.md.
#
# Usage: bin/nix/check-build-context-runtime.sh <graph.json>
# <graph.json> is the output of `conan install --format=json`.
set -euo pipefail
if [ "$#" -ne 1 ]; then
echo "usage: $0 <graph.json>" >&2
exit 2
fi
if [ "$(uname -s)" != "Linux" ]; then
echo "$0: Linux only" >&2
exit 2
fi
folders="$(jq -r '.graph.nodes[] | select(.context == "build" and .package_folder) | .package_folder' "$1" | sort -u)"
checked=0
failed=0
while IFS= read -r file; do
case "$(file -b "${file}")" in
ELF*) ;;
*) continue ;;
esac
[[ "$(readelf -ldW "${file}")" == */nix/store/* ]] || continue
checked=$((checked + 1))
# `ldd` lists the interpreter and every library as the loader resolves them.
if deps="$(ldd "${file}" 2>&1)"; then
bad="$(printf '%s\n' "${deps}" |
grep -E 'not found|/nix/store/' |
grep -vE '/nix/store/[^/]+-glibc-[^/]+/' || true)"
else
case "${deps}" in
*"not a dynamic executable"*) continue ;;
esac
bad="${deps}"
fi
if [ -n "${bad}" ]; then
failed=$((failed + 1))
echo "::error file=${file}::loads a library from the Nix store other than glibc"
echo "${file}"
echo "${bad}" | sed 's/^/ /'
fi
done < <(
# shellcheck disable=SC2086 # one folder per line, no spaces in Conan paths
[ -z "${folders}" ] || find ${folders} -type f \( -perm -u+x -o -name '*.so*' \)
)
echo "Build-context packages: checked ${checked} binaries, ${failed} failed."
[ "${failed}" -eq 0 ]
@@ -10,7 +10,7 @@
# alone; the scripts in a Conan cache are all git hook samples and autotools # alone; the scripts in a Conan cache are all git hook samples and autotools
# scratch, 36 false positives to 0 real. # scratch, 36 false positives to 0 real.
# #
# Usage: bin/check-nix-store-refs.sh <path> # Usage: bin/nix/check-nix-store-refs.sh <path>
set -euo pipefail set -euo pipefail
File renamed without changes.
+20 -5
View File
@@ -9,12 +9,13 @@ ARG DEBIAN_FRONTEND=noninteractive
RUN <<EOF RUN <<EOF
pkgs=() pkgs=()
pkgs+=(ca-certificates) # Trust store for curl, git, pip and nix.
pkgs+=(curl) # Required to install nix. pkgs+=(curl) # Required to install nix.
pkgs+=(doxygen) # Needed for Clio's check-doxygen-docs.sh. pkgs+=(doxygen) # Needed for Clio's check-doxygen-docs.sh.
pkgs+=(git) # Required for prepare-runner. pkgs+=(git) # Required for prepare-runner.
pkgs+=(libatomic1) # Required to run pre-commit provided `node`. pkgs+=(libatomic1) # Required to run pre-commit provided `node`.
pkgs+=(python3) # Python 3 interpreter. pkgs+=(python3) # Python 3 interpreter.
pkgs+=(python3-pip) # Package manager for Python applications. pkgs+=(python3-venv) # Virtual environment for Python applications.
pkgs+=(xz-utils) # Required to install nix pkgs+=(xz-utils) # Required to install nix
apt-get update apt-get update
@@ -23,9 +24,21 @@ apt-get clean
rm -rf /var/lib/apt/lists/* rm -rf /var/lib/apt/lists/*
EOF EOF
ARG PRE_COMMIT_VERSION=4.6.0 # Sanity-check that the system CA bundle distrusts the compromised eMudhra roots,
RUN pip install --no-cache --break-system-packages \ # before pip and the nix installer download anything with it.
pre-commit==${PRE_COMMIT_VERSION} RUN --mount=type=bind,source=bin/check-distrusted-roots.sh,target=/check-distrusted-roots.sh \
/check-distrusted-roots.sh
# Ahead of the system Python on PATH,
# so `python3` and `pip` resolve to the venv and installs stay out of the system Python.
ENV VIRTUAL_ENV="/opt/venv"
ENV PATH="${VIRTUAL_ENV}/bin:${PATH}"
ARG PRE_COMMIT_VERSION=4.6.2
RUN <<EOF
python3 -m venv "${VIRTUAL_ENV}"
pip install --no-cache pre-commit==${PRE_COMMIT_VERSION}
EOF
RUN sh <(curl --proto '=https' --tlsv1.2 -L https://nixos.org/nix/install) --daemon --yes RUN sh <(curl --proto '=https' --tlsv1.2 -L https://nixos.org/nix/install) --daemon --yes
@@ -33,7 +46,9 @@ RUN sh <(curl --proto '=https' --tlsv1.2 -L https://nixos.org/nix/install) --dae
# so nix is available in all shells including non-interactive shells (e.g., GitHub Actions). # so nix is available in all shells including non-interactive shells (e.g., GitHub Actions).
ENV PATH="/nix/var/nix/profiles/default/bin:${PATH}" ENV PATH="/nix/var/nix/profiles/default/bin:${PATH}"
ENV NIX_PROFILES="/nix/var/nix/profiles/default" ENV NIX_PROFILES="/nix/var/nix/profiles/default"
ENV NIX_SSL_CERT_FILE="/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt" # The system bundle gets security updates through apt;
# the one in the Nix profile is frozen at the installer's nixpkgs.
ENV NIX_SSL_CERT_FILE="/etc/ssl/certs/ca-certificates.crt"
# Verify nix installation # Verify nix installation
RUN nix --version RUN nix --version
+23 -61
View File
@@ -5,15 +5,6 @@ The script determines the staged files itself (see `pass_filenames: false` in
.pre-commit-config.yaml) so run-clang-tidy is run once and handles parallelism .pre-commit-config.yaml) so run-clang-tidy is run once and handles parallelism
internally: pre-commit would otherwise split the files across parallel hook internally: pre-commit would otherwise split the files across parallel hook
invocations that race when fixes edit a shared header. invocations that race when fixes edit a shared header.
Fixes are collected with `-export-fixes` and applied by clang-apply-replacements
in a separate step rather than with run-clang-tidy's `-fix`. The `add_module`
build isolates each module's headers behind a per-module symlink directory
(build/modules/<module>/...), so a header reachable from several translation
units is referenced through different paths that all resolve to the same source
file. clang-apply-replacements deduplicates identical replacements by their
literal path, so those paths must be canonicalised to the real source path
first; otherwise the same fix is applied once per path and corrupts the header.
""" """
from __future__ import annotations from __future__ import annotations
@@ -23,24 +14,29 @@ import re
import shutil import shutil
import subprocess import subprocess
import sys import sys
import tempfile
from pathlib import Path from pathlib import Path
CLANG_TIDY_VERSION = 22
# Extensions run-clang-tidy can analyse: `.cpp` translation units and, thanks to # Extensions run-clang-tidy can analyse: `.cpp` translation units and, thanks to
# the `verify_headers` build option, `.h`/`.hpp` headers (each has its own # the `verify_headers` build option, `.h`/`.hpp` headers (each has its own
# compile_commands.json entry). `.ipp` fragments have no entry and are skipped. # compile_commands.json entry). `.ipp` fragments have no entry and are skipped.
TIDY_EXTENSIONS = {".cpp", ".h", ".hpp"} TIDY_EXTENSIONS = {".cpp", ".h", ".hpp"}
# A single-quoted `FilePath:` entry in an -export-fixes YAML file, allowing the
# `- ` marker that precedes it inside a `Replacements:` sequence. clang-tidy def clang_tidy_major() -> str | None:
# emits paths single-quoted and doubles any embedded quote per YAML rules. """Major version of the `clang-tidy` on PATH, which run-clang-tidy invokes."""
FILEPATH_RE = re.compile(r"^(\s*(?:-\s+)?FilePath:\s*)'((?:[^']|'')*)'\s*$") if not (clang_tidy := shutil.which("clang-tidy")):
return None
output = subprocess.run(
[clang_tidy, "--version"], capture_output=True, text=True
).stdout
m = re.search(r"LLVM version (\d+)", output)
return m.group(1) if m else None
def find_tool(name: str) -> str | None: def find_tool(name: str, version: str | None) -> str | None:
for candidate in (f"{name}-{CLANG_TIDY_VERSION}", name): """Prefer `<name>-<version>`, so a host tool of another version can't win."""
candidates = ([f"{name}-{version}"] if version else []) + [name]
for candidate in candidates:
if path := shutil.which(candidate): if path := shutil.which(candidate):
return path return path
return None return None
@@ -68,25 +64,6 @@ def staged_files(repo_root: Path) -> list[Path]:
return [repo_root / rel for rel in output.splitlines() if rel] return [repo_root / rel for rel in output.splitlines() if rel]
def canonicalize_fix_paths(fixes_dir: Path) -> None:
"""Rewrite every `FilePath` in the exported fixes to its real source path.
A header included through a module's isolation symlink is recorded under that
symlink's path; collapsing all paths to the same real file lets
clang-apply-replacements recognise the per-translation-unit duplicates and
apply each fix once.
"""
for yaml in fixes_dir.glob("*.yaml"):
lines = []
for line in yaml.read_text().splitlines():
if m := FILEPATH_RE.match(line):
path = m.group(2).replace("''", "'")
real = os.path.realpath(path).replace("'", "''")
line = f"{m.group(1)}'{real}'"
lines.append(line)
yaml.write_text("\n".join(lines) + "\n")
def main(): def main():
if not os.environ.get("TIDY"): if not os.environ.get("TIDY"):
return 0 return 0
@@ -103,20 +80,13 @@ def main():
if not files: if not files:
return 0 return 0
run_clang_tidy = find_tool("run-clang-tidy") version = clang_tidy_major()
clang_apply_replacements = find_tool("clang-apply-replacements") run_clang_tidy = find_tool("run-clang-tidy", version)
missing = [ if not run_clang_tidy:
name tried = f" (tried the '-{version}' suffix too)" if version else ""
for name, path in (
("run-clang-tidy", run_clang_tidy),
("clang-apply-replacements", clang_apply_replacements),
)
if not path
]
if missing:
print( print(
f"clang-tidy check failed: TIDY is enabled but {' and '.join(missing)} " f"clang-tidy check failed: TIDY is enabled but run-clang-tidy "
f"was not found in PATH (tried the '-{CLANG_TIDY_VERSION}' suffix too).", f"was not found in PATH{tried}.",
file=sys.stderr, file=sys.stderr,
) )
return 1 return 1
@@ -130,27 +100,19 @@ def main():
) )
return 1 return 1
with tempfile.TemporaryDirectory() as fixes_dir:
result = subprocess.run( result = subprocess.run(
[ [
run_clang_tidy, run_clang_tidy,
"-quiet", "-quiet",
"-p", "-p",
build_dir, build_dir,
"-export-fixes", "-fix",
fixes_dir, "-format",
"-allow-no-checks", "-allow-no-checks",
] ]
+ files + files
) )
canonicalize_fix_paths(Path(fixes_dir)) return result.returncode
# `FormatStyle` in .clang-tidy does not reach this path,
# so ask for the repository style here.
applied = subprocess.run(
[clang_apply_replacements, "--format", "--style=file", fixes_dir]
)
return result.returncode or applied.returncode
if __name__ == "__main__": if __name__ == "__main__":
+33
View File
@@ -1360,6 +1360,39 @@
# Example: # Example:
# owner_reserve = 200000 # 0.2 XRP # owner_reserve = 200000 # 0.2 XRP
# #
# gas_limit = <gas>
#
# The gas limit is the maximum amount of gas that can be
# consumed by a single transaction. The gas limit is used to prevent
# transactions from consuming too many resources.
#
# If this parameter is unspecified, xrpld will use an internal
# default. Don't change this without understanding the consequences.
#
# Example:
# gas_limit = 1000000 # 1 million gas
#
# bytecode_size_limit = <bytes>
#
# The bytecode size limit is the maximum size of a WASM extension in
# bytes. The size limit is used to prevent extensions from consuming
# too many resources.
#
# If this parameter is unspecified, xrpld will use an internal
# default. Don't change this without understanding the consequences.
#
# Example:
# bytecode_size_limit = 100000 # 100 kb
#
# gas_price = <micro-drops>
#
# The gas price is the conversion between WASM gas and its price in drops.
#
# If this parameter is unspecified, xrpld will use an internal
# default. Don't change this without understanding the consequences.
#
# Example:
# gas_price = 1000000 # 1 drop per gas
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
# #
# 9. Misc Settings # 9. Misc Settings
+11 -3
View File
@@ -9,13 +9,21 @@ include_guard(GLOBAL)
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# Compiler detection (C++) # Compiler detection (C++)
# -------------------------------------------------------------------- # --------------------------------------------------------------------
set(is_clang FALSE) # is_any_clang is true for both LLVM Clang and AppleClang. Their version numbers
# and feature sets differ, so use is_llvm_clang or is_apple_clang when it matters.
set(is_any_clang FALSE)
set(is_llvm_clang FALSE)
set(is_apple_clang FALSE)
set(is_gcc FALSE) set(is_gcc FALSE)
set(is_msvc FALSE) set(is_msvc FALSE)
set(is_xcode FALSE) set(is_xcode FALSE)
if(CMAKE_CXX_COMPILER_ID MATCHES ".*Clang") # Clang or AppleClang if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
set(is_clang TRUE) set(is_any_clang TRUE)
set(is_llvm_clang TRUE)
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
set(is_any_clang TRUE)
set(is_apple_clang TRUE)
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set(is_gcc TRUE) set(is_gcc TRUE)
elseif(MSVC) elseif(MSVC)
+2 -2
View File
@@ -17,7 +17,7 @@
(runtime libraries resolved through the rpath) are skipped too. (runtime libraries resolved through the rpath) are skipped too.
Everywhere else `patch_nix_binary` is a no-op. Everywhere else `patch_nix_binary` is a no-op.
The default loader is resolved by bin/default-loader-path.sh. The default loader is resolved by bin/nix/default-loader-path.sh.
#]===================================================================] #]===================================================================]
include_guard(GLOBAL) include_guard(GLOBAL)
@@ -25,7 +25,7 @@ include_guard(GLOBAL)
include(CompilationEnv) include(CompilationEnv)
# Resolves the system default ELF loader path for the current architecture. # Resolves the system default ELF loader path for the current architecture.
set(_loader_path_script "${CMAKE_SOURCE_DIR}/bin/default-loader-path.sh") set(_loader_path_script "${CMAKE_SOURCE_DIR}/bin/nix/default-loader-path.sh")
if( if(
is_linux is_linux
+6 -3
View File
@@ -130,7 +130,7 @@ else()
INTERFACE INTERFACE
-Wall -Wall
-Wdeprecated -Wdeprecated
$<$<BOOL:${is_clang}>:-Wno-deprecated-declarations> $<$<BOOL:${is_any_clang}>:-Wno-deprecated-declarations>
$<$<BOOL:${wextra}>:-Wextra $<$<BOOL:${wextra}>:-Wextra
-Wno-unused-parameter> -Wno-unused-parameter>
$<$<BOOL:${werr}>:-Werror> $<$<BOOL:${werr}>:-Werror>
@@ -177,7 +177,7 @@ else()
if( if(
is_nix_compiler is_nix_compiler
AND is_linux AND is_linux
AND is_clang AND is_any_clang
AND CMAKE_CXX_FLAGS MATCHES "stdlib=libstdc" AND CMAKE_CXX_FLAGS MATCHES "stdlib=libstdc"
) )
string( string(
@@ -204,7 +204,10 @@ if(voidstar)
"Antithesis instrumentation requires Linux, aborting..." "Antithesis instrumentation requires Linux, aborting..."
) )
elseif( elseif(
NOT (is_clang AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 16.0) NOT (
is_llvm_clang
AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 16.0
)
) )
message( message(
FATAL_ERROR FATAL_ERROR
+20
View File
@@ -292,6 +292,25 @@ if(xrpld)
) )
target_sources(xrpld PRIVATE ${sources}) target_sources(xrpld PRIVATE ${sources})
rpcspec_generate_instantiations(
OUT_VAR rpcspec_instantiations
VALUE_TYPE "::json::Value"
VIEW_HEADER "xrpld/rpc/detail/JsonObjectView.hpp"
HANDLERS
account_channels
account_currencies
account_info
account_lines
account_nfts
account_offers
book_changes
deposit_authorized
ledger
nft_offers_common
transaction_entry
)
target_sources(xrpld PRIVATE ${rpcspec_instantiations})
if(tests) if(tests)
file( file(
GLOB_RECURSE sources GLOB_RECURSE sources
@@ -322,6 +341,7 @@ if(xrpld)
# antithesis_instrumentation.h, which is not exported as INTERFACE # antithesis_instrumentation.h, which is not exported as INTERFACE
target_include_directories( target_include_directories(
xrpld xrpld
SYSTEM
PRIVATE ${CMAKE_SOURCE_DIR}/external/antithesis-sdk PRIVATE ${CMAKE_SOURCE_DIR}/external/antithesis-sdk
) )
endif() endif()
+7 -2
View File
@@ -58,7 +58,7 @@ target_link_options(common INTERFACE ${sanitizers_linker_flags})
# This module appends -fsanitize-ignorelist=<path> for Clang builds. # This module appends -fsanitize-ignorelist=<path> for Clang builds.
# The ignorelist path contains CMAKE_SOURCE_DIR, so it must be set here, rather than in the Conan profile. # The ignorelist path contains CMAKE_SOURCE_DIR, so it must be set here, rather than in the Conan profile.
# GCC does not support -fsanitize-ignorelist. # GCC does not support -fsanitize-ignorelist.
if(is_clang) if(is_any_clang)
set(ignorelist_path set(ignorelist_path
"${CMAKE_SOURCE_DIR}/sanitizers/suppressions/sanitizer-ignorelist.txt" "${CMAKE_SOURCE_DIR}/sanitizers/suppressions/sanitizer-ignorelist.txt"
) )
@@ -77,19 +77,24 @@ if(is_clang)
message(STATUS " Ignorelist: ${ignorelist_path}") message(STATUS " Ignorelist: ${ignorelist_path}")
endif() endif()
# Define SANITIZERS macro for BuildInfo.cpp # Define the SANITIZERS macro for BuildInfo.cpp, plus one of XRPL_ASAN,
# XRPL_TSAN and XRPL_UBSAN per active sanitizer, so that code can test for a
# specific one with #ifdef instead of parsing the dot-joined SANITIZERS string.
set(sanitizers_list) set(sanitizers_list)
if(SANITIZERS MATCHES "address") if(SANITIZERS MATCHES "address")
set(enable_asan ON) set(enable_asan ON)
list(APPEND sanitizers_list "ASAN") list(APPEND sanitizers_list "ASAN")
target_compile_definitions(common INTERFACE XRPL_ASAN)
endif() endif()
if(SANITIZERS MATCHES "thread") if(SANITIZERS MATCHES "thread")
set(enable_tsan ON) set(enable_tsan ON)
list(APPEND sanitizers_list "TSAN") list(APPEND sanitizers_list "TSAN")
target_compile_definitions(common INTERFACE XRPL_TSAN)
endif() endif()
if(SANITIZERS MATCHES "undefinedbehavior") if(SANITIZERS MATCHES "undefinedbehavior")
set(enable_ubsan ON) set(enable_ubsan ON)
list(APPEND sanitizers_list "UBSAN") list(APPEND sanitizers_list "UBSAN")
target_compile_definitions(common INTERFACE XRPL_UBSAN)
endif() endif()
if(sanitizers_list) if(sanitizers_list)
+2 -5
View File
@@ -23,11 +23,8 @@ if(NOT is_multiconfig)
endif() endif()
endif() endif()
if(is_clang) # both Clang and AppleClang if(is_llvm_clang)
if( if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 16.0)
"${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang"
AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 16.0
)
message(FATAL_ERROR "This project requires clang 16 or later") message(FATAL_ERROR "This project requires clang 16 or later")
endif() endif()
elseif(is_gcc) elseif(is_gcc)
+3 -3
View File
@@ -62,11 +62,11 @@ if(unity)
set(CMAKE_UNITY_BUILD ON CACHE BOOL "Do a unity build") set(CMAKE_UNITY_BUILD ON CACHE BOOL "Do a unity build")
endif() endif()
if(is_clang AND is_linux) if(is_llvm_clang AND is_linux)
option(voidstar "Enable Antithesis instrumentation." OFF) option(voidstar "Enable Antithesis instrumentation." OFF)
endif() endif()
if(is_gcc OR is_clang) if(is_gcc OR is_any_clang)
include(ProcessorCount) include(ProcessorCount)
ProcessorCount(PROCESSOR_COUNT) ProcessorCount(PROCESSOR_COUNT)
@@ -125,7 +125,7 @@ else()
set(use_mold OFF CACHE BOOL "mold linker, linux only" FORCE) set(use_mold OFF CACHE BOOL "mold linker, linux only" FORCE)
endif() endif()
if(is_clang) if(is_any_clang)
option(use_lld "enables detection of lld linker" ON) option(use_lld "enables detection of lld linker" ON)
else() else()
set(use_lld OFF CACHE BOOL "try lld linker, clang only" FORCE) set(use_lld OFF CACHE BOOL "try lld linker, clang only" FORCE)
+2 -1
View File
@@ -34,11 +34,12 @@ include(create_symbolic_link)
# sometimes `PUBLIC` and sometimes `PRIVATE`. # sometimes `PUBLIC` and sometimes `PRIVATE`.
# The Cs are all guaranteed to be unique. # The Cs are all guaranteed to be unique.
# We can guarantee a unique X per target by using # We can guarantee a unique X per target by using
# `${CMAKE_CURRENT_BINARY_DIR}/include/${target}`. # `${CMAKE_CURRENT_BINARY_DIR}/modules/${target}`.
# #
# isolate_headers(target A B scope) # isolate_headers(target A B scope)
function(isolate_headers target A B scope) function(isolate_headers target A B scope)
file(RELATIVE_PATH C "${A}" "${B}") file(RELATIVE_PATH C "${A}" "${B}")
# Keep in sync with ExcludeHeaderFilterRegex in .clang-tidy.
set(X "${CMAKE_CURRENT_BINARY_DIR}/modules/${target}") set(X "${CMAKE_CURRENT_BINARY_DIR}/modules/${target}")
set(Y "${X}/${C}") set(Y "${X}/${C}")
cmake_path(GET Y PARENT_PATH parent) cmake_path(GET Y PARENT_PATH parent)
+2 -2
View File
@@ -7,7 +7,7 @@
pcpp>=1.30 pcpp>=1.30
# Parser combinator library - used to parse the macro DSL # Parser combinator library - used to parse the macro DSL
pyparsing>=3.0.0 pyparsing>=3.3.3
# Template engine - used to generate C++ code from templates # Template engine - used to generate C++ code from templates
Mako>=1.2.2 Mako>=1.4.2
+6 -6
View File
@@ -1,8 +1,8 @@
# This file was autogenerated by uv via the following command: # This file was autogenerated by uv via the following command:
# uv pip compile requirements.in --generate-hashes --output-file requirements.txt # uv pip compile requirements.in --generate-hashes --output-file requirements.txt
mako==1.3.12 \ mako==1.4.3 \
--hash=sha256:8f61569480282dbf557145ce441e4ba888be453c30989f879f0d652e39f53ea9 \ --hash=sha256:723296007c870bfd6b3f0c3230dba7198096e5269297ebf5e4eff9e7ffa39d4f \
--hash=sha256:9f778e93289bd410bb35daadeb4fc66d95a746f0b75777b942088b7fd7af550a --hash=sha256:cd6537fe88d5fec315c55c2f8529bc4ce7a9a352ad7db3eeaa6a66e2dd4ec37a
# via -r requirements.in # via -r requirements.in
markupsafe==3.0.3 \ markupsafe==3.0.3 \
--hash=sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f \ --hash=sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f \
@@ -99,7 +99,7 @@ pcpp==1.30 \
--hash=sha256:05fe08292b6da57f385001c891a87f40d6aa7f46787b03e8ba326d20a3297c6e \ --hash=sha256:05fe08292b6da57f385001c891a87f40d6aa7f46787b03e8ba326d20a3297c6e \
--hash=sha256:5af9fbce55f136d7931ae915fae03c34030a3b36c496e72d9636cedc8e2543a1 --hash=sha256:5af9fbce55f136d7931ae915fae03c34030a3b36c496e72d9636cedc8e2543a1
# via -r requirements.in # via -r requirements.in
pyparsing==3.3.2 \ pyparsing==3.3.3 \
--hash=sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d \ --hash=sha256:928ae7e20211f3b6f3915a72f06a0cfd29ab9d24279dd6346b6b1a7146397d36 \
--hash=sha256:c777f4d763f140633dcb6d8a3eda953bf7a214dc4eff598413c070bcdc117cbc --hash=sha256:ece8c00a69cf01b45d0b1dedabb469c90d8caf996d4fda40f147627a122849a4
# via -r requirements.in # via -r requirements.in
+7 -3
View File
@@ -3,11 +3,11 @@
"requires": [ "requires": [
"zlib/1.3.2#1cb806da49011867778ffb6ac7190fcb%1782392402.122708", "zlib/1.3.2#1cb806da49011867778ffb6ac7190fcb%1782392402.122708",
"xxhash/0.8.3#681d36a0a6111fc56e5e45ea182c19cc%1782392402.420688", "xxhash/0.8.3#681d36a0a6111fc56e5e45ea182c19cc%1782392402.420688",
"xrpl-rpc-spec/0.1.19#870b2d3abcfbbf13b61c2d3c69495060%1790348286.187549", "xrpl-rpc-spec/0.1.29#852afc87cac32aca93cc50a985d73fe0%1792359643.19817",
"sqlite3/3.53.0#324ada52333108388a9a6108bfa96734%1782392403.185447", "sqlite3/3.53.0#324ada52333108388a9a6108bfa96734%1782392403.185447",
"soci/4.0.3#e726491a03468795453f7c83fc924a96%1782392402.679521", "soci/4.0.3#e726491a03468795453f7c83fc924a96%1782392402.679521",
"snappy/1.1.10#968fef506ff261592ec30c574d4a7809%1782307151.633168", "snappy/1.1.10#968fef506ff261592ec30c574d4a7809%1782307151.633168",
"secp256k1/0.7.1#b1f450b7f78a36fff75bb6934a356f3a%1782338841.3729", "secp256k1/0.7.1#f4d16a4d907dd057598954476ca6f88c%1792234329.790275",
"rocksdb/10.5.1#4a197eca381a3e5ae8adf8cffa5aacd0%1782392413.075713", "rocksdb/10.5.1#4a197eca381a3e5ae8adf8cffa5aacd0%1782392413.075713",
"re2/20251105#8579cfd0bda4daf0683f9e3898f964b4%1782392402.431897", "re2/20251105#8579cfd0bda4daf0683f9e3898f964b4%1782392402.431897",
"protobuf/6.33.5#ff253ead763bd8d9904a52979cd21e81%1782392410.233933", "protobuf/6.33.5#ff253ead763bd8d9904a52979cd21e81%1782392410.233933",
@@ -20,7 +20,7 @@
"libarchive/3.8.7#c446109bd1f1d8ba7936c94189bc50e6%1782392403.066892", "libarchive/3.8.7#c446109bd1f1d8ba7936c94189bc50e6%1782392403.066892",
"jemalloc/5.3.1#1fc58d55316041f10fbc1e8a2eae632a%1776700028.228", "jemalloc/5.3.1#1fc58d55316041f10fbc1e8a2eae632a%1776700028.228",
"gtest/1.17.0#5224b3b3ff3b4ce1133cbdd27d53ee7d%1782392402.791979", "gtest/1.17.0#5224b3b3ff3b4ce1133cbdd27d53ee7d%1782392402.791979",
"grpc/1.81.1#b87796a4269034856cbc1a2522db16eb%1788275071.530512", "grpc/1.81.1#aaa93ab6cda2f2baa6a84490582c8adf%1791284951.826256",
"fast_float/8.2.10#f6f28d6bb22112078e7dbda611caf681%1785888854.601666", "fast_float/8.2.10#f6f28d6bb22112078e7dbda611caf681%1785888854.601666",
"ed25519/2015.03#ae761bdc52730a843f0809bdf6c1b1f6%1782307148.15562", "ed25519/2015.03#ae761bdc52730a843f0809bdf6c1b1f6%1782307148.15562",
"date/3.0.4#862e11e80030356b53c2c38599ceb32b%1782392402.538492", "date/3.0.4#862e11e80030356b53c2c38599ceb32b%1782392402.538492",
@@ -34,11 +34,15 @@
"build_requires": [ "build_requires": [
"zlib/1.3.2#1cb806da49011867778ffb6ac7190fcb%1782392402.122708", "zlib/1.3.2#1cb806da49011867778ffb6ac7190fcb%1782392402.122708",
"strawberryperl/5.32.1.1#8d114504d172cfea8ea1662d09b6333e%1782395692.540639", "strawberryperl/5.32.1.1#8d114504d172cfea8ea1662d09b6333e%1782395692.540639",
"re2/20251105#8579cfd0bda4daf0683f9e3898f964b4%1782392402.431897",
"protobuf/6.33.5#ff253ead763bd8d9904a52979cd21e81%1782392410.233933", "protobuf/6.33.5#ff253ead763bd8d9904a52979cd21e81%1782392410.233933",
"openssl/3.6.3#f806de8933e3bf6f01016c6a888cee2e%1783945160.863288",
"nasm/2.16.01#31e26f2ee3c4346ecd347911bd126904%1782395690.33162", "nasm/2.16.01#31e26f2ee3c4346ecd347911bd126904%1782395690.33162",
"msys2/cci.latest#d22fe7b2808f5fd34d0a7923ace9c54f%1770657326.649", "msys2/cci.latest#d22fe7b2808f5fd34d0a7923ace9c54f%1770657326.649",
"m4/1.4.19#1727f439cf74e83826ec96d0b4904eee%1784541921.659", "m4/1.4.19#1727f439cf74e83826ec96d0b4904eee%1784541921.659",
"grpc/1.81.1#aaa93ab6cda2f2baa6a84490582c8adf%1791284951.826256",
"cmake/4.3.3#840cf00ea09777e05c2050a50a82c722%1782392418.696091", "cmake/4.3.3#840cf00ea09777e05c2050a50a82c722%1782392418.696091",
"c-ares/1.34.6#545240bb1c40e2cacd4362d6b8967650%1782392402.681654",
"b2/5.4.2#ffd6084a119587e70f11cd45d1a386e2%1782392402.624226", "b2/5.4.2#ffd6084a119587e70f11cd45d1a386e2%1782392402.624226",
"automake/1.16.5#b91b7c384c3deaa9d535be02da14d04f%1755524470.56", "automake/1.16.5#b91b7c384c3deaa9d535be02da14d04f%1755524470.56",
"autoconf/2.71#51077f068e61700d65bb05541ea1e4b0%1731054366.86", "autoconf/2.71#51077f068e61700d65bb05541ea1e4b0%1731054366.86",
+9 -1
View File
@@ -3,5 +3,13 @@
core:non_interactive=True core:non_interactive=True
core.download:parallel={{ os.cpu_count() }} core.download:parallel={{ os.cpu_count() }}
core.upload:parallel={{ os.cpu_count() }} core.upload:parallel={{ os.cpu_count() }}
tools.files.download:retry=5 # Fall back to Conan Center's source backups when a recipe's upstream URL is down
# (e.g. the GNU FTP mirrors), see
# https://github.com/conan-io/conan-center-index/issues/28147#issuecomment-3183544772
# The backups are only tried once every upstream URL has used up its retries,
# so keep the retries low.
core.sources:download_urls=["origin", "https://c3i.jfrog.io/artifactory/conan-center-backup-sources"]
tools.files.download:retry=1
tools.files.download:retry_wait=10 tools.files.download:retry_wait=10
# Fail fast on unreachable hosts (default connect timeout is 30s), keep the 60s read timeout.
core.net.http:timeout=(5, 60)
+31 -4
View File
@@ -29,9 +29,9 @@ os.version={{ min_macos_version }}
[conf] [conf]
{# The Boost recipe builds with b2, which doesn't use Conan's toolchain files. #} {# The Boost recipe builds with b2, which doesn't use Conan's toolchain files. #}
{# Instead it hand-rolls the compiler for user-config.jam, #} {# Instead it hand-rolls the compiler for user-config.jam, #}
{# and its fallback probes a version-suffixed binary (e.g. `g++-15`) before plain `g++`. #} {# and its fallback probes a version-suffixed binary (e.g. `g++-<major>`) before plain `g++`. #}
{# Inside the Nix shell the wrapper only provides `g++`/`gcc` (no `-15` suffix), #} {# Inside the Nix shell the wrapper only provides `g++`/`gcc` (no `-<major>` suffix), #}
{# so on a host that also has a system `g++-15` the probe escapes Nix #} {# so on a host that also has a system `g++-<major>` the probe escapes Nix #}
{# and picks the system compiler, which is mismatched with the Nix libraries #} {# and picks the system compiler, which is mismatched with the Nix libraries #}
{# and breaks the build (e.g. Boost.Stacktrace link checks fail). #} {# and breaks the build (e.g. Boost.Stacktrace link checks fail). #}
{# Pinning the executables here short-circuits that probe so Boost (and the rest of the toolchain) #} {# Pinning the executables here short-circuits that probe so Boost (and the rest of the toolchain) #}
@@ -49,8 +49,31 @@ tools.build:compiler_executables={'c':'{{ cc_exe }}','cpp':'{{ cxx_exe }}'}
user.package:cppstd_version=23 user.package:cppstd_version=23
tools.info.package_id:confs+=["user.package:cppstd_version"] tools.info.package_id:confs+=["user.package:cppstd_version"]
{% if os == "Macos" %} {% if os == "Linux" and context == "build" %}
{# Build-context executables (protoc, grpc_cpp_plugin, build tools) run during the build #}
{# and would otherwise load libstdc++/libgcc from a Nix store path #}
{# that might change with a Nix toolchain update. #}
{# --as-needed drops the ones they link but don't use, #}
{# such as libatomic for grpc_cpp_plugin on arm64. #}
{% set static_runtime_flags = ["-static-libstdc++", "-static-libgcc", "-Wl,--as-needed"] %}
tools.build:exelinkflags+={{ static_runtime_flags }}
tools.info.package_id:confs+=["tools.build:exelinkflags"]
{% endif %}
{% if os == "Linux" and context == "build" %}
{# b2 links itself with its own script, which ignores exelinkflags #}
{# and only takes CXXFLAGS when use_cxx_env is set (see [buildenv] below). #}
[options]
b2/*:use_cxx_env=True
{% endif %}
[buildenv] [buildenv]
{# gRPC emits thousands of compiler warnings that we cannot act on. #}
{# CMake picks up CXXFLAGS, and unlike tools.build:cxxflags, #}
{# this is not part of the package ID, so binaries stay shareable. #}
grpc/*:CXXFLAGS=-w
{% if os == "Macos" %}
{# os.version adds -mmacosx-version-min to compiler command lines, #} {# os.version adds -mmacosx-version-min to compiler command lines, #}
{# but Boost.Context's b2 assembly (.S) rule ignores it, #} {# but Boost.Context's b2 assembly (.S) rule ignores it, #}
{# so those objects keep the host SDK version and still warn at link time. #} {# so those objects keep the host SDK version and still warn at link time. #}
@@ -58,3 +81,7 @@ tools.info.package_id:confs+=["user.package:cppstd_version"]
{# Scoped to boost/* since it is the only gap. #} {# Scoped to boost/* since it is the only gap. #}
boost/*:MACOSX_DEPLOYMENT_TARGET={{ min_macos_version }} boost/*:MACOSX_DEPLOYMENT_TARGET={{ min_macos_version }}
{% endif %} {% endif %}
{% if os == "Linux" and context == "build" %}
b2/*:CXXFLAGS={{ static_runtime_flags | join(" ") }}
{% endif %}
+3
View File
@@ -5,6 +5,9 @@ include(default)
{% if not sanitizers %} {% if not sanitizers %}
{# Sanitizers not configured; no additional settings needed #} {# Sanitizers not configured; no additional settings needed #}
{% elif context == "build" %}
{# Build-context packages are tools we run, not code we test, #}
{# so don't instrument them #}
{% else %} {% else %}
{% if compiler == "msvc" %} {% if compiler == "msvc" %}
+8 -3
View File
@@ -40,7 +40,7 @@ class Xrpl(ConanFile):
"nudb/2.0.9", "nudb/2.0.9",
"openssl/3.6.3", "openssl/3.6.3",
"soci/4.0.3", "soci/4.0.3",
"xrpl-rpc-spec/0.1.19", "xrpl-rpc-spec/0.1.29",
"zlib/1.3.2", "zlib/1.3.2",
] ]
@@ -49,7 +49,8 @@ class Xrpl(ConanFile):
] ]
tool_requires = [ tool_requires = [
"protobuf/6.33.5", "grpc/<host_version>",
"protobuf/<host_version>",
] ]
default_options = { default_options = {
@@ -123,6 +124,10 @@ class Xrpl(ConanFile):
"xxhash/*:shared": False, "xxhash/*:shared": False,
} }
# default_options only reach the host context;
# give tool_requires (and their dependencies) the same dependency options.
default_build_options = {k: v for k, v in default_options.items() if "/" in k}
def set_version(self): def set_version(self):
self.version = self.version or DEV_VERSION self.version = self.version or DEV_VERSION
@@ -149,7 +154,7 @@ class Xrpl(ConanFile):
self.requires("xxhash/0.8.3", transitive_headers=True) self.requires("xxhash/0.8.3", transitive_headers=True)
exports_sources = ( exports_sources = (
"bin/default-loader-path.sh", "bin/nix/default-loader-path.sh",
"CMakeLists.txt", "CMakeLists.txt",
"cfg/*", "cfg/*",
"cmake/*", "cmake/*",
+5 -6
View File
@@ -80,13 +80,12 @@ function(add_xrpl_crate name)
# `cc` picks its runtime flag from `crt-static` alone, so it compiles a # `cc` picks its runtime flag from `crt-static` alone, so it compiles a
# crate's C++ with `-MT`; Debug needs `-MTd` (to match cmake/XrplCompiler.cmake). # crate's C++ with `-MT`; Debug needs `-MTd` (to match cmake/XrplCompiler.cmake).
if(is_msvc) if(is_msvc)
corrosion_set_env_vars( corrosion_set_env_vars(${ARG_CRATE} "$<$<CONFIG:Debug>:CXXFLAGS=-MTd>")
${ARG_CRATE}
"$<$<CONFIG:Debug>:CXXFLAGS=-MTd>"
)
endif() endif()
corrosion_add_cxxbridge(${name}_cxxbridge CRATE ${ARG_CRATE} FILES corrosion_add_cxxbridge(
${ARG_FILES} ${name}_cxxbridge
CRATE ${ARG_CRATE}
FILES ${ARG_FILES}
) )
# Generated cxxbridge headers don't exist at configure time; CMake 3.28+ # Generated cxxbridge headers don't exist at configure time; CMake 3.28+
# validates INTERFACE_SOURCES on consuming targets. Clear it to skip the # validates INTERFACE_SOURCES on consuming targets. Clear it to skip the
+10 -10
View File
@@ -57,9 +57,9 @@ dependencies = [
[[package]] [[package]]
name = "cxx" name = "cxx"
version = "1.0.202" version = "1.0.205"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13f6de320895f42e6e081abb5c7983bedcf0b6d0ff9323de0d33f620c8ac1199" checksum = "c8a02bfeba9074b2bbb39492c9b0908ec854f455a3cccdcde7a1de55e2315e40"
dependencies = [ dependencies = [
"cc", "cc",
"cxx-build", "cxx-build",
@@ -72,9 +72,9 @@ dependencies = [
[[package]] [[package]]
name = "cxx-build" name = "cxx-build"
version = "1.0.202" version = "1.0.205"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fde53ca86b9704a943fef0f1e1d836239a6aedca5de3c65fa9f97ec0bd46d39" checksum = "bbc2ac76997619d2d888b58ad79488f1c835de41ca4dd3dd7082acf4ecb0a50f"
dependencies = [ dependencies = [
"cc", "cc",
"codespan-reporting", "codespan-reporting",
@@ -87,9 +87,9 @@ dependencies = [
[[package]] [[package]]
name = "cxxbridge-cmd" name = "cxxbridge-cmd"
version = "1.0.202" version = "1.0.205"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07bae89236c811fd4d08ed3441759ac4ac98d752cbfd3de341315ba16ad20ec3" checksum = "54a486ed16a3f2a053fe7f5b98db4c1a59846a23e8cb9e49f9d1bd48830d51a2"
dependencies = [ dependencies = [
"clap", "clap",
"codespan-reporting", "codespan-reporting",
@@ -101,15 +101,15 @@ dependencies = [
[[package]] [[package]]
name = "cxxbridge-flags" name = "cxxbridge-flags"
version = "1.0.202" version = "1.0.205"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49045042e5fced01b80742aba5508de82aa4f13677ed3fa2b4cda709c40c5918" checksum = "c72569be94e2283764d334cd285980b747dbe221e27e315484eb6bcd93fa808a"
[[package]] [[package]]
name = "cxxbridge-macro" name = "cxxbridge-macro"
version = "1.0.202" version = "1.0.205"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b181252e2e3d3b5d183afbdc033a3958b445eb3e1a0ae65fc3d4f5259f5da6fd" checksum = "423e795284a7f7b3f843c956a5322c4bc497b60c2dd1a6339da10313cb18d575"
dependencies = [ dependencies = [
"indexmap", "indexmap",
"proc-macro2", "proc-macro2",
+38 -81
View File
@@ -4,6 +4,18 @@ This document explains how to set one up.
[BUILD.md]: ../../BUILD.md [BUILD.md]: ../../BUILD.md
## Supported development platforms
- **Linux**: the [Nix development shell](./nix.md),
which provides the same toolchain CI uses on any distribution.
- **macOS** 15 (Sequoia) or newer: the [Nix development shell](./nix.md),
or the system [Apple Clang](#macos-apple-clang).
CI runs on macOS 26 (Tahoe), but the build defaults `CMAKE_OSX_DEPLOYMENT_TARGET` to 15.
- **Windows**: best effort, see [Windows](#windows).
For the platforms supported for running `xrpld`,
see [Requirements](../install.md#requirements).
## Tested compiler versions ## Tested compiler versions
`xrpld` is built in the **C++23** dialect by default, so your toolchain has to `xrpld` is built in the **C++23** dialect by default, so your toolchain has to
@@ -11,13 +23,14 @@ support it — see [compiler support for C++23][cpp23-support].
The versions currently tested in CI are: The versions currently tested in CI are:
| Compiler | Version | | Compiler | Version |
| ----------- | ------------------ | | ----------- | ------------------------------- |
| GCC | 15.2 | | GCC | `gccVersion` in [packages.nix] |
| Clang | 22 | | Clang | `llvmVersion` in [packages.nix] |
| Apple Clang | 21 | | Apple Clang | 21 |
| MSVC | Visual Studio 2026 | | MSVC | Visual Studio 2026 |
LLVM tools (`clang-tidy` and `clang-format`) are also pinned to version 22. LLVM tools (`clang-tidy` and `clang-format`)
come from the same LLVM release as Clang.
### Older compilers ### Older compilers
@@ -34,20 +47,16 @@ compiler building. Treat support for anything outside the table as best-effort.
## Required tools ## Required tools
Besides a compiler, building `xrpld` requires: Besides a compiler, building `xrpld` requires
[Git](https://git-scm.com/downloads),
| Tool | Minimum version | [Python](https://www.python.org/downloads/),
| ------------------------------------------- | --------------- | [Conan](https://conan.io/downloads.html),
| [Git](https://git-scm.com/downloads) | any recent | and [CMake](https://cmake.org/download/).
| [Python](https://www.python.org/downloads/) | 3.11 | Building with `-Drust=ON` additionally requires a Rust toolchain,
| [Conan](https://conan.io/downloads.html) | 2.17 | see [Rust](#rust).
| [CMake](https://cmake.org/download/) | 3.16 |
On Linux and macOS, the [Nix development shell](./nix.md) provides all of them On Linux and macOS, the [Nix development shell](./nix.md) provides all of them
(see below). On Windows they have to be installed manually. at the versions CI uses, recorded in [`nix/check-tools/`](../../nix/check-tools).
Building with `-Drust=ON` additionally requires a Rust toolchain, see
[Rust](#rust). A default build does not, so it is not in the table above.
Once they are in place, verify that everything is installed and runnable with: Once they are in place, verify that everything is installed and runnable with:
@@ -57,60 +66,19 @@ Once they are in place, verify that everything is installed and runnable with:
## Linux and macOS ## Linux and macOS
The **recommended way** to get a development environment on Linux and macOS is Use the [Nix development shell](./nix.md):
the Nix development shell. It provides the exact tooling used in CI — `git`, it provides the compiler and every tool CI uses,
`python`, `conan`, `cmake`, `clang-tidy`, `clang-format`, and everything else — without installing anything system-wide.
with a single command and without installing anything system-wide:
```bash ### macOS: Apple Clang
nix --experimental-features 'nix-command flakes' develop
```
On **Linux**, Nix also provides the compiler (GCC); on **macOS**, it provides You can also build with the system Apple Clang,
Clang. If you instead opt to use your system-wide Apple Clang (via installing the other [required tools](#required-tools) any way you like
`nix develop .#apple-clang`), you need to manage its version yourself (see (or getting them from `nix develop .#apple-clang`).
below). Its version is whatever your installed Xcode (or Command Line Tools) provides,
so check that `clang --version` is at least the [tested one](#tested-compiler-versions).
See [Using the Nix development shell](./nix.md) for installation and usage If several Xcode versions are installed,
details, including how to select a different compiler and why we recommend Nix select one with `sudo xcode-select -s <path>` or the `DEVELOPER_DIR` environment variable.
over a hand-maintained environment.
### macOS: managing the Apple Clang version
If you use your system-wide Apple Clang on macOS (via `nix develop .#apple-clang`),
the compiler version is whatever your installed Xcode (or Command Line Tools)
provides. The following command should return a version greater than or equal to
the [tested one](#tested-compiler-versions):
```bash
clang --version
```
If you develop other applications using Xcode, you might be consistently
updating to the newest version of Apple Clang, which will likely cause issues
building xrpld. You may want to install and pin a specific version of Xcode:
1. **Download Xcode**
- Visit [Apple Developer Downloads](https://developer.apple.com/download/more/)
- Sign in with your Apple Developer account
- Search for an Xcode version that includes the expected Apple Clang version
- Download the `.xip` file
2. **Install and configure Xcode**
```bash
# Extract the .xip file and rename for version management
# Example: Xcode_16.2.app
# Move to Applications directory
sudo mv Xcode_16.2.app /Applications/
# Set as default toolchain (persistent)
sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer
# Set as environment variable (temporary)
export DEVELOPER_DIR=/Applications/Xcode_16.2.app/Contents/Developer
```
## Windows ## Windows
@@ -122,8 +90,7 @@ manually:
"x64 Native Tools Command Prompt". CI configures CMake with the "x64 Native Tools Command Prompt". CI configures CMake with the
`Visual Studio 18 2026` generator. `Visual Studio 18 2026` generator.
- [Git for Windows](https://git-scm.com/download/win) - [Git for Windows](https://git-scm.com/download/win)
- Python, Conan, and CMake, at the versions listed in - recent releases of Python, Conan, and CMake
[Required tools](#required-tools).
- a [Rust toolchain](https://rustup.rs) — only needed to build with - a [Rust toolchain](https://rustup.rs) — only needed to build with
`-Drust=ON`, see [Rust](#rust) `-Drust=ON`, see [Rust](#rust)
@@ -144,15 +111,5 @@ version.
Everything else the Rust build needs on the CMake side comes from Conan along Everything else the Rust build needs on the CMake side comes from Conan along
with the rest of the dependencies, so there is nothing further to install. with the rest of the dependencies, so there is nothing further to install.
## Clang-tidy
`clang-tidy` is required to run static analysis checks locally (see
[CONTRIBUTING.md](../../CONTRIBUTING.md)). It is not required to build the
project. The version this project uses is listed in
[Tested compiler versions](#tested-compiler-versions).
On Linux and macOS, the [Nix development shell](./nix.md) provides that exact
version out of the box — run it via `run-clang-tidy`. No separate installation
is needed.
[cpp23-support]: https://en.cppreference.com/w/cpp/compiler_support/23 [cpp23-support]: https://en.cppreference.com/w/cpp/compiler_support/23
[packages.nix]: ../../nix/packages.nix
+23 -18
View File
@@ -9,9 +9,7 @@ This guide explains how to use Nix to set up a reproducible development environm
- **Reproducible environment**: Everyone gets the same versions of tools and compilers - **Reproducible environment**: Everyone gets the same versions of tools and compilers
- **Matches CI**: The Linux CI runs in Docker images built from this exact Nix environment, and CI builds some macOS configurations in it as well - **Matches CI**: The Linux CI runs in Docker images built from this exact Nix environment, and CI builds some macOS configurations in it as well
- **No system pollution**: Dependencies are isolated and don't affect your system packages - **No system pollution**: Dependencies are isolated and don't affect your system packages
- **Consistent compilers**: The GCC and Clang shells use the same versions as CI
- **Quick setup**: Get started with a single command - **Quick setup**: Get started with a single command
- **Works on Linux and macOS**: Consistent experience across platforms
## Install Nix ## Install Nix
@@ -27,13 +25,8 @@ From the root of the xrpld repository, enter the default development shell:
nix --experimental-features 'nix-command flakes' develop nix --experimental-features 'nix-command flakes' develop
``` ```
This will: This downloads and sets up all required development tools (CMake, Ninja, Conan, etc.)
and the compiler for your platform (see [Platform notes](#platform-notes)).
- Download and set up all required development tools (CMake, Ninja, Conan, etc.)
- Configure the appropriate compiler for your platform:
- **Linux**: GCC (provided by Nix)
- **macOS**: Clang (provided by Nix)
The first time you run this command, it will take a few minutes to download and build the environment. Subsequent runs will be much faster. The first time you run this command, it will take a few minutes to download and build the environment. Subsequent runs will be much faster.
### Platform notes ### Platform notes
@@ -183,24 +176,36 @@ at link or run time.
> configuration CI covers, and no dependency binaries are published for it. > configuration CI covers, and no dependency binaries are published for it.
This is checked rather than assumed. This is checked rather than assumed.
[`bin/check-nix-store-refs.sh`](../../bin/check-nix-store-refs.sh) takes one file [`bin/nix/check-nix-store-refs.sh`](../../bin/nix/check-nix-store-refs.sh) takes one
or directory and fails if a binary under it resolves a store path at run time. file or directory and fails if a binary under it resolves a store path at run time.
CI runs it over the build output and the Conan cache, and again in the upload job CI runs it over the build output and the Conan cache, and again in the upload job
before anything is published. You can run it yourself: before anything is published. You can run it yourself:
```bash ```bash
bin/check-nix-store-refs.sh build bin/nix/check-nix-store-refs.sh build
bin/check-nix-store-refs.sh ~/.conan2-nix bin/nix/check-nix-store-refs.sh ~/.conan2-nix
``` ```
It works on Linux too, but asserts something narrower there: the toolchain always It works on Linux too, but asserts something narrower there: the toolchain always
writes the store into `PT_INTERP` and `RUNPATH`, and CI builds inside an image writes the store into `PT_INTERP` and `RUNPATH`. That is fine for the pinned
whose store is fixed for its lifetime, so that is fine. Only the binaries glibc, whose path does not move, but not for the GCC runtime, which moves with
[`PatchNixBinary.cmake`](../../cmake/PatchNixBinary.cmake) retargets to the every GCC update. So [`conan/profiles/default`](../../conan/profiles/default)
system loader have to be clean, and those are what CI checks: links build-context packages, whose executables run during the build, with
`-static-libstdc++ -static-libgcc -Wl,--as-needed`, and
[`conan/profiles/sanitizers`](../../conan/profiles/sanitizers) does not
instrument them. CI checks that they load nothing from the store but glibc, from
the graph `conan install --format=json` writes:
```bash ```bash
bin/check-nix-store-refs.sh build/xrpld bin/nix/check-build-context-runtime.sh graph.json
```
Only the binaries [`PatchNixBinary.cmake`](../../cmake/PatchNixBinary.cmake)
retargets to the system loader have to be fully clean, and those are what CI
checks:
```bash
bin/nix/check-nix-store-refs.sh build/xrpld
``` ```
### The libresolv stub ### The libresolv stub
+3 -3
View File
@@ -178,11 +178,11 @@ A binary stops starting after a `nix flake update`, or after
dyld[57271]: Library not loaded: /nix/store/…-libresolv-93/lib/libresolv.9.dylib dyld[57271]: Library not loaded: /nix/store/…-libresolv-93/lib/libresolv.9.dylib
``` ```
[`bin/check-nix-store-refs.sh`](../../bin/check-nix-store-refs.sh) finds the same [`bin/nix/check-nix-store-refs.sh`](../../bin/nix/check-nix-store-refs.sh) finds the
thing without having to run anything, and names the file: same thing without having to run anything, and names the file:
``` ```
$ bin/check-nix-store-refs.sh ~/.conan2-nix $ bin/nix/check-nix-store-refs.sh ~/.conan2-nix
::error file=/Users/you/.conan2-nix/p/b/c-area24ded30c388c/p/bin/adig::references the Nix store at run time ::error file=/Users/you/.conan2-nix/p/b/c-area24ded30c388c/p/bin/adig::references the Nix store at run time
/Users/you/.conan2-nix/p/b/c-area24ded30c388c/p/bin/adig /Users/you/.conan2-nix/p/b/c-area24ded30c388c/p/bin/adig
/nix/store/p4lp3xq4imd1qzqh08x8vcq2zfhi7rca-libresolv-93/lib/libresolv.9.dylib /nix/store/p4lp3xq4imd1qzqh08x8vcq2zfhi7rca-libresolv-93/lib/libresolv.9.dylib
+13
View File
@@ -10,6 +10,19 @@ and DNF on Red Hat-based distributions such as RHEL, AlmaLinux, and Rocky Linux,
where `yum` is a symlink to `dnf`. where `yum` is a symlink to `dnf`.
To build from source instead, see [BUILD.md](../BUILD.md). To build from source instead, see [BUILD.md](../BUILD.md).
## Requirements
Linux is the only operating system officially supported for running `xrpld`;
macOS and Windows builds are for development only.
Any x86-64 Linux distribution with APT or DNF and glibc 2.31 or newer should work
(see [How libc is handled](../nix/docker/README.md#how-libc-is-handled)).
CI tests the packages on Debian 11–13, Ubuntu 20.04–26.04,
RHEL (UBI) 9–10, AlmaLinux 9–10, and Rocky Linux 9–10.
For the hardware needed to run a node,
see [System Requirements](https://xrpl.org/system-requirements.html).
## Release channels ## Release channels
Packages are published to four channels: Packages are published to four channels:
+1 -1
View File
@@ -6,7 +6,7 @@ project(antithesis-sdk-cpp VERSION 0.4.4 LANGUAGES CXX)
add_library(antithesis-sdk-cpp INTERFACE antithesis_sdk.h) add_library(antithesis-sdk-cpp INTERFACE antithesis_sdk.h)
# Note, both sections below created by xrpld project # Note, both sections below created by xrpld project
target_include_directories(antithesis-sdk-cpp INTERFACE target_include_directories(antithesis-sdk-cpp SYSTEM INTERFACE
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}> $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
) )
Generated
+6 -6
View File
@@ -2,11 +2,11 @@
"nodes": { "nodes": {
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1781173989, "lastModified": 1791130267,
"narHash": "sha256-fnzKKPvS+oieI/pTzotA5tkoM47EB1NpaBcgk4R97hE=", "narHash": "sha256-1sjwcQMcgAbmiip/VivBSiK8p2bTkQGOvCuO7vnwfx4=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "8c91a71d13451abc40eb9dae8910f972f979852f", "rev": "9013764fcc0ea99fa16cf7aa7decf8a5c3889dd2",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -47,11 +47,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1784611586, "lastModified": 1791189933,
"narHash": "sha256-OfqgY+0hp/zseZB7uyH0U8kIDPS4scZZCyAurEplvG0=", "narHash": "sha256-Y8eN7ki0Urx4Ojf4w1xSpWg8uk/3lJqK+E0Oth77rH0=",
"owner": "oxalica", "owner": "oxalica",
"repo": "rust-overlay", "repo": "rust-overlay",
"rev": "14f58845249f3552a89b07772626b8d3c632fa86", "rev": "e60029353d0c48d216bc4b065168ccd4079c166f",
"type": "github" "type": "github"
}, },
"original": { "original": {
+1 -1
View File
@@ -34,7 +34,7 @@ lz4Compress(void const* in, std::size_t inSize, BufferFactory&& bf)
// data // data
auto compressed = bf(outCapacity); auto compressed = bf(outCapacity);
auto compressedSize = LZ4_compress_default( auto const compressedSize = LZ4_compress_default(
reinterpret_cast<char const*>(in), reinterpret_cast<char const*>(in),
reinterpret_cast<char*>(compressed), reinterpret_cast<char*>(compressed),
inSize, inSize,
+22 -14
View File
@@ -20,12 +20,14 @@ SharedIntrusive<T>::SharedIntrusive(T* p, TAdoptTag) noexcept : ptr_{p}
template <class T> template <class T>
SharedIntrusive<T>::SharedIntrusive(SharedIntrusive const& rhs) SharedIntrusive<T>::SharedIntrusive(SharedIntrusive const& rhs)
: ptr_{[&] { : ptr_{
[&] {
auto p = rhs.unsafeGetRawPtr(); auto p = rhs.unsafeGetRawPtr();
if (p) if (p)
p->addStrongRef(); p->addStrongRef();
return p; return p;
}()} }(),
}
{ {
} }
@@ -33,12 +35,14 @@ template <class T>
template <class TT> template <class TT>
requires std::convertible_to<TT*, T*> requires std::convertible_to<TT*, T*>
SharedIntrusive<T>::SharedIntrusive(SharedIntrusive<TT> const& rhs) SharedIntrusive<T>::SharedIntrusive(SharedIntrusive<TT> const& rhs)
: ptr_{[&] { : ptr_{
[&] {
auto p = rhs.unsafeGetRawPtr(); auto p = rhs.unsafeGetRawPtr();
if (p) if (p)
p->addStrongRef(); p->addStrongRef();
return p; return p;
}()} }(),
}
{ {
} }
@@ -140,12 +144,14 @@ SharedIntrusive<T>::~SharedIntrusive()
template <class T> template <class T>
template <class TT> template <class TT>
SharedIntrusive<T>::SharedIntrusive(StaticCastTagSharedIntrusive, SharedIntrusive<TT> const& rhs) SharedIntrusive<T>::SharedIntrusive(StaticCastTagSharedIntrusive, SharedIntrusive<TT> const& rhs)
: ptr_{[&] { : ptr_{
[&] {
auto p = static_cast<T*>(rhs.unsafeGetRawPtr()); auto p = static_cast<T*>(rhs.unsafeGetRawPtr());
if (p) if (p)
p->addStrongRef(); p->addStrongRef();
return p; return p;
}()} }(),
}
{ {
} }
@@ -159,12 +165,14 @@ SharedIntrusive<T>::SharedIntrusive(StaticCastTagSharedIntrusive, SharedIntrusiv
template <class T> template <class T>
template <class TT> template <class TT>
SharedIntrusive<T>::SharedIntrusive(DynamicCastTagSharedIntrusive, SharedIntrusive<TT> const& rhs) SharedIntrusive<T>::SharedIntrusive(DynamicCastTagSharedIntrusive, SharedIntrusive<TT> const& rhs)
: ptr_{[&] { : ptr_{
[&] {
auto p = dynamic_cast<T*>(rhs.unsafeGetRawPtr()); auto p = dynamic_cast<T*>(rhs.unsafeGetRawPtr());
if (p) if (p)
p->addStrongRef(); p->addStrongRef();
return p; return p;
}()} }(),
}
{ {
} }
@@ -260,7 +268,7 @@ SharedIntrusive<T>::unsafeReleaseAndStore(T* next)
return; return;
using enum ReleaseStrongRefAction; using enum ReleaseStrongRefAction;
auto action = prev->releaseStrongRef(); auto const action = prev->releaseStrongRef();
switch (action) switch (action)
{ {
case NoOp: case NoOp:
@@ -361,7 +369,7 @@ WeakIntrusive<T>::unsafeReleaseNoStore()
return; return;
using enum ReleaseWeakRefAction; using enum ReleaseWeakRefAction;
auto action = ptr_->releaseWeakRef(); auto const action = ptr_->releaseWeakRef();
switch (action) switch (action)
{ {
case NoOp: case NoOp:
@@ -580,7 +588,7 @@ SharedWeakUnion<T>::convertToStrong()
auto p = unsafeGetRawPtr(); auto p = unsafeGetRawPtr();
if (p && p->checkoutStrongRefFromWeak()) if (p && p->checkoutStrongRefFromWeak())
{ {
[[maybe_unused]] auto action = p->releaseWeakRef(); [[maybe_unused]] auto const action = p->releaseWeakRef();
XRPL_ASSERT( XRPL_ASSERT(
(action == ReleaseWeakRefAction::NoOp), (action == ReleaseWeakRefAction::NoOp),
"xrpl::SharedWeakUnion::convertToStrong : " "xrpl::SharedWeakUnion::convertToStrong : "
@@ -603,7 +611,7 @@ SharedWeakUnion<T>::convertToWeak()
return false; return false;
using enum ReleaseStrongRefAction; using enum ReleaseStrongRefAction;
auto action = p->addWeakReleaseStrongRef(); auto const action = p->addWeakReleaseStrongRef();
switch (action) switch (action)
{ {
case NoOp: case NoOp:
@@ -670,7 +678,7 @@ SharedWeakUnion<T>::unsafeReleaseNoStore()
if (isStrong()) if (isStrong())
{ {
using enum ReleaseStrongRefAction; using enum ReleaseStrongRefAction;
auto strongAction = p->releaseStrongRef(); auto const strongAction = p->releaseStrongRef();
switch (strongAction) switch (strongAction)
{ {
case NoOp: case NoOp:
@@ -688,7 +696,7 @@ SharedWeakUnion<T>::unsafeReleaseNoStore()
else else
{ {
using enum ReleaseWeakRefAction; using enum ReleaseWeakRefAction;
auto weakAction = p->releaseWeakRef(); auto const weakAction = p->releaseWeakRef();
switch (weakAction) switch (weakAction)
{ {
case NoOp: case NoOp:
+2 -2
View File
@@ -406,10 +406,10 @@ IntrusiveRefCounts::useCount() const noexcept
inline IntrusiveRefCounts::~IntrusiveRefCounts() noexcept inline IntrusiveRefCounts::~IntrusiveRefCounts() noexcept
{ {
#ifndef NDEBUG #ifndef NDEBUG
auto v = refCounts_.load(std::memory_order_acquire); auto const v = refCounts_.load(std::memory_order_acquire);
XRPL_ASSERT( XRPL_ASSERT(
(!(v & kValueMask)), "xrpl::IntrusiveRefCounts::~IntrusiveRefCounts : count must be zero"); (!(v & kValueMask)), "xrpl::IntrusiveRefCounts::~IntrusiveRefCounts : count must be zero");
auto t = v & kTagMask; auto const t = v & kTagMask;
XRPL_ASSERT((!t || t == kTagMask), "xrpl::IntrusiveRefCounts::~IntrusiveRefCounts : valid tag"); XRPL_ASSERT((!t || t == kTagMask), "xrpl::IntrusiveRefCounts::~IntrusiveRefCounts : valid tag");
#endif #endif
} }
+147
View File
@@ -3,9 +3,156 @@
#include <algorithm> #include <algorithm>
#include <cassert> #include <cassert>
#include <cstddef> #include <cstddef>
#include <cstdint>
#include <limits>
#include <optional>
namespace xrpl { namespace xrpl {
/**
* Add two signed 64-bit integers, returning std::nullopt when the exact
* mathematical sum is not representable in std::int64_t.
*/
[[nodiscard]] constexpr std::optional<std::int64_t>
checkedAdd(std::int64_t a, std::int64_t b) noexcept
{
using L = std::numeric_limits<std::int64_t>;
if ((b > 0 && a > L::max() - b) || (b < 0 && a < L::min() - b))
return std::nullopt;
return a + b;
}
/**
* Subtract two signed 64-bit integers, returning std::nullopt when the exact
* mathematical difference is not representable in std::int64_t.
*/
[[nodiscard]] constexpr std::optional<std::int64_t>
checkedSub(std::int64_t a, std::int64_t b) noexcept
{
using L = std::numeric_limits<std::int64_t>;
if ((b > 0 && a < L::min() + b) || (b < 0 && a > L::max() + b))
return std::nullopt;
return a - b;
}
/**
* Multiply two signed 64-bit integers, returning std::nullopt when the exact
* mathematical product is not representable in std::int64_t.
*/
[[nodiscard]] constexpr std::optional<std::int64_t>
checkedMul(std::int64_t a, std::int64_t b) noexcept
{
using L = std::numeric_limits<std::int64_t>;
if (a == 0 || b == 0)
return 0;
if (a > 0)
{
if (b > 0 ? a > L::max() / b : b < L::min() / a)
return std::nullopt;
}
else if (b > 0 ? a < L::min() / b : b < L::max() / a)
{
return std::nullopt;
}
return a * b;
}
static_assert(checkedAdd(0, 0) == 0);
static_assert(checkedAdd(1, -1) == 0);
static_assert(checkedAdd(-5, 2) == -3);
static_assert(!checkedAdd(std::numeric_limits<std::int64_t>::max(), 1).has_value());
static_assert(!checkedAdd(std::numeric_limits<std::int64_t>::min(), -1).has_value());
static_assert(
checkedAdd(std::numeric_limits<std::int64_t>::max() - 1, 1) ==
std::numeric_limits<std::int64_t>::max());
static_assert(
checkedAdd(
std::numeric_limits<std::int64_t>::min(),
std::numeric_limits<std::int64_t>::max()) == -1);
static_assert(
checkedAdd(
std::numeric_limits<std::int64_t>::max(),
std::numeric_limits<std::int64_t>::min()) == -1);
static_assert(
!checkedAdd(std::numeric_limits<std::int64_t>::max(), std::numeric_limits<std::int64_t>::max())
.has_value());
static_assert(
!checkedAdd(std::numeric_limits<std::int64_t>::min(), std::numeric_limits<std::int64_t>::min())
.has_value());
static_assert(checkedSub(0, 0) == 0);
static_assert(checkedSub(1, 1) == 0);
static_assert(checkedSub(-5, 2) == -7);
static_assert(checkedSub(-5, -2) == -3);
static_assert(!checkedSub(std::numeric_limits<std::int64_t>::min(), 1).has_value());
static_assert(!checkedSub(std::numeric_limits<std::int64_t>::max(), -1).has_value());
static_assert(
checkedSub(std::numeric_limits<std::int64_t>::min() + 1, 1) ==
std::numeric_limits<std::int64_t>::min());
static_assert(
checkedSub(-1, std::numeric_limits<std::int64_t>::max()) ==
std::numeric_limits<std::int64_t>::min());
static_assert(
!checkedSub(std::numeric_limits<std::int64_t>::max(), std::numeric_limits<std::int64_t>::min())
.has_value());
static_assert(
!checkedSub(std::numeric_limits<std::int64_t>::min(), std::numeric_limits<std::int64_t>::max())
.has_value());
static_assert(checkedMul(0, std::numeric_limits<std::int64_t>::min()) == 0);
static_assert(checkedMul(std::numeric_limits<std::int64_t>::min(), 0) == 0);
static_assert(checkedMul(-1, -1) == 1);
// a > 0, b > 0
static_assert(
checkedMul(std::numeric_limits<std::int64_t>::max(), 1) ==
std::numeric_limits<std::int64_t>::max());
static_assert(
checkedMul(std::numeric_limits<std::int64_t>::max() / 2, 2) ==
std::numeric_limits<std::int64_t>::max() - 1);
static_assert(!checkedMul((std::numeric_limits<std::int64_t>::max() / 2) + 1, 2).has_value());
static_assert(!checkedMul(2, (std::numeric_limits<std::int64_t>::max() / 2) + 1).has_value());
// a > 0, b < 0
static_assert(
checkedMul(std::numeric_limits<std::int64_t>::max(), -1) ==
-std::numeric_limits<std::int64_t>::max());
static_assert(
checkedMul((std::numeric_limits<std::int64_t>::max() / 2) + 1, -2) ==
std::numeric_limits<std::int64_t>::min());
static_assert(!checkedMul((std::numeric_limits<std::int64_t>::max() / 2) + 2, -2).has_value());
static_assert(
checkedMul(1, std::numeric_limits<std::int64_t>::min()) ==
std::numeric_limits<std::int64_t>::min());
static_assert(
checkedMul(2, std::numeric_limits<std::int64_t>::min() / 2) ==
std::numeric_limits<std::int64_t>::min());
static_assert(!checkedMul(2, (std::numeric_limits<std::int64_t>::min() / 2) - 1).has_value());
// a < 0, b > 0
static_assert(
checkedMul(std::numeric_limits<std::int64_t>::min(), 1) ==
std::numeric_limits<std::int64_t>::min());
static_assert(
checkedMul(std::numeric_limits<std::int64_t>::min() / 2, 2) ==
std::numeric_limits<std::int64_t>::min());
static_assert(!checkedMul((std::numeric_limits<std::int64_t>::min() / 2) - 1, 2).has_value());
static_assert(!checkedMul(std::numeric_limits<std::int64_t>::min(), 2).has_value());
// a < 0, b < 0
static_assert(
checkedMul(-(std::numeric_limits<std::int64_t>::max() / 2), -2) ==
std::numeric_limits<std::int64_t>::max() - 1);
static_assert(!checkedMul(std::numeric_limits<std::int64_t>::min() / 2, -2).has_value());
static_assert(
checkedMul(-1, -std::numeric_limits<std::int64_t>::max()) ==
std::numeric_limits<std::int64_t>::max());
static_assert(!checkedMul(std::numeric_limits<std::int64_t>::min(), -1).has_value());
static_assert(!checkedMul(-1, std::numeric_limits<std::int64_t>::min()).has_value());
/** /**
* Calculate one number divided by another number in percentage. * Calculate one number divided by another number in percentage.
* The result is rounded up to the next integer, and capped in the range [0,100] * The result is rounded up to the next integer, and capped in the range [0,100]
+6 -2
View File
@@ -352,9 +352,9 @@ class Number final
using rep = std::int64_t; 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()}; int exponent_{std::numeric_limits<int>::lowest()};
bool negative_{false};
public: public:
// The range for the exponent when normalized // The range for the exponent when normalized
@@ -650,8 +650,12 @@ private:
shiftExponent(int exponentDelta) const; shiftExponent(int exponentDelta) const;
}; };
// The number class currently has 3 tail padding bytes. If you are adding new
// members, try to fit them there before expanding the size of the class.
static_assert(sizeof(Number) == 16);
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} : mantissa_{mantissa}, exponent_{exponent}, negative_(negative)
{ {
} }
+1 -1
View File
@@ -340,7 +340,7 @@ public:
for (auto const& c : cfg) for (auto const& c : cfg)
{ {
auto& a = allocators_.emplace_back(c.extra_, c.alloc_, c.align_); auto const& a = allocators_.emplace_back(c.extra_, c.alloc_, c.align_);
if (a.size() > maxSize_) if (a.size() > maxSize_)
maxSize_ = a.size(); maxSize_ = a.size();
+1 -1
View File
@@ -36,7 +36,7 @@ template <typename T>
concept SomeChar = std::same_as<std::remove_cvref_t<T>, int8_t> || concept SomeChar = std::same_as<std::remove_cvref_t<T>, int8_t> ||
std::same_as<std::remove_cvref_t<T>, char> || std::same_as<std::remove_cvref_t<T>, uint8_t>; std::same_as<std::remove_cvref_t<T>, char> || std::same_as<std::remove_cvref_t<T>, uint8_t>;
inline constexpr std::array<std::optional<int>, 256> const kDigitLookupTable = []() { inline constexpr std::array<std::optional<int>, 256> const kDigitLookupTable = [] {
std::array<std::optional<int>, 256> t{}; std::array<std::optional<int>, 256> t{};
for (int i = 0; i < 10; ++i) for (int i = 0; i < 10; ++i)
+34 -3
View File
@@ -153,6 +153,24 @@ private:
Policy policy, Policy policy,
Callback&& replaceCallback = nullptr); Callback&& replaceCallback = nullptr);
/**
* canonicalizeImpl variant for callers that already hold `mutex_`.
*
* The unnamed `scoped_lock<MutexType> const&` parameter is proof of
* ownership; this overload does not acquire the lock. Use it from other
* methods (e.g. fetchAndModify) that need to compose canonicalize with
* additional work under a single critical section, without relying on
* recursive-mutex re-entry.
*/
template <class Policy, class Callback = std::nullptr_t>
bool
canonicalizeImpl(
std::scoped_lock<MutexType> const&,
key_type const& key,
CanonicalizeClientPointerType<Policy> data,
Policy policy,
Callback&& replaceCallback = nullptr);
public: public:
/** /**
* Replace aliased objects with originals. * Replace aliased objects with originals.
@@ -239,9 +257,6 @@ public:
bool bool
retrieve(key_type const& key, T& data); retrieve(key_type const& key, T& data);
MutexType&
peekMutex();
std::vector<key_type> std::vector<key_type>
getKeys() const; getKeys() const;
@@ -263,6 +278,22 @@ public:
fetch(key_type const& digest, Handler const& h); fetch(key_type const& digest, Handler const& h);
// End CachedSLEs functions. // End CachedSLEs functions.
/**
* Fetch or create an entry and execute a callback while holding the lock.
*
* The entry for the given key is fetched from the cache or created if it
* doesn't exist. The callback is then invoked with a reference to the
* entry while the cache mutex is still held, allowing safe modification
* of the cached object.
*
* @param key The key to fetch or create
* @param callback Function to call with the entry under lock.
* Signature: void(T&)
*/
template <class Callback>
void
fetchAndModify(key_type const& key, Callback&& callback);
private: private:
SharedPointerType SharedPointerType
initialFetch(key_type const& key, std::scoped_lock<MutexType> const& l); initialFetch(key_type const& key, std::scoped_lock<MutexType> const& l);
+76 -27
View File
@@ -4,6 +4,7 @@
#include <xrpl/basics/Log.h> // IWYU pragma: keep #include <xrpl/basics/Log.h> // IWYU pragma: keep
#include <xrpl/basics/TaggedCache.h> #include <xrpl/basics/TaggedCache.h>
#include <xrpl/basics/scope.h> #include <xrpl/basics/scope.h>
#include <xrpl/beast/utility/instrumentation.h>
#include <algorithm> #include <algorithm>
@@ -300,7 +301,7 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
// Remove from cache, if !valid, remove from map too. Returns true if removed from cache // Remove from cache, if !valid, remove from map too. Returns true if removed from cache
std::scoped_lock const lock(mutex_); std::scoped_lock const lock(mutex_);
auto cit = cache_.find(key); auto const cit = cache_.find(key);
if (cit == cache_.end()) if (cit == cache_.end())
return false; return false;
@@ -335,6 +336,29 @@ template <class Policy, class Callback>
inline bool inline bool
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>:: TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::
canonicalizeImpl( canonicalizeImpl(
key_type const& key,
CanonicalizeClientPointerType<Policy> data,
Policy policy,
Callback&& replaceCallback)
{
std::scoped_lock<MutexType> const lock(mutex_);
return canonicalizeImpl(lock, key, data, policy, std::forward<Callback>(replaceCallback));
}
template <
class Key,
class T,
bool IsKeyCache,
class SharedWeakUnionPointer,
class SharedPointerType,
class Hash,
class KeyEqual,
class Mutex>
template <class Policy, class Callback>
inline bool
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::
canonicalizeImpl(
std::scoped_lock<MutexType> const&,
key_type const& key, key_type const& key,
CanonicalizeClientPointerType<Policy> data, CanonicalizeClientPointerType<Policy> data,
[[maybe_unused]] Policy policy, [[maybe_unused]] Policy policy,
@@ -354,9 +378,7 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
// passing a const argument is a compile error. // passing a const argument is a compile error.
constexpr bool replaceCached = std::is_same_v<Policy, detail::ReplaceCached>; constexpr bool replaceCached = std::is_same_v<Policy, detail::ReplaceCached>;
std::scoped_lock const lock(mutex_); auto const cit = cache_.find(key);
auto cit = cache_.find(key);
if (cit == cache_.end()) if (cit == cache_.end())
{ {
@@ -371,7 +393,7 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
Entry& entry = cit->second; Entry& entry = cit->second;
entry.touch(clock_.now()); entry.touch(clock_.now());
auto shouldReplaceCached = [&] { auto const shouldReplaceCached = [&] {
if constexpr (replaceCached) if constexpr (replaceCached)
{ {
return true; return true;
@@ -400,7 +422,7 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
return true; return true;
} }
auto cachedData = entry.lock(); auto const cachedData = entry.lock();
if (cachedData) if (cachedData)
{ {
@@ -563,7 +585,7 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
retrieve(key_type const& key, T& data) retrieve(key_type const& key, T& data)
{ {
// retrieve the value of the stored data // retrieve the value of the stored data
auto entry = fetch(key); auto const entry = fetch(key);
if (!entry) if (!entry)
return false; return false;
@@ -572,22 +594,6 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
return true; return true;
} }
template <
class Key,
class T,
bool IsKeyCache,
class SharedWeakUnionPointer,
class SharedPointerType,
class Hash,
class KeyEqual,
class Mutex>
inline auto
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::
peekMutex() -> MutexType&
{
return mutex_;
}
template < template <
class Key, class Key,
class T, class T,
@@ -687,7 +693,7 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
return ret; return ret;
} }
auto sle = h(); auto const sle = h();
if (!sle) if (!sle)
return {}; return {};
@@ -700,6 +706,49 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
} }
// End CachedSLEs functions. // End CachedSLEs functions.
template <
class Key,
class T,
bool IsKeyCache,
class SharedWeakUnionPointer,
class SharedPointerType,
class Hash,
class KeyEqual,
class Mutex>
template <class Callback>
inline void
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::
fetchAndModify(key_type const& key, Callback&& callback)
{
static_assert(
!IsKeyCache, "fetchAndModify is only supported for value caches, not key-only caches");
static_assert(
std::is_same_v<std::shared_ptr<T>, SharedPointerType> ||
std::is_same_v<intr_ptr::SharedPtr<T>, SharedPointerType>,
"fetchAndModify requires std::shared_ptr<T> or intr_ptr::SharedPtr<T>");
std::scoped_lock<MutexType> const lock(mutex_);
// Same pointer-type dispatch as insert(): the placeholder must have exactly
// SharedPointerType so canonicalizeImpl can write the cached pointer back.
SharedPointerType entry = [] {
if constexpr (std::is_same_v<std::shared_ptr<T>, SharedPointerType>)
{
return std::make_shared<T>();
}
else
{
return intr_ptr::makeShared<T>();
}
}();
canonicalizeImpl(lock, key, entry, detail::ReplaceClient{});
ALWAYS(
entry != nullptr, "xrpl::TaggedCache::fetchAndModify : entry present after canonicalize");
callback(*entry);
}
template < template <
class Key, class Key,
class T, class T,
@@ -713,7 +762,7 @@ inline SharedPointerType
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>:: TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::
initialFetch(key_type const& key, std::scoped_lock<MutexType> const& l) initialFetch(key_type const& key, std::scoped_lock<MutexType> const& l)
{ {
auto cit = cache_.find(key); auto const cit = cache_.find(key);
if (cit == cache_.end()) if (cit == cache_.end())
return {}; return {};
@@ -783,7 +832,7 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
std::atomic<int>& allRemovals, std::atomic<int>& allRemovals,
std::scoped_lock<std::recursive_mutex> const&) std::scoped_lock<std::recursive_mutex> const&)
{ {
return std::thread([&, this]() { return std::thread([&, this] {
int cacheRemovals = 0; int cacheRemovals = 0;
int mapRemovals = 0; int mapRemovals = 0;
@@ -863,7 +912,7 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
std::atomic<int>& allRemovals, std::atomic<int>& allRemovals,
std::scoped_lock<std::recursive_mutex> const&) std::scoped_lock<std::recursive_mutex> const&)
{ {
return std::thread([&, this]() { return std::thread([&, this] {
// NOLINTBEGIN https://github.com/XRPLF/rippled/issues/7056 // NOLINTBEGIN https://github.com/XRPLF/rippled/issues/7056
int cacheRemovals = 0; int cacheRemovals = 0;
int mapRemovals = 0; int mapRemovals = 0;
+3 -2
View File
@@ -195,7 +195,8 @@ private:
{ {
// Local lambda that converts a single hex char to four bits and // Local lambda that converts a single hex char to four bits and
// ORs those bits into a uint32_t. // ORs those bits into a uint32_t.
auto hexCharToUInt = [](char c, std::uint32_t shift, std::uint32_t& accum) -> ParseResult { auto const hexCharToUInt =
[](char c, std::uint32_t shift, std::uint32_t& accum) -> ParseResult {
std::uint32_t nibble = 0xFFu; std::uint32_t nibble = 0xFFu;
if (c < '0' || c > 'f') if (c < '0' || c > 'f')
return ParseResult::BadChar; return ParseResult::BadChar;
@@ -453,7 +454,7 @@ public:
{ {
for (int i = kWidth - 1; i >= 0; --i) for (int i = kWidth - 1; i >= 0; --i)
{ {
auto prev = data_[i]; auto const prev = data_[i];
data_[i] = boost::endian::native_to_big(boost::endian::big_to_native(data_[i]) - 1); data_[i] = boost::endian::native_to_big(boost::endian::big_to_native(data_[i]) - 1);
if (prev != 0) if (prev != 0)
@@ -17,7 +17,7 @@
namespace xrpl { namespace xrpl {
template <typename Key> template <typename Key>
static std::size_t std::size_t
extract(Key const& key) extract(Key const& key)
{ {
return key; return key;
@@ -365,7 +365,7 @@ public:
size() const size() const
{ {
std::size_t ret = 0; std::size_t ret = 0;
for (auto& p : map_) for (auto const& p : map_)
ret += p.size(); ret += p.size();
return ret; return ret;
} }
@@ -1604,7 +1604,7 @@ AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::erase(
beast::detail::AgedContainerIterator<IsConst, Iterator> pos) beast::detail::AgedContainerIterator<IsConst, Iterator> pos)
requires(!IsBoostReverseIterator<Iterator>::value) requires(!IsBoostReverseIterator<Iterator>::value)
{ {
unlinkAndDeleteElement(&*((pos++).iterator())); unlinkAndDeleteElement(&*(pos++).iterator());
return beast::detail::AgedContainerIterator<false, Iterator>(pos.iterator()); return beast::detail::AgedContainerIterator<false, Iterator>(pos.iterator());
} }
@@ -1617,7 +1617,7 @@ AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::erase(
requires(!IsBoostReverseIterator<Iterator>::value) requires(!IsBoostReverseIterator<Iterator>::value)
{ {
for (; first != last;) for (; first != last;)
unlinkAndDeleteElement(&*((first++).iterator())); unlinkAndDeleteElement(&*(first++).iterator());
return beast::detail::AgedContainerIterator<false, Iterator>(first.iterator()); return beast::detail::AgedContainerIterator<false, Iterator>(first.iterator());
} }
@@ -2404,7 +2404,7 @@ beast::detail::AgedContainerIterator<false, Iterator>
AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>::erase( AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>::erase(
beast::detail::AgedContainerIterator<IsConst, Iterator> pos) beast::detail::AgedContainerIterator<IsConst, Iterator> pos)
{ {
unlinkAndDeleteElement(&*((pos++).iterator())); unlinkAndDeleteElement(&*(pos++).iterator());
return beast::detail::AgedContainerIterator<false, Iterator>(pos.iterator()); return beast::detail::AgedContainerIterator<false, Iterator>(pos.iterator());
} }
@@ -2424,7 +2424,7 @@ AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>
beast::detail::AgedContainerIterator<IsConst, Iterator> last) beast::detail::AgedContainerIterator<IsConst, Iterator> last)
{ {
for (; first != last;) for (; first != last;)
unlinkAndDeleteElement(&*((first++).iterator())); unlinkAndDeleteElement(&*(first++).iterator());
return beast::detail::AgedContainerIterator<false, Iterator>(first.iterator()); return beast::detail::AgedContainerIterator<false, Iterator>(first.iterator());
} }
@@ -2536,7 +2536,7 @@ AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>
return false; return false;
for (auto iter(cbegin()), last(cend()), otherLast(other.cend()); iter != last; ++iter) for (auto iter(cbegin()), last(cend()), otherLast(other.cend()); iter != last; ++iter)
{ {
auto otherIter(other.find(extract(*iter))); auto const otherIter(other.find(extract(*iter)));
if (otherIter == otherLast) if (otherIter == otherLast)
return false; return false;
} }
+1 -1
View File
@@ -68,7 +68,7 @@ struct LexicalCast<Out, std::string_view>
if (first != last && *first == '+') if (first != last && *first == '+')
++first; ++first;
auto ret = std::from_chars(first, last, out); auto const ret = std::from_chars(first, last, out);
return ret.ec == std::errc() && ret.ptr == last; return ret.ec == std::errc() && ret.ptr == last;
} }
+1 -1
View File
@@ -390,7 +390,7 @@ void
hash_append(Hasher& h, boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept hash_append(Hasher& h, boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept
requires(IsContiguouslyHashable<Key, Hasher>::value) requires(IsContiguouslyHashable<Key, Hasher>::value)
{ {
h(&(v.begin()), v.size() * sizeof(Key)); h(&v.begin(), v.size() * sizeof(Key));
} }
// tuple // tuple
+1 -1
View File
@@ -8,7 +8,7 @@ namespace beast::insight {
class HookImpl : public std::enable_shared_from_this<HookImpl> class HookImpl : public std::enable_shared_from_this<HookImpl>
{ {
public: public:
using HandlerType = std::function<void(void)>; using HandlerType = std::function<void()>;
virtual ~HookImpl() = 0; virtual ~HookImpl() = 0;
}; };
+2 -2
View File
@@ -61,7 +61,7 @@ isMulticast(Address const& addr)
inline bool inline bool
isPrivate(Address const& addr) isPrivate(Address const& addr)
{ {
return (addr.is_v4()) ? isPrivate(addr.to_v4()) : isPrivate(addr.to_v6()); return addr.is_v4() ? isPrivate(addr.to_v4()) : isPrivate(addr.to_v6());
} }
/** /**
@@ -70,7 +70,7 @@ isPrivate(Address const& addr)
inline bool inline bool
isPublic(Address const& addr) isPublic(Address const& addr)
{ {
return (addr.is_v4()) ? isPublic(addr.to_v4()) : isPublic(addr.to_v6()); return addr.is_v4() ? isPublic(addr.to_v4()) : isPublic(addr.to_v6());
} }
} // namespace ip } // namespace ip
+1 -1
View File
@@ -83,7 +83,7 @@ trimRight(String const& s)
{ {
using std::begin; using std::begin;
using std::end; using std::end;
auto first(begin(s)); auto const first(begin(s));
auto last(end(s)); auto last(end(s));
last = trimRight(first, last); last = trimRight(first, last);
return {first, last}; return {first, last};
+1 -1
View File
@@ -34,7 +34,7 @@ typeName()
name += " volatile"; name += " volatile";
if (std::is_lvalue_reference_v<T>) if (std::is_lvalue_reference_v<T>)
{ {
name += "&"; name += '&';
} }
else if (std::is_rvalue_reference_v<T>) else if (std::is_rvalue_reference_v<T>)
{ {
+1 -1
View File
@@ -32,7 +32,7 @@ public:
Module, Module,
// Match nothing (used internally) // Match nothing (used internally)
None None,
}; };
private: private:
+1 -1
View File
@@ -20,7 +20,7 @@ namespace beast::unit_test {
namespace detail { namespace detail {
template <class String> template <class String>
static std::string std::string
makeReason(String const& reason, char const* file, int line) makeReason(String const& reason, char const* file, int line)
{ {
std::string s(reason); std::string s(reason);
+3 -3
View File
@@ -47,8 +47,8 @@ public:
template <class F, class... Args> template <class F, class... Args>
explicit Thread(Suite& s, F&& f, Args&&... args) : s_(&s) explicit Thread(Suite& s, F&& f, Args&&... args) : s_(&s)
{ {
std::function<void(void)> b = [f = std::forward<F>(f), std::function<void()> b = [f = std::forward<F>(f),
... args = std::forward<Args>(args)]() mutable { ... args = std::forward<Args>(args)] mutable {
std::invoke(f, args...); std::invoke(f, args...);
}; };
t_ = std::thread(&Thread::run, this, std::move(b)); t_ = std::thread(&Thread::run, this, std::move(b));
@@ -94,7 +94,7 @@ public:
private: private:
void void
run(std::function<void(void)> f) run(std::function<void()> f)
{ {
try try
{ {
+1 -1
View File
@@ -24,7 +24,7 @@ enum class Severity : std::uint8_t {
Fatal = 5, Fatal = 5,
Disabled = 6, Disabled = 6,
None = Disabled None = Disabled,
}; };
/** /**
+1 -1
View File
@@ -18,7 +18,7 @@ enum class Type : std::uint8_t {
PrefixSha256 = 1, PrefixSha256 = 1,
ThresholdSha256 = 2, ThresholdSha256 = 2,
RsaSha256 = 3, RsaSha256 = 3,
Ed25519Sha256 = 4 Ed25519Sha256 = 4,
}; };
class Condition class Condition
@@ -49,7 +49,7 @@ public:
using namespace der; using namespace der;
auto p = parsePreamble(s, ec); auto const p = parsePreamble(s, ec);
if (ec) if (ec)
return nullptr; return nullptr;
+1 -1
View File
@@ -21,7 +21,7 @@ enum class Error {
UnexpectedTag, UnexpectedTag,
LongTag, LongTag,
LargeSize, LargeSize,
PreimageTooLong PreimageTooLong,
}; };
std::error_code std::error_code
+1 -1
View File
@@ -396,7 +396,7 @@ inline bool
getIfExists<bool>(Section const& section, std::string const& name, bool& v) getIfExists<bool>(Section const& section, std::string const& name, bool& v)
{ {
int intVal = 0; int intVal = 0;
auto stat = getIfExists(section, name, intVal); auto const stat = getIfExists(section, name, intVal);
if (stat) if (stat)
v = bool(intVal); v = bool(intVal);
return stat; return stat;
+3
View File
@@ -94,6 +94,7 @@ struct Keys
static constexpr auto kBbtOptions = "bbt_options"; static constexpr auto kBbtOptions = "bbt_options";
static constexpr auto kBgThreads = "bg_threads"; static constexpr auto kBgThreads = "bg_threads";
static constexpr auto kBlockSize = "block_size"; static constexpr auto kBlockSize = "block_size";
static constexpr auto kBytecodeSizeLimit = "bytecode_size_limit";
static constexpr auto kCacheAge = "cache_age"; static constexpr auto kCacheAge = "cache_age";
static constexpr auto kCacheMb = "cache_mb"; static constexpr auto kCacheMb = "cache_mb";
static constexpr auto kCacheSize = "cache_size"; static constexpr auto kCacheSize = "cache_size";
@@ -108,6 +109,8 @@ struct Keys
static constexpr auto kFileSizeMult = "file_size_mult"; static constexpr auto kFileSizeMult = "file_size_mult";
static constexpr auto kFilterBits = "filter_bits"; static constexpr auto kFilterBits = "filter_bits";
static constexpr auto kFilterFull = "filter_full"; static constexpr auto kFilterFull = "filter_full";
static constexpr auto kGasLimit = "gas_limit";
static constexpr auto kGasPrice = "gas_price";
static constexpr auto kHardSet = "hard_set"; static constexpr auto kHardSet = "hard_set";
static constexpr auto kHighThreads = "high_threads"; static constexpr auto kHighThreads = "high_threads";
static constexpr auto kHoldTime = "hold_time"; static constexpr auto kHoldTime = "hold_time";
+2 -2
View File
@@ -93,14 +93,14 @@ public:
void void
check(std::vector<TxID> accepted, Predicate&& pred) check(std::vector<TxID> accepted, Predicate&& pred)
{ {
auto acceptTxid = accepted.begin(); auto const acceptTxid = accepted.begin();
auto const ae = accepted.end(); auto const ae = accepted.end();
std::sort(acceptTxid, ae); std::sort(acceptTxid, ae);
// We want to remove all tracking entries for transactions that were // We want to remove all tracking entries for transactions that were
// accepted as well as those which match the predicate. // accepted as well as those which match the predicate.
auto i = removeIfIntersectOrMatch( auto const i = removeIfIntersectOrMatch(
tracker_.begin(), tracker_.begin(),
tracker_.end(), tracker_.end(),
accepted.begin(), accepted.begin(),
+10 -9
View File
@@ -779,7 +779,7 @@ Consensus<Adaptor>::peerProposalInternal(
{ {
// update current position // update current position
auto peerPosIt = currPeerPositions_.find(peerID); auto const peerPosIt = currPeerPositions_.find(peerID);
if (peerPosIt != currPeerPositions_.end()) if (peerPosIt != currPeerPositions_.end())
{ {
@@ -1110,7 +1110,7 @@ Consensus<Adaptor>::checkLedger(std::unique_ptr<std::stringstream> const& clog)
{ {
CLOG(clog) << "checkLedger. "; CLOG(clog) << "checkLedger. ";
auto netLgr = adaptor_.getPrevLedger(prevLedgerID_, previousLedger_, mode_.get()); auto const netLgr = adaptor_.getPrevLedger(prevLedgerID_, previousLedger_, mode_.get());
CLOG(clog) << "network ledgerid " << netLgr << ", " CLOG(clog) << "network ledgerid " << netLgr << ", "
<< "previous ledger " << prevLedgerID_ << ". "; << "previous ledger " << prevLedgerID_ << ". ";
@@ -1159,8 +1159,8 @@ Consensus<Adaptor>::phaseOpen(std::unique_ptr<std::stringstream> const& clog)
// it is shortly before ledger close time // it is shortly before ledger close time
bool const anyTransactions = adaptor_.hasOpenTransactions(); bool const anyTransactions = adaptor_.hasOpenTransactions();
auto proposersClosed = currPeerPositions_.size(); auto const proposersClosed = currPeerPositions_.size();
auto proposersValidated = adaptor_.proposersValidated(prevLedgerID_); auto const proposersValidated = adaptor_.proposersValidated(prevLedgerID_);
openTime_.tick(clock_.now()); openTime_.tick(clock_.now());
@@ -1669,7 +1669,7 @@ Consensus<Adaptor>::haveConsensus(std::unique_ptr<std::stringstream> const& clog
// CHECKME: should possibly count unacquired TX sets as disagreeing // CHECKME: should possibly count unacquired TX sets as disagreeing
int agree = 0, disagree = 0; int agree = 0, disagree = 0;
auto ourPosition = result_->position.position(); auto const ourPosition = result_->position.position();
// Count number of agreements/disagreements with our position // Count number of agreements/disagreements with our position
for (auto const& [nodeId, peerPos] : currPeerPositions_) for (auto const& [nodeId, peerPos] : currPeerPositions_)
@@ -1686,7 +1686,7 @@ Consensus<Adaptor>::haveConsensus(std::unique_ptr<std::stringstream> const& clog
++disagree; ++disagree;
} }
} }
auto currentFinished = adaptor_.proposersFinished(previousLedger_, prevLedgerID_); auto const currentFinished = adaptor_.proposersFinished(previousLedger_, prevLedgerID_);
JLOG(j_.debug()) << "Checking for TX consensus: agree=" << agree << ", disagree=" << disagree; JLOG(j_.debug()) << "Checking for TX consensus: agree=" << agree << ", disagree=" << disagree;
@@ -1812,7 +1812,7 @@ Consensus<Adaptor>::createDisputes(TxSetT const& o, std::unique_ptr<std::strings
<< ". "; << ". ";
JLOG(j_.debug()) << "createDisputes " << result_->txns.id() << " to " << o.id(); JLOG(j_.debug()) << "createDisputes " << result_->txns.id() << " to " << o.id();
auto differences = result_->txns.compare(o); auto const differences = result_->txns.compare(o);
int dc = 0; int dc = 0;
@@ -1826,7 +1826,7 @@ Consensus<Adaptor>::createDisputes(TxSetT const& o, std::unique_ptr<std::strings
"xrpl::Consensus::createDisputes : has disputed transactions"); "xrpl::Consensus::createDisputes : has disputed transactions");
TxT const tx = inThisSet ? result_->txns.find(txId) : o.find(txId); TxT const tx = inThisSet ? result_->txns.find(txId) : o.find(txId);
auto txID = tx.id(); auto const txID = tx.id();
if (result_->disputes.find(txID) != result_->disputes.end()) if (result_->disputes.find(txID) != result_->disputes.end())
continue; continue;
@@ -1837,7 +1837,8 @@ Consensus<Adaptor>::createDisputes(TxSetT const& o, std::unique_ptr<std::strings
tx, tx,
result_->txns.exists(txID), result_->txns.exists(txID),
std::max(prevProposers_, currPeerPositions_.size()), std::max(prevProposers_, currPeerPositions_.size()),
j_}; j_,
};
// Update all of the available peer's votes on the disputed transaction // Update all of the available peer's votes on the disputed transaction
for (auto const& [nodeId, peerPos] : currPeerPositions_) for (auto const& [nodeId, peerPos] : currPeerPositions_)
+16 -8
View File
@@ -145,18 +145,26 @@ struct ConsensusParms
std::map<AvalancheState, AvalancheCutoff> const avalancheCutoffs{ std::map<AvalancheState, AvalancheCutoff> const avalancheCutoffs{
// {state, {time, percent, nextState}}, // {state, {time, percent, nextState}},
// Initial state: 50% of nodes must vote yes // Initial state: 50% of nodes must vote yes
{AvalancheState::Init, {
{.consensusTime = 0, .consensusPct = 50, .next = AvalancheState::Mid}}, AvalancheState::Init,
{.consensusTime = 0, .consensusPct = 50, .next = AvalancheState::Mid},
},
// mid-consensus starts after 50% of the previous round time, and // mid-consensus starts after 50% of the previous round time, and
// requires 65% yes // requires 65% yes
{AvalancheState::Mid, {
{.consensusTime = 50, .consensusPct = 65, .next = AvalancheState::Late}}, AvalancheState::Mid,
{.consensusTime = 50, .consensusPct = 65, .next = AvalancheState::Late},
},
// late consensus starts after 85% time, and requires 70% yes // late consensus starts after 85% time, and requires 70% yes
{AvalancheState::Late, {
{.consensusTime = 85, .consensusPct = 70, .next = AvalancheState::Stuck}}, AvalancheState::Late,
{.consensusTime = 85, .consensusPct = 70, .next = AvalancheState::Stuck},
},
// we're stuck after 2x time, requires 95% yes votes // we're stuck after 2x time, requires 95% yes votes
{AvalancheState::Stuck, {
{.consensusTime = 200, .consensusPct = 95, .next = AvalancheState::Stuck}}, AvalancheState::Stuck,
{.consensusTime = 200, .consensusPct = 95, .next = AvalancheState::Stuck},
},
}; };
/** /**
+3 -3
View File
@@ -59,7 +59,7 @@ enum class ConsensusMode {
* if we entered the round observing, but is used to indicate we did * if we entered the round observing, but is used to indicate we did
* have the wrongLedger at some point. * have the wrongLedger at some point.
*/ */
SwitchedLedger SwitchedLedger,
}; };
inline std::string inline std::string
@@ -222,7 +222,7 @@ medianCloseOffset(ConsensusCloseTimes const& times)
// Accumulate weight in time order; the first bin to reach halfWeight is // Accumulate weight in time order; the first bin to reach halfWeight is
// the (lower) weighted median. Returns true once that bin is found. // the (lower) weighted median. Returns true once that bin is found.
auto step = [&](time_point t, std::int64_t w) { auto const step = [&](time_point t, std::int64_t w) {
XRPL_ASSERT(tally < halfWeight, "xrpl::medianCloseOffset::step : median not yet found"); XRPL_ASSERT(tally < halfWeight, "xrpl::medianCloseOffset::step : median not yet found");
tally += w; tally += w;
if (tally >= halfWeight) if (tally >= halfWeight)
@@ -267,7 +267,7 @@ enum class ConsensusState {
No, ///< We do not have consensus No, ///< We do not have consensus
MovedOn, ///< The network has consensus without us MovedOn, ///< The network has consensus without us
Expired, ///< Consensus time limit has hard-expired Expired, ///< Consensus time limit has hard-expired
Yes ///< We have consensus along with the network Yes, ///< We have consensus along with the network
}; };
/** /**
+1 -1
View File
@@ -266,7 +266,7 @@ template <class Tx, class NodeId>
void void
DisputedTx<Tx, NodeId>::unVote(NodeId const& peer) DisputedTx<Tx, NodeId>::unVote(NodeId const& peer)
{ {
auto it = votes_.find(peer); auto const it = votes_.find(peer);
if (it != votes_.end()) if (it != votes_.end())
{ {
+1 -1
View File
@@ -211,7 +211,7 @@ struct Node
void void
erase(Node const* child) erase(Node const* child)
{ {
auto it = std::ranges::find_if( auto const it = std::ranges::find_if(
children, [child](std::unique_ptr<Node> const& curr) { return curr.get() == child; }); children, [child](std::unique_ptr<Node> const& curr) { return curr.get() == child; });
XRPL_ASSERT(it != children.end(), "xrpl::Node::erase : valid input"); XRPL_ASSERT(it != children.end(), "xrpl::Node::erase : valid input");
std::swap(*it, children.back()); std::swap(*it, children.back());
+9 -9
View File
@@ -184,7 +184,7 @@ enum class ValStatus {
/** /**
* Multiple validations by a validator for different ledgers * Multiple validations by a validator for different ledgers
*/ */
Conflicting Conflicting,
}; };
inline std::string inline std::string
@@ -366,7 +366,7 @@ private:
removeTrie(std::scoped_lock<Mutex> const&, NodeID const& nodeID, Validation const& val) removeTrie(std::scoped_lock<Mutex> const&, NodeID const& nodeID, Validation const& val)
{ {
{ {
auto it = acquiring_.find(std::make_pair(val.seq(), val.ledgerID())); auto const it = acquiring_.find(std::make_pair(val.seq(), val.ledgerID()));
if (it != acquiring_.end()) if (it != acquiring_.end())
{ {
it->second.erase(nodeID); it->second.erase(nodeID);
@@ -375,7 +375,7 @@ private:
} }
} }
{ {
auto it = lastLedger_.find(nodeID); auto const it = lastLedger_.find(nodeID);
if (it != lastLedger_.end() && it->second.id() == val.ledgerID()) if (it != lastLedger_.end() && it->second.id() == val.ledgerID())
{ {
trie_.remove(it->second); trie_.remove(it->second);
@@ -443,7 +443,7 @@ private:
// Clear any prior acquiring ledger for this node // Clear any prior acquiring ledger for this node
if (prior) if (prior)
{ {
auto it = acquiring_.find(*prior); auto const it = acquiring_.find(*prior);
if (it != acquiring_.end()) if (it != acquiring_.end())
{ {
it->second.erase(nodeID); it->second.erase(nodeID);
@@ -455,7 +455,7 @@ private:
checkAcquired(lock); checkAcquired(lock);
std::pair<Seq, ID> const valPair{val.seq(), val.ledgerID()}; std::pair<Seq, ID> const valPair{val.seq(), val.ledgerID()};
auto it = acquiring_.find(valPair); auto const it = acquiring_.find(valPair);
if (it != acquiring_.end()) if (it != acquiring_.end())
{ {
it->second.insert(nodeID); it->second.insert(nodeID);
@@ -529,7 +529,7 @@ private:
} }
else else
{ {
auto cit = typename decltype(current_)::const_iterator{it}; auto const cit = typename decltype(current_)::const_iterator{it};
// contains a live record // contains a live record
f(cit->first, cit->second); f(cit->first, cit->second);
++it; ++it;
@@ -554,7 +554,7 @@ private:
void void
byLedger(std::scoped_lock<Mutex> const&, ID const& ledgerID, Pre&& pre, F&& f) byLedger(std::scoped_lock<Mutex> const&, ID const& ledgerID, Pre&& pre, F&& f)
{ {
auto it = byLedger_.find(ledgerID); auto const it = byLedger_.find(ledgerID);
if (it != byLedger_.end()) if (it != byLedger_.end())
{ {
// Update set time since it is being used // Update set time since it is being used
@@ -857,7 +857,7 @@ public:
if (!preferred) if (!preferred)
{ {
// fall back to majority over acquiring ledgers // fall back to majority over acquiring ledgers
auto it = std::ranges::max_element(acquiring_, [](auto const& a, auto const& b) { auto const it = std::ranges::max_element(acquiring_, [](auto const& a, auto const& b) {
std::pair<Seq, ID> const& aKey = a.first; std::pair<Seq, ID> const& aKey = a.first;
typename HashSet<NodeID>::size_type const& aSize = a.second.size(); typename HashSet<NodeID>::size_type const& aSize = a.second.size();
std::pair<Seq, ID> const& bKey = b.first; std::pair<Seq, ID> const& bKey = b.first;
@@ -937,7 +937,7 @@ public:
return (preferred->first >= minSeq) ? preferred->second : lcl.id(); return (preferred->first >= minSeq) ? preferred->second : lcl.id();
// Otherwise, rely on peer ledgers // Otherwise, rely on peer ledgers
auto it = std::ranges::max_element(peerCounts, [](auto const& a, auto const& b) { auto const it = std::ranges::max_element(peerCounts, [](auto const& a, auto const& b) {
// Prefer larger counts, then larger ids on ties // Prefer larger counts, then larger ids on ties
// (max_element expects this to return true if a < b) // (max_element expects this to return true if a < b)
return std::tie(a.second, a.first) < std::tie(b.second, b.first); return std::tie(a.second, a.first) < std::tie(b.second, b.first);
+1 -1
View File
@@ -156,7 +156,7 @@ public:
{ {
if (!allClosuresDoneCond_.wait_for(lock, wait, [this] { return closureCount_ == 0; })) if (!allClosuresDoneCond_.wait_for(lock, wait, [this] { return closureCount_ == 0; }))
{ {
if (auto stream = j.error()) if (auto const stream = j.error())
stream << name << " waiting for ClosureCounter::join()."; stream << name << " waiting for ClosureCounter::join().";
allClosuresDoneCond_.wait(lock, [this] { return closureCount_ == 0; }); allClosuresDoneCond_.wait(lock, [this] { return closureCount_ == 0; });
} }
+2 -2
View File
@@ -54,7 +54,7 @@ JobQueue::Coro::post()
} }
// sp keeps 'this' alive // sp keeps 'this' alive
if (jq_.addJob(type_, name_, [this, sp = shared_from_this()]() { resume(); })) if (jq_.addJob(type_, name_, [this, sp = shared_from_this()] { resume(); }))
{ {
return true; return true;
} }
@@ -130,7 +130,7 @@ inline void
JobQueue::Coro::join() JobQueue::Coro::join()
{ {
std::unique_lock<std::mutex> lk(mutexRun_); std::unique_lock<std::mutex> lk(mutexRun_);
cv_.wait(lk, [this]() { return !running_; }); cv_.wait(lk, [this] { return !running_; });
} }
} // namespace xrpl } // namespace xrpl
Loaded 100 of 979 files, more files were not shown because too many files have changed in this diff. Show more