mirror of
https://github.com/XRPLF/rippled.git
synced 2026-07-24 07:30:30 +00:00
Compare commits
29 Commits
develop
...
copilot/re
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3b1e9f2a8a | ||
|
|
4b7a21bdfe | ||
|
|
f956135e29 | ||
|
|
3e4422df28 | ||
|
|
9f5bf51b31 | ||
|
|
9ccb7742ca | ||
|
|
336b9c101e | ||
|
|
5fdbedf6ac | ||
|
|
ce4490d793 | ||
|
|
ba2ff93d6e | ||
|
|
4714160052 | ||
|
|
5147825d61 | ||
|
|
719368ae25 | ||
|
|
3e372656d3 | ||
|
|
81964068a1 | ||
|
|
2e0ea38d7d | ||
|
|
aa1f84e226 | ||
|
|
ae7076c054 | ||
|
|
9a221d1291 | ||
|
|
5e6d8a4692 | ||
|
|
11c7d912f6 | ||
|
|
b7d6cdf713 | ||
|
|
193ddcbfac | ||
|
|
3a70d9dfba | ||
|
|
03e8a68670 | ||
|
|
28143d74af | ||
|
|
ff4c538a9f | ||
|
|
9fe94c47c3 | ||
|
|
3f307f8128 |
17
.clang-tidy
17
.clang-tidy
@@ -56,17 +56,32 @@ Checks: "-*,
|
||||
|
||||
readability-*,
|
||||
-readability-avoid-const-params-in-decls,
|
||||
-readability-avoid-unconditional-preprocessor-if,
|
||||
-readability-container-data-pointer,
|
||||
-readability-delete-null-pointer,
|
||||
-readability-function-cognitive-complexity,
|
||||
-readability-function-size,
|
||||
-readability-identifier-length,
|
||||
-readability-inconsistent-declaration-parameter-name,
|
||||
-readability-isolate-declaration,
|
||||
-readability-magic-numbers,
|
||||
-readability-misplaced-array-index,
|
||||
-readability-named-parameter,
|
||||
-readability-operators-representation,
|
||||
-readability-qualified-auto,
|
||||
-readability-redundant-access-specifiers,
|
||||
-readability-redundant-control-flow,
|
||||
-readability-redundant-function-ptr-dereference,
|
||||
-readability-redundant-preprocessor,
|
||||
-readability-redundant-smartptr-get,
|
||||
-readability-redundant-string-cstr,
|
||||
-readability-simplify-subscript-expr,
|
||||
-readability-static-accessed-through-instance,
|
||||
-readability-uppercase-literal-suffix
|
||||
-readability-string-compare,
|
||||
-readability-uniqueptr-delete-release,
|
||||
-readability-uppercase-literal-suffix,
|
||||
-readability-use-anyofallof,
|
||||
-readability-use-concise-preprocessor-directives
|
||||
"
|
||||
# ---
|
||||
# bugprone-narrowing-conversions, # This will break a lot of code but we should enable it in the future because it can eliminate a lot of bugs
|
||||
|
||||
@@ -30,9 +30,7 @@ ignoreRegExpList:
|
||||
- ABCDEFGHIJKLMNOPQRSTUVWXYZ
|
||||
- ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
|
||||
overrides:
|
||||
- filename:
|
||||
- "**/*_test.cpp" # legacy boost.test files
|
||||
- "src/tests/**/*.cpp" # gtest test files
|
||||
- filename: "**/*_test.cpp" # all test files
|
||||
ignoreRegExpList:
|
||||
- /"[^"]*"/g # double-quoted strings
|
||||
- /'[^']*'/g # single-quoted strings
|
||||
@@ -67,7 +65,6 @@ words:
|
||||
- Btrfs
|
||||
- Buildx
|
||||
- canonicality
|
||||
- canonicalised
|
||||
- changespq
|
||||
- checkme
|
||||
- choco
|
||||
@@ -75,7 +72,6 @@ words:
|
||||
- citardauq
|
||||
- clawback
|
||||
- clawbacks
|
||||
- clippy
|
||||
- cmaketoolchain
|
||||
- coeffs
|
||||
- coldwallet
|
||||
@@ -218,7 +214,6 @@ words:
|
||||
- Nyffenegger
|
||||
- onlatest
|
||||
- ostr
|
||||
- oxalica
|
||||
- pargs
|
||||
- partitioner
|
||||
- paychan
|
||||
@@ -264,9 +259,6 @@ words:
|
||||
- rocksdb
|
||||
- Rohrs
|
||||
- roundings
|
||||
- rustc
|
||||
- rustfmt
|
||||
- rustup
|
||||
- sahyadri
|
||||
- Satoshi
|
||||
- scons
|
||||
@@ -310,7 +302,6 @@ words:
|
||||
- takerpays
|
||||
- ters
|
||||
- TMEndpointv2
|
||||
- toolchain
|
||||
- tparam
|
||||
- trixie
|
||||
- tx
|
||||
@@ -343,7 +334,6 @@ words:
|
||||
- unsquelch
|
||||
- unsquelched
|
||||
- unsquelching
|
||||
- unsuffixed
|
||||
- unvalidated
|
||||
- unveto
|
||||
- unvetoed
|
||||
|
||||
@@ -11,9 +11,6 @@ endfunction()
|
||||
function(create_symbolic_link target link)
|
||||
endfunction()
|
||||
|
||||
function(xrpl_add_benchmark name)
|
||||
endfunction()
|
||||
|
||||
macro(exclude_from_default target_)
|
||||
endmacro()
|
||||
|
||||
|
||||
8
.github/pull_request_template.md
vendored
8
.github/pull_request_template.md
vendored
@@ -1,10 +1,10 @@
|
||||
<!--
|
||||
This PR template helps you write a good pull request description.
|
||||
This PR template helps you to write a good pull request description.
|
||||
Please feel free to include additional useful information even beyond what is requested below.
|
||||
|
||||
If your branch is on a personal fork and has a name that allows it to
|
||||
run CI build/test jobs (e.g. "ci/foo"), remember to rename it BEFORE
|
||||
opening the PR. This avoids redundant test runs. Renaming
|
||||
opening the PR. This avoids unnecessary redundant test runs. Renaming
|
||||
the branch after opening the PR will close the PR.
|
||||
https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-branches-in-your-repository/renaming-a-branch
|
||||
-->
|
||||
@@ -15,7 +15,7 @@ https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-
|
||||
Please include a summary of the changes.
|
||||
This may be a direct input to the release notes.
|
||||
If too broad, please consider splitting into multiple PRs.
|
||||
If there is a relevant task or issue, please link it here.
|
||||
If a relevant task or issue, please link it here.
|
||||
-->
|
||||
|
||||
### Context of Change
|
||||
@@ -65,5 +65,5 @@ This section may not be needed if your change includes thoroughly commented unit
|
||||
|
||||
<!--
|
||||
## Future Tasks
|
||||
For future tasks related to this PR.
|
||||
For future tasks related to PR.
|
||||
-->
|
||||
|
||||
6
.github/scripts/levelization/README.md
vendored
6
.github/scripts/levelization/README.md
vendored
@@ -40,13 +40,13 @@ listed later.
|
||||
| 04 | xrpl/protocol |
|
||||
| 05 | xrpl/core xrpl/resource xrpl/server |
|
||||
| 06 | xrpl/ledger xrpl/nodestore xrpl/net |
|
||||
| 07 | xrpl/shamap xrpl/consensus |
|
||||
| 07 | xrpl/shamap |
|
||||
|
||||
## xrpld Modules (Application Implementation)
|
||||
|
||||
| Level / Tier | Module(s) |
|
||||
| ------------ | --------------------------- |
|
||||
| 05 | xrpld/conditions |
|
||||
| ------------ | -------------------------------- |
|
||||
| 05 | xrpld/conditions xrpld/consensus |
|
||||
| 06 | xrpld/core xrpld/peerfinder |
|
||||
| 07 | xrpld/shamap xrpld/overlay |
|
||||
| 08 | xrpld/app |
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
Loop: xrpld.app xrpld.overlay
|
||||
xrpld.app > xrpld.overlay
|
||||
|
||||
Loop: xrpld.app xrpld.peerfinder
|
||||
xrpld.peerfinder ~= xrpld.app
|
||||
|
||||
Loop: xrpld.app xrpld.rpc
|
||||
xrpld.rpc > xrpld.app
|
||||
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
benchmarks.libxrpl > xrpl.basics
|
||||
benchmarks.libxrpl > xrpl.config
|
||||
benchmarks.libxrpl > xrpl.nodestore
|
||||
libxrpl.basics > xrpl.basics
|
||||
libxrpl.conditions > xrpl.basics
|
||||
libxrpl.conditions > xrpl.conditions
|
||||
libxrpl.config > xrpl.basics
|
||||
libxrpl.config > xrpl.config
|
||||
libxrpl.consensus > xrpl.basics
|
||||
libxrpl.consensus > xrpl.consensus
|
||||
libxrpl.core > xrpl.basics
|
||||
libxrpl.core > xrpl.core
|
||||
libxrpl.core > xrpl.json
|
||||
@@ -27,9 +22,6 @@ libxrpl.nodestore > xrpl.config
|
||||
libxrpl.nodestore > xrpl.json
|
||||
libxrpl.nodestore > xrpl.nodestore
|
||||
libxrpl.nodestore > xrpl.protocol
|
||||
libxrpl.peerfinder > xrpl.basics
|
||||
libxrpl.peerfinder > xrpl.peerfinder
|
||||
libxrpl.peerfinder > xrpl.protocol
|
||||
libxrpl.protocol > xrpl.basics
|
||||
libxrpl.protocol > xrpl.json
|
||||
libxrpl.protocol > xrpl.protocol
|
||||
@@ -65,9 +57,9 @@ test.app > test.jtx
|
||||
test.app > test.unit_test
|
||||
test.app > xrpl.basics
|
||||
test.app > xrpl.config
|
||||
test.app > xrpl.consensus
|
||||
test.app > xrpl.core
|
||||
test.app > xrpld.app
|
||||
test.app > xrpld.consensus
|
||||
test.app > xrpld.core
|
||||
test.app > xrpld.overlay
|
||||
test.app > xrpld.rpc
|
||||
@@ -88,9 +80,12 @@ test.basics > xrpl.protocol
|
||||
test.beast > xrpl.basics
|
||||
test.conditions > xrpl.basics
|
||||
test.conditions > xrpl.conditions
|
||||
test.consensus > test.csf
|
||||
test.consensus > test.jtx
|
||||
test.consensus > test.unit_test
|
||||
test.consensus > xrpl.basics
|
||||
test.consensus > xrpld.app
|
||||
test.consensus > xrpld.consensus
|
||||
test.consensus > xrpl.ledger
|
||||
test.consensus > xrpl.protocol
|
||||
test.consensus > xrpl.shamap
|
||||
@@ -105,6 +100,10 @@ test.core > xrpl.json
|
||||
test.core > xrpl.protocol
|
||||
test.core > xrpl.rdb
|
||||
test.core > xrpl.server
|
||||
test.csf > xrpl.basics
|
||||
test.csf > xrpld.consensus
|
||||
test.csf > xrpl.json
|
||||
test.csf > xrpl.ledger
|
||||
test.json > test.jtx
|
||||
test.json > xrpl.json
|
||||
test.jtx > test.unit_test
|
||||
@@ -144,17 +143,22 @@ test.overlay > xrpl.config
|
||||
test.overlay > xrpld.app
|
||||
test.overlay > xrpld.core
|
||||
test.overlay > xrpld.overlay
|
||||
test.overlay > xrpld.peerfinder
|
||||
test.overlay > xrpl.json
|
||||
test.overlay > xrpl.nodestore
|
||||
test.overlay > xrpl.peerfinder
|
||||
test.overlay > xrpl.protocol
|
||||
test.overlay > xrpl.resource
|
||||
test.overlay > xrpl.server
|
||||
test.overlay > xrpl.shamap
|
||||
test.peerfinder > test.beast
|
||||
test.peerfinder > test.unit_test
|
||||
test.peerfinder > xrpl.basics
|
||||
test.peerfinder > xrpld.core
|
||||
test.peerfinder > xrpld.peerfinder
|
||||
test.peerfinder > xrpl.protocol
|
||||
test.protocol > test.jtx
|
||||
test.protocol > test.unit_test
|
||||
test.protocol > xrpl.basics
|
||||
test.protocol > xrpld.core
|
||||
test.protocol > xrpl.json
|
||||
test.protocol > xrpl.protocol
|
||||
test.rpc > test.jtx
|
||||
@@ -184,13 +188,11 @@ test.unit_test > xrpl.basics
|
||||
test.unit_test > xrpl.protocol
|
||||
tests.libxrpl > xrpl.basics
|
||||
tests.libxrpl > xrpl.config
|
||||
tests.libxrpl > xrpl.consensus
|
||||
tests.libxrpl > xrpl.core
|
||||
tests.libxrpl > xrpl.json
|
||||
tests.libxrpl > xrpl.ledger
|
||||
tests.libxrpl > xrpl.net
|
||||
tests.libxrpl > xrpl.nodestore
|
||||
tests.libxrpl > xrpl.peerfinder
|
||||
tests.libxrpl > xrpl.protocol
|
||||
tests.libxrpl > xrpl.protocol_autogen
|
||||
tests.libxrpl > xrpl.resource
|
||||
@@ -200,10 +202,6 @@ tests.libxrpl > xrpl.tx
|
||||
xrpl.conditions > xrpl.basics
|
||||
xrpl.conditions > xrpl.protocol
|
||||
xrpl.config > xrpl.basics
|
||||
xrpl.consensus > xrpl.basics
|
||||
xrpl.consensus > xrpl.json
|
||||
xrpl.consensus > xrpl.ledger
|
||||
xrpl.consensus > xrpl.protocol
|
||||
xrpl.core > xrpl.basics
|
||||
xrpl.core > xrpl.json
|
||||
xrpl.core > xrpl.protocol
|
||||
@@ -218,8 +216,6 @@ xrpl.nodestore > xrpl.basics
|
||||
xrpl.nodestore > xrpl.config
|
||||
xrpl.nodestore > xrpl.json
|
||||
xrpl.nodestore > xrpl.protocol
|
||||
xrpl.peerfinder > xrpl.basics
|
||||
xrpl.peerfinder > xrpl.protocol
|
||||
xrpl.protocol > xrpl.basics
|
||||
xrpl.protocol > xrpl.json
|
||||
xrpl.protocol_autogen > xrpl.json
|
||||
@@ -246,20 +242,23 @@ xrpl.tx > xrpl.protocol
|
||||
xrpld.app > test.unit_test
|
||||
xrpld.app > xrpl.basics
|
||||
xrpld.app > xrpl.config
|
||||
xrpld.app > xrpl.consensus
|
||||
xrpld.app > xrpl.core
|
||||
xrpld.app > xrpld.consensus
|
||||
xrpld.app > xrpld.core
|
||||
xrpld.app > xrpl.json
|
||||
xrpld.app > xrpl.ledger
|
||||
xrpld.app > xrpl.net
|
||||
xrpld.app > xrpl.nodestore
|
||||
xrpld.app > xrpl.peerfinder
|
||||
xrpld.app > xrpl.protocol
|
||||
xrpld.app > xrpl.rdb
|
||||
xrpld.app > xrpl.resource
|
||||
xrpld.app > xrpl.server
|
||||
xrpld.app > xrpl.shamap
|
||||
xrpld.app > xrpl.tx
|
||||
xrpld.consensus > xrpl.basics
|
||||
xrpld.consensus > xrpl.json
|
||||
xrpld.consensus > xrpl.ledger
|
||||
xrpld.consensus > xrpl.protocol
|
||||
xrpld.core > xrpl.basics
|
||||
xrpld.core > xrpl.config
|
||||
xrpld.core > xrpl.core
|
||||
@@ -268,22 +267,21 @@ xrpld.core > xrpl.protocol
|
||||
xrpld.core > xrpl.rdb
|
||||
xrpld.overlay > xrpl.basics
|
||||
xrpld.overlay > xrpl.config
|
||||
xrpld.overlay > xrpl.consensus
|
||||
xrpld.overlay > xrpl.core
|
||||
xrpld.overlay > xrpld.consensus
|
||||
xrpld.overlay > xrpld.core
|
||||
xrpld.overlay > xrpld.peerfinder
|
||||
xrpld.overlay > xrpl.json
|
||||
xrpld.overlay > xrpl.ledger
|
||||
xrpld.overlay > xrpl.peerfinder
|
||||
xrpld.overlay > xrpl.protocol
|
||||
xrpld.overlay > xrpl.resource
|
||||
xrpld.overlay > xrpl.server
|
||||
xrpld.overlay > xrpl.shamap
|
||||
xrpld.overlay > xrpl.tx
|
||||
xrpld.peerfinder > xrpl.basics
|
||||
xrpld.peerfinder > xrpld.app
|
||||
xrpld.peerfinder > xrpl.config
|
||||
xrpld.peerfinder > xrpld.core
|
||||
xrpld.peerfinder > xrpl.peerfinder
|
||||
xrpld.peerfinder > xrpl.protocol
|
||||
xrpld.peerfinder > xrpl.rdb
|
||||
xrpld.perflog > xrpl.basics
|
||||
xrpld.perflog > xrpl.config
|
||||
|
||||
62
.github/scripts/strategy-matrix/generate.py
vendored
62
.github/scripts/strategy-matrix/generate.py
vendored
@@ -25,16 +25,24 @@ def get_cmake_args(build_type: str, extra_args: str) -> str:
|
||||
return " ".join(args)
|
||||
|
||||
|
||||
def runs_on_event(exclude_event_types: list[str], event: str | None) -> bool:
|
||||
"""Whether a config should run for the current event.
|
||||
|
||||
'exclude_event_types' is a list of GitHub event names (e.g.
|
||||
["pull_request"]) on which the config should NOT run; an empty list means
|
||||
the config runs on every event. When no event is given (event is None), no
|
||||
filtering is applied.
|
||||
"""
|
||||
if event is None:
|
||||
return True
|
||||
return event not in exclude_event_types
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Input types — shapes of the JSON config files
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
# Every config must declare 'minimal'. Minimal configs form the reduced matrix
|
||||
# built for pull requests by default; the full matrix adds the rest. Packaging
|
||||
# configs declare it too, but packaging is gated in the workflow, not by it.
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class LinuxConfig:
|
||||
"""One entry in linux.json's 'configs' or 'package_configs' arrays."""
|
||||
@@ -42,11 +50,13 @@ class LinuxConfig:
|
||||
compiler: list[str]
|
||||
build_type: list[str]
|
||||
arch: list[str]
|
||||
minimal: bool
|
||||
sanitizers: list[str] = dataclasses.field(default_factory=list)
|
||||
suffix: str = ""
|
||||
extra_cmake_args: str = ""
|
||||
image: str = "" # only used by package_configs entries
|
||||
# List of GitHub event names (e.g. "pull_request") on which this config
|
||||
# should NOT run. Empty means it runs on every event.
|
||||
exclude_event_types: list[str] = dataclasses.field(default_factory=list)
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
@@ -79,9 +89,11 @@ class PlatformConfig:
|
||||
"""One entry in macos.json's or windows.json's 'configs' array."""
|
||||
|
||||
build_type: list[str]
|
||||
minimal: bool
|
||||
build_only: bool = False # if true, skip tests (e.g. macos/Windows Debug)
|
||||
extra_cmake_args: str = ""
|
||||
# List of GitHub event names (e.g. "pull_request") on which this config
|
||||
# should NOT run. Empty means it runs on every event.
|
||||
exclude_event_types: list[str] = dataclasses.field(default_factory=list)
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
if isinstance(self.build_type, str):
|
||||
@@ -156,18 +168,20 @@ _ARCHS: dict[str, Architecture] = {
|
||||
}
|
||||
|
||||
|
||||
def expand_linux_matrix(linux: LinuxFile, minimal: bool) -> list[MatrixEntry]:
|
||||
def expand_linux_matrix(
|
||||
linux: LinuxFile, event: str | None = None
|
||||
) -> list[MatrixEntry]:
|
||||
"""Expand a LinuxFile into a flat list of matrix entries.
|
||||
|
||||
Each config entry is expanded over the cross-product of its
|
||||
compiler, build_type, sanitizers, and architecture lists. When 'minimal' is
|
||||
true, only configs flagged as minimal are included.
|
||||
compiler, build_type, sanitizers, and architecture lists. Configs that
|
||||
exclude the current event are skipped.
|
||||
"""
|
||||
entries: list[MatrixEntry] = []
|
||||
|
||||
for distro, configs in linux.configs.items():
|
||||
for cfg in configs:
|
||||
if minimal and not cfg.minimal:
|
||||
if not runs_on_event(cfg.exclude_event_types, event):
|
||||
continue
|
||||
# An empty sanitizers list means "one entry with no sanitizer".
|
||||
effective_sanitizers = cfg.sanitizers or [""]
|
||||
@@ -226,17 +240,19 @@ def expand_linux_packaging(linux: LinuxFile) -> list[PackagingEntry]:
|
||||
return entries
|
||||
|
||||
|
||||
def expand_platform_matrix(pf: PlatformFile, minimal: bool) -> list[MatrixEntry]:
|
||||
def expand_platform_matrix(
|
||||
pf: PlatformFile, event: str | None = None
|
||||
) -> list[MatrixEntry]:
|
||||
"""Expand a PlatformFile (macOS or Windows) into matrix entries.
|
||||
|
||||
When 'minimal' is true, only configs flagged as minimal are included.
|
||||
Configs that exclude the current event are skipped.
|
||||
"""
|
||||
platform_name, arch = pf.platform.split("/")
|
||||
is_windows = platform_name == "windows"
|
||||
|
||||
entries: list[MatrixEntry] = []
|
||||
for cfg in pf.configs:
|
||||
if minimal and not cfg.minimal:
|
||||
if not runs_on_event(cfg.exclude_event_types, event):
|
||||
continue
|
||||
for build_type in cfg.build_type:
|
||||
entries.append(
|
||||
@@ -276,12 +292,12 @@ if __name__ == "__main__":
|
||||
action="store_true",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-m",
|
||||
"--minimal",
|
||||
help="Emit only the minimal matrix (the configs flagged 'minimal'), "
|
||||
"used for pull requests by default. If omitted, the full matrix is "
|
||||
"emitted.",
|
||||
action="store_true",
|
||||
"-e",
|
||||
"--event",
|
||||
help="The GitHub event name that triggered the workflow (e.g. 'push', "
|
||||
"'pull_request'). Configs are filtered by their 'event_type'. If "
|
||||
"omitted, no filtering is applied.",
|
||||
default=None,
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
@@ -292,15 +308,15 @@ if __name__ == "__main__":
|
||||
else:
|
||||
if args.config in ("linux", None):
|
||||
matrix += expand_linux_matrix(
|
||||
LinuxFile.load(THIS_DIR / "linux.json"), args.minimal
|
||||
LinuxFile.load(THIS_DIR / "linux.json"), args.event
|
||||
)
|
||||
if args.config in ("macos", None):
|
||||
matrix += expand_platform_matrix(
|
||||
PlatformFile.load(THIS_DIR / "macos.json"), args.minimal
|
||||
PlatformFile.load(THIS_DIR / "macos.json"), args.event
|
||||
)
|
||||
if args.config in ("windows", None):
|
||||
matrix += expand_platform_matrix(
|
||||
PlatformFile.load(THIS_DIR / "windows.json"), args.minimal
|
||||
PlatformFile.load(THIS_DIR / "windows.json"), args.event
|
||||
)
|
||||
|
||||
print(f"matrix={json.dumps({'include': [dataclasses.asdict(e) for e in matrix]})}")
|
||||
|
||||
33
.github/scripts/strategy-matrix/linux.json
vendored
33
.github/scripts/strategy-matrix/linux.json
vendored
@@ -1,31 +1,17 @@
|
||||
{
|
||||
"image_tag": "sha-3122de8",
|
||||
"image_tag": "sha-e29b523",
|
||||
"configs": {
|
||||
"ubuntu": [
|
||||
{
|
||||
"compiler": ["clang"],
|
||||
"build_type": ["Release"],
|
||||
"arch": ["amd64"],
|
||||
"minimal": true
|
||||
},
|
||||
{
|
||||
"compiler": ["gcc"],
|
||||
"build_type": ["Release"],
|
||||
"arch": ["amd64"],
|
||||
"minimal": false
|
||||
},
|
||||
{
|
||||
"compiler": ["gcc", "clang"],
|
||||
"build_type": ["Debug", "Release"],
|
||||
"arch": ["arm64"],
|
||||
"minimal": false
|
||||
"arch": ["amd64", "arm64"]
|
||||
},
|
||||
|
||||
{
|
||||
"compiler": ["gcc", "clang"],
|
||||
"build_type": ["Debug", "Release"],
|
||||
"arch": ["amd64"],
|
||||
"minimal": false,
|
||||
"sanitizers": ["address", "undefinedbehavior"]
|
||||
},
|
||||
|
||||
@@ -33,7 +19,6 @@
|
||||
"compiler": ["gcc"],
|
||||
"build_type": ["Debug"],
|
||||
"arch": ["amd64"],
|
||||
"minimal": true,
|
||||
"suffix": "coverage",
|
||||
"extra_cmake_args": "-DUNIT_TEST_REFERENCE_FEE=500 -Dcoverage=ON -Dcoverage_format=xml -DCODE_COVERAGE_VERBOSE=ON -DCMAKE_C_FLAGS=-O0 -DCMAKE_CXX_FLAGS=-O0"
|
||||
},
|
||||
@@ -41,7 +26,6 @@
|
||||
"compiler": ["clang"],
|
||||
"build_type": ["Debug"],
|
||||
"arch": ["amd64"],
|
||||
"minimal": false,
|
||||
"suffix": "voidstar",
|
||||
"extra_cmake_args": "-Dvoidstar=ON"
|
||||
},
|
||||
@@ -49,7 +33,6 @@
|
||||
"compiler": ["clang"],
|
||||
"build_type": ["Release"],
|
||||
"arch": ["amd64"],
|
||||
"minimal": false,
|
||||
"suffix": "reffee",
|
||||
"extra_cmake_args": "-DUNIT_TEST_REFERENCE_FEE=1000"
|
||||
},
|
||||
@@ -57,9 +40,9 @@
|
||||
"compiler": ["gcc"],
|
||||
"build_type": ["Debug"],
|
||||
"arch": ["amd64"],
|
||||
"minimal": false,
|
||||
"suffix": "unity",
|
||||
"extra_cmake_args": "-Dunity=ON"
|
||||
"extra_cmake_args": "-Dunity=ON",
|
||||
"exclude_event_types": ["pull_request"]
|
||||
}
|
||||
],
|
||||
|
||||
@@ -67,8 +50,7 @@
|
||||
{
|
||||
"compiler": ["gcc"],
|
||||
"build_type": ["Release"],
|
||||
"arch": ["amd64"],
|
||||
"minimal": false
|
||||
"arch": ["amd64"]
|
||||
}
|
||||
],
|
||||
|
||||
@@ -76,8 +58,7 @@
|
||||
{
|
||||
"compiler": ["gcc"],
|
||||
"build_type": ["Release"],
|
||||
"arch": ["amd64"],
|
||||
"minimal": false
|
||||
"arch": ["amd64"]
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -87,7 +68,6 @@
|
||||
"compiler": ["gcc"],
|
||||
"build_type": ["Release"],
|
||||
"arch": ["amd64"],
|
||||
"minimal": false,
|
||||
"image": "ghcr.io/xrplf/xrpld/packaging-debian:sha-577d745"
|
||||
}
|
||||
],
|
||||
@@ -97,7 +77,6 @@
|
||||
"compiler": ["gcc"],
|
||||
"build_type": ["Release"],
|
||||
"arch": ["amd64"],
|
||||
"minimal": false,
|
||||
"image": "ghcr.io/xrplf/xrpld/packaging-rhel:sha-577d745"
|
||||
}
|
||||
]
|
||||
|
||||
5
.github/scripts/strategy-matrix/macos.json
vendored
5
.github/scripts/strategy-matrix/macos.json
vendored
@@ -4,14 +4,13 @@
|
||||
"configs": [
|
||||
{
|
||||
"build_type": "Release",
|
||||
"extra_cmake_args": "-DCMAKE_POLICY_VERSION_MINIMUM=3.5",
|
||||
"minimal": true
|
||||
"extra_cmake_args": "-DCMAKE_POLICY_VERSION_MINIMUM=3.5"
|
||||
},
|
||||
{
|
||||
"build_type": "Debug",
|
||||
"extra_cmake_args": "-DCMAKE_POLICY_VERSION_MINIMUM=3.5",
|
||||
"build_only": true,
|
||||
"minimal": false
|
||||
"exclude_event_types": ["pull_request"]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
4
.github/scripts/strategy-matrix/windows.json
vendored
4
.github/scripts/strategy-matrix/windows.json
vendored
@@ -2,11 +2,11 @@
|
||||
"platform": "windows/amd64",
|
||||
"runner": ["self-hosted", "Windows", "dev-box-windows-2026"],
|
||||
"configs": [
|
||||
{ "build_type": "Release", "minimal": true },
|
||||
{ "build_type": "Release" },
|
||||
{
|
||||
"build_type": "Debug",
|
||||
"build_only": true,
|
||||
"minimal": false
|
||||
"exclude_event_types": ["pull_request"]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
8
.github/workflows/build-nix-images.yml
vendored
8
.github/workflows/build-nix-images.yml
vendored
@@ -1,4 +1,4 @@
|
||||
name: Build `nix` Docker images
|
||||
name: Build Nix Docker images
|
||||
|
||||
on:
|
||||
push:
|
||||
@@ -8,7 +8,6 @@ on:
|
||||
- ".github/workflows/build-nix-images.yml"
|
||||
- "flake.nix"
|
||||
- "flake.lock"
|
||||
- "rust-toolchain.toml"
|
||||
- "nix/**"
|
||||
- "!nix/docker/README.md"
|
||||
- "!nix/devshell.nix"
|
||||
@@ -19,7 +18,6 @@ on:
|
||||
- ".github/workflows/build-nix-images.yml"
|
||||
- "flake.nix"
|
||||
- "flake.lock"
|
||||
- "rust-toolchain.toml"
|
||||
- "nix/**"
|
||||
- "!nix/docker/README.md"
|
||||
- "!nix/devshell.nix"
|
||||
@@ -38,7 +36,7 @@ defaults:
|
||||
|
||||
jobs:
|
||||
build-merge:
|
||||
name: Build and push `nix-${{ matrix.distro.name }}` image
|
||||
name: Build and push nix-${{ matrix.distro.name }}
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
@@ -56,7 +54,7 @@ jobs:
|
||||
base_image: debian:bookworm
|
||||
- name: rhel
|
||||
base_image: registry.access.redhat.com/ubi9/ubi:latest
|
||||
uses: XRPLF/actions/.github/workflows/build-multiarch-image.yml@9e7e4e80af9e684c116b38369add8eea64451f32
|
||||
uses: XRPLF/actions/.github/workflows/build-multiarch-image.yml@ee03d31bcc4501d7599dc1b1ecd7a34af582ad1c
|
||||
with:
|
||||
image_name: xrpld/nix-${{ matrix.distro.name }}
|
||||
dockerfile: nix/docker/Dockerfile
|
||||
|
||||
6
.github/workflows/build-packaging-images.yml
vendored
6
.github/workflows/build-packaging-images.yml
vendored
@@ -1,4 +1,4 @@
|
||||
name: Build `packaging` Docker images
|
||||
name: Build packaging Docker images
|
||||
|
||||
on:
|
||||
push:
|
||||
@@ -26,7 +26,7 @@ defaults:
|
||||
|
||||
jobs:
|
||||
build-merge:
|
||||
name: Build and push `packaging-${{ matrix.distro.name }}` image
|
||||
name: Build and push packaging-${{ matrix.distro.name }}
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
@@ -38,7 +38,7 @@ jobs:
|
||||
base_image: debian:bookworm
|
||||
- name: rhel
|
||||
base_image: registry.access.redhat.com/ubi9/ubi:latest
|
||||
uses: XRPLF/actions/.github/workflows/build-multiarch-image.yml@9e7e4e80af9e684c116b38369add8eea64451f32
|
||||
uses: XRPLF/actions/.github/workflows/build-multiarch-image.yml@ee03d31bcc4501d7599dc1b1ecd7a34af582ad1c
|
||||
with:
|
||||
image_name: xrpld/packaging-${{ matrix.distro.name }}
|
||||
dockerfile: package/Dockerfile
|
||||
|
||||
38
.github/workflows/build-pre-commit-image.yml
vendored
38
.github/workflows/build-pre-commit-image.yml
vendored
@@ -1,38 +0,0 @@
|
||||
name: Build `pre-commit` Docker image
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- develop
|
||||
paths:
|
||||
- ".github/workflows/build-pre-commit-image.yml"
|
||||
- "bin/pre-commit/Dockerfile"
|
||||
- "rust-toolchain.toml"
|
||||
pull_request:
|
||||
paths:
|
||||
- ".github/workflows/build-pre-commit-image.yml"
|
||||
- "bin/pre-commit/Dockerfile"
|
||||
- "rust-toolchain.toml"
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
# Read `on-trigger.yml` for the rationale behind this concurrency group name.
|
||||
group: ${{ github.workflow }}-${{ github.event_name == 'push' && github.ref == 'refs/heads/develop' && github.sha || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
build-merge:
|
||||
name: Build and push `pre-commit` image
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
uses: XRPLF/actions/.github/workflows/build-multiarch-image.yml@9e7e4e80af9e684c116b38369add8eea64451f32
|
||||
with:
|
||||
image_name: xrpld/pre-commit
|
||||
dockerfile: bin/pre-commit/Dockerfile
|
||||
base_image: ubuntu:26.04
|
||||
push: ${{ github.event_name == 'push' }}
|
||||
2
.github/workflows/check-pr-title.yml
vendored
2
.github/workflows/check-pr-title.yml
vendored
@@ -20,4 +20,4 @@ on:
|
||||
jobs:
|
||||
check_title:
|
||||
if: ${{ github.event.pull_request.draft != true }}
|
||||
uses: XRPLF/actions/.github/workflows/check-pr-title.yml@d7c65e49225a38f6d8010eacf017bb5a98d7476c
|
||||
uses: XRPLF/actions/.github/workflows/check-pr-title.yml@cba1f0891650baf1a9c88624dc2d72573be2eb81
|
||||
|
||||
1
.github/workflows/conflicting-pr.yml
vendored
1
.github/workflows/conflicting-pr.yml
vendored
@@ -14,7 +14,6 @@ permissions:
|
||||
|
||||
jobs:
|
||||
main:
|
||||
if: ${{ !contains(github.event.pull_request.labels.*.name, 'IgnoreConflicts') }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check if PRs are dirty
|
||||
|
||||
44
.github/workflows/on-pr.yml
vendored
44
.github/workflows/on-pr.yml
vendored
@@ -1,11 +1,7 @@
|
||||
# This workflow runs workflows to check, build and test the project
|
||||
# on every meaningful change on pull_request.
|
||||
# However, it will not run if the PR is a draft
|
||||
# unless it has the 'DraftRunCI' or 'Full CI build' label.
|
||||
#
|
||||
# By default a PR builds only a minimal matrix.
|
||||
# The full matrix runs once the PR is labeled "Ready to merge" or "Full CI build".
|
||||
# For commits to PRs that target a release branch,
|
||||
# This workflow runs all workflows to check, build and test the project on
|
||||
# various Linux flavors, as well as on MacOS and Windows, on every push to a
|
||||
# user branch. However, it will not run if the pull request is a draft unless it
|
||||
# has the 'DraftRunCI' label. For commits to PRs that target a release branch,
|
||||
# it also uploads the libxrpl recipe to the Conan remote.
|
||||
name: PR
|
||||
|
||||
@@ -19,16 +15,8 @@ on:
|
||||
- reopened
|
||||
- synchronize
|
||||
- ready_for_review
|
||||
# Trigger on label changes so toggling "Ready to merge" or "Full CI build"
|
||||
# switches between the minimal and full matrix without needing a new push.
|
||||
- labeled
|
||||
- unlabeled
|
||||
|
||||
concurrency:
|
||||
# A single per-ref group with cancel-in-progress means any newer run (a push
|
||||
# or a label change) supersedes the in-progress one for that ref. Keeping
|
||||
# exactly one authoritative run per ref ensures a fast do-nothing run can never
|
||||
# mask a real build's checks.
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
@@ -37,18 +25,11 @@ defaults:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
# This job determines whether the rest of the workflow should run at all,
|
||||
# based on the current set of labels: it runs when the PR is not a draft
|
||||
# (which should also cover merge-group) or has the 'DraftRunCI' or
|
||||
# 'Full CI build' label. Whether a build then happens, and whether it is the
|
||||
# minimal or full matrix, is decided further below and in the strategy matrix.
|
||||
# This job determines whether the rest of the workflow should run. It runs
|
||||
# when the PR is not a draft (which should also cover merge-group) or
|
||||
# has the 'DraftRunCI' label.
|
||||
should-run:
|
||||
if: >-
|
||||
${{
|
||||
!github.event.pull_request.draft
|
||||
|| contains(github.event.pull_request.labels.*.name, 'DraftRunCI')
|
||||
|| contains(github.event.pull_request.labels.*.name, 'Full CI build')
|
||||
}}
|
||||
if: ${{ !github.event.pull_request.draft || contains(github.event.pull_request.labels.*.name, 'DraftRunCI') }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
@@ -110,17 +91,15 @@ jobs:
|
||||
# least one of:
|
||||
# * Any of the files checked in the `changes` step were modified
|
||||
# * The PR is NOT a draft and is labeled "Ready to merge"
|
||||
# * The PR is labeled "Full CI build" (draft or not)
|
||||
# * The workflow is running from the merge queue
|
||||
id: go
|
||||
env:
|
||||
FILES: ${{ steps.changes.outputs.any_changed }}
|
||||
DRAFT: ${{ github.event.pull_request.draft }}
|
||||
READY: ${{ contains(github.event.pull_request.labels.*.name, 'Ready to merge') }}
|
||||
FULL: ${{ contains(github.event.pull_request.labels.*.name, 'Full CI build') }}
|
||||
MERGE: ${{ github.event_name == 'merge_group' }}
|
||||
run: |
|
||||
echo "go=${{ (env.DRAFT != 'true' && env.READY == 'true') || env.FULL == 'true' || env.FILES == 'true' || env.MERGE == 'true' }}" >>"${GITHUB_OUTPUT}"
|
||||
echo "go=${{ (env.DRAFT != 'true' && env.READY == 'true') || env.FILES == 'true' || env.MERGE == 'true' }}" >>"${GITHUB_OUTPUT}"
|
||||
cat "${GITHUB_OUTPUT}"
|
||||
outputs:
|
||||
go: ${{ steps.go.outputs.go == 'true' }}
|
||||
@@ -163,10 +142,7 @@ jobs:
|
||||
|
||||
package:
|
||||
needs: [should-run, build-test]
|
||||
# Packaging consumes the debian/rhel release binaries, which are only built
|
||||
# by the full matrix. Skip it for pull requests that ran only the minimal
|
||||
# matrix (i.e. not yet labeled "Ready to merge" or "Full CI build").
|
||||
if: ${{ needs.should-run.outputs.go == 'true' && (github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'Ready to merge') || contains(github.event.pull_request.labels.*.name, 'Full CI build')) }}
|
||||
if: ${{ needs.should-run.outputs.go == 'true' }}
|
||||
uses: ./.github/workflows/reusable-package.yml
|
||||
|
||||
upload-recipe:
|
||||
|
||||
4
.github/workflows/pre-commit.yml
vendored
4
.github/workflows/pre-commit.yml
vendored
@@ -14,7 +14,7 @@ on:
|
||||
jobs:
|
||||
# Call the workflow in the XRPLF/actions repo that runs the pre-commit hooks.
|
||||
run-hooks:
|
||||
uses: XRPLF/actions/.github/workflows/pre-commit.yml@3ba08d6ddf114092891d48491fc2e26c3ba15552
|
||||
uses: XRPLF/actions/.github/workflows/pre-commit.yml@1bde119a1ab71305ba5d3716e7a82cea1c7bdede
|
||||
with:
|
||||
runs_on: ubuntu-latest
|
||||
container: '{ "image": "ghcr.io/xrplf/xrpld/pre-commit:sha-f56b79f" }'
|
||||
container: '{ "image": "ghcr.io/xrplf/ci/tools-rippled-pre-commit:sha-41ec7c1" }'
|
||||
|
||||
4
.github/workflows/publish-docs.yml
vendored
4
.github/workflows/publish-docs.yml
vendored
@@ -41,13 +41,13 @@ env:
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-3122de8
|
||||
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-e29b523
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
|
||||
- name: Prepare runner
|
||||
uses: XRPLF/actions/prepare-runner@e4b6449d55a61c002d7c3fdfa6c20f721ede0606
|
||||
uses: XRPLF/actions/prepare-runner@64ec3cf3b152b4444638f470bbd6df7a7a30c81c
|
||||
with:
|
||||
enable_ccache: false
|
||||
|
||||
|
||||
61
.github/workflows/reusable-build-test-config.yml
vendored
61
.github/workflows/reusable-build-test-config.yml
vendored
@@ -113,7 +113,7 @@ jobs:
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
|
||||
- name: Prepare runner
|
||||
uses: XRPLF/actions/prepare-runner@e4b6449d55a61c002d7c3fdfa6c20f721ede0606
|
||||
uses: XRPLF/actions/prepare-runner@64ec3cf3b152b4444638f470bbd6df7a7a30c81c
|
||||
with:
|
||||
enable_ccache: ${{ inputs.ccache_enabled }}
|
||||
|
||||
@@ -124,7 +124,7 @@ jobs:
|
||||
- name: Check tools
|
||||
env:
|
||||
CHECK_TOOLS_SKIP_CLONE: "1"
|
||||
run: ./bin/check-tools.sh || true
|
||||
run: ./bin/check-tools.sh
|
||||
|
||||
- name: Print build environment
|
||||
uses: XRPLF/actions/print-build-env@59dec886e4afb05a1724443af08baccbc045b574
|
||||
@@ -223,13 +223,11 @@ jobs:
|
||||
BUILD_TYPE: ${{ inputs.build_type }}
|
||||
CMAKE_TARGET: ${{ inputs.cmake_target }}
|
||||
run: |
|
||||
set -o pipefail
|
||||
cmake \
|
||||
--build . \
|
||||
--config "${BUILD_TYPE}" \
|
||||
--parallel "${BUILD_NPROC}" \
|
||||
--target "${CMAKE_TARGET}" \
|
||||
2>&1 | tee "${GITHUB_WORKSPACE}/build.log"
|
||||
--target "${CMAKE_TARGET}"
|
||||
|
||||
- name: Show ccache statistics
|
||||
if: ${{ inputs.ccache_enabled }}
|
||||
@@ -324,46 +322,27 @@ jobs:
|
||||
PRELOAD=""
|
||||
fi
|
||||
|
||||
LD_PRELOAD="$PRELOAD" ./xrpld --unittest --unittest-jobs "${BUILD_NPROC}" 2>&1 | tee "${GITHUB_WORKSPACE}/unittest.log"
|
||||
LD_PRELOAD="$PRELOAD" ./xrpld --unittest --unittest-jobs "${BUILD_NPROC}" 2>&1 | tee unittest.log
|
||||
|
||||
# Smoke-run every benchmark module with a single repetition to confirm the
|
||||
# benchmarks still build and execute. This is a correctness check, not a
|
||||
# performance measurement, so it is skipped for instrumented builds
|
||||
# (sanitizers/coverage/voidstar), where it would be slow and meaningless,
|
||||
# and on Windows, where the `install` target does not build them.
|
||||
- name: Run the benchmarks
|
||||
if: ${{ !inputs.build_only && runner.os != 'Windows' && env.SANITIZERS_ENABLED == 'false' && env.COVERAGE_ENABLED != 'true' && env.VOIDSTAR_ENABLED != 'true' }}
|
||||
working-directory: ${{ env.BUILD_DIR }}
|
||||
- name: Show test failure summary
|
||||
if: ${{ failure() && !inputs.build_only }}
|
||||
env:
|
||||
WORKING_DIR: ${{ runner.os == 'Windows' && format('{0}\{1}', env.BUILD_DIR, inputs.build_type) || env.BUILD_DIR }}
|
||||
run: |
|
||||
rc=0
|
||||
while IFS= read -r bench; do
|
||||
echo "::group::${bench}"
|
||||
"./${bench}" --benchmark_repetitions=1 || rc=1
|
||||
echo "::endgroup::"
|
||||
done < <(find src/benchmarks -type f -perm -u+x -name 'xrpl.bench.*')
|
||||
exit "${rc}"
|
||||
|
||||
- name: Show build/test failure summary
|
||||
if: ${{ failure() }}
|
||||
run: |
|
||||
cd "${GITHUB_WORKSPACE}"
|
||||
|
||||
if [ -f unittest.log ]; then
|
||||
if ! grep -E "failed" unittest.log | grep -vE "^I[0-9]|^[0-9]+> (ERR:|FTL:)"; then
|
||||
echo "unittest.log present but no failure lines found."
|
||||
if [ ! -d "${WORKING_DIR}" ]; then
|
||||
echo "Working directory '${WORKING_DIR}' does not exist."
|
||||
exit 0
|
||||
fi
|
||||
elif [ -f build.log ]; then
|
||||
# GCC/Clang emit "error:" (covers "fatal error:"); MSVC emits
|
||||
# "error C####:", "error LNK####:", and "fatal error LNK####:".
|
||||
# -A6 prints the lines that follow each match (source line, caret,
|
||||
# notes, and the "N errors generated" tally) to capture the whole
|
||||
# diagnostic block.
|
||||
if ! grep -E -A6 "error:|error C[0-9]{4}|error LNK[0-9]{4}|fatal error" build.log; then
|
||||
echo "build.log present but no compile errors found."
|
||||
|
||||
cd "${WORKING_DIR}"
|
||||
|
||||
if [ ! -f unittest.log ]; then
|
||||
echo "unittest.log not found; embedded tests may not have run."
|
||||
exit 0
|
||||
fi
|
||||
else
|
||||
echo "unittest.log/build.log not found; something went wrong."
|
||||
exit 1
|
||||
|
||||
if ! grep -E "failed" unittest.log; then
|
||||
echo "Log present but no failure lines found in unittest.log."
|
||||
fi
|
||||
- name: Debug failure (Linux)
|
||||
if: ${{ failure() && runner.os == 'Linux' && !inputs.build_only }}
|
||||
|
||||
4
.github/workflows/reusable-clang-tidy.yml
vendored
4
.github/workflows/reusable-clang-tidy.yml
vendored
@@ -34,7 +34,7 @@ jobs:
|
||||
needs: [determine-files]
|
||||
if: ${{ needs.determine-files.outputs.cpp_changed_files != '' || needs.determine-files.outputs.need_full_run == 'true' }}
|
||||
runs-on: ["self-hosted", "Linux", "X64", "heavy"]
|
||||
container: "ghcr.io/xrplf/xrpld/nix-debian:sha-3122de8"
|
||||
container: "ghcr.io/xrplf/xrpld/nix-debian:sha-e29b523"
|
||||
permissions:
|
||||
contents: read
|
||||
issues: write
|
||||
@@ -43,7 +43,7 @@ jobs:
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
|
||||
- name: Prepare runner
|
||||
uses: XRPLF/actions/prepare-runner@e4b6449d55a61c002d7c3fdfa6c20f721ede0606
|
||||
uses: XRPLF/actions/prepare-runner@64ec3cf3b152b4444638f470bbd6df7a7a30c81c
|
||||
with:
|
||||
enable_ccache: false
|
||||
|
||||
|
||||
2
.github/workflows/reusable-package.yml
vendored
2
.github/workflows/reusable-package.yml
vendored
@@ -30,7 +30,7 @@ jobs:
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
||||
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
||||
with:
|
||||
python-version: "3.13"
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ jobs:
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
||||
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
||||
with:
|
||||
python-version: "3.13"
|
||||
|
||||
@@ -35,8 +35,5 @@ jobs:
|
||||
id: generate
|
||||
env:
|
||||
GENERATE_CONFIG: ${{ inputs.os != '' && format('--config={0}', inputs.os) || '' }}
|
||||
# Run only the minimal matrix for pull requests that are not yet
|
||||
# labeled "Ready to merge" or "Full CI build". Any other event (merge
|
||||
# queue, push, schedule, manual dispatch) runs the full matrix.
|
||||
GENERATE_MINIMAL: ${{ (github.event_name == 'pull_request' && !contains(github.event.pull_request.labels.*.name, 'Ready to merge') && !contains(github.event.pull_request.labels.*.name, 'Full CI build')) && '--minimal' || '' }}
|
||||
run: ./generate.py ${GENERATE_CONFIG} ${GENERATE_MINIMAL} >>"${GITHUB_OUTPUT}"
|
||||
GENERATE_EVENT: ${{ github.event_name }}
|
||||
run: ./generate.py ${GENERATE_CONFIG} --event="${GENERATE_EVENT}" >>"${GITHUB_OUTPUT}"
|
||||
|
||||
2
.github/workflows/reusable-upload-recipe.yml
vendored
2
.github/workflows/reusable-upload-recipe.yml
vendored
@@ -40,7 +40,7 @@ defaults:
|
||||
jobs:
|
||||
upload:
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-3122de8
|
||||
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-e29b523
|
||||
env:
|
||||
REMOTE_NAME: ${{ inputs.remote_name }}
|
||||
CONAN_LOGIN_USERNAME_XRPLF: ${{ secrets.remote_username }}
|
||||
|
||||
2
.github/workflows/upload-conan-deps.yml
vendored
2
.github/workflows/upload-conan-deps.yml
vendored
@@ -68,7 +68,7 @@ jobs:
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
|
||||
- name: Prepare runner
|
||||
uses: XRPLF/actions/prepare-runner@e4b6449d55a61c002d7c3fdfa6c20f721ede0606
|
||||
uses: XRPLF/actions/prepare-runner@64ec3cf3b152b4444638f470bbd6df7a7a30c81c
|
||||
with:
|
||||
enable_ccache: false
|
||||
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -81,9 +81,6 @@ DerivedData
|
||||
# Python
|
||||
__pycache__
|
||||
|
||||
# Rust build artifacts.
|
||||
target/
|
||||
|
||||
# Direnv's directory
|
||||
/.direnv
|
||||
|
||||
|
||||
@@ -32,11 +32,6 @@ repos:
|
||||
# as standalone translation units, so they have no compile_commands.json
|
||||
# entry to lint (verify_headers checks them transitively).
|
||||
exclude: '^include/xrpl/protocol_autogen|\.ipp$'
|
||||
# run-clang-tidy --fix may edit headers included by files it is not run on,
|
||||
# so pre-commit must not split the files across parallel hook invocations.
|
||||
# The script determines the staged files itself and lets run-clang-tidy
|
||||
# handle parallelism internally.
|
||||
pass_filenames: false
|
||||
- id: fix-include-style
|
||||
name: fix include style
|
||||
entry: ./bin/pre-commit/fix_include_style.py
|
||||
@@ -55,7 +50,7 @@ repos:
|
||||
types_or: [c++, c]
|
||||
|
||||
- repo: https://github.com/pre-commit/mirrors-clang-format
|
||||
rev: f4d7745e17a28aad7eed2f4874ca8d1568c11c4c # frozen: v22.1.8
|
||||
rev: dd18dad857d6133e90bbe478f4f2f22ec0030269 # frozen: v22.1.5
|
||||
hooks:
|
||||
- id: clang-format
|
||||
args: [--style=file]
|
||||
@@ -68,7 +63,7 @@ repos:
|
||||
- id: gersemi
|
||||
|
||||
- repo: https://github.com/rbubley/mirrors-prettier
|
||||
rev: 9337a74165b178ae2c766f60bee7252a0f06f3e8 # frozen: v3.9.5
|
||||
rev: 39e2973981e6d2f9b6c543b0086a2d2393abdc89 # frozen: v3.9.4
|
||||
hooks:
|
||||
- id: prettier
|
||||
args: [--end-of-line=auto]
|
||||
|
||||
@@ -28,9 +28,6 @@ This section contains changes targeting a future version.
|
||||
|
||||
### Additions
|
||||
|
||||
- `account_tx`: Added an optional `delegate` request object to filter delegated transactions. The object requires `delegate_filter`, which must be either `actor` for transactions owned by the requested account but signed by another account, or `authorizer` for transactions signed by the requested account on behalf of another account. The optional `counter_party` account narrows the results to a specific signer/delegate for `actor` or a specific owner/delegator for `authorizer`. Malformed `delegate`, `delegate_filter`, and `counter_party` values return standard invalid field errors, and invalid account IDs return `actMalformed`.
|
||||
When paginating delegate-filtered queries, a marker from a delegate-filtered query includes a `delegate` flag and is only valid for follow-up requests that also supply `delegate` (mixing marker conventions returns `invalidParams`). Because filtering is applied after the ledger scan, a page may contain fewer results than `limit` (possibly zero) while still returning a marker, so callers must continue until no marker is present.
|
||||
|
||||
- `ledger_entry`, `account_objects`: The `Delegate` ledger entry now includes an optional `DestinationNode` field, which stores the index into the authorized account's owner directory. This field is present on entries created after bidirectional directory tracking was introduced and may appear in RPC responses for those entries. ([#6681](https://github.com/XRPLF/rippled/pull/6681))
|
||||
|
||||
- `server_definitions`: Added the following new sections to the response ([#6321](https://github.com/XRPLF/rippled/pull/6321)):
|
||||
|
||||
@@ -131,10 +131,6 @@ else()
|
||||
endif()
|
||||
target_link_libraries(xrpl_libs INTERFACE ${nudb})
|
||||
|
||||
if(benchmark)
|
||||
find_package(benchmark REQUIRED)
|
||||
endif()
|
||||
|
||||
if(coverage)
|
||||
include(XrplCov)
|
||||
endif()
|
||||
@@ -149,7 +145,3 @@ if(tests)
|
||||
include(CTest)
|
||||
add_subdirectory(src/tests/libxrpl)
|
||||
endif()
|
||||
|
||||
if(benchmark)
|
||||
add_subdirectory(src/benchmarks/libxrpl)
|
||||
endif()
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
# By default, anyone can review changes.
|
||||
|
||||
# The CI tooling team should review changes to the CI configuration.
|
||||
/.github/ @XRPLF/ci-tooling
|
||||
@@ -83,11 +83,8 @@ If you create new source files, they must be organized as follows:
|
||||
`src/libxrpl`.
|
||||
- All other non-test files must go under `src/xrpld`.
|
||||
- All test source files must go under `src/test`.
|
||||
- All benchmark source files must go under `src/benchmarks`.
|
||||
|
||||
The source must be formatted according to the style guide below. The easiest
|
||||
way to satisfy this is to install the [`pre-commit`](#pre-commit-hooks) hooks,
|
||||
which format and lint your changes automatically on every commit.
|
||||
The source must be formatted according to the style guide below.
|
||||
|
||||
Header includes must be [levelized](.github/scripts/levelization).
|
||||
|
||||
@@ -215,61 +212,13 @@ This is a non-exhaustive list of recommended style guidelines. These are
|
||||
not always strictly enforced and serve as a way to keep the codebase
|
||||
coherent rather than a set of _thou shalt not_ commandments.
|
||||
|
||||
## Pre-commit hooks
|
||||
|
||||
We use the [`pre-commit`](https://pre-commit.com/) framework to run the
|
||||
formatting and linting tools that keep the codebase consistent. `pre-commit`
|
||||
runs each tool configured in
|
||||
[`.pre-commit-config.yaml`](./.pre-commit-config.yaml) in its own isolated
|
||||
environment, so you don't need to install most of the individual tools
|
||||
yourself. The version of each hook sourced from an external repository
|
||||
(`clang-format`, `gersemi`, etc.) is pinned in that file, so running the hooks
|
||||
locally uses exactly the same versions as CI. A few `local` hooks — most notably
|
||||
`clang-tidy` — run tools from your own environment; see
|
||||
[Installing clang-tidy](#installing-clang-tidy) for how to get those.
|
||||
|
||||
To get started, install `pre-commit` and enable the git hook scripts:
|
||||
|
||||
```bash
|
||||
pip install pre-commit
|
||||
pre-commit install
|
||||
```
|
||||
|
||||
Once installed, the hooks run automatically on your staged files every time you
|
||||
`git commit`. You can also run them on demand:
|
||||
|
||||
```bash
|
||||
# Run all hooks against only the staged files
|
||||
pre-commit run
|
||||
|
||||
# Run all hooks against every file in the repository
|
||||
pre-commit run --all-files
|
||||
|
||||
# Run a single hook (e.g. clang-format) against all files
|
||||
pre-commit run clang-format --all-files
|
||||
```
|
||||
|
||||
The hooks configured in this repository include, among others:
|
||||
|
||||
- `clang-format` — C++/proto formatting (see [Formatting](#formatting))
|
||||
- `clang-tidy` — C++ static analysis (see [Clang-tidy](#clang-tidy)); opt in with `TIDY=1`
|
||||
- `fix-include-style`, `fix-pragma-once`, `check-doxygen-style` — C++ hygiene
|
||||
- `gersemi` — CMake formatting
|
||||
- `prettier`, `black`, `shfmt` — formatting for JavaScript/JSON/Markdown, Python, and shell
|
||||
- `cspell` — spell checking
|
||||
|
||||
The same hooks run in CI on every pull request, so running them locally before
|
||||
you push helps you avoid CI failures.
|
||||
|
||||
## Formatting
|
||||
|
||||
All code must conform to `clang-format`, according to the settings in
|
||||
[`.clang-format`](./.clang-format), unless the result would be unreasonably
|
||||
difficult to read or maintain. The `clang-format` version is pinned in
|
||||
[`.pre-commit-config.yaml`](./.pre-commit-config.yaml), so the
|
||||
[`pre-commit`](#pre-commit-hooks) hook always formats with the same version as
|
||||
CI. To demarcate lines that should be left as-is, surround them with comments
|
||||
like this:
|
||||
All code must conform to `clang-format` version 22,
|
||||
according to the settings in [`.clang-format`](./.clang-format),
|
||||
unless the result would be unreasonably difficult to read or maintain.
|
||||
To demarcate lines that should be left as-is, surround them with comments like
|
||||
this:
|
||||
|
||||
```
|
||||
// clang-format off
|
||||
@@ -277,21 +226,9 @@ like this:
|
||||
// clang-format on
|
||||
```
|
||||
|
||||
The easiest way to format your changes is to let the `pre-commit` hook run
|
||||
automatically on commit, or to run it manually:
|
||||
|
||||
```bash
|
||||
pre-commit run clang-format --all-files
|
||||
```
|
||||
|
||||
You can also format individual files in place by running `clang-format -i <file>...`
|
||||
You can format individual files in place by running `clang-format -i <file>...`
|
||||
from any directory within this project.
|
||||
|
||||
> [!NOTE]
|
||||
> This uses whatever `clang-format` version is installed locally, which may
|
||||
> differ from the pinned version used by `pre-commit` and CI, so the results
|
||||
> can vary.
|
||||
|
||||
There is a Continuous Integration job that runs clang-format on pull requests. If the code doesn't comply, a patch file that corrects auto-fixable formatting issues is generated.
|
||||
|
||||
To download the patch file:
|
||||
@@ -302,6 +239,13 @@ To download the patch file:
|
||||
4. Download the zip file and extract it to your local git repository. Run `git apply [patch-file-name]`.
|
||||
5. Commit and push.
|
||||
|
||||
You can install a pre-commit hook to automatically run `clang-format` before every commit:
|
||||
|
||||
```
|
||||
pip3 install pre-commit
|
||||
pre-commit install
|
||||
```
|
||||
|
||||
## Clang-tidy
|
||||
|
||||
All code must pass `clang-tidy` checks according to the settings in [`.clang-tidy`](./.clang-tidy).
|
||||
@@ -323,7 +267,7 @@ Before running clang-tidy, you must build the project to generate required files
|
||||
|
||||
#### Via pre-commit (recommended)
|
||||
|
||||
If you have already installed the [`pre-commit`](#pre-commit-hooks) hooks, you can run clang-tidy on your staged files using:
|
||||
If you have already installed the pre-commit hooks (see above), you can run clang-tidy on your staged files using:
|
||||
|
||||
```
|
||||
TIDY=1 pre-commit run clang-tidy
|
||||
|
||||
@@ -110,23 +110,6 @@ if [ "${os}" = "linux" ] || [ "${os}" = "macos" ]; then
|
||||
fi
|
||||
fi
|
||||
|
||||
# Rust toolchain. Part of the Nix commonPackages, so available on both Linux
|
||||
# and macOS. The cargo plugins are invoked through cargo (`cargo <sub>`), which
|
||||
# resolves the matching `cargo-<sub>` binary on PATH; `--version` is offline and
|
||||
# does not need a Cargo project.
|
||||
if [ "${os}" = "linux" ] || [ "${os}" = "macos" ]; then
|
||||
echo
|
||||
echo "Rust toolchain:"
|
||||
check cargo
|
||||
check cargo-audit cargo audit --version
|
||||
check cargo-llvm-cov cargo llvm-cov --version
|
||||
check cargo-nextest cargo nextest --version
|
||||
check clippy clippy-driver --version
|
||||
check rust-analyzer
|
||||
check rustc
|
||||
check rustfmt
|
||||
fi
|
||||
|
||||
# GCC is the default compiler on Linux. macOS uses the system Apple Clang
|
||||
# instead, so GCC/g++/gcov are not expected there.
|
||||
if [ "${os}" = "linux" ]; then
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
ARG BASE_IMAGE=ubuntu:26.04
|
||||
|
||||
FROM ${BASE_IMAGE}
|
||||
|
||||
SHELL ["/bin/bash", "-e", "-o", "pipefail", "-c"]
|
||||
ENTRYPOINT ["/bin/bash"]
|
||||
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
RUN <<EOF
|
||||
pkgs=()
|
||||
pkgs+=(curl) # Required to install nix.
|
||||
pkgs+=(doxygen) # Needed for Clio's check-doxygen-docs.sh.
|
||||
pkgs+=(git) # Required for prepare-runner.
|
||||
pkgs+=(libatomic1) # Required to run pre-commit provided `node`.
|
||||
pkgs+=(python3) # Python 3 interpreter.
|
||||
pkgs+=(python3-pip) # Package manager for Python applications.
|
||||
pkgs+=(xz-utils) # Required to install nix
|
||||
|
||||
apt-get update
|
||||
apt-get install -y --no-install-recommends "${pkgs[@]}"
|
||||
apt-get clean
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
EOF
|
||||
|
||||
ARG PRE_COMMIT_VERSION=4.6.0
|
||||
RUN pip install --no-cache --break-system-packages \
|
||||
pre-commit==${PRE_COMMIT_VERSION}
|
||||
|
||||
RUN sh <(curl --proto '=https' --tlsv1.2 -L https://nixos.org/nix/install) --daemon --yes
|
||||
|
||||
# Add nix to PATH and set NIX environment variables,
|
||||
# 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 NIX_PROFILES="/nix/var/nix/profiles/default"
|
||||
ENV NIX_SSL_CERT_FILE="/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt"
|
||||
|
||||
# Verify nix installation
|
||||
RUN nix --version
|
||||
|
||||
ENV RUSTUP_HOME="/opt/rust/rustup"
|
||||
ENV CARGO_HOME="/opt/rust/cargo"
|
||||
ENV PATH="/opt/rust/cargo/bin:${PATH}"
|
||||
|
||||
WORKDIR /tmp
|
||||
COPY rust-toolchain.toml /tmp/rust-toolchain.toml
|
||||
RUN <<EOF
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \
|
||||
| sh -s -- -y --no-modify-path --profile minimal --default-toolchain none
|
||||
rustup toolchain install
|
||||
rustup show
|
||||
cargo fmt --version
|
||||
EOF
|
||||
|
||||
WORKDIR /
|
||||
@@ -1,46 +1,27 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Pre-commit hook that runs clang-tidy on staged files using run-clang-tidy.
|
||||
"""Pre-commit hook that runs clang-tidy on changed files using run-clang-tidy.
|
||||
|
||||
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
|
||||
internally: pre-commit would otherwise split the files across parallel hook
|
||||
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.
|
||||
The set of files is chosen by pre-commit (see .pre-commit-config.yaml), which
|
||||
filters to C/C++ sources and excludes `.ipp` fragments. Headers are linted
|
||||
directly: the `verify_headers` build option (ON by default) compiles every
|
||||
`.h`/`.hpp` on its own, so each header is the main file of its own
|
||||
compile_commands.json entry and run-clang-tidy can analyse it just like a
|
||||
`.cpp`.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
|
||||
CLANG_TIDY_VERSION = 22
|
||||
|
||||
# Extensions run-clang-tidy can analyse: `.cpp` translation units and, thanks to
|
||||
# the `verify_headers` build option, `.h`/`.hpp` headers (each has its own
|
||||
# compile_commands.json entry). `.ipp` fragments have no entry and are skipped.
|
||||
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
|
||||
# emits paths single-quoted and doubles any embedded quote per YAML rules.
|
||||
FILEPATH_RE = re.compile(r"^(\s*(?:-\s+)?FilePath:\s*)'((?:[^']|'')*)'\s*$")
|
||||
|
||||
|
||||
def find_tool(name: str) -> str | None:
|
||||
for candidate in (f"{name}-{CLANG_TIDY_VERSION}", name):
|
||||
def find_run_clang_tidy() -> str | None:
|
||||
for candidate in (f"run-clang-tidy-{CLANG_TIDY_VERSION}", "run-clang-tidy"):
|
||||
if path := shutil.which(candidate):
|
||||
return path
|
||||
return None
|
||||
@@ -54,43 +35,23 @@ def find_build_dir(repo_root: Path) -> Path | None:
|
||||
return None
|
||||
|
||||
|
||||
def staged_files(repo_root: Path) -> list[Path]:
|
||||
"""Return absolute paths of staged, lint-able C/C++ files.
|
||||
|
||||
`--diff-filter=d` excludes deletions so we never lint a removed file.
|
||||
"""
|
||||
output = subprocess.check_output(
|
||||
["git", "diff", "--staged", "--name-only", "--diff-filter=d", "--"]
|
||||
+ [f"*{ext}" for ext in TIDY_EXTENSIONS],
|
||||
text=True,
|
||||
cwd=repo_root,
|
||||
)
|
||||
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():
|
||||
if not os.environ.get("TIDY"):
|
||||
return 0
|
||||
|
||||
files = sys.argv[1:]
|
||||
if not files:
|
||||
return 0
|
||||
|
||||
run_clang_tidy = find_run_clang_tidy()
|
||||
if not run_clang_tidy:
|
||||
print(
|
||||
f"clang-tidy check failed: TIDY is enabled but neither "
|
||||
f"'run-clang-tidy-{CLANG_TIDY_VERSION}' nor 'run-clang-tidy' was found in PATH.",
|
||||
file=sys.stderr,
|
||||
)
|
||||
return 1
|
||||
|
||||
repo_root = Path(
|
||||
subprocess.check_output(
|
||||
["git", "rev-parse", "--show-toplevel"],
|
||||
@@ -98,29 +59,6 @@ def main():
|
||||
text=True,
|
||||
).strip()
|
||||
)
|
||||
|
||||
files = staged_files(repo_root)
|
||||
if not files:
|
||||
return 0
|
||||
|
||||
run_clang_tidy = find_tool("run-clang-tidy")
|
||||
clang_apply_replacements = find_tool("clang-apply-replacements")
|
||||
missing = [
|
||||
name
|
||||
for name, path in (
|
||||
("run-clang-tidy", run_clang_tidy),
|
||||
("clang-apply-replacements", clang_apply_replacements),
|
||||
)
|
||||
if not path
|
||||
]
|
||||
if missing:
|
||||
print(
|
||||
f"clang-tidy check failed: TIDY is enabled but {' and '.join(missing)} "
|
||||
f"was not found in PATH (tried the '-{CLANG_TIDY_VERSION}' suffix too).",
|
||||
file=sys.stderr,
|
||||
)
|
||||
return 1
|
||||
|
||||
build_dir = find_build_dir(repo_root)
|
||||
if not build_dir:
|
||||
print(
|
||||
@@ -130,23 +68,11 @@ def main():
|
||||
)
|
||||
return 1
|
||||
|
||||
with tempfile.TemporaryDirectory() as fixes_dir:
|
||||
result = subprocess.run(
|
||||
[
|
||||
run_clang_tidy,
|
||||
"-quiet",
|
||||
"-p",
|
||||
build_dir,
|
||||
"-export-fixes",
|
||||
fixes_dir,
|
||||
"-allow-no-checks",
|
||||
]
|
||||
[run_clang_tidy, "-quiet", "-p", str(build_dir), "-fix", "-allow-no-checks"]
|
||||
+ files
|
||||
)
|
||||
canonicalize_fix_paths(Path(fixes_dir))
|
||||
applied = subprocess.run([clang_apply_replacements, fixes_dir])
|
||||
|
||||
return result.returncode or applied.returncode
|
||||
return result.returncode
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
include(isolate_headers)
|
||||
|
||||
# Define a benchmark executable for the module `name`.
|
||||
#
|
||||
# This follows the same general pattern as other build helpers in this repo
|
||||
# (e.g. `add_module`): create a target and isolate headers, but here the target
|
||||
# is a benchmark executable and no `add_test(...)` is registered.
|
||||
#
|
||||
# `isolate_headers` exposes only `${CMAKE_CURRENT_SOURCE_DIR}/${name}` on the
|
||||
# include path, rooted at `src`, so a benchmark's own headers are reached as
|
||||
# `<benchmarks/.../${name}/...>` and nothing else in the tree leaks in.
|
||||
function(xrpl_add_benchmark name)
|
||||
set(target ${PROJECT_NAME}.bench.${name})
|
||||
|
||||
file(
|
||||
GLOB_RECURSE sources
|
||||
CONFIGURE_DEPENDS
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/${name}/*.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/${name}.cpp"
|
||||
)
|
||||
add_executable(${target} ${ARGN} ${sources})
|
||||
|
||||
# Benchmark sources register cases through Google Benchmark's static
|
||||
# registrars (anonymous-namespace lambdas). Merging several such files into
|
||||
# one unity translation unit collides those internal-linkage entities, so
|
||||
# keep benchmarks out of the unity build - mirroring xrpl.libpb in
|
||||
# XrplCore.cmake. Each file compiles fine on its own.
|
||||
set_target_properties(${target} PROPERTIES UNITY_BUILD OFF)
|
||||
|
||||
isolate_headers(
|
||||
${target}
|
||||
"${CMAKE_SOURCE_DIR}/src"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/${name}"
|
||||
PRIVATE
|
||||
)
|
||||
endfunction()
|
||||
@@ -133,12 +133,6 @@ target_link_libraries(
|
||||
add_module(xrpl resource)
|
||||
target_link_libraries(xrpl.libxrpl.resource PUBLIC xrpl.libxrpl.protocol)
|
||||
|
||||
add_module(xrpl peerfinder)
|
||||
target_link_libraries(
|
||||
xrpl.libxrpl.peerfinder
|
||||
PUBLIC xrpl.libxrpl.basics xrpl.libxrpl.protocol
|
||||
)
|
||||
|
||||
# Level 08
|
||||
add_module(xrpl net)
|
||||
target_link_libraries(
|
||||
@@ -207,16 +201,6 @@ target_link_libraries(
|
||||
add_module(xrpl tx)
|
||||
target_link_libraries(xrpl.libxrpl.tx PUBLIC xrpl.libxrpl.ledger)
|
||||
|
||||
add_module(xrpl consensus)
|
||||
target_link_libraries(
|
||||
xrpl.libxrpl.consensus
|
||||
PUBLIC
|
||||
xrpl.libxrpl.basics
|
||||
xrpl.libxrpl.json
|
||||
xrpl.libxrpl.protocol
|
||||
xrpl.libxrpl.ledger
|
||||
)
|
||||
|
||||
add_library(xrpl.libxrpl)
|
||||
set_target_properties(xrpl.libxrpl PROPERTIES OUTPUT_NAME xrpl)
|
||||
|
||||
@@ -236,7 +220,6 @@ target_link_modules(
|
||||
beast
|
||||
conditions
|
||||
config
|
||||
consensus
|
||||
core
|
||||
crypto
|
||||
git
|
||||
@@ -244,7 +227,6 @@ target_link_modules(
|
||||
ledger
|
||||
net
|
||||
nodestore
|
||||
peerfinder
|
||||
protocol
|
||||
protocol_autogen
|
||||
rdb
|
||||
|
||||
@@ -30,8 +30,6 @@ if(tests)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
option(benchmark "Build benchmarks" ON)
|
||||
|
||||
# Enabled by default so every header is compiled on its own as the main file of
|
||||
# its own compile_commands.json entry - this is what lets clang-tidy (and clangd
|
||||
# and IDEs) analyse a header's own includes directly. The per-header objects are
|
||||
|
||||
11
conan.lock
11
conan.lock
@@ -10,23 +10,22 @@
|
||||
"rocksdb/10.5.1#4a197eca381a3e5ae8adf8cffa5aacd0%1782392413.075713",
|
||||
"re2/20251105#8579cfd0bda4daf0683f9e3898f964b4%1782392402.431897",
|
||||
"protobuf/6.33.5#ff253ead763bd8d9904a52979cd21e81%1782392410.233933",
|
||||
"openssl/3.6.3#f806de8933e3bf6f01016c6a888cee2e%1783945160.863288",
|
||||
"openssl/3.6.3#1163d4ddc603907084d08a6a0c6e580f%1782307150.583886",
|
||||
"nudb/2.0.9#11149c73f8f2baff9a0198fe25971fc7%1782392402.297166",
|
||||
"mpt-crypto/0.4.0-rc4#ffdba12f2332357f0d8b0ae944cfff52%1784138702.932355",
|
||||
"mpt-crypto/0.4.0-rc2#a580f2f9ad0e795de696aa62d54fb9af%1782425834.488828",
|
||||
"lz4/1.10.0#982d9b673900f665a1da109e09c17cab%1782392402.164188",
|
||||
"libiconv/1.17#9923bc6dc6f106646d6967e0039a5ada%1782392792.775744",
|
||||
"libbacktrace/cci.20210118#a7691bfccd8caaf66309df196790a5a1%1782392402.420732",
|
||||
"libarchive/3.8.7#c446109bd1f1d8ba7936c94189bc50e6%1782392403.066892",
|
||||
"jemalloc/5.3.1#1fc58d55316041f10fbc1e8a2eae632a%1776700028.228",
|
||||
"gtest/1.17.0#5224b3b3ff3b4ce1133cbdd27d53ee7d%1782392402.791979",
|
||||
"grpc/1.81.1#f729f6d75992d20f9c72828e9142d62f%1783945160.094135",
|
||||
"grpc/1.81.1#5217e6ef0544c42b46f4af35d5e7f649%1782307148.845616",
|
||||
"ed25519/2015.03#ae761bdc52730a843f0809bdf6c1b1f6%1782307148.15562",
|
||||
"date/3.0.4#862e11e80030356b53c2c38599ceb32b%1782392402.538492",
|
||||
"c-ares/1.34.6#545240bb1c40e2cacd4362d6b8967650%1782392402.681654",
|
||||
"bzip2/1.0.8#c470882369c2d95c5c77e970c0c7e321%1782392402.296732",
|
||||
"boost/1.91.0#ea540ca2133d831b560036aa24dece3c%1782392419.475605",
|
||||
"benchmark/1.9.5#b885dc73ad67b40a55d45684d1c88ad1%1782736613.864841",
|
||||
"abseil/20250127.0#9ef01c1451a8340f9022e46238c0fbb6%1783945159.651047"
|
||||
"abseil/20250127.0#bb0baf1f362bc4a725a24eddd419b8f7%1782307147.395833"
|
||||
],
|
||||
"build_requires": [
|
||||
"zlib/1.3.2#1cb806da49011867778ffb6ac7190fcb%1782392402.122708",
|
||||
@@ -39,7 +38,7 @@
|
||||
"b2/5.4.2#ffd6084a119587e70f11cd45d1a386e2%1782392402.624226",
|
||||
"automake/1.16.5#b91b7c384c3deaa9d535be02da14d04f%1755524470.56",
|
||||
"autoconf/2.71#51077f068e61700d65bb05541ea1e4b0%1731054366.86",
|
||||
"abseil/20250127.0#9ef01c1451a8340f9022e46238c0fbb6%1783945159.651047"
|
||||
"abseil/20250127.0#bb0baf1f362bc4a725a24eddd419b8f7%1782307147.395833"
|
||||
],
|
||||
"python_requires": [],
|
||||
"overrides": {
|
||||
|
||||
@@ -20,22 +20,6 @@ compiler.libcxx={{ detect_api.detect_libcxx(compiler, version, compiler_exe) }}
|
||||
{% endif %}
|
||||
|
||||
[conf]
|
||||
{# The Boost recipe builds with b2, which doesn't use Conan's toolchain files. #}
|
||||
{# Instead it hand-rolls the compiler for user-config.jam, #}
|
||||
{# and its fallback probes a version-suffixed binary (e.g. `g++-15`) before plain `g++`. #}
|
||||
{# Inside the Nix shell the wrapper only provides `g++`/`gcc` (no `-15` suffix), #}
|
||||
{# so on a host that also has a system `g++-15` the probe escapes Nix #}
|
||||
{# and picks the system compiler, which is mismatched with the Nix libraries #}
|
||||
{# and breaks the build (e.g. Boost.Stacktrace link checks fail). #}
|
||||
{# Pinning the executables here short-circuits that probe so Boost (and the rest of the toolchain) #}
|
||||
{# resolve the same compiler. #}
|
||||
{# Not part of the package ID, so binaries stay shareable. #}
|
||||
{% if os != "Windows" %}
|
||||
{% set cc_exe = {"gcc": "gcc", "clang": "clang", "apple-clang": "clang"}.get(compiler) %}
|
||||
{% set cxx_exe = {"gcc": "g++", "clang": "clang++", "apple-clang": "clang++"}.get(compiler) %}
|
||||
tools.build:compiler_executables={'c':'{{ cc_exe }}','cpp':'{{ cxx_exe }}'}
|
||||
{% endif %}
|
||||
|
||||
{# By default, Conan tries to reuse binaries built with different cppstd versions. #}
|
||||
{# We want to avoid that to improve reproduceability, so we add the cppstd version to the package ID. #}
|
||||
{# More info: https://docs.conan.io/2/reference/extensions/binary_compatibility.html #}
|
||||
|
||||
@@ -15,7 +15,6 @@ class Xrpl(ConanFile):
|
||||
settings = "os", "compiler", "build_type", "arch"
|
||||
options = {
|
||||
"assertions": [True, False],
|
||||
"benchmark": [True, False],
|
||||
"coverage": [True, False],
|
||||
"fPIC": [True, False],
|
||||
"jemalloc": [True, False],
|
||||
@@ -47,7 +46,6 @@ class Xrpl(ConanFile):
|
||||
|
||||
default_options = {
|
||||
"assertions": False,
|
||||
"benchmark": True,
|
||||
"coverage": False,
|
||||
"fPIC": True,
|
||||
"jemalloc": False,
|
||||
@@ -131,14 +129,12 @@ class Xrpl(ConanFile):
|
||||
self.options["boost"].without_cobalt = True
|
||||
|
||||
def requirements(self):
|
||||
if self.options.benchmark:
|
||||
self.requires("benchmark/1.9.5")
|
||||
self.requires("boost/1.91.0", force=True, transitive_headers=True)
|
||||
self.requires("date/3.0.4", transitive_headers=True)
|
||||
if self.options.jemalloc:
|
||||
self.requires("jemalloc/5.3.1")
|
||||
self.requires("lz4/1.10.0", force=True)
|
||||
self.requires("mpt-crypto/0.4.0-rc4", transitive_headers=True)
|
||||
self.requires("mpt-crypto/0.4.0-rc2", transitive_headers=True)
|
||||
self.requires("protobuf/6.33.5", force=True)
|
||||
if self.options.rocksdb:
|
||||
self.requires("rocksdb/10.5.1")
|
||||
@@ -166,7 +162,6 @@ class Xrpl(ConanFile):
|
||||
def generate(self):
|
||||
tc = CMakeToolchain(self)
|
||||
tc.variables["tests"] = self.options.tests
|
||||
tc.variables["benchmark"] = self.options.benchmark
|
||||
tc.variables["assert"] = self.options.assertions
|
||||
tc.variables["coverage"] = self.options.coverage
|
||||
tc.variables["jemalloc"] = self.options.jemalloc
|
||||
|
||||
30
docs/build/nix.md
vendored
30
docs/build/nix.md
vendored
@@ -38,10 +38,8 @@ The first time you run this command, it will take a few minutes to download and
|
||||
|
||||
### Platform notes
|
||||
|
||||
- **Linux**: `nix develop` gives you a shell with all the tooling necessary to develop xrpld
|
||||
and with the same GCC/glibc toolchain that Nix builds for CI.
|
||||
See [Choosing a different compiler](#choosing-a-different-compiler)
|
||||
for the custom-vs-plain toolchain trade-off.
|
||||
- **Linux**: `nix develop` gives you a shell with all the tooling necessary to
|
||||
develop xrpld and with GCC 15.2 (also provided by Nix). There are no caveats.
|
||||
- **macOS**: `nix develop` gives you a full environment too, with Clang (and
|
||||
every other tool, including Conan) provided by Nix. To use your system-wide
|
||||
Apple Clang instead, enter `nix develop .#apple-clang`. Conan has no binary in
|
||||
@@ -65,16 +63,8 @@ The first time you run this command, it will take a few minutes to download and
|
||||
### Choosing a different compiler
|
||||
|
||||
A compiler can be chosen by providing its name with the `.#` prefix, e.g. `nix develop .#clang`.
|
||||
|
||||
On Linux, `.#gcc` and `.#clang` provide the exact toolchain CI uses:
|
||||
the compiler (pinned in [`nix/packages.nix`](../../nix/packages.nix))
|
||||
rebuilt against the pinned custom glibc (see [`nix/compilers.nix`](../../nix/compilers.nix)).
|
||||
Building that toolchain the first time is slow unless it is fetched from a Nix binary cache.
|
||||
If you don't need the custom glibc, the Linux-only `.#gcc-plain` and `.#clang-plain`
|
||||
give you the stock nixpkgs compilers of the same versions.
|
||||
On macOS there is no custom glibc, so `.#gcc` and `.#clang` are already the plain nixpkgs toolchain,
|
||||
and the `-plain` variants do not exist.
|
||||
|
||||
The `.#gcc` and `.#clang` shells provide the same GCC and Clang versions used in CI
|
||||
(pinned in [`nix/packages.nix`](../../nix/packages.nix)).
|
||||
Use `nix flake show` to see all the available development shells.
|
||||
|
||||
Use `nix develop .#no-compiler` to use the compiler from your system.
|
||||
@@ -82,18 +72,14 @@ Use `nix develop .#no-compiler` to use the compiler from your system.
|
||||
### Example Usage
|
||||
|
||||
```bash
|
||||
# Use GCC — same toolchain as CI (custom glibc on Linux)
|
||||
# Use GCC (same version as CI)
|
||||
nix develop .#gcc
|
||||
|
||||
# Use Clang — same toolchain as CI (custom glibc on Linux)
|
||||
# Use Clang (same version as CI)
|
||||
nix develop .#clang
|
||||
|
||||
# Use default for your platform
|
||||
nix develop
|
||||
|
||||
# Stock nixpkgs GCC/Clang, Linux only — skips the custom-glibc build, but does not match CI
|
||||
nix develop .#gcc-plain
|
||||
nix develop .#clang-plain
|
||||
```
|
||||
|
||||
### Using a different shell
|
||||
@@ -124,10 +110,6 @@ nix develop -c "$SHELL"
|
||||
|
||||
Once inside the Nix development shell, follow the standard [build instructions](../../BUILD.md#steps). The Nix shell provides all necessary tools (CMake, Ninja, Conan, etc.).
|
||||
|
||||
Coverage builds (`-Dcoverage=ON`) work in the `gcc` shell (and `gcc-plain` on Linux):
|
||||
each ships a `gcov` matching its compiler, since Nix's cc-wrapper does not expose one.
|
||||
The `clang` shells do not include `llvm-cov`, so use a `gcc` shell for coverage.
|
||||
|
||||
## Automatic Activation with direnv
|
||||
|
||||
[direnv](https://direnv.net/) or [nix-direnv](https://github.com/nix-community/nix-direnv) can automatically activate the Nix development shell when you enter the repository directory.
|
||||
|
||||
23
flake.lock
generated
23
flake.lock
generated
@@ -36,28 +36,7 @@
|
||||
"root": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs",
|
||||
"nixpkgs-custom-glibc": "nixpkgs-custom-glibc",
|
||||
"rust-overlay": "rust-overlay"
|
||||
}
|
||||
},
|
||||
"rust-overlay": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1784611586,
|
||||
"narHash": "sha256-OfqgY+0hp/zseZB7uyH0U8kIDPS4scZZCyAurEplvG0=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "14f58845249f3552a89b07772626b8d3c632fa86",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"type": "github"
|
||||
"nixpkgs-custom-glibc": "nixpkgs-custom-glibc"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
17
flake.nix
17
flake.nix
@@ -10,25 +10,12 @@
|
||||
url = "github:NixOS/nixpkgs/9cd98386a38891d1074fc18036b842dc4416f562";
|
||||
flake = false;
|
||||
};
|
||||
# Pinned Rust toolchains, delivered from the Nix store. Lets the Nix CI
|
||||
# image and dev shell honour the single `rust-toolchain.toml` pin (shared
|
||||
# with the rustup-based non-Nix runners) while staying hermetic — the
|
||||
# toolchain lands in the image's Nix closure and is locked by flake.lock.
|
||||
rust-overlay = {
|
||||
url = "github:oxalica/rust-overlay";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
};
|
||||
|
||||
outputs =
|
||||
{
|
||||
nixpkgs,
|
||||
nixpkgs-custom-glibc,
|
||||
rust-overlay,
|
||||
...
|
||||
}:
|
||||
{ nixpkgs, nixpkgs-custom-glibc, ... }:
|
||||
let
|
||||
forEachSystem = import ./nix/utils.nix { inherit nixpkgs nixpkgs-custom-glibc rust-overlay; };
|
||||
forEachSystem = import ./nix/utils.nix { inherit nixpkgs nixpkgs-custom-glibc; };
|
||||
in
|
||||
{
|
||||
devShells = forEachSystem (import ./nix/devshell.nix);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <filesystem>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
@@ -13,6 +13,6 @@ namespace xrpl {
|
||||
* @throws runtime_error
|
||||
*/
|
||||
void
|
||||
extractTarLz4(boost::filesystem::path const& src, boost::filesystem::path const& dst);
|
||||
extractTarLz4(std::filesystem::path const& src, std::filesystem::path const& dst);
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -1,24 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
|
||||
#include <cstddef>
|
||||
#include <filesystem>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <system_error>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
std::string
|
||||
getFileContents(
|
||||
boost::system::error_code& ec,
|
||||
boost::filesystem::path const& sourcePath,
|
||||
std::error_code& ec,
|
||||
std::filesystem::path const& sourcePath,
|
||||
std::optional<std::size_t> maxSize = std::nullopt);
|
||||
|
||||
void
|
||||
writeFileContents(
|
||||
boost::system::error_code& ec,
|
||||
boost::filesystem::path const& destPath,
|
||||
std::error_code& ec,
|
||||
std::filesystem::path const& destPath,
|
||||
std::string const& contents);
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
|
||||
#include <boost/beast/core/string.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
@@ -84,7 +84,7 @@ private:
|
||||
* @return `true` if the file was opened.
|
||||
*/
|
||||
bool
|
||||
open(boost::filesystem::path const& path);
|
||||
open(std::filesystem::path const& path);
|
||||
|
||||
/**
|
||||
* Close and re-open the system file associated with the log
|
||||
@@ -133,7 +133,7 @@ private:
|
||||
|
||||
private:
|
||||
std::unique_ptr<std::ofstream> stream_;
|
||||
boost::filesystem::path path_;
|
||||
std::filesystem::path path_;
|
||||
};
|
||||
|
||||
std::mutex mutable mutex_;
|
||||
@@ -152,7 +152,7 @@ public:
|
||||
virtual ~Logs() = default;
|
||||
|
||||
bool
|
||||
open(boost::filesystem::path const& pathToLogFile);
|
||||
open(std::filesystem::path const& pathToLogFile);
|
||||
|
||||
beast::Journal::Sink&
|
||||
get(std::string const& name);
|
||||
|
||||
@@ -364,8 +364,6 @@ public:
|
||||
static constexpr internalrep kMaxRep = std::numeric_limits<rep>::max();
|
||||
static_assert(kMaxRep == 9'223'372'036'854'775'807);
|
||||
static_assert(-kMaxRep == std::numeric_limits<rep>::min() + 1);
|
||||
static constexpr internalrep kMaxRepUp = ((kMaxRep / 10) + 1) * 10;
|
||||
static_assert(kMaxRepUp == 9'223'372'036'854'775'810ULL);
|
||||
|
||||
// May need to make unchecked private
|
||||
struct Unchecked
|
||||
@@ -593,13 +591,6 @@ public:
|
||||
std::pair<T, int>
|
||||
normalizeToRange() const;
|
||||
|
||||
// Safely convert rep (int64) mantissa to internalrep (uint64). If the rep
|
||||
// is negative, returns the positive value. This takes a little extra work
|
||||
// because converting std::numeric_limits<std::int64_t>::min() flirts with
|
||||
// UB, and can vary across compilers.
|
||||
static internalrep
|
||||
externalToInternal(rep mantissa);
|
||||
|
||||
private:
|
||||
static thread_local RoundingMode mode;
|
||||
// The available ranges for mantissa
|
||||
@@ -654,6 +645,13 @@ private:
|
||||
// exponent could go out of range, so it will be checked.
|
||||
[[nodiscard]] Number
|
||||
shiftExponent(int exponentDelta) const;
|
||||
|
||||
// Safely convert rep (int64) mantissa to internalrep (uint64). If the rep
|
||||
// is negative, returns the positive value. This takes a little extra work
|
||||
// because converting std::numeric_limits<std::int64_t>::min() flirts with
|
||||
// UB, and can vary across compilers.
|
||||
static internalrep
|
||||
externalToInternal(rep mantissa);
|
||||
};
|
||||
|
||||
constexpr Number::Number(bool negative, internalrep mantissa, int exponent, Unchecked) noexcept
|
||||
|
||||
@@ -3,9 +3,6 @@
|
||||
#include <xrpl/basics/IntrusivePointer.ipp>
|
||||
#include <xrpl/basics/Log.h> // IWYU pragma: keep
|
||||
#include <xrpl/basics/TaggedCache.h>
|
||||
#include <xrpl/basics/scope.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
@@ -604,42 +601,8 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
|
||||
std::vector<key_type> v;
|
||||
|
||||
{
|
||||
// Keep track of how many iterations are needed. Exit the loop if the number of retries gets
|
||||
// absurd. (Note that if this somehow ever happens, one more allocation will be done under
|
||||
// lock, which is undesirable, but really should be almost impossible.)
|
||||
std::size_t allocationIterations = 0;
|
||||
std::unique_lock lock(mutex_);
|
||||
for (auto size = cache_.size(); v.capacity() < size && allocationIterations < 20;
|
||||
size = cache_.size())
|
||||
{
|
||||
ScopeUnlock const unlock(lock);
|
||||
if (allocationIterations > 0)
|
||||
{
|
||||
JLOG(journal_.info())
|
||||
<< "getKeys(): Cache grew beyond allocated capacity after "
|
||||
<< allocationIterations << " prior attempt(s). Have " << v.capacity()
|
||||
<< ", need " << size << ". Retrying allocation";
|
||||
}
|
||||
// Allocate the current size plus a little extra, in case the cache grows while
|
||||
// allocating. Each time another allocation is needed, the extra also gets bigger until
|
||||
// it ultimately doubles the size + 1.
|
||||
constexpr std::size_t baseShift = 5;
|
||||
auto const bufferOffset = std::min(allocationIterations, std::size_t{baseShift});
|
||||
auto const bufferShift = baseShift - bufferOffset;
|
||||
size += (size >> bufferShift) + 1;
|
||||
v.reserve(size);
|
||||
++allocationIterations;
|
||||
}
|
||||
if (v.capacity() < cache_.size())
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
UNREACHABLE("xrpl::TaggedCache::getKeys(): failed to allocate sufficient capacity");
|
||||
std::scoped_lock const lock(mutex_);
|
||||
v.reserve(cache_.size());
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
XRPL_ASSERT(lock.owns_lock(), "xrpl::TaggedCache::getKeys(): owns lock");
|
||||
XRPL_ASSERT(
|
||||
v.capacity() >= cache_.size(), "xrpl::TaggedCache::getKeys(): sufficient capacity");
|
||||
for (auto const& _ : cache_)
|
||||
v.push_back(_.first);
|
||||
}
|
||||
|
||||
@@ -308,9 +308,7 @@ public:
|
||||
XRPL_ASSERT(
|
||||
c.size() * sizeof(typename Container::value_type) == size(),
|
||||
"xrpl::BaseUInt::fromRaw(Container auto) : input size match");
|
||||
std::size_t const canCopy =
|
||||
std::min(size(), c.size() * sizeof(typename Container::value_type));
|
||||
std::memcpy(result.data_.data(), c.data(), canCopy);
|
||||
std::memcpy(result.data_.data(), c.data(), size());
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -324,11 +322,7 @@ public:
|
||||
XRPL_ASSERT(
|
||||
c.size() * sizeof(typename Container::value_type) == size(),
|
||||
"xrpl::BaseUInt::operator=(Container auto) : input size match");
|
||||
std::size_t const canCopy =
|
||||
std::min(size(), c.size() * sizeof(typename Container::value_type));
|
||||
if (canCopy < size())
|
||||
*this = beast::kZero;
|
||||
std::memcpy(data_.data(), c.data(), canCopy);
|
||||
std::memcpy(data_.data(), c.data(), size());
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include <xrpl/beast/container/detail/aged_associative_container.h>
|
||||
#include <xrpl/beast/container/detail/aged_container_iterator.h>
|
||||
#include <xrpl/beast/container/detail/empty_base_optimization.h>
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
|
||||
#include <boost/intrusive/list.hpp>
|
||||
#include <boost/intrusive/unordered_set.hpp>
|
||||
|
||||
@@ -358,13 +358,12 @@ template <class = void>
|
||||
bool
|
||||
tokenInList(boost::string_ref const& value, boost::string_ref const& token)
|
||||
{
|
||||
auto const list = makeList(value);
|
||||
// ListIterator is not default-constructible, so it does not model a std::ranges
|
||||
// sentinel/range; the classic std::any_of (which only needs an input iterator)
|
||||
// is used instead.
|
||||
// NOLINTNEXTLINE(modernize-use-ranges)
|
||||
return std::any_of(
|
||||
list.begin(), list.end(), [&token](auto const& item) { return ciEqual(item, token); });
|
||||
for (auto const& item : makeList(value))
|
||||
{
|
||||
if (ciEqual(item, token))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <bool IsRequest, class Body, class Fields>
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
|
||||
#include <xrpl/beast/unit_test/runner.h>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
|
||||
#include <exception>
|
||||
#include <filesystem>
|
||||
#include <memory>
|
||||
#include <ostream>
|
||||
#include <sstream>
|
||||
@@ -27,7 +27,7 @@ makeReason(String const& reason, char const* file, int line)
|
||||
std::string s(reason);
|
||||
if (!s.empty())
|
||||
s.append(": ");
|
||||
namespace fs = boost::filesystem;
|
||||
namespace fs = std::filesystem;
|
||||
s.append(fs::path{file}.filename().string());
|
||||
s.append("(");
|
||||
s.append(boost::lexical_cast<std::string>(line));
|
||||
|
||||
@@ -1,20 +1,58 @@
|
||||
#pragma once
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include <filesystem>
|
||||
#include <iomanip>
|
||||
#include <random>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <system_error>
|
||||
|
||||
namespace beast {
|
||||
|
||||
/**
|
||||
* Generate a unique, non-existing path under @p base with an optional @p prefix
|
||||
* and a random hex suffix.
|
||||
*
|
||||
* Attempts up to @p maxAttempts paths. Throws `std::runtime_error` if a
|
||||
* unique path cannot be found or if the filesystem returns an error while
|
||||
* checking for existence.
|
||||
*/
|
||||
inline std::filesystem::path
|
||||
uniqueRandomPath(
|
||||
std::filesystem::path const& base,
|
||||
std::size_t maxAttempts = 100,
|
||||
std::string const& prefix = "")
|
||||
{
|
||||
std::random_device rd;
|
||||
for (std::size_t attempt = 0; attempt < maxAttempts; ++attempt)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << prefix << std::hex << std::setfill('0') << std::setw(8) << rd() << std::setw(8)
|
||||
<< rd();
|
||||
auto candidate = base / oss.str();
|
||||
std::error_code ec;
|
||||
bool const exists = std::filesystem::exists(candidate, ec);
|
||||
if (ec)
|
||||
{
|
||||
throw std::runtime_error(
|
||||
"Unable to check path '" + candidate.string() + "': " + ec.message());
|
||||
}
|
||||
if (!exists)
|
||||
return candidate;
|
||||
}
|
||||
throw std::runtime_error("Unable to generate a unique path under '" + base.string() + "'");
|
||||
}
|
||||
|
||||
/**
|
||||
* RAII temporary directory.
|
||||
*
|
||||
* The directory and all its contents are deleted when
|
||||
* the instance of `temp_dir` is destroyed.
|
||||
* the instance of `TempDir` is destroyed.
|
||||
*/
|
||||
class TempDir
|
||||
{
|
||||
boost::filesystem::path path_;
|
||||
std::filesystem::path path_;
|
||||
|
||||
public:
|
||||
#if !GENERATING_DOCS
|
||||
@@ -28,12 +66,8 @@ public:
|
||||
*/
|
||||
TempDir()
|
||||
{
|
||||
auto const dir = boost::filesystem::temp_directory_path();
|
||||
do
|
||||
{
|
||||
path_ = dir / boost::filesystem::unique_path();
|
||||
} while (boost::filesystem::exists(path_));
|
||||
boost::filesystem::create_directory(path_);
|
||||
path_ = uniqueRandomPath(std::filesystem::temp_directory_path());
|
||||
std::filesystem::create_directory(path_);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -42,8 +76,8 @@ public:
|
||||
~TempDir()
|
||||
{
|
||||
// use non-throwing calls in the destructor
|
||||
boost::system::error_code ec;
|
||||
boost::filesystem::remove_all(path_, ec);
|
||||
std::error_code ec;
|
||||
std::filesystem::remove_all(path_, ec);
|
||||
// TODO: warn/notify if ec set ?
|
||||
}
|
||||
|
||||
|
||||
@@ -4,10 +4,9 @@
|
||||
#include <xrpl/core/Job.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <filesystem>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
@@ -44,7 +43,7 @@ public:
|
||||
*/
|
||||
struct Setup
|
||||
{
|
||||
boost::filesystem::path perfLog;
|
||||
std::filesystem::path perfLog;
|
||||
// log_interval is in milliseconds to support faster testing.
|
||||
milliseconds logInterval{seconds(1)};
|
||||
};
|
||||
@@ -149,7 +148,7 @@ public:
|
||||
};
|
||||
|
||||
PerfLog::Setup
|
||||
setupPerfLog(Section const& section, boost::filesystem::path const& configDir);
|
||||
setupPerfLog(Section const& section, std::filesystem::path const& configDir);
|
||||
|
||||
std::unique_ptr<PerfLog>
|
||||
makePerfLog(
|
||||
|
||||
@@ -263,11 +263,10 @@ constructLoanState(
|
||||
Number const& principalOutstanding,
|
||||
Number const& managementFeeOutstanding);
|
||||
|
||||
// Overload of constructLoanState() that reads the three tracked fields
|
||||
// directly from a Loan ledger object, which always holds rounded values,
|
||||
// rather than taking them as separate Number arguments.
|
||||
// Constructs a valid LoanState object from a Loan object, which always has
|
||||
// rounded values
|
||||
LoanState
|
||||
constructLoanState(SLE::const_ref loan);
|
||||
constructRoundedLoanState(SLE::const_ref loan);
|
||||
|
||||
Number
|
||||
computeManagementFee(
|
||||
|
||||
@@ -41,19 +41,6 @@ public:
|
||||
std::unique_ptr<NodeStore::Backend>&& newBackend,
|
||||
std::function<void(std::string const& writableName, std::string const& archiveName)> const&
|
||||
f) = 0;
|
||||
|
||||
/**
|
||||
* Marks an online-delete rotation as in progress (or completed).
|
||||
*
|
||||
* While in flight, a read served by the archive backend is copied
|
||||
* forward into the writable backend even for ordinary
|
||||
* (duplicate == false) fetches: the archive is about to be deleted,
|
||||
* and a node body canonicalized into caches during the rotation
|
||||
* window would otherwise survive only in RAM once the archive is
|
||||
* dropped.
|
||||
*/
|
||||
virtual void
|
||||
setRotationInFlight(bool inFlight) = 0;
|
||||
};
|
||||
|
||||
} // namespace xrpl::NodeStore
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#include <xrpl/nodestore/NodeObject.h>
|
||||
#include <xrpl/nodestore/Scheduler.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
@@ -70,22 +69,11 @@ public:
|
||||
void
|
||||
sweep() override;
|
||||
|
||||
void
|
||||
setRotationInFlight(bool inFlight) override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<Backend> writableBackend_;
|
||||
std::shared_ptr<Backend> archiveBackend_;
|
||||
mutable std::mutex mutex_;
|
||||
|
||||
// True between SHAMapStore starting the cache-freshen phase and the
|
||||
// completion of rotate(). While true, archive hits on ordinary
|
||||
// (duplicate == false) fetches are copied forward into the writable
|
||||
// backend; copyForwardCount_ tallies them per rotation for the
|
||||
// summary line logged at swap.
|
||||
std::atomic<bool> rotationInFlight_{false};
|
||||
std::atomic<std::uint64_t> copyForwardCount_{0};
|
||||
|
||||
std::shared_ptr<NodeObject>
|
||||
fetchNodeObject(uint256 const& hash, std::uint32_t, FetchReport& fetchReport, bool duplicate)
|
||||
override;
|
||||
|
||||
@@ -1,163 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/beast/utility/PropertyStream.h>
|
||||
#include <xrpl/peerfinder/detail/Tuning.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
namespace xrpl::PeerFinder {
|
||||
|
||||
struct PeerLimitConfig
|
||||
{
|
||||
std::optional<std::size_t> maxPeers;
|
||||
std::optional<std::size_t> inPeers;
|
||||
std::optional<std::size_t> outPeers;
|
||||
};
|
||||
|
||||
/**
|
||||
* PeerFinder configuration settings.
|
||||
*/
|
||||
struct Config
|
||||
{
|
||||
/**
|
||||
* The largest number of public peer slots to allow.
|
||||
* This includes both inbound and outbound, but does not include
|
||||
* fixed peers.
|
||||
*/
|
||||
std::size_t maxPeers{Tuning::kDefaultMaxPeers};
|
||||
|
||||
/**
|
||||
* The number of automatic outbound connections to maintain.
|
||||
* Outbound connections are only maintained if autoConnect
|
||||
* is `true`.
|
||||
*/
|
||||
std::size_t outPeers = calcOutPeers(); // Note: relies on `maxPeers` being initialized
|
||||
|
||||
/**
|
||||
* The number of automatic inbound connections to maintain.
|
||||
* Inbound connections are only maintained if wantIncoming
|
||||
* is `true`.
|
||||
*/
|
||||
std::size_t inPeers{0};
|
||||
|
||||
/**
|
||||
* `true` if we want our IP address kept private.
|
||||
*/
|
||||
bool peerPrivate = true;
|
||||
|
||||
/**
|
||||
* `true` if we want to accept incoming connections.
|
||||
*/
|
||||
bool wantIncoming{true};
|
||||
|
||||
/**
|
||||
* `true` if we want to establish connections automatically
|
||||
*/
|
||||
bool autoConnect{true};
|
||||
|
||||
/**
|
||||
* The listening port number.
|
||||
*/
|
||||
std::uint16_t listeningPort{0};
|
||||
|
||||
/**
|
||||
* The set of features we advertise.
|
||||
*/
|
||||
std::string features;
|
||||
|
||||
/**
|
||||
* Limit how many incoming connections we allow per IP
|
||||
*/
|
||||
int ipLimit{0};
|
||||
|
||||
/**
|
||||
* `true` if we want to verify endpoints in TMEndpoints messages
|
||||
*/
|
||||
bool verifyEndpoints = true;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns a suitable value for outPeers according to the rules.
|
||||
*/
|
||||
[[nodiscard]] std::size_t
|
||||
calcOutPeers() const;
|
||||
|
||||
/**
|
||||
* Adjusts the values so they follow the business rules.
|
||||
*/
|
||||
void
|
||||
applyTuning();
|
||||
|
||||
/**
|
||||
* Write the configuration into a property stream
|
||||
*/
|
||||
void
|
||||
onWrite(beast::PropertyStream::Map& map) const;
|
||||
|
||||
/**
|
||||
* Make PeerFinder::Config from peer limit and server mode parameters.
|
||||
*/
|
||||
static Config
|
||||
makeConfig(
|
||||
bool peerPrivate,
|
||||
bool standalone,
|
||||
PeerLimitConfig const& limits,
|
||||
std::uint16_t port,
|
||||
bool validationPublicKey,
|
||||
int ipLimit,
|
||||
bool verifyEndpoints);
|
||||
|
||||
/**
|
||||
* Compares two configurations for equality field by field.
|
||||
*/
|
||||
friend bool
|
||||
operator==(Config const& lhs, Config const& rhs) = default;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Possible results from activating a slot.
|
||||
*/
|
||||
enum class Result { InboundDisabled, DuplicatePeer, IpLimitExceeded, Full, Success };
|
||||
|
||||
/**
|
||||
* @brief Converts a `Result` enum value to its string representation.
|
||||
*
|
||||
* This function provides a human-readable string for a given `Result` enum,
|
||||
* which is useful for logging, debugging, or displaying status messages.
|
||||
*
|
||||
* @param result The `Result` enum value to convert.
|
||||
* @return A `std::string_view` representing the enum value. Returns "unknown"
|
||||
* if the enum value is not explicitly handled.
|
||||
*
|
||||
* @note This function returns a `std::string_view` for performance.
|
||||
* A `std::string` would need to allocate memory on the heap and copy the
|
||||
* string literal into it every time the function is called.
|
||||
*/
|
||||
inline std::string_view
|
||||
to_string(Result result) noexcept
|
||||
{
|
||||
switch (result)
|
||||
{
|
||||
case Result::InboundDisabled:
|
||||
return "inbound disabled";
|
||||
case Result::DuplicatePeer:
|
||||
return "peer already connected";
|
||||
case Result::IpLimitExceeded:
|
||||
return "ip limit exceeded";
|
||||
case Result::Full:
|
||||
return "slots full";
|
||||
case Result::Success:
|
||||
return "success";
|
||||
}
|
||||
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
} // namespace xrpl::PeerFinder
|
||||
@@ -1,179 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/beast/net/IPEndpoint.h>
|
||||
#include <xrpl/beast/utility/PropertyStream.h>
|
||||
#include <xrpl/peerfinder/Config.h>
|
||||
#include <xrpl/peerfinder/Slot.h>
|
||||
#include <xrpl/peerfinder/Types.h>
|
||||
#include <xrpl/protocol/PublicKey.h>
|
||||
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace xrpl::PeerFinder {
|
||||
|
||||
/**
|
||||
* Maintains a set of IP addresses used for getting into the network.
|
||||
*/
|
||||
class Manager : public beast::PropertyStream::Source
|
||||
{
|
||||
protected:
|
||||
Manager() noexcept;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Destroy the object.
|
||||
* Any pending source fetch operations are aborted.
|
||||
* There may be some listener calls made before the
|
||||
* destructor returns.
|
||||
*/
|
||||
~Manager() override = default;
|
||||
|
||||
/**
|
||||
* Set the configuration for the manager.
|
||||
* The new settings will be applied asynchronously.
|
||||
* Thread safety:
|
||||
* Can be called from any threads at any time.
|
||||
*/
|
||||
virtual void
|
||||
setConfig(Config const& config) = 0;
|
||||
|
||||
/**
|
||||
* Transition to the started state, synchronously.
|
||||
*/
|
||||
virtual void
|
||||
start() = 0;
|
||||
|
||||
/**
|
||||
* Transition to the stopped state, synchronously.
|
||||
*/
|
||||
virtual void
|
||||
stop() = 0;
|
||||
|
||||
/**
|
||||
* Returns the configuration for the manager.
|
||||
*/
|
||||
virtual Config
|
||||
config() = 0;
|
||||
|
||||
/**
|
||||
* Add a peer that should always be connected.
|
||||
* This is useful for maintaining a private cluster of peers.
|
||||
* The string is the name as specified in the configuration
|
||||
* file, along with the set of corresponding IP addresses.
|
||||
*/
|
||||
virtual void
|
||||
addFixedPeer(std::string_view name, std::vector<beast::IP::Endpoint> const& addresses) = 0;
|
||||
|
||||
/**
|
||||
* Add a set of strings as fallback IP::Endpoint sources.
|
||||
* @param name A label used for diagnostics.
|
||||
*/
|
||||
virtual void
|
||||
addFallbackStrings(std::string const& name, std::vector<std::string> const& strings) = 0;
|
||||
|
||||
/**
|
||||
* Add a URL as a fallback location to obtain IP::Endpoint sources.
|
||||
* @param name A label used for diagnostics.
|
||||
*/
|
||||
/* VFALCO NOTE Unimplemented
|
||||
virtual void addFallbackURL (std::string const& name,
|
||||
std::string const& url) = 0;
|
||||
*/
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Create a new inbound slot with the specified remote endpoint.
|
||||
* If nullptr is returned, then the slot could not be assigned.
|
||||
* Usually this is because of a detected self-connection.
|
||||
*/
|
||||
virtual std::pair<std::shared_ptr<Slot>, Result>
|
||||
newInboundSlot(
|
||||
beast::IP::Endpoint const& localEndpoint,
|
||||
beast::IP::Endpoint const& remoteEndpoint) = 0;
|
||||
|
||||
/**
|
||||
* Create a new outbound slot with the specified remote endpoint.
|
||||
* If nullptr is returned, then the slot could not be assigned.
|
||||
* Usually this is because of a duplicate connection.
|
||||
*/
|
||||
virtual std::pair<std::shared_ptr<Slot>, Result>
|
||||
newOutboundSlot(beast::IP::Endpoint const& remoteEndpoint) = 0;
|
||||
|
||||
/**
|
||||
* Called when mtENDPOINTS is received.
|
||||
*/
|
||||
virtual void
|
||||
onEndpoints(std::shared_ptr<Slot> const& slot, Endpoints const& endpoints) = 0;
|
||||
|
||||
/**
|
||||
* Called when the slot is closed.
|
||||
* This always happens when the socket is closed, unless the socket
|
||||
* was canceled.
|
||||
*/
|
||||
virtual void
|
||||
onClosed(std::shared_ptr<Slot> const& slot) = 0;
|
||||
|
||||
/**
|
||||
* Called when an outbound connection is deemed to have failed
|
||||
*/
|
||||
virtual void
|
||||
onFailure(std::shared_ptr<Slot> const& slot) = 0;
|
||||
|
||||
/**
|
||||
* Called when we received redirect IPs from a busy peer.
|
||||
*/
|
||||
virtual void
|
||||
onRedirects(
|
||||
boost::asio::ip::tcp::endpoint const& remoteAddress,
|
||||
std::vector<boost::asio::ip::tcp::endpoint> const& eps) = 0;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Called when an outbound connection attempt succeeds.
|
||||
* The local endpoint must be valid. If the caller receives an error
|
||||
* when retrieving the local endpoint from the socket, it should
|
||||
* proceed as if the connection attempt failed by calling on_closed
|
||||
* instead of on_connected.
|
||||
* @return `true` if the connection should be kept
|
||||
*/
|
||||
virtual bool
|
||||
onConnected(std::shared_ptr<Slot> const& slot, beast::IP::Endpoint const& localEndpoint) = 0;
|
||||
|
||||
/**
|
||||
* Request an active slot type.
|
||||
*/
|
||||
virtual Result
|
||||
activate(std::shared_ptr<Slot> const& slot, PublicKey const& key, bool reserved) = 0;
|
||||
|
||||
/**
|
||||
* Returns a set of endpoints suitable for redirection.
|
||||
*/
|
||||
virtual std::vector<Endpoint>
|
||||
redirect(std::shared_ptr<Slot> const& slot) = 0;
|
||||
|
||||
/**
|
||||
* Return a set of addresses we should connect to.
|
||||
*/
|
||||
virtual std::vector<beast::IP::Endpoint>
|
||||
autoconnect() = 0;
|
||||
|
||||
virtual std::vector<std::pair<std::shared_ptr<Slot>, std::vector<Endpoint>>>
|
||||
buildEndpointsForPeers() = 0;
|
||||
|
||||
/**
|
||||
* Perform periodic activity.
|
||||
* This should be called once per second.
|
||||
*/
|
||||
virtual void
|
||||
oncePerSecond() = 0;
|
||||
};
|
||||
|
||||
} // namespace xrpl::PeerFinder
|
||||
@@ -1,46 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/beast/clock/abstract_clock.h>
|
||||
#include <xrpl/beast/net/IPEndpoint.h>
|
||||
#include <xrpl/peerfinder/detail/Tuning.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace xrpl::PeerFinder {
|
||||
|
||||
using clock_type = beast::AbstractClock<std::chrono::steady_clock>;
|
||||
|
||||
/**
|
||||
* Represents a set of addresses.
|
||||
*/
|
||||
using IPAddresses = std::vector<beast::IP::Endpoint>;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Describes a connectable peer address along with some metadata.
|
||||
*/
|
||||
struct Endpoint
|
||||
{
|
||||
Endpoint() = default;
|
||||
|
||||
Endpoint(beast::IP::Endpoint ep, std::uint32_t hops);
|
||||
|
||||
std::uint32_t hops = 0;
|
||||
beast::IP::Endpoint address;
|
||||
};
|
||||
|
||||
inline bool
|
||||
operator<(Endpoint const& lhs, Endpoint const& rhs)
|
||||
{
|
||||
return lhs.address < rhs.address;
|
||||
}
|
||||
|
||||
/**
|
||||
* A set of Endpoint used for connecting.
|
||||
*/
|
||||
using Endpoints = std::vector<Endpoint>;
|
||||
|
||||
} // namespace xrpl::PeerFinder
|
||||
@@ -1,36 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/beast/insight/Collector.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/peerfinder/PeerfinderManager.h>
|
||||
#include <xrpl/peerfinder/Types.h>
|
||||
#include <xrpl/peerfinder/detail/Store.h>
|
||||
|
||||
#include <boost/asio/io_context.hpp>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace xrpl::PeerFinder {
|
||||
|
||||
/**
|
||||
* @brief Create a new Manager.
|
||||
*
|
||||
* @param ioContext The io_context used to schedule asynchronous work.
|
||||
* @param clock The clock used for timekeeping.
|
||||
* @param journal The journal used for logging.
|
||||
* @param store The persistence backend for the bootstrap cache. The caller
|
||||
* retains ownership and must keep it alive (and opened) for the lifetime of
|
||||
* the returned Manager. This lets consumers supply their own Store
|
||||
* implementation (e.g. the SQLite-backed StoreSqdb in xrpld).
|
||||
* @param collector The collector used to report metrics.
|
||||
* @return The newly created Manager.
|
||||
*/
|
||||
std::unique_ptr<Manager>
|
||||
makeManager(
|
||||
boost::asio::io_context& ioContext,
|
||||
clock_type& clock,
|
||||
beast::Journal journal,
|
||||
Store& store,
|
||||
beast::insight::Collector::ptr const& collector);
|
||||
|
||||
} // namespace xrpl::PeerFinder
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <xrpl/protocol/Protocol.h>
|
||||
#include <xrpl/protocol/STXChainBridge.h>
|
||||
#include <xrpl/protocol/UintTypes.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
@@ -422,8 +423,21 @@ struct KeyletDesc
|
||||
bool includeInTests{};
|
||||
};
|
||||
|
||||
// This list should include all of the keylet functions that take a single AccountID parameter.
|
||||
extern std::array<KeyletDesc<AccountID const&>, 6> const kDirectAccountKeylets;
|
||||
// This list should include all of the keylet functions that take a single
|
||||
// AccountID parameter.
|
||||
std::array<KeyletDesc<AccountID const&>, 6> const kDirectAccountKeylets{
|
||||
{{.function = &keylet::account, .expectedLEName = jss::AccountRoot, .includeInTests = false},
|
||||
{.function = &keylet::ownerDir, .expectedLEName = jss::DirectoryNode, .includeInTests = true},
|
||||
{.function = &keylet::signerList, .expectedLEName = jss::SignerList, .includeInTests = true},
|
||||
// It's normally impossible to create an item at nftpage_min, but
|
||||
// test it anyway, since the invariant checks for it.
|
||||
{.function = &keylet::nftokenPageMin,
|
||||
.expectedLEName = jss::NFTokenPage,
|
||||
.includeInTests = true},
|
||||
{.function = &keylet::nftokenPageMax,
|
||||
.expectedLEName = jss::NFTokenPage,
|
||||
.includeInTests = true},
|
||||
{.function = &keylet::did, .expectedLEName = jss::DID, .includeInTests = true}}};
|
||||
|
||||
MPTID
|
||||
makeMptID(std::uint32_t sequence, AccountID const& account);
|
||||
|
||||
@@ -229,6 +229,13 @@ public:
|
||||
[[nodiscard]] AccountID
|
||||
getAccountID(SField const& field) const;
|
||||
|
||||
/**
|
||||
* The account responsible for the authorization: the delegate when
|
||||
* sfDelegate is present, otherwise the account.
|
||||
*/
|
||||
[[nodiscard]] AccountID
|
||||
getInitiator() const;
|
||||
|
||||
[[nodiscard]] Blob
|
||||
getFieldVL(SField const& field) const;
|
||||
[[nodiscard]] STAmount const&
|
||||
|
||||
@@ -142,26 +142,9 @@ public:
|
||||
TxnSql status,
|
||||
std::string const& escapedMetaData) const;
|
||||
|
||||
/**
|
||||
* The IDs of the inner transactions of a Batch.
|
||||
*/
|
||||
[[nodiscard]] std::vector<uint256>
|
||||
[[nodiscard]] std::vector<uint256> const&
|
||||
getBatchTransactionIDs() const;
|
||||
|
||||
/**
|
||||
* The inner transactions of a Batch, built and validated at construction.
|
||||
* Always seated for Batch STTx instances (construction throws if oversized).
|
||||
*/
|
||||
[[nodiscard]] std::vector<std::shared_ptr<STTx const>> const&
|
||||
getBatchTransactions() const;
|
||||
|
||||
/**
|
||||
* The account responsible for the authorization: the delegate when
|
||||
* sfDelegate is present, otherwise the account.
|
||||
*/
|
||||
[[nodiscard]] AccountID
|
||||
getInitiator() const;
|
||||
|
||||
[[nodiscard]] AccountID
|
||||
getFeePayerID() const;
|
||||
|
||||
@@ -183,16 +166,13 @@ private:
|
||||
checkMultiSign(Rules const& rules, STObject const& sigObject) const;
|
||||
|
||||
[[nodiscard]] std::expected<void, std::string>
|
||||
checkBatchSingleSign(STObject const& batchSigner, std::vector<uint256> const& txIds) const;
|
||||
checkBatchSingleSign(STObject const& batchSigner) const;
|
||||
|
||||
[[nodiscard]] std::expected<void, std::string>
|
||||
checkBatchMultiSign(
|
||||
STObject const& batchSigner,
|
||||
Rules const& rules,
|
||||
std::vector<uint256> const& txIds) const;
|
||||
checkBatchMultiSign(STObject const& batchSigner, Rules const& rules) const;
|
||||
|
||||
void
|
||||
buildBatchTxns();
|
||||
buildBatchTxnIds();
|
||||
|
||||
STBase*
|
||||
copy(std::size_t n, void* buf) const override;
|
||||
@@ -200,11 +180,11 @@ private:
|
||||
move(std::size_t n, void* buf) override;
|
||||
|
||||
friend class detail::STVar;
|
||||
std::optional<std::vector<std::shared_ptr<STTx const>>> batchTxns_;
|
||||
std::optional<std::vector<uint256>> batchTxnIds_;
|
||||
};
|
||||
|
||||
bool
|
||||
passesLocalChecks(STTx const& tx, std::string&);
|
||||
passesLocalChecks(STObject const& st, std::string&);
|
||||
|
||||
/**
|
||||
* Sterilize a transaction.
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
// Add new amendments to the top of this list.
|
||||
// Keep it sorted in reverse chronological order.
|
||||
|
||||
XRPL_FIX (Cleanup3_4_0, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(Sponsor, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(BatchV1_1, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(LendingProtocolV1_1, Supported::No, VoteBehavior::DefaultNo)
|
||||
|
||||
@@ -110,7 +110,6 @@ JSS(accounts); // in: LedgerEntry, Subscribe, handlers/Ledger
|
||||
JSS(accounts_proposed); // in: Subscribe, Unsubscribe
|
||||
JSS(action); //
|
||||
JSS(active); // out: OverlayImpl
|
||||
JSS(actor); // in/out: AccountTx
|
||||
JSS(acquiring); // out: LedgerRequest
|
||||
JSS(address); // out: PeerImp
|
||||
JSS(affected); // out: AcceptedLedgerTx
|
||||
@@ -134,7 +133,6 @@ JSS(attestation_reward_account); //
|
||||
JSS(auction_slot); // out: amm_info
|
||||
JSS(authorized); // out: AccountLines
|
||||
JSS(authorize); // out: delegate
|
||||
JSS(authorizer); // in/out: AccountTx
|
||||
JSS(authorized_credentials); // in: ledger_entry DepositPreauth
|
||||
JSS(auth_accounts); // out: amm_info
|
||||
JSS(auth_change); // out: AccountInfo
|
||||
@@ -193,7 +191,6 @@ JSS(converge_time); // out: NetworkOPs
|
||||
JSS(converge_time_s); // out: NetworkOPs
|
||||
JSS(cookie); // out: NetworkOPs
|
||||
JSS(count); // in: AccountTx*, ValidatorList
|
||||
JSS(counter_party); // in/out: AccountTx
|
||||
JSS(counters); // in/out: retrieve counters
|
||||
JSS(credentials); // in: deposit_authorized
|
||||
JSS(credential_type); // in: LedgerEntry DepositPreauth
|
||||
@@ -273,7 +270,6 @@ JSS(freeze); // out: AccountLines
|
||||
JSS(freeze_peer); // out: AccountLines
|
||||
JSS(deep_freeze); // out: AccountLines
|
||||
JSS(deep_freeze_peer); // out: AccountLines
|
||||
JSS(delegate_filter); // in/out: AccountTx
|
||||
JSS(frozen_balances); // out: GatewayBalances
|
||||
JSS(full); // in: LedgerClearer, handlers/Ledger
|
||||
JSS(full_reply); // out: PathFind
|
||||
|
||||
@@ -6,13 +6,12 @@
|
||||
#include <xrpl/core/StartUpType.h>
|
||||
#include <xrpl/rdb/SociDB.h>
|
||||
|
||||
#include <boost/filesystem/path.hpp>
|
||||
|
||||
#include <soci/statement.h>
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <filesystem>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
@@ -80,7 +79,7 @@ public:
|
||||
|
||||
StartUpType startUp = StartUpType::Normal;
|
||||
bool standAlone = false;
|
||||
boost::filesystem::path dataDir;
|
||||
std::filesystem::path dataDir;
|
||||
// Indicates whether or not to return the `globalPragma`
|
||||
// from commonPragma()
|
||||
bool useGlobalPragma = false;
|
||||
@@ -143,7 +142,7 @@ public:
|
||||
|
||||
template <std::size_t N, std::size_t M>
|
||||
DatabaseCon(
|
||||
boost::filesystem::path const& dataDir,
|
||||
std::filesystem::path const& dataDir,
|
||||
std::string const& dbName,
|
||||
std::array<std::string, N> const& pragma,
|
||||
std::array<char const*, M> const& initSQL,
|
||||
@@ -155,7 +154,7 @@ public:
|
||||
// Use this constructor to setup checkpointing
|
||||
template <std::size_t N, std::size_t M>
|
||||
DatabaseCon(
|
||||
boost::filesystem::path const& dataDir,
|
||||
std::filesystem::path const& dataDir,
|
||||
std::string const& dbName,
|
||||
std::array<std::string, N> const& pragma,
|
||||
std::array<char const*, M> const& initSQL,
|
||||
@@ -190,7 +189,7 @@ private:
|
||||
|
||||
template <std::size_t N, std::size_t M>
|
||||
DatabaseCon(
|
||||
boost::filesystem::path const& pPath,
|
||||
std::filesystem::path const& pPath,
|
||||
std::vector<std::string> const* commonPragma,
|
||||
std::array<std::string, N> const& pragma,
|
||||
std::array<char const*, M> const& initSQL,
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
#include <xrpl/protocol/TxMeta.h>
|
||||
#include <xrpl/protocol/TxSearched.h>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/variant.hpp>
|
||||
|
||||
#include <concepts>
|
||||
@@ -46,22 +45,6 @@ struct LedgerRange
|
||||
uint32_t max;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Enumeration of possible delegate types that can occur during filtering in account_tx
|
||||
*/
|
||||
enum class DelegateType {
|
||||
Actor, ///< Another account signed and submitted transactions on behalf of this account (this
|
||||
///< account is the owner/delegator).
|
||||
Authorizer ///< This account signed and submitted transactions on behalf of another account
|
||||
///< (this account is the signer/delegatee).
|
||||
};
|
||||
|
||||
struct DelegateFilter
|
||||
{
|
||||
DelegateType type = DelegateType::Actor;
|
||||
std::optional<AccountID> counterparty;
|
||||
};
|
||||
|
||||
class RelationalDatabase
|
||||
{
|
||||
public:
|
||||
@@ -98,7 +81,6 @@ public:
|
||||
std::optional<AccountTxMarker> marker;
|
||||
std::uint32_t limit = 0;
|
||||
bool bAdmin = false;
|
||||
std::optional<DelegateFilter> delegate;
|
||||
};
|
||||
|
||||
using AccountTx = std::pair<std::shared_ptr<Transaction>, std::shared_ptr<TxMeta>>;
|
||||
@@ -118,7 +100,6 @@ public:
|
||||
bool forward = false;
|
||||
uint32_t limit = 0;
|
||||
std::optional<AccountTxMarker> marker;
|
||||
std::optional<DelegateFilter> delegate;
|
||||
};
|
||||
|
||||
struct AccountTxResult
|
||||
@@ -127,7 +108,6 @@ public:
|
||||
LedgerRange ledgerRange{};
|
||||
uint32_t limit = 0;
|
||||
std::optional<AccountTxMarker> marker;
|
||||
std::optional<DelegateFilter> delegate;
|
||||
};
|
||||
|
||||
virtual ~RelationalDatabase() = default;
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#include <soci/session.h>
|
||||
|
||||
#include <memory>
|
||||
#ifdef __clang__
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated"
|
||||
#endif
|
||||
@@ -120,6 +120,6 @@ makeCheckpointer(std::uintptr_t id, std::weak_ptr<soci::session>, JobQueue&, Ser
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
#ifdef __clang__
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
@@ -4,10 +4,9 @@
|
||||
#include <xrpl/rdb/DatabaseCon.h>
|
||||
#include <xrpl/rdb/SociDB.h>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
struct SavedState
|
||||
|
||||
@@ -71,18 +71,9 @@ public:
|
||||
/**
|
||||
* @brief called for each ledger entry in the current transaction.
|
||||
*
|
||||
* @param isDelete true if the SLE is being deleted.
|
||||
* @param before ledger entry before modification by the transaction. `before` will be null if
|
||||
* the entry is new.
|
||||
* @param after ledger entry after modification by the transaction. Always non-null. When
|
||||
* deleting, `after` may differ from `before`. Whether that is important is up to the
|
||||
* individual invariant check.
|
||||
*
|
||||
* @note `after` IS NEVER NULL. `isDelete` is the only correct way to check for deletions.
|
||||
* Do not make logic or branching decisions on whether on `after` is set, because it will
|
||||
* always be set. Treat a null `after` as a programming error (with XRPL_ASSERT). An
|
||||
* invariant MAY check for null defensively, if it makes more sense, but an assertion is
|
||||
* preferred for new invariants.
|
||||
* @param isDelete true if the SLE is being deleted
|
||||
* @param before ledger entry before modification by the transaction
|
||||
* @param after ledger entry after modification by the transaction
|
||||
*/
|
||||
void
|
||||
visitEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after);
|
||||
@@ -325,26 +316,17 @@ public:
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Invariant: Token holder's trustline/MPT balance cannot be invalid
|
||||
* after Clawback.
|
||||
* @brief Invariant: Token holder's trustline balance cannot be negative after
|
||||
* Clawback.
|
||||
*
|
||||
* We iterate all the trust lines affected by this transaction and ensure
|
||||
* that no more than one trustline is modified, and also holder's balance is
|
||||
* non-negative. When featureMPTokensV2 is enabled, also verify the holder's
|
||||
* raw trustline/MPToken balance decreased by the clawed amount.
|
||||
* non-negative.
|
||||
*/
|
||||
class ValidClawback
|
||||
{
|
||||
struct EntryChange
|
||||
{
|
||||
SLE::const_pointer before;
|
||||
SLE::const_pointer after;
|
||||
};
|
||||
|
||||
std::uint32_t trustlinesChanged_ = 0;
|
||||
std::uint32_t mptokensChanged_ = 0;
|
||||
EntryChange iou_;
|
||||
EntryChange mpt_;
|
||||
|
||||
public:
|
||||
void
|
||||
@@ -458,7 +440,7 @@ using InvariantChecks = std::tuple<
|
||||
ValidLoan,
|
||||
ValidVault,
|
||||
ValidConfidentialMPToken,
|
||||
ValidMPTBalanceChanges,
|
||||
ValidMPTPayment,
|
||||
ValidAmounts,
|
||||
ValidMPTTransfer,
|
||||
ObjectHasPseudoAccount,
|
||||
|
||||
@@ -87,7 +87,7 @@ public:
|
||||
* OutstandingAmount after application equals OutstandingAmount before
|
||||
* application plus the net holder balance delta.
|
||||
*/
|
||||
class ValidMPTBalanceChanges
|
||||
class ValidMPTPayment
|
||||
{
|
||||
enum class Order { Before = 0, After = 1 };
|
||||
struct MPTData
|
||||
|
||||
@@ -17,8 +17,7 @@ class ValidPermissionedDEX
|
||||
bool regularOffers_ = false; // post-fixCleanup3_2_0: excludes deleted offers
|
||||
bool badHybridsOld_ = false; // pre-fixCleanup3_1_3: missing field/domain or size > 1
|
||||
bool badHybrids_ = false; // post-fixCleanup3_1_3: also catches size == 0 (size != 1)
|
||||
hash_set<uint256> domainsOld_; // pre-fixCleanup3_4_0: also flags deleted domains
|
||||
hash_set<uint256> domains_; // post-fixCleanup3_4_0: excludes deleted domains
|
||||
hash_set<uint256> domains_;
|
||||
|
||||
public:
|
||||
void
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
@@ -40,9 +39,6 @@ public:
|
||||
static NotTEC
|
||||
checkSign(PreclaimContext const& ctx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
|
||||
@@ -80,10 +76,6 @@ private:
|
||||
// only be reached through Batch::checkSign.
|
||||
static NotTEC
|
||||
checkBatchSign(PreclaimContext const& ctx);
|
||||
|
||||
// nullopt on overflow or oversized signer arrays.
|
||||
static std::optional<XRPAmount>
|
||||
calculateBaseFeeImpl(ReadView const& view, STTx const& tx);
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
125
nix/ci-env.nix
125
nix/ci-env.nix
@@ -6,18 +6,106 @@
|
||||
let
|
||||
inherit (import ./packages.nix { inherit pkgs; })
|
||||
commonPackages
|
||||
gccVersion
|
||||
gccPackage
|
||||
llvmPackages
|
||||
llvmVersion
|
||||
mkVersionedToolLinks
|
||||
;
|
||||
|
||||
# Custom-glibc toolchain, shared with the Linux dev shell (see compilers.nix).
|
||||
inherit (import ./compilers.nix { inherit pkgs customGlibc; })
|
||||
customGcc
|
||||
customClang
|
||||
customBinutils
|
||||
customGcov
|
||||
;
|
||||
# Underlying compiler toolchains to wrap (versions pinned in packages.nix).
|
||||
customGccPackage = gccPackage;
|
||||
customLlvmPackages = llvmPackages;
|
||||
|
||||
# binutils wrapped to emit binaries that reference the custom glibc
|
||||
# (dynamic linker path, library search path, RPATH).
|
||||
customBinutils = pkgs.wrapBintoolsWith {
|
||||
bintools = pkgs.binutils-unwrapped;
|
||||
libc = customGlibc;
|
||||
};
|
||||
|
||||
# Rebuild gcc (specifically libstdc++ / libgcc_s) against the custom
|
||||
# glibc. The override swaps gcc.cc's bootstrap stdenv for one that uses
|
||||
# the existing gcc binary but links against the custom glibc, so the
|
||||
# resulting compiler ships runtime libraries that only reference symbols
|
||||
# available in that glibc.
|
||||
customGccCc = customGccPackage.cc.override {
|
||||
stdenv = pkgs.stdenvAdapters.overrideCC pkgs.stdenv (
|
||||
pkgs.wrapCCWith {
|
||||
cc = customGccPackage.cc;
|
||||
libc = customGlibc;
|
||||
bintools = customBinutils;
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
# cc-wrapper around the rebuilt compiler, pointing at the custom glibc
|
||||
# headers and libraries. This is what we actually expose to users.
|
||||
customGcc = pkgs.wrapCCWith {
|
||||
cc = customGccCc;
|
||||
libc = customGlibc;
|
||||
bintools = customBinutils;
|
||||
};
|
||||
|
||||
# gcov ships in gcc's `cc` output, but the cc-wrapper doesn't expose it.
|
||||
# Surface the gcov from our rebuilt gcc (linked against the custom glibc, so
|
||||
# it runs under the loader installed in the image) and matching the exact
|
||||
# compiler version, so gcovr can produce coverage reports in the CI env.
|
||||
customGcov = pkgs.runCommand "gcov-custom-for-ci-env" { } ''
|
||||
mkdir -p "$out/bin"
|
||||
ln -s "${customGccCc}/bin/gcov" "$out/bin/gcov"
|
||||
'';
|
||||
|
||||
# stdenv built around the rebuilt gcc / custom glibc. Used to rebuild
|
||||
# compiler-rt below so its sanitizer runtimes see the custom glibc
|
||||
# headers.
|
||||
customStdenv = pkgs.stdenvAdapters.overrideCC pkgs.stdenv customGcc;
|
||||
|
||||
# Rebuild compiler-rt against the custom glibc so the sanitizer runtimes
|
||||
# don't use glibc symbols (or sysconf constants like _SC_SIGSTKSZ) that
|
||||
# only exist in newer glibc versions. scudo is dropped because its CMake
|
||||
# includes CheckAtomic with -nostdinc++ in CMAKE_REQUIRED_FLAGS, which
|
||||
# makes std::atomic unfindable in our stdenv; we don't use scudo (only
|
||||
# asan/ubsan/tsan etc.).
|
||||
customCompilerRt =
|
||||
(customLlvmPackages.compiler-rt.override {
|
||||
stdenv = customStdenv;
|
||||
}).overrideAttrs
|
||||
(old: {
|
||||
postPatch = (old.postPatch or "") + ''
|
||||
substituteInPlace lib/CMakeLists.txt \
|
||||
--replace-quiet 'add_subdirectory(scudo/standalone)' \
|
||||
'# scudo/standalone disabled in xrpld ci-env'
|
||||
'';
|
||||
});
|
||||
|
||||
# cc-wrapper around clang, pointing at the custom glibc headers and
|
||||
# libraries. Reuses the rebuilt gcc for libstdc++ / libgcc_s so that
|
||||
# C++ binaries produced by clang also only reference symbols available
|
||||
# in the custom glibc. compiler-rt is wired into a resource-root so
|
||||
# sanitizer runtimes (libclang_rt.*.a) are found at link time; this
|
||||
# mirrors what nixpkgs does internally when building llvmPackages.clang.
|
||||
customClang = pkgs.wrapCCWith {
|
||||
cc = customLlvmPackages.clang-unwrapped;
|
||||
libc = customGlibc;
|
||||
bintools = customBinutils;
|
||||
gccForLibs = customGccCc;
|
||||
extraPackages = [ customCompilerRt ];
|
||||
extraBuildCommands = ''
|
||||
rsrc="$out/resource-root"
|
||||
mkdir "$rsrc"
|
||||
ln -s "${customLlvmPackages.clang-unwrapped.lib}/lib/clang/${toString llvmVersion}/include" "$rsrc/include"
|
||||
ln -s "${customCompilerRt.out}/lib" "$rsrc/lib"
|
||||
ln -s "${customCompilerRt.out}/share" "$rsrc/share" || true
|
||||
echo "-resource-dir=$rsrc" >> $out/nix-support/cc-cflags
|
||||
# compiler-rt ships the sanitizer/profile/xray interface headers (e.g.
|
||||
# <sanitizer/lsan_interface.h>) in its `dev` output. In a normal Nix
|
||||
# build these reach the include path because compiler-rt is propagated
|
||||
# via depsTargetTargetPropagated and stdenv's setup hooks add its
|
||||
# dev/include. The CI image runs clang outside a Nix stdenv (binaries
|
||||
# on PATH, no setup hooks), so that never happens; add the headers
|
||||
# explicitly. gcc ships its own copy, which is why this is clang-only.
|
||||
echo "-isystem ${customCompilerRt.dev}/include" >> $out/nix-support/cc-cflags
|
||||
'';
|
||||
};
|
||||
|
||||
# Strip the generic cc/c++/cpp symlinks from the clang wrapper so it can
|
||||
# coexist with the gcc wrapper in buildEnv. gcc remains the default
|
||||
@@ -39,25 +127,6 @@ in
|
||||
customGcov
|
||||
customClangForCiEnv
|
||||
customBinutils
|
||||
(mkVersionedToolLinks {
|
||||
name = "gcc";
|
||||
package = customGcc;
|
||||
version = gccVersion;
|
||||
tools = [
|
||||
"gcc"
|
||||
"g++"
|
||||
"cpp"
|
||||
];
|
||||
})
|
||||
(mkVersionedToolLinks {
|
||||
name = "clang";
|
||||
package = customClang;
|
||||
version = llvmVersion;
|
||||
tools = [
|
||||
"clang"
|
||||
"clang++"
|
||||
];
|
||||
})
|
||||
# CA certificate bundle so HTTPS clients (git, curl, conan) can verify
|
||||
# TLS connections without ca-certificates being installed in the system.
|
||||
pkgs.cacert
|
||||
|
||||
@@ -1,117 +0,0 @@
|
||||
# Custom-glibc compiler toolchain shared by the CI environment (ci-env.nix) and
|
||||
# the Linux dev shell (devshell.nix): gcc / clang / binutils rebuilt to target
|
||||
# the pinned custom glibc. Linux only — the pinned glibc snapshot does not build
|
||||
# on darwin, so callers must not evaluate this on macOS.
|
||||
{
|
||||
pkgs,
|
||||
customGlibc,
|
||||
}:
|
||||
let
|
||||
inherit (import ./packages.nix { inherit pkgs; })
|
||||
gccPackage
|
||||
llvmPackages
|
||||
llvmVersion
|
||||
mkGcov
|
||||
;
|
||||
|
||||
# binutils wrapped to emit binaries that reference the custom glibc
|
||||
# (dynamic linker path, library search path, RPATH).
|
||||
customBinutils = pkgs.wrapBintoolsWith {
|
||||
bintools = pkgs.binutils-unwrapped;
|
||||
libc = customGlibc;
|
||||
};
|
||||
|
||||
# Rebuild gcc (specifically libstdc++ / libgcc_s) against the custom
|
||||
# glibc. The override swaps gcc.cc's bootstrap stdenv for one that uses
|
||||
# the existing gcc binary but links against the custom glibc, so the
|
||||
# resulting compiler ships runtime libraries that only reference symbols
|
||||
# available in that glibc.
|
||||
customGccCc = gccPackage.cc.override {
|
||||
stdenv = pkgs.stdenvAdapters.overrideCC pkgs.stdenv (
|
||||
pkgs.wrapCCWith {
|
||||
cc = gccPackage.cc;
|
||||
libc = customGlibc;
|
||||
bintools = customBinutils;
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
# cc-wrapper around the rebuilt compiler, pointing at the custom glibc
|
||||
# headers and libraries. This is what we actually expose to users.
|
||||
customGcc = pkgs.wrapCCWith {
|
||||
cc = customGccCc;
|
||||
libc = customGlibc;
|
||||
bintools = customBinutils;
|
||||
};
|
||||
|
||||
# gcov matching the rebuilt gcc (linked against the custom glibc), so gcovr
|
||||
# can produce coverage reports both in CI and in the dev shell.
|
||||
customGcov = mkGcov {
|
||||
name = "custom";
|
||||
cc = customGccCc;
|
||||
};
|
||||
|
||||
# stdenv built around the rebuilt gcc / custom glibc. Exported as the dev
|
||||
# shell's gcc stdenv, and used below to rebuild compiler-rt so its sanitizer
|
||||
# runtimes see the custom glibc headers.
|
||||
customStdenv = pkgs.stdenvAdapters.overrideCC pkgs.stdenv customGcc;
|
||||
|
||||
# Rebuild compiler-rt against the custom glibc so the sanitizer runtimes
|
||||
# don't use glibc symbols (or sysconf constants like _SC_SIGSTKSZ) that
|
||||
# only exist in newer glibc versions. scudo is dropped because its CMake
|
||||
# includes CheckAtomic with -nostdinc++ in CMAKE_REQUIRED_FLAGS, which
|
||||
# makes std::atomic unfindable in our stdenv; we don't use scudo (only
|
||||
# asan/ubsan/tsan etc.).
|
||||
customCompilerRt =
|
||||
(llvmPackages.compiler-rt.override {
|
||||
stdenv = customStdenv;
|
||||
}).overrideAttrs
|
||||
(old: {
|
||||
postPatch = (old.postPatch or "") + ''
|
||||
substituteInPlace lib/CMakeLists.txt \
|
||||
--replace-quiet 'add_subdirectory(scudo/standalone)' \
|
||||
'# scudo/standalone disabled in xrpld ci-env'
|
||||
'';
|
||||
});
|
||||
|
||||
# cc-wrapper around clang, pointing at the custom glibc headers and
|
||||
# libraries. Reuses the rebuilt gcc for libstdc++ / libgcc_s so that
|
||||
# C++ binaries produced by clang also only reference symbols available
|
||||
# in the custom glibc. compiler-rt is wired into a resource-root so
|
||||
# sanitizer runtimes (libclang_rt.*.a) are found at link time; this
|
||||
# mirrors what nixpkgs does internally when building llvmPackages.clang.
|
||||
customClang = pkgs.wrapCCWith {
|
||||
cc = llvmPackages.clang-unwrapped;
|
||||
libc = customGlibc;
|
||||
bintools = customBinutils;
|
||||
gccForLibs = customGccCc;
|
||||
extraPackages = [ customCompilerRt ];
|
||||
extraBuildCommands = ''
|
||||
rsrc="$out/resource-root"
|
||||
mkdir "$rsrc"
|
||||
ln -s "${llvmPackages.clang-unwrapped.lib}/lib/clang/${toString llvmVersion}/include" "$rsrc/include"
|
||||
ln -s "${customCompilerRt.out}/lib" "$rsrc/lib"
|
||||
ln -s "${customCompilerRt.out}/share" "$rsrc/share" || true
|
||||
echo "-resource-dir=$rsrc" >> $out/nix-support/cc-cflags
|
||||
# compiler-rt ships the sanitizer/profile/xray interface headers (e.g.
|
||||
# <sanitizer/lsan_interface.h>) in its `dev` output. In a normal Nix
|
||||
# build these reach the include path because compiler-rt is propagated
|
||||
# via depsTargetTargetPropagated and stdenv's setup hooks add its
|
||||
# dev/include. The CI image runs clang outside a Nix stdenv (binaries
|
||||
# on PATH, no setup hooks), so that never happens; add the headers
|
||||
# explicitly. gcc ships its own copy, which is why this is clang-only.
|
||||
echo "-isystem ${customCompilerRt.dev}/include" >> $out/nix-support/cc-cflags
|
||||
'';
|
||||
};
|
||||
in
|
||||
{
|
||||
inherit
|
||||
customGcc
|
||||
customClang
|
||||
customBinutils
|
||||
customStdenv
|
||||
customGcov
|
||||
;
|
||||
|
||||
customClangStdenv = pkgs.stdenvAdapters.overrideCC pkgs.stdenv customClang;
|
||||
}
|
||||
@@ -1,64 +1,23 @@
|
||||
{ pkgs, customGlibc, ... }:
|
||||
{ pkgs, ... }:
|
||||
let
|
||||
inherit (import ./packages.nix { inherit pkgs; })
|
||||
commonPackages
|
||||
gccPackage
|
||||
gccVersion
|
||||
llvmVersion
|
||||
llvmPackages
|
||||
mkVersionedToolLinks
|
||||
mkGcov
|
||||
;
|
||||
|
||||
# Plain nixpkgs stdenvs — no custom glibc.
|
||||
plainGccStdenv = pkgs."gcc${toString gccVersion}Stdenv";
|
||||
plainClangStdenv = llvmPackages.stdenv;
|
||||
|
||||
# Custom-glibc stdenvs, matching the CI environment (see compilers.nix). The
|
||||
# pinned glibc snapshot only builds on Linux, so on darwin these fall back to
|
||||
# the plain stdenvs; the `if isLinux` guard keeps `customGlibc` from being
|
||||
# forced (and erroring) on macOS.
|
||||
customCompilers = import ./compilers.nix { inherit pkgs customGlibc; };
|
||||
customGccStdenv = if pkgs.stdenv.isLinux then customCompilers.customStdenv else plainGccStdenv;
|
||||
customClangStdenv =
|
||||
if pkgs.stdenv.isLinux then customCompilers.customClangStdenv else plainClangStdenv;
|
||||
|
||||
# gcov matching each gcc shell, so `-Dcoverage=ON` builds work in the shell.
|
||||
plainGcov = mkGcov {
|
||||
name = "plain";
|
||||
cc = gccPackage.cc;
|
||||
};
|
||||
customGccGcov = if pkgs.stdenv.isLinux then customCompilers.customGcov else plainGcov;
|
||||
|
||||
# Shown when entering a *-plain shell. These exist only on Linux (see below),
|
||||
# where the stock toolchain diverges from CI.
|
||||
plainWarningHook = ''
|
||||
echo "⚠️ WARNING: this is the stock nixpkgs toolchain and does not match CI's glibc. Prefer 'nix develop .#gcc' / '.#clang' unless you need to skip the custom-glibc build."
|
||||
'';
|
||||
|
||||
# Tools to expose under version-suffixed names (see mkVersionedToolLinks).
|
||||
gccVersionedTools = [
|
||||
"gcc"
|
||||
"g++"
|
||||
"cpp"
|
||||
];
|
||||
clangVersionedTools = [
|
||||
"clang"
|
||||
"clang++"
|
||||
];
|
||||
# Plain nixpkgs stdenvs — no custom glibc, unlike ci-env.nix.
|
||||
gccStdenv = pkgs."gcc${toString gccVersion}Stdenv";
|
||||
clangStdenv = llvmPackages.stdenv;
|
||||
|
||||
# compilerName is the command used to print the version, or null for none.
|
||||
makeShell =
|
||||
{
|
||||
stdenv,
|
||||
compilerName,
|
||||
version ? null,
|
||||
versionedTools ? [ ],
|
||||
extraPackages ? [ ],
|
||||
warningHook ? "",
|
||||
}:
|
||||
let
|
||||
compilerVersionHook =
|
||||
compilerVersion =
|
||||
if compilerName == null then
|
||||
''echo "No compiler specified - using system compiler"''
|
||||
else
|
||||
@@ -66,19 +25,12 @@ let
|
||||
echo "Compiler: "
|
||||
${compilerName} --version
|
||||
'';
|
||||
versionedLinks = pkgs.lib.optional (version != null) (mkVersionedToolLinks {
|
||||
name = compilerName;
|
||||
package = stdenv.cc;
|
||||
inherit version;
|
||||
tools = versionedTools;
|
||||
});
|
||||
in
|
||||
(pkgs.mkShell.override { inherit stdenv; }) {
|
||||
packages = commonPackages ++ versionedLinks ++ extraPackages;
|
||||
packages = commonPackages;
|
||||
shellHook = ''
|
||||
echo "Welcome to xrpld development shell";
|
||||
${compilerVersionHook}
|
||||
${warningHook}
|
||||
${compilerVersion}
|
||||
'';
|
||||
};
|
||||
in
|
||||
@@ -86,21 +38,14 @@ rec {
|
||||
# macOS: Nix Clang. Linux: Nix GCC.
|
||||
default = if pkgs.stdenv.isDarwin then clang else gcc;
|
||||
|
||||
# gcc/clang use the custom-glibc toolchain, matching CI. On darwin there is no
|
||||
# custom glibc, so they fall back to the plain nixpkgs toolchain.
|
||||
gcc = makeShell {
|
||||
stdenv = customGccStdenv;
|
||||
stdenv = gccStdenv;
|
||||
compilerName = "gcc";
|
||||
version = gccVersion;
|
||||
versionedTools = gccVersionedTools;
|
||||
extraPackages = [ customGccGcov ];
|
||||
};
|
||||
|
||||
clang = makeShell {
|
||||
stdenv = customClangStdenv;
|
||||
stdenv = clangStdenv;
|
||||
compilerName = "clang";
|
||||
version = llvmVersion;
|
||||
versionedTools = clangVersionedTools;
|
||||
};
|
||||
|
||||
# Nix provides no compiler; use the one from your system (e.g. Apple Clang).
|
||||
@@ -110,24 +55,3 @@ rec {
|
||||
};
|
||||
apple-clang = no-compiler;
|
||||
}
|
||||
# The *-plain shells (stock nixpkgs toolchain) exist only on Linux: on darwin
|
||||
# gcc/clang are already plain, so these would be redundant and are omitted, which
|
||||
# makes `nix develop .#gcc-plain` fail there rather than silently aliasing gcc.
|
||||
// pkgs.lib.optionalAttrs pkgs.stdenv.isLinux {
|
||||
gcc-plain = makeShell {
|
||||
stdenv = plainGccStdenv;
|
||||
compilerName = "gcc";
|
||||
version = gccVersion;
|
||||
versionedTools = gccVersionedTools;
|
||||
extraPackages = [ plainGcov ];
|
||||
warningHook = plainWarningHook;
|
||||
};
|
||||
|
||||
clang-plain = makeShell {
|
||||
stdenv = plainClangStdenv;
|
||||
compilerName = "clang";
|
||||
version = llvmVersion;
|
||||
versionedTools = clangVersionedTools;
|
||||
warningHook = plainWarningHook;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -8,12 +8,10 @@ RUN mkdir -p ~/.config/nix && \
|
||||
|
||||
# Copy our source and setup our working dir.
|
||||
COPY nix/ci-env.nix /tmp/build/nix/ci-env.nix
|
||||
COPY nix/compilers.nix /tmp/build/nix/compilers.nix
|
||||
COPY nix/packages.nix /tmp/build/nix/packages.nix
|
||||
COPY nix/utils.nix /tmp/build/nix/utils.nix
|
||||
COPY flake.nix /tmp/build/
|
||||
COPY flake.lock /tmp/build/
|
||||
COPY rust-toolchain.toml /tmp/build/
|
||||
WORKDIR /tmp/build
|
||||
|
||||
FROM builder-source AS builder
|
||||
@@ -77,13 +75,9 @@ COPY bin/check-tools.sh /tmp/check-tools.sh
|
||||
RUN /tmp/check-tools.sh
|
||||
|
||||
# Sanity-check that the g++/clang++ are able to build binaries, including sanitizer-instrumented ones.
|
||||
COPY nix/docker/test_files/cpp/ /tmp/test_files/cpp/
|
||||
RUN /tmp/test_files/cpp/compile-sources.sh /tmp/test_files/cpp/sources /tmp/cpp-bins
|
||||
|
||||
# Sanity-check that rustc is able to build binaries, including ones that rely on
|
||||
# the runtime overflow check.
|
||||
COPY nix/docker/test_files/rust/ /tmp/test_files/rust/
|
||||
RUN /tmp/test_files/rust/compile-sources.sh /tmp/test_files/rust/sources /tmp/rust-bins
|
||||
COPY nix/docker/test_files/cpp_sources/ /tmp/cpp_sources/
|
||||
COPY nix/docker/test_files/compile-cpp-sources.sh /tmp/compile-cpp-sources.sh
|
||||
RUN /tmp/compile-cpp-sources.sh /tmp/cpp_sources /tmp/bins
|
||||
|
||||
# Tester: start from a clean BASE_IMAGE, install sanitizer runtime libraries,
|
||||
# and run the compiled test binaries to verify they execute correctly.
|
||||
@@ -100,18 +94,15 @@ SHELL ["/bin/bash", "-e", "-o", "pipefail", "-c"]
|
||||
|
||||
# Sanity-check that the built binaries run correctly in the vanilla base image, with the necessary sanitizer runtime libraries installed.
|
||||
COPY bin/install-sanitizer-libs.sh /tmp/install-sanitizer-libs.sh
|
||||
COPY nix/docker/test_files/cpp/run-binaries.sh /tmp/test_files/cpp/run-binaries.sh
|
||||
COPY nix/docker/test_files/rust/run-binaries.sh /tmp/test_files/rust/run-binaries.sh
|
||||
COPY --from=final /tmp/cpp-bins /tmp/cpp-bins
|
||||
COPY --from=final /tmp/rust-bins /tmp/rust-bins
|
||||
COPY nix/docker/test_files/run-test-binaries.sh /tmp/run-test-binaries.sh
|
||||
COPY --from=final /tmp/bins /tmp/bins
|
||||
|
||||
RUN <<EOF
|
||||
if echo "${BASE_IMAGE}" | grep -qiE 'nixos'; then
|
||||
echo "Skipping runnning binaries on NixOS."
|
||||
else
|
||||
/tmp/install-sanitizer-libs.sh
|
||||
/tmp/test_files/cpp/run-binaries.sh /tmp/cpp-bins
|
||||
/tmp/test_files/rust/run-binaries.sh /tmp/rust-bins
|
||||
/tmp/run-test-binaries.sh /tmp/bins
|
||||
fi
|
||||
touch /tmp/tests-passed
|
||||
EOF
|
||||
|
||||
@@ -42,14 +42,9 @@ work without `ca-certificates` being installed in the base image.
|
||||
- installs the dynamic linker if the base image lacks one (see
|
||||
[How libc is handled](#how-libc-is-handled)),
|
||||
- runs [`bin/check-tools.sh`](../../bin/check-tools.sh) to verify every
|
||||
expected tool is present and runnable.
|
||||
expected tool is present and runnable, and
|
||||
- compiles the C++ test programs in
|
||||
[`test_files/cpp/sources/`](./test_files/cpp/sources) with both `g++` and
|
||||
`clang++`, and sanitizers, and
|
||||
- compiles the Rust test programs in
|
||||
[`test_files/rust/sources/`](./test_files/rust/sources) with `rustc`, and
|
||||
builds the [`test_files/rust/proc_macro/`](./test_files/rust/proc_macro)
|
||||
workspace with `cargo` to exercise proc-macro dylib loading.
|
||||
[`test_files/`](./test_files) with both `g++` and `clang++`, and sanitizers.
|
||||
3. **`tester`** — Start again from a clean `BASE_IMAGE` (no Nix toolchain),
|
||||
install only the sanitizer runtime libraries
|
||||
([`install-sanitizer-libs.sh`](./install-sanitizer-libs.sh)), and run the
|
||||
@@ -78,23 +73,18 @@ toolchain being present at runtime. Two pieces make that work:
|
||||
[`loader-path.sh`](./loader-path.sh) reports the expected loader path for the
|
||||
current architecture, so we can patch the binaries to use the correct loader.
|
||||
|
||||
The build then verifies all of this end to end, and the C++ and Rust programs
|
||||
go through the same pipeline: each is compiled in `final`, has its `PT_INTERP`
|
||||
patched to the target loader, and is then run in the clean `tester` stage to
|
||||
confirm it emits the expected diagnostic on a stock base image. The C++ programs
|
||||
are in `test_files/cpp/sources/` (a regular binary plus ASan/TSan/UBSan
|
||||
variants); the Rust programs are in `test_files/rust/sources/` (a hello binary
|
||||
plus panic and overflow-check variants), plus the `test_files/rust/proc_macro/`
|
||||
workspace — a crate whose compilation additionally loads a proc-macro dylib, and
|
||||
whose resulting binary is patched and run like the others.
|
||||
The build then verifies all of this end to end: the test programs in
|
||||
`test_files/` (a regular binary plus ASan/TSan/UBSan variants) are compiled in
|
||||
`final`, their `PT_INTERP` is patched to the target loader, and they are run in
|
||||
the clean `tester` stage to confirm each emits the expected sanitizer
|
||||
diagnostic on a stock base image.
|
||||
|
||||
## Files
|
||||
|
||||
| File | Purpose |
|
||||
| ----------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
|
||||
| ----------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
|
||||
| [`./Dockerfile`](./Dockerfile) | Multi-stage build described above. |
|
||||
| [`./loader-path.sh`](./loader-path.sh) | Print the dynamic-linker (`PT_INTERP`) path for the current architecture. |
|
||||
| [`./test_files/cpp/`](./test_files/cpp) | C++ sanitizer smoke test: sources + compile/run scripts. |
|
||||
| [`./test_files/rust/`](./test_files/rust) | Rust smoke test: rustc sources + a cargo proc-macro workspace + compile/run scripts. |
|
||||
| [`./test_files/`](./test_files) | C++ sources and scripts to compile and run the sanitizer smoke tests. |
|
||||
| [`/bin/check-tools.sh`](../../bin/check-tools.sh) | Verify every expected tools are present and runnable. |
|
||||
| [`/bin/install-sanitizer-libs.sh`](../../bin/install-sanitizer-libs.sh) | Install `libasan`/`libtsan`/`libubsan` runtimes on the supported base images. |
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
#!/bin/bash
|
||||
# Compile all Rust test binaries during the Docker image build.
|
||||
# Each binary has the target system's ELF PT_INTERP (dynamic-linker path)
|
||||
# baked in so it can run on the (potentially minimal) final BASE_IMAGE.
|
||||
|
||||
set -eo pipefail
|
||||
|
||||
src_dir="${1:?usage: $0 <src_dir> <dst_dir>}"
|
||||
dst_dir="${2:?usage: $0 <src_dir> <dst_dir>}"
|
||||
|
||||
loader="$(/tmp/loader-path.sh)"
|
||||
|
||||
mkdir -p "${dst_dir}"
|
||||
|
||||
function compile() {
|
||||
local name="${1}"
|
||||
local extra_flags="${2:-}"
|
||||
|
||||
local src="${src_dir}/${name}.rs"
|
||||
local binary="${dst_dir}/${name}"
|
||||
|
||||
echo "=== Compiling ${name} with rustc ==="
|
||||
# -O optimizes (opt-level 2); Rust statically links its own std, so the
|
||||
# only dynamic dependency left is the system glibc (+ libgcc_s), exactly
|
||||
# like the C++ binaries.
|
||||
local compile_cmd="rustc --edition 2021 -O -g ${extra_flags} \
|
||||
${src} -o ${binary}"
|
||||
echo "Compile cmd: ${compile_cmd}"
|
||||
eval "${compile_cmd}"
|
||||
|
||||
echo "=== Patching ${binary} to use ${loader} as PT_INTERP ==="
|
||||
local patch_cmd="patchelf --set-interpreter ${loader} --remove-rpath ${binary}"
|
||||
echo "Patch cmd: ${patch_cmd}"
|
||||
eval "${patch_cmd}"
|
||||
}
|
||||
|
||||
# `-O` disables overflow checks by default, so `overflow` re-enables them
|
||||
# explicitly to exercise the runtime overflow check.
|
||||
compile hello
|
||||
compile panic
|
||||
compile overflow "-C overflow-checks=on"
|
||||
|
||||
function compile_proc_macro() {
|
||||
local proj="${src_dir}/../proc_macro"
|
||||
|
||||
echo "=== Building proc-macro workspace (cargo) ==="
|
||||
cargo build --manifest-path "${proj}/Cargo.toml" --offline
|
||||
|
||||
local built="${proj}/target/debug/test_macro"
|
||||
if [ ! -f "${built}" ]; then
|
||||
echo "ERROR: built test_macro binary not found at ${built}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local binary="${dst_dir}/proc_macro"
|
||||
cp "${built}" "${binary}"
|
||||
|
||||
echo "=== Patching ${binary} to use ${loader} as PT_INTERP ==="
|
||||
patchelf --set-interpreter "${loader}" --remove-rpath "${binary}"
|
||||
|
||||
rm -rf "${proj}/target"
|
||||
}
|
||||
|
||||
compile_proc_macro
|
||||
|
||||
echo "=== All binaries compiled ==="
|
||||
|
||||
ls -la "${dst_dir}"
|
||||
14
nix/docker/test_files/rust/proc_macro/Cargo.lock
generated
14
nix/docker/test_files/rust/proc_macro/Cargo.lock
generated
@@ -1,14 +0,0 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "echo_macro"
|
||||
version = "0.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "test_macro"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"echo_macro",
|
||||
]
|
||||
@@ -1,3 +0,0 @@
|
||||
[workspace]
|
||||
resolver = "2"
|
||||
members = ["echo_macro", "test_macro"]
|
||||
@@ -1,8 +0,0 @@
|
||||
[package]
|
||||
name = "echo_macro"
|
||||
version = "0.0.0"
|
||||
edition = "2024"
|
||||
publish = false
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
@@ -1,6 +0,0 @@
|
||||
use proc_macro::TokenStream;
|
||||
|
||||
#[proc_macro]
|
||||
pub fn define_echo(item: TokenStream) -> TokenStream {
|
||||
format!("fn echo() -> u32 {{ {item} }}").parse().unwrap()
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
[package]
|
||||
name = "test_macro"
|
||||
version = "0.0.0"
|
||||
edition = "2024"
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
echo_macro = { path = "../echo_macro" }
|
||||
@@ -1,9 +0,0 @@
|
||||
use echo_macro::define_echo;
|
||||
|
||||
define_echo!(42);
|
||||
|
||||
fn main() {
|
||||
let a = echo();
|
||||
println!("proc-macro answer = {a}");
|
||||
assert_eq!(a, 42, "proc-macro expansion produced the wrong value");
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
#!/bin/bash
|
||||
# Run pre-compiled Rust binaries and confirm each emits its expected diagnostic.
|
||||
# Binaries must already exist in <bins_dir> as <name> for name in
|
||||
# {hello,panic,overflow,proc_macro}.
|
||||
|
||||
set -eo pipefail
|
||||
|
||||
bins_dir="${1:?usage: $0 <bins_dir>}"
|
||||
|
||||
failed_binaries=()
|
||||
|
||||
# Run a binary and verify its exit code and output.
|
||||
# Usage: run <binary> <expected_output> <expected_rc>
|
||||
function run() {
|
||||
local binary="${1}"
|
||||
local expected_output="${2}"
|
||||
local expected_rc="${3}"
|
||||
|
||||
local out_file
|
||||
out_file="$(mktemp)"
|
||||
|
||||
echo "=== Run ${binary} ==="
|
||||
set +e
|
||||
"${binary}" >"${out_file}" 2>&1
|
||||
local rc=$?
|
||||
set -e
|
||||
|
||||
cat "${out_file}"
|
||||
|
||||
local failed=0
|
||||
if [ "${expected_rc}" = "nonzero" ]; then
|
||||
if [ "${rc}" -eq 0 ]; then
|
||||
echo "ERROR: expected non-zero exit code from ${binary}, got ${rc}" >&2
|
||||
failed=1
|
||||
fi
|
||||
elif [ "${rc}" -ne "${expected_rc}" ]; then
|
||||
echo "ERROR: expected exit code ${expected_rc} from ${binary}, got ${rc}" >&2
|
||||
failed=1
|
||||
fi
|
||||
|
||||
if ! grep -q "${expected_output}" "${out_file}"; then
|
||||
echo "ERROR: expected '${expected_output}' from ${binary}" >&2
|
||||
failed=1
|
||||
fi
|
||||
|
||||
if [ "${failed}" -eq 0 ]; then
|
||||
echo "OK: '${expected_output}' detected"
|
||||
else
|
||||
failed_binaries+=("${binary}")
|
||||
fi
|
||||
}
|
||||
|
||||
declare -A expect=(
|
||||
[hello]="Hello from main thread"
|
||||
[panic]="explicit panic from test"
|
||||
[overflow]="attempt to add with overflow"
|
||||
[proc_macro]="proc-macro answer = 42"
|
||||
)
|
||||
|
||||
for name in hello panic overflow proc_macro; do
|
||||
binary="${bins_dir}/${name}"
|
||||
|
||||
if [ "${name}" = "hello" ] || [ "${name}" = "proc_macro" ]; then
|
||||
expected_rc=0
|
||||
else
|
||||
expected_rc=nonzero
|
||||
fi
|
||||
run "${binary}" "${expect[$name]}" "${expected_rc}"
|
||||
done
|
||||
|
||||
if [ "${#failed_binaries[@]}" -gt 0 ]; then
|
||||
echo "ERROR: the following binaries failed:" >&2
|
||||
printf ' %s\n' "${failed_binaries[@]}" >&2
|
||||
exit 1
|
||||
fi
|
||||
@@ -1,16 +0,0 @@
|
||||
use std::thread;
|
||||
|
||||
fn main() {
|
||||
const NUM_THREADS: usize = 10;
|
||||
let mut handles = Vec::with_capacity(NUM_THREADS);
|
||||
for id in 0..NUM_THREADS {
|
||||
handles.push(thread::spawn(move || {
|
||||
println!("Hello from thread {id}");
|
||||
}));
|
||||
}
|
||||
for handle in handles {
|
||||
handle.join().expect("worker thread panicked");
|
||||
}
|
||||
|
||||
println!("Hello from main thread");
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
use std::hint::black_box;
|
||||
|
||||
// Rust analogue of the C++ UBSan check: with overflow checks enabled the
|
||||
// compiler inserts a runtime check that panics on signed integer overflow.
|
||||
// `black_box` keeps the operands opaque so the addition is evaluated at
|
||||
// runtime rather than being rejected by the compile-time overflow lint.
|
||||
fn main() {
|
||||
let max = black_box(i32::MAX);
|
||||
let one = black_box(1);
|
||||
println!("Current max: {max}");
|
||||
let overflowed = max + one;
|
||||
println!("Overflowed result: {overflowed}");
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
fn main() {
|
||||
// Verify the panic runtime works: a panic must print its message to stderr
|
||||
// and exit with a non-zero status (Rust's default panic exit code is 101).
|
||||
panic!("explicit panic from test");
|
||||
}
|
||||
@@ -15,66 +15,6 @@ let
|
||||
runClangTidy = pkgs.writeShellScriptBin "run-clang-tidy" ''
|
||||
exec ${pkgs.python3}/bin/python3 ${llvmPackages.clang-unwrapped}/bin/run-clang-tidy "$@"
|
||||
'';
|
||||
|
||||
rustToolchain = pkgs.rust-bin.fromRustupToolchainFile ../rust-toolchain.toml;
|
||||
|
||||
# Nix wraps its toolchain so that binaries are exposed only under unsuffixed
|
||||
# names (gcc, g++, clang-tidy, ...). Several tools probe for a
|
||||
# version-suffixed name first and fall back to a system binary on the PATH
|
||||
# when Nix doesn't provide it:
|
||||
# - Conan's Boost recipe looks up `g++-<major>` before plain `g++`.
|
||||
# - bin/pre-commit/clang_tidy_check.py looks up `run-clang-tidy-<v>` and
|
||||
# `clang-apply-replacements-<v>` before the unsuffixed names.
|
||||
# On a host that also has the matching system binary (e.g. Ubuntu's
|
||||
# `/usr/bin/g++-15` or `clang-tidy-22`) the probe escapes Nix and mixes a
|
||||
# system tool into the Nix environment. Generate version-suffixed symlinks
|
||||
# next to a package's tools so those probes resolve to the Nix ones.
|
||||
#
|
||||
# Compiler links must point at whichever compiler is active in a given
|
||||
# environment (the plain stdenv compiler in the dev shell, the custom-glibc
|
||||
# wrappers in ci-env.nix), so those callers pass their own `package`; the
|
||||
# clang tooling is environment-independent and is linked in commonPackages.
|
||||
mkVersionedToolLinks =
|
||||
{
|
||||
name,
|
||||
package,
|
||||
version,
|
||||
tools,
|
||||
}:
|
||||
pkgs.linkFarm "${name}-${toString version}-versioned-links" (
|
||||
map (tool: {
|
||||
name = "bin/${tool}-${toString version}";
|
||||
path = "${package}/bin/${tool}";
|
||||
}) tools
|
||||
);
|
||||
|
||||
# The cc-wrapper doesn't re-export gcov, but coverage tooling (gcovr) needs a
|
||||
# gcov that exactly matches the compiler. Surface it from a gcc `cc` output.
|
||||
mkGcov =
|
||||
{ name, cc }:
|
||||
pkgs.linkFarm "gcov-${name}" [
|
||||
{
|
||||
name = "bin/gcov";
|
||||
path = "${cc}/bin/gcov";
|
||||
}
|
||||
];
|
||||
|
||||
clangToolLinks = mkVersionedToolLinks {
|
||||
name = "clang-tools";
|
||||
package = clangTools;
|
||||
version = llvmVersion;
|
||||
tools = [
|
||||
"clang-tidy"
|
||||
"clang-apply-replacements"
|
||||
"clang-format"
|
||||
];
|
||||
};
|
||||
runClangTidyLink = mkVersionedToolLinks {
|
||||
name = "run-clang-tidy";
|
||||
package = runClangTidy;
|
||||
version = llvmVersion;
|
||||
tools = [ "run-clang-tidy" ];
|
||||
};
|
||||
in
|
||||
{
|
||||
inherit
|
||||
@@ -82,13 +22,9 @@ in
|
||||
llvmVersion
|
||||
gccPackage
|
||||
llvmPackages
|
||||
mkVersionedToolLinks
|
||||
mkGcov
|
||||
;
|
||||
|
||||
commonPackages = with pkgs; [
|
||||
clangToolLinks
|
||||
runClangTidyLink
|
||||
ccache
|
||||
clangbuildanalyzer
|
||||
clangTools
|
||||
@@ -126,11 +62,5 @@ in
|
||||
runClangTidy
|
||||
vim
|
||||
zip
|
||||
# Rust packages
|
||||
cargo-audit
|
||||
cargo-llvm-cov
|
||||
cargo-nextest
|
||||
corrosion
|
||||
rustToolchain
|
||||
];
|
||||
}
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
{
|
||||
nixpkgs,
|
||||
nixpkgs-custom-glibc,
|
||||
rust-overlay,
|
||||
}:
|
||||
{ nixpkgs, nixpkgs-custom-glibc }:
|
||||
function:
|
||||
nixpkgs.lib.genAttrs
|
||||
[
|
||||
@@ -14,12 +10,7 @@ nixpkgs.lib.genAttrs
|
||||
(
|
||||
system:
|
||||
function {
|
||||
# rust-overlay adds `pkgs.rust-bin`, from which we build the pinned Rust
|
||||
# toolchain (see packages.nix). Consumed by both the CI image and dev shell.
|
||||
pkgs = import nixpkgs {
|
||||
inherit system;
|
||||
overlays = [ (import rust-overlay) ];
|
||||
};
|
||||
pkgs = import nixpkgs { inherit system; };
|
||||
# glibc 2.31 — matches the system libc on Ubuntu 20.04 LTS. Sourced
|
||||
# from the nixpkgs snapshot pinned via the `nixpkgs-custom-glibc`
|
||||
# flake input, so the build uses the compiler from that snapshot
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
[toolchain]
|
||||
channel = "1.95"
|
||||
components = ["rustfmt", "clippy", "rust-analyzer", "llvm-tools-preview"]
|
||||
profile = "minimal"
|
||||
@@ -29,7 +29,7 @@ src:test/beast/beast_PropertyStream_test.cpp
|
||||
src:src/test/app/Invariants_test.cpp
|
||||
|
||||
# ASan false positive: stack-use-after-scope in ErrorCodes.h inline functions.
|
||||
# When Clang inlines the StaticString overloads (e.g. invalidFieldError(StaticString)),
|
||||
# When Clang inlines the StaticString overloads (e.g. invalid_field_error(StaticString)),
|
||||
# ASan scope-poisons the temporary std::string before the inlined callee finishes reading
|
||||
# through the const ref. This corrupts the coroutine stack and crashes the Simulate test.
|
||||
# See asan.supp comments for full explanation and planned fix.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user