Compare commits

..

54 Commits

Author SHA1 Message Date
Ed Hennis
c65794da36 Merge remote-tracking branch 'XRPLF/develop' into ximinez/acquireAsyncDispatch
* XRPLF/develop: (81 commits)
  ci: Only publish docs in public repos (6687)
  chore: Enable remaining clang-tidy `performance` checks (6648)
  refactor: Address PR comments after the modularisation PRs (6389)
  chore: Fix clang-tidy header filter (6686)
  ci: [DEPENDABOT] bump actions/deploy-pages from 4.0.5 to 5.0.0 (6684)
  ci: [DEPENDABOT] bump codecov/codecov-action from 5.5.3 to 6.0.0 (6685)
  fix: Guard Coro::resume() against completed coroutines (6608)
  refactor: Split LoanInvariant into LoanBrokerInvariant and LoanInvariant (6674)
  ci: Don't publish docs on release branches (6673)
  refactor: Make function naming in ServiceRegistry consistent (6390)
  chore: Shorten job names to stay within Linux 15-char thread limit (6669)
  fix: Improve loan invariant message (6668)
  ci: Upload artifacts only in public repositories (6670)
  ci: Add conflicting-pr workflow (6656)
  chore: Add more AI tools to .gitignore (6658)
  chore: Show warning message if user may need to connect to VPN (6619)
  feat: Add placeholder amendment for assorted bug fixes (6652)
  chore: Update sqlite3->3.51.0, protobuf->6.33.5, openssl->3.6.1, grpc->1.78.1 (6653)
  refactor: Modularise ledger (6536)
  chore: Use unpatched version of soci (6649)
  ...
2026-03-30 22:38:24 -04:00
Ed Hennis
30716646d7 Merge branch 'develop' into ximinez/acquireAsyncDispatch 2026-03-12 15:05:10 -04:00
Ed Hennis
49b69a59eb Merge branch 'develop' into ximinez/acquireAsyncDispatch 2026-03-10 13:38:46 -04:00
Ed Hennis
5e37aa63c2 Merge branch 'develop' into ximinez/acquireAsyncDispatch 2026-03-06 13:04:22 -04:00
Ed Hennis
979beeb162 Merge branch 'develop' into ximinez/acquireAsyncDispatch 2026-03-04 17:11:47 -04:00
Ed Hennis
75e134a1fd Merge branch 'develop' into ximinez/acquireAsyncDispatch 2026-03-03 20:46:56 -04:00
Ed Hennis
828bcb3a7d Merge branch 'develop' into ximinez/acquireAsyncDispatch 2026-03-03 15:54:51 -04:00
Ed Hennis
6fc972746d Merge branch 'develop' into ximinez/acquireAsyncDispatch 2026-02-24 17:35:00 -04:00
Ed Hennis
930afbdea8 Merge branch 'develop' into ximinez/acquireAsyncDispatch 2026-02-20 18:50:00 -04:00
Ed Hennis
95c5bef48b Merge branch 'develop' into ximinez/acquireAsyncDispatch 2026-02-20 18:26:19 -04:00
Ed Hennis
b489b6c3ce Merge branch 'develop' into ximinez/acquireAsyncDispatch 2026-02-20 17:32:02 -04:00
Ed Hennis
70765acef4 Merge remote-tracking branch 'upstream/develop' into ximinez/acquireAsyncDispatch
* upstream/develop:
  ci: [DEPENDABOT] bump tj-actions/changed-files from 46.0.5 to 47.0.4 (6394)
  ci: [DEPENDABOT] bump codecov/codecov-action from 5.4.3 to 5.5.2 (6398)
  ci: Build docs in PRs and in private repos (6400)
  ci: Add dependabot config (6379)
  Fix tautological assertion (6393)
  chore: Apply clang-format width 100 (6387)
2026-02-20 16:30:42 -05:00
Ed Hennis
77aa90bd0e Update formatting 2026-02-20 16:27:59 -05:00
Ed Hennis
4758bb6dc9 Merge commit '25cca465538a56cce501477f9e5e2c1c7ea2d84c' into ximinez/acquireAsyncDispatch
* commit '25cca465538a56cce501477f9e5e2c1c7ea2d84c':
  chore: Set clang-format width to 100 in config file (6387)
2026-02-20 16:27:39 -05:00
Ed Hennis
46e3dcb5fb Merge branch 'develop' into ximinez/acquireAsyncDispatch 2026-02-19 16:24:54 -05:00
Ed Hennis
d57579f10b Merge remote-tracking branch 'XRPLF/develop' into ximinez/acquireAsyncDispatch
* XRPLF/develop:
  refactor: Modularize app/tx (6228)
  refactor: Decouple app/tx from `Application` and `Config` (6227)
  chore: Update clang-format to 21.1.8 (6352)
  refactor: Modularize `HashRouter`, `Conditions`, and `OrderBookDB` (6226)
  chore: Fix minor issues in comments (6346)
  refactor: Modularize the NetworkOPs interface (6225)
  chore: Fix `gcov` lib coverage build failure on macOS (6350)
  refactor: Modularize RelationalDB (6224)
  refactor: Modularize WalletDB and Manifest (6223)
  fix: Update invariant checks for Permissioned Domains (6134)
  refactor: Change main thread name to `xrpld-main` (6336)
  refactor: Fix spelling issues in tests (6199)
  test: Add file and line location to Env (6276)
  chore: Remove CODEOWNERS (6337)
  perf: Remove unnecessary caches (5439)
  chore: Restore unity builds (6328)
  refactor: Update secp256k1 to 0.7.1 (6331)
  fix: Increment sequence when accepting new manifests (6059)
  fix typo in LendingHelpers unit-test (6215)
2026-02-18 19:52:18 -05:00
Ed Hennis
d8dd376d1c Merge branch 'develop' into ximinez/acquireAsyncDispatch 2026-02-04 16:30:10 -04:00
Ed Hennis
a8c03e2e6c Merge branch 'develop' into ximinez/acquireAsyncDispatch 2026-02-03 16:08:06 -04:00
Ed Hennis
2167a66bc7 Fix formatting 2026-01-28 19:39:15 -05:00
Ed Hennis
ed948a858c Merge branch 'develop' into ximinez/acquireAsyncDispatch 2026-01-28 18:49:15 -04:00
Ed Hennis
608c102743 Merge commit '5f638f55536def0d88b970d1018a465a238e55f4' into ximinez/acquireAsyncDispatch
* commit '5f638f55536def0d88b970d1018a465a238e55f4':
  chore: Set ColumnLimit to 120 in clang-format (6288)
2026-01-28 17:47:53 -05:00
Ed Hennis
36d1607a4e Merge commit '92046785d1fea5f9efe5a770d636792ea6cab78b' into ximinez/acquireAsyncDispatch
* commit '92046785d1fea5f9efe5a770d636792ea6cab78b':
  test: Fix the `xrpl.net` unit test using async read (6241)
  ci: Upload Conan recipes for develop, release candidates, and releases (6286)
  fix: Stop embedded tests from hanging on ARM by using `atomic_flag` (6248)
  fix:  Remove DEFAULT fields that change to the default in associateAsset (6259) (6273)
  refactor: Update Boost to 1.90 (6280)
  refactor: clean up uses of `std::source_location` (6272)
  ci: Pass missing sanitizers input to actions (6266)
  ci: Properly propagate Conan credentials (6265)
  ci: Explicitly set version when exporting the Conan recipe (6264)
  ci: Use plus instead of hyphen for Conan recipe version suffix (6261)
  chore: Detect uninitialized variables in CMake files (6247)
  ci: Run on-trigger and on-pr when generate-version is modified (6257)
  refactor: Enforce 15-char limit and simplify labels for thread naming (6212)
  docs: Update Ripple Bug Bounty public key (6258)
  ci: Add missing commit hash to Conan recipe version (6256)
  fix: Include `<functional>` header in `Number.h` (6254)
  ci: Upload Conan recipe for merges into develop and commits to release (6235)
  Limit reply size on `TMGetObjectByHash` queries (6110)
  ci: remove 'master' branch as a trigger (6234)
  Improve ledger_entry lookups for fee, amendments, NUNL, and hashes (5644)
2026-01-28 17:47:47 -05:00
Ed Hennis
53ebb86d60 Merge branch 'develop' into ximinez/acquireAsyncDispatch 2026-01-15 13:03:36 -04:00
Ed Hennis
1d989bc6de Merge branch 'develop' into ximinez/acquireAsyncDispatch 2026-01-15 12:06:00 -04:00
Ed Hennis
64c0cb8c7e Merge branch 'develop' into ximinez/acquireAsyncDispatch 2026-01-13 18:19:11 -04:00
Ed Hennis
c77cfef41c Merge branch 'develop' into ximinez/acquireAsyncDispatch 2026-01-13 15:28:01 -04:00
Ed Hennis
08aa8c06d1 Merge branch 'develop' into ximinez/acquireAsyncDispatch 2026-01-12 14:52:16 -04:00
Ed Hennis
9498672f8e Merge branch 'develop' into ximinez/acquireAsyncDispatch 2026-01-11 00:50:43 -04:00
Ed Hennis
e91d55a0e0 Merge branch 'develop' into ximinez/acquireAsyncDispatch 2026-01-08 17:06:11 -04:00
Ed Hennis
afdc452cfc Merge branch 'develop' into ximinez/acquireAsyncDispatch 2026-01-08 13:04:20 -04:00
Ed Hennis
a0d4ef1a54 Merge branch 'develop' into ximinez/acquireAsyncDispatch 2026-01-06 14:02:15 -05:00
Ed Hennis
8bc384f8bf Merge branch 'develop' into ximinez/acquireAsyncDispatch 2025-12-22 17:39:59 -05:00
Ed Hennis
bd961c484b Merge branch 'develop' into ximinez/acquireAsyncDispatch 2025-12-18 19:59:52 -05:00
Ed Hennis
aee242a8d4 Merge branch 'develop' into ximinez/acquireAsyncDispatch 2025-12-12 20:34:59 -05:00
Ed Hennis
fcae74de58 Merge remote-tracking branch 'XRPLF/develop' into ximinez/acquireAsyncDispatch
* XRPLF/develop:
  refactor: Rename `ripple` namespace to `xrpl` (5982)
  refactor: Move JobQueue and related classes into xrpl.core module (6121)
  refactor: Rename `rippled` binary to `xrpld` (5983)
  refactor: rename info() to header() (6138)
  refactor: rename `LedgerInfo` to `LedgerHeader` (6136)
  refactor: clean up `RPCHelpers` (5684)
  chore: Fix docs readme and cmake (6122)
  chore: Clean up .gitignore and .gitattributes (6001)
  chore: Use updated secp256k1 recipe (6118)
2025-12-11 15:33:12 -05:00
Ed Hennis
a56effcb00 Merge branch 'develop' into ximinez/acquireAsyncDispatch 2025-12-05 21:13:10 -05:00
Ed Hennis
64c2eca465 Merge branch 'develop' into ximinez/acquireAsyncDispatch 2025-12-02 17:37:29 -05:00
Ed Hennis
e56f750e1d Merge branch 'develop' into ximinez/acquireAsyncDispatch 2025-12-01 14:40:45 -05:00
Ed Hennis
fde000f3eb Merge branch 'develop' into ximinez/acquireAsyncDispatch 2025-11-28 15:46:44 -05:00
Ed Hennis
d0a62229da Merge branch 'develop' into ximinez/acquireAsyncDispatch 2025-11-27 01:48:56 -05:00
Ed Hennis
d5932cc7d4 Merge branch 'develop' into ximinez/acquireAsyncDispatch 2025-11-26 00:25:17 -05:00
Ed Hennis
0b534da781 Merge branch 'develop' into ximinez/acquireAsyncDispatch 2025-11-25 14:55:06 -05:00
Ed Hennis
71a70d343b Merge branch 'develop' into ximinez/acquireAsyncDispatch 2025-11-24 21:49:11 -05:00
Ed Hennis
0899e65030 Merge branch 'develop' into ximinez/acquireAsyncDispatch 2025-11-24 21:30:22 -05:00
Ed Hennis
31ba529761 Merge branch 'develop' into ximinez/acquireAsyncDispatch 2025-11-21 12:47:58 -05:00
Ed Hennis
e2c6e5ebb6 Merge branch 'develop' into ximinez/acquireAsyncDispatch 2025-11-18 22:39:29 -05:00
Ed Hennis
9d807fce48 Merge branch 'develop' into ximinez/acquireAsyncDispatch 2025-11-15 03:08:41 -05:00
Ed Hennis
9ef160765c Merge branch 'develop' into ximinez/acquireAsyncDispatch 2025-11-13 12:19:21 -05:00
Ed Hennis
d6c0eb243b Merge branch 'develop' into ximinez/acquireAsyncDispatch 2025-11-12 14:12:55 -05:00
Ed Hennis
84c9fc123c Fix formatting 2025-11-10 19:53:05 -05:00
Ed Hennis
00a2a58cfa Add missing header 2025-11-10 19:53:05 -05:00
Ed Hennis
bb2098d873 Add a unit test for CanProcess
- Delete the copy ctor & operator
2025-11-10 19:53:05 -05:00
Ed Hennis
46a5bc74db refactor: acquireAsync will dispatch the job, not the other way around 2025-11-10 19:53:05 -05:00
Ed Hennis
7b72b9cc82 Improve job queue collision checks and logging
- Improve logging related to ledger acquisition and operating mode
  changes
- Class "CanProcess" to keep track of processing of distinct items
2025-11-10 19:53:05 -05:00
42 changed files with 424 additions and 1133 deletions

View File

@@ -99,15 +99,14 @@ def generate_strategy_matrix(all: bool, config: Config) -> list:
continue
# RHEL:
# - 9 using GCC 12: Debug and Release on linux/amd64
# (Release is required for RPM packaging).
# - 9 using GCC 12: Debug on linux/amd64.
# - 10 using Clang: Release on linux/amd64.
if os["distro_name"] == "rhel":
skip = True
if os["distro_version"] == "9":
if (
f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-12"
and build_type in ["Debug", "Release"]
and build_type == "Debug"
and architecture["platform"] == "linux/amd64"
):
skip = False
@@ -122,8 +121,7 @@ def generate_strategy_matrix(all: bool, config: Config) -> list:
continue
# Ubuntu:
# - Jammy using GCC 12: Debug on linux/arm64, Release on
# linux/amd64 (Release is required for DEB packaging).
# - Jammy using GCC 12: Debug on linux/arm64.
# - Noble using GCC 14: Release on linux/amd64.
# - Noble using Clang 18: Debug on linux/amd64.
# - Noble using Clang 19: Release on linux/arm64.
@@ -136,12 +134,6 @@ def generate_strategy_matrix(all: bool, config: Config) -> list:
and architecture["platform"] == "linux/arm64"
):
skip = False
if (
f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-12"
and build_type == "Release"
and architecture["platform"] == "linux/amd64"
):
skip = False
elif os["distro_version"] == "noble":
if (
f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-14"

View File

@@ -67,7 +67,6 @@ jobs:
.github/workflows/reusable-build-test.yml
.github/workflows/reusable-clang-tidy.yml
.github/workflows/reusable-clang-tidy-files.yml
.github/workflows/reusable-package.yml
.github/workflows/reusable-strategy-matrix.yml
.github/workflows/reusable-test.yml
.github/workflows/reusable-upload-recipe.yml
@@ -82,8 +81,6 @@ jobs:
CMakeLists.txt
conanfile.py
conan.lock
package/**
- name: Check whether to run
# This step determines whether the rest of the workflow should
# run. The rest of the workflow will run if this job runs AND at
@@ -140,39 +137,6 @@ jobs:
secrets:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
generate-version:
needs: should-run
if: ${{ needs.should-run.outputs.go == 'true' }}
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.version }}
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Generate version
id: version
uses: ./.github/actions/generate-version
package-deb:
needs: [should-run, build-test, generate-version]
if: ${{ needs.should-run.outputs.go == 'true' }}
uses: ./.github/workflows/reusable-package.yml
with:
pkg_type: deb
artifact_name: xrpld-ubuntu-jammy-gcc-12-amd64-release
version: ${{ needs.generate-version.outputs.version }}
container_image: ghcr.io/xrplf/ci/ubuntu-jammy:gcc-12
package-rpm:
needs: [should-run, build-test, generate-version]
if: ${{ needs.should-run.outputs.go == 'true' }}
uses: ./.github/workflows/reusable-package.yml
with:
pkg_type: rpm
artifact_name: xrpld-rhel-9-gcc-12-amd64-release
version: ${{ needs.generate-version.outputs.version }}
container_image: ghcr.io/xrplf/ci/rhel-9:gcc-12
upload-recipe:
needs:
- should-run

View File

@@ -1,5 +1,5 @@
# This workflow uploads the libxrpl recipe to the Conan remote and builds
# release packages when a versioned tag is pushed.
# This workflow uploads the libxrpl recipe to the Conan remote when a versioned
# tag is pushed.
name: Tag
on:
@@ -22,49 +22,3 @@ jobs:
secrets:
remote_username: ${{ secrets.CONAN_REMOTE_USERNAME }}
remote_password: ${{ secrets.CONAN_REMOTE_PASSWORD }}
build-test:
if: ${{ github.repository == 'XRPLF/rippled' }}
uses: ./.github/workflows/reusable-build-test.yml
strategy:
fail-fast: true
matrix:
os: [linux]
with:
ccache_enabled: false
os: ${{ matrix.os }}
strategy_matrix: minimal
secrets:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
generate-version:
if: ${{ github.repository == 'XRPLF/rippled' }}
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.version }}
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Generate version
id: version
uses: ./.github/actions/generate-version
package-deb:
needs: [build-test, generate-version]
if: ${{ github.repository == 'XRPLF/rippled' }}
uses: ./.github/workflows/reusable-package.yml
with:
pkg_type: deb
artifact_name: xrpld-ubuntu-jammy-gcc-12-amd64-release
version: ${{ needs.generate-version.outputs.version }}
container_image: ghcr.io/xrplf/ci/ubuntu-jammy:gcc-12
package-rpm:
needs: [build-test, generate-version]
if: ${{ github.repository == 'XRPLF/rippled' }}
uses: ./.github/workflows/reusable-package.yml
with:
pkg_type: rpm
artifact_name: xrpld-rhel-9-gcc-12-amd64-release
version: ${{ needs.generate-version.outputs.version }}
container_image: ghcr.io/xrplf/ci/rhel-9:gcc-12

View File

@@ -38,8 +38,6 @@ on:
- "CMakeLists.txt"
- "conanfile.py"
- "conan.lock"
- "package/**"
- ".github/workflows/reusable-package.yml"
# Run at 06:32 UTC on every day of the week from Monday through Friday. This
# will force all dependencies to be rebuilt, which is useful to verify that
@@ -100,32 +98,3 @@ jobs:
secrets:
remote_username: ${{ secrets.CONAN_REMOTE_USERNAME }}
remote_password: ${{ secrets.CONAN_REMOTE_PASSWORD }}
generate-version:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.version }}
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Generate version
id: version
uses: ./.github/actions/generate-version
package-deb:
needs: [build-test, generate-version]
uses: ./.github/workflows/reusable-package.yml
with:
pkg_type: deb
artifact_name: xrpld-ubuntu-jammy-gcc-12-amd64-release
version: ${{ needs.generate-version.outputs.version }}
container_image: ghcr.io/xrplf/ci/ubuntu-jammy:gcc-12
package-rpm:
needs: [build-test, generate-version]
uses: ./.github/workflows/reusable-package.yml
with:
pkg_type: rpm
artifact_name: xrpld-rhel-9-gcc-12-amd64-release
version: ${{ needs.generate-version.outputs.version }}
container_image: ghcr.io/xrplf/ci/rhel-9:gcc-12

View File

@@ -1,83 +0,0 @@
# Build a Linux package (DEB or RPM) from a pre-built binary artifact.
name: Package
on:
workflow_call:
inputs:
pkg_type:
description: "Package type to build: deb or rpm."
required: true
type: string
artifact_name:
description: "Name of the pre-built binary artifact to download."
required: true
type: string
version:
description: "Version string used for naming the output artifact."
required: true
type: string
pkg_release:
description: "Package release number. Increment when repackaging the same executable."
required: false
type: string
default: "1"
container_image:
description: "Container image to use for packaging."
required: true
type: string
defaults:
run:
shell: bash
env:
BUILD_DIR: build
jobs:
package:
name: ${{ inputs.pkg_type }} (${{ inputs.version }})
runs-on: ["self-hosted", "Linux", "X64", "heavy"]
container: ${{ inputs.container_image }}
timeout-minutes: 30
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Download pre-built binary
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: ${{ inputs.artifact_name }}
path: ${{ env.BUILD_DIR }}
- name: Make binary executable
run: chmod +x "${BUILD_DIR}/xrpld"
- name: Generate RPM spec from template
if: ${{ inputs.pkg_type == 'rpm' }}
env:
PKG_VERSION: ${{ inputs.version }}
PKG_RELEASE: ${{ inputs.pkg_release }}
run: |
mkdir -p "${BUILD_DIR}/package/rpm"
sed -e "s/@xrpld_version@/${PKG_VERSION}/" \
-e "s/@pkg_release@/${PKG_RELEASE}/" \
package/rpm/xrpld.spec.in > "${BUILD_DIR}/package/rpm/xrpld.spec"
- name: Build package
env:
PKG_TYPE: ${{ inputs.pkg_type }}
PKG_VERSION: ${{ inputs.version }}
PKG_RELEASE: ${{ inputs.pkg_release }}
run: |
./package/build_pkg.sh "$PKG_TYPE" . "$BUILD_DIR" "$PKG_VERSION" "$PKG_RELEASE"
- name: Upload package artifact
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: xrpld-${{ inputs.pkg_type }}-${{ inputs.version }}
path: |
${{ env.BUILD_DIR }}/debbuild/*.deb
${{ env.BUILD_DIR }}/debbuild/*.ddeb
${{ env.BUILD_DIR }}/rpmbuild/RPMS/**/*.rpm
if-no-files-found: error

View File

@@ -133,7 +133,6 @@ endif()
include(XrplCore)
include(XrplInstall)
include(XrplPackaging)
include(XrplValidatorKeys)
if(tests)

View File

@@ -12,14 +12,14 @@ if(is_root_project AND TARGET xrpld)
install(
FILES "${CMAKE_CURRENT_SOURCE_DIR}/cfg/xrpld-example.cfg"
DESTINATION "${CMAKE_INSTALL_SYSCONFDIR}"
DESTINATION "${CMAKE_INSTALL_SYSCONFDIR}/xrpld"
RENAME xrpld.cfg
COMPONENT runtime
)
install(
FILES "${CMAKE_CURRENT_SOURCE_DIR}/cfg/validators-example.txt"
DESTINATION "${CMAKE_INSTALL_SYSCONFDIR}"
DESTINATION "${CMAKE_INSTALL_SYSCONFDIR}/xrpld"
RENAME validators.txt
COMPONENT runtime
)

View File

@@ -1,142 +0,0 @@
#[===================================================================[
Linux packaging support: RPM and Debian targets + install tests
#]===================================================================]
if(NOT CMAKE_INSTALL_PREFIX STREQUAL "/opt/xrpld")
message(
STATUS
"Packaging targets require -DCMAKE_INSTALL_PREFIX=/opt/xrpld "
"(current: '${CMAKE_INSTALL_PREFIX}'); skipping."
)
return()
endif()
if(NOT DEFINED pkg_release)
set(pkg_release 1)
endif()
configure_file(
${CMAKE_SOURCE_DIR}/package/rpm/xrpld.spec.in
${CMAKE_BINARY_DIR}/package/rpm/xrpld.spec
@ONLY
)
find_program(RPMBUILD_EXECUTABLE rpmbuild)
if(RPMBUILD_EXECUTABLE)
add_custom_target(
package-rpm
COMMAND
${CMAKE_SOURCE_DIR}/package/build_pkg.sh rpm ${CMAKE_SOURCE_DIR}
${CMAKE_BINARY_DIR}
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
COMMENT "Building RPM package"
VERBATIM
)
else()
message(STATUS "rpmbuild not found; 'package-rpm' target not available")
endif()
find_program(DPKG_BUILDPACKAGE_EXECUTABLE dpkg-buildpackage)
if(DPKG_BUILDPACKAGE_EXECUTABLE)
add_custom_target(
package-deb
COMMAND
${CMAKE_SOURCE_DIR}/package/build_pkg.sh deb ${CMAKE_SOURCE_DIR}
${CMAKE_BINARY_DIR} ${xrpld_version}
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
COMMENT "Building Debian package"
VERBATIM
)
else()
message(
STATUS
"dpkg-buildpackage not found; 'package-deb' target not available"
)
endif()
#[===================================================================[
CTest fixtures for package install verification (requires docker)
#]===================================================================]
find_program(DOCKER_EXECUTABLE docker)
if(NOT DOCKER_EXECUTABLE)
message(STATUS "docker not found; package install tests not available")
return()
endif()
set(DEB_TEST_IMAGE "geerlingguy/docker-ubuntu2204-ansible:latest")
set(RPM_TEST_IMAGE "geerlingguy/docker-rockylinux9-ansible:latest")
foreach(PKG deb rpm)
if(PKG STREQUAL "deb")
set(IMAGE ${DEB_TEST_IMAGE})
else()
set(IMAGE ${RPM_TEST_IMAGE})
endif()
# This image runs systemd for full testing xrpld.service
add_test(
NAME ${PKG}_container_start
COMMAND
sh -c
"docker rm -f xrpld_${PKG}_install_test 2>/dev/null || true && \
docker run -d \
--name xrpld_${PKG}_install_test \
--cgroupns host \
--volume '${CMAKE_SOURCE_DIR}:/root:ro' \
--volume /sys/fs/cgroup:/sys/fs/cgroup:rw \
--tmpfs /tmp --tmpfs /run \
--tmpfs /run/lock \
${IMAGE} \
/usr/sbin/init"
)
set_tests_properties(
${PKG}_container_start
PROPERTIES FIXTURES_SETUP ${PKG}_container LABELS packaging
)
# On CI: always stop. Locally: leave running on failure for diagnosis.
add_test(
NAME ${PKG}_container_stop
COMMAND
sh -c
"if [ -n \"$CI\" ] || ! docker exec xrpld_${PKG}_install_test test -f /tmp/test_failed 2>/dev/null; then \
docker rm -f xrpld_${PKG}_install_test; \
else \
echo 'Tests failed — leaving xrpld_${PKG}_install_test running for diagnosis'; \
echo 'Clean up with: docker rm -f xrpld_${PKG}_install_test'; \
fi"
)
set_tests_properties(
${PKG}_container_stop
PROPERTIES FIXTURES_CLEANUP ${PKG}_container LABELS packaging
)
add_test(
NAME ${PKG}_install
COMMAND
docker exec -w /root xrpld_${PKG}_install_test bash
/root/package/test/smoketest.sh local
)
set_tests_properties(
${PKG}_install
PROPERTIES
FIXTURES_REQUIRED ${PKG}_container
FIXTURES_SETUP ${PKG}_installed
LABELS packaging
TIMEOUT 600
)
add_test(
NAME ${PKG}_install_paths
COMMAND
docker exec -w /root xrpld_${PKG}_install_test sh
/root/package/test/check_install_paths.sh
)
set_tests_properties(
${PKG}_install_paths
PROPERTIES
FIXTURES_REQUIRED "${PKG}_container;${PKG}_installed"
LABELS packaging
TIMEOUT 60
)
endforeach()

View File

@@ -93,14 +93,11 @@ words:
- desync
- desynced
- determ
- disablerepo
- distro
- doxyfile
- dxrpl
- enablerepo
- endmacro
- exceptioned
- EXPECT_STREQ
- Falco
- fcontext
- finalizers
@@ -154,7 +151,6 @@ words:
- Merkle
- Metafuncton
- misprediction
- missingok
- mptbalance
- MPTDEX
- mptflags
@@ -185,9 +181,7 @@ words:
- NOLINT
- NOLINTNEXTLINE
- nonxrp
- noreplace
- noripple
- notifempty
- nudb
- nullptr
- nunl
@@ -207,7 +201,6 @@ words:
- preauthorize
- preauthorizes
- preclaim
- preun
- protobuf
- protos
- ptrs
@@ -242,14 +235,12 @@ words:
- sfields
- shamap
- shamapitem
- shlibs
- sidechain
- SIGGOOD
- sle
- sles
- soci
- socidb
- SRPMS
- sslws
- statsd
- STATSDCOLLECTOR
@@ -277,8 +268,8 @@ words:
- txn
- txns
- txs
- ubsan
- UBSAN
- ubsan
- umant
- unacquired
- unambiguity
@@ -315,6 +306,7 @@ words:
- xbridge
- xchain
- ximinez
- EXPECT_STREQ
- XMACRO
- xrpkuwait
- xrpl

View File

@@ -0,0 +1,139 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2024 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_BASICS_CANPROCESS_H_INCLUDED
#define RIPPLE_BASICS_CANPROCESS_H_INCLUDED
#include <functional>
#include <mutex>
#include <set>
/** RAII class to check if an Item is already being processed on another thread,
* as indicated by it's presence in a Collection.
*
* If the Item is not in the Collection, it will be added under lock in the
* ctor, and removed under lock in the dtor. The object will be considered
* "usable" and evaluate to `true`.
*
* If the Item is in the Collection, no changes will be made to the collection,
* and the CanProcess object will be considered "unusable".
*
* It's up to the caller to decide what "usable" and "unusable" mean. (e.g.
* Process or skip a block of code, or set a flag.)
*
* The current use is to avoid lock contention that would be involved in
* processing something associated with the Item.
*
* Examples:
*
* void IncomingLedgers::acquireAsync(LedgerHash const& hash, ...)
* {
* if (CanProcess check{acquiresMutex_, pendingAcquires_, hash})
* {
* acquire(hash, ...);
* }
* }
*
* bool
* NetworkOPsImp::recvValidation(
* std::shared_ptr<STValidation> const& val,
* std::string const& source)
* {
* CanProcess check(
* validationsMutex_, pendingValidations_, val->getLedgerHash());
* BypassAccept bypassAccept =
* check ? BypassAccept::no : BypassAccept::yes;
* handleNewValidation(app_, val, source, bypassAccept, m_journal);
* }
*
*/
class CanProcess
{
public:
template <class Mutex, class Collection, class Item>
CanProcess(Mutex& mtx, Collection& collection, Item const& item)
: cleanup_(insert(mtx, collection, item))
{
}
~CanProcess()
{
if (cleanup_)
cleanup_();
}
CanProcess(CanProcess const&) = delete;
CanProcess&
operator=(CanProcess const&) = delete;
explicit
operator bool() const
{
return static_cast<bool>(cleanup_);
}
private:
template <bool useIterator, class Mutex, class Collection, class Item>
std::function<void()>
doInsert(Mutex& mtx, Collection& collection, Item const& item)
{
std::unique_lock<Mutex> lock(mtx);
// TODO: Use structured binding once LLVM 16 is the minimum supported
// version. See also: https://github.com/llvm/llvm-project/issues/48582
// https://github.com/llvm/llvm-project/commit/127bf44385424891eb04cff8e52d3f157fc2cb7c
auto const insertResult = collection.insert(item);
auto const it = insertResult.first;
if (!insertResult.second)
return {};
if constexpr (useIterator)
return [&, it]() {
std::unique_lock<Mutex> lock(mtx);
collection.erase(it);
};
else
return [&]() {
std::unique_lock<Mutex> lock(mtx);
collection.erase(item);
};
}
// Generic insert() function doesn't use iterators because they may get
// invalidated
template <class Mutex, class Collection, class Item>
std::function<void()>
insert(Mutex& mtx, Collection& collection, Item const& item)
{
return doInsert<false>(mtx, collection, item);
}
// Specialize insert() for std::set, which does not invalidate iterators for
// insert and erase
template <class Mutex, class Item>
std::function<void()>
insert(Mutex& mtx, std::set<Item>& collection, Item const& item)
{
return doInsert<true>(mtx, collection, item);
}
// If set, then the item is "usable"
std::function<void()> cleanup_;
};
#endif

View File

@@ -199,7 +199,7 @@ public:
/** Add a suppression peer and get message's relay status.
* Return pair:
* element 1: true if the peer is added.
* element 1: true if the key is added.
* element 2: optional is seated to the relay time point or
* is unseated if has not relayed yet. */
std::pair<bool, std::optional<Stopwatch::time_point>>

View File

@@ -35,6 +35,8 @@ struct LedgerHeader
// If validated is false, it means "not yet validated."
// Once validated is true, it will never be set false at a later time.
// NOTE: If you are accessing this directly, you are probably doing it
// wrong. Use LedgerMaster::isValidated().
// VFALCO TODO Make this not mutable
bool mutable validated = false;
bool accepted = false;

View File

@@ -185,7 +185,7 @@ public:
virtual bool
isFull() = 0;
virtual void
setMode(OperatingMode om) = 0;
setMode(OperatingMode om, char const* reason) = 0;
virtual bool
isBlocked() = 0;
virtual bool

View File

@@ -1,118 +0,0 @@
# Linux Packaging
This directory contains all files needed to build RPM and Debian packages for `xrpld`.
## Directory layout
```
package/
build_pkg.sh Staging and build script (called by CMake targets and CI)
rpm/
xrpld.spec.in RPM spec template (substitutes @xrpld_version@, @pkg_release@)
deb/
debian/ Debian control files (control, rules, install, links, conffiles, ...)
shared/
xrpld.service systemd unit file (used by both RPM and DEB)
xrpld.sysusers sysusers.d config (used by both RPM and DEB)
xrpld.tmpfiles tmpfiles.d config (used by both RPM and DEB)
xrpld.logrotate logrotate config (installed to /opt/xrpld/bin/, user activates)
update-xrpld.sh auto-update script (installed to /opt/xrpld/bin/)
update-xrpld-cron cron entry for auto-update (installed to /opt/xrpld/bin/)
test/
smoketest.sh Package install smoke test
check_install_paths.sh Verify install paths and compat symlinks
```
## Prerequisites
| Package type | Container | Tool required |
| ------------ | -------------------------------------- | --------------------------------------------------------------- |
| RPM | `ghcr.io/xrplf/ci/rhel-9:gcc-12` | `rpmbuild` |
| DEB | `ghcr.io/xrplf/ci/ubuntu-jammy:gcc-12` | `dpkg-buildpackage`, `debhelper (>= 13)`, `dh-sequence-systemd` |
## Building packages
### Via CI (recommended)
The `reusable-package.yml` workflow downloads a pre-built `xrpld` binary artifact
and calls `build_pkg.sh` directly. No CMake configure or build step is needed in
the packaging job.
### Via CMake (local development)
Configure with the required install prefix, then invoke the target:
```bash
cmake \
-DCMAKE_INSTALL_PREFIX=/opt/xrpld \
-Dxrpld=ON \
-Dtests=OFF \
..
# RPM (in RHEL container):
cmake --build . --target package-rpm
# DEB (in Debian/Ubuntu container):
cmake --build . --target package-deb
```
The `cmake/XrplPackaging.cmake` module gates each target on whether the required
tool (`rpmbuild` / `dpkg-buildpackage`) is present at configure time, so
configuring on a host that lacks one simply omits the corresponding target.
`CMAKE_INSTALL_PREFIX` must be `/opt/xrpld`; if it is not, both targets are
skipped with a `STATUS` message.
## How `build_pkg.sh` works
`build_pkg.sh <pkg_type> <src_dir> <build_dir> [version] [pkg_release]` stages
all files and invokes the platform build tool. It resolves `src_dir` and
`build_dir` to absolute paths, then calls `stage_common()` to copy the binary,
config files, and shared support files into the staging area.
### RPM
1. Creates the standard `rpmbuild/{BUILD,BUILDROOT,RPMS,SOURCES,SPECS,SRPMS}` tree inside the build directory.
2. Copies the generated `xrpld.spec` and all source files (binary, configs, service files) into `SOURCES/`.
3. Runs `rpmbuild -bb`. The spec uses manual `install` commands to place files.
4. Output: `rpmbuild/RPMS/x86_64/xrpld-*.rpm`
### DEB
1. Creates a staging source tree at `debbuild/source/` inside the build directory.
2. Stages the binary, configs, `README.md`, and `LICENSE.md`.
3. Copies `package/deb/debian/` control files into `debbuild/source/debian/`.
4. Copies shared service/sysusers/tmpfiles into `debian/` where `dh_installsystemd`, `dh_installsysusers`, and `dh_installtmpfiles` pick them up automatically.
5. Generates a minimal `debian/changelog` (pre-release versions use `~` instead of `-`).
6. Runs `dpkg-buildpackage -b --no-sign`. `debian/rules` uses manual `install` commands.
7. Output: `debbuild/*.deb` and `debbuild/*.ddeb` (dbgsym package)
## Post-build verification
```bash
# DEB
dpkg-deb -c debbuild/*.deb | grep -E 'systemd|sysusers|tmpfiles'
lintian -I debbuild/*.deb
# RPM
rpm -qlp rpmbuild/RPMS/x86_64/*.rpm
```
## Reproducibility
The following environment variables improve build reproducibility. They are not
set automatically by `build_pkg.sh`; set them manually if needed:
```bash
export SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct)
export TZ=UTC
export LC_ALL=C.UTF-8
export GZIP=-n
export DEB_BUILD_OPTIONS="noautodbgsym reproducible=+fixfilepath"
```
## TODO
- Port debsigs signing instructions and integrate into CI.
- Port RPM GPG signing setup (key import + `%{?_gpg_sign}` in spec).
- Introduce a virtual package for key rotation.

View File

@@ -1,92 +0,0 @@
#!/usr/bin/env bash
# Build an RPM or Debian package from a pre-built xrpld binary.
#
# Usage: build_pkg.sh <pkg_type> <src_dir> <build_dir> [version] [pkg_release]
# pkg_type : rpm | deb
# src_dir : path to repository root
# build_dir : directory containing the pre-built xrpld binary
# version : package version string (e.g. 2.4.0-b1)
# pkg_release : package release number (default: 1)
set -euo pipefail
PKG_TYPE="${1:?pkg_type required}"
SRC_DIR="$(cd "${2:?src_dir required}" && pwd)"
BUILD_DIR="$(cd "${3:?build_dir required}" && pwd)"
VERSION="${4:-1.0.0}"
PKG_RELEASE="${5:-1}"
SHARED="${SRC_DIR}/package/shared"
# Stage files common to both package types into a target directory.
stage_common() {
local dest="$1"
cp "${BUILD_DIR}/xrpld" "${dest}/xrpld"
cp "${SRC_DIR}/cfg/xrpld-example.cfg" "${dest}/xrpld.cfg"
cp "${SRC_DIR}/cfg/validators-example.txt" "${dest}/validators.txt"
cp "${SHARED}/xrpld.logrotate" "${dest}/xrpld.logrotate"
cp "${SHARED}/update-xrpld.sh" "${dest}/update-xrpld.sh"
cp "${SHARED}/update-xrpld-cron" "${dest}/update-xrpld-cron"
}
build_rpm() {
local topdir="${BUILD_DIR}/rpmbuild"
mkdir -p "${topdir}"/{BUILD,BUILDROOT,RPMS,SOURCES,SPECS,SRPMS}
cp "${BUILD_DIR}/package/rpm/xrpld.spec" "${topdir}/SPECS/xrpld.spec"
stage_common "${topdir}/SOURCES"
cp "${SHARED}/xrpld.service" "${topdir}/SOURCES/xrpld.service"
cp "${SHARED}/xrpld.sysusers" "${topdir}/SOURCES/xrpld.sysusers"
cp "${SHARED}/xrpld.tmpfiles" "${topdir}/SOURCES/xrpld.tmpfiles"
cp "${SRC_DIR}/LICENSE.md" "${topdir}/SOURCES/LICENSE.md"
cp "${SRC_DIR}/README.md" "${topdir}/SOURCES/README.md"
set -x
rpmbuild -bb \
--define "_topdir ${topdir}" \
"${topdir}/SPECS/xrpld.spec"
}
build_deb() {
local staging="${BUILD_DIR}/debbuild/source"
rm -rf "${staging}"
mkdir -p "${staging}"
stage_common "${staging}"
cp "${SRC_DIR}/README.md" "${staging}/"
cp "${SRC_DIR}/LICENSE.md" "${staging}/"
# debian/ control files
cp -r "${SRC_DIR}/package/deb/debian" "${staging}/debian"
# Shared support files for dh_installsystemd / sysusers / tmpfiles
cp "${SHARED}/xrpld.service" "${staging}/debian/xrpld.service"
cp "${SHARED}/xrpld.sysusers" "${staging}/debian/xrpld.sysusers"
cp "${SHARED}/xrpld.tmpfiles" "${staging}/debian/xrpld.tmpfiles"
# Generate debian/changelog (pre-release versions use ~ instead of -).
local deb_version="${VERSION//-/\~}"
# TODO: Add facility for generating the changelog
cat > "${staging}/debian/changelog" <<EOF
xrpld (${deb_version}-${PKG_RELEASE}) unstable; urgency=medium
* Release ${VERSION}.
-- XRPL Foundation <contact@xrplf.org> $(LC_ALL=C date -u -R)
EOF
chmod +x "${staging}/debian/rules"
set -x
( cd "${staging}" && dpkg-buildpackage -b --no-sign -d )
}
case "${PKG_TYPE}" in
rpm) build_rpm ;;
deb) build_deb ;;
*)
echo "Unknown package type: ${PKG_TYPE}" >&2
exit 1
;;
esac

View File

@@ -1,23 +0,0 @@
Source: xrpld
Section: net
Priority: optional
Maintainer: XRPL Foundation <contact@xrplf.org>
Rules-Requires-Root: no
Build-Depends:
debhelper-compat (= 13)
Standards-Version: 4.7.0
Homepage: https://github.com/XRPLF/rippled
Vcs-Git: https://github.com/XRPLF/rippled.git
Vcs-Browser: https://github.com/XRPLF/rippled
Package: xrpld
Section: net
Priority: optional
Architecture: any
Depends:
${shlibs:Depends},
${misc:Depends}
Description: XRP Ledger daemon
Reference implementation of the XRP Ledger protocol. Participates
in the peer-to-peer network, processes transactions, and maintains
a local ledger copy.

View File

@@ -1,20 +0,0 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: rippled
Source: https://github.com/XRPLF/rippled
Files: *
Copyright: 2012-2025 Ripple Labs Inc.
License: ISC
License: ISC
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

View File

@@ -1,35 +0,0 @@
#!/usr/bin/make -f
export DH_VERBOSE = 1
export DH_OPTIONS = -v
%:
dh $@
override_dh_auto_configure override_dh_auto_build override_dh_auto_test:
@:
override_dh_auto_install:
install -Dm0755 xrpld debian/tmp/opt/xrpld/bin/xrpld
install -Dm0644 xrpld.cfg debian/tmp/opt/xrpld/etc/xrpld.cfg
install -Dm0644 validators.txt debian/tmp/opt/xrpld/etc/validators.txt
install -Dm0644 xrpld.logrotate debian/tmp/opt/xrpld/bin/xrpld.logrotate
install -Dm0755 update-xrpld.sh debian/tmp/opt/xrpld/bin/update-xrpld.sh
install -Dm0644 update-xrpld-cron debian/tmp/opt/xrpld/bin/update-xrpld-cron
install -Dm0644 README.md debian/tmp/usr/share/doc/xrpld/README.md
install -Dm0644 LICENSE.md debian/tmp/usr/share/doc/xrpld/LICENSE.md
override_dh_installsystemd:
dh_installsystemd
override_dh_installsysusers:
dh_installsysusers
override_dh_installtmpfiles:
dh_installtmpfiles
override_dh_install:
dh_install
override_dh_dwz:
@:

View File

@@ -1 +0,0 @@
3.0 (quilt)

View File

@@ -1,2 +0,0 @@
/opt/xrpld/etc/xrpld.cfg
/opt/xrpld/etc/validators.txt

View File

@@ -1,10 +0,0 @@
opt/xrpld/bin/xrpld
opt/xrpld/bin/xrpld.logrotate
opt/xrpld/bin/update-xrpld.sh
opt/xrpld/bin/update-xrpld-cron
opt/xrpld/etc/xrpld.cfg
opt/xrpld/etc/validators.txt
usr/share/doc/xrpld/README.md
usr/share/doc/xrpld/LICENSE.md

View File

@@ -1,10 +0,0 @@
opt/xrpld/etc etc/opt/xrpld
opt/xrpld/bin/xrpld usr/bin/xrpld
## remove when "rippled" deprecated
opt/xrpld/bin/xrpld opt/xrpld/bin/rippled
opt/xrpld/bin/xrpld usr/local/bin/rippled
opt/xrpld/etc/xrpld.cfg opt/xrpld/etc/rippled.cfg
opt/xrpld opt/ripple
etc/opt/xrpld etc/opt/ripple

View File

@@ -1,121 +0,0 @@
%global xrpld_version @xrpld_version@
%global pkg_release @pkg_release@
%global _opt_prefix /opt/xrpld
%global ver_base %(v=%{xrpld_version}; echo ${v%%-*})
%global _has_dash %(v=%{xrpld_version}; [ "${v#*-}" != "$v" ] && echo 1 || echo 0)
%if 0%{?_has_dash}
%global ver_suffix %(v=%{xrpld_version}; printf %s "${v#*-}")
%endif
Name: xrpld
Version: %{ver_base}
Release: %{?ver_suffix:0.%{ver_suffix}.}%{pkg_release}%{?dist}
Summary: XRP Ledger daemon
License: ISC
URL: https://github.com/XRPLF/rippled
Source0: xrpld
Source1: xrpld.cfg
Source2: validators.txt
Source3: xrpld.service
Source4: xrpld.sysusers
Source5: xrpld.tmpfiles
Source6: xrpld.logrotate
Source7: update-xrpld.sh
Source8: update-xrpld-cron
Source9: LICENSE.md
Source10: README.md
ExclusiveArch: x86_64
BuildRequires: systemd-rpm-macros
%undefine _debugsource_packages
%debug_package
%{?systemd_requires}
%{?sysusers_requires_compat}
%description
xrpld is the reference implementation of the XRP Ledger protocol. It
participates in the peer-to-peer XRP Ledger network, processes
transactions, and maintains the ledger database.
%install
rm -rf %{buildroot}
# Suppress debugsource subpackage — no source files in the build tree.
touch %{_builddir}/debugsourcefiles.list
# Install binary and config files.
install -Dm0755 %{SOURCE0} %{buildroot}%{_opt_prefix}/bin/xrpld
install -Dm0644 %{SOURCE1} %{buildroot}%{_opt_prefix}/etc/xrpld.cfg
install -Dm0644 %{SOURCE2} %{buildroot}%{_opt_prefix}/etc/validators.txt
mkdir -p %{buildroot}/etc/opt %{buildroot}/usr/bin %{buildroot}/usr/local/bin
ln -s %{_opt_prefix}/etc %{buildroot}/etc/opt/xrpld
ln -s %{_opt_prefix}/bin/xrpld %{buildroot}/usr/bin/xrpld
## remove when "rippled" deprecated
ln -s xrpld %{buildroot}%{_opt_prefix}/bin/rippled
ln -s %{_opt_prefix}/bin/xrpld %{buildroot}/usr/local/bin/rippled
ln -s xrpld.cfg %{buildroot}%{_opt_prefix}/etc/rippled.cfg
ln -s %{_opt_prefix} %{buildroot}/opt/ripple
ln -s /etc/opt/xrpld %{buildroot}/etc/opt/ripple
# Install systemd/sysusers/tmpfiles support files.
install -Dm0644 %{SOURCE3} %{buildroot}%{_unitdir}/xrpld.service
install -Dm0644 %{SOURCE4} %{buildroot}%{_sysusersdir}/xrpld.conf
install -Dm0644 %{SOURCE5} %{buildroot}%{_tmpfilesdir}/xrpld.conf
install -Dm0644 %{SOURCE6} %{buildroot}%{_opt_prefix}/bin/xrpld.logrotate
install -Dm0755 %{SOURCE7} %{buildroot}%{_opt_prefix}/bin/update-xrpld.sh
install -Dm0644 %{SOURCE8} %{buildroot}%{_opt_prefix}/bin/update-xrpld-cron
# Install doc/license files.
install -Dm0644 %{SOURCE9} %{buildroot}%{_opt_prefix}/share/LICENSE.md
install -Dm0644 %{SOURCE10} %{buildroot}%{_opt_prefix}/share/README.md
%pre
%sysusers_create_compat %{SOURCE4}
%post
systemd-tmpfiles --create %{_tmpfilesdir}/xrpld.conf || :
%systemd_post xrpld.service
%preun
%systemd_preun xrpld.service
%postun
%systemd_postun_with_restart xrpld.service
%files
%license %{_opt_prefix}/share/LICENSE.md
%doc %{_opt_prefix}/share/README.md
%dir %{_opt_prefix}
%dir %{_opt_prefix}/bin
%dir %{_opt_prefix}/etc
%{_opt_prefix}/bin/xrpld
%{_opt_prefix}/bin/xrpld.logrotate
%{_opt_prefix}/bin/update-xrpld.sh
%{_opt_prefix}/bin/update-xrpld-cron
/usr/bin/xrpld
/etc/opt/xrpld
%config(noreplace) %{_opt_prefix}/etc/xrpld.cfg
%config(noreplace) %{_opt_prefix}/etc/validators.txt
%{_unitdir}/xrpld.service
%{_sysusersdir}/xrpld.conf
%{_tmpfilesdir}/xrpld.conf
%ghost %dir /var/lib/xrpld
%ghost %dir /var/log/xrpld
# TODO: remove when rippled deprecated
%{_opt_prefix}/bin/rippled
/usr/local/bin/rippled
%{_opt_prefix}/etc/rippled.cfg
/etc/opt/ripple
/opt/ripple

View File

@@ -1,9 +0,0 @@
# For automatic updates, symlink this file to /etc/cron.d/
# Do not remove the newline at the end of this cron script
# bash required for use of RANDOM below.
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
# invoke check/update script with random delay up to 59 mins
0 * * * * root sleep $((RANDOM*3540/32768)) && /opt/xrpld/bin/update-xrpld.sh

View File

@@ -1,74 +0,0 @@
#!/usr/bin/env bash
# auto-update script for xrpld daemon
# Check for sudo/root permissions
if [[ $(id -u) -ne 0 ]] ; then
echo "This update script must be run as root or sudo"
exit 1
fi
LOCKDIR=/run/lock/xrpld-update.lock
UPDATELOG=/var/log/xrpld/update.log
function cleanup {
# If this directory isn't removed, future updates will fail.
rmdir "$LOCKDIR"
}
# Use mkdir to check if process is already running. mkdir is atomic, as against file create.
if ! mkdir "$LOCKDIR" 2>/dev/null; then
echo "$(date -u) lockdir exists - won't proceed." >> "$UPDATELOG"
exit 1
fi
trap cleanup EXIT
can_update=false
if command -v apt-get &>/dev/null; then
apt-get update -qq
if apt-get -s --only-upgrade install xrpld 2>/dev/null | grep -q '^Inst xrpld'; then
can_update=true
fi
function apply_update {
DEBIAN_FRONTEND=noninteractive apt-get install -y -qq xrpld
}
elif command -v yum &>/dev/null; then
REPO=${REPO:-stable}
if [[ ! "$REPO" =~ ^(stable|unstable|nightly|develop)$ ]]; then
echo "Invalid REPO value: ${REPO}" >&2
exit 1
fi
yum --disablerepo=* --enablerepo="ripple-${REPO}" clean expire-cache
# yum check-update exits 100 when updates are available, 0 for none, 1 for errors.
yum check-update -q --enablerepo="ripple-${REPO}" xrpld
rc=$?
if [ $rc -eq 100 ]; then
can_update=true
elif [ $rc -ne 0 ]; then
echo "yum check-update failed with exit code $rc"
exit 1
fi
function apply_update {
yum update -y --enablerepo="ripple-${REPO}" xrpld
}
else
echo "No supported package manager found (apt-get or yum)"
exit 1
fi
# Do the actual update and restart the service after reloading systemctl daemon.
if [ "$can_update" = true ] ; then
exec >>"${UPDATELOG}" 2>&1
set -e
apply_update
systemctl daemon-reload
systemctl restart xrpld.service
echo "$(date -u) xrpld daemon updated."
else
echo "$(date -u) no updates available" >> "$UPDATELOG"
fi

View File

@@ -1,15 +0,0 @@
/var/log/xrpld/*.log {
daily
minsize 200M
rotate 7
nocreate
missingok
notifempty
compress
compresscmd /usr/bin/nice
compressoptions -n19 ionice -c3 gzip
compressext .gz
postrotate
/opt/xrpld/bin/xrpld --conf /etc/opt/xrpld/xrpld.cfg logrotate
endscript
}

View File

@@ -1,21 +0,0 @@
[Unit]
Description=XRP Ledger Daemon
After=network-online.target
Wants=network-online.target
StartLimitIntervalSec=60
StartLimitBurst=3
[Service]
Type=simple
ExecStart=/opt/xrpld/bin/xrpld --net --silent --conf /etc/opt/xrpld/xrpld.cfg
Restart=on-failure
RestartSec=5
NoNewPrivileges=true
ProtectSystem=full
PrivateTmp=true
User=xrpld
Group=xrpld
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target

View File

@@ -1 +0,0 @@
u xrpld - "XRP Ledger daemon" /var/lib/xrpld /sbin/nologin

View File

@@ -1,2 +0,0 @@
d /var/lib/xrpld 0750 xrpld xrpld -
d /var/log/xrpld 0750 xrpld xrpld -

View File

@@ -1,45 +0,0 @@
#!/usr/bin/env sh
# Validate installed paths and compat symlinks for xrpld packages.
set -e
set -x
trap 'test $? -ne 0 && touch /tmp/test_failed' EXIT
check() { test $1 "$2" || { echo "FAIL: $1 $2"; exit 1; }; }
check_resolves_to() {
actual=$(readlink -f "$1")
[ "$actual" = "$2" ] || { echo "FAIL: $1 resolves to $actual, expected $2"; exit 1; }
}
# compat directory symlinks — existence and resolved target
check -L /opt/ripple
check_resolves_to /opt/ripple /opt/xrpld
check -L /etc/opt/xrpld
check_resolves_to /etc/opt/xrpld /opt/xrpld/etc
check -L /etc/opt/ripple
check_resolves_to /etc/opt/ripple /opt/xrpld/etc
# config accessible via all expected paths
check -f /opt/xrpld/etc/xrpld.cfg
check -f /opt/xrpld/etc/rippled.cfg
check -f /etc/opt/xrpld/xrpld.cfg
check -f /etc/opt/xrpld/rippled.cfg
check -f /etc/opt/ripple/xrpld.cfg
check -f /etc/opt/ripple/rippled.cfg
if systemctl is-system-running >/dev/null 2>&1; then
# service file sanity check
SERVICE=$(systemctl cat xrpld)
echo "$SERVICE" | grep -q 'ExecStart=/opt/xrpld/bin/xrpld' || { echo "FAIL: ExecStart wrong"; echo "$SERVICE"; exit 1; }
echo "$SERVICE" | grep -q 'User=xrpld' || { echo "FAIL: User not xrpld"; echo "$SERVICE"; exit 1; }
fi
# binary accessible via all expected paths
/opt/xrpld/bin/xrpld --version
/opt/xrpld/bin/rippled --version
/opt/ripple/bin/xrpld --version
/opt/ripple/bin/rippled --version
/usr/bin/xrpld --version
/usr/local/bin/rippled --version

View File

@@ -1,88 +0,0 @@
#!/usr/bin/env bash
# Install a locally-built package and run basic verification.
#
# Usage: smoketest.sh local
# Expects packages in build/{dpkg,rpm}/packages/ or build/debbuild/ / build/rpmbuild/RPMS/
set -o pipefail
set -x
rm -f /tmp/test_failed /tmp/unittest_results
trap 'test $? -ne 0 && touch /tmp/test_failed' EXIT
install_from=$1
. /etc/os-release
case ${ID} in
ubuntu|debian)
pkgtype="dpkg"
;;
fedora|centos|rhel|rocky|almalinux)
pkgtype="rpm"
;;
*)
echo "unrecognized distro!"
exit 1
;;
esac
if [ "${install_from}" != "local" ]; then
echo "only 'local' install mode is supported"
exit 1
fi
# Install the package
if [ "${pkgtype}" = "dpkg" ] ; then
apt-get -y update
# Find .deb files — check both possible output locations
mapfile -t debs < <(find build/debbuild/ build/dpkg/packages/ -name '*.deb' ! -name '*dbgsym*' 2>/dev/null)
if [ ${#debs[@]} -eq 0 ]; then
echo "No .deb files found"
exit 1
fi
dpkg --no-debsig -i "${debs[@]}" || apt-get -y install -f
elif [ "${pkgtype}" = "rpm" ] ; then
# Find .rpm files — check both possible output locations
mapfile -t rpms < <(find build/rpmbuild/RPMS/ build/rpm/packages/ -name '*.rpm' \
! -name '*debug*' ! -name '*devel*' ! -name '*.src.rpm' 2>/dev/null)
if [ ${#rpms[@]} -eq 0 ]; then
echo "No .rpm files found"
exit 1
fi
rpm -i "${rpms[@]}"
fi
# Verify installed version
VERSION_OUTPUT=$(/opt/xrpld/bin/xrpld --version)
INSTALLED=$(echo "$VERSION_OUTPUT" | head -1 | awk '{print $NF}')
echo "Installed version: ${INSTALLED}"
# Run unit tests
if [ -n "${CI:-}" ]; then
unittest_jobs=$(nproc)
else
unittest_jobs=16
fi
(
cd /tmp
/opt/xrpld/bin/xrpld --unittest --unittest-jobs "${unittest_jobs}" > /tmp/unittest_results || true
)
if [ ! -s /tmp/unittest_results ]; then
echo "Unit test results file is empty — xrpld may have crashed"
exit 1
fi
num_failures=$(tail /tmp/unittest_results -n1 | grep -oP '\d+(?= failures)')
if [ -z "$num_failures" ]; then
echo "Could not parse unit test results — expected summary line not found"
exit 1
fi
if [ "${num_failures}" -ne 0 ]; then
echo "$num_failures unit test(s) failed:"
grep 'failed:' /tmp/unittest_results
exit 1
fi
# Compat path checks
"$(dirname "${BASH_SOURCE[0]}")/check_install_paths.sh"

View File

@@ -85,7 +85,12 @@ public:
}
virtual void
acquireAsync(uint256 const& hash, std::uint32_t seq, InboundLedger::Reason reason) override
acquireAsync(
JobType type,
std::string const& name,
uint256 const& hash,
std::uint32_t seq,
InboundLedger::Reason reason) override
{
}

View File

@@ -0,0 +1,165 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012-2016 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <xrpl/basics/CanProcess.h>
#include <xrpl/beast/unit_test.h>
#include <memory>
namespace ripple {
namespace test {
struct CanProcess_test : beast::unit_test::suite
{
template <class Mutex, class Collection, class Item>
void
test(
std::string const& name,
Mutex& mtx,
Collection& collection,
std::vector<Item> const& items)
{
testcase(name);
if (!BEAST_EXPECT(!items.empty()))
return;
if (!BEAST_EXPECT(collection.empty()))
return;
// CanProcess objects can't be copied or moved. To make that easier,
// store shared_ptrs
std::vector<std::shared_ptr<CanProcess>> trackers;
// Fill up the vector with two CanProcess for each Item. The first
// inserts the item into the collection and is "good". The second does
// not and is "bad".
for (int i = 0; i < items.size(); ++i)
{
{
auto const& good =
trackers.emplace_back(std::make_shared<CanProcess>(mtx, collection, items[i]));
BEAST_EXPECT(*good);
}
BEAST_EXPECT(trackers.size() == (2 * i) + 1);
BEAST_EXPECT(collection.size() == i + 1);
{
auto const& bad =
trackers.emplace_back(std::make_shared<CanProcess>(mtx, collection, items[i]));
BEAST_EXPECT(!*bad);
}
BEAST_EXPECT(trackers.size() == 2 * (i + 1));
BEAST_EXPECT(collection.size() == i + 1);
}
BEAST_EXPECT(collection.size() == items.size());
// Now remove the items from the vector<CanProcess> two at a time, and
// try to get another CanProcess for that item.
for (int i = 0; i < items.size(); ++i)
{
// Remove the "bad" one in the second position
// This will have no effect on the collection
{
auto const iter = trackers.begin() + 1;
BEAST_EXPECT(!**iter);
trackers.erase(iter);
}
BEAST_EXPECT(trackers.size() == (2 * items.size()) - 1);
BEAST_EXPECT(collection.size() == items.size());
{
// Append a new "bad" one
auto const& bad =
trackers.emplace_back(std::make_shared<CanProcess>(mtx, collection, items[i]));
BEAST_EXPECT(!*bad);
}
BEAST_EXPECT(trackers.size() == 2 * items.size());
BEAST_EXPECT(collection.size() == items.size());
// Remove the "good" one from the front
{
auto const iter = trackers.begin();
BEAST_EXPECT(**iter);
trackers.erase(iter);
}
BEAST_EXPECT(trackers.size() == (2 * items.size()) - 1);
BEAST_EXPECT(collection.size() == items.size() - 1);
{
// Append a new "good" one
auto const& good =
trackers.emplace_back(std::make_shared<CanProcess>(mtx, collection, items[i]));
BEAST_EXPECT(*good);
}
BEAST_EXPECT(trackers.size() == 2 * items.size());
BEAST_EXPECT(collection.size() == items.size());
}
// Now remove them all two at a time
for (int i = items.size() - 1; i >= 0; --i)
{
// Remove the "bad" one from the front
{
auto const iter = trackers.begin();
BEAST_EXPECT(!**iter);
trackers.erase(iter);
}
BEAST_EXPECT(trackers.size() == (2 * i) + 1);
BEAST_EXPECT(collection.size() == i + 1);
// Remove the "good" one now in front
{
auto const iter = trackers.begin();
BEAST_EXPECT(**iter);
trackers.erase(iter);
}
BEAST_EXPECT(trackers.size() == 2 * i);
BEAST_EXPECT(collection.size() == i);
}
BEAST_EXPECT(trackers.empty());
BEAST_EXPECT(collection.empty());
}
void
run() override
{
{
std::mutex m;
std::set<int> collection;
std::vector<int> const items{1, 2, 3, 4, 5};
test("set of int", m, collection, items);
}
{
std::mutex m;
std::set<std::string> collection;
std::vector<std::string> const items{"one", "two", "three", "four", "five"};
test("set of string", m, collection, items);
}
{
std::mutex m;
std::unordered_set<char> collection;
std::vector<char> const items{'1', '2', '3', '4', '5'};
test("unorderd_set of char", m, collection, items);
}
{
std::mutex m;
std::unordered_set<std::uint64_t> collection;
std::vector<std::uint64_t> const items{100u, 1000u, 150u, 4u, 0u};
test("unordered_set of uint64_t", m, collection, items);
}
}
};
BEAST_DEFINE_TESTSUITE(CanProcess, ripple_basics, ripple);
} // namespace test
} // namespace ripple

View File

@@ -105,10 +105,8 @@ RCLConsensus::Adaptor::acquireLedger(LedgerHash const& hash)
// Tell the ledger acquire system that we need the consensus ledger
acquiringLedger_ = hash;
app_.getJobQueue().addJob(jtADVANCE, "GetConsL1", [id = hash, &app = app_, this]() {
JLOG(j_.debug()) << "JOB advanceLedger getConsensusLedger1 started";
app.getInboundLedgers().acquireAsync(id, 0, InboundLedger::Reason::CONSENSUS);
});
app_.getInboundLedgers().acquireAsync(
jtADVANCE, "GetConsL1", hash, 0, InboundLedger::Reason::CONSENSUS);
}
return std::nullopt;
}
@@ -998,7 +996,7 @@ void
RCLConsensus::Adaptor::updateOperatingMode(std::size_t const positions) const
{
if ((positions == 0u) && app_.getOPs().isFull())
app_.getOPs().setMode(OperatingMode::CONNECTED);
app_.getOPs().setMode(OperatingMode::CONNECTED, "updateOperatingMode: no positions");
}
void

View File

@@ -116,12 +116,8 @@ RCLValidationsAdaptor::acquire(LedgerHash const& hash)
{
JLOG(j_.warn()) << "Need validated ledger for preferred ledger analysis " << hash;
Application* pApp = &app_;
app_.getJobQueue().addJob(jtADVANCE, "GetConsL2", [pApp, hash, this]() {
JLOG(j_.debug()) << "JOB advanceLedger getConsensusLedger2 started";
pApp->getInboundLedgers().acquireAsync(hash, 0, InboundLedger::Reason::CONSENSUS);
});
app_.getInboundLedgers().acquireAsync(
jtADVANCE, "GetConsL2", hash, 0, InboundLedger::Reason::CONSENSUS);
return std::nullopt;
}

View File

@@ -26,7 +26,12 @@ public:
// Queue. TODO review whether all callers of acquire() can use this
// instead. Inbound ledger acquisition is asynchronous anyway.
virtual void
acquireAsync(uint256 const& hash, std::uint32_t seq, InboundLedger::Reason reason) = 0;
acquireAsync(
JobType type,
std::string const& name,
uint256 const& hash,
std::uint32_t seq,
InboundLedger::Reason reason) = 0;
virtual std::shared_ptr<InboundLedger>
find(LedgerHash const& hash) = 0;

View File

@@ -359,7 +359,14 @@ InboundLedger::onTimer(bool wasProgress, ScopedLockType&)
if (!wasProgress)
{
checkLocal();
if (checkLocal())
{
// Done. Something else (probably consensus) built the ledger
// locally while waiting for data (or possibly before requesting)
XRPL_ASSERT(isDone(), "ripple::InboundLedger::onTimer : done");
JLOG(journal_.info()) << "Finished while waiting " << hash_;
return;
}
mByHash = true;

View File

@@ -2,6 +2,7 @@
#include <xrpld/app/ledger/LedgerMaster.h>
#include <xrpld/app/main/Application.h>
#include <xrpl/basics/CanProcess.h>
#include <xrpl/basics/DecayingSample.h>
#include <xrpl/basics/scope.h>
#include <xrpl/beast/container/aged_map.h>
@@ -58,12 +59,15 @@ public:
(reason != InboundLedger::Reason::CONSENSUS))
return {};
std::stringstream ss;
bool isNew = true;
std::shared_ptr<InboundLedger> inbound;
{
ScopedLockType sl(mLock);
if (stopping_)
{
JLOG(j_.debug()) << "Abort(stopping): " << ss.str();
return {};
}
@@ -82,47 +86,61 @@ public:
++mCounter;
}
}
ss << " IsNew: " << (isNew ? "true" : "false");
if (inbound->isFailed())
{
JLOG(j_.debug()) << "Abort(failed): " << ss.str();
return {};
}
if (!isNew)
inbound->update(seq);
if (!inbound->isComplete())
{
JLOG(j_.debug()) << "InProgress: " << ss.str();
return {};
}
JLOG(j_.debug()) << "Complete: " << ss.str();
return inbound->getLedger();
};
using namespace std::chrono_literals;
std::shared_ptr<Ledger const> ledger =
perf::measureDurationAndLog(doAcquire, "InboundLedgersImp::acquire", 500ms, j_);
return ledger;
return perf::measureDurationAndLog(doAcquire, "InboundLedgersImp::acquire", 500ms, j_);
}
void
acquireAsync(uint256 const& hash, std::uint32_t seq, InboundLedger::Reason reason) override
acquireAsync(
JobType type,
std::string const& name,
uint256 const& hash,
std::uint32_t seq,
InboundLedger::Reason reason) override
{
std::unique_lock lock(acquiresMutex_);
try
if (auto check = std::make_shared<CanProcess const>(acquiresMutex_, pendingAcquires_, hash);
*check)
{
if (pendingAcquires_.contains(hash))
return;
pendingAcquires_.insert(hash);
scope_unlock unlock(lock);
acquire(hash, seq, reason);
app_.getJobQueue().addJob(type, name, [check, name, hash, seq, reason, this]() {
JLOG(j_.debug()) << "JOB acquireAsync " << name << " started ";
try
{
acquire(hash, seq, reason);
}
catch (std::exception const& e)
{
JLOG(j_.warn()) << "Exception thrown for acquiring new "
"inbound ledger "
<< hash << ": " << e.what();
}
catch (...)
{
JLOG(j_.warn()) << "Unknown exception thrown for acquiring new "
"inbound ledger "
<< hash;
}
});
}
catch (std::exception const& e)
{
JLOG(j_.warn()) << "Exception thrown for acquiring new inbound ledger " << hash << ": "
<< e.what();
}
catch (...)
{
JLOG(j_.warn()) << "Unknown exception thrown for acquiring new inbound ledger " << hash;
}
pendingAcquires_.erase(hash);
}
std::shared_ptr<InboundLedger>

View File

@@ -923,8 +923,9 @@ LedgerMaster::checkAccept(std::shared_ptr<Ledger const> const& ledger)
return;
}
JLOG(m_journal.info()) << "Advancing accepted ledger to " << ledger->header().seq
<< " with >= " << minVal << " validations";
JLOG(m_journal.info()) << "Advancing accepted ledger to " << ledger->header().seq << " ("
<< to_short_string(ledger->header().hash) << ") with >= " << minVal
<< " validations";
ledger->setValidated();
ledger->setFull();

View File

@@ -13,7 +13,8 @@ TimeoutCounter::TimeoutCounter(
QueueJobParameter&& jobParameter,
beast::Journal journal)
: app_(app)
, journal_(journal)
, sink_(journal, to_short_string(hash) + " ")
, journal_(sink_)
, hash_(hash)
, timeouts_(0)
, complete_(false)
@@ -33,6 +34,7 @@ TimeoutCounter::setTimer(ScopedLockType& sl)
{
if (isDone())
return;
JLOG(journal_.debug()) << "Setting timer for " << timerInterval_.count() << "ms";
timer_.expires_after(timerInterval_);
timer_.async_wait([wptr = pmDowncast()](boost::system::error_code const& ec) {
if (ec == boost::asio::error::operation_aborted)
@@ -40,6 +42,10 @@ TimeoutCounter::setTimer(ScopedLockType& sl)
if (auto ptr = wptr.lock())
{
JLOG(ptr->journal_.debug())
<< "timer: ec: " << ec
<< " (operation_aborted: " << boost::asio::error::operation_aborted << " - "
<< (ec == boost::asio::error::operation_aborted ? "aborted" : "other") << ")";
ScopedLockType sl(ptr->mtx_);
ptr->queueJob(sl);
}

View File

@@ -3,6 +3,7 @@
#include <xrpld/app/main/Application.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/beast/utility/WrappedSink.h>
#include <xrpl/core/Job.h>
#include <boost/asio/basic_waitable_timer.hpp>
@@ -103,6 +104,7 @@ protected:
// Used in this class for access to boost::asio::io_context and
// xrpl::Overlay. Used in subtypes for the kitchen sink.
Application& app_;
beast::WrappedSink sink_;
beast::Journal journal_;
mutable std::recursive_mutex mtx_;

View File

@@ -30,10 +30,10 @@
#include <xrpld/rpc/MPTokenIssuanceID.h>
#include <xrpld/rpc/ServerHandler.h>
#include <xrpl/basics/CanProcess.h>
#include <xrpl/basics/UptimeClock.h>
#include <xrpl/basics/mulDiv.h>
#include <xrpl/basics/safe_cast.h>
#include <xrpl/basics/scope.h>
#include <xrpl/beast/utility/rngfill.h>
#include <xrpl/core/HashRouter.h>
#include <xrpl/core/NetworkIDService.h>
@@ -401,7 +401,7 @@ public:
isFull() override;
void
setMode(OperatingMode om) override;
setMode(OperatingMode om, char const* reason) override;
bool
isBlocked() override;
@@ -839,7 +839,7 @@ NetworkOPsImp::strOperatingMode(bool const admin /* = false */) const
inline void
NetworkOPsImp::setStandAlone()
{
setMode(OperatingMode::FULL);
setMode(OperatingMode::FULL, "setStandAlone");
}
inline void
@@ -982,7 +982,7 @@ NetworkOPsImp::processHeartbeatTimer()
{
if (mMode != OperatingMode::DISCONNECTED)
{
setMode(OperatingMode::DISCONNECTED);
setMode(OperatingMode::DISCONNECTED, "Heartbeat: insufficient peers");
std::stringstream ss;
ss << "Node count (" << numPeers << ") has fallen "
<< "below required minimum (" << minPeerCount_ << ").";
@@ -1006,7 +1006,7 @@ NetworkOPsImp::processHeartbeatTimer()
if (mMode == OperatingMode::DISCONNECTED)
{
setMode(OperatingMode::CONNECTED);
setMode(OperatingMode::CONNECTED, "Heartbeat: sufficient peers");
JLOG(m_journal.info()) << "Node count (" << numPeers << ") is sufficient.";
CLOG(clog.ss()) << "setting mode to CONNECTED based on " << numPeers << " peers. ";
}
@@ -1017,11 +1017,11 @@ NetworkOPsImp::processHeartbeatTimer()
CLOG(clog.ss()) << "mode: " << strOperatingMode(origMode, true);
if (mMode == OperatingMode::SYNCING)
{
setMode(OperatingMode::SYNCING);
setMode(OperatingMode::SYNCING, "Heartbeat: check syncing");
}
else if (mMode == OperatingMode::CONNECTED)
{
setMode(OperatingMode::CONNECTED);
setMode(OperatingMode::CONNECTED, "Heartbeat: check connected");
}
auto newMode = mMode.load();
if (origMode != newMode)
@@ -1726,7 +1726,7 @@ void
NetworkOPsImp::setAmendmentBlocked()
{
amendmentBlocked_ = true;
setMode(OperatingMode::CONNECTED);
setMode(OperatingMode::CONNECTED, "setAmendmentBlocked");
}
inline bool
@@ -1757,7 +1757,7 @@ void
NetworkOPsImp::setUNLBlocked()
{
unlBlocked_ = true;
setMode(OperatingMode::CONNECTED);
setMode(OperatingMode::CONNECTED, "setUNLBlocked");
}
inline void
@@ -1857,7 +1857,7 @@ NetworkOPsImp::checkLastClosedLedger(Overlay::PeerSequence const& peerList, uint
if ((mMode == OperatingMode::TRACKING) || (mMode == OperatingMode::FULL))
{
setMode(OperatingMode::CONNECTED);
setMode(OperatingMode::CONNECTED, "check LCL: not on consensus ledger");
}
if (consensus)
@@ -1945,8 +1945,8 @@ NetworkOPsImp::beginConsensus(
// this shouldn't happen unless we jump ledgers
if (mMode == OperatingMode::FULL)
{
JLOG(m_journal.warn()) << "Don't have LCL, going to tracking";
setMode(OperatingMode::TRACKING);
JLOG(m_journal.warn()) << "beginConsensus Don't have LCL, going to tracking";
setMode(OperatingMode::TRACKING, "beginConsensus: No LCL");
CLOG(clog) << "beginConsensus Don't have LCL, going to tracking. ";
}
@@ -2074,7 +2074,7 @@ NetworkOPsImp::endConsensus(std::unique_ptr<std::stringstream> const& clog)
// validations we have for LCL. If the ledger is good enough, go to
// TRACKING - TODO
if (!needNetworkLedger_)
setMode(OperatingMode::TRACKING);
setMode(OperatingMode::TRACKING, "endConsensus: check tracking");
}
if (((mMode == OperatingMode::CONNECTED) || (mMode == OperatingMode::TRACKING)) &&
@@ -2087,7 +2087,7 @@ NetworkOPsImp::endConsensus(std::unique_ptr<std::stringstream> const& clog)
if (registry_.get().getTimeKeeper().now() <
(current->header().parentCloseTime + 2 * current->header().closeTimeResolution))
{
setMode(OperatingMode::FULL);
setMode(OperatingMode::FULL, "endConsensus: check full");
}
}
@@ -2099,7 +2099,7 @@ NetworkOPsImp::consensusViewChange()
{
if ((mMode == OperatingMode::FULL) || (mMode == OperatingMode::TRACKING))
{
setMode(OperatingMode::CONNECTED);
setMode(OperatingMode::CONNECTED, "consensusViewChange");
}
}
@@ -2403,7 +2403,7 @@ NetworkOPsImp::pubPeerStatus(std::function<Json::Value(void)> const& func)
}
void
NetworkOPsImp::setMode(OperatingMode om)
NetworkOPsImp::setMode(OperatingMode om, char const* reason)
{
using namespace std::chrono_literals;
if (om == OperatingMode::CONNECTED)
@@ -2423,11 +2423,12 @@ NetworkOPsImp::setMode(OperatingMode om)
if (mMode == om)
return;
auto const sink = om < mMode ? m_journal.warn() : m_journal.info();
mMode = om;
accounting_.mode(om);
JLOG(m_journal.info()) << "STATE->" << strOperatingMode();
JLOG(sink) << "STATE->" << strOperatingMode() << " - " << reason;
pubServer();
}
@@ -2436,36 +2437,24 @@ NetworkOPsImp::recvValidation(std::shared_ptr<STValidation> const& val, std::str
{
JLOG(m_journal.trace()) << "recvValidation " << val->getLedgerHash() << " from " << source;
std::unique_lock lock(validationsMutex_);
BypassAccept bypassAccept = BypassAccept::no;
try
{
if (pendingValidations_.contains(val->getLedgerHash()))
CanProcess const check(validationsMutex_, pendingValidations_, val->getLedgerHash());
try
{
bypassAccept = BypassAccept::yes;
BypassAccept bypassAccept = check ? BypassAccept::no : BypassAccept::yes;
handleNewValidation(registry_.app(), val, source, bypassAccept, m_journal);
}
else
catch (std::exception const& e)
{
pendingValidations_.insert(val->getLedgerHash());
JLOG(m_journal.warn()) << "Exception thrown for handling new validation "
<< val->getLedgerHash() << ": " << e.what();
}
catch (...)
{
JLOG(m_journal.warn())
<< "Unknown exception thrown for handling new validation " << val->getLedgerHash();
}
scope_unlock unlock(lock);
handleNewValidation(registry_.get().getApp(), val, source, bypassAccept, m_journal);
}
catch (std::exception const& e)
{
JLOG(m_journal.warn()) << "Exception thrown for handling new validation "
<< val->getLedgerHash() << ": " << e.what();
}
catch (...)
{
JLOG(m_journal.warn()) << "Unknown exception thrown for handling new validation "
<< val->getLedgerHash();
}
if (bypassAccept == BypassAccept::no)
{
pendingValidations_.erase(val->getLedgerHash());
}
lock.unlock();
pubValidation(val);