Compare commits

..

14 Commits

Author SHA1 Message Date
Ayaz Salikhov
89707d9668 ci: Run clang-tidy 3 times to make sure we don't have to fix again (#2803) 2025-11-24 12:19:34 +00:00
Ayaz Salikhov
ae260d1229 chore: Update spdlog and fmt libraries (#2804) 2025-11-24 11:27:29 +00:00
dependabot[bot]
058c05cfb6 ci: [DEPENDABOT] Bump actions/checkout from 5.0.0 to 6.0.0 (#2806)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-24 09:59:28 +00:00
dependabot[bot]
b2a7d185cb ci: [DEPENDABOT] Bump peter-evans/create-pull-request from 7.0.8 to 7.0.9 (#2805)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-24 09:58:51 +00:00
github-actions[bot]
9ea61ba6b9 style: clang-tidy auto fixes (#2801)
Co-authored-by: mathbunnyru <12270691+mathbunnyru@users.noreply.github.com>
2025-11-21 11:27:40 +00:00
github-actions[bot]
19157dec74 style: clang-tidy auto fixes (#2799)
Co-authored-by: mathbunnyru <12270691+mathbunnyru@users.noreply.github.com>
2025-11-21 11:02:07 +00:00
github-actions[bot]
42a6f516dc style: clang-tidy auto fixes (#2797) 2025-11-21 10:17:56 +00:00
emrearıyürek
2cd8226a11 refactor: Make getLedgerIndex return std::expected instead of throwing (#2788)
Co-authored-by: Ayaz Salikhov <mathbunnyru@users.noreply.github.com>
Co-authored-by: Sergey Kuznetsov <kuzzz99@gmail.com>
2025-11-20 17:46:15 +00:00
Sergey Kuznetsov
e3170203de fix: Print cache saving error (#2794) 2025-11-20 14:48:42 +00:00
Ayaz Salikhov
8b280e7742 ci: Always upload cache on develop (#2793) 2025-11-19 20:42:18 +00:00
Ayaz Salikhov
7ed30bc40d ci: Don't download ccache on develop branch (#2792) 2025-11-19 19:32:12 +00:00
Sergey Kuznetsov
ac608004bc docs: Fix graceful_period description (#2791) 2025-11-19 19:17:44 +00:00
Alex Kremer
6ab92ca0a6 chore: Enable TSAN in CI (#2785) 2025-11-19 18:06:33 +00:00
Alex Kremer
77387d8f9f chore: Add defines for asan/tsan to conan profile (#2784)
Co-authored-by: Ayaz Salikhov <mathbunnyru@users.noreply.github.com>
2025-11-19 17:28:10 +00:00
54 changed files with 381 additions and 173 deletions

View File

@@ -4,7 +4,7 @@ import json
LINUX_OS = ["heavy", "heavy-arm64"] LINUX_OS = ["heavy", "heavy-arm64"]
LINUX_CONTAINERS = [ LINUX_CONTAINERS = [
'{ "image": "ghcr.io/xrplf/clio-ci:62369411404eb32b0140603a785ff05e1dc36ce8" }' '{ "image": "ghcr.io/xrplf/clio-ci:77387d8f9f13aea8f23831d221ac3e7683bb69b7" }'
] ]
LINUX_COMPILERS = ["gcc", "clang"] LINUX_COMPILERS = ["gcc", "clang"]

View File

@@ -48,7 +48,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
- name: Download Clio binary from artifact - name: Download Clio binary from artifact
if: ${{ inputs.artifact_name != null }} if: ${{ inputs.artifact_name != null }}

View File

@@ -49,7 +49,7 @@ jobs:
build_type: [Release, Debug] build_type: [Release, Debug]
container: container:
[ [
'{ "image": "ghcr.io/xrplf/clio-ci:62369411404eb32b0140603a785ff05e1dc36ce8" }', '{ "image": "ghcr.io/xrplf/clio-ci:77387d8f9f13aea8f23831d221ac3e7683bb69b7" }',
] ]
static: [true] static: [true]
@@ -79,7 +79,7 @@ jobs:
uses: ./.github/workflows/reusable-build.yml uses: ./.github/workflows/reusable-build.yml
with: with:
runs_on: heavy runs_on: heavy
container: '{ "image": "ghcr.io/xrplf/clio-ci:62369411404eb32b0140603a785ff05e1dc36ce8" }' container: '{ "image": "ghcr.io/xrplf/clio-ci:77387d8f9f13aea8f23831d221ac3e7683bb69b7" }'
conan_profile: gcc conan_profile: gcc
build_type: Debug build_type: Debug
download_ccache: true download_ccache: true
@@ -98,7 +98,7 @@ jobs:
uses: ./.github/workflows/reusable-build.yml uses: ./.github/workflows/reusable-build.yml
with: with:
runs_on: heavy runs_on: heavy
container: '{ "image": "ghcr.io/xrplf/clio-ci:62369411404eb32b0140603a785ff05e1dc36ce8" }' container: '{ "image": "ghcr.io/xrplf/clio-ci:77387d8f9f13aea8f23831d221ac3e7683bb69b7" }'
conan_profile: gcc conan_profile: gcc
build_type: Release build_type: Release
download_ccache: true download_ccache: true
@@ -115,10 +115,10 @@ jobs:
needs: build-and-test needs: build-and-test
runs-on: heavy runs-on: heavy
container: container:
image: ghcr.io/xrplf/clio-ci:62369411404eb32b0140603a785ff05e1dc36ce8 image: ghcr.io/xrplf/clio-ci:77387d8f9f13aea8f23831d221ac3e7683bb69b7
steps: steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 - uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
with: with:

View File

@@ -21,10 +21,10 @@ jobs:
name: Build Clio / `libXRPL ${{ github.event.client_payload.version }}` name: Build Clio / `libXRPL ${{ github.event.client_payload.version }}`
runs-on: heavy runs-on: heavy
container: container:
image: ghcr.io/xrplf/clio-ci:62369411404eb32b0140603a785ff05e1dc36ce8 image: ghcr.io/xrplf/clio-ci:77387d8f9f13aea8f23831d221ac3e7683bb69b7
steps: steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
with: with:
fetch-depth: 0 fetch-depth: 0
@@ -69,7 +69,7 @@ jobs:
needs: build needs: build
runs-on: heavy runs-on: heavy
container: container:
image: ghcr.io/xrplf/clio-ci:62369411404eb32b0140603a785ff05e1dc36ce8 image: ghcr.io/xrplf/clio-ci:77387d8f9f13aea8f23831d221ac3e7683bb69b7
steps: steps:
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 - uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
@@ -92,7 +92,7 @@ jobs:
issues: write issues: write
steps: steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
- name: Create an issue - name: Create an issue
uses: ./.github/actions/create-issue uses: ./.github/actions/create-issue

View File

@@ -31,7 +31,7 @@ jobs:
if: github.event_name != 'push' || contains(github.event.head_commit.message, 'clang-tidy auto fixes') if: github.event_name != 'push' || contains(github.event.head_commit.message, 'clang-tidy auto fixes')
runs-on: heavy runs-on: heavy
container: container:
image: ghcr.io/xrplf/clio-ci:62369411404eb32b0140603a785ff05e1dc36ce8 image: ghcr.io/xrplf/clio-ci:77387d8f9f13aea8f23831d221ac3e7683bb69b7
permissions: permissions:
contents: write contents: write
@@ -39,7 +39,7 @@ jobs:
pull-requests: write pull-requests: write
steps: steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
with: with:
fetch-depth: 0 fetch-depth: 0
@@ -62,27 +62,30 @@ jobs:
uses: XRPLF/actions/.github/actions/get-nproc@046b1620f6bfd6cd0985dc82c3df02786801fe0a uses: XRPLF/actions/.github/actions/get-nproc@046b1620f6bfd6cd0985dc82c3df02786801fe0a
id: nproc id: nproc
- name: Run clang-tidy - name: Run clang-tidy (several times)
continue-on-error: true continue-on-error: true
id: run_clang_tidy id: clang_tidy
run: | run: |
run-clang-tidy-${{ env.LLVM_TOOLS_VERSION }} -p build -j "${{ steps.nproc.outputs.nproc }}" -fix -quiet 1>output.txt # We run clang-tidy several times, because some fixes may enable new fixes in subsequent runs.
CLANG_TIDY_COMMAND="run-clang-tidy-${{ env.LLVM_TOOLS_VERSION }} -p build -j ${{ steps.nproc.outputs.nproc }} -fix -quiet"
${CLANG_TIDY_COMMAND} ||
${CLANG_TIDY_COMMAND} ||
${CLANG_TIDY_COMMAND}
- name: Check for changes
id: files_changed
continue-on-error: true
run: |
git diff --exit-code
- name: Fix local includes and clang-format style - name: Fix local includes and clang-format style
if: ${{ steps.run_clang_tidy.outcome != 'success' }} if: ${{ steps.files_changed.outcome != 'success' }}
run: | run: |
pre-commit run --all-files fix-local-includes || true pre-commit run --all-files fix-local-includes || true
pre-commit run --all-files clang-format || true pre-commit run --all-files clang-format || true
- name: Print issues found
if: ${{ steps.run_clang_tidy.outcome != 'success' }}
run: |
sed -i '/error\||/!d' ./output.txt
cat output.txt
rm output.txt
- name: Create an issue - name: Create an issue
if: ${{ steps.run_clang_tidy.outcome != 'success' && github.event_name != 'pull_request' }} if: ${{ (steps.clang_tidy.outcome != 'success' || steps.files_changed.outcome != 'success') && github.event_name != 'pull_request' }}
id: create_issue id: create_issue
uses: ./.github/actions/create-issue uses: ./.github/actions/create-issue
env: env:
@@ -95,7 +98,7 @@ jobs:
List of the issues found: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}/ List of the issues found: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}/
- uses: crazy-max/ghaction-import-gpg@e89d40939c28e39f97cf32126055eeae86ba74ec # v6.3.0 - uses: crazy-max/ghaction-import-gpg@e89d40939c28e39f97cf32126055eeae86ba74ec # v6.3.0
if: ${{ steps.run_clang_tidy.outcome != 'success' && github.event_name != 'pull_request' }} if: ${{ steps.files_changed.outcome != 'success' && github.event_name != 'pull_request' }}
with: with:
gpg_private_key: ${{ secrets.ACTIONS_GPG_PRIVATE_KEY }} gpg_private_key: ${{ secrets.ACTIONS_GPG_PRIVATE_KEY }}
passphrase: ${{ secrets.ACTIONS_GPG_PASSPHRASE }} passphrase: ${{ secrets.ACTIONS_GPG_PASSPHRASE }}
@@ -103,8 +106,8 @@ jobs:
git_commit_gpgsign: true git_commit_gpgsign: true
- name: Create PR with fixes - name: Create PR with fixes
if: ${{ steps.run_clang_tidy.outcome != 'success' && github.event_name != 'pull_request' }} if: ${{ steps.files_changed.outcome != 'success' && github.event_name != 'pull_request' }}
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8 uses: peter-evans/create-pull-request@84ae59a2cdc2258d6fa0732dd66352dddae2a412 # v7.0.9
env: env:
GH_REPO: ${{ github.repository }} GH_REPO: ${{ github.repository }}
GH_TOKEN: ${{ github.token }} GH_TOKEN: ${{ github.token }}
@@ -119,5 +122,5 @@ jobs:
reviewers: "godexsoft,kuznetsss,PeterChen13579,mathbunnyru" reviewers: "godexsoft,kuznetsss,PeterChen13579,mathbunnyru"
- name: Fail the job - name: Fail the job
if: ${{ steps.run_clang_tidy.outcome != 'success' }} if: ${{ steps.clang_tidy.outcome != 'success' || steps.files_changed.outcome != 'success' }}
run: exit 1 run: exit 1

View File

@@ -18,11 +18,11 @@ jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:
image: ghcr.io/xrplf/clio-ci:62369411404eb32b0140603a785ff05e1dc36ce8 image: ghcr.io/xrplf/clio-ci:77387d8f9f13aea8f23831d221ac3e7683bb69b7
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
with: with:
lfs: true lfs: true

View File

@@ -43,17 +43,17 @@ jobs:
conan_profile: gcc conan_profile: gcc
build_type: Release build_type: Release
static: true static: true
container: '{ "image": "ghcr.io/xrplf/clio-ci:62369411404eb32b0140603a785ff05e1dc36ce8" }' container: '{ "image": "ghcr.io/xrplf/clio-ci:77387d8f9f13aea8f23831d221ac3e7683bb69b7" }'
- os: heavy - os: heavy
conan_profile: gcc conan_profile: gcc
build_type: Debug build_type: Debug
static: true static: true
container: '{ "image": "ghcr.io/xrplf/clio-ci:62369411404eb32b0140603a785ff05e1dc36ce8" }' container: '{ "image": "ghcr.io/xrplf/clio-ci:77387d8f9f13aea8f23831d221ac3e7683bb69b7" }'
- os: heavy - os: heavy
conan_profile: gcc.ubsan conan_profile: gcc.ubsan
build_type: Release build_type: Release
static: false static: false
container: '{ "image": "ghcr.io/xrplf/clio-ci:62369411404eb32b0140603a785ff05e1dc36ce8" }' container: '{ "image": "ghcr.io/xrplf/clio-ci:77387d8f9f13aea8f23831d221ac3e7683bb69b7" }'
uses: ./.github/workflows/reusable-build-test.yml uses: ./.github/workflows/reusable-build-test.yml
with: with:
@@ -77,7 +77,7 @@ jobs:
include: include:
- os: heavy - os: heavy
conan_profile: clang conan_profile: clang
container: '{ "image": "ghcr.io/xrplf/clio-ci:62369411404eb32b0140603a785ff05e1dc36ce8" }' container: '{ "image": "ghcr.io/xrplf/clio-ci:77387d8f9f13aea8f23831d221ac3e7683bb69b7" }'
static: true static: true
- os: macos15 - os: macos15
conan_profile: apple-clang conan_profile: apple-clang
@@ -145,7 +145,7 @@ jobs:
issues: write issues: write
steps: steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
- name: Create an issue - name: Create an issue
uses: ./.github/actions/create-issue uses: ./.github/actions/create-issue

View File

@@ -29,7 +29,7 @@ jobs:
conan_profile: gcc conan_profile: gcc
build_type: Release build_type: Release
static: true static: true
container: '{ "image": "ghcr.io/xrplf/clio-ci:62369411404eb32b0140603a785ff05e1dc36ce8" }' container: '{ "image": "ghcr.io/xrplf/clio-ci:77387d8f9f13aea8f23831d221ac3e7683bb69b7" }'
uses: ./.github/workflows/reusable-build-test.yml uses: ./.github/workflows/reusable-build-test.yml
with: with:

View File

@@ -90,7 +90,7 @@ jobs:
if: ${{ runner.os == 'macOS' }} if: ${{ runner.os == 'macOS' }}
uses: XRPLF/actions/.github/actions/cleanup-workspace@ea9970b7c211b18f4c8bcdb28c29f5711752029f uses: XRPLF/actions/.github/actions/cleanup-workspace@ea9970b7c211b18f4c8bcdb28c29f5711752029f
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
with: with:
fetch-depth: 0 fetch-depth: 0
# We need to fetch tags to have correct version in the release # We need to fetch tags to have correct version in the release
@@ -116,9 +116,8 @@ jobs:
code_coverage: ${{ inputs.code_coverage }} code_coverage: ${{ inputs.code_coverage }}
- name: Restore ccache cache - name: Restore ccache cache
if: ${{ inputs.download_ccache }} if: ${{ inputs.download_ccache && github.ref != 'refs/heads/develop' }}
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
id: restore_cache
with: with:
path: ${{ env.CCACHE_DIR }} path: ${{ env.CCACHE_DIR }}
key: ${{ steps.cache_key.outputs.key }} key: ${{ steps.cache_key.outputs.key }}
@@ -160,17 +159,14 @@ jobs:
name: build_time_report_${{ runner.os }}_${{ inputs.build_type }}_${{ inputs.conan_profile }} name: build_time_report_${{ runner.os }}_${{ inputs.build_type }}_${{ inputs.conan_profile }}
path: build_time_report.txt path: build_time_report.txt
- name: Show ccache's statistics - name: Show ccache's statistics and zero it
if: ${{ inputs.download_ccache }} if: ${{ inputs.download_ccache }}
id: ccache_stats
run: | run: |
ccache -s > /tmp/ccache.stats ccache --show-stats
miss_rate=$(cat /tmp/ccache.stats | grep 'Misses' | head -n1 | sed 's/.*(\(.*\)%).*/\1/') ccache --zero-stats
echo "miss_rate=${miss_rate}" >> $GITHUB_OUTPUT
cat /tmp/ccache.stats
- name: Save ccache cache - name: Save ccache cache
if: ${{ inputs.upload_ccache && github.ref == 'refs/heads/develop' && (steps.restore_cache.outputs.cache-hit != 'true' || steps.ccache_stats.outputs.miss_rate == '100.0') }} if: ${{ inputs.upload_ccache && github.ref == 'refs/heads/develop' }}
uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with: with:
path: ${{ env.CCACHE_DIR }} path: ${{ env.CCACHE_DIR }}

View File

@@ -46,7 +46,7 @@ jobs:
release: release:
runs-on: heavy runs-on: heavy
container: container:
image: ghcr.io/xrplf/clio-ci:62369411404eb32b0140603a785ff05e1dc36ce8 image: ghcr.io/xrplf/clio-ci:77387d8f9f13aea8f23831d221ac3e7683bb69b7
env: env:
GH_REPO: ${{ github.repository }} GH_REPO: ${{ github.repository }}
GH_TOKEN: ${{ github.token }} GH_TOKEN: ${{ github.token }}
@@ -55,7 +55,7 @@ jobs:
contents: write contents: write
steps: steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
with: with:
fetch-depth: 0 fetch-depth: 0

View File

@@ -54,7 +54,7 @@ jobs:
if: ${{ runner.os == 'macOS' }} if: ${{ runner.os == 'macOS' }}
uses: XRPLF/actions/.github/actions/cleanup-workspace@ea9970b7c211b18f4c8bcdb28c29f5711752029f uses: XRPLF/actions/.github/actions/cleanup-workspace@ea9970b7c211b18f4c8bcdb28c29f5711752029f
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
with: with:
fetch-depth: 0 fetch-depth: 0

View File

@@ -16,7 +16,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
with: with:
fetch-depth: 0 fetch-depth: 0

View File

@@ -44,14 +44,13 @@ jobs:
uses: ./.github/workflows/reusable-build-test.yml uses: ./.github/workflows/reusable-build-test.yml
with: with:
runs_on: heavy runs_on: heavy
container: '{ "image": "ghcr.io/xrplf/clio-ci:62369411404eb32b0140603a785ff05e1dc36ce8" }' container: '{ "image": "ghcr.io/xrplf/clio-ci:77387d8f9f13aea8f23831d221ac3e7683bb69b7" }'
download_ccache: false download_ccache: false
upload_ccache: false upload_ccache: false
conan_profile: ${{ matrix.compiler }}${{ matrix.sanitizer_ext }} conan_profile: ${{ matrix.compiler }}${{ matrix.sanitizer_ext }}
build_type: ${{ matrix.build_type }} build_type: ${{ matrix.build_type }}
static: false static: false
# Currently, both gcc.tsan and clang.tsan unit tests hang run_unit_tests: true
run_unit_tests: ${{ matrix.sanitizer_ext != '.tsan' }}
run_integration_tests: false run_integration_tests: false
upload_clio_server: false upload_clio_server: false
targets: clio_tests clio_integration_tests targets: clio_tests clio_integration_tests

View File

@@ -56,7 +56,7 @@ jobs:
needs: repo needs: repo
steps: steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
- name: Get changed files - name: Get changed files
id: changed-files id: changed-files
@@ -94,7 +94,7 @@ jobs:
needs: repo needs: repo
steps: steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
- name: Get changed files - name: Get changed files
id: changed-files id: changed-files
@@ -132,7 +132,7 @@ jobs:
needs: [repo, gcc-amd64, gcc-arm64] needs: [repo, gcc-amd64, gcc-arm64]
steps: steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
- name: Get changed files - name: Get changed files
id: changed-files id: changed-files
@@ -183,7 +183,7 @@ jobs:
needs: repo needs: repo
steps: steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
- name: Get changed files - name: Get changed files
id: changed-files id: changed-files
@@ -219,7 +219,7 @@ jobs:
needs: [repo, gcc-merge] needs: [repo, gcc-merge]
steps: steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
- name: Get changed files - name: Get changed files
id: changed-files id: changed-files
@@ -250,7 +250,7 @@ jobs:
needs: [repo, gcc-merge] needs: [repo, gcc-merge]
steps: steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
- name: Get changed files - name: Get changed files
id: changed-files id: changed-files
@@ -281,7 +281,7 @@ jobs:
needs: [repo, tools-amd64, tools-arm64] needs: [repo, tools-amd64, tools-arm64]
steps: steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
- name: Get changed files - name: Get changed files
id: changed-files id: changed-files
@@ -316,7 +316,7 @@ jobs:
needs: [repo, tools-merge] needs: [repo, tools-merge]
steps: steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
- uses: ./.github/actions/build-docker-image - uses: ./.github/actions/build-docker-image
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -338,7 +338,7 @@ jobs:
needs: [repo, gcc-merge, clang, tools-merge] needs: [repo, gcc-merge, clang, tools-merge]
steps: steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
- uses: ./.github/actions/build-docker-image - uses: ./.github/actions/build-docker-image
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -50,7 +50,7 @@ jobs:
outputs: outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }} matrix: ${{ steps.set-matrix.outputs.matrix }}
steps: steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
- name: Calculate conan matrix - name: Calculate conan matrix
id: set-matrix id: set-matrix
@@ -73,7 +73,7 @@ jobs:
CONAN_PROFILE: ${{ matrix.compiler }}${{ matrix.sanitizer_ext }} CONAN_PROFILE: ${{ matrix.compiler }}${{ matrix.sanitizer_ext }}
steps: steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
- name: Prepare runner - name: Prepare runner
uses: XRPLF/actions/.github/actions/prepare-runner@8abb0722cbff83a9a2dc7d06c473f7a4964b7382 uses: XRPLF/actions/.github/actions/prepare-runner@8abb0722cbff83a9a2dc7d06c473f7a4964b7382

View File

@@ -75,11 +75,6 @@ if (san)
endif () endif ()
target_compile_options(clio_options INTERFACE ${SAN_OPTIMIZATION_FLAG} ${SAN_FLAG} -fno-omit-frame-pointer) target_compile_options(clio_options INTERFACE ${SAN_OPTIMIZATION_FLAG} ${SAN_FLAG} -fno-omit-frame-pointer)
if (san STREQUAL "address")
# ASAN needs these definitions as well as correct b2 flags in conan profile for sanitizers
target_compile_definitions(clio_options INTERFACE BOOST_USE_ASAN=1 BOOST_USE_UCONTEXT=1)
endif ()
target_link_libraries(clio_options INTERFACE ${SAN_FLAG} ${SAN_LIB}) target_link_libraries(clio_options INTERFACE ${SAN_FLAG} ${SAN_LIB})
endif () endif ()

View File

@@ -5,7 +5,7 @@
"xxhash/0.8.3#681d36a0a6111fc56e5e45ea182c19cc%1756234289.683", "xxhash/0.8.3#681d36a0a6111fc56e5e45ea182c19cc%1756234289.683",
"xrpl/3.0.0-rc1#f5c8ecd42bdf511ad36f57bc702dacd2%1762975621.294", "xrpl/3.0.0-rc1#f5c8ecd42bdf511ad36f57bc702dacd2%1762975621.294",
"sqlite3/3.49.1#8631739a4c9b93bd3d6b753bac548a63%1756234266.869", "sqlite3/3.49.1#8631739a4c9b93bd3d6b753bac548a63%1756234266.869",
"spdlog/1.15.3#3ca0e9e6b83af4d0151e26541d140c86%1754401846.61", "spdlog/1.16.0#942c2c39562ae25ba575d9c8e2bdf3b6%1760375663.769",
"soci/4.0.3#a9f8d773cd33e356b5879a4b0564f287%1756234262.318", "soci/4.0.3#a9f8d773cd33e356b5879a4b0564f287%1756234262.318",
"re2/20230301#dfd6e2bf050eb90ddd8729cfb4c844a4%1756234257.976", "re2/20230301#dfd6e2bf050eb90ddd8729cfb4c844a4%1756234257.976",
"rapidjson/cci.20220822#1b9d8c2256876a154172dc5cfbe447c6%1754325007.656", "rapidjson/cci.20220822#1b9d8c2256876a154172dc5cfbe447c6%1754325007.656",
@@ -21,9 +21,9 @@
"http_parser/2.9.4#98d91690d6fd021e9e624218a85d9d97%1754325001.385", "http_parser/2.9.4#98d91690d6fd021e9e624218a85d9d97%1754325001.385",
"gtest/1.14.0#f8f0757a574a8dd747d16af62d6eb1b7%1754325000.842", "gtest/1.14.0#f8f0757a574a8dd747d16af62d6eb1b7%1754325000.842",
"grpc/1.50.1#02291451d1e17200293a409410d1c4e1%1756234248.958", "grpc/1.50.1#02291451d1e17200293a409410d1c4e1%1756234248.958",
"fmt/11.2.0#579bb2cdf4a7607621beea4eb4651e0f%1754324999.086", "fmt/12.1.0#50abab23274d56bb8f42c94b3b9a40c7%1761885265.231",
"doctest/2.4.11#a4211dfc329a16ba9f280f9574025659%1756234220.819", "doctest/2.4.11#a4211dfc329a16ba9f280f9574025659%1756234220.819",
"date/3.0.4#f74bbba5a08fa388256688743136cb6f%1756234217.493", "date/3.0.4#862e11e80030356b53c2c38599ceb32b%1763584497.32",
"cassandra-cpp-driver/2.17.0#e50919efac8418c26be6671fd702540a%1754324997.363", "cassandra-cpp-driver/2.17.0#e50919efac8418c26be6671fd702540a%1754324997.363",
"c-ares/1.34.5#b78b91e7cfb1f11ce777a285bbf169c6%1756234217.915", "c-ares/1.34.5#b78b91e7cfb1f11ce777a285bbf169c6%1756234217.915",
"bzip2/1.0.8#00b4a4658791c1f06914e087f0e792f5%1756234261.716", "bzip2/1.0.8#00b4a4658791c1f06914e087f0e792f5%1756234261.716",
@@ -52,6 +52,9 @@
], ],
"sqlite3/3.44.2": [ "sqlite3/3.44.2": [
"sqlite3/3.49.1" "sqlite3/3.49.1"
],
"fmt/12.0.0": [
"fmt/12.1.0"
] ]
}, },
"config_requires": [] "config_requires": []

View File

@@ -14,14 +14,13 @@ class ClioConan(ConanFile):
requires = [ requires = [
'boost/1.83.0', 'boost/1.83.0',
'cassandra-cpp-driver/2.17.0', 'cassandra-cpp-driver/2.17.0',
'fmt/11.2.0',
'protobuf/3.21.12', 'protobuf/3.21.12',
'grpc/1.50.1', 'grpc/1.50.1',
'openssl/1.1.1w', 'openssl/1.1.1w',
'xrpl/3.0.0-rc1', 'xrpl/3.0.0-rc1',
'zlib/1.3.1', 'zlib/1.3.1',
'libbacktrace/cci.20210118', 'libbacktrace/cci.20210118',
'spdlog/1.15.3', 'spdlog/1.16.0',
] ]
default_options = { default_options = {
@@ -47,6 +46,7 @@ class ClioConan(ConanFile):
def requirements(self): def requirements(self):
self.requires('gtest/1.14.0') self.requires('gtest/1.14.0')
self.requires('benchmark/1.9.4') self.requires('benchmark/1.9.4')
self.requires('fmt/12.1.0', force=True)
def configure(self): def configure(self):
if self.settings.compiler == 'apple-clang': if self.settings.compiler == 'apple-clang':

View File

@@ -3,7 +3,11 @@
{% set sanitizer_opt_map = {"asan": "address", "tsan": "thread", "ubsan": "undefined"} %} {% set sanitizer_opt_map = {"asan": "address", "tsan": "thread", "ubsan": "undefined"} %}
{% set sanitizer = sanitizer_opt_map[sani] %} {% set sanitizer = sanitizer_opt_map[sani] %}
{% set sanitizer_b2_flags_map = {"address": "define=BOOST_USE_ASAN=1 context-impl=ucontext address-sanitizer=on", "thread": "thread-sanitizer=on", "undefined": "undefined-sanitizer=on"} %} {% set sanitizer_b2_flags_map = {
"address": "context-impl=ucontext address-sanitizer=norecover",
"thread": "context-impl=ucontext thread-sanitizer=norecover",
"undefined": "undefined-sanitizer=norecover"
} %}
{% set sanitizer_b2_flags_str = sanitizer_b2_flags_map[sanitizer] %} {% set sanitizer_b2_flags_str = sanitizer_b2_flags_map[sanitizer] %}
{% set sanitizer_build_flags_str = "-fsanitize=" ~ sanitizer ~ " -g -O1 -fno-omit-frame-pointer" %} {% set sanitizer_build_flags_str = "-fsanitize=" ~ sanitizer ~ " -g -O1 -fno-omit-frame-pointer" %}
@@ -24,4 +28,10 @@ tools.build:cxxflags+={{ sanitizer_build_flags }}
tools.build:exelinkflags+={{ sanitizer_link_flags }} tools.build:exelinkflags+={{ sanitizer_link_flags }}
tools.build:sharedlinkflags+={{ sanitizer_link_flags }} tools.build:sharedlinkflags+={{ sanitizer_link_flags }}
tools.info.package_id:confs+=["tools.build:cflags", "tools.build:cxxflags", "tools.build:exelinkflags", "tools.build:sharedlinkflags"] {% if sanitizer == "address" %}
tools.build:defines+=["BOOST_USE_ASAN", "BOOST_USE_UCONTEXT"]
{% elif sanitizer == "thread" %}
tools.build:defines+=["BOOST_USE_TSAN", "BOOST_USE_UCONTEXT"]
{% endif %}
tools.info.package_id:confs+=["tools.build:cflags", "tools.build:cxxflags", "tools.build:exelinkflags", "tools.build:sharedlinkflags", "tools.build:defines"]

View File

@@ -1,6 +1,6 @@
services: services:
clio_develop: clio_develop:
image: ghcr.io/xrplf/clio-ci:62369411404eb32b0140603a785ff05e1dc36ce8 image: ghcr.io/xrplf/clio-ci:77387d8f9f13aea8f23831d221ac3e7683bb69b7
volumes: volumes:
- clio_develop_conan_data:/root/.conan2/p - clio_develop_conan_data:/root/.conan2/p
- clio_develop_ccache:/root/.ccache - clio_develop_ccache:/root/.ccache

View File

@@ -191,7 +191,7 @@ Open the `index.html` file in your browser to see the documentation pages.
It is also possible to build Clio using [Docker](https://www.docker.com/) if you don't want to install all the dependencies on your machine. It is also possible to build Clio using [Docker](https://www.docker.com/) if you don't want to install all the dependencies on your machine.
```sh ```sh
docker run -it ghcr.io/xrplf/clio-ci:62369411404eb32b0140603a785ff05e1dc36ce8 docker run -it ghcr.io/xrplf/clio-ci:77387d8f9f13aea8f23831d221ac3e7683bb69b7
git clone https://github.com/XRPLF/clio git clone https://github.com/XRPLF/clio
cd clio cd clio
``` ```

View File

@@ -391,7 +391,7 @@ This document provides a list of all available Clio configuration properties in
- **Type**: double - **Type**: double
- **Default value**: `10` - **Default value**: `10`
- **Constraints**: The value must be a positive double number. - **Constraints**: The value must be a positive double number.
- **Description**: The number of milliseconds the server waits to shutdown gracefully. If Clio does not shutdown gracefully after the specified value, it will be killed instead. - **Description**: The number of seconds the server waits to shutdown gracefully. If Clio does not shutdown gracefully after the specified value, it will be killed instead.
### cache.num_diffs ### cache.num_diffs

View File

@@ -53,7 +53,7 @@ LedgerCacheSaver::save()
success.has_value()) { success.has_value()) {
LOG(util::LogService::info()) << "Successfully saved ledger cache in " << durationMs << " ms"; LOG(util::LogService::info()) << "Successfully saved ledger cache in " << durationMs << " ms";
} else { } else {
LOG(util::LogService::error()) << "Error saving LedgerCache to file"; LOG(util::LogService::error()) << "Error saving LedgerCache to file: " << success.error();
} }
}); });
} }

View File

@@ -316,8 +316,11 @@ tag_invoke(boost::json::value_to_tag<AMMInfoHandler::Input>, boost::json::value
if (jsonObject.contains(JS(ledger_hash))) if (jsonObject.contains(JS(ledger_hash)))
input.ledgerHash = boost::json::value_to<std::string>(jv.at(JS(ledger_hash))); input.ledgerHash = boost::json::value_to<std::string>(jv.at(JS(ledger_hash)));
if (jsonObject.contains(JS(ledger_index))) if (jsonObject.contains(JS(ledger_index))) {
input.ledgerIndex = util::getLedgerIndex(jsonObject.at(JS(ledger_index))); auto const expectedLedgerIndex = util::getLedgerIndex(jsonObject.at(JS(ledger_index)));
if (expectedLedgerIndex.has_value())
input.ledgerIndex = *expectedLedgerIndex;
}
if (jsonObject.contains(JS(asset))) if (jsonObject.contains(JS(asset)))
input.issue1 = parseIssue(jsonObject.at(JS(asset)).as_object()); input.issue1 = parseIssue(jsonObject.at(JS(asset)).as_object());

View File

@@ -154,8 +154,11 @@ tag_invoke(boost::json::value_to_tag<AccountChannelsHandler::Input>, boost::json
if (jsonObject.contains(JS(destination_account))) if (jsonObject.contains(JS(destination_account)))
input.destinationAccount = boost::json::value_to<std::string>(jv.at(JS(destination_account))); input.destinationAccount = boost::json::value_to<std::string>(jv.at(JS(destination_account)));
if (jsonObject.contains(JS(ledger_index))) if (jsonObject.contains(JS(ledger_index))) {
input.ledgerIndex = util::getLedgerIndex(jv.at(JS(ledger_index))); auto const expectedLedgerIndex = util::getLedgerIndex(jv.at(JS(ledger_index)));
if (expectedLedgerIndex.has_value())
input.ledgerIndex = *expectedLedgerIndex;
}
return input; return input;
} }

View File

@@ -128,8 +128,11 @@ tag_invoke(boost::json::value_to_tag<AccountCurrenciesHandler::Input>, boost::js
if (jsonObject.contains(JS(ledger_hash))) if (jsonObject.contains(JS(ledger_hash)))
input.ledgerHash = boost::json::value_to<std::string>(jv.at(JS(ledger_hash))); input.ledgerHash = boost::json::value_to<std::string>(jv.at(JS(ledger_hash)));
if (jsonObject.contains(JS(ledger_index))) if (jsonObject.contains(JS(ledger_index))) {
input.ledgerIndex = util::getLedgerIndex(jv.at(JS(ledger_index))); auto const expectedLedgerIndex = util::getLedgerIndex(jv.at(JS(ledger_index)));
if (expectedLedgerIndex.has_value())
input.ledgerIndex = *expectedLedgerIndex;
}
return input; return input;
} }

View File

@@ -204,8 +204,11 @@ tag_invoke(boost::json::value_to_tag<AccountInfoHandler::Input>, boost::json::va
if (jsonObject.contains(JS(ledger_hash))) if (jsonObject.contains(JS(ledger_hash)))
input.ledgerHash = boost::json::value_to<std::string>(jsonObject.at(JS(ledger_hash))); input.ledgerHash = boost::json::value_to<std::string>(jsonObject.at(JS(ledger_hash)));
if (jsonObject.contains(JS(ledger_index))) if (jsonObject.contains(JS(ledger_index))) {
input.ledgerIndex = util::getLedgerIndex(jsonObject.at(JS(ledger_index))); auto const expectedLedgerIndex = util::getLedgerIndex(jsonObject.at(JS(ledger_index)));
if (expectedLedgerIndex.has_value())
input.ledgerIndex = *expectedLedgerIndex;
}
if (jsonObject.contains(JS(signer_lists))) if (jsonObject.contains(JS(signer_lists)))
input.signerLists = boost::json::value_to<JsonBool>(jsonObject.at(JS(signer_lists))); input.signerLists = boost::json::value_to<JsonBool>(jsonObject.at(JS(signer_lists)));

View File

@@ -215,8 +215,11 @@ tag_invoke(boost::json::value_to_tag<AccountLinesHandler::Input>, boost::json::v
if (jsonObject.contains(JS(ignore_default))) if (jsonObject.contains(JS(ignore_default)))
input.ignoreDefault = jv.at(JS(ignore_default)).as_bool(); input.ignoreDefault = jv.at(JS(ignore_default)).as_bool();
if (jsonObject.contains(JS(ledger_index))) if (jsonObject.contains(JS(ledger_index))) {
input.ledgerIndex = util::getLedgerIndex(jv.at(JS(ledger_index))); auto const expectedLedgerIndex = util::getLedgerIndex(jv.at(JS(ledger_index)));
if (expectedLedgerIndex.has_value())
input.ledgerIndex = *expectedLedgerIndex;
}
return input; return input;
} }

View File

@@ -164,8 +164,11 @@ tag_invoke(boost::json::value_to_tag<AccountMPTokenIssuancesHandler::Input>, boo
if (jsonObject.contains(JS(ledger_hash))) if (jsonObject.contains(JS(ledger_hash)))
input.ledgerHash = boost::json::value_to<std::string>(jv.at(JS(ledger_hash))); input.ledgerHash = boost::json::value_to<std::string>(jv.at(JS(ledger_hash)));
if (jsonObject.contains(JS(ledger_index))) if (jsonObject.contains(JS(ledger_index))) {
input.ledgerIndex = util::getLedgerIndex(jv.at(JS(ledger_index))); auto const expectedLedgerIndex = util::getLedgerIndex(jv.at(JS(ledger_index)));
if (expectedLedgerIndex.has_value())
input.ledgerIndex = *expectedLedgerIndex;
}
return input; return input;
} }

View File

@@ -139,8 +139,11 @@ tag_invoke(boost::json::value_to_tag<AccountMPTokensHandler::Input>, boost::json
if (jsonObject.contains(JS(ledger_hash))) if (jsonObject.contains(JS(ledger_hash)))
input.ledgerHash = boost::json::value_to<std::string>(jv.at(JS(ledger_hash))); input.ledgerHash = boost::json::value_to<std::string>(jv.at(JS(ledger_hash)));
if (jsonObject.contains(JS(ledger_index))) if (jsonObject.contains(JS(ledger_index))) {
input.ledgerIndex = util::getLedgerIndex(jv.at(JS(ledger_index))); auto const expectedLedgerIndex = util::getLedgerIndex(jv.at(JS(ledger_index)));
if (expectedLedgerIndex.has_value())
input.ledgerIndex = *expectedLedgerIndex;
}
return input; return input;
} }

View File

@@ -157,8 +157,11 @@ tag_invoke(boost::json::value_to_tag<AccountNFTsHandler::Input>, boost::json::va
if (jsonObject.contains(JS(ledger_hash))) if (jsonObject.contains(JS(ledger_hash)))
input.ledgerHash = boost::json::value_to<std::string>(jsonObject.at(JS(ledger_hash))); input.ledgerHash = boost::json::value_to<std::string>(jsonObject.at(JS(ledger_hash)));
if (jsonObject.contains(JS(ledger_index))) if (jsonObject.contains(JS(ledger_index))) {
input.ledgerIndex = util::getLedgerIndex(jsonObject.at(JS(ledger_index))); auto const expectedLedgerIndex = util::getLedgerIndex(jsonObject.at(JS(ledger_index)));
if (expectedLedgerIndex.has_value())
input.ledgerIndex = *expectedLedgerIndex;
}
if (jsonObject.contains(JS(limit))) if (jsonObject.contains(JS(limit)))
input.limit = util::integralValueAs<uint32_t>(jsonObject.at(JS(limit))); input.limit = util::integralValueAs<uint32_t>(jsonObject.at(JS(limit)));

View File

@@ -153,8 +153,11 @@ tag_invoke(boost::json::value_to_tag<AccountObjectsHandler::Input>, boost::json:
if (jsonObject.contains(JS(ledger_hash))) if (jsonObject.contains(JS(ledger_hash)))
input.ledgerHash = boost::json::value_to<std::string>(jv.at(JS(ledger_hash))); input.ledgerHash = boost::json::value_to<std::string>(jv.at(JS(ledger_hash)));
if (jsonObject.contains(JS(ledger_index))) if (jsonObject.contains(JS(ledger_index))) {
input.ledgerIndex = util::getLedgerIndex(jv.at(JS(ledger_index))); auto const expectedLedgerIndex = util::getLedgerIndex(jv.at(JS(ledger_index)));
if (expectedLedgerIndex.has_value())
input.ledgerIndex = *expectedLedgerIndex;
}
if (jsonObject.contains(JS(type))) { if (jsonObject.contains(JS(type))) {
input.type = input.type =

View File

@@ -169,8 +169,11 @@ tag_invoke(boost::json::value_to_tag<AccountOffersHandler::Input>, boost::json::
if (jsonObject.contains(JS(ledger_hash))) if (jsonObject.contains(JS(ledger_hash)))
input.ledgerHash = boost::json::value_to<std::string>(jsonObject.at(JS(ledger_hash))); input.ledgerHash = boost::json::value_to<std::string>(jsonObject.at(JS(ledger_hash)));
if (jsonObject.contains(JS(ledger_index))) if (jsonObject.contains(JS(ledger_index))) {
input.ledgerIndex = util::getLedgerIndex(jsonObject.at(JS(ledger_index))); auto const expectedLedgerIndex = util::getLedgerIndex(jsonObject.at(JS(ledger_index)));
if (expectedLedgerIndex.has_value())
input.ledgerIndex = *expectedLedgerIndex;
}
if (jsonObject.contains(JS(limit))) if (jsonObject.contains(JS(limit)))
input.limit = util::integralValueAs<uint32_t>(jsonObject.at(JS(limit))); input.limit = util::integralValueAs<uint32_t>(jsonObject.at(JS(limit)));

View File

@@ -258,8 +258,10 @@ tag_invoke(boost::json::value_to_tag<AccountTxHandler::Input>, boost::json::valu
input.ledgerHash = boost::json::value_to<std::string>(jsonObject.at(JS(ledger_hash))); input.ledgerHash = boost::json::value_to<std::string>(jsonObject.at(JS(ledger_hash)));
if (jsonObject.contains(JS(ledger_index))) { if (jsonObject.contains(JS(ledger_index))) {
input.ledgerIndex = util::getLedgerIndex(jsonObject.at(JS(ledger_index))); auto const expectedLedgerIndex = util::getLedgerIndex(jsonObject.at(JS(ledger_index)));
if (not input.ledgerIndex.has_value()) { if (expectedLedgerIndex.has_value()) {
input.ledgerIndex = *expectedLedgerIndex;
} else {
// could not get the latest validated ledger seq here, using this flag to indicate that // could not get the latest validated ledger seq here, using this flag to indicate that
input.usingValidatedLedger = true; input.usingValidatedLedger = true;
} }

View File

@@ -90,8 +90,11 @@ tag_invoke(boost::json::value_to_tag<BookChangesHandler::Input>, boost::json::va
if (jsonObject.contains(JS(ledger_hash))) if (jsonObject.contains(JS(ledger_hash)))
input.ledgerHash = boost::json::value_to<std::string>(jv.at(JS(ledger_hash))); input.ledgerHash = boost::json::value_to<std::string>(jv.at(JS(ledger_hash)));
if (jsonObject.contains(JS(ledger_index))) if (jsonObject.contains(JS(ledger_index))) {
input.ledgerIndex = util::getLedgerIndex(jv.at(JS(ledger_index))); auto const expectedLedgerIndex = util::getLedgerIndex(jv.at(JS(ledger_index)));
if (expectedLedgerIndex.has_value())
input.ledgerIndex = *expectedLedgerIndex;
}
return input; return input;
} }

View File

@@ -122,8 +122,11 @@ tag_invoke(boost::json::value_to_tag<BookOffersHandler::Input>, boost::json::val
if (jsonObject.contains(JS(ledger_hash))) if (jsonObject.contains(JS(ledger_hash)))
input.ledgerHash = boost::json::value_to<std::string>(jv.at(JS(ledger_hash))); input.ledgerHash = boost::json::value_to<std::string>(jv.at(JS(ledger_hash)));
if (jsonObject.contains(JS(ledger_index))) if (jsonObject.contains(JS(ledger_index))) {
input.ledgerIndex = util::getLedgerIndex(jv.at(JS(ledger_index))); auto const expectedLedgerIndex = util::getLedgerIndex(jv.at(JS(ledger_index)));
if (expectedLedgerIndex.has_value())
input.ledgerIndex = *expectedLedgerIndex;
}
if (jsonObject.contains(JS(taker))) if (jsonObject.contains(JS(taker)))
input.taker = accountFromStringStrict(boost::json::value_to<std::string>(jv.at(JS(taker)))); input.taker = accountFromStringStrict(boost::json::value_to<std::string>(jv.at(JS(taker))));

View File

@@ -145,8 +145,11 @@ tag_invoke(boost::json::value_to_tag<DepositAuthorizedHandler::Input>, boost::js
if (jsonObject.contains(JS(ledger_hash))) if (jsonObject.contains(JS(ledger_hash)))
input.ledgerHash = boost::json::value_to<std::string>(jv.at(JS(ledger_hash))); input.ledgerHash = boost::json::value_to<std::string>(jv.at(JS(ledger_hash)));
if (jsonObject.contains(JS(ledger_index))) if (jsonObject.contains(JS(ledger_index))) {
input.ledgerIndex = util::getLedgerIndex(jv.at(JS(ledger_index))); auto const expectedLedgerIndex = util::getLedgerIndex(jv.at(JS(ledger_index)));
if (expectedLedgerIndex.has_value())
input.ledgerIndex = *expectedLedgerIndex;
}
if (jsonObject.contains(JS(credentials))) if (jsonObject.contains(JS(credentials)))
input.credentials = boost::json::value_to<boost::json::array>(jv.at(JS(credentials))); input.credentials = boost::json::value_to<boost::json::array>(jv.at(JS(credentials)));

View File

@@ -168,8 +168,11 @@ tag_invoke(boost::json::value_to_tag<FeatureHandler::Input>, boost::json::value
if (jsonObject.contains(JS(ledger_hash))) if (jsonObject.contains(JS(ledger_hash)))
input.ledgerHash = boost::json::value_to<std::string>(jv.at(JS(ledger_hash))); input.ledgerHash = boost::json::value_to<std::string>(jv.at(JS(ledger_hash)));
if (jsonObject.contains(JS(ledger_index))) if (jsonObject.contains(JS(ledger_index))) {
input.ledgerIndex = util::getLedgerIndex(jv.at(JS(ledger_index))); auto const expectedLedgerIndex = util::getLedgerIndex(jv.at(JS(ledger_index)));
if (expectedLedgerIndex.has_value())
input.ledgerIndex = *expectedLedgerIndex;
}
return input; return input;
} }

View File

@@ -249,8 +249,11 @@ tag_invoke(boost::json::value_to_tag<GatewayBalancesHandler::Input>, boost::json
if (jsonObject.contains(JS(ledger_hash))) if (jsonObject.contains(JS(ledger_hash)))
input.ledgerHash = boost::json::value_to<std::string>(jv.at(JS(ledger_hash))); input.ledgerHash = boost::json::value_to<std::string>(jv.at(JS(ledger_hash)));
if (jsonObject.contains(JS(ledger_index))) if (jsonObject.contains(JS(ledger_index))) {
input.ledgerIndex = util::getLedgerIndex(jv.at(JS(ledger_index))); auto const expectedLedgerIndex = util::getLedgerIndex(jv.at(JS(ledger_index)));
if (expectedLedgerIndex.has_value())
input.ledgerIndex = *expectedLedgerIndex;
}
if (jsonObject.contains(JS(hotwallet))) { if (jsonObject.contains(JS(hotwallet))) {
if (jsonObject.at(JS(hotwallet)).is_string()) { if (jsonObject.at(JS(hotwallet)).is_string()) {

View File

@@ -263,8 +263,11 @@ tag_invoke(boost::json::value_to_tag<GetAggregatePriceHandler::Input>, boost::js
if (jsonObject.contains(JS(ledger_hash))) if (jsonObject.contains(JS(ledger_hash)))
input.ledgerHash = boost::json::value_to<std::string>(jv.at(JS(ledger_hash))); input.ledgerHash = boost::json::value_to<std::string>(jv.at(JS(ledger_hash)));
if (jsonObject.contains(JS(ledger_index))) if (jsonObject.contains(JS(ledger_index))) {
input.ledgerIndex = util::getLedgerIndex(jv.at(JS(ledger_index))); auto const expectedLedgerIndex = util::getLedgerIndex(jv.at(JS(ledger_index)));
if (expectedLedgerIndex.has_value())
input.ledgerIndex = *expectedLedgerIndex;
}
for (auto const& oracle : jsonObject.at(JS(oracles)).as_array()) { for (auto const& oracle : jsonObject.at(JS(oracles)).as_array()) {
input.oracles.push_back( input.oracles.push_back(

View File

@@ -208,8 +208,11 @@ tag_invoke(boost::json::value_to_tag<LedgerHandler::Input>, boost::json::value c
if (jsonObject.contains(JS(ledger_hash))) if (jsonObject.contains(JS(ledger_hash)))
input.ledgerHash = boost::json::value_to<std::string>(jv.at(JS(ledger_hash))); input.ledgerHash = boost::json::value_to<std::string>(jv.at(JS(ledger_hash)));
if (jsonObject.contains(JS(ledger_index))) if (jsonObject.contains(JS(ledger_index))) {
input.ledgerIndex = util::getLedgerIndex(jv.at(JS(ledger_index))); auto const expectedLedgerIndex = util::getLedgerIndex(jv.at(JS(ledger_index)));
if (expectedLedgerIndex.has_value())
input.ledgerIndex = *expectedLedgerIndex;
}
if (jsonObject.contains(JS(transactions))) if (jsonObject.contains(JS(transactions)))
input.transactions = jv.at(JS(transactions)).as_bool(); input.transactions = jv.at(JS(transactions)).as_bool();

View File

@@ -210,8 +210,11 @@ tag_invoke(boost::json::value_to_tag<LedgerDataHandler::Input>, boost::json::val
if (jsonObject.contains(JS(ledger_hash))) if (jsonObject.contains(JS(ledger_hash)))
input.ledgerHash = boost::json::value_to<std::string>(jsonObject.at(JS(ledger_hash))); input.ledgerHash = boost::json::value_to<std::string>(jsonObject.at(JS(ledger_hash)));
if (jsonObject.contains(JS(ledger_index))) if (jsonObject.contains(JS(ledger_index))) {
input.ledgerIndex = util::getLedgerIndex(jsonObject.at(JS(ledger_index))); auto const expectedLedgerIndex = util::getLedgerIndex(jsonObject.at(JS(ledger_index)));
if (expectedLedgerIndex.has_value())
input.ledgerIndex = *expectedLedgerIndex;
}
if (jsonObject.contains(JS(type))) if (jsonObject.contains(JS(type)))
input.type = util::LedgerTypes::getLedgerEntryTypeFromStr(boost::json::value_to<std::string>(jv.at(JS(type)))); input.type = util::LedgerTypes::getLedgerEntryTypeFromStr(boost::json::value_to<std::string>(jv.at(JS(type))));

View File

@@ -305,8 +305,11 @@ tag_invoke(boost::json::value_to_tag<LedgerEntryHandler::Input>, boost::json::va
if (jsonObject.contains(JS(ledger_hash))) if (jsonObject.contains(JS(ledger_hash)))
input.ledgerHash = boost::json::value_to<std::string>(jv.at(JS(ledger_hash))); input.ledgerHash = boost::json::value_to<std::string>(jv.at(JS(ledger_hash)));
if (jsonObject.contains(JS(ledger_index))) if (jsonObject.contains(JS(ledger_index))) {
input.ledgerIndex = util::getLedgerIndex(jv.at(JS(ledger_index))); auto const expectedLedgerIndex = util::getLedgerIndex(jv.at(JS(ledger_index)));
if (expectedLedgerIndex.has_value())
input.ledgerIndex = *expectedLedgerIndex;
}
if (jsonObject.contains(JS(binary))) if (jsonObject.contains(JS(binary)))
input.binary = jv.at(JS(binary)).as_bool(); input.binary = jv.at(JS(binary)).as_bool();

View File

@@ -124,8 +124,11 @@ tag_invoke(boost::json::value_to_tag<MPTHoldersHandler::Input>, boost::json::val
if (jsonObject.contains(JS(ledger_hash))) if (jsonObject.contains(JS(ledger_hash)))
input.ledgerHash = jsonObject.at(JS(ledger_hash)).as_string().c_str(); input.ledgerHash = jsonObject.at(JS(ledger_hash)).as_string().c_str();
if (jsonObject.contains(JS(ledger_index))) if (jsonObject.contains(JS(ledger_index))) {
input.ledgerIndex = util::getLedgerIndex(jsonObject.at(JS(ledger_index))); auto const expectedLedgerIndex = util::getLedgerIndex(jsonObject.at(JS(ledger_index)));
if (expectedLedgerIndex.has_value())
input.ledgerIndex = *expectedLedgerIndex;
}
if (jsonObject.contains(JS(limit))) if (jsonObject.contains(JS(limit)))
input.limit = util::integralValueAs<uint32_t>(jsonObject.at(JS(limit))); input.limit = util::integralValueAs<uint32_t>(jsonObject.at(JS(limit)));

View File

@@ -215,8 +215,11 @@ tag_invoke(boost::json::value_to_tag<NFTHistoryHandler::Input>, boost::json::val
if (jsonObject.contains(JS(ledger_hash))) if (jsonObject.contains(JS(ledger_hash)))
input.ledgerHash = boost::json::value_to<std::string>(jsonObject.at(JS(ledger_hash))); input.ledgerHash = boost::json::value_to<std::string>(jsonObject.at(JS(ledger_hash)));
if (jsonObject.contains(JS(ledger_index))) if (jsonObject.contains(JS(ledger_index))) {
input.ledgerIndex = util::getLedgerIndex(jsonObject.at(JS(ledger_index))); auto const expectedLedgerIndex = util::getLedgerIndex(jsonObject.at(JS(ledger_index)));
if (expectedLedgerIndex.has_value())
input.ledgerIndex = *expectedLedgerIndex;
}
if (jsonObject.contains(JS(binary))) if (jsonObject.contains(JS(binary)))
input.binary = jsonObject.at(JS(binary)).as_bool(); input.binary = jsonObject.at(JS(binary)).as_bool();

View File

@@ -115,8 +115,11 @@ tag_invoke(boost::json::value_to_tag<NFTInfoHandler::Input>, boost::json::value
if (jsonObject.contains(JS(ledger_hash))) if (jsonObject.contains(JS(ledger_hash)))
input.ledgerHash = boost::json::value_to<std::string>(jsonObject.at(JS(ledger_hash))); input.ledgerHash = boost::json::value_to<std::string>(jsonObject.at(JS(ledger_hash)));
if (jsonObject.contains(JS(ledger_index))) if (jsonObject.contains(JS(ledger_index))) {
input.ledgerIndex = util::getLedgerIndex(jsonObject.at(JS(ledger_index))); auto const expectedLedgerIndex = util::getLedgerIndex(jsonObject.at(JS(ledger_index)));
if (expectedLedgerIndex.has_value())
input.ledgerIndex = *expectedLedgerIndex;
}
return input; return input;
} }

View File

@@ -194,8 +194,11 @@ tag_invoke(boost::json::value_to_tag<NFTOffersHandlerBase::Input>, boost::json::
if (jsonObject.contains(JS(ledger_hash))) if (jsonObject.contains(JS(ledger_hash)))
input.ledgerHash = boost::json::value_to<std::string>(jsonObject.at(JS(ledger_hash))); input.ledgerHash = boost::json::value_to<std::string>(jsonObject.at(JS(ledger_hash)));
if (jsonObject.contains(JS(ledger_index))) if (jsonObject.contains(JS(ledger_index))) {
input.ledgerIndex = util::getLedgerIndex(jsonObject.at(JS(ledger_index))); auto const expectedLedgerIndex = util::getLedgerIndex(jsonObject.at(JS(ledger_index)));
if (expectedLedgerIndex.has_value())
input.ledgerIndex = *expectedLedgerIndex;
}
if (jsonObject.contains(JS(marker))) if (jsonObject.contains(JS(marker)))
input.marker = boost::json::value_to<std::string>(jsonObject.at(JS(marker))); input.marker = boost::json::value_to<std::string>(jsonObject.at(JS(marker)));

View File

@@ -136,8 +136,11 @@ tag_invoke(boost::json::value_to_tag<NFTsByIssuerHandler::Input>, boost::json::v
if (jsonObject.contains(JS(ledger_hash))) if (jsonObject.contains(JS(ledger_hash)))
input.ledgerHash = boost::json::value_to<std::string>(jsonObject.at(JS(ledger_hash))); input.ledgerHash = boost::json::value_to<std::string>(jsonObject.at(JS(ledger_hash)));
if (jsonObject.contains(JS(ledger_index))) if (jsonObject.contains(JS(ledger_index))) {
input.ledgerIndex = util::getLedgerIndex(jsonObject.at(JS(ledger_index))); auto const expectedLedgerIndex = util::getLedgerIndex(jsonObject.at(JS(ledger_index)));
if (expectedLedgerIndex.has_value())
input.ledgerIndex = *expectedLedgerIndex;
}
if (jsonObject.contains(JS(limit))) if (jsonObject.contains(JS(limit)))
input.limit = util::integralValueAs<uint32_t>(jsonObject.at(JS(limit))); input.limit = util::integralValueAs<uint32_t>(jsonObject.at(JS(limit)));

View File

@@ -196,8 +196,11 @@ tag_invoke(boost::json::value_to_tag<NoRippleCheckHandler::Input>, boost::json::
if (jsonObject.contains(JS(ledger_hash))) if (jsonObject.contains(JS(ledger_hash)))
input.ledgerHash = boost::json::value_to<std::string>(jsonObject.at(JS(ledger_hash))); input.ledgerHash = boost::json::value_to<std::string>(jsonObject.at(JS(ledger_hash)));
if (jsonObject.contains(JS(ledger_index))) if (jsonObject.contains(JS(ledger_index))) {
input.ledgerIndex = util::getLedgerIndex(jsonObject.at(JS(ledger_index))); auto const expectedLedgerIndex = util::getLedgerIndex(jsonObject.at(JS(ledger_index)));
if (expectedLedgerIndex.has_value())
input.ledgerIndex = *expectedLedgerIndex;
}
return input; return input;
} }

View File

@@ -109,8 +109,11 @@ tag_invoke(boost::json::value_to_tag<TransactionEntryHandler::Input>, boost::jso
if (jsonObject.contains(JS(ledger_hash))) if (jsonObject.contains(JS(ledger_hash)))
input.ledgerHash = boost::json::value_to<std::string>(jv.at(JS(ledger_hash))); input.ledgerHash = boost::json::value_to<std::string>(jv.at(JS(ledger_hash)));
if (jsonObject.contains(JS(ledger_index))) if (jsonObject.contains(JS(ledger_index))) {
input.ledgerIndex = util::getLedgerIndex(jv.at(JS(ledger_index))); auto const expectedLedgerIndex = util::getLedgerIndex(jv.at(JS(ledger_index)));
if (expectedLedgerIndex.has_value())
input.ledgerIndex = *expectedLedgerIndex;
}
return input; return input;
} }

View File

@@ -177,8 +177,11 @@ tag_invoke(boost::json::value_to_tag<VaultInfoHandler::Input>, boost::json::valu
if (jsonObject.contains(JS(vault_id))) if (jsonObject.contains(JS(vault_id)))
input.vaultID = jsonObject.at(JS(vault_id)).as_string(); input.vaultID = jsonObject.at(JS(vault_id)).as_string();
if (jsonObject.contains(JS(ledger_index))) if (jsonObject.contains(JS(ledger_index))) {
input.ledgerIndex = util::getLedgerIndex(jsonObject.at(JS(ledger_index))); auto const expectedLedgerIndex = util::getLedgerIndex(jsonObject.at(JS(ledger_index)));
if (expectedLedgerIndex.has_value())
input.ledgerIndex = *expectedLedgerIndex;
}
return input; return input;
} }

View File

@@ -23,10 +23,13 @@
#include <boost/json.hpp> #include <boost/json.hpp>
#include <boost/json/object.hpp> #include <boost/json/object.hpp>
#include <xrpl/beast/core/LexicalCast.h>
#include <algorithm> #include <algorithm>
#include <cctype> #include <cctype>
#include <charconv>
#include <concepts> #include <concepts>
#include <expected>
#include <stdexcept> #include <stdexcept>
#include <string> #include <string>
@@ -96,12 +99,11 @@ removeSecret(boost::json::object const& object)
* *
* @tparam Type The type to cast to * @tparam Type The type to cast to
* @param value The JSON value to cast * @param value The JSON value to cast
* @return Value casted to the requested type * @return Value casted to the requested type or an error message
* @throws logic_error if the underlying number is neither int64 nor uint64
*/ */
template <std::integral Type> template <std::integral Type>
Type std::expected<Type, std::string>
integralValueAs(boost::json::value const& value) tryIntegralValueAs(boost::json::value const& value)
{ {
if (value.is_uint64()) if (value.is_uint64())
return static_cast<Type>(value.as_uint64()); return static_cast<Type>(value.as_uint64());
@@ -109,29 +111,49 @@ integralValueAs(boost::json::value const& value)
if (value.is_int64()) if (value.is_int64())
return static_cast<Type>(value.as_int64()); return static_cast<Type>(value.as_int64());
throw std::logic_error("Value neither uint64 nor int64"); return std::unexpected("Value neither uint64 nor int64");
}
/**
* @brief Detects the type of number stored in value and casts it back to the requested Type.
* @note This conversion can possibly cause wrapping around or UB. Use with caution.
*
* @tparam Type The type to cast to
* @param value The JSON value to cast
* @return Value casted to the requested type
* @throws logic_error if the underlying number is neither int64 nor uint64
*/
template <std::integral Type>
Type
integralValueAs(boost::json::value const& value)
{
auto expectedResult = tryIntegralValueAs<Type>(value);
if (expectedResult.has_value())
return *expectedResult;
throw std::logic_error(std::move(expectedResult).error());
} }
/** /**
* @brief Extracts ledger index from a JSON value which can be either a number or a string. * @brief Extracts ledger index from a JSON value which can be either a number or a string.
* *
* @param value The JSON value to extract ledger index from * @param value The JSON value to extract ledger index from
* @return An optional containing the ledger index if it is a number; std::nullopt otherwise * @return The extracted ledger index or an error message
* @throws logic_error comes from integralValueAs if the underlying number is neither int64 nor uint64
* @throws std::invalid_argument or std::out_of_range if the string cannot be converted to a number
*/ */
[[nodiscard]] inline std::optional<uint32_t> [[nodiscard]] inline std::expected<uint32_t, std::string>
getLedgerIndex(boost::json::value const& value) getLedgerIndex(boost::json::value const& value)
{ {
std::optional<uint32_t> ledgerIndex;
if (not value.is_string()) { if (not value.is_string()) {
ledgerIndex = util::integralValueAs<uint32_t>(value); return tryIntegralValueAs<uint32_t>(value);
} else if (value.as_string() != "validated") {
ledgerIndex = std::stoi(value.as_string().c_str());
} }
if (value.as_string() != "validated") {
uint32_t ledgerIndex{};
if (beast::lexicalCastChecked(ledgerIndex, value.as_string().c_str())) {
return ledgerIndex; return ledgerIndex;
} }
return std::unexpected("Invalid ledger index string");
}
return std::unexpected("'validated' ledger index is requested");
}
} // namespace util } // namespace util

View File

@@ -255,7 +255,7 @@ This document provides a list of all available Clio configuration properties in
.value = "The number of worker threads or processes that are responsible for managing and processing " .value = "The number of worker threads or processes that are responsible for managing and processing "
"subscription-based tasks from `rippled`."}, "subscription-based tasks from `rippled`."},
KV{.key = "graceful_period", KV{.key = "graceful_period",
.value = "The number of milliseconds the server waits to shutdown gracefully. If Clio does not shutdown " .value = "The number of seconds the server waits to shutdown gracefully. If Clio does not shutdown "
"gracefully after the specified value, it will be killed instead."}, "gracefully after the specified value, it will be killed instead."},
KV{.key = "cache.num_diffs", KV{.key = "cache.num_diffs",
.value = "The number of cursors generated is the number of changed (without counting deleted) objects in " .value = "The number of cursors generated is the number of changed (without counting deleted) objects in "

View File

@@ -18,6 +18,7 @@
//============================================================================== //==============================================================================
#include "util/JsonUtils.hpp" #include "util/JsonUtils.hpp"
#include "util/NameGenerator.hpp"
#include <boost/json/parse.hpp> #include <boost/json/parse.hpp>
#include <boost/json/value.hpp> #include <boost/json/value.hpp>
@@ -26,7 +27,8 @@
#include <cstdint> #include <cstdint>
#include <limits> #include <limits>
#include <stdexcept> #include <stdexcept>
#include <tuple> #include <string>
#include <type_traits>
TEST(JsonUtils, RemoveSecrets) TEST(JsonUtils, RemoveSecrets)
{ {
@@ -90,28 +92,123 @@ TEST(JsonUtils, integralValueAs)
EXPECT_THROW(util::integralValueAs<int>(stringJson), std::logic_error); EXPECT_THROW(util::integralValueAs<int>(stringJson), std::logic_error);
} }
TEST(JsonUtils, getLedgerIndex) TEST(JsonUtils, tryIntegralValueAs)
{ {
auto const emptyJson = boost::json::value(); auto const expectedResultUint64 = static_cast<uint64_t>(std::numeric_limits<int32_t>::max()) + 1u;
EXPECT_THROW(std::ignore = util::getLedgerIndex(emptyJson), std::logic_error); auto const uint64Json = boost::json::value(expectedResultUint64);
auto const boolJson = boost::json::value(true); auto const expectedResultInt64 = static_cast<int64_t>(std::numeric_limits<int32_t>::max()) + 1u;
EXPECT_THROW(std::ignore = util::getLedgerIndex(emptyJson), std::logic_error); auto const int64Json = boost::json::value(expectedResultInt64);
auto const numberJson = boost::json::value(12345); auto checkHasValue = [&](boost::json::value const& jv, auto const& expectedValue) {
auto ledgerIndex = util::getLedgerIndex(numberJson); using T = std::remove_cvref_t<decltype(expectedValue)>;
EXPECT_TRUE(ledgerIndex.has_value()); auto const res = util::tryIntegralValueAs<T>(jv);
EXPECT_EQ(ledgerIndex.value(), 12345u); ASSERT_TRUE(res.has_value());
EXPECT_EQ(res.value(), expectedValue);
};
auto const validStringJson = boost::json::value("12345"); auto checkError = [&](boost::json::value const& jv) {
ledgerIndex = util::getLedgerIndex(validStringJson); auto res = util::tryIntegralValueAs<int>(jv);
EXPECT_TRUE(ledgerIndex.has_value()); EXPECT_FALSE(res.has_value());
EXPECT_EQ(ledgerIndex.value(), 12345u); EXPECT_EQ(res.error(), "Value neither uint64 nor int64");
};
auto const invalidStringJson = boost::json::value("invalid123"); // checks for uint64Json
EXPECT_THROW(std::ignore = util::getLedgerIndex(invalidStringJson), std::invalid_argument); checkHasValue(uint64Json, std::numeric_limits<int32_t>::min());
checkHasValue(uint64Json, static_cast<uint32_t>(expectedResultUint64));
checkHasValue(uint64Json, static_cast<int64_t>(expectedResultUint64));
checkHasValue(uint64Json, expectedResultUint64);
auto const validatedJson = boost::json::value("validated"); // checks for int64Json
ledgerIndex = util::getLedgerIndex(validatedJson); checkHasValue(int64Json, std::numeric_limits<int32_t>::min());
EXPECT_FALSE(ledgerIndex.has_value()); checkHasValue(int64Json, static_cast<uint32_t>(expectedResultInt64));
checkHasValue(int64Json, expectedResultInt64);
checkHasValue(int64Json, static_cast<uint64_t>(expectedResultInt64));
// non-integral inputs
checkError(boost::json::value());
checkError(boost::json::value(false));
checkError(boost::json::value(3.14));
checkError(boost::json::value("not a number"));
}
struct GetLedgerIndexParameterTestBundle {
std::string testName;
boost::json::value jv;
std::expected<uint32_t, std::string> expectedResult;
};
// parameterized test cases for parameters check
struct GetLedgerIndexParameterTest : ::testing::TestWithParam<GetLedgerIndexParameterTestBundle> {};
INSTANTIATE_TEST_CASE_P(
JsonUtils,
GetLedgerIndexParameterTest,
testing::Values(
GetLedgerIndexParameterTestBundle{
.testName = "EmptyValue",
.jv = boost::json::value(),
.expectedResult = std::unexpected{"Value neither uint64 nor int64"}
},
GetLedgerIndexParameterTestBundle{
.testName = "BoolValue",
.jv = boost::json::value(false),
.expectedResult = std::unexpected{"Value neither uint64 nor int64"}
},
GetLedgerIndexParameterTestBundle{
.testName = "NumberValue",
.jv = boost::json::value(123),
.expectedResult = 123u
},
GetLedgerIndexParameterTestBundle{
.testName = "StringNumberValue",
.jv = boost::json::value("123"),
.expectedResult = 123u
},
GetLedgerIndexParameterTestBundle{
.testName = "StringNumberWithPlusSignValue",
.jv = boost::json::value("+123"),
.expectedResult = 123u
},
GetLedgerIndexParameterTestBundle{
.testName = "StringEmptyValue",
.jv = boost::json::value(""),
.expectedResult = std::unexpected{"Invalid ledger index string"}
},
GetLedgerIndexParameterTestBundle{
.testName = "StringWithLeadingCharsValue",
.jv = boost::json::value("123invalid"),
.expectedResult = std::unexpected{"Invalid ledger index string"}
},
GetLedgerIndexParameterTestBundle{
.testName = "StringWithTrailingCharsValue",
.jv = boost::json::value("invalid123"),
.expectedResult = std::unexpected{"Invalid ledger index string"}
},
GetLedgerIndexParameterTestBundle{
.testName = "StringWithLeadingAndTrailingCharsValue",
.jv = boost::json::value("123invalid123"),
.expectedResult = std::unexpected{"Invalid ledger index string"}
},
GetLedgerIndexParameterTestBundle{
.testName = "ValidatedStringValue",
.jv = boost::json::value("validated"),
.expectedResult = std::unexpected{"'validated' ledger index is requested"}
}
),
tests::util::kNAME_GENERATOR
);
TEST_P(GetLedgerIndexParameterTest, getLedgerIndexParams)
{
auto const& testBundle = GetParam();
auto const ledgerIndex = util::getLedgerIndex(testBundle.jv);
if (testBundle.expectedResult.has_value()) {
EXPECT_TRUE(ledgerIndex.has_value());
EXPECT_EQ(ledgerIndex.value(), testBundle.expectedResult.value());
} else {
EXPECT_FALSE(ledgerIndex.has_value());
EXPECT_EQ(ledgerIndex.error(), testBundle.expectedResult.error());
}
} }