mirror of
https://github.com/XRPLF/rippled.git
synced 2026-08-21 22:30:57 +00:00
Merge remote-tracking branch 'origin/develop' into FN-36-credential_pins_pseudo_account
This commit is contained in:
@@ -85,6 +85,8 @@ CheckOptions:
|
||||
|
||||
readability-braces-around-statements.ShortStatementLines: 2
|
||||
readability-identifier-naming.MacroDefinitionCase: UPPER_CASE
|
||||
readability-identifier-naming.NamespaceCase: lower_case
|
||||
readability-identifier-naming.InlineNamespaceCase: lower_case
|
||||
readability-identifier-naming.ClassCase: CamelCase
|
||||
readability-identifier-naming.StructCase: CamelCase
|
||||
readability-identifier-naming.UnionCase: CamelCase
|
||||
|
||||
@@ -132,6 +132,7 @@ words:
|
||||
- godexsoft
|
||||
- gpgcheck
|
||||
- gpgkey
|
||||
- Hinnant
|
||||
- hotwallet
|
||||
- hwaddress
|
||||
- hwrap
|
||||
@@ -165,6 +166,7 @@ words:
|
||||
- llection
|
||||
- LOCALGOOD
|
||||
- logwstream
|
||||
- Lombrozo
|
||||
- lseq
|
||||
- lsmf
|
||||
- ltype
|
||||
@@ -201,6 +203,7 @@ words:
|
||||
- nftokens
|
||||
- nftpage
|
||||
- nikb
|
||||
- Nikolaos
|
||||
- nixfmt
|
||||
- nixos
|
||||
- nixpkgs
|
||||
|
||||
19
.github/scripts/strategy-matrix/generate.py
vendored
19
.github/scripts/strategy-matrix/generate.py
vendored
@@ -33,6 +33,10 @@ def get_cmake_args(build_type: str, extra_args: str) -> str:
|
||||
# Every config must declare 'minimal'. Minimal configs form the reduced matrix
|
||||
# built for pull requests by default; the full matrix adds the rest. Packaging
|
||||
# configs declare it too, but packaging is gated in the workflow, not by it.
|
||||
#
|
||||
# Configs may also opt into 'benchmark' to smoke-run the benchmarks. Note that
|
||||
# the flag applies to every entry a config expands into, so only set it on
|
||||
# configs that expand to a single combination.
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
@@ -43,6 +47,7 @@ class LinuxConfig:
|
||||
build_type: list[str]
|
||||
arch: list[str]
|
||||
minimal: bool
|
||||
benchmark: bool = False # if true, smoke-run the benchmarks after testing
|
||||
sanitizers: list[str] = dataclasses.field(default_factory=list)
|
||||
suffix: str = ""
|
||||
extra_cmake_args: str = ""
|
||||
@@ -81,6 +86,7 @@ class PlatformConfig:
|
||||
build_type: list[str]
|
||||
minimal: bool
|
||||
build_only: bool = False # if true, skip tests (e.g. macos/Windows Debug)
|
||||
benchmark: bool = False # if true, smoke-run the benchmarks after testing
|
||||
extra_cmake_args: str = ""
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
@@ -125,6 +131,7 @@ class MatrixEntry:
|
||||
cmake_args: str
|
||||
cmake_target: str
|
||||
build_only: bool
|
||||
benchmark: bool
|
||||
build_type: str
|
||||
architecture: Architecture
|
||||
sanitizers: str
|
||||
@@ -136,7 +143,8 @@ class MatrixEntry:
|
||||
class PackagingEntry:
|
||||
"""One entry in the generated packaging strategy matrix."""
|
||||
|
||||
artifact_name: str
|
||||
xrpld_artifact_name: str
|
||||
validator_keys_artifact_name: str
|
||||
image: str
|
||||
distro: str # e.g. "debian" or "rhel"; drives package-format-specific steps
|
||||
|
||||
@@ -193,6 +201,7 @@ def expand_linux_matrix(linux: LinuxFile, minimal: bool) -> list[MatrixEntry]:
|
||||
cmake_args=get_cmake_args(build_type, cfg.extra_cmake_args),
|
||||
cmake_target="all",
|
||||
build_only=False,
|
||||
benchmark=cfg.benchmark,
|
||||
build_type=build_type,
|
||||
architecture=arch_info,
|
||||
sanitizers=sanitizer,
|
||||
@@ -210,14 +219,19 @@ def expand_linux_packaging(linux: LinuxFile) -> list[PackagingEntry]:
|
||||
the nix-based build images, because deb/rpm tooling (debhelper, rpm-build)
|
||||
is taken from the distro's archive rather than from nixpkgs. Each config
|
||||
entry carries its own 'image'.
|
||||
|
||||
The artifact names must match what the build job uploads: one artifact per
|
||||
binary, each named after the build config.
|
||||
"""
|
||||
entries = []
|
||||
for distro, configs in linux.package_configs.items():
|
||||
for cfg in configs:
|
||||
for compiler, build_type in itertools.product(cfg.compiler, cfg.build_type):
|
||||
config_name = f"{distro}-{compiler}-{build_type.lower()}-amd64"
|
||||
entries.append(
|
||||
PackagingEntry(
|
||||
artifact_name=f"xrpld-{distro}-{compiler}-{build_type.lower()}-amd64",
|
||||
xrpld_artifact_name=f"xrpld-{config_name}",
|
||||
validator_keys_artifact_name=f"validator-keys-{config_name}",
|
||||
image=cfg.image,
|
||||
distro=distro,
|
||||
)
|
||||
@@ -245,6 +259,7 @@ def expand_platform_matrix(pf: PlatformFile, minimal: bool) -> list[MatrixEntry]
|
||||
cmake_args=get_cmake_args(build_type, cfg.extra_cmake_args),
|
||||
cmake_target="install" if is_windows else "all",
|
||||
build_only=cfg.build_only,
|
||||
benchmark=cfg.benchmark,
|
||||
build_type=build_type,
|
||||
architecture=Architecture(platform=pf.platform, runner=pf.runner),
|
||||
sanitizers="",
|
||||
|
||||
9
.github/scripts/strategy-matrix/linux.json
vendored
9
.github/scripts/strategy-matrix/linux.json
vendored
@@ -14,7 +14,8 @@
|
||||
"compiler": ["clang"],
|
||||
"build_type": ["Release"],
|
||||
"arch": ["amd64"],
|
||||
"minimal": true
|
||||
"minimal": true,
|
||||
"benchmark": true
|
||||
},
|
||||
|
||||
{
|
||||
@@ -69,7 +70,8 @@
|
||||
"compiler": ["gcc"],
|
||||
"build_type": ["Release"],
|
||||
"arch": ["amd64"],
|
||||
"minimal": false
|
||||
"minimal": false,
|
||||
"extra_cmake_args": "-Dvalidator_keys=ON"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -78,7 +80,8 @@
|
||||
"compiler": ["gcc"],
|
||||
"build_type": ["Release"],
|
||||
"arch": ["amd64"],
|
||||
"minimal": false
|
||||
"minimal": false,
|
||||
"extra_cmake_args": "-Dvalidator_keys=ON"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
7
.github/workflows/on-pr.yml
vendored
7
.github/workflows/on-pr.yml
vendored
@@ -82,6 +82,7 @@ jobs:
|
||||
.github/scripts/strategy-matrix/**
|
||||
.github/workflows/reusable-build-test-config.yml
|
||||
.github/workflows/reusable-build-test.yml
|
||||
.github/workflows/reusable-check-autogen.yml
|
||||
.github/workflows/reusable-clang-tidy.yml
|
||||
.github/workflows/reusable-package.yml
|
||||
.github/workflows/reusable-strategy-matrix.yml
|
||||
@@ -126,6 +127,11 @@ jobs:
|
||||
outputs:
|
||||
go: ${{ steps.go.outputs.go == 'true' }}
|
||||
|
||||
check-autogen:
|
||||
needs: should-run
|
||||
if: ${{ needs.should-run.outputs.go == 'true' }}
|
||||
uses: ./.github/workflows/reusable-check-autogen.yml
|
||||
|
||||
check-levelization:
|
||||
needs: should-run
|
||||
if: ${{ needs.should-run.outputs.go == 'true' }}
|
||||
@@ -200,6 +206,7 @@ jobs:
|
||||
passed:
|
||||
if: failure() || cancelled()
|
||||
needs:
|
||||
- check-autogen
|
||||
- check-levelization
|
||||
- check-rename
|
||||
- clang-tidy
|
||||
|
||||
4
.github/workflows/on-trigger.yml
vendored
4
.github/workflows/on-trigger.yml
vendored
@@ -20,6 +20,7 @@ on:
|
||||
- ".github/scripts/strategy-matrix/**"
|
||||
- ".github/workflows/reusable-build-test-config.yml"
|
||||
- ".github/workflows/reusable-build-test.yml"
|
||||
- ".github/workflows/reusable-check-autogen.yml"
|
||||
- ".github/workflows/reusable-clang-tidy.yml"
|
||||
- ".github/workflows/reusable-package.yml"
|
||||
- ".github/workflows/reusable-strategy-matrix.yml"
|
||||
@@ -67,6 +68,9 @@ defaults:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
check-autogen:
|
||||
uses: ./.github/workflows/reusable-check-autogen.yml
|
||||
|
||||
clang-tidy:
|
||||
uses: ./.github/workflows/reusable-clang-tidy.yml
|
||||
permissions:
|
||||
|
||||
70
.github/workflows/reusable-build-test-config.yml
vendored
70
.github/workflows/reusable-build-test-config.yml
vendored
@@ -3,6 +3,12 @@ name: Build and test configuration
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
benchmark:
|
||||
description: "Whether to smoke-run the benchmarks after testing."
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
build_only:
|
||||
description: 'Whether to only build or to build and test the code ("true", "false").'
|
||||
required: true
|
||||
@@ -100,9 +106,10 @@ jobs:
|
||||
# header files are copied into separate directories by CMake, which will
|
||||
# otherwise result in cache misses.
|
||||
CCACHE_SLOPPINESS: include_file_ctime,include_file_mtime
|
||||
# Determine if coverage and voidstar should be enabled.
|
||||
# Determine if coverage, voidstar and validator-keys should be enabled.
|
||||
COVERAGE_ENABLED: ${{ contains(inputs.cmake_args, '-Dcoverage=ON') }}
|
||||
VOIDSTAR_ENABLED: ${{ contains(inputs.cmake_args, '-Dvoidstar=ON') }}
|
||||
VALIDATOR_KEYS_ENABLED: ${{ contains(inputs.cmake_args, '-Dvalidator_keys=ON') }}
|
||||
SANITIZERS_ENABLED: ${{ inputs.sanitizers != '' }}
|
||||
steps:
|
||||
- name: Cleanup workspace (macOS and Windows)
|
||||
@@ -170,9 +177,9 @@ jobs:
|
||||
..
|
||||
|
||||
# Export the sanitizer options before any instrumented binary runs. The
|
||||
# protocol code-gen and build steps below invoke instrumented dependency
|
||||
# tools (protoc, grpc), so setting UBSAN_OPTIONS here lets the UBSan
|
||||
# suppression list silence their diagnostics too, not just at test time.
|
||||
# build step below invokes instrumented dependency tools (protoc, grpc),
|
||||
# so setting UBSAN_OPTIONS here lets the UBSan suppression list silence
|
||||
# their diagnostics too, not just at test time.
|
||||
# GITHUB_WORKSPACE (not the github.workspace context) is used so the path
|
||||
# resolves correctly inside the container job.
|
||||
- name: Set sanitizer options
|
||||
@@ -190,32 +197,6 @@ jobs:
|
||||
echo "UBSAN_OPTIONS=include=${SUPP}/runtime-ubsan-options.txt:suppressions=${SUPP}/ubsan.supp" >>${GITHUB_ENV}
|
||||
echo "LSAN_OPTIONS=include=${SUPP}/runtime-lsan-options.txt:suppressions=${SUPP}/lsan.supp" >>${GITHUB_ENV}
|
||||
|
||||
- name: Check protocol autogen files are up-to-date
|
||||
working-directory: ${{ env.BUILD_DIR }}
|
||||
env:
|
||||
MESSAGE: |
|
||||
|
||||
The generated protocol wrapper classes are out of date.
|
||||
|
||||
This typically happens when the macro files or generator scripts
|
||||
have changed but the generated files were not regenerated.
|
||||
|
||||
To fix this:
|
||||
1. Run: cmake --build . --target setup_code_gen
|
||||
2. Run: cmake --build . --target code_gen
|
||||
3. Commit and push the regenerated files
|
||||
run: |
|
||||
set -e
|
||||
cmake --build . --target setup_code_gen
|
||||
cmake --build . --target code_gen
|
||||
DIFF=$(git -C .. status --porcelain -- include/xrpl/protocol_autogen src/tests/libxrpl/protocol_autogen)
|
||||
if [ -n "${DIFF}" ]; then
|
||||
echo "::error::Generated protocol files are out of date"
|
||||
git -C .. diff -- include/xrpl/protocol_autogen src/tests/libxrpl/protocol_autogen
|
||||
echo "${MESSAGE}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Build the binary
|
||||
working-directory: ${{ env.BUILD_DIR }}
|
||||
env:
|
||||
@@ -249,6 +230,22 @@ jobs:
|
||||
retention-days: 3
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Run the validator-keys tests
|
||||
if: ${{ env.VALIDATOR_KEYS_ENABLED == 'true' }}
|
||||
working-directory: ${{ env.BUILD_DIR }}
|
||||
run: ./validator-keys --unittest
|
||||
|
||||
- name: Upload the validator-keys binary
|
||||
if: ${{ github.event.repository.visibility == 'public' && env.VALIDATOR_KEYS_ENABLED == 'true' }}
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: validator-keys-${{ inputs.config_name }}
|
||||
path: |
|
||||
${{ env.BUILD_DIR }}/validator-keys
|
||||
${{ env.BUILD_DIR }}/validator-keys-LICENSE
|
||||
retention-days: 3
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Upload the test binary (Linux)
|
||||
if: ${{ github.event.repository.visibility == 'public' && runner.os == 'Linux' }}
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
@@ -328,11 +325,14 @@ jobs:
|
||||
|
||||
# Smoke-run every benchmark module with a single repetition to confirm the
|
||||
# benchmarks still build and execute. This is a correctness check, not a
|
||||
# performance measurement, so it is skipped for instrumented builds
|
||||
# (sanitizers/coverage/voidstar), where it would be slow and meaningless,
|
||||
# and on Windows, where the `install` target does not build them.
|
||||
# performance measurement, so there is nothing to gain from repeating it
|
||||
# across configurations: it is opted into by a single config in the
|
||||
# strategy matrix (see the 'benchmark' flag in the JSON files), which
|
||||
# keeps it off instrumented builds (sanitizers/coverage/voidstar), where
|
||||
# it would be slow and meaningless, off Debug builds, where it is much
|
||||
# slower, and off Windows, where the `install` target does not build them.
|
||||
- name: Run the benchmarks
|
||||
if: ${{ !inputs.build_only && runner.os != 'Windows' && env.SANITIZERS_ENABLED == 'false' && env.COVERAGE_ENABLED != 'true' && env.VOIDSTAR_ENABLED != 'true' }}
|
||||
if: ${{ inputs.benchmark }}
|
||||
working-directory: ${{ env.BUILD_DIR }}
|
||||
run: |
|
||||
rc=0
|
||||
@@ -387,7 +387,7 @@ jobs:
|
||||
--target coverage
|
||||
|
||||
- name: Upload coverage report
|
||||
if: ${{ github.repository == 'XRPLF/rippled' && !inputs.build_only && env.COVERAGE_ENABLED == 'true' }}
|
||||
if: ${{ github.repository_owner == 'XRPLF' && !inputs.build_only && env.COVERAGE_ENABLED == 'true' }}
|
||||
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
|
||||
with:
|
||||
disable_search: true
|
||||
|
||||
1
.github/workflows/reusable-build-test.yml
vendored
1
.github/workflows/reusable-build-test.yml
vendored
@@ -40,6 +40,7 @@ jobs:
|
||||
fail-fast: ${{ github.event_name == 'merge_group' }}
|
||||
matrix: ${{ fromJson(needs.generate-matrix.outputs.matrix) }}
|
||||
with:
|
||||
benchmark: ${{ matrix.benchmark }}
|
||||
build_only: ${{ matrix.build_only }}
|
||||
build_type: ${{ matrix.build_type }}
|
||||
ccache_enabled: ${{ inputs.ccache_enabled }}
|
||||
|
||||
76
.github/workflows/reusable-check-autogen.yml
vendored
Normal file
76
.github/workflows/reusable-check-autogen.yml
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
# This workflow checks that the generated protocol wrapper classes are
|
||||
# up-to-date with the macro files and generator scripts they are produced from,
|
||||
# see more info in include/xrpl/protocol_autogen/README.md.
|
||||
name: Check autogen
|
||||
|
||||
# This workflow can only be triggered by other workflows.
|
||||
on: workflow_call
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}-autogen
|
||||
cancel-in-progress: true
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
env:
|
||||
BUILD_DIR: build/codegen
|
||||
|
||||
jobs:
|
||||
autogen:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
||||
with:
|
||||
python-version: "3.13"
|
||||
|
||||
# Code generation is pure Python, so the standalone project below offers
|
||||
# the same targets as the main build without needing its dependencies or
|
||||
# a compiler, which keeps this job down to a few seconds.
|
||||
- name: Configure CMake
|
||||
run: cmake -S cmake/codegen -B "${BUILD_DIR}"
|
||||
|
||||
- name: Install code generation dependencies
|
||||
run: cmake --build "${BUILD_DIR}" --target setup_code_gen
|
||||
|
||||
- name: Generate code
|
||||
run: cmake --build "${BUILD_DIR}" --target code_gen
|
||||
|
||||
- name: Check for differences
|
||||
env:
|
||||
MESSAGE: |
|
||||
|
||||
The generated protocol wrapper classes are out of date.
|
||||
|
||||
This typically happens when the macro files or generator scripts
|
||||
have changed but the generated files were not regenerated.
|
||||
|
||||
Run the following from the repository root, then commit and push
|
||||
the regenerated files. This needs neither the dependencies nor a
|
||||
compiler. See include/xrpl/protocol_autogen/README.md for more info.
|
||||
|
||||
cmake -S cmake/codegen -B build/codegen
|
||||
cmake --build build/codegen --target setup_code_gen
|
||||
cmake --build build/codegen --target code_gen
|
||||
|
||||
In an already configured build directory, the 'setup_code_gen' and
|
||||
'code_gen' targets do the same thing.
|
||||
run: |
|
||||
# Record untracked files in the index without staging their contents,
|
||||
# so that classes generated for a newly added transaction or ledger
|
||||
# entry type show up in the diff below rather than silently as an
|
||||
# empty one.
|
||||
git add --intent-to-add .
|
||||
DIFF=$(git status --porcelain)
|
||||
if [ -n "${DIFF}" ]; then
|
||||
# Print the differences to give the contributor a hint about what to
|
||||
# expect when running code generation on their own machine.
|
||||
git diff
|
||||
echo "${MESSAGE}"
|
||||
exit 1
|
||||
fi
|
||||
26
.github/workflows/reusable-package.yml
vendored
26
.github/workflows/reusable-package.yml
vendored
@@ -1,7 +1,7 @@
|
||||
# Build Linux packages (DEB and RPM) from pre-built binary artifacts.
|
||||
# Discovers which configurations to package from linux.json (configs in
|
||||
# "package_configs") and fans out one job per distro. Only linux/amd64 is
|
||||
# supported; the runner is hardcoded in the job below.
|
||||
# Build Linux packages (DEB and RPM) from pre-built binary artifacts (xrpld and
|
||||
# validator-keys). Discovers which configurations to package from linux.json
|
||||
# (configs in "package_configs") and fans out one job per distro. Only
|
||||
# linux/amd64 is supported; the runner is hardcoded in the job below.
|
||||
name: Package
|
||||
|
||||
on:
|
||||
@@ -45,7 +45,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix: ${{ fromJson(needs.generate-matrix.outputs.matrix) }}
|
||||
name: "${{ matrix.artifact_name }}"
|
||||
name: "${{ matrix.xrpld_artifact_name }}"
|
||||
permissions:
|
||||
contents: read
|
||||
runs-on: ["self-hosted", "Linux", "X64", "heavy"]
|
||||
@@ -56,14 +56,20 @@ jobs:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
|
||||
- name: Download pre-built binary
|
||||
- name: Download pre-built xrpld binary
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
name: ${{ matrix.artifact_name }}
|
||||
name: ${{ matrix.xrpld_artifact_name }}
|
||||
path: ${{ env.BUILD_DIR }}
|
||||
|
||||
- name: Make binary executable
|
||||
run: chmod +x "${BUILD_DIR}/xrpld"
|
||||
- name: Download pre-built validator-keys binary
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
name: ${{ matrix.validator_keys_artifact_name }}
|
||||
path: ${{ env.BUILD_DIR }}
|
||||
|
||||
- name: Make binaries executable
|
||||
run: chmod +x "${BUILD_DIR}/xrpld" "${BUILD_DIR}/validator-keys"
|
||||
|
||||
- name: Build package
|
||||
env:
|
||||
@@ -73,7 +79,7 @@ jobs:
|
||||
- name: Upload package artifact
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: ${{ matrix.artifact_name }}-pkg
|
||||
name: ${{ matrix.xrpld_artifact_name }}-pkg
|
||||
path: |
|
||||
${{ env.BUILD_DIR }}/debbuild/*.deb
|
||||
${{ env.BUILD_DIR }}/debbuild/*.ddeb
|
||||
|
||||
@@ -42,6 +42,7 @@ This section contains changes targeting a future version.
|
||||
|
||||
### Bugfixes
|
||||
|
||||
- `get_aggregate_price`: Duplicate entries in the `oracles` request array are now ignored. [#6586](https://github.com/XRPLF/rippled/pull/6586)
|
||||
- Peer Crawler: The `port` field in `overlay.active[]` now consistently returns an integer instead of a string for outbound peers. [#6318](https://github.com/XRPLF/rippled/pull/6318)
|
||||
- `ping`: The `ip` field is no longer returned as an empty string for proxied connections without a forwarded-for header. It is now omitted, consistent with the behavior for identified connections. [#6730](https://github.com/XRPLF/rippled/pull/6730)
|
||||
- gRPC `GetLedgerDiff`: Fixed error message that incorrectly said "base ledger not validated" when the desired ledger was not validated. [#6730](https://github.com/XRPLF/rippled/pull/6730)
|
||||
|
||||
14
BUILD.md
14
BUILD.md
@@ -42,6 +42,8 @@ Our Linux CI tooling is distro-independent and uses a Nix-based environment, so
|
||||
### macOS
|
||||
|
||||
Many `xrpld` engineers use macOS for development.
|
||||
The minimum supported version is macOS 15 (Sequoia).
|
||||
CI testing is done in macOS 26 (Tahoe), but the build defaults `CMAKE_OSX_DEPLOYMENT_TARGET` to 15.
|
||||
|
||||
### Windows
|
||||
|
||||
@@ -245,7 +247,17 @@ cmake --build . --target setup_code_gen # create venv and install dependencies
|
||||
cmake --build . --target code_gen # regenerate code
|
||||
```
|
||||
|
||||
The regenerated files should be committed alongside your changes.
|
||||
The same targets are also available as a standalone project, which does not
|
||||
need the dependencies to be configured first:
|
||||
|
||||
```
|
||||
cmake -S cmake/codegen -B build/codegen
|
||||
cmake --build build/codegen --target setup_code_gen
|
||||
cmake --build build/codegen --target code_gen
|
||||
```
|
||||
|
||||
The regenerated files should be committed alongside your changes. CI verifies
|
||||
that they are up-to-date.
|
||||
|
||||
## Coverage report
|
||||
|
||||
|
||||
@@ -13,6 +13,23 @@ if(DEFINED CMAKE_MODULE_PATH)
|
||||
endif()
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||
|
||||
# Must be set before project() because project() consumes it when configuring the compiler and SDK.
|
||||
# A user-provided -DCMAKE_OSX_DEPLOYMENT_TARGET still takes precedence.
|
||||
#
|
||||
# CMAKE_SYSTEM_NAME can't be used before project(), so CMAKE_HOST_SYSTEM_NAME is used instead.
|
||||
#
|
||||
# When CMAKE_OSX_DEPLOYMENT_TARGET is bumped to >=26.0, FastFloat dependency won't be needed anymore
|
||||
if(
|
||||
CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin"
|
||||
AND NOT DEFINED CMAKE_OSX_DEPLOYMENT_TARGET
|
||||
)
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET
|
||||
"15.0"
|
||||
CACHE STRING
|
||||
"Minimum macOS deployment version"
|
||||
)
|
||||
endif()
|
||||
|
||||
project(xrpl)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
@@ -87,6 +104,7 @@ include(deps/Boost)
|
||||
add_subdirectory(external/antithesis-sdk)
|
||||
find_package(date REQUIRED)
|
||||
find_package(ed25519 REQUIRED)
|
||||
find_package(FastFloat REQUIRED)
|
||||
find_package(gRPC REQUIRED)
|
||||
find_package(LibArchive REQUIRED)
|
||||
find_package(lz4 REQUIRED)
|
||||
@@ -102,6 +120,7 @@ target_link_libraries(
|
||||
xrpl_libs
|
||||
INTERFACE
|
||||
ed25519::ed25519
|
||||
FastFloat::fast_float
|
||||
lz4::lz4
|
||||
mpt-crypto::mpt-crypto
|
||||
OpenSSL::Crypto
|
||||
@@ -142,8 +161,10 @@ endif()
|
||||
include(XrplCore)
|
||||
include(XrplProtocolAutogen)
|
||||
include(XrplInstall)
|
||||
include(XrplPackaging)
|
||||
include(XrplValidatorKeys)
|
||||
# Must come after XrplValidatorKeys: the 'package' target depends on the
|
||||
# validator-keys target existing.
|
||||
include(XrplPackaging)
|
||||
|
||||
if(tests)
|
||||
include(CTest)
|
||||
|
||||
@@ -488,6 +488,17 @@
|
||||
# Must be a number between 100 and 1000, defaults to 250
|
||||
#
|
||||
#
|
||||
# [max_subscriptions_per_connection]
|
||||
#
|
||||
# Maximum number of account, real-time account, and account-history
|
||||
# subscriptions a single client connection may hold at once. Bounds the
|
||||
# per-connection state torn down when the connection disconnects. Book
|
||||
# subscriptions are tracked separately and are not counted here.
|
||||
#
|
||||
# Defaults to 100000 if not set; large enough for legitimate power users
|
||||
# such as block explorers.
|
||||
#
|
||||
#
|
||||
# [overlay]
|
||||
#
|
||||
# Controls settings related to the peer to peer overlay.
|
||||
@@ -538,6 +549,45 @@
|
||||
# only be used for local testing and debugging. Do not disable
|
||||
# on mainnet.
|
||||
#
|
||||
# max_untrusted_count = <number>
|
||||
#
|
||||
# The number of manifests the server keeps for validators it does not
|
||||
# list, and the number it sends and processes in a single peer protocol
|
||||
# message. Once the server holds this many, a manifest for a new
|
||||
# unlisted validator is rejected, so peer gossip cannot grow the cache
|
||||
# without end.
|
||||
#
|
||||
# This option can take any value between 50 and 1000, inclusive. If
|
||||
# the option is not present the server uses its built-in value.
|
||||
#
|
||||
# The current default (which is subject to change) is 300.
|
||||
#
|
||||
# max_trusted_count = <number>
|
||||
#
|
||||
# The number of manifests for listed validators to allow for when
|
||||
# sizing peer protocol messages. Manifests for listed validators are
|
||||
# never dropped, whether sending or receiving, because doing so would
|
||||
# delay a validator key change reaching this server. Set this above the
|
||||
# number of validators the server lists.
|
||||
#
|
||||
# Together the two counts above set the largest manifest message the
|
||||
# server accepts: bigger messages are discarded without reading them,
|
||||
# and without penalising the sender. Raising either means the server
|
||||
# accepts and sends bigger messages than a peer using the defaults, and
|
||||
# those peers will discard what this server sends. Lowering either below
|
||||
# what peers send makes this server discard their manifest messages,
|
||||
# which it does without recording anything.
|
||||
#
|
||||
# This option can take any value between 50 and 1000, inclusive. If
|
||||
# the option is not present the server uses its built-in value.
|
||||
#
|
||||
# The current default (which is subject to change) is 300.
|
||||
#
|
||||
# NOTE: These two options (max_untrusted_count and max_trusted_count)
|
||||
# are transitional. They exist to bound manifest-message size and cache
|
||||
# growth during the network upgrade. They may be removed in a future
|
||||
# release once the fleet has upgraded, and should not be relied upon as
|
||||
# stable configuration.
|
||||
#
|
||||
# [transaction_queue] EXPERIMENTAL
|
||||
#
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
Patch executables to run in non-Nix environments.
|
||||
|
||||
The Nix toolchain links binaries against an ELF interpreter (loader)
|
||||
that lives in the Nix store, so the resulting binaries don't run elsewhere.
|
||||
`patch_nix_binary` adds a POST_BUILD step that resets the interpreter
|
||||
to the system default loader and drops the rpath.
|
||||
that lives in the Nix store, so the resulting binaries don't run elsewhere
|
||||
(including once installed from the .deb package). `patch_nix_binary` resets
|
||||
the interpreter to the system default loader and drops the rpath, once the
|
||||
binary has been linked.
|
||||
|
||||
This runs by default for Nix-toolchain builds (determined by whether the compiler resolves under /nix/store/).
|
||||
Those builds are where binaries get a Nix-store loader.
|
||||
@@ -52,13 +53,38 @@ function(patch_nix_binary target)
|
||||
if(NOT PATCH_NIX_BINARIES)
|
||||
return()
|
||||
endif()
|
||||
add_custom_command(
|
||||
TARGET ${target}
|
||||
POST_BUILD
|
||||
COMMAND
|
||||
"${PATCHELF_COMMAND}" --set-interpreter "${DEFAULT_LOADER_PATH}"
|
||||
--remove-rpath "$<TARGET_FILE:${target}>"
|
||||
COMMENT "Patching ${target}: set default loader, remove rpath"
|
||||
VERBATIM
|
||||
|
||||
set(patch_command
|
||||
"${PATCHELF_COMMAND}"
|
||||
--set-interpreter
|
||||
"${DEFAULT_LOADER_PATH}"
|
||||
--remove-rpath
|
||||
"$<TARGET_FILE:${target}>"
|
||||
)
|
||||
set(comment "Patching ${target}: set default loader, remove rpath")
|
||||
|
||||
# POST_BUILD is the cheap way to do this: it runs only when the binary is
|
||||
# relinked. It is also only available in the directory that defined the
|
||||
# target, so for a target from elsewhere (e.g. a FetchContent subproject)
|
||||
# fall back to a custom target that runs after the binary is linked. That
|
||||
# one runs on every build, which is harmless because patchelf is idempotent.
|
||||
get_target_property(target_source_dir ${target} SOURCE_DIR)
|
||||
if("${target_source_dir}" STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
add_custom_command(
|
||||
TARGET ${target}
|
||||
POST_BUILD
|
||||
COMMAND ${patch_command}
|
||||
COMMENT "${comment}"
|
||||
VERBATIM
|
||||
)
|
||||
else()
|
||||
add_custom_target(
|
||||
${target}-patch-nix
|
||||
ALL
|
||||
COMMAND ${patch_command}
|
||||
COMMENT "${comment}"
|
||||
VERBATIM
|
||||
)
|
||||
add_dependencies(${target}-patch-nix ${target})
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
@@ -25,6 +25,19 @@ if(NOT (RPMBUILD_EXECUTABLE OR DPKG_BUILDPACKAGE_EXECUTABLE))
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(NOT TARGET xrpld)
|
||||
message(STATUS "xrpld=ON is required; 'package' target not available")
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(NOT TARGET validator-keys)
|
||||
message(
|
||||
STATUS
|
||||
"validator_keys=ON is required; 'package' target not available"
|
||||
)
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(package_env
|
||||
SRC_DIR=${CMAKE_SOURCE_DIR}
|
||||
BUILD_DIR=${CMAKE_BINARY_DIR}
|
||||
@@ -37,7 +50,7 @@ add_custom_target(
|
||||
${CMAKE_COMMAND} -E env ${package_env}
|
||||
${CMAKE_SOURCE_DIR}/package/build_pkg.sh
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
|
||||
DEPENDS xrpld
|
||||
DEPENDS xrpld validator-keys
|
||||
COMMENT "Building Linux package (deb/rpm inferred from host tooling)"
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
@@ -2,21 +2,22 @@
|
||||
Protocol Autogen - Code generation for protocol wrapper classes
|
||||
#]===================================================================]
|
||||
|
||||
# The repository root, derived from the location of this file rather than from
|
||||
# the including project, so that the targets below can also be offered on their
|
||||
# own by cmake/codegen/CMakeLists.txt.
|
||||
get_filename_component(XRPL_ROOT "${CMAKE_CURRENT_LIST_DIR}/.." ABSOLUTE)
|
||||
|
||||
set(CODEGEN_VENV_DIR
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/.venv"
|
||||
"${XRPL_ROOT}/.venv"
|
||||
CACHE PATH
|
||||
"Path to a Python virtual environment for code generation. A venv will be created here by setup_code_gen and used to run generation scripts."
|
||||
)
|
||||
|
||||
# Directory paths
|
||||
set(MACRO_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include/xrpl/protocol/detail")
|
||||
set(AUTOGEN_HEADER_DIR
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/xrpl/protocol_autogen"
|
||||
)
|
||||
set(AUTOGEN_TEST_DIR
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/tests/libxrpl/protocol_autogen"
|
||||
)
|
||||
set(SCRIPTS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/cmake/scripts/codegen")
|
||||
set(MACRO_DIR "${XRPL_ROOT}/include/xrpl/protocol/detail")
|
||||
set(AUTOGEN_HEADER_DIR "${XRPL_ROOT}/include/xrpl/protocol_autogen")
|
||||
set(AUTOGEN_TEST_DIR "${XRPL_ROOT}/src/tests/libxrpl/protocol_autogen")
|
||||
set(SCRIPTS_DIR "${XRPL_ROOT}/cmake/scripts/codegen")
|
||||
|
||||
# Input macro files
|
||||
set(TRANSACTIONS_MACRO "${MACRO_DIR}/transactions.macro")
|
||||
@@ -114,14 +115,14 @@ if(CODEGEN_VENV_DIR)
|
||||
setup_code_gen
|
||||
COMMAND ${Python3_EXECUTABLE} -m venv "${CODEGEN_VENV_DIR}"
|
||||
COMMAND ${CODEGEN_PYTHON} -m pip install -r "${REQUIREMENTS_FILE}"
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
WORKING_DIRECTORY "${XRPL_ROOT}"
|
||||
COMMENT "Creating venv and installing code generation dependencies..."
|
||||
)
|
||||
else()
|
||||
add_custom_target(
|
||||
setup_code_gen
|
||||
COMMAND ${Python3_EXECUTABLE} -m pip install -r "${REQUIREMENTS_FILE}"
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
WORKING_DIRECTORY "${XRPL_ROOT}"
|
||||
COMMENT "Installing code generation dependencies..."
|
||||
)
|
||||
endif()
|
||||
@@ -139,8 +140,8 @@ add_custom_target(
|
||||
-DSFIELDS_MACRO=${SFIELDS_MACRO}
|
||||
-DAUTOGEN_HEADER_DIR=${AUTOGEN_HEADER_DIR}
|
||||
-DAUTOGEN_TEST_DIR=${AUTOGEN_TEST_DIR} -P
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/XrplProtocolAutogenRun.cmake"
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/XrplProtocolAutogenRun.cmake"
|
||||
WORKING_DIRECTORY "${XRPL_ROOT}"
|
||||
COMMENT "Running protocol code generation..."
|
||||
SOURCES ${ALL_INPUT_FILES}
|
||||
)
|
||||
|
||||
@@ -5,22 +5,39 @@ option(
|
||||
)
|
||||
|
||||
if(validator_keys)
|
||||
git_branch(current_branch)
|
||||
# default to tracking VK master branch unless we are on release
|
||||
if(NOT (current_branch STREQUAL "release"))
|
||||
set(current_branch "master")
|
||||
endif()
|
||||
message(STATUS "Tracking ValidatorKeys branch: ${current_branch}")
|
||||
# Own the install destination below rather than relying on another module
|
||||
# having pulled this in first.
|
||||
include(GNUInstallDirs)
|
||||
|
||||
# Pinned to an exact commit, not a branch: the tool ships inside our
|
||||
# packages, so the same xrpld version must always package the same
|
||||
# validator-keys. Bump this deliberately.
|
||||
set(validator_keys_commit "4c0fb75eec9601c711645998c904507e87e910ae")
|
||||
message(STATUS "Using ValidatorKeys commit: ${validator_keys_commit}")
|
||||
|
||||
FetchContent_Declare(
|
||||
validator_keys
|
||||
GIT_REPOSITORY https://github.com/ripple/validator-keys-tool.git
|
||||
GIT_TAG "${current_branch}"
|
||||
GIT_TAG "${validator_keys_commit}"
|
||||
)
|
||||
FetchContent_MakeAvailable(validator_keys)
|
||||
# The tool's own CMakeLists excludes the target from 'all' when it is built
|
||||
# as a subproject. Undo that, so validator_keys=ON really does build it.
|
||||
set_target_properties(
|
||||
validator-keys
|
||||
PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}"
|
||||
PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}"
|
||||
EXCLUDE_FROM_ALL OFF
|
||||
EXCLUDE_FROM_DEFAULT_BUILD OFF
|
||||
)
|
||||
# We ship this binary, so like xrpld it must not keep the Nix store's ELF
|
||||
# loader, or it cannot run on the target distro at all.
|
||||
patch_nix_binary(validator-keys)
|
||||
|
||||
configure_file(
|
||||
"${validator_keys_SOURCE_DIR}/LICENSE"
|
||||
"${CMAKE_BINARY_DIR}/validator-keys-LICENSE"
|
||||
COPYONLY
|
||||
)
|
||||
install(TARGETS validator-keys RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
endif()
|
||||
|
||||
21
cmake/codegen/CMakeLists.txt
Normal file
21
cmake/codegen/CMakeLists.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
#[===================================================================[
|
||||
Protocol Autogen - Standalone project
|
||||
|
||||
Exposes the 'setup_code_gen' and 'code_gen' targets on their own, without
|
||||
configuring the rest of xrpl. Code generation is pure Python, so this needs
|
||||
neither the dependencies nor a compiler, which makes it usable in CI and by
|
||||
contributors who only want to regenerate the protocol wrapper classes:
|
||||
|
||||
cmake -S cmake/codegen -B build/codegen
|
||||
cmake --build build/codegen --target setup_code_gen
|
||||
cmake --build build/codegen --target code_gen
|
||||
|
||||
The targets are identical to the ones offered by the top-level build, since
|
||||
both come from cmake/XrplProtocolAutogen.cmake.
|
||||
#]===================================================================]
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
project(xrpl_codegen LANGUAGES NONE)
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/../XrplProtocolAutogen.cmake")
|
||||
@@ -12,7 +12,7 @@
|
||||
"protobuf/6.33.5#ff253ead763bd8d9904a52979cd21e81%1782392410.233933",
|
||||
"openssl/3.6.3#f806de8933e3bf6f01016c6a888cee2e%1783945160.863288",
|
||||
"nudb/2.0.9#11149c73f8f2baff9a0198fe25971fc7%1782392402.297166",
|
||||
"mpt-crypto/0.4.0-rc4#ffdba12f2332357f0d8b0ae944cfff52%1784138702.932355",
|
||||
"mpt-crypto/1.0.2#b313cef0c1a493eb970ad185b2e9bab7%1784285108.866483",
|
||||
"lz4/1.10.0#982d9b673900f665a1da109e09c17cab%1782392402.164188",
|
||||
"libiconv/1.17#9923bc6dc6f106646d6967e0039a5ada%1782392792.775744",
|
||||
"libbacktrace/cci.20210118#a7691bfccd8caaf66309df196790a5a1%1782392402.420732",
|
||||
@@ -20,6 +20,7 @@
|
||||
"jemalloc/5.3.1#1fc58d55316041f10fbc1e8a2eae632a%1776700028.228",
|
||||
"gtest/1.17.0#5224b3b3ff3b4ce1133cbdd27d53ee7d%1782392402.791979",
|
||||
"grpc/1.81.1#f729f6d75992d20f9c72828e9142d62f%1783945160.094135",
|
||||
"fast_float/8.2.10#f6f28d6bb22112078e7dbda611caf681%1782494504.298",
|
||||
"ed25519/2015.03#ae761bdc52730a843f0809bdf6c1b1f6%1782307148.15562",
|
||||
"date/3.0.4#862e11e80030356b53c2c38599ceb32b%1782392402.538492",
|
||||
"c-ares/1.34.6#545240bb1c40e2cacd4362d6b8967650%1782392402.681654",
|
||||
@@ -34,7 +35,7 @@
|
||||
"protobuf/6.33.5#ff253ead763bd8d9904a52979cd21e81%1782392410.233933",
|
||||
"nasm/2.16.01#31e26f2ee3c4346ecd347911bd126904%1782395690.33162",
|
||||
"msys2/cci.latest#d22fe7b2808f5fd34d0a7923ace9c54f%1770657326.649",
|
||||
"m4/1.4.19#34c4bbc3eeebe98ca6edf2f52d602e7d%1777282960.259",
|
||||
"m4/1.4.19#1727f439cf74e83826ec96d0b4904eee%1784541921.659",
|
||||
"cmake/4.3.3#840cf00ea09777e05c2050a50a82c722%1782392418.696091",
|
||||
"b2/5.4.2#ffd6084a119587e70f11cd45d1a386e2%1782392402.624226",
|
||||
"automake/1.16.5#b91b7c384c3deaa9d535be02da14d04f%1755524470.56",
|
||||
|
||||
@@ -5,6 +5,13 @@
|
||||
{% if os == "Linux" %}
|
||||
{% set compiler_version = detect_api.default_compiler_version(compiler, version) %}
|
||||
{% endif %}
|
||||
{% if os == "Macos" %}
|
||||
{# Minimum macOS the dependencies target. #}
|
||||
{# Without this, Conan builds each dependency against the (possibly newer) host SDK, so the #}
|
||||
{# dependency objects target a newer macOS than the binary and the linker warns. #}
|
||||
{# Keep at or below CMAKE_OSX_DEPLOYMENT_TARGET in CMakeLists.txt. #}
|
||||
{% set min_macos_version = "15.0" %}
|
||||
{% endif %}
|
||||
|
||||
[settings]
|
||||
os={{ os }}
|
||||
@@ -18,6 +25,9 @@ compiler.runtime=static
|
||||
{% else %}
|
||||
compiler.libcxx={{ detect_api.detect_libcxx(compiler, version, compiler_exe) }}
|
||||
{% endif %}
|
||||
{% if os == "Macos" %}
|
||||
os.version={{ min_macos_version }}
|
||||
{% endif %}
|
||||
|
||||
[conf]
|
||||
{# The Boost recipe builds with b2, which doesn't use Conan's toolchain files. #}
|
||||
@@ -41,3 +51,13 @@ tools.build:compiler_executables={'c':'{{ cc_exe }}','cpp':'{{ cxx_exe }}'}
|
||||
{# More info: https://docs.conan.io/2/reference/extensions/binary_compatibility.html #}
|
||||
user.package:cppstd_version=23
|
||||
tools.info.package_id:confs+=["user.package:cppstd_version"]
|
||||
|
||||
{% if os == "Macos" %}
|
||||
[buildenv]
|
||||
{# os.version adds -mmacosx-version-min to compiler command lines, #}
|
||||
{# but Boost.Context's b2 assembly (.S) rule ignores it, #}
|
||||
{# so those objects keep the host SDK version and still warn at link time. #}
|
||||
{# clang's assembler honors this env var regardless, pinning them. #}
|
||||
{# Scoped to boost/* since it is the only gap. #}
|
||||
boost/*:MACOSX_DEPLOYMENT_TARGET={{ min_macos_version }}
|
||||
{% endif %}
|
||||
|
||||
@@ -29,6 +29,7 @@ class Xrpl(ConanFile):
|
||||
|
||||
requires = [
|
||||
"ed25519/2015.03",
|
||||
"fast_float/8.2.10",
|
||||
"grpc/1.81.1",
|
||||
"libarchive/3.8.7",
|
||||
"nudb/2.0.9",
|
||||
@@ -138,7 +139,7 @@ class Xrpl(ConanFile):
|
||||
if self.options.jemalloc:
|
||||
self.requires("jemalloc/5.3.1")
|
||||
self.requires("lz4/1.10.0", force=True)
|
||||
self.requires("mpt-crypto/0.4.0-rc4", transitive_headers=True)
|
||||
self.requires("mpt-crypto/1.0.2", transitive_headers=True)
|
||||
self.requires("protobuf/6.33.5", force=True)
|
||||
if self.options.rocksdb:
|
||||
self.requires("rocksdb/10.5.1")
|
||||
@@ -211,6 +212,7 @@ class Xrpl(ConanFile):
|
||||
"boost::thread",
|
||||
"date::date",
|
||||
"ed25519::ed25519",
|
||||
"fast_float::fast_float",
|
||||
"grpc::grpc++",
|
||||
"libarchive::libarchive",
|
||||
"lz4::lz4",
|
||||
|
||||
72
docs/build/nix_troubleshooting.md
vendored
72
docs/build/nix_troubleshooting.md
vendored
@@ -3,6 +3,78 @@
|
||||
Common issues encountered when using the [Nix development shell](./nix.md), and
|
||||
how to resolve them.
|
||||
|
||||
## `command not found: nix` after a macOS update
|
||||
|
||||
If a shell suddenly can't find `nix` at all:
|
||||
|
||||
```
|
||||
$ nix develop
|
||||
zsh: command not found: nix
|
||||
```
|
||||
|
||||
then Nix is almost certainly still installed — only the shell hook that puts it
|
||||
on your `PATH` is gone. Confirm that first:
|
||||
|
||||
```bash
|
||||
ls -l /nix/var/nix/profiles/default/bin/nix
|
||||
```
|
||||
|
||||
If that exists, the installation is fine and this is purely a `PATH` problem.
|
||||
|
||||
### Why it happens
|
||||
|
||||
The installer does not touch your dotfiles. Instead it sources a setup script
|
||||
from the Nix store by editing **system-wide** rc files:
|
||||
|
||||
| Shell | File the installer edits |
|
||||
| ----- | ------------------------------------- |
|
||||
| bash | `/etc/bashrc`, `/etc/bash.bashrc` |
|
||||
| zsh | `/etc/zshrc` |
|
||||
| fish | `$__fish_sysconf_dir/conf.d/nix.fish` |
|
||||
|
||||
macOS manages `/etc/zshrc`, so an OS update can replace it with the vendor copy
|
||||
and silently drop the Nix block. `/etc/bashrc` and the fish file usually survive,
|
||||
which is why the breakage often shows up in zsh only. You can verify this by
|
||||
diffing against the backup the installer left behind:
|
||||
|
||||
```bash
|
||||
diff /etc/zshrc /etc/zshrc.backup-before-nix
|
||||
```
|
||||
|
||||
If they are identical, the Nix snippet was wiped. This is upstream issue
|
||||
[NixOS/nix#3616](https://github.com/NixOS/nix/issues/3616).
|
||||
|
||||
### Fix
|
||||
|
||||
To unblock the current shell:
|
||||
|
||||
```bash
|
||||
. /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh
|
||||
```
|
||||
|
||||
For a permanent fix, add the snippet to your **user** rc file rather than
|
||||
restoring `/etc/zshrc` — user dotfiles are not clobbered by OS updates:
|
||||
|
||||
```bash
|
||||
cat >>~/.zshrc <<'EOF'
|
||||
|
||||
# Nix
|
||||
if [ -e '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh' ]; then
|
||||
. '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh'
|
||||
fi
|
||||
# End Nix
|
||||
EOF
|
||||
```
|
||||
|
||||
The scripts guard against double-sourcing via `__ETC_PROFILE_NIX_SOURCED`, so
|
||||
this is safe even if a system-wide hook is later restored.
|
||||
|
||||
> [!NOTE]
|
||||
> `/etc/zshrc` and `~/.zshrc` are only read by **interactive** zsh. If the
|
||||
> snippet is present but `zsh -c '…'`, a script, or an IDE terminal still can't
|
||||
> find `nix`, that shell is non-interactive — put the snippet in `~/.zshenv`
|
||||
> instead.
|
||||
|
||||
## Git worktrees
|
||||
|
||||
If `nix develop` fails with an error like:
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace xrpl {
|
||||
class Resolver
|
||||
{
|
||||
public:
|
||||
using HandlerType = std::function<void(std::string, std::vector<beast::IP::Endpoint>)>;
|
||||
using HandlerType = std::function<void(std::string, std::vector<beast::ip::Endpoint>)>;
|
||||
|
||||
virtual ~Resolver() = 0;
|
||||
|
||||
|
||||
@@ -41,6 +41,35 @@
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
namespace base64 {
|
||||
|
||||
/**
|
||||
* Returns the maximum number of characters needed to base64-encode @p nBytes bytes.
|
||||
*
|
||||
* @param nBytes Number of input bytes.
|
||||
* @return Size of the encoded string, including padding.
|
||||
*/
|
||||
constexpr std::size_t
|
||||
encodedSize(std::size_t const nBytes)
|
||||
{
|
||||
return 4 * ((nBytes + 2) / 3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum number of bytes a base64 string of @p numChars characters
|
||||
* decodes to.
|
||||
*
|
||||
* @param numChars Number of base64 characters.
|
||||
* @return Upper bound on the number of decoded bytes.
|
||||
*/
|
||||
constexpr std::size_t
|
||||
decodedSize(std::size_t const numChars)
|
||||
{
|
||||
return ((numChars / 4) * 3) + 2;
|
||||
}
|
||||
|
||||
} // namespace base64
|
||||
|
||||
std::string
|
||||
base64Encode(std::uint8_t const* data, std::size_t len);
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ public:
|
||||
* @param journal Destination for logging output.
|
||||
*/
|
||||
static std::shared_ptr<StatsDCollector>
|
||||
make(IP::Endpoint const& address, std::string const& prefix, Journal journal);
|
||||
make(ip::Endpoint const& address, std::string const& prefix, Journal journal);
|
||||
};
|
||||
|
||||
} // namespace beast::insight
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace beast {
|
||||
namespace IP {
|
||||
namespace ip {
|
||||
|
||||
using Address = boost::asio::ip::address;
|
||||
|
||||
@@ -73,13 +73,13 @@ isPublic(Address const& addr)
|
||||
return (addr.is_v4()) ? isPublic(addr.to_v4()) : isPublic(addr.to_v6());
|
||||
}
|
||||
|
||||
} // namespace IP
|
||||
} // namespace ip
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <class Hasher>
|
||||
void
|
||||
hash_append(Hasher& h, beast::IP::Address const& addr) noexcept
|
||||
hash_append(Hasher& h, beast::ip::Address const& addr) noexcept
|
||||
{
|
||||
using beast::hash_append;
|
||||
if (addr.is_v4())
|
||||
@@ -101,12 +101,12 @@ hash_append(Hasher& h, beast::IP::Address const& addr) noexcept
|
||||
|
||||
namespace boost {
|
||||
template <>
|
||||
struct hash<::beast::IP::Address>
|
||||
struct hash<::beast::ip::Address>
|
||||
{
|
||||
explicit hash() = default;
|
||||
|
||||
std::size_t
|
||||
operator()(::beast::IP::Address const& addr) const
|
||||
operator()(::beast::ip::Address const& addr) const
|
||||
{
|
||||
return ::beast::Uhash<>{}(addr);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
|
||||
namespace beast::IP {
|
||||
namespace beast::ip {
|
||||
|
||||
/**
|
||||
* Convert to Endpoint.
|
||||
@@ -32,7 +32,7 @@ toAsioAddress(Endpoint const& endpoint);
|
||||
boost::asio::ip::tcp::endpoint
|
||||
toAsioEndpoint(Endpoint const& endpoint);
|
||||
|
||||
} // namespace beast::IP
|
||||
} // namespace beast::ip
|
||||
|
||||
namespace beast {
|
||||
|
||||
@@ -41,25 +41,25 @@ struct IPAddressConversion
|
||||
{
|
||||
explicit IPAddressConversion() = default;
|
||||
|
||||
static IP::Endpoint
|
||||
static ip::Endpoint
|
||||
fromAsio(boost::asio::ip::address const& address)
|
||||
{
|
||||
return IP::fromAsio(address);
|
||||
return ip::fromAsio(address);
|
||||
}
|
||||
static IP::Endpoint
|
||||
static ip::Endpoint
|
||||
fromAsio(boost::asio::ip::tcp::endpoint const& endpoint)
|
||||
{
|
||||
return IP::fromAsio(endpoint);
|
||||
return ip::fromAsio(endpoint);
|
||||
}
|
||||
static boost::asio::ip::address
|
||||
toAsioAddress(IP::Endpoint const& address)
|
||||
toAsioAddress(ip::Endpoint const& address)
|
||||
{
|
||||
return IP::toAsioAddress(address);
|
||||
return ip::toAsioAddress(address);
|
||||
}
|
||||
static boost::asio::ip::tcp::endpoint
|
||||
toAsioEndpoint(IP::Endpoint const& address)
|
||||
toAsioEndpoint(ip::Endpoint const& address)
|
||||
{
|
||||
return IP::toAsioEndpoint(address);
|
||||
return ip::toAsioEndpoint(address);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include <boost/asio/ip/address_v4.hpp>
|
||||
|
||||
namespace beast::IP {
|
||||
namespace beast::ip {
|
||||
|
||||
using AddressV4 = boost::asio::ip::address_v4;
|
||||
|
||||
@@ -25,4 +25,4 @@ isPublic(AddressV4 const& addr);
|
||||
char
|
||||
getClass(AddressV4 const& address);
|
||||
|
||||
} // namespace beast::IP
|
||||
} // namespace beast::ip
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include <boost/asio/ip/address_v6.hpp>
|
||||
|
||||
namespace beast::IP {
|
||||
namespace beast::ip {
|
||||
|
||||
using AddressV6 = boost::asio::ip::address_v6;
|
||||
|
||||
@@ -18,4 +18,4 @@ isPrivate(AddressV6 const& addr);
|
||||
bool
|
||||
isPublic(AddressV6 const& addr);
|
||||
|
||||
} // namespace beast::IP
|
||||
} // namespace beast::ip
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
namespace beast::IP {
|
||||
namespace beast::ip {
|
||||
|
||||
using Port = std::uint16_t;
|
||||
|
||||
@@ -223,7 +223,7 @@ operator<<(OutputStream& os, Endpoint const& endpoint)
|
||||
std::istream&
|
||||
operator>>(std::istream& is, Endpoint& endpoint);
|
||||
|
||||
} // namespace beast::IP
|
||||
} // namespace beast::ip
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -232,12 +232,12 @@ namespace std {
|
||||
* std::hash support.
|
||||
*/
|
||||
template <>
|
||||
struct hash<::beast::IP::Endpoint>
|
||||
struct hash<::beast::ip::Endpoint>
|
||||
{
|
||||
hash() = default;
|
||||
|
||||
std::size_t
|
||||
operator()(::beast::IP::Endpoint const& endpoint) const
|
||||
operator()(::beast::ip::Endpoint const& endpoint) const
|
||||
{
|
||||
return ::beast::Uhash<>{}(endpoint);
|
||||
}
|
||||
@@ -249,12 +249,12 @@ namespace boost {
|
||||
* boost::hash support.
|
||||
*/
|
||||
template <>
|
||||
struct hash<::beast::IP::Endpoint>
|
||||
struct hash<::beast::ip::Endpoint>
|
||||
{
|
||||
hash() = default;
|
||||
|
||||
std::size_t
|
||||
operator()(::beast::IP::Endpoint const& endpoint) const
|
||||
operator()(::beast::ip::Endpoint const& endpoint) const
|
||||
{
|
||||
return ::beast::Uhash<>{}(endpoint);
|
||||
}
|
||||
|
||||
@@ -295,6 +295,20 @@ public:
|
||||
return runner_->arg();
|
||||
}
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Lets a suite compose other suites (e.g. an aggregator that reruns a
|
||||
* group of related suites under its own name) via `SuiteInfo::run`.
|
||||
*
|
||||
* @return The runner this suite is executing under.
|
||||
*/
|
||||
Runner&
|
||||
runner() const
|
||||
{
|
||||
return *runner_;
|
||||
}
|
||||
|
||||
public:
|
||||
/**
|
||||
* DEPRECATED
|
||||
* @return `true` if the test condition indicates success(a false value)
|
||||
|
||||
@@ -25,6 +25,7 @@ struct Sections
|
||||
static constexpr auto kLedgerHistory = "ledger_history";
|
||||
static constexpr auto kLedgerReplay = "ledger_replay";
|
||||
static constexpr auto kLedgerTxTables = "ledger_tx_tables";
|
||||
static constexpr auto kMaxSubscriptionsPerConnection = "max_subscriptions_per_connection";
|
||||
static constexpr auto kMaxTransactions = "max_transactions";
|
||||
static constexpr auto kNetworkId = "network_id";
|
||||
static constexpr auto kNetworkQuorum = "network_quorum";
|
||||
@@ -118,7 +119,9 @@ struct Keys
|
||||
static constexpr auto kLogInterval = "log_interval";
|
||||
static constexpr auto kMaxDivergedTime = "max_diverged_time";
|
||||
static constexpr auto kMaxLedgerCountsToStore = "max_ledger_counts_to_store";
|
||||
static constexpr auto kMaxTrustedCount = "max_trusted_count";
|
||||
static constexpr auto kMaxUnknownTime = "max_unknown_time";
|
||||
static constexpr auto kMaxUntrustedCount = "max_untrusted_count";
|
||||
static constexpr auto kMaximumTxnInLedger = "maximum_txn_in_ledger";
|
||||
static constexpr auto kMaximumTxnPerAccount = "maximum_txn_per_account";
|
||||
static constexpr auto kMemoryLevel = "memory_level";
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <ranges>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
@@ -1579,7 +1580,13 @@ Consensus<Adaptor>::updateOurPositions(std::unique_ptr<std::stringstream> const&
|
||||
JLOG(j_.info()) << ss.str();
|
||||
CLOG(clog) << ss.str();
|
||||
|
||||
for (auto const& [t, v] : closeTimeVotes)
|
||||
// Walk the votes highest-time first so that, among close times tied
|
||||
// for the most votes, the earliest wins. The smaller value is the
|
||||
// safer choice: without close-time consensus this round, the winner
|
||||
// only updates our position for the next proposal, and a too-early
|
||||
// time is bounded below by the prior ledger's close time. Only the
|
||||
// tie-break changes; the bin with the most votes still wins.
|
||||
for (auto const& [t, v] : std::views::reverse(closeTimeVotes))
|
||||
{
|
||||
JLOG(j_.debug()) << "CCTime: seq "
|
||||
<< static_cast<std::uint32_t>(previousLedger_.seq()) + 1 << ": "
|
||||
|
||||
@@ -8,7 +8,9 @@
|
||||
|
||||
#include <chrono>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
namespace xrpl {
|
||||
@@ -189,6 +191,75 @@ struct ConsensusCloseTimes
|
||||
NetClock::time_point self;
|
||||
};
|
||||
|
||||
/**
|
||||
* Offset of the network's close time relative to ours, using a weighted median.
|
||||
*
|
||||
* Treats the sample set as `{self x 1}` merged with `{t x w}` for each
|
||||
* `(t, w)` in `times.peers`, in time order, and returns `(median - self)`
|
||||
* in whole seconds. Uses the lower weighted median: the median is the
|
||||
* earliest time at which the running weight reaches half the total, so an
|
||||
* even total whose halfway point falls between two bins resolves to the
|
||||
* earlier bin.
|
||||
*
|
||||
* @param times Our own close time and the weighted close times of peers.
|
||||
* @return Weighted median of all close times minus our own, in whole seconds.
|
||||
*/
|
||||
inline std::chrono::seconds
|
||||
medianCloseOffset(ConsensusCloseTimes const& times)
|
||||
{
|
||||
using namespace std::chrono;
|
||||
using time_point = NetClock::time_point;
|
||||
|
||||
std::int64_t totalWeight = 1;
|
||||
for (auto const& [_, w] : times.peers)
|
||||
totalWeight += w;
|
||||
|
||||
std::int64_t const halfWeight = (totalWeight + 1) / 2;
|
||||
|
||||
std::optional<time_point> median{};
|
||||
std::int64_t tally = 0;
|
||||
bool selfPlaced = false;
|
||||
|
||||
// Accumulate weight in time order; the first bin to reach halfWeight is
|
||||
// the (lower) weighted median. Returns true once that bin is found.
|
||||
auto step = [&](time_point t, std::int64_t w) {
|
||||
XRPL_ASSERT(tally < halfWeight, "xrpl::medianCloseOffset::step : median not yet found");
|
||||
tally += w;
|
||||
if (tally >= halfWeight)
|
||||
{
|
||||
median = t;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
for (auto const& [t, w] : times.peers)
|
||||
{
|
||||
if (!selfPlaced && times.self <= t)
|
||||
{
|
||||
selfPlaced = true;
|
||||
if (step(times.self, 1))
|
||||
break;
|
||||
}
|
||||
if (step(t, w))
|
||||
break;
|
||||
}
|
||||
if (!selfPlaced && !median)
|
||||
step(times.self, 1);
|
||||
|
||||
if (!median)
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
UNREACHABLE("xrpl::medianCloseOffset : median not found");
|
||||
median = times.self;
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
return duration_cast<seconds>(
|
||||
duration<std::int64_t>{median->time_since_epoch().count()} -
|
||||
duration<std::int64_t>{times.self.time_since_epoch().count()});
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether we have or don't have a consensus
|
||||
*/
|
||||
|
||||
@@ -18,9 +18,9 @@ namespace xrpl {
|
||||
namespace node_store {
|
||||
class Database;
|
||||
} // namespace node_store
|
||||
namespace Resource {
|
||||
namespace resource {
|
||||
class Manager;
|
||||
} // namespace Resource
|
||||
} // namespace resource
|
||||
namespace perf {
|
||||
class PerfLog;
|
||||
} // namespace perf
|
||||
@@ -160,7 +160,7 @@ public:
|
||||
virtual PeerReservationTable&
|
||||
getPeerReservations() = 0;
|
||||
|
||||
virtual Resource::Manager&
|
||||
virtual resource::Manager&
|
||||
getResourceManager() = 0;
|
||||
|
||||
// Storage services
|
||||
|
||||
@@ -623,6 +623,7 @@ class ValueConstIterator : public ValueIteratorBase
|
||||
public:
|
||||
using size_t = unsigned int;
|
||||
using difference_type = int;
|
||||
using value_type = Value const;
|
||||
using reference = Value const&;
|
||||
using pointer = Value const*;
|
||||
using SelfType = ValueConstIterator;
|
||||
@@ -687,6 +688,7 @@ class ValueIterator : public ValueIteratorBase
|
||||
public:
|
||||
using size_t = unsigned int;
|
||||
using difference_type = int;
|
||||
using value_type = Value;
|
||||
using reference = Value&;
|
||||
using pointer = Value*;
|
||||
using SelfType = ValueIterator;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <xrpl/basics/Log.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
|
||||
@@ -15,6 +16,7 @@
|
||||
#include <xrpl/protocol/Issue.h>
|
||||
#include <xrpl/protocol/Keylet.h>
|
||||
#include <xrpl/protocol/LedgerFormats.h>
|
||||
#include <xrpl/protocol/MPTAmount.h>
|
||||
#include <xrpl/protocol/MPTIssue.h>
|
||||
#include <xrpl/protocol/Rate.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
@@ -241,10 +243,25 @@ escrowUnlockApplyHelper<MPTIssue>(
|
||||
auto finalAmt = amount;
|
||||
if ((!senderIssuer && !receiverIssuer) && lockedRate != kParityRate)
|
||||
{
|
||||
// compute transfer fee, if any
|
||||
auto const xferFee = amount.value() - divideRound(amount, lockedRate, amount.asset(), true);
|
||||
// compute balance to transfer
|
||||
finalAmt = amount.value() - xferFee;
|
||||
if (ctx.view.rules().enabled(fixCleanup3_4_0))
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
lockedRate >= kParityRate,
|
||||
"xrpl::escrowUnlockApplyHelper<MPTIssue> : lockedRate is at least parity");
|
||||
// MPTs are integral, so round the delivered amount down and
|
||||
// charge any fractional transfer fee to the escrowed amount.
|
||||
auto const delivered =
|
||||
mulRatio(amount.mpt(), kParityRate.value, lockedRate.value, false);
|
||||
finalAmt = STAmount(amount.asset(), delivered.value());
|
||||
}
|
||||
else
|
||||
{
|
||||
// compute transfer fee, if any
|
||||
auto const xferFee =
|
||||
amount.value() - divideRound(amount, lockedRate, amount.asset(), true);
|
||||
// compute balance to transfer
|
||||
finalAmt = amount.value() - xferFee;
|
||||
}
|
||||
}
|
||||
return unlockEscrowMPT(
|
||||
ctx.view,
|
||||
|
||||
@@ -296,7 +296,7 @@ struct AccountingDeltas
|
||||
|
||||
// Whole-life (pre-LendingProtocolV1_1) recognition model: interest is
|
||||
// recognized into AssetsTotal/DebtTotal up front, at origination.
|
||||
namespace Accrual {
|
||||
namespace accrual {
|
||||
|
||||
// LoanSet origination: what's added to Vault.AssetsTotal and LoanBroker.DebtTotal
|
||||
AccountingDeltas
|
||||
@@ -318,11 +318,11 @@ loanVaultExposure(SLE::const_ref loanSle);
|
||||
AccountingDeltas
|
||||
loanPaymentDeltas(LoanPaymentParts const& parts);
|
||||
|
||||
} // namespace Accrual
|
||||
} // namespace accrual
|
||||
|
||||
// Cash-basis (LendingProtocolV1_1) recognition model: AssetsTotal/DebtTotal
|
||||
// are principal-only, interest is recognized only as it's actually paid.
|
||||
namespace CashBasis {
|
||||
namespace cash_basis {
|
||||
|
||||
AccountingDeltas
|
||||
loanOriginationDeltas(Number const& principalRequested);
|
||||
@@ -333,11 +333,11 @@ loanVaultExposure(SLE::const_ref loanSle);
|
||||
AccountingDeltas
|
||||
loanPaymentDeltas(LoanPaymentParts const& parts);
|
||||
|
||||
} // namespace CashBasis
|
||||
} // namespace cash_basis
|
||||
|
||||
// Public dispatchers: pick CashBasis:: if featureLendingProtocolV1_1 is
|
||||
// Public dispatchers: pick cash_basis:: if featureLendingProtocolV1_1 is
|
||||
// enabled AND the Vault's LEVersion (VaultHelpers::getVaultVersion) is
|
||||
// VaultVersion::CashBasis, else Accrual::. These are the only entry points
|
||||
// VaultVersion::CashBasis, else accrual::. These are the only entry points
|
||||
// transactors call.
|
||||
AccountingDeltas
|
||||
loanOriginationDeltas(
|
||||
|
||||
@@ -67,16 +67,16 @@ public:
|
||||
return socket_->next_layer();
|
||||
}
|
||||
|
||||
beast::IP::Endpoint
|
||||
beast::ip::Endpoint
|
||||
localEndpoint()
|
||||
{
|
||||
return beast::IP::fromAsio(lowestLayer().local_endpoint());
|
||||
return beast::ip::fromAsio(lowestLayer().local_endpoint());
|
||||
}
|
||||
|
||||
beast::IP::Endpoint
|
||||
beast::ip::Endpoint
|
||||
remoteEndpoint()
|
||||
{
|
||||
return beast::IP::fromAsio(lowestLayer().remote_endpoint());
|
||||
return beast::ip::fromAsio(lowestLayer().remote_endpoint());
|
||||
}
|
||||
|
||||
lowest_layer_type&
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
namespace xrpl::PeerFinder {
|
||||
namespace xrpl::peer_finder {
|
||||
|
||||
struct PeerLimitConfig
|
||||
{
|
||||
@@ -28,7 +28,7 @@ struct Config
|
||||
* This includes both inbound and outbound, but does not include
|
||||
* fixed peers.
|
||||
*/
|
||||
std::size_t maxPeers{Tuning::kDefaultMaxPeers};
|
||||
std::size_t maxPeers{tuning::kDefaultMaxPeers};
|
||||
|
||||
/**
|
||||
* The number of automatic outbound connections to maintain.
|
||||
@@ -100,7 +100,7 @@ struct Config
|
||||
onWrite(beast::PropertyStream::Map& map) const;
|
||||
|
||||
/**
|
||||
* Make PeerFinder::Config from peer limit and server mode parameters.
|
||||
* Make peer_finder::Config from peer limit and server mode parameters.
|
||||
*/
|
||||
static Config
|
||||
makeConfig(
|
||||
@@ -160,4 +160,4 @@ to_string(Result result) noexcept
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
} // namespace xrpl::PeerFinder
|
||||
} // namespace xrpl::peer_finder
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace xrpl::PeerFinder {
|
||||
namespace xrpl::peer_finder {
|
||||
|
||||
/**
|
||||
* Maintains a set of IP addresses used for getting into the network.
|
||||
@@ -68,17 +68,17 @@ public:
|
||||
* file, along with the set of corresponding IP addresses.
|
||||
*/
|
||||
virtual void
|
||||
addFixedPeer(std::string_view name, std::vector<beast::IP::Endpoint> const& addresses) = 0;
|
||||
addFixedPeer(std::string_view name, std::vector<beast::ip::Endpoint> const& addresses) = 0;
|
||||
|
||||
/**
|
||||
* Add a set of strings as fallback IP::Endpoint sources.
|
||||
* Add a set of strings as fallback ip::Endpoint sources.
|
||||
* @param name A label used for diagnostics.
|
||||
*/
|
||||
virtual void
|
||||
addFallbackStrings(std::string const& name, std::vector<std::string> const& strings) = 0;
|
||||
|
||||
/**
|
||||
* Add a URL as a fallback location to obtain IP::Endpoint sources.
|
||||
* Add a URL as a fallback location to obtain ip::Endpoint sources.
|
||||
* @param name A label used for diagnostics.
|
||||
*/
|
||||
/* VFALCO NOTE Unimplemented
|
||||
@@ -95,8 +95,8 @@ public:
|
||||
*/
|
||||
virtual std::pair<std::shared_ptr<Slot>, Result>
|
||||
newInboundSlot(
|
||||
beast::IP::Endpoint const& localEndpoint,
|
||||
beast::IP::Endpoint const& remoteEndpoint) = 0;
|
||||
beast::ip::Endpoint const& localEndpoint,
|
||||
beast::ip::Endpoint const& remoteEndpoint) = 0;
|
||||
|
||||
/**
|
||||
* Create a new outbound slot with the specified remote endpoint.
|
||||
@@ -104,7 +104,7 @@ public:
|
||||
* Usually this is because of a duplicate connection.
|
||||
*/
|
||||
virtual std::pair<std::shared_ptr<Slot>, Result>
|
||||
newOutboundSlot(beast::IP::Endpoint const& remoteEndpoint) = 0;
|
||||
newOutboundSlot(beast::ip::Endpoint const& remoteEndpoint) = 0;
|
||||
|
||||
/**
|
||||
* Called when mtENDPOINTS is received.
|
||||
@@ -145,7 +145,7 @@ public:
|
||||
* @return `true` if the connection should be kept
|
||||
*/
|
||||
virtual bool
|
||||
onConnected(std::shared_ptr<Slot> const& slot, beast::IP::Endpoint const& localEndpoint) = 0;
|
||||
onConnected(std::shared_ptr<Slot> const& slot, beast::ip::Endpoint const& localEndpoint) = 0;
|
||||
|
||||
/**
|
||||
* Request an active slot type.
|
||||
@@ -162,7 +162,7 @@ public:
|
||||
/**
|
||||
* Return a set of addresses we should connect to.
|
||||
*/
|
||||
virtual std::vector<beast::IP::Endpoint>
|
||||
virtual std::vector<beast::ip::Endpoint>
|
||||
autoconnect() = 0;
|
||||
|
||||
virtual std::vector<std::pair<std::shared_ptr<Slot>, std::vector<Endpoint>>>
|
||||
@@ -176,4 +176,4 @@ public:
|
||||
oncePerSecond() = 0;
|
||||
};
|
||||
|
||||
} // namespace xrpl::PeerFinder
|
||||
} // namespace xrpl::peer_finder
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
namespace xrpl::PeerFinder {
|
||||
namespace xrpl::peer_finder {
|
||||
|
||||
/**
|
||||
* Properties and state associated with a peer to peer overlay connection.
|
||||
@@ -52,13 +52,13 @@ public:
|
||||
/**
|
||||
* The remote endpoint of socket.
|
||||
*/
|
||||
[[nodiscard]] virtual beast::IP::Endpoint const&
|
||||
[[nodiscard]] virtual beast::ip::Endpoint const&
|
||||
remoteEndpoint() const = 0;
|
||||
|
||||
/**
|
||||
* The local endpoint of the socket, when known.
|
||||
*/
|
||||
[[nodiscard]] virtual std::optional<beast::IP::Endpoint> const&
|
||||
[[nodiscard]] virtual std::optional<beast::ip::Endpoint> const&
|
||||
localEndpoint() const = 0;
|
||||
|
||||
[[nodiscard]] virtual std::optional<std::uint16_t>
|
||||
@@ -72,4 +72,4 @@ public:
|
||||
publicKey() const = 0;
|
||||
};
|
||||
|
||||
} // namespace xrpl::PeerFinder
|
||||
} // namespace xrpl::peer_finder
|
||||
|
||||
@@ -8,14 +8,14 @@
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace xrpl::PeerFinder {
|
||||
namespace xrpl::peer_finder {
|
||||
|
||||
using clock_type = beast::AbstractClock<std::chrono::steady_clock>;
|
||||
|
||||
/**
|
||||
* Represents a set of addresses.
|
||||
*/
|
||||
using IPAddresses = std::vector<beast::IP::Endpoint>;
|
||||
using IPAddresses = std::vector<beast::ip::Endpoint>;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -26,10 +26,10 @@ struct Endpoint
|
||||
{
|
||||
Endpoint() = default;
|
||||
|
||||
Endpoint(beast::IP::Endpoint ep, std::uint32_t hops);
|
||||
Endpoint(beast::ip::Endpoint ep, std::uint32_t hops);
|
||||
|
||||
std::uint32_t hops = 0;
|
||||
beast::IP::Endpoint address;
|
||||
beast::ip::Endpoint address;
|
||||
};
|
||||
|
||||
inline bool
|
||||
@@ -43,4 +43,4 @@ operator<(Endpoint const& lhs, Endpoint const& rhs)
|
||||
*/
|
||||
using Endpoints = std::vector<Endpoint>;
|
||||
|
||||
} // namespace xrpl::PeerFinder
|
||||
} // namespace xrpl::peer_finder
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace xrpl::PeerFinder {
|
||||
namespace xrpl::peer_finder {
|
||||
|
||||
/**
|
||||
* Stores IP addresses useful for gaining initial connections.
|
||||
@@ -65,7 +65,7 @@ private:
|
||||
};
|
||||
|
||||
using left_t = boost::bimaps::
|
||||
unordered_set_of<beast::IP::Endpoint, boost::hash<beast::IP::Endpoint>, std::equal_to<>>;
|
||||
unordered_set_of<beast::ip::Endpoint, boost::hash<beast::ip::Endpoint>, std::equal_to<>>;
|
||||
using right_t = boost::bimaps::multiset_of<Entry, std::less<>>;
|
||||
using map_type = boost::bimap<left_t, right_t>;
|
||||
using value_type = map_type::value_type;
|
||||
@@ -73,11 +73,11 @@ private:
|
||||
struct Transform
|
||||
{
|
||||
using first_argument_type = map_type::right_map::const_iterator::value_type const&;
|
||||
using result_type = beast::IP::Endpoint const&;
|
||||
using result_type = beast::ip::Endpoint const&;
|
||||
|
||||
explicit Transform() = default;
|
||||
|
||||
beast::IP::Endpoint const&
|
||||
beast::ip::Endpoint const&
|
||||
operator()(map_type::right_map::const_iterator::value_type const& v) const
|
||||
{
|
||||
return v.get_left();
|
||||
@@ -121,7 +121,7 @@ public:
|
||||
size() const;
|
||||
|
||||
/**
|
||||
* IP::Endpoint iterators that traverse in decreasing valence.
|
||||
* ip::Endpoint iterators that traverse in decreasing valence.
|
||||
*/
|
||||
/** @{ */
|
||||
[[nodiscard]] const_iterator
|
||||
@@ -146,25 +146,25 @@ public:
|
||||
* Add a newly-learned address to the cache.
|
||||
*/
|
||||
bool
|
||||
insert(beast::IP::Endpoint const& endpoint);
|
||||
insert(beast::ip::Endpoint const& endpoint);
|
||||
|
||||
/**
|
||||
* Add a staticallyconfigured address to the cache.
|
||||
*/
|
||||
bool
|
||||
insertStatic(beast::IP::Endpoint const& endpoint);
|
||||
insertStatic(beast::ip::Endpoint const& endpoint);
|
||||
|
||||
/**
|
||||
* Called when an outbound connection handshake completes.
|
||||
*/
|
||||
void
|
||||
onSuccess(beast::IP::Endpoint const& endpoint);
|
||||
onSuccess(beast::ip::Endpoint const& endpoint);
|
||||
|
||||
/**
|
||||
* Called when an outbound connection attempt fails to handshake.
|
||||
*/
|
||||
void
|
||||
onFailure(beast::IP::Endpoint const& endpoint);
|
||||
onFailure(beast::ip::Endpoint const& endpoint);
|
||||
|
||||
/**
|
||||
* Stores the cache in the persistent database on a timer.
|
||||
@@ -189,4 +189,4 @@ private:
|
||||
flagForUpdate();
|
||||
};
|
||||
|
||||
} // namespace xrpl::PeerFinder
|
||||
} // namespace xrpl::peer_finder
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
namespace xrpl::PeerFinder {
|
||||
namespace xrpl::peer_finder {
|
||||
|
||||
/**
|
||||
* Tests remote listening sockets to make sure they are connectable.
|
||||
@@ -104,7 +104,7 @@ public:
|
||||
*/
|
||||
template <class Handler>
|
||||
void
|
||||
asyncConnect(beast::IP::Endpoint const& endpoint, Handler&& handler);
|
||||
asyncConnect(beast::ip::Endpoint const& endpoint, Handler&& handler);
|
||||
|
||||
private:
|
||||
void
|
||||
@@ -179,7 +179,7 @@ Checker<Protocol>::wait()
|
||||
template <class Protocol>
|
||||
template <class Handler>
|
||||
void
|
||||
Checker<Protocol>::asyncConnect(beast::IP::Endpoint const& endpoint, Handler&& handler)
|
||||
Checker<Protocol>::asyncConnect(beast::ip::Endpoint const& endpoint, Handler&& handler)
|
||||
{
|
||||
auto const op =
|
||||
std::make_shared<AsyncOp<Handler>>(*this, ioContext_, std::forward<Handler>(handler));
|
||||
@@ -202,4 +202,4 @@ Checker<Protocol>::remove(BasicAsyncOp& op)
|
||||
cond_.notify_all();
|
||||
}
|
||||
|
||||
} // namespace xrpl::PeerFinder
|
||||
} // namespace xrpl::peer_finder
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
namespace xrpl::PeerFinder {
|
||||
namespace xrpl::peer_finder {
|
||||
|
||||
/**
|
||||
* Direction of a slot count adjustment.
|
||||
@@ -50,7 +50,7 @@ public:
|
||||
// Must be handshaked and in the right state
|
||||
XRPL_ASSERT(
|
||||
s.state() == Slot::State::Connected || s.state() == Slot::State::Accept,
|
||||
"xrpl::PeerFinder::Counts::can_activate : valid input state");
|
||||
"xrpl::peer_finder::Counts::can_activate : valid input state");
|
||||
|
||||
if (s.fixed() || s.reserved())
|
||||
return true;
|
||||
@@ -67,9 +67,9 @@ public:
|
||||
[[nodiscard]] std::size_t
|
||||
attemptsNeeded() const
|
||||
{
|
||||
if (attempts_ >= Tuning::kMaxConnectAttempts)
|
||||
if (attempts_ >= tuning::kMaxConnectAttempts)
|
||||
return 0;
|
||||
return Tuning::kMaxConnectAttempts - attempts_;
|
||||
return tuning::kMaxConnectAttempts - attempts_;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -295,7 +295,7 @@ private:
|
||||
switch (s.state())
|
||||
{
|
||||
case Slot::State::Accept:
|
||||
XRPL_ASSERT(s.inbound(), "xrpl::PeerFinder::Counts::adjust : input is inbound");
|
||||
XRPL_ASSERT(s.inbound(), "xrpl::peer_finder::Counts::adjust : input is inbound");
|
||||
acceptCount_ += n;
|
||||
break;
|
||||
|
||||
@@ -303,7 +303,7 @@ private:
|
||||
case Slot::State::Connected:
|
||||
XRPL_ASSERT(
|
||||
!s.inbound(),
|
||||
"xrpl::PeerFinder::Counts::adjust : input is not "
|
||||
"xrpl::peer_finder::Counts::adjust : input is not "
|
||||
"inbound");
|
||||
attempts_ += n;
|
||||
break;
|
||||
@@ -331,7 +331,7 @@ private:
|
||||
|
||||
// LCOV_EXCL_START
|
||||
default:
|
||||
UNREACHABLE("xrpl::PeerFinder::Counts::adjust : invalid input state");
|
||||
UNREACHABLE("xrpl::peer_finder::Counts::adjust : invalid input state");
|
||||
break;
|
||||
// LCOV_EXCL_STOP
|
||||
};
|
||||
@@ -391,4 +391,4 @@ private:
|
||||
int closingCount_{0};
|
||||
};
|
||||
|
||||
} // namespace xrpl::PeerFinder
|
||||
} // namespace xrpl::peer_finder
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include <chrono>
|
||||
#include <cstddef>
|
||||
|
||||
namespace xrpl::PeerFinder {
|
||||
namespace xrpl::peer_finder {
|
||||
|
||||
/**
|
||||
* Metadata for a Fixed slot.
|
||||
@@ -36,8 +36,8 @@ public:
|
||||
void
|
||||
failure(clock_type::time_point const& now)
|
||||
{
|
||||
failures_ = std::min(failures_ + 1, Tuning::kConnectionBackoff.size() - 1);
|
||||
when_ = now + std::chrono::minutes(Tuning::kConnectionBackoff[failures_]);
|
||||
failures_ = std::min(failures_ + 1, tuning::kConnectionBackoff.size() - 1);
|
||||
when_ = now + std::chrono::minutes(tuning::kConnectionBackoff[failures_]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -55,4 +55,4 @@ private:
|
||||
std::size_t failures_{0};
|
||||
};
|
||||
|
||||
} // namespace xrpl::PeerFinder
|
||||
} // namespace xrpl::peer_finder
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace xrpl::PeerFinder {
|
||||
namespace xrpl::peer_finder {
|
||||
|
||||
namespace detail {
|
||||
|
||||
@@ -28,7 +28,7 @@ template <class Target, class HopContainer>
|
||||
std::size_t
|
||||
handoutOne(Target& t, HopContainer& h)
|
||||
{
|
||||
XRPL_ASSERT(!t.full(), "xrpl::PeerFinder::detail::handoutOne : target is not full");
|
||||
XRPL_ASSERT(!t.full(), "xrpl::peer_finder::detail::handoutOne : target is not full");
|
||||
for (auto it = h.begin(); it != h.end(); ++it)
|
||||
{
|
||||
auto const& e = *it;
|
||||
@@ -95,7 +95,7 @@ public:
|
||||
[[nodiscard]] bool
|
||||
full() const
|
||||
{
|
||||
return list_.size() >= Tuning::kRedirectEndpointCount;
|
||||
return list_.size() >= tuning::kRedirectEndpointCount;
|
||||
}
|
||||
|
||||
[[nodiscard]] SlotImp::ptr const&
|
||||
@@ -124,7 +124,7 @@ private:
|
||||
template <class>
|
||||
RedirectHandouts::RedirectHandouts(SlotImp::ptr slot) : slot_(std::move(slot))
|
||||
{
|
||||
list_.reserve(Tuning::kRedirectEndpointCount);
|
||||
list_.reserve(tuning::kRedirectEndpointCount);
|
||||
}
|
||||
|
||||
template <class>
|
||||
@@ -138,7 +138,7 @@ RedirectHandouts::tryInsert(Endpoint const& ep)
|
||||
// addresses in a peer HTTP handshake instead of
|
||||
// the tmENDPOINTS message.
|
||||
//
|
||||
if (ep.hops > Tuning::kMaxHops)
|
||||
if (ep.hops > tuning::kMaxHops)
|
||||
return false;
|
||||
|
||||
// Don't send them our address
|
||||
@@ -181,7 +181,7 @@ public:
|
||||
[[nodiscard]] bool
|
||||
full() const
|
||||
{
|
||||
return list_.size() >= Tuning::kNumberOfEndpoints;
|
||||
return list_.size() >= tuning::kNumberOfEndpoints;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -210,7 +210,7 @@ private:
|
||||
template <class>
|
||||
SlotHandouts::SlotHandouts(SlotImp::ptr slot) : slot_(std::move(slot))
|
||||
{
|
||||
list_.reserve(Tuning::kNumberOfEndpoints);
|
||||
list_.reserve(tuning::kNumberOfEndpoints);
|
||||
}
|
||||
|
||||
template <class>
|
||||
@@ -220,7 +220,7 @@ SlotHandouts::tryInsert(Endpoint const& ep)
|
||||
if (full())
|
||||
return false;
|
||||
|
||||
if (ep.hops > Tuning::kMaxHops)
|
||||
if (ep.hops > tuning::kMaxHops)
|
||||
return false;
|
||||
|
||||
if (slot_->recent.filter(ep.address, ep.hops))
|
||||
@@ -259,9 +259,9 @@ class ConnectHandouts
|
||||
public:
|
||||
// Keeps track of addresses we have made outgoing connections
|
||||
// to, for the purposes of not connecting to them too frequently.
|
||||
using Squelches = beast::aged_set<beast::IP::Address>;
|
||||
using Squelches = beast::aged_set<beast::ip::Address>;
|
||||
|
||||
using list_type = std::vector<beast::IP::Endpoint>;
|
||||
using list_type = std::vector<beast::ip::Endpoint>;
|
||||
|
||||
private:
|
||||
std::size_t needed_;
|
||||
@@ -274,7 +274,7 @@ public:
|
||||
|
||||
template <class = void>
|
||||
bool
|
||||
tryInsert(beast::IP::Endpoint const& endpoint);
|
||||
tryInsert(beast::ip::Endpoint const& endpoint);
|
||||
|
||||
[[nodiscard]] bool
|
||||
empty() const
|
||||
@@ -316,13 +316,13 @@ ConnectHandouts::ConnectHandouts(std::size_t needed, Squelches& squelches)
|
||||
|
||||
template <class>
|
||||
bool
|
||||
ConnectHandouts::tryInsert(beast::IP::Endpoint const& endpoint)
|
||||
ConnectHandouts::tryInsert(beast::ip::Endpoint const& endpoint)
|
||||
{
|
||||
if (full())
|
||||
return false;
|
||||
|
||||
// Make sure the address isn't already in our list
|
||||
if (std::ranges::any_of(list_, [&endpoint](beast::IP::Endpoint const& other) {
|
||||
if (std::ranges::any_of(list_, [&endpoint](beast::ip::Endpoint const& other) {
|
||||
// Ignore port for security reasons
|
||||
return other.address() == endpoint.address();
|
||||
}))
|
||||
@@ -341,4 +341,4 @@ ConnectHandouts::tryInsert(beast::IP::Endpoint const& endpoint)
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace xrpl::PeerFinder
|
||||
} // namespace xrpl::peer_finder
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace xrpl::PeerFinder {
|
||||
namespace xrpl::peer_finder {
|
||||
|
||||
template <class>
|
||||
class Livecache;
|
||||
@@ -188,10 +188,10 @@ class Livecache : protected detail::LivecacheBase
|
||||
{
|
||||
private:
|
||||
using cache_type = beast::aged_map<
|
||||
beast::IP::Endpoint,
|
||||
beast::ip::Endpoint,
|
||||
Element,
|
||||
std::chrono::steady_clock,
|
||||
std::less<beast::IP::Endpoint>,
|
||||
std::less<beast::ip::Endpoint>,
|
||||
Allocator>;
|
||||
|
||||
beast::Journal journal_;
|
||||
@@ -220,8 +220,8 @@ public:
|
||||
// but not given out (since they would exceed maxHops). They
|
||||
// are used for automatic connection attempts.
|
||||
//
|
||||
using Histogram = std::array<int, 1 + Tuning::kMaxHops + 1>;
|
||||
using lists_type = std::array<list_type, 1 + Tuning::kMaxHops + 1>;
|
||||
using Histogram = std::array<int, 1 + tuning::kMaxHops + 1>;
|
||||
using lists_type = std::array<list_type, 1 + tuning::kMaxHops + 1>;
|
||||
|
||||
template <bool IsConst>
|
||||
struct Transform
|
||||
@@ -400,7 +400,7 @@ Livecache<Allocator>::expire()
|
||||
{
|
||||
std::size_t n(0);
|
||||
typename cache_type::time_point const expired(
|
||||
cache_.clock().now() - Tuning::kLiveCacheSecondsToLive);
|
||||
cache_.clock().now() - tuning::kLiveCacheSecondsToLive);
|
||||
for (auto iter(cache_.chronological.begin());
|
||||
iter != cache_.chronological.end() && iter.when() <= expired;)
|
||||
{
|
||||
@@ -427,8 +427,8 @@ Livecache<Allocator>::insert(Endpoint const& ep)
|
||||
// when redirecting.
|
||||
//
|
||||
XRPL_ASSERT(
|
||||
ep.hops <= (Tuning::kMaxHops + 1),
|
||||
"xrpl::PeerFinder::Livecache::insert : maximum input hops");
|
||||
ep.hops <= (tuning::kMaxHops + 1),
|
||||
"xrpl::peer_finder::Livecache::insert : maximum input hops");
|
||||
auto result = cache_.emplace(ep.address, ep);
|
||||
Element& e(result.first->second);
|
||||
if (result.second)
|
||||
@@ -468,7 +468,7 @@ void
|
||||
Livecache<Allocator>::onWrite(beast::PropertyStream::Map& map)
|
||||
{
|
||||
typename cache_type::time_point const expired(
|
||||
cache_.clock().now() - Tuning::kLiveCacheSecondsToLive);
|
||||
cache_.clock().now() - tuning::kLiveCacheSecondsToLive);
|
||||
map["size"] = size();
|
||||
map["hist"] = hops.histogram();
|
||||
beast::PropertyStream::Set set("entries", map);
|
||||
@@ -527,8 +527,8 @@ void
|
||||
Livecache<Allocator>::HopsT::insert(Element& e)
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
e.endpoint.hops <= Tuning::kMaxHops + 1,
|
||||
"xrpl::PeerFinder::Livecache::HopsT::insert : maximum input hops");
|
||||
e.endpoint.hops <= tuning::kMaxHops + 1,
|
||||
"xrpl::peer_finder::Livecache::HopsT::insert : maximum input hops");
|
||||
// This has security implications without a shuffle
|
||||
lists_[e.endpoint.hops].push_front(e);
|
||||
++hist_[e.endpoint.hops];
|
||||
@@ -539,8 +539,8 @@ void
|
||||
Livecache<Allocator>::HopsT::reinsert(Element& e, std::uint32_t numHops)
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
numHops <= Tuning::kMaxHops + 1,
|
||||
"xrpl::PeerFinder::Livecache::HopsT::reinsert : maximum hops input");
|
||||
numHops <= tuning::kMaxHops + 1,
|
||||
"xrpl::peer_finder::Livecache::HopsT::reinsert : maximum hops input");
|
||||
|
||||
auto& list = lists_[e.endpoint.hops];
|
||||
list.erase(list.iterator_to(e));
|
||||
@@ -561,4 +561,4 @@ Livecache<Allocator>::HopsT::remove(Element& e)
|
||||
list.erase(list.iterator_to(e));
|
||||
}
|
||||
|
||||
} // namespace xrpl::PeerFinder
|
||||
} // namespace xrpl::peer_finder
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace xrpl::PeerFinder {
|
||||
namespace xrpl::peer_finder {
|
||||
|
||||
/**
|
||||
* The Logic for maintaining the list of Slot addresses.
|
||||
@@ -57,7 +57,7 @@ public:
|
||||
// Maps remote endpoints to slots. Since a slot has a
|
||||
// remote endpoint upon construction, this holds all counts_.
|
||||
//
|
||||
using Slots = std::map<beast::IP::Endpoint, std::shared_ptr<SlotImp>>;
|
||||
using Slots = std::map<beast::ip::Endpoint, std::shared_ptr<SlotImp>>;
|
||||
|
||||
beast::Journal journal;
|
||||
clock_type& clock;
|
||||
@@ -81,7 +81,7 @@ private:
|
||||
Counts counts_;
|
||||
|
||||
// A list of slots that should always be connected
|
||||
std::map<beast::IP::Endpoint, Fixed> fixed_;
|
||||
std::map<beast::ip::Endpoint, Fixed> fixed_;
|
||||
|
||||
public:
|
||||
// Live livecache from mtENDPOINTS messages
|
||||
@@ -96,7 +96,7 @@ public:
|
||||
// The addresses (but not port) we are connected to. This includes
|
||||
// outgoing connection attempts. Note that this set can contain
|
||||
// duplicates (since the port is not set)
|
||||
std::multiset<beast::IP::Address> connectedAddresses;
|
||||
std::multiset<beast::ip::Address> connectedAddresses;
|
||||
|
||||
// Set of public keys belonging to active peers
|
||||
std::set<PublicKey> keys;
|
||||
@@ -170,13 +170,13 @@ public:
|
||||
}
|
||||
|
||||
void
|
||||
addFixedPeer(std::string_view name, beast::IP::Endpoint const& ep)
|
||||
addFixedPeer(std::string_view name, beast::ip::Endpoint const& ep)
|
||||
{
|
||||
addFixedPeer(name, std::vector<beast::IP::Endpoint>{ep});
|
||||
addFixedPeer(name, std::vector<beast::ip::Endpoint>{ep});
|
||||
}
|
||||
|
||||
void
|
||||
addFixedPeer(std::string_view name, std::vector<beast::IP::Endpoint> const& addresses)
|
||||
addFixedPeer(std::string_view name, std::vector<beast::ip::Endpoint> const& addresses)
|
||||
{
|
||||
std::scoped_lock const _(lock);
|
||||
|
||||
@@ -213,8 +213,8 @@ public:
|
||||
// Called when the Checker completes a connectivity test
|
||||
void
|
||||
checkComplete(
|
||||
beast::IP::Endpoint const& remoteAddress,
|
||||
beast::IP::Endpoint const& checkedAddress,
|
||||
beast::ip::Endpoint const& remoteAddress,
|
||||
beast::ip::Endpoint const& checkedAddress,
|
||||
boost::system::error_code ec)
|
||||
{
|
||||
if (ec == boost::asio::error::operation_aborted)
|
||||
@@ -256,8 +256,8 @@ public:
|
||||
|
||||
std::pair<SlotImp::ptr, Result>
|
||||
newInboundSlot(
|
||||
beast::IP::Endpoint const& localEndpoint,
|
||||
beast::IP::Endpoint const& remoteEndpoint)
|
||||
beast::ip::Endpoint const& localEndpoint,
|
||||
beast::ip::Endpoint const& remoteEndpoint)
|
||||
{
|
||||
JLOG(journal.debug()) << std::left << std::setw(18) << "Logic accept" << remoteEndpoint
|
||||
<< " on local " << localEndpoint;
|
||||
@@ -293,7 +293,7 @@ public:
|
||||
// Remote address must not already exist
|
||||
XRPL_ASSERT(
|
||||
result.second,
|
||||
"xrpl::PeerFinder::Logic::new_inbound_slot : remote endpoint "
|
||||
"xrpl::peer_finder::Logic::new_inbound_slot : remote endpoint "
|
||||
"inserted");
|
||||
// Add to the connected address list
|
||||
connectedAddresses.emplace(remoteEndpoint.address());
|
||||
@@ -306,7 +306,7 @@ public:
|
||||
|
||||
// Can't check for self-connect because we don't know the local endpoint
|
||||
std::pair<SlotImp::ptr, Result>
|
||||
newOutboundSlot(beast::IP::Endpoint const& remoteEndpoint)
|
||||
newOutboundSlot(beast::ip::Endpoint const& remoteEndpoint)
|
||||
{
|
||||
JLOG(journal.debug()) << std::left << std::setw(18) << "Logic connect " << remoteEndpoint;
|
||||
|
||||
@@ -329,7 +329,7 @@ public:
|
||||
// Remote address must not already exist
|
||||
XRPL_ASSERT(
|
||||
result.second,
|
||||
"xrpl::PeerFinder::Logic::new_outbound_slot : remote endpoint "
|
||||
"xrpl::peer_finder::Logic::new_outbound_slot : remote endpoint "
|
||||
"inserted");
|
||||
|
||||
// Add to the connected address list
|
||||
@@ -342,7 +342,7 @@ public:
|
||||
}
|
||||
|
||||
bool
|
||||
onConnected(SlotImp::ptr const& slot, beast::IP::Endpoint const& localEndpoint)
|
||||
onConnected(SlotImp::ptr const& slot, beast::ip::Endpoint const& localEndpoint)
|
||||
{
|
||||
beast::WrappedSink sink{journal.sink(), slot->prefix()};
|
||||
beast::Journal const journal{sink};
|
||||
@@ -354,7 +354,7 @@ public:
|
||||
// The object must exist in our table
|
||||
XRPL_ASSERT(
|
||||
slots.contains(slot->remoteEndpoint()),
|
||||
"xrpl::PeerFinder::Logic::onConnected : valid slot input");
|
||||
"xrpl::peer_finder::Logic::onConnected : valid slot input");
|
||||
// Assign the local endpoint now that it's known
|
||||
slot->localEndpoint(localEndpoint);
|
||||
|
||||
@@ -365,7 +365,7 @@ public:
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
iter->second->localEndpoint() == slot->remoteEndpoint(),
|
||||
"xrpl::PeerFinder::Logic::onConnected : local and remote "
|
||||
"xrpl::peer_finder::Logic::onConnected : local and remote "
|
||||
"endpoints do match");
|
||||
JLOG(journal.warn()) << "Logic dropping as self connect";
|
||||
return false;
|
||||
@@ -393,11 +393,11 @@ public:
|
||||
// The object must exist in our table
|
||||
XRPL_ASSERT(
|
||||
slots.contains(slot->remoteEndpoint()),
|
||||
"xrpl::PeerFinder::Logic::activate : valid slot input");
|
||||
"xrpl::peer_finder::Logic::activate : valid slot input");
|
||||
// Must be accepted or connected
|
||||
XRPL_ASSERT(
|
||||
slot->state() == Slot::State::Accept || slot->state() == Slot::State::Connected,
|
||||
"xrpl::PeerFinder::Logic::activate : valid slot state");
|
||||
"xrpl::peer_finder::Logic::activate : valid slot state");
|
||||
|
||||
// Check for duplicate connection by key
|
||||
if (keys.contains(key))
|
||||
@@ -425,7 +425,7 @@ public:
|
||||
{
|
||||
[[maybe_unused]] bool const inserted = keys.insert(key).second;
|
||||
// Public key must not already exist
|
||||
XRPL_ASSERT(inserted, "xrpl::PeerFinder::Logic::activate : public key inserted");
|
||||
XRPL_ASSERT(inserted, "xrpl::peer_finder::Logic::activate : public key inserted");
|
||||
}
|
||||
|
||||
// Change state and update counts
|
||||
@@ -443,7 +443,7 @@ public:
|
||||
if (iter == fixed_.end())
|
||||
{
|
||||
logicError(
|
||||
"PeerFinder::Logic::activate(): remote_endpoint "
|
||||
"peer_finder::Logic::activate(): remote_endpoint "
|
||||
"missing from fixed_");
|
||||
}
|
||||
|
||||
@@ -476,10 +476,10 @@ public:
|
||||
// VFALCO TODO This should add the returned addresses to the
|
||||
// squelch list in one go once the list is built,
|
||||
// rather than having each module add to the squelch list.
|
||||
std::vector<beast::IP::Endpoint>
|
||||
std::vector<beast::ip::Endpoint>
|
||||
autoconnect()
|
||||
{
|
||||
std::vector<beast::IP::Endpoint> none;
|
||||
std::vector<beast::ip::Endpoint> none;
|
||||
|
||||
std::scoped_lock const _(lock);
|
||||
|
||||
@@ -635,7 +635,7 @@ public:
|
||||
// either. ipv6 has a slightly more compact string
|
||||
// representation of 0, so use that for self entries.
|
||||
ep.address =
|
||||
beast::IP::Endpoint(beast::IP::AddressV6()).atPort(config_.listeningPort);
|
||||
beast::ip::Endpoint(beast::ip::AddressV6()).atPort(config_.listeningPort);
|
||||
for (auto& t : targets)
|
||||
t.insert(ep);
|
||||
}
|
||||
@@ -656,7 +656,7 @@ public:
|
||||
result.emplace_back(slot, list);
|
||||
}
|
||||
|
||||
whenBroadcast = now + Tuning::kSecondsPerMessage;
|
||||
whenBroadcast = now + tuning::kSecondsPerMessage;
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -675,7 +675,7 @@ public:
|
||||
entry.second->expire();
|
||||
|
||||
// Expire the recent attempts table
|
||||
beast::expire(squelches, Tuning::kRecentAttemptDuration);
|
||||
beast::expire(squelches, tuning::kRecentAttemptDuration);
|
||||
|
||||
bootcache.periodicActivity();
|
||||
}
|
||||
@@ -692,7 +692,7 @@ public:
|
||||
Endpoint& ep(*iter);
|
||||
|
||||
// Enforce hop limit
|
||||
if (ep.hops > Tuning::kMaxHops)
|
||||
if (ep.hops > tuning::kMaxHops)
|
||||
{
|
||||
JLOG(journal.debug()) << std::left << std::setw(18) << "Endpoints drop "
|
||||
<< ep.address << " for excess hops " << ep.hops;
|
||||
@@ -754,10 +754,10 @@ public:
|
||||
beast::Journal const journal{sink};
|
||||
|
||||
// If we're sent too many endpoints, sample them at random:
|
||||
if (list.size() > Tuning::kNumberOfEndpointsMax)
|
||||
if (list.size() > tuning::kNumberOfEndpointsMax)
|
||||
{
|
||||
std::shuffle(list.begin(), list.end(), defaultPrng());
|
||||
list.resize(Tuning::kNumberOfEndpointsMax);
|
||||
list.resize(tuning::kNumberOfEndpointsMax);
|
||||
}
|
||||
|
||||
JLOG(journal.trace()) << "Endpoints contained " << list.size()
|
||||
@@ -768,12 +768,12 @@ public:
|
||||
// The object must exist in our table
|
||||
XRPL_ASSERT(
|
||||
slots.contains(slot->remoteEndpoint()),
|
||||
"xrpl::PeerFinder::Logic::onEndpoints : valid slot input");
|
||||
"xrpl::peer_finder::Logic::onEndpoints : valid slot input");
|
||||
|
||||
// Must be handshaked!
|
||||
XRPL_ASSERT(
|
||||
slot->state() == Slot::State::Active,
|
||||
"xrpl::PeerFinder::Logic::onEndpoints : valid slot state");
|
||||
"xrpl::peer_finder::Logic::onEndpoints : valid slot state");
|
||||
|
||||
clock_type::time_point const now(clock.now());
|
||||
|
||||
@@ -785,7 +785,7 @@ public:
|
||||
|
||||
for (auto const& ep : list)
|
||||
{
|
||||
XRPL_ASSERT(ep.hops, "xrpl::PeerFinder::Logic::onEndpoints : nonzero hops");
|
||||
XRPL_ASSERT(ep.hops, "xrpl::peer_finder::Logic::onEndpoints : nonzero hops");
|
||||
|
||||
slot->recent.insert(ep.address, ep.hops);
|
||||
|
||||
@@ -837,7 +837,7 @@ public:
|
||||
bootcache.insert(ep.address);
|
||||
}
|
||||
|
||||
slot->whenAcceptEndpoints = now + Tuning::kSecondsPerMessage;
|
||||
slot->whenAcceptEndpoints = now + tuning::kSecondsPerMessage;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
@@ -851,7 +851,7 @@ public:
|
||||
if (iter == slots.end())
|
||||
{
|
||||
logicError(
|
||||
"PeerFinder::Logic::remove(): remote_endpoint "
|
||||
"peer_finder::Logic::remove(): remote_endpoint "
|
||||
"missing from slots_");
|
||||
}
|
||||
|
||||
@@ -866,7 +866,7 @@ public:
|
||||
if (iter == keys.end())
|
||||
{
|
||||
logicError(
|
||||
"PeerFinder::Logic::remove(): public_key missing "
|
||||
"peer_finder::Logic::remove(): public_key missing "
|
||||
"from keys_");
|
||||
}
|
||||
|
||||
@@ -879,7 +879,7 @@ public:
|
||||
if (iter == connectedAddresses.end())
|
||||
{
|
||||
logicError(
|
||||
"PeerFinder::Logic::remove(): remote_endpoint "
|
||||
"peer_finder::Logic::remove(): remote_endpoint "
|
||||
"address missing from connectedAddresses_");
|
||||
}
|
||||
|
||||
@@ -907,7 +907,7 @@ public:
|
||||
if (iter == fixed_.end())
|
||||
{
|
||||
logicError(
|
||||
"PeerFinder::Logic::on_closed(): remote_endpoint "
|
||||
"peer_finder::Logic::on_closed(): remote_endpoint "
|
||||
"missing from fixed_");
|
||||
}
|
||||
|
||||
@@ -943,7 +943,7 @@ public:
|
||||
// LCOV_EXCL_START
|
||||
default:
|
||||
UNREACHABLE(
|
||||
"xrpl::PeerFinder::Logic::on_closed : invalid slot "
|
||||
"xrpl::peer_finder::Logic::on_closed : invalid slot "
|
||||
"state");
|
||||
break;
|
||||
// LCOV_EXCL_STOP
|
||||
@@ -968,17 +968,17 @@ public:
|
||||
// Returns `true` if the address matches a fixed slot address
|
||||
// Must have the lock held
|
||||
bool
|
||||
fixed(beast::IP::Endpoint const& endpoint) const
|
||||
fixed(beast::ip::Endpoint const& endpoint) const
|
||||
{
|
||||
return std::ranges::any_of(
|
||||
fixed_, [&endpoint](auto const& entry) { return entry.first == endpoint; });
|
||||
}
|
||||
|
||||
// Returns `true` if the address matches a fixed slot address
|
||||
// Note that this does not use the port information in the IP::Endpoint
|
||||
// Note that this does not use the port information in the ip::Endpoint
|
||||
// Must have the lock held
|
||||
bool
|
||||
fixed(beast::IP::Address const& address) const
|
||||
fixed(beast::ip::Address const& address) const
|
||||
{
|
||||
return std::ranges::any_of(
|
||||
fixed_, [&address](auto const& entry) { return entry.first.address() == address; });
|
||||
@@ -1097,9 +1097,9 @@ public:
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
// Returns true if the IP::Endpoint contains no invalid data.
|
||||
// Returns true if the ip::Endpoint contains no invalid data.
|
||||
bool
|
||||
isValidAddress(beast::IP::Endpoint const& address)
|
||||
isValidAddress(beast::ip::Endpoint const& address)
|
||||
{
|
||||
if (isUnspecified(address))
|
||||
return false;
|
||||
@@ -1220,7 +1220,7 @@ Logic<Checker>::onRedirects(
|
||||
{
|
||||
std::scoped_lock const _(lock);
|
||||
std::size_t n = 0;
|
||||
for (; first != last && n < Tuning::kMaxRedirects; ++first, ++n)
|
||||
for (; first != last && n < tuning::kMaxRedirects; ++first, ++n)
|
||||
bootcache.insert(beast::IPAddressConversion::fromAsio(*first));
|
||||
if (n > 0)
|
||||
{
|
||||
@@ -1229,4 +1229,4 @@ Logic<Checker>::onRedirects(
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace xrpl::PeerFinder
|
||||
} // namespace xrpl::peer_finder
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
namespace xrpl::PeerFinder {
|
||||
namespace xrpl::peer_finder {
|
||||
|
||||
class SlotImp : public Slot
|
||||
{
|
||||
@@ -21,13 +21,13 @@ public:
|
||||
|
||||
// inbound
|
||||
SlotImp(
|
||||
beast::IP::Endpoint const& localEndpoint,
|
||||
beast::IP::Endpoint remoteEndpoint,
|
||||
beast::ip::Endpoint const& localEndpoint,
|
||||
beast::ip::Endpoint remoteEndpoint,
|
||||
bool fixed,
|
||||
clock_type& clock);
|
||||
|
||||
// outbound
|
||||
SlotImp(beast::IP::Endpoint remoteEndpoint, bool fixed, clock_type& clock);
|
||||
SlotImp(beast::ip::Endpoint remoteEndpoint, bool fixed, clock_type& clock);
|
||||
|
||||
bool
|
||||
inbound() const override
|
||||
@@ -53,13 +53,13 @@ public:
|
||||
return state_;
|
||||
}
|
||||
|
||||
beast::IP::Endpoint const&
|
||||
beast::ip::Endpoint const&
|
||||
remoteEndpoint() const override
|
||||
{
|
||||
return remoteEndpoint_;
|
||||
}
|
||||
|
||||
std::optional<beast::IP::Endpoint> const&
|
||||
std::optional<beast::ip::Endpoint> const&
|
||||
localEndpoint() const override
|
||||
{
|
||||
return localEndpoint_;
|
||||
@@ -93,13 +93,13 @@ public:
|
||||
}
|
||||
|
||||
void
|
||||
localEndpoint(beast::IP::Endpoint const& endpoint)
|
||||
localEndpoint(beast::ip::Endpoint const& endpoint)
|
||||
{
|
||||
localEndpoint_ = endpoint;
|
||||
}
|
||||
|
||||
void
|
||||
remoteEndpoint(beast::IP::Endpoint const& endpoint)
|
||||
remoteEndpoint(beast::ip::Endpoint const& endpoint)
|
||||
{
|
||||
remoteEndpoint_ = endpoint;
|
||||
}
|
||||
@@ -140,20 +140,20 @@ public:
|
||||
* sending a slot the same address too frequently.
|
||||
*/
|
||||
void
|
||||
insert(beast::IP::Endpoint const& ep, std::uint32_t hops);
|
||||
insert(beast::ip::Endpoint const& ep, std::uint32_t hops);
|
||||
|
||||
/**
|
||||
* Returns `true` if we should not send endpoint to the slot.
|
||||
*/
|
||||
bool
|
||||
filter(beast::IP::Endpoint const& ep, std::uint32_t hops);
|
||||
filter(beast::ip::Endpoint const& ep, std::uint32_t hops);
|
||||
|
||||
private:
|
||||
void
|
||||
expire();
|
||||
|
||||
friend class SlotImp;
|
||||
beast::aged_unordered_map<beast::IP::Endpoint, std::uint32_t> cache_;
|
||||
beast::aged_unordered_map<beast::ip::Endpoint, std::uint32_t> cache_;
|
||||
} recent;
|
||||
|
||||
void
|
||||
@@ -167,8 +167,8 @@ private:
|
||||
bool const fixed_;
|
||||
bool reserved_;
|
||||
State state_;
|
||||
beast::IP::Endpoint remoteEndpoint_;
|
||||
std::optional<beast::IP::Endpoint> localEndpoint_;
|
||||
beast::ip::Endpoint remoteEndpoint_;
|
||||
std::optional<beast::ip::Endpoint> localEndpoint_;
|
||||
std::optional<PublicKey> publicKey_;
|
||||
|
||||
static std::int32_t constexpr kUnknownPort = -1;
|
||||
@@ -196,4 +196,4 @@ public:
|
||||
clock_type::time_point whenAcceptEndpoints;
|
||||
};
|
||||
|
||||
} // namespace xrpl::PeerFinder
|
||||
} // namespace xrpl::peer_finder
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace xrpl::PeerFinder {
|
||||
namespace xrpl::peer_finder {
|
||||
|
||||
/**
|
||||
* A static or dynamic source of peer addresses.
|
||||
@@ -46,4 +46,4 @@ public:
|
||||
fetch(Results& results, beast::Journal journal) = 0;
|
||||
};
|
||||
|
||||
} // namespace xrpl::PeerFinder
|
||||
} // namespace xrpl::peer_finder
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace xrpl::PeerFinder {
|
||||
namespace xrpl::peer_finder {
|
||||
|
||||
/**
|
||||
* Provides addresses from a static set of strings.
|
||||
@@ -22,4 +22,4 @@ public:
|
||||
make(std::string const& name, Strings const& strings);
|
||||
};
|
||||
|
||||
} // namespace xrpl::PeerFinder
|
||||
} // namespace xrpl::peer_finder
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
namespace xrpl::PeerFinder {
|
||||
namespace xrpl::peer_finder {
|
||||
|
||||
/**
|
||||
* Abstract persistence for PeerFinder data.
|
||||
@@ -17,7 +17,7 @@ public:
|
||||
virtual ~Store() = default;
|
||||
|
||||
// load the bootstrap cache
|
||||
using load_callback = std::function<void(beast::IP::Endpoint, int)>;
|
||||
using load_callback = std::function<void(beast::ip::Endpoint, int)>;
|
||||
virtual std::size_t
|
||||
load(load_callback const& cb) = 0;
|
||||
|
||||
@@ -26,11 +26,11 @@ public:
|
||||
{
|
||||
explicit Entry() = default;
|
||||
|
||||
beast::IP::Endpoint endpoint;
|
||||
beast::ip::Endpoint endpoint;
|
||||
int valence{};
|
||||
};
|
||||
virtual void
|
||||
save(std::vector<Entry> const& v) = 0;
|
||||
};
|
||||
|
||||
} // namespace xrpl::PeerFinder
|
||||
} // namespace xrpl::peer_finder
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
* Heuristically tuned constants.
|
||||
*/
|
||||
/** @{ */
|
||||
namespace xrpl::PeerFinder::Tuning {
|
||||
namespace xrpl::peer_finder::tuning {
|
||||
|
||||
//---------------------------------------------------------
|
||||
//
|
||||
@@ -111,5 +111,5 @@ constexpr std::chrono::seconds kLiveCacheSecondsToLive(30);
|
||||
// Note that we ignore the port for purposes of comparison.
|
||||
constexpr std::chrono::seconds kRecentAttemptDuration(60);
|
||||
|
||||
} // namespace xrpl::PeerFinder::Tuning
|
||||
} // namespace xrpl::peer_finder::tuning
|
||||
/** @} */
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace xrpl::PeerFinder {
|
||||
namespace xrpl::peer_finder {
|
||||
|
||||
/**
|
||||
* @brief Create a new Manager.
|
||||
@@ -33,4 +33,4 @@ makeManager(
|
||||
Store& store,
|
||||
beast::insight::Collector::ptr const& collector);
|
||||
|
||||
} // namespace xrpl::PeerFinder
|
||||
} // namespace xrpl::peer_finder
|
||||
|
||||
@@ -301,14 +301,15 @@ message TMLedgerData {
|
||||
}
|
||||
|
||||
message TMPing {
|
||||
// Previously used - don't reuse.
|
||||
reserved 3, 4;
|
||||
|
||||
enum pingType {
|
||||
ptPING = 0; // we want a reply
|
||||
ptPONG = 1; // this is a reply
|
||||
}
|
||||
required pingType type = 1;
|
||||
optional uint32 seq = 2; // detect stale replies, ensure other side is reading
|
||||
optional uint64 pingTime = 3; // know when we think we sent the ping
|
||||
optional uint64 netTime = 4;
|
||||
optional uint32 seq = 2; // detect stale replies, ensure other side is reading
|
||||
}
|
||||
|
||||
message TMSquelch {
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace xrpl {
|
||||
* Command line Requests use apiCommandLineVersion.
|
||||
*/
|
||||
|
||||
namespace RPC {
|
||||
namespace rpc {
|
||||
|
||||
template <unsigned int Version>
|
||||
static constexpr std::integral_constant<unsigned, Version> kApiVersion = {};
|
||||
@@ -60,7 +60,7 @@ static_assert(kApiMaximumValidVersion >= kApiMaximumSupportedVersion);
|
||||
inline void
|
||||
setVersion(json::Value& parent, unsigned int apiVersion, bool betaEnabled)
|
||||
{
|
||||
XRPL_ASSERT(apiVersion != kApiInvalidVersion, "xrpl::RPC::setVersion : input is valid");
|
||||
XRPL_ASSERT(apiVersion != kApiInvalidVersion, "xrpl::rpc::setVersion : input is valid");
|
||||
|
||||
auto& retObj = parent[jss::version] = json::ValueType::Object;
|
||||
|
||||
@@ -99,12 +99,12 @@ setVersion(json::Value& parent, unsigned int apiVersion, bool betaEnabled)
|
||||
inline unsigned int
|
||||
getAPIVersionNumber(json::Value const& jv, bool betaEnabled)
|
||||
{
|
||||
static json::Value const kMinVersion(RPC::kApiMinimumSupportedVersion);
|
||||
static json::Value const kMinVersion(rpc::kApiMinimumSupportedVersion);
|
||||
json::Value const maxVersion(
|
||||
betaEnabled ? RPC::kApiBetaVersion : RPC::kApiMaximumSupportedVersion);
|
||||
betaEnabled ? rpc::kApiBetaVersion : rpc::kApiMaximumSupportedVersion);
|
||||
|
||||
if (!jv.isObject() || !jv.isMember(jss::api_version))
|
||||
return RPC::kApiVersionIfUnspecified;
|
||||
return rpc::kApiVersionIfUnspecified;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -113,33 +113,33 @@ getAPIVersionNumber(json::Value const& jv, bool betaEnabled)
|
||||
{
|
||||
case json::ValueType::Int:
|
||||
if (rawVersion.asInt() < 0)
|
||||
return RPC::kApiInvalidVersion;
|
||||
return rpc::kApiInvalidVersion;
|
||||
[[fallthrough]];
|
||||
case json::ValueType::UInt: {
|
||||
auto const apiVersion = rawVersion.asUInt();
|
||||
if (apiVersion < kMinVersion || apiVersion > maxVersion)
|
||||
return RPC::kApiInvalidVersion;
|
||||
return rpc::kApiInvalidVersion;
|
||||
return apiVersion;
|
||||
}
|
||||
default:
|
||||
return RPC::kApiInvalidVersion;
|
||||
return rpc::kApiInvalidVersion;
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return RPC::kApiInvalidVersion;
|
||||
return rpc::kApiInvalidVersion;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace RPC
|
||||
} // namespace rpc
|
||||
|
||||
template <unsigned MinVer, unsigned MaxVer, typename Fn, typename... Args>
|
||||
void
|
||||
forApiVersions(Fn const& fn, Args&&... args)
|
||||
requires //
|
||||
(MaxVer >= MinVer) && //
|
||||
(MinVer >= RPC::kApiMinimumSupportedVersion) && //
|
||||
(RPC::kApiMaximumValidVersion >= MaxVer) && requires {
|
||||
(MinVer >= rpc::kApiMinimumSupportedVersion) && //
|
||||
(rpc::kApiMaximumValidVersion >= MaxVer) && requires {
|
||||
fn(std::integral_constant<unsigned int, MinVer>{}, std::forward<Args>(args)...);
|
||||
fn(std::integral_constant<unsigned int, MaxVer>{}, std::forward<Args>(args)...);
|
||||
}
|
||||
@@ -158,11 +158,11 @@ template <typename Fn, typename... Args>
|
||||
void
|
||||
forAllApiVersions(Fn const& fn, Args&&... args)
|
||||
requires requires {
|
||||
forApiVersions<RPC::kApiMinimumSupportedVersion, RPC::kApiMaximumValidVersion>(
|
||||
forApiVersions<rpc::kApiMinimumSupportedVersion, rpc::kApiMaximumValidVersion>(
|
||||
fn, std::forward<Args>(args)...);
|
||||
}
|
||||
{
|
||||
forApiVersions<RPC::kApiMinimumSupportedVersion, RPC::kApiMaximumValidVersion>(
|
||||
forApiVersions<rpc::kApiMinimumSupportedVersion, rpc::kApiMaximumValidVersion>(
|
||||
fn, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
* Versioning information for this build.
|
||||
*/
|
||||
// VFALCO The namespace is deprecated
|
||||
namespace xrpl::BuildInfo {
|
||||
namespace xrpl::build_info {
|
||||
|
||||
/**
|
||||
* Server version.
|
||||
@@ -84,4 +84,4 @@ isXrpldVersion(std::uint64_t version);
|
||||
bool
|
||||
isNewerVersion(std::uint64_t version);
|
||||
|
||||
} // namespace xrpl::BuildInfo
|
||||
} // namespace xrpl::build_info
|
||||
|
||||
@@ -167,7 +167,7 @@ enum WarningCodeI {
|
||||
|
||||
// VFALCO NOTE these should probably not be in the RPC namespace.
|
||||
|
||||
namespace RPC {
|
||||
namespace rpc {
|
||||
|
||||
/**
|
||||
* Maps an rpc error code to its token, default message, and HTTP status.
|
||||
@@ -337,7 +337,7 @@ containsError(json::Value const& json);
|
||||
int
|
||||
errorCodeHttpStatus(ErrorCodeI code);
|
||||
|
||||
} // namespace RPC
|
||||
} // namespace rpc
|
||||
|
||||
/**
|
||||
* Returns a single string with the contents of an RPC error.
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <xrpl/protocol/LedgerFormats.h>
|
||||
#include <xrpl/protocol/Protocol.h>
|
||||
#include <xrpl/protocol/STXChainBridge.h>
|
||||
#include <xrpl/protocol/SeqProxy.h>
|
||||
#include <xrpl/protocol/UintTypes.h>
|
||||
|
||||
#include <array>
|
||||
@@ -21,8 +22,6 @@
|
||||
#include <utility>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
class SeqProxy;
|
||||
/**
|
||||
* Keylet computation functions.
|
||||
*
|
||||
@@ -123,7 +122,7 @@ trustLine(AccountID const& id, Issue const& issue) noexcept
|
||||
*/
|
||||
/** @{ */
|
||||
Keylet
|
||||
offer(AccountID const& id, std::uint32_t seq) noexcept;
|
||||
offer(AccountID const& id, SeqProxy const& seq) noexcept;
|
||||
|
||||
inline Keylet
|
||||
offer(uint256 const& key) noexcept
|
||||
@@ -136,7 +135,7 @@ offer(uint256 const& key) noexcept
|
||||
* The initial directory page for a specific quality
|
||||
*/
|
||||
Keylet
|
||||
quality(Keylet const& k, std::uint64_t q) noexcept;
|
||||
quality(Keylet const& k, std::uint64_t const q) noexcept;
|
||||
|
||||
/**
|
||||
* The directory for the next lower quality
|
||||
@@ -149,10 +148,7 @@ next(Keylet const& k);
|
||||
*/
|
||||
/** @{ */
|
||||
Keylet
|
||||
ticket(AccountID const& id, std::uint32_t ticketSeq);
|
||||
|
||||
Keylet
|
||||
ticket(AccountID const& id, SeqProxy ticketSeq);
|
||||
ticket(AccountID const& id, SeqProxy const& ticketSeq);
|
||||
|
||||
inline Keylet
|
||||
ticket(uint256 const& key)
|
||||
@@ -178,7 +174,7 @@ sponsorship(AccountID const& sponsor, AccountID const& sponsee) noexcept;
|
||||
*/
|
||||
/** @{ */
|
||||
Keylet
|
||||
check(AccountID const& id, std::uint32_t seq) noexcept;
|
||||
check(AccountID const& id, SeqProxy const& seq) noexcept;
|
||||
|
||||
inline Keylet
|
||||
check(uint256 const& key) noexcept
|
||||
@@ -225,10 +221,10 @@ ownerDir(AccountID const& id) noexcept;
|
||||
*/
|
||||
/** @{ */
|
||||
Keylet
|
||||
page(uint256 const& root, std::uint64_t index = 0) noexcept;
|
||||
page(uint256 const& root, std::uint64_t const index = 0) noexcept;
|
||||
|
||||
inline Keylet
|
||||
page(Keylet const& root, std::uint64_t index = 0) noexcept
|
||||
page(Keylet const& root, std::uint64_t const index = 0) noexcept
|
||||
{
|
||||
XRPL_ASSERT(root.type == ltDIR_NODE, "xrpl::keylet::page : valid root type");
|
||||
return page(root.key, index);
|
||||
@@ -239,13 +235,13 @@ page(Keylet const& root, std::uint64_t index = 0) noexcept
|
||||
* An escrow entry
|
||||
*/
|
||||
Keylet
|
||||
escrow(AccountID const& src, std::uint32_t seq) noexcept;
|
||||
escrow(AccountID const& src, SeqProxy const& seq) noexcept;
|
||||
|
||||
/**
|
||||
* A PaymentChannel
|
||||
*/
|
||||
Keylet
|
||||
payChannel(AccountID const& src, AccountID const& dst, std::uint32_t seq) noexcept;
|
||||
payChannel(AccountID const& src, AccountID const& dst, SeqProxy const& seq) noexcept;
|
||||
|
||||
/**
|
||||
* NFT page keylets
|
||||
@@ -276,7 +272,7 @@ nftokenPage(Keylet const& k, uint256 const& token);
|
||||
* An offer from an account to buy or sell an NFT
|
||||
*/
|
||||
Keylet
|
||||
nftokenOffer(AccountID const& owner, std::uint32_t seq);
|
||||
nftokenOffer(AccountID const& owner, SeqProxy const& seq);
|
||||
|
||||
inline Keylet
|
||||
nftokenOffer(uint256 const& offer)
|
||||
@@ -316,17 +312,17 @@ bridge(STXChainBridge const& bridge, STXChainBridge::ChainType chainType);
|
||||
|
||||
// `seq` is stored as `sfXChainClaimID` in the object
|
||||
Keylet
|
||||
xChainClaimID(STXChainBridge const& bridge, std::uint64_t seq);
|
||||
xChainClaimID(STXChainBridge const& bridge, std::uint64_t const seq);
|
||||
|
||||
// `seq` is stored as `sfXChainAccountCreateCount` in the object
|
||||
Keylet
|
||||
xChainCreateAccountClaimID(STXChainBridge const& bridge, std::uint64_t seq);
|
||||
xChainCreateAccountClaimID(STXChainBridge const& bridge, std::uint64_t const seq);
|
||||
|
||||
Keylet
|
||||
did(AccountID const& account) noexcept;
|
||||
|
||||
Keylet
|
||||
oracle(AccountID const& account, std::uint32_t const& documentID) noexcept;
|
||||
oracle(AccountID const& account, std::uint32_t const documentID) noexcept;
|
||||
|
||||
Keylet
|
||||
credential(AccountID const& subject, AccountID const& issuer, Slice const& credType) noexcept;
|
||||
@@ -337,9 +333,6 @@ credential(uint256 const& key) noexcept
|
||||
return {ltCREDENTIAL, key};
|
||||
}
|
||||
|
||||
Keylet
|
||||
mptokenIssuance(std::uint32_t seq, AccountID const& issuer) noexcept;
|
||||
|
||||
Keylet
|
||||
mptokenIssuance(MPTID const& issuanceID) noexcept;
|
||||
|
||||
@@ -362,7 +355,7 @@ Keylet
|
||||
mptoken(uint256 const& issuanceKey, AccountID const& holder) noexcept;
|
||||
|
||||
Keylet
|
||||
vault(AccountID const& owner, std::uint32_t seq) noexcept;
|
||||
vault(AccountID const& owner, SeqProxy const& seq) noexcept;
|
||||
|
||||
inline Keylet
|
||||
vault(uint256 const& vaultKey)
|
||||
@@ -371,7 +364,7 @@ vault(uint256 const& vaultKey)
|
||||
}
|
||||
|
||||
Keylet
|
||||
loanBroker(AccountID const& owner, std::uint32_t seq) noexcept;
|
||||
loanBroker(AccountID const& owner, SeqProxy const& seq) noexcept;
|
||||
|
||||
inline Keylet
|
||||
loanBroker(uint256 const& key)
|
||||
@@ -380,7 +373,7 @@ loanBroker(uint256 const& key)
|
||||
}
|
||||
|
||||
Keylet
|
||||
loan(uint256 const& loanBrokerID, std::uint32_t loanSeq) noexcept;
|
||||
loan(uint256 const& loanBrokerID, SeqProxy const& loanSeq) noexcept;
|
||||
|
||||
inline Keylet
|
||||
loan(uint256 const& key)
|
||||
@@ -389,7 +382,7 @@ loan(uint256 const& key)
|
||||
}
|
||||
|
||||
Keylet
|
||||
permissionedDomain(AccountID const& account, std::uint32_t seq) noexcept;
|
||||
permissionedDomain(AccountID const& account, SeqProxy const& seq) noexcept;
|
||||
|
||||
Keylet
|
||||
permissionedDomain(uint256 const& domainID) noexcept;
|
||||
@@ -407,12 +400,6 @@ getQualityNext(uint256 const& uBase);
|
||||
std::uint64_t
|
||||
getQuality(uint256 const& uBase);
|
||||
|
||||
uint256
|
||||
getTicketIndex(AccountID const& account, std::uint32_t uSequence);
|
||||
|
||||
uint256
|
||||
getTicketIndex(AccountID const& account, SeqProxy ticketSeq);
|
||||
|
||||
template <class... KeyletParams>
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
|
||||
struct KeyletDesc
|
||||
@@ -426,6 +413,6 @@ struct KeyletDesc
|
||||
extern std::array<KeyletDesc<AccountID const&>, 6> const kDirectAccountKeylets;
|
||||
|
||||
MPTID
|
||||
makeMptID(std::uint32_t sequence, AccountID const& account);
|
||||
makeMptID(std::uint32_t const sequence, AccountID const& account);
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -190,17 +190,6 @@ enum LedgerEntryType : std::uint16_t {
|
||||
LSF_FLAG(lsfMPTCanClawback, 0x00000040) \
|
||||
LSF_FLAG(lsfMPTCanHoldConfidentialBalance, 0x00000080)) \
|
||||
\
|
||||
LEDGER_OBJECT(MPTokenIssuanceMutable, \
|
||||
LSF_FLAG(lsmfMPTCanEnableCanLock, 0x00000002) \
|
||||
LSF_FLAG(lsmfMPTCanEnableRequireAuth, 0x00000004) \
|
||||
LSF_FLAG(lsmfMPTCanEnableCanEscrow, 0x00000008) \
|
||||
LSF_FLAG(lsmfMPTCanEnableCanTrade, 0x00000010) \
|
||||
LSF_FLAG(lsmfMPTCanEnableCanTransfer, 0x00000020) \
|
||||
LSF_FLAG(lsmfMPTCanEnableCanClawback, 0x00000040) \
|
||||
LSF_FLAG(lsmfMPTCannotEnableCanHoldConfidentialBalance, 0x00000080) \
|
||||
LSF_FLAG(lsmfMPTCanMutateMetadata, 0x00010000) \
|
||||
LSF_FLAG(lsmfMPTCanMutateTransferFee, 0x00020000)) \
|
||||
\
|
||||
LEDGER_OBJECT(MPToken, \
|
||||
LSF_FLAG2(lsfMPTLocked, 0x00000001) \
|
||||
LSF_FLAG(lsfMPTAuthorized, 0x00000002) \
|
||||
@@ -294,6 +283,17 @@ getAllLedgerFlags()
|
||||
#pragma pop_macro("TO_MAP")
|
||||
#pragma pop_macro("ALL_LEDGER_FLAGS")
|
||||
|
||||
// MPTokenIssuance ImmutableFlags (sfImmutableFlags)
|
||||
inline constexpr std::uint32_t lsifMPTCanLock = 0x00000002;
|
||||
inline constexpr std::uint32_t lsifMPTRequireAuth = 0x00000004;
|
||||
inline constexpr std::uint32_t lsifMPTCanEscrow = 0x00000008;
|
||||
inline constexpr std::uint32_t lsifMPTCanTrade = 0x00000010;
|
||||
inline constexpr std::uint32_t lsifMPTCanTransfer = 0x00000020;
|
||||
inline constexpr std::uint32_t lsifMPTCanClawback = 0x00000040;
|
||||
inline constexpr std::uint32_t lsifMPTCanHoldConfidentialBalance = 0x00000080;
|
||||
inline constexpr std::uint32_t lsifMPTMetadata = 0x00010000;
|
||||
inline constexpr std::uint32_t lsifMPTTransferFee = 0x00020000;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
|
||||
@@ -188,6 +188,6 @@ struct MultiApiJson
|
||||
|
||||
// Wrapper for Json for all supported API versions.
|
||||
using MultiApiJson =
|
||||
detail::MultiApiJson<RPC::kApiMinimumSupportedVersion, RPC::kApiMaximumValidVersion>;
|
||||
detail::MultiApiJson<rpc::kApiMinimumSupportedVersion, rpc::kApiMaximumValidVersion>;
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace xrpl::RPC {
|
||||
namespace xrpl::rpc {
|
||||
|
||||
/**
|
||||
* Adds common synthetic fields to transaction-related JSON responses
|
||||
@@ -16,4 +16,4 @@ void
|
||||
insertNFTSyntheticInJson(json::Value&, std::shared_ptr<STTx const> const&, TxMeta const&);
|
||||
/** @} */
|
||||
|
||||
} // namespace xrpl::RPC
|
||||
} // namespace xrpl::rpc
|
||||
|
||||
@@ -139,7 +139,7 @@ tenthBipsOfValue(T value, TenthBips<TBips> bips)
|
||||
return value * bips.value() / kTenthBipsPerUnity.value();
|
||||
}
|
||||
|
||||
namespace Lending {
|
||||
namespace lending {
|
||||
/**
|
||||
* The maximum management fee rate allowed by a loan broker in 1/10 bips.
|
||||
*
|
||||
@@ -236,7 +236,7 @@ static constexpr int kLoanPaymentsPerFeeIncrement = 5;
|
||||
* without an amendment
|
||||
*/
|
||||
static constexpr int kLoanMaximumPaymentsPerTransaction = 100;
|
||||
} // namespace Lending
|
||||
} // namespace lending
|
||||
|
||||
/**
|
||||
* The maximum length of a URI inside an NFT
|
||||
|
||||
@@ -260,7 +260,7 @@ calcAccountID(PublicKey const& pk);
|
||||
|
||||
inline std::string
|
||||
getFingerprint(
|
||||
beast::IP::Endpoint const& address,
|
||||
beast::ip::Endpoint const& address,
|
||||
std::optional<PublicKey> const& publicKey = std::nullopt,
|
||||
std::optional<std::string> const& id = std::nullopt)
|
||||
{
|
||||
|
||||
@@ -90,7 +90,11 @@ public:
|
||||
operator=(STObject&& other);
|
||||
|
||||
STObject(SOTemplate const& type, SField const& name);
|
||||
STObject(SOTemplate const& type, SerialIter& sit, SField const& name);
|
||||
STObject(
|
||||
SOTemplate const& type,
|
||||
SerialIter& sit,
|
||||
SField const& name,
|
||||
bool requireCanonicalOrder = false);
|
||||
STObject(SerialIter& sit, SField const& name, int depth = 0);
|
||||
STObject(SerialIter&& sit, SField const& name);
|
||||
explicit STObject(SField const& name);
|
||||
@@ -123,7 +127,7 @@ public:
|
||||
set(SOTemplate const&);
|
||||
|
||||
bool
|
||||
set(SerialIter& u, int depth = 0);
|
||||
set(SerialIter& u, int depth = 0, bool requireCanonicalOrder = false);
|
||||
|
||||
[[nodiscard]] SerializedTypeID
|
||||
getSType() const override;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/basics/CountedObject.h>
|
||||
#include <xrpl/basics/UnorderedContainers.h>
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
@@ -108,6 +109,9 @@ public:
|
||||
[[nodiscard]] bool
|
||||
isType(Type const& pe) const;
|
||||
|
||||
[[nodiscard]] size_t
|
||||
getHash() const;
|
||||
|
||||
bool
|
||||
operator==(STPathElement const& t) const;
|
||||
|
||||
@@ -171,12 +175,23 @@ public:
|
||||
reserve(size_t s);
|
||||
};
|
||||
|
||||
template <class Hasher>
|
||||
void
|
||||
hash_append(Hasher& h, STPath const& p) noexcept
|
||||
{
|
||||
for (auto const& e : p)
|
||||
{
|
||||
beast::hash_append(h, e.getHash());
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// A set of zero or more payment paths
|
||||
class STPathSet final : public STBase, public CountedObject<STPathSet>
|
||||
{
|
||||
std::vector<STPath> value_;
|
||||
xrpl::hardened_hash_set<STPath> seenHashes_;
|
||||
|
||||
public:
|
||||
STPathSet() = default;
|
||||
@@ -205,9 +220,6 @@ public:
|
||||
std::vector<STPath>::const_reference
|
||||
operator[](std::vector<STPath>::size_type n) const;
|
||||
|
||||
std::vector<STPath>::reference
|
||||
operator[](std::vector<STPath>::size_type n);
|
||||
|
||||
[[nodiscard]] std::vector<STPath>::const_iterator
|
||||
begin() const;
|
||||
|
||||
@@ -227,6 +239,9 @@ public:
|
||||
void
|
||||
emplaceBack(Args&&... args);
|
||||
|
||||
[[nodiscard]] bool
|
||||
contains(STPath const& path) const;
|
||||
|
||||
private:
|
||||
STBase*
|
||||
copy(std::size_t n, void* buf) const override;
|
||||
@@ -515,12 +530,6 @@ STPathSet::operator[](std::vector<STPath>::size_type n) const
|
||||
return value_[n];
|
||||
}
|
||||
|
||||
inline std::vector<STPath>::reference
|
||||
STPathSet::operator[](std::vector<STPath>::size_type n)
|
||||
{
|
||||
return value_[n];
|
||||
}
|
||||
|
||||
inline std::vector<STPath>::const_iterator
|
||||
STPathSet::begin() const
|
||||
{
|
||||
@@ -549,6 +558,7 @@ inline void
|
||||
STPathSet::pushBack(STPath const& e)
|
||||
{
|
||||
value_.push_back(e);
|
||||
seenHashes_.emplace(value_.back());
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
@@ -556,6 +566,13 @@ inline void
|
||||
STPathSet::emplaceBack(Args&&... args)
|
||||
{
|
||||
value_.emplace_back(std::forward<Args>(args)...);
|
||||
seenHashes_.emplace(value_.back());
|
||||
}
|
||||
|
||||
inline bool
|
||||
STPathSet::contains(STPath const& path) const
|
||||
{
|
||||
return seenHashes_.contains(path);
|
||||
}
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -93,12 +93,6 @@ public:
|
||||
[[nodiscard]] SeqProxy
|
||||
getSeqProxy() const;
|
||||
|
||||
/**
|
||||
* Returns the first non-zero value of (Sequence, TicketSequence).
|
||||
*/
|
||||
[[nodiscard]] std::uint32_t
|
||||
getSeqValue() const;
|
||||
|
||||
[[nodiscard]] boost::container::flat_set<AccountID>
|
||||
getMentionedAccounts() const;
|
||||
|
||||
|
||||
@@ -54,6 +54,22 @@ class STValidation final : public STObject, public CountedObject<STValidation>
|
||||
NetClock::time_point seenTime_;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @struct DeserializeOptions
|
||||
* @brief Options controlling deserialization of a STValidation.
|
||||
|
||||
* @var DeserializeOptions::checkSignature
|
||||
* Whether to verify the data was signed properly
|
||||
*
|
||||
* @var DeserializeOptions::requireCanonicalOrder
|
||||
* Whether to require the fields to be in canonical order
|
||||
*/
|
||||
struct DeserializeOptions
|
||||
{
|
||||
bool checkSignature;
|
||||
bool requireCanonicalOrder;
|
||||
};
|
||||
|
||||
/**
|
||||
* Construct a STValidation from a peer from serialized data.
|
||||
*
|
||||
@@ -64,12 +80,12 @@ public:
|
||||
* that signed the validation. For manifest based
|
||||
* validators, this should be the NodeID of the master
|
||||
* public key.
|
||||
* @param checkSignature Whether to verify the data was signed properly
|
||||
* @param options Options controlling deserialization
|
||||
*
|
||||
* @note Throws if the object is not valid
|
||||
*/
|
||||
template <class LookupNodeID>
|
||||
STValidation(SerialIter& sit, LookupNodeID&& lookupNodeID, bool checkSignature);
|
||||
STValidation(SerialIter& sit, LookupNodeID&& lookupNodeID, DeserializeOptions options);
|
||||
|
||||
/**
|
||||
* Construct, sign and trust a new STValidation issued by this node.
|
||||
@@ -163,8 +179,8 @@ private:
|
||||
};
|
||||
|
||||
template <class LookupNodeID>
|
||||
STValidation::STValidation(SerialIter& sit, LookupNodeID&& lookupNodeID, bool checkSignature)
|
||||
: STObject(validationFormat(), sit, sfValidation)
|
||||
STValidation::STValidation(SerialIter& sit, LookupNodeID&& lookupNodeID, DeserializeOptions options)
|
||||
: STObject(validationFormat(), sit, sfValidation, options.requireCanonicalOrder)
|
||||
, signingPubKey_([this]() {
|
||||
auto const spk = getFieldVL(sfSigningPubKey);
|
||||
|
||||
@@ -175,7 +191,7 @@ STValidation::STValidation(SerialIter& sit, LookupNodeID&& lookupNodeID, bool ch
|
||||
}())
|
||||
, nodeID_(lookupNodeID(signingPubKey_))
|
||||
{
|
||||
if (checkSignature && !isValid())
|
||||
if (options.checkSignature && !isValid())
|
||||
{
|
||||
JLOG(debugLog().error()) << "Invalid signature in validation: "
|
||||
<< getJson(JsonOptions::Values::None);
|
||||
|
||||
@@ -53,14 +53,29 @@ public:
|
||||
operator=(SeqProxy const& other) = default;
|
||||
|
||||
/**
|
||||
* Factory function to return a sequence-based SeqProxy
|
||||
* Factory function to return a sequence-based SeqProxy.
|
||||
* Outside of tests, this function should only be used for "secondary" transaction sequences,
|
||||
* e.g. `sfOfferSequence`, or sequence fields in an existing ledger object. DO NOT use this for
|
||||
* the "primary" sequence of a transaction, `sfSequence`.
|
||||
*/
|
||||
static constexpr SeqProxy
|
||||
sequence(std::uint32_t v)
|
||||
rawSequence(std::uint32_t v)
|
||||
{
|
||||
return SeqProxy{Type::Seq, v};
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory function to return a ticket-based SeqProxy.
|
||||
* Outside of tests, this function should only be used for "secondary" transaction sequences,
|
||||
* e.g. `sfOfferSequence`, or sequence fields in an existing ledger object. DO NOT use this for
|
||||
* the "primary" ticket sequence of a transaction, `sfTicketSequence`.
|
||||
*/
|
||||
static constexpr SeqProxy
|
||||
rawTicket(std::uint32_t v)
|
||||
{
|
||||
return SeqProxy{Type::Ticket, v};
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr std::uint32_t
|
||||
value() const
|
||||
{
|
||||
|
||||
@@ -152,7 +152,14 @@ inline constexpr FlagValue tfUniversalMask = ~tfUniversal;
|
||||
\
|
||||
TRANSACTION(MPTokenIssuanceSet, \
|
||||
TF_FLAG(tfMPTLock, 0x00000001) \
|
||||
TF_FLAG(tfMPTUnlock, 0x00000002), \
|
||||
TF_FLAG(tfMPTUnlock, 0x00000002) \
|
||||
TF_FLAG(tfMPTSetCanLock, 0x00000004) \
|
||||
TF_FLAG(tfMPTSetRequireAuth, 0x00000008) \
|
||||
TF_FLAG(tfMPTSetCanEscrow, 0x00000010) \
|
||||
TF_FLAG(tfMPTSetCanTrade, 0x00000020) \
|
||||
TF_FLAG(tfMPTSetCanTransfer, 0x00000040) \
|
||||
TF_FLAG(tfMPTSetCanClawback, 0x00000080) \
|
||||
TF_FLAG(tfMPTSetCanHoldConfidentialBalance, 0x00000100), \
|
||||
MASK_ADJ(0)) \
|
||||
\
|
||||
TRANSACTION(NFTokenCreateOffer, \
|
||||
@@ -356,38 +363,26 @@ inline constexpr FlagValue tfMPTPaymentMask = ~(tfUniversal | tfPartialPayment);
|
||||
inline constexpr FlagValue tfTrustSetPermissionMask =
|
||||
~(tfUniversal | tfSetfAuth | tfSetFreeze | tfClearFreeze);
|
||||
|
||||
// MPTokenIssuanceCreate MutableFlags:
|
||||
// Indicating specific fields or flags may be changed after issuance.
|
||||
inline constexpr FlagValue tmfMPTCanEnableCanLock = lsmfMPTCanEnableCanLock;
|
||||
inline constexpr FlagValue tmfMPTCanEnableRequireAuth = lsmfMPTCanEnableRequireAuth;
|
||||
inline constexpr FlagValue tmfMPTCanEnableCanEscrow = lsmfMPTCanEnableCanEscrow;
|
||||
inline constexpr FlagValue tmfMPTCanEnableCanTrade = lsmfMPTCanEnableCanTrade;
|
||||
inline constexpr FlagValue tmfMPTCanEnableCanTransfer = lsmfMPTCanEnableCanTransfer;
|
||||
inline constexpr FlagValue tmfMPTCanEnableCanClawback = lsmfMPTCanEnableCanClawback;
|
||||
inline constexpr FlagValue tmfMPTCanMutateMetadata = lsmfMPTCanMutateMetadata;
|
||||
inline constexpr FlagValue tmfMPTCanMutateTransferFee = lsmfMPTCanMutateTransferFee;
|
||||
inline constexpr FlagValue tmfMPTCannotEnableCanHoldConfidentialBalance =
|
||||
lsmfMPTCannotEnableCanHoldConfidentialBalance;
|
||||
inline constexpr FlagValue tmfMPTokenIssuanceCreateMutableMask =
|
||||
~(tmfMPTCanEnableCanLock | tmfMPTCanEnableRequireAuth | tmfMPTCanEnableCanEscrow |
|
||||
tmfMPTCanEnableCanTrade | tmfMPTCanEnableCanTransfer | tmfMPTCanEnableCanClawback |
|
||||
tmfMPTCanMutateMetadata | tmfMPTCanMutateTransferFee |
|
||||
tmfMPTCannotEnableCanHoldConfidentialBalance);
|
||||
// MPTokenIssuanceCreate / MPTokenIssuanceSet ImmutableFlags:
|
||||
// Defines the immutable fields and flags specific to MPTokenIssuance.
|
||||
inline constexpr FlagValue tifMPTCanLock = lsifMPTCanLock;
|
||||
inline constexpr FlagValue tifMPTRequireAuth = lsifMPTRequireAuth;
|
||||
inline constexpr FlagValue tifMPTCanEscrow = lsifMPTCanEscrow;
|
||||
inline constexpr FlagValue tifMPTCanTrade = lsifMPTCanTrade;
|
||||
inline constexpr FlagValue tifMPTCanTransfer = lsifMPTCanTransfer;
|
||||
inline constexpr FlagValue tifMPTCanClawback = lsifMPTCanClawback;
|
||||
inline constexpr FlagValue tifMPTMetadata = lsifMPTMetadata;
|
||||
inline constexpr FlagValue tifMPTTransferFee = lsifMPTTransferFee;
|
||||
inline constexpr FlagValue tifMPTCanHoldConfidentialBalance = lsifMPTCanHoldConfidentialBalance;
|
||||
inline constexpr FlagValue tifMPTokenIssuanceImmutableMask =
|
||||
~(tifMPTCanLock | tifMPTRequireAuth | tifMPTCanEscrow | tifMPTCanTrade | tifMPTCanTransfer |
|
||||
tifMPTCanClawback | tifMPTMetadata | tifMPTTransferFee | tifMPTCanHoldConfidentialBalance);
|
||||
|
||||
// MPTokenIssuanceSet MutableFlags:
|
||||
// Enable mutable capability flags. These flags are one-way: once enabled,
|
||||
// the corresponding capability cannot be disabled by MPTokenIssuanceSet.
|
||||
|
||||
inline constexpr FlagValue tmfMPTSetCanLock = 0x00000001;
|
||||
inline constexpr FlagValue tmfMPTSetRequireAuth = 0x00000002;
|
||||
inline constexpr FlagValue tmfMPTSetCanEscrow = 0x00000004;
|
||||
inline constexpr FlagValue tmfMPTSetCanTrade = 0x00000008;
|
||||
inline constexpr FlagValue tmfMPTSetCanTransfer = 0x00000010;
|
||||
inline constexpr FlagValue tmfMPTSetCanClawback = 0x00000020;
|
||||
inline constexpr FlagValue tmfMPTSetCanHoldConfidentialBalance = 0x00000040;
|
||||
inline constexpr FlagValue tmfMPTokenIssuanceSetMutableMask =
|
||||
~(tmfMPTSetCanLock | tmfMPTSetRequireAuth | tmfMPTSetCanEscrow | tmfMPTSetCanTrade |
|
||||
tmfMPTSetCanTransfer | tmfMPTSetCanClawback | tmfMPTSetCanHoldConfidentialBalance);
|
||||
// MPTokenIssuanceSet set of flags that is used to enable capabilities on an MPTokenIssuance.
|
||||
// Used as `txFlags & tfMPTokenIssuanceSetEnableFlagMask` to extract the capability-enabling bits.
|
||||
inline constexpr FlagValue tfMPTokenIssuanceSetEnableFlagMask = tfMPTSetCanLock |
|
||||
tfMPTSetRequireAuth | tfMPTSetCanEscrow | tfMPTSetCanTrade | tfMPTSetCanTransfer |
|
||||
tfMPTSetCanClawback | tfMPTSetCanHoldConfidentialBalance;
|
||||
|
||||
// Prior to fixRemoveNFTokenAutoTrustLine, transfer of an NFToken between accounts allowed a
|
||||
// TrustLine to be added to the issuer of that token without explicit permission from that issuer.
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
namespace Attestations {
|
||||
namespace attestations {
|
||||
|
||||
struct AttestationBase
|
||||
{
|
||||
@@ -227,7 +227,7 @@ struct CmpByCreateCount
|
||||
}
|
||||
};
|
||||
|
||||
}; // namespace Attestations
|
||||
}; // namespace attestations
|
||||
|
||||
// Result when checking when two attestation match.
|
||||
enum class AttestationMatch {
|
||||
@@ -241,7 +241,7 @@ enum class AttestationMatch {
|
||||
|
||||
struct XChainClaimAttestation
|
||||
{
|
||||
using TSignedAttestation = Attestations::AttestationClaim;
|
||||
using TSignedAttestation = attestations::AttestationClaim;
|
||||
static SField const& arrayFieldName;
|
||||
|
||||
AccountID keyAccount;
|
||||
@@ -297,7 +297,7 @@ struct XChainClaimAttestation
|
||||
|
||||
struct XChainCreateAccountAttestation
|
||||
{
|
||||
using TSignedAttestation = Attestations::AttestationCreateAccount;
|
||||
using TSignedAttestation = attestations::AttestationCreateAccount;
|
||||
static SField const& arrayFieldName;
|
||||
|
||||
AccountID keyAccount;
|
||||
|
||||
@@ -59,7 +59,6 @@ XRPL_FIX (PreviousTxnID, Supported::Yes, VoteBehavior::DefaultNo
|
||||
XRPL_FIX (XChainRewardRounding, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (EmptyDID, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(PriceOracle, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (AMMOverflowOffer, Supported::Yes, VoteBehavior::DefaultYes)
|
||||
XRPL_FIX (FillOrKill, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(DID, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(XChainBridge, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
@@ -100,6 +99,7 @@ XRPL_RETIRE_FIX(1578)
|
||||
XRPL_RETIRE_FIX(1623)
|
||||
XRPL_RETIRE_FIX(1781)
|
||||
XRPL_RETIRE_FIX(AmendmentMajorityCalc)
|
||||
XRPL_RETIRE_FIX(AMMOverflowOffer)
|
||||
XRPL_RETIRE_FIX(CheckThreading)
|
||||
XRPL_RETIRE_FIX(DisallowIncomingV1)
|
||||
XRPL_RETIRE_FIX(InnerObjTemplate)
|
||||
|
||||
@@ -404,7 +404,7 @@ LEDGER_ENTRY(ltMPTOKEN_ISSUANCE, 0x007e, MPTokenIssuance, mpt_issuance, ({
|
||||
{sfPreviousTxnID, SoeRequired},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired},
|
||||
{sfDomainID, SoeOptional},
|
||||
{sfMutableFlags, SoeDefault},
|
||||
{sfImmutableFlags, SoeDefault},
|
||||
{sfReferenceHolding, SoeOptional},
|
||||
{sfIssuerEncryptionKey, SoeOptional},
|
||||
{sfAuditorEncryptionKey, SoeOptional},
|
||||
|
||||
@@ -98,7 +98,7 @@ TYPED_SFIELD(sfVoteWeight, UINT32, 48)
|
||||
TYPED_SFIELD(sfFirstNFTokenSequence, UINT32, 50)
|
||||
TYPED_SFIELD(sfOracleDocumentID, UINT32, 51)
|
||||
TYPED_SFIELD(sfPermissionValue, UINT32, 52)
|
||||
TYPED_SFIELD(sfMutableFlags, UINT32, 53)
|
||||
TYPED_SFIELD(sfImmutableFlags, UINT32, 53)
|
||||
TYPED_SFIELD(sfStartDate, UINT32, 54)
|
||||
TYPED_SFIELD(sfPaymentInterval, UINT32, 55)
|
||||
TYPED_SFIELD(sfGracePeriod, UINT32, 56)
|
||||
@@ -239,6 +239,7 @@ TYPED_SFIELD(sfManagementFeeOutstanding, NUMBER, 17, SField::kSmdNeedsAsset
|
||||
|
||||
// int32
|
||||
TYPED_SFIELD(sfLoanScale, INT32, 1)
|
||||
TYPED_SFIELD(sfRemainingOwnerCountDelta, INT32, 2)
|
||||
|
||||
// currency amount (common)
|
||||
TYPED_SFIELD(sfAmount, AMOUNT, 1)
|
||||
@@ -278,6 +279,7 @@ TYPED_SFIELD(sfMinAccountCreateAmount, AMOUNT, 30)
|
||||
TYPED_SFIELD(sfLPTokenBalance, AMOUNT, 31)
|
||||
TYPED_SFIELD(sfFeeAmount, AMOUNT, 32)
|
||||
TYPED_SFIELD(sfMaxFee, AMOUNT, 33)
|
||||
TYPED_SFIELD(sfFeeAmountDelta, AMOUNT, 34)
|
||||
|
||||
// variable length (common)
|
||||
TYPED_SFIELD(sfPublicKey, VL, 1)
|
||||
|
||||
@@ -705,7 +705,7 @@ TRANSACTION(ttMPTOKEN_ISSUANCE_CREATE, 54, MPTokenIssuanceCreate,
|
||||
{sfMaximumAmount, SoeOptional},
|
||||
{sfMPTokenMetadata, SoeOptional},
|
||||
{sfDomainID, SoeOptional},
|
||||
{sfMutableFlags, SoeOptional},
|
||||
{sfImmutableFlags, SoeOptional},
|
||||
}))
|
||||
|
||||
/** This transaction type destroys a MPTokensIssuance instance */
|
||||
@@ -734,7 +734,7 @@ TRANSACTION(ttMPTOKEN_ISSUANCE_SET, 56, MPTokenIssuanceSet,
|
||||
{sfDomainID, SoeOptional},
|
||||
{sfMPTokenMetadata, SoeOptional},
|
||||
{sfTransferFee, SoeOptional},
|
||||
{sfMutableFlags, SoeOptional},
|
||||
{sfImmutableFlags, SoeOptional},
|
||||
{sfIssuerEncryptionKey, SoeOptional},
|
||||
{sfAuditorEncryptionKey, SoeOptional},
|
||||
}))
|
||||
@@ -1085,7 +1085,7 @@ TRANSACTION(ttLOAN_PAY, 84, LoanPay,
|
||||
# include <xrpl/tx/transactors/token/ConfidentialMPTConvert.h>
|
||||
#endif
|
||||
TRANSACTION(ttCONFIDENTIAL_MPT_CONVERT, 85, ConfidentialMPTConvert,
|
||||
Delegation::Delegable,
|
||||
Delegation::NotDelegable,
|
||||
featureConfidentialTransfer,
|
||||
NoPriv,
|
||||
({
|
||||
@@ -1189,9 +1189,9 @@ TRANSACTION(ttSPONSORSHIP_SET, 91, SponsorshipSet,
|
||||
({
|
||||
{sfCounterpartySponsor, SoeOptional},
|
||||
{sfSponsee, SoeOptional},
|
||||
{sfFeeAmount, SoeOptional},
|
||||
{sfFeeAmountDelta, SoeOptional},
|
||||
{sfMaxFee, SoeOptional},
|
||||
{sfRemainingOwnerCount, SoeOptional},
|
||||
{sfRemainingOwnerCountDelta, SoeOptional},
|
||||
}))
|
||||
|
||||
/** This system-generated transaction type is used to update the status of the various amendments.
|
||||
|
||||
@@ -23,6 +23,16 @@ By default, `CODEGEN_VENV_DIR` points to `.venv` in the project root. The
|
||||
`setup_code_gen` target creates a venv there and installs the required packages.
|
||||
The `code_gen` target then uses the venv's Python interpreter to run generation.
|
||||
|
||||
Generation is pure Python, so the same targets are also available as a
|
||||
standalone project that needs neither the dependencies nor a compiler. This is
|
||||
what CI uses, and it is handy if you only want to regenerate these files:
|
||||
|
||||
```bash
|
||||
cmake -S cmake/codegen -B build/codegen
|
||||
cmake --build build/codegen --target setup_code_gen
|
||||
cmake --build build/codegen --target code_gen
|
||||
```
|
||||
|
||||
### Python Dependencies
|
||||
|
||||
The code generation requires the following Python packages (installed by `setup_code_gen`):
|
||||
|
||||
@@ -256,27 +256,27 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfMutableFlags (SoeDefault)
|
||||
* @brief Get sfImmutableFlags (SoeDefault)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_UINT32::type::value_type>
|
||||
getMutableFlags() const
|
||||
getImmutableFlags() const
|
||||
{
|
||||
if (hasMutableFlags())
|
||||
return this->sle_->at(sfMutableFlags);
|
||||
if (hasImmutableFlags())
|
||||
return this->sle_->at(sfImmutableFlags);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfMutableFlags is present.
|
||||
* @brief Check if sfImmutableFlags is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasMutableFlags() const
|
||||
hasImmutableFlags() const
|
||||
{
|
||||
return this->sle_->isFieldPresent(sfMutableFlags);
|
||||
return this->sle_->isFieldPresent(sfImmutableFlags);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -557,13 +557,13 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfMutableFlags (SoeDefault)
|
||||
* @brief Set sfImmutableFlags (SoeDefault)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
MPTokenIssuanceBuilder&
|
||||
setMutableFlags(std::decay_t<typename SF_UINT32::type::value_type> const& value)
|
||||
setImmutableFlags(std::decay_t<typename SF_UINT32::type::value_type> const& value)
|
||||
{
|
||||
object_[sfMutableFlags] = value;
|
||||
object_[sfImmutableFlags] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ class ConfidentialMPTConvertBuilder;
|
||||
* @brief Transaction: ConfidentialMPTConvert
|
||||
*
|
||||
* Type: ttCONFIDENTIAL_MPT_CONVERT (85)
|
||||
* Delegable: Delegation::Delegable
|
||||
* Delegable: Delegation::NotDelegable
|
||||
* Amendment: featureConfidentialTransfer
|
||||
* Privileges: NoPriv
|
||||
*
|
||||
|
||||
@@ -178,29 +178,29 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfMutableFlags (SoeOptional)
|
||||
* @brief Get sfImmutableFlags (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_UINT32::type::value_type>
|
||||
getMutableFlags() const
|
||||
getImmutableFlags() const
|
||||
{
|
||||
if (hasMutableFlags())
|
||||
if (hasImmutableFlags())
|
||||
{
|
||||
return this->tx_->at(sfMutableFlags);
|
||||
return this->tx_->at(sfImmutableFlags);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfMutableFlags is present.
|
||||
* @brief Check if sfImmutableFlags is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasMutableFlags() const
|
||||
hasImmutableFlags() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfMutableFlags);
|
||||
return this->tx_->isFieldPresent(sfImmutableFlags);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -302,13 +302,13 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfMutableFlags (SoeOptional)
|
||||
* @brief Set sfImmutableFlags (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
MPTokenIssuanceCreateBuilder&
|
||||
setMutableFlags(std::decay_t<typename SF_UINT32::type::value_type> const& value)
|
||||
setImmutableFlags(std::decay_t<typename SF_UINT32::type::value_type> const& value)
|
||||
{
|
||||
object_[sfMutableFlags] = value;
|
||||
object_[sfImmutableFlags] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
@@ -163,29 +163,29 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfMutableFlags (SoeOptional)
|
||||
* @brief Get sfImmutableFlags (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_UINT32::type::value_type>
|
||||
getMutableFlags() const
|
||||
getImmutableFlags() const
|
||||
{
|
||||
if (hasMutableFlags())
|
||||
if (hasImmutableFlags())
|
||||
{
|
||||
return this->tx_->at(sfMutableFlags);
|
||||
return this->tx_->at(sfImmutableFlags);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfMutableFlags is present.
|
||||
* @brief Check if sfImmutableFlags is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasMutableFlags() const
|
||||
hasImmutableFlags() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfMutableFlags);
|
||||
return this->tx_->isFieldPresent(sfImmutableFlags);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -341,13 +341,13 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfMutableFlags (SoeOptional)
|
||||
* @brief Set sfImmutableFlags (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
MPTokenIssuanceSetBuilder&
|
||||
setMutableFlags(std::decay_t<typename SF_UINT32::type::value_type> const& value)
|
||||
setImmutableFlags(std::decay_t<typename SF_UINT32::type::value_type> const& value)
|
||||
{
|
||||
object_[sfMutableFlags] = value;
|
||||
object_[sfImmutableFlags] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
@@ -100,29 +100,29 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfFeeAmount (SoeOptional)
|
||||
* @brief Get sfFeeAmountDelta (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_AMOUNT::type::value_type>
|
||||
getFeeAmount() const
|
||||
getFeeAmountDelta() const
|
||||
{
|
||||
if (hasFeeAmount())
|
||||
if (hasFeeAmountDelta())
|
||||
{
|
||||
return this->tx_->at(sfFeeAmount);
|
||||
return this->tx_->at(sfFeeAmountDelta);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfFeeAmount is present.
|
||||
* @brief Check if sfFeeAmountDelta is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasFeeAmount() const
|
||||
hasFeeAmountDelta() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfFeeAmount);
|
||||
return this->tx_->isFieldPresent(sfFeeAmountDelta);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -152,29 +152,29 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfRemainingOwnerCount (SoeOptional)
|
||||
* @brief Get sfRemainingOwnerCountDelta (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_UINT32::type::value_type>
|
||||
getRemainingOwnerCount() const
|
||||
protocol_autogen::Optional<SF_INT32::type::value_type>
|
||||
getRemainingOwnerCountDelta() const
|
||||
{
|
||||
if (hasRemainingOwnerCount())
|
||||
if (hasRemainingOwnerCountDelta())
|
||||
{
|
||||
return this->tx_->at(sfRemainingOwnerCount);
|
||||
return this->tx_->at(sfRemainingOwnerCountDelta);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfRemainingOwnerCount is present.
|
||||
* @brief Check if sfRemainingOwnerCountDelta is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasRemainingOwnerCount() const
|
||||
hasRemainingOwnerCountDelta() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfRemainingOwnerCount);
|
||||
return this->tx_->isFieldPresent(sfRemainingOwnerCountDelta);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -243,13 +243,13 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfFeeAmount (SoeOptional)
|
||||
* @brief Set sfFeeAmountDelta (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
SponsorshipSetBuilder&
|
||||
setFeeAmount(std::decay_t<typename SF_AMOUNT::type::value_type> const& value)
|
||||
setFeeAmountDelta(std::decay_t<typename SF_AMOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfFeeAmount] = value;
|
||||
object_[sfFeeAmountDelta] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -265,13 +265,13 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfRemainingOwnerCount (SoeOptional)
|
||||
* @brief Set sfRemainingOwnerCountDelta (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
SponsorshipSetBuilder&
|
||||
setRemainingOwnerCount(std::decay_t<typename SF_UINT32::type::value_type> const& value)
|
||||
setRemainingOwnerCountDelta(std::decay_t<typename SF_INT32::type::value_type> const& value)
|
||||
{
|
||||
object_[sfRemainingOwnerCount] = value;
|
||||
object_[sfRemainingOwnerCountDelta] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
|
||||
namespace xrpl::Resource {
|
||||
namespace xrpl::resource {
|
||||
|
||||
/**
|
||||
* A consumption charge.
|
||||
@@ -32,7 +32,7 @@ public:
|
||||
label() const;
|
||||
|
||||
/**
|
||||
* Return the cost of the charge in Resource::Manager units.
|
||||
* Return the cost of the charge in resource::Manager units.
|
||||
*/
|
||||
[[nodiscard]] value_type
|
||||
cost() const;
|
||||
@@ -60,4 +60,4 @@ private:
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, Charge const& v);
|
||||
|
||||
} // namespace xrpl::Resource
|
||||
} // namespace xrpl::resource
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
|
||||
namespace xrpl::Resource {
|
||||
namespace xrpl::resource {
|
||||
|
||||
struct Entry;
|
||||
class Logic;
|
||||
@@ -96,4 +96,4 @@ private:
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, Consumer const& v);
|
||||
|
||||
} // namespace xrpl::Resource
|
||||
} // namespace xrpl::resource
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
namespace xrpl::Resource {
|
||||
namespace xrpl::resource {
|
||||
|
||||
/**
|
||||
* The disposition of a consumer after applying a load charge.
|
||||
@@ -24,4 +24,4 @@ enum class Disposition {
|
||||
Drop
|
||||
};
|
||||
|
||||
} // namespace xrpl::Resource
|
||||
} // namespace xrpl::resource
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include <xrpl/resource/Charge.h>
|
||||
|
||||
namespace xrpl::Resource {
|
||||
namespace xrpl::resource {
|
||||
|
||||
/**
|
||||
* Schedule of fees charged for imposing load on the server.
|
||||
@@ -13,6 +13,7 @@ extern Charge const kFeeRequestNoReply; // A request that we cannot satisfy.
|
||||
extern Charge const kFeeInvalidSignature; // An object whose signature we had to check that failed.
|
||||
extern Charge const kFeeUselessData; // Data we have no use for.
|
||||
extern Charge const kFeeInvalidData; // Data we have to verify before rejecting.
|
||||
extern Charge const kFeeMalformedData; // Data that no honest peer would send.
|
||||
|
||||
// RPC loads
|
||||
extern Charge const kFeeMalformedRpc; // An RPC request that we can immediately tell is invalid.
|
||||
@@ -31,4 +32,4 @@ extern Charge const kFeeWarning; // The cost of receiving a warning.
|
||||
extern Charge const kFeeDrop; // The cost of being dropped for excess load.
|
||||
/** @} */
|
||||
|
||||
} // namespace xrpl::Resource
|
||||
} // namespace xrpl::resource
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace xrpl::Resource {
|
||||
namespace xrpl::resource {
|
||||
|
||||
/**
|
||||
* Data format for exchanging consumption information across peers.
|
||||
@@ -21,10 +21,10 @@ struct Gossip
|
||||
explicit Item() = default;
|
||||
|
||||
int balance{};
|
||||
beast::IP::Endpoint address;
|
||||
beast::ip::Endpoint address;
|
||||
};
|
||||
|
||||
std::vector<Item> items;
|
||||
};
|
||||
|
||||
} // namespace xrpl::Resource
|
||||
} // namespace xrpl::resource
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Resource::Manager
|
||||
# resource::Manager
|
||||
|
||||
The ResourceManager module has these responsibilities:
|
||||
|
||||
@@ -36,7 +36,7 @@ to the general public.
|
||||
## Consumer Types
|
||||
|
||||
Consumers are placed into three classifications (as identified by the
|
||||
Resource::Kind enumeration):
|
||||
resource::Kind enumeration):
|
||||
|
||||
- InBound,
|
||||
- OutBound, and
|
||||
@@ -72,6 +72,6 @@ drop connections to those IP addresses that occur commonly in the gossip.
|
||||
|
||||
## Access
|
||||
|
||||
In xrpld, the Application holds a unique instance of Resource::Manager,
|
||||
In xrpld, the Application holds a unique instance of resource::Manager,
|
||||
which may be retrieved by calling the method
|
||||
`Application::getResourceManager()`.
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
namespace xrpl::Resource {
|
||||
namespace xrpl::resource {
|
||||
|
||||
/**
|
||||
* Tracks load and resource consumption.
|
||||
@@ -32,10 +32,10 @@ public:
|
||||
* IP if proxied.
|
||||
*/
|
||||
virtual Consumer
|
||||
newInboundEndpoint(beast::IP::Endpoint const& address) = 0;
|
||||
newInboundEndpoint(beast::ip::Endpoint const& address) = 0;
|
||||
virtual Consumer
|
||||
newInboundEndpoint(
|
||||
beast::IP::Endpoint const& address,
|
||||
beast::ip::Endpoint const& address,
|
||||
bool const proxy,
|
||||
std::string_view forwardedFor) = 0;
|
||||
|
||||
@@ -43,13 +43,13 @@ public:
|
||||
* Create a new endpoint keyed by outbound IP address and port.
|
||||
*/
|
||||
virtual Consumer
|
||||
newOutboundEndpoint(beast::IP::Endpoint const& address) = 0;
|
||||
newOutboundEndpoint(beast::ip::Endpoint const& address) = 0;
|
||||
|
||||
/**
|
||||
* Create a new unlimited endpoint keyed by forwarded IP.
|
||||
*/
|
||||
virtual Consumer
|
||||
newUnlimitedEndpoint(beast::IP::Endpoint const& address) = 0;
|
||||
newUnlimitedEndpoint(beast::ip::Endpoint const& address) = 0;
|
||||
|
||||
/**
|
||||
* Extract packaged consumer information for export.
|
||||
@@ -78,4 +78,4 @@ public:
|
||||
std::unique_ptr<Manager>
|
||||
makeManager(beast::insight::Collector::ptr const& collector, beast::Journal journal);
|
||||
|
||||
} // namespace xrpl::Resource
|
||||
} // namespace xrpl::resource
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
|
||||
namespace xrpl::Resource {
|
||||
namespace xrpl::resource {
|
||||
|
||||
using clock_type = beast::AbstractClock<std::chrono::steady_clock>;
|
||||
|
||||
@@ -91,4 +91,4 @@ operator<<(std::ostream& os, Entry const& v)
|
||||
return os;
|
||||
}
|
||||
|
||||
} // namespace xrpl::Resource
|
||||
} // namespace xrpl::resource
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace xrpl::Resource {
|
||||
namespace xrpl::resource {
|
||||
|
||||
/**
|
||||
* A set of imported consumer data from a gossip origin.
|
||||
@@ -32,4 +32,4 @@ struct Import
|
||||
std::vector<Item> items;
|
||||
};
|
||||
|
||||
} // namespace xrpl::Resource
|
||||
} // namespace xrpl::resource
|
||||
|
||||
@@ -7,17 +7,17 @@
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
|
||||
namespace xrpl::Resource {
|
||||
namespace xrpl::resource {
|
||||
|
||||
// The consumer key
|
||||
struct Key
|
||||
{
|
||||
Kind kind;
|
||||
beast::IP::Endpoint address;
|
||||
beast::ip::Endpoint address;
|
||||
|
||||
Key() = delete;
|
||||
|
||||
Key(Kind k, beast::IP::Endpoint addr) : kind(k), address(std::move(addr))
|
||||
Key(Kind k, beast::ip::Endpoint addr) : kind(k), address(std::move(addr))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -47,4 +47,4 @@ struct Key
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace xrpl::Resource
|
||||
} // namespace xrpl::resource
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
namespace xrpl::Resource {
|
||||
namespace xrpl::resource {
|
||||
|
||||
/**
|
||||
* Kind of consumer.
|
||||
@@ -12,4 +12,4 @@ namespace xrpl::Resource {
|
||||
*/
|
||||
enum class Kind { Inbound, Outbound, Unlimited };
|
||||
|
||||
} // namespace xrpl::Resource
|
||||
} // namespace xrpl::resource
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
namespace xrpl::Resource {
|
||||
namespace xrpl::resource {
|
||||
|
||||
class Logic
|
||||
{
|
||||
@@ -96,7 +96,7 @@ public:
|
||||
}
|
||||
|
||||
Consumer
|
||||
newInboundEndpoint(beast::IP::Endpoint const& address)
|
||||
newInboundEndpoint(beast::ip::Endpoint const& address)
|
||||
{
|
||||
Entry* entry(nullptr);
|
||||
|
||||
@@ -126,7 +126,7 @@ public:
|
||||
}
|
||||
|
||||
Consumer
|
||||
newOutboundEndpoint(beast::IP::Endpoint const& address)
|
||||
newOutboundEndpoint(beast::ip::Endpoint const& address)
|
||||
{
|
||||
Entry* entry(nullptr);
|
||||
|
||||
@@ -159,7 +159,7 @@ public:
|
||||
* enabled.
|
||||
*/
|
||||
Consumer
|
||||
newUnlimitedEndpoint(beast::IP::Endpoint const& address)
|
||||
newUnlimitedEndpoint(beast::ip::Endpoint const& address)
|
||||
{
|
||||
Entry* entry(nullptr);
|
||||
|
||||
@@ -387,7 +387,7 @@ public:
|
||||
{
|
||||
std::scoped_lock const _(lock_);
|
||||
Entry& entry(iter->second);
|
||||
XRPL_ASSERT(entry.refcount == 0, "xrpl::Resource::Logic::erase : entry not used");
|
||||
XRPL_ASSERT(entry.refcount == 0, "xrpl::resource::Logic::erase : entry not used");
|
||||
inactive_.erase(inactive_.iteratorTo(entry));
|
||||
table_.erase(iter);
|
||||
}
|
||||
@@ -421,7 +421,7 @@ public:
|
||||
default:
|
||||
// LCOV_EXCL_START
|
||||
UNREACHABLE(
|
||||
"xrpl::Resource::Logic::release : invalid entry "
|
||||
"xrpl::resource::Logic::release : invalid entry "
|
||||
"kind");
|
||||
break;
|
||||
// LCOV_EXCL_STOP
|
||||
@@ -440,7 +440,7 @@ public:
|
||||
static_assert(
|
||||
kFeeLogAsWarn > kFeeLogAsInfo && kFeeLogAsInfo > kFeeLogAsDebug && kFeeLogAsDebug > 10);
|
||||
|
||||
static auto kGetStream = [](Resource::Charge::value_type cost, beast::Journal& journal) {
|
||||
static auto kGetStream = [](resource::Charge::value_type cost, beast::Journal& journal) {
|
||||
if (cost >= kFeeLogAsWarn)
|
||||
return journal.warn();
|
||||
if (cost >= kFeeLogAsInfo)
|
||||
@@ -564,4 +564,4 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace xrpl::Resource
|
||||
} // namespace xrpl::resource
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include <chrono>
|
||||
|
||||
namespace xrpl::Resource {
|
||||
namespace xrpl::resource {
|
||||
|
||||
/**
|
||||
* Tunable constants.
|
||||
@@ -26,4 +26,4 @@ static constexpr std::chrono::seconds kSecondsUntilExpiration{300};
|
||||
// Number of seconds until imported gossip expires
|
||||
static constexpr std::chrono::seconds kGossipExpirationSeconds{30};
|
||||
|
||||
} // namespace xrpl::Resource
|
||||
} // namespace xrpl::resource
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <xrpl/server/Manifest.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
@@ -22,6 +23,39 @@ namespace xrpl {
|
||||
// Operations that clients may wish to perform against the network
|
||||
// Master operational handler, server sequencer, network tracker
|
||||
|
||||
/**
|
||||
* Maximum number of subscriptions a single client connection may hold at once.
|
||||
*
|
||||
* Applies to the account, real-time account, and account-history subscriptions
|
||||
* tracked on one InfoSub (the sets counted by totalSubscriptionCount), bounding
|
||||
* the disconnect-time cleanup of those sets. Book subscriptions are tracked
|
||||
* separately (OrderBookDB) and are not counted here. Generous enough for
|
||||
* legitimate power users such as block explorers.
|
||||
*/
|
||||
constexpr std::size_t kMaxSubscriptionsPerConnection = 100'000;
|
||||
|
||||
/**
|
||||
* Whether adding @p additional subscriptions to a connection already holding
|
||||
* @p current would exceed the cap.
|
||||
*
|
||||
* Pure arithmetic split out so it can be unit-tested without a live
|
||||
* connection. The first term avoids underflow in the subtraction.
|
||||
*
|
||||
* @param current Subscriptions already tracked on the connection.
|
||||
* @param additional Subscriptions a request would add.
|
||||
* @param cap The effective per-connection cap. Defaults to the
|
||||
* built-in limit; callers may pass a configured override.
|
||||
* @return true if the request must be rejected to stay within the cap.
|
||||
*/
|
||||
[[nodiscard]] constexpr bool
|
||||
exceedsSubscriptionCap(
|
||||
std::size_t current,
|
||||
std::size_t additional,
|
||||
std::size_t cap = kMaxSubscriptionsPerConnection)
|
||||
{
|
||||
return additional > cap || current > cap - additional;
|
||||
}
|
||||
|
||||
class InfoSubRequest : public CountedObject<InfoSubRequest>
|
||||
{
|
||||
public:
|
||||
@@ -44,12 +78,12 @@ public:
|
||||
* map.
|
||||
*
|
||||
* @note Lifetime contract: every `InfoSub` instance MUST be destroyed
|
||||
* before the backing `Source`. NetworkOPsImp shutdown drops all
|
||||
* subscriber strong refs before its own teardown to satisfy this.
|
||||
* before the backing `Source`. NetworkOPsImp shutdown drops all
|
||||
* subscriber strong refs before its own teardown to satisfy this.
|
||||
* @note Thread-safety: per-instance state is guarded by `lock_`. The
|
||||
* destructor reads tracking sets without taking `lock_` because
|
||||
* the strong-pointer ref-count is zero at destruction time, so
|
||||
* no other thread can be calling the public mutators.
|
||||
* destructor reads tracking sets without taking `lock_` because
|
||||
* the strong-pointer ref-count is zero at destruction time, so
|
||||
* no other thread can be calling the public mutators.
|
||||
*/
|
||||
class InfoSub : public CountedObject<InfoSub>
|
||||
{
|
||||
@@ -62,7 +96,7 @@ public:
|
||||
|
||||
using ref = std::shared_ptr<InfoSub> const&;
|
||||
|
||||
using Consumer = Resource::Consumer;
|
||||
using Consumer = resource::Consumer;
|
||||
|
||||
public:
|
||||
/**
|
||||
@@ -117,6 +151,34 @@ public:
|
||||
AccountID const& account,
|
||||
bool historyOnly) = 0;
|
||||
|
||||
/**
|
||||
* Schedule the server-side teardown of a disconnecting connection's
|
||||
* account subscriptions off the destructor thread.
|
||||
*
|
||||
* The implementation posts a low-priority JobQueue task that erases the
|
||||
* entries in bounded chunks, so `~InfoSub` returns immediately instead
|
||||
* of running the erase loop inline. The sets are taken by value so the
|
||||
* job owns its copies and never references the destroyed `InfoSub`.
|
||||
* Cleanup is keyed on `seq` (unique per connection), so deferring it
|
||||
* cannot disturb a reconnected client reusing the same accounts.
|
||||
*
|
||||
* @param seq The disconnecting connection's unique subscription id.
|
||||
* @param rtAccounts Real-time account subscriptions to remove.
|
||||
* @param normalAccounts Normal account subscriptions to remove.
|
||||
* @param historyAccounts Account-history subscriptions to remove.
|
||||
*
|
||||
* @note The implementing `Source` must outlive any job it posts. If the
|
||||
* JobQueue is already stopping (process shutdown), the job is not
|
||||
* enqueued; the cleanup is skipped because the server-side maps
|
||||
* are about to be destroyed and no publishing can run.
|
||||
*/
|
||||
virtual void
|
||||
scheduleAccountCleanup(
|
||||
std::uint64_t seq,
|
||||
hash_set<AccountID> rtAccounts,
|
||||
hash_set<AccountID> normalAccounts,
|
||||
hash_set<AccountID> historyAccounts) = 0;
|
||||
|
||||
// VFALCO TODO Document the bool return value
|
||||
virtual bool
|
||||
subLedger(ref ispListener, json::Value& jvResult) = 0;
|
||||
@@ -153,12 +215,12 @@ public:
|
||||
* @param ispListener The subscriber requesting removal.
|
||||
* @param book The order book to unsubscribe from.
|
||||
* @return true if the entry was present and removed, false if the
|
||||
* subscriber was not subscribed to @p book.
|
||||
* subscriber was not subscribed to @p book.
|
||||
*
|
||||
* @note Thread-safety: acquires subLock_ internally.
|
||||
* @note Thread-safety: acquires bookLock_ internally.
|
||||
* @note Do NOT call from ~InfoSub(). Use unsubBookInternal instead
|
||||
* to avoid a redundant write-back to bookSubscriptions_ on a
|
||||
* partially-destroyed object.
|
||||
* to avoid a redundant write-back to bookSubscriptions_ on a
|
||||
* partially-destroyed object.
|
||||
*/
|
||||
virtual bool
|
||||
unsubBook(ref ispListener, Book const&) = 0;
|
||||
@@ -173,9 +235,9 @@ public:
|
||||
* @param uListener The sequence number of the subscriber being torn down.
|
||||
* @param book The order book entry to remove.
|
||||
* @return true if the entry was present and removed, false otherwise
|
||||
* (e.g., already removed by a concurrent RPC unsubscribe).
|
||||
* (e.g., already removed by a concurrent RPC unsubscribe).
|
||||
*
|
||||
* @note Thread-safety: acquires subLock_ internally.
|
||||
* @note Thread-safety: acquires bookLock_ internally.
|
||||
*/
|
||||
virtual bool
|
||||
unsubBookInternal(std::uint64_t uListener, Book const&) = 0;
|
||||
@@ -221,8 +283,8 @@ public:
|
||||
|
||||
/**
|
||||
* Journal used by InfoSub for diagnostics that occur after the
|
||||
* owning subsystem (e.g. application-level Logs) is the only
|
||||
* surviving sink — primarily destructor-time cleanup failures.
|
||||
* owning subsystem (e.g. application-level Logs) is the only
|
||||
* surviving sink — primarily destructor-time cleanup failures.
|
||||
*/
|
||||
[[nodiscard]] virtual beast::Journal const&
|
||||
journal() const = 0;
|
||||
@@ -243,6 +305,56 @@ public:
|
||||
[[nodiscard]] std::uint64_t
|
||||
getSeq() const;
|
||||
|
||||
/**
|
||||
* Return the number of subscriptions currently tracked on this
|
||||
* connection.
|
||||
*
|
||||
* The combined size of the per-connection account, real-time account, and
|
||||
* account-history subscription sets. `doSubscribe` reads this to enforce
|
||||
* the per-connection subscription cap before admitting more.
|
||||
*
|
||||
* @return The total tracked subscription count for this connection.
|
||||
*
|
||||
* @note Thread-safe: takes `lock_` for the read; read-only.
|
||||
*/
|
||||
[[nodiscard]] std::size_t
|
||||
totalSubscriptionCount() const;
|
||||
|
||||
/**
|
||||
* Enforce the cap and reserve a request's net-new accounts, atomically.
|
||||
*
|
||||
* Under one hold of `lock_`: count the net-new entries in the two sets,
|
||||
* check the total against @p cap, and insert them only if it fits.
|
||||
* All-or-nothing. Doing check and insert together stops two concurrent
|
||||
* requests sharing an InfoSub (the admin subscribe-by-url path) from both
|
||||
* passing the check before either records its accounts. The server-side
|
||||
* maps are populated afterwards by subAccount, whose re-insert is a no-op.
|
||||
*
|
||||
* @param proposedAccounts Real-time (accounts_proposed) ids to reserve.
|
||||
* @param normalAccounts Normal (accounts) ids to reserve.
|
||||
* @param cap The effective per-connection cap.
|
||||
* @return true if reserved; false if the request must be rejected.
|
||||
* @note Thread-safe: takes `lock_`.
|
||||
*/
|
||||
[[nodiscard]] bool
|
||||
tryReserveAccountSubscriptions(
|
||||
hash_set<AccountID> const& proposedAccounts,
|
||||
hash_set<AccountID> const& normalAccounts,
|
||||
std::size_t cap);
|
||||
|
||||
/**
|
||||
* Whether this connection already tracks an account-history for @p account.
|
||||
*
|
||||
* `doSubscribe` reads this to charge the cap for an account_history_tx_stream
|
||||
* only when it is net-new, matching the account branches.
|
||||
*
|
||||
* @param account The account an account_history_tx_stream would add.
|
||||
* @return true if @p account is already in the account-history set.
|
||||
* @note Thread-safe: takes `lock_`; read-only.
|
||||
*/
|
||||
[[nodiscard]] bool
|
||||
hasAccountHistorySubscription(AccountID const& account) const;
|
||||
|
||||
void
|
||||
onSendEmpty();
|
||||
|
||||
@@ -302,7 +414,9 @@ public:
|
||||
getApiVersion() const noexcept;
|
||||
|
||||
protected:
|
||||
std::mutex lock_;
|
||||
// Mutable so the read-only totalSubscriptionCount() accessor can lock it
|
||||
// from a const method; locking semantics are otherwise unchanged.
|
||||
mutable std::mutex lock_;
|
||||
|
||||
private:
|
||||
Consumer consumer_;
|
||||
|
||||
@@ -3,12 +3,14 @@
|
||||
#include <xrpl/basics/Blob.h>
|
||||
#include <xrpl/basics/Slice.h>
|
||||
#include <xrpl/basics/UnorderedContainers.h>
|
||||
#include <xrpl/basics/base64.h>
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/protocol/PublicKey.h>
|
||||
#include <xrpl/protocol/SecretKey.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
@@ -43,12 +45,15 @@ namespace xrpl {
|
||||
dynamically generates the signatureless form when it needs to verify
|
||||
the signature.
|
||||
|
||||
An instance of ManifestCache stores, for each trusted validator, (a) its
|
||||
An instance of ManifestCache stores, for each known validator, (a) its
|
||||
master public key, and (b) the most senior of all valid manifests it has
|
||||
seen for that validator, if any. On startup, the [validator_token] config
|
||||
entry (which contains the manifest for this validator) is decoded and
|
||||
added to the manifest cache. Other manifests are added as "gossip"
|
||||
received from xrpld peers.
|
||||
received from xrpld peers, including ones for validators this node does not
|
||||
trust. Manifests for untrusted validators are capped (kMaxUntrustedCount)
|
||||
so peer gossip cannot grow the cache without bound; trusted validators are
|
||||
not capped. Entries are never evicted, so a stored revocation is permanent.
|
||||
|
||||
When an ephemeral key is compromised, a new signing key pair is created,
|
||||
along with a new manifest vouching for it (with a higher sequence number),
|
||||
@@ -164,6 +169,100 @@ struct Manifest
|
||||
std::string
|
||||
to_string(Manifest const& m);
|
||||
|
||||
/**
|
||||
* Largest a valid manifest can be, in decoded bytes.
|
||||
*
|
||||
* A manifest has a fixed set of fields. Each is serialized as a field header
|
||||
* (1-2 bytes), an optional length prefix (1 byte for these sizes), and the
|
||||
* field body. Taking every field at its largest gives the maximum below, so
|
||||
* anything larger cannot be a valid manifest.
|
||||
*
|
||||
* Field header + length + body = bytes
|
||||
* sfVersion (U16) 2 0 2 4
|
||||
* sfSequence (U32) 1 0 4 5
|
||||
* sfPublicKey (33) 1 1 33 35
|
||||
* sfSigningPubKey (33) 1 1 33 35
|
||||
* sfSignature (72) 1 1 72 74
|
||||
* sfMasterSignature (72) 2 1 72 75
|
||||
* sfDomain (128) 1 1 128 130
|
||||
* -----
|
||||
* 358
|
||||
*/
|
||||
constexpr std::size_t kMaxManifestBytes = 358;
|
||||
|
||||
/**
|
||||
* Largest a valid manifest can be, in base64 characters.
|
||||
*
|
||||
* base64 encodes 3 bytes as 4 characters, so this is the encoded form of
|
||||
* @ref kMaxManifestBytes. Callers that receive a base64 manifest should
|
||||
* reject anything longer than this before decoding, to avoid allocating
|
||||
* memory for an oversized input.
|
||||
*/
|
||||
constexpr std::size_t kMaxManifestBase64 = base64::encodedSize(kMaxManifestBytes);
|
||||
|
||||
/**
|
||||
* Default number of untrusted manifests to store in cache and allowed
|
||||
* in one Manifest message.
|
||||
*
|
||||
* Bounds unlisted validators two ways. In the cache, a manifest for a
|
||||
* brand-new unlisted key is rejected once this many are held, so peer gossip
|
||||
* cannot grow the cache without end. In a TMManifests message, this many are
|
||||
* sent and processed, so a peer sending its whole cache cannot force unbounded
|
||||
* work.
|
||||
*
|
||||
* Operators can override this with `[overlay] max_untrusted_count`. Both users
|
||||
* read the configured value and fall back to this default.
|
||||
*/
|
||||
constexpr std::size_t kMaxUntrustedCount = 300;
|
||||
|
||||
/**
|
||||
* Default number of trusted manifests allowed in a Manifest message.
|
||||
* Not used atm while creating the message, but used to calculate the higher limit on
|
||||
* received message size. Introduced to maintain consistency. Future implementation
|
||||
* will use this limit.
|
||||
*
|
||||
* Trusted manifests are never dropped: every one this node holds is sent, and
|
||||
* every one received is processed, since dropping one would delay a validator
|
||||
* key rotation. This count only sizes the largest message accepted, so it must
|
||||
* stay above any realistic validator list. Cap can be increased in the config
|
||||
* file if messages get rejected with actual trusted manifest count crossing
|
||||
* configured(or else default) value.
|
||||
* Operators can override this with `[overlay] max_trusted_count`.
|
||||
*/
|
||||
constexpr std::size_t kMaxTrustedCount = 300;
|
||||
|
||||
/**
|
||||
* Number of untrusted manifests to store in cache and allowed
|
||||
* in one Manifest message..
|
||||
*
|
||||
* Returns the operator's override when one is configured, otherwise
|
||||
* @ref kMaxUntrustedCount. Config stores an override rather than the default
|
||||
* itself because the core module cannot depend on this module.
|
||||
*
|
||||
* @param configured The value from `[overlay] max_untrusted_count`, or
|
||||
* `std::nullopt` when the operator did not set it.
|
||||
*/
|
||||
constexpr std::size_t
|
||||
untrustedManifestCount(std::optional<std::size_t> const& configured)
|
||||
{
|
||||
return configured.value_or(kMaxUntrustedCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of trusted manifests allowed in a Manifest message.
|
||||
*
|
||||
* Not a cap on how many are sent or processed; see @ref kMaxTrustedCount.
|
||||
* but used to calculate the higher limit on received message size.
|
||||
*
|
||||
* @param configured The value from `[overlay] max_trusted_count`, or
|
||||
* `std::nullopt` when the operator did not set it.
|
||||
*/
|
||||
constexpr std::size_t
|
||||
trustedManifestCount(std::optional<std::size_t> const& configured)
|
||||
{
|
||||
return configured.value_or(kMaxTrustedCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs Manifest from serialized string
|
||||
*
|
||||
@@ -172,7 +271,7 @@ to_string(Manifest const& m);
|
||||
* @return `std::nullopt` if string is invalid
|
||||
*
|
||||
* @note This does not verify manifest signatures.
|
||||
* `Manifest::verify` should be called after constructing manifest.
|
||||
* `Manifest::verify` should be called after constructing manifest.
|
||||
*/
|
||||
/** @{ */
|
||||
std::optional<Manifest>
|
||||
@@ -225,30 +324,17 @@ loadValidatorToken(
|
||||
beast::Journal journal = beast::Journal(beast::Journal::getNullSink()));
|
||||
|
||||
enum class ManifestDisposition {
|
||||
/**
|
||||
* Manifest is valid
|
||||
*/
|
||||
Accepted = 0,
|
||||
Accepted = 0, ///< Manifest is valid
|
||||
|
||||
/**
|
||||
* Sequence is too old
|
||||
*/
|
||||
Stale,
|
||||
Stale, ///< Sequence is too old
|
||||
|
||||
/**
|
||||
* The master key is not acceptable to us
|
||||
*/
|
||||
BadMasterKey,
|
||||
BadMasterKey, ///< The master key is not acceptable to us
|
||||
|
||||
/**
|
||||
* The ephemeral key is not acceptable to us
|
||||
*/
|
||||
BadEphemeralKey,
|
||||
BadEphemeralKey, ///< The ephemeral key is not acceptable to us
|
||||
|
||||
/**
|
||||
* Timely, but invalid signature
|
||||
*/
|
||||
Invalid
|
||||
Invalid, ///< Timely, but invalid signature
|
||||
|
||||
UntrustedCapacity ///< Unlisted and limit reached
|
||||
};
|
||||
|
||||
inline std::string
|
||||
@@ -266,11 +352,25 @@ to_string(ManifestDisposition m)
|
||||
return "badEphemeralKey";
|
||||
case ManifestDisposition::Invalid:
|
||||
return "invalid";
|
||||
case ManifestDisposition::UntrustedCapacity:
|
||||
return "untrustedCapacity";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether a manifest counts against the 'untrusted' cache cap.
|
||||
*
|
||||
* Passed to `ManifestCache::applyManifest` with no default, so every caller
|
||||
* must choose. `Capped` is the safe, flood-resistant value; only listed or
|
||||
* configured keys should use `Uncapped`.
|
||||
*/
|
||||
enum class ManifestRateLimitCapPolicy : std::uint8_t {
|
||||
Capped, ///< Subject to the untrusted cap (unlisted peer gossip)
|
||||
Uncapped ///< Bypasses the cap (listed/trusted or config manifests)
|
||||
};
|
||||
|
||||
class DatabaseCon;
|
||||
|
||||
/**
|
||||
@@ -294,8 +394,51 @@ private:
|
||||
|
||||
std::atomic<std::uint32_t> seq_{0};
|
||||
|
||||
/**
|
||||
* Master keys of cached manifests for validators this node does not list.
|
||||
*
|
||||
* One entry per capped key in `map_`; its size enforces the cap below.
|
||||
* A key is added when first cached under `Capped` and removed when it
|
||||
* becomes listed (see `promoteToTrusted`) or an `Uncapped` update arrives,
|
||||
* never re-added on de-listing. Uncapped keys are not tracked here.
|
||||
*/
|
||||
hash_set<PublicKey> untrustedKeys_;
|
||||
|
||||
/**
|
||||
* Maximum number of untrusted master keys kept in the cache.
|
||||
*
|
||||
* Once reached, a manifest for a brand-new unlisted key is rejected. Set
|
||||
* from the config, defaulting to @ref kMaxUntrustedCount.
|
||||
*/
|
||||
std::size_t const maxUntrustedCount_;
|
||||
|
||||
/**
|
||||
* Running count of manifests rejected because the untrusted cap was full.
|
||||
*
|
||||
* Drives throttled logging (see `kUntrustedRejectCount`). Atomic because
|
||||
* `applyManifest` may run concurrently.
|
||||
*/
|
||||
std::atomic<std::uint64_t> untrustedRejectCount_{0};
|
||||
|
||||
/**
|
||||
* Number of cap rejections between summary warnings.
|
||||
*
|
||||
* @see untrustedRejectCount_
|
||||
*/
|
||||
static constexpr std::uint64_t kUntrustedRejectCount = 10000;
|
||||
|
||||
public:
|
||||
explicit ManifestCache(beast::Journal j = beast::Journal(beast::Journal::getNullSink())) : j_(j)
|
||||
/**
|
||||
* @param j Journal for logging.
|
||||
*
|
||||
* @param maxUntrustedCount Untrusted master keys to keep. Pass the
|
||||
* configured value; defaults to @ref kMaxUntrustedCount. Taken as a
|
||||
* parameter because this module cannot depend on the config.
|
||||
*/
|
||||
explicit ManifestCache(
|
||||
beast::Journal j = beast::Journal(beast::Journal::getNullSink()),
|
||||
std::size_t maxUntrustedCount = kMaxUntrustedCount)
|
||||
: j_(j), maxUntrustedCount_(maxUntrustedCount)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -378,17 +521,44 @@ public:
|
||||
/**
|
||||
* Add manifest to cache.
|
||||
*
|
||||
* A brand-new unlisted key is rejected once the untrusted cap is full;
|
||||
* updates to a cached key and `Uncapped` manifests bypass the cap. The
|
||||
* caller decides `cap` before calling so the cache lock is not held while
|
||||
* consulting the validator list, which would risk a lock-ordering deadlock.
|
||||
*
|
||||
* @param m Manifest to add
|
||||
*
|
||||
* @return `ManifestDisposition::accepted` if successful, or
|
||||
* `stale` or `invalid` otherwise
|
||||
* @param cap `Uncapped` skips the untrusted cap; use it for keys that are
|
||||
* listed, configured, or loaded from the DB. Note `Uncapped` does not
|
||||
* assert the key is currently trusted (a DB entry may predate a
|
||||
* de-listing). Callers must state this explicitly so a manifest is
|
||||
* never left uncapped by omission.
|
||||
*
|
||||
* @return `Accepted` if stored, `Stale` if superseded, `Invalid`/
|
||||
* `BadEphemeralKey` if malformed, or `UntrustedCapacity` if the
|
||||
* untrusted cap is full.
|
||||
*
|
||||
* @par Thread Safety
|
||||
*
|
||||
* May be called concurrently
|
||||
*/
|
||||
ManifestDisposition
|
||||
applyManifest(Manifest m);
|
||||
applyManifest(Manifest m, ManifestRateLimitCapPolicy cap);
|
||||
|
||||
/**
|
||||
* Stop counting a master key against the untrusted cap.
|
||||
*
|
||||
* Called when a cached untrusted key becomes listed, freeing its slot.
|
||||
* Idempotent and a no-op for keys that were never counted.
|
||||
*
|
||||
* @param pk Master public key that is now listed/trusted
|
||||
*
|
||||
* @par Thread Safety
|
||||
*
|
||||
* May be called concurrently
|
||||
*/
|
||||
void
|
||||
promoteToTrusted(PublicKey const& pk);
|
||||
|
||||
/**
|
||||
* Populate manifest cache with manifests in database and config.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user