mirror of
https://github.com/XRPLF/rippled.git
synced 2026-01-11 10:15:24 +00:00
Compare commits
48 Commits
pratik/Mig
...
ximinez/di
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8ad0d43744 | ||
|
|
b2c5927b48 | ||
|
|
7c1183547a | ||
|
|
14467fba5e | ||
|
|
fc00723836 | ||
|
|
c24a6041f7 | ||
|
|
039b8b90fd | ||
|
|
e1d97bea12 | ||
|
|
b9bda49134 | ||
|
|
53aa5ca903 | ||
|
|
510c0d82e9 | ||
|
|
17565d21d4 | ||
|
|
07ff532d30 | ||
|
|
2c37ef7762 | ||
|
|
3c9f5b6252 | ||
|
|
f80059e467 | ||
|
|
d734c8dddd | ||
|
|
69cb14c832 | ||
|
|
44d21b8f6d | ||
|
|
3d1b3a49b3 | ||
|
|
0b87a26f04 | ||
|
|
0f23ad820c | ||
|
|
b7139da4d0 | ||
|
|
2ec85c2a98 | ||
|
|
40198d9792 | ||
|
|
6208a3aa9a | ||
|
|
f059f0beda | ||
|
|
41c1be2bac | ||
|
|
e70b95195b | ||
|
|
f816ffa55f | ||
|
|
cf748702af | ||
|
|
2cc40a1647 | ||
|
|
238735d18b | ||
|
|
e5cdeab184 | ||
|
|
2acb3fc306 | ||
|
|
f3a9a9362d | ||
|
|
91c5ad2388 | ||
|
|
ced186ae6a | ||
|
|
e1b5945077 | ||
|
|
a2b4b06918 | ||
|
|
54d528868f | ||
|
|
6dd31bdef6 | ||
|
|
d411e38615 | ||
|
|
730ac9b763 | ||
|
|
39715d6915 | ||
|
|
fbeae82d61 | ||
|
|
429c15ac0d | ||
|
|
9382fe1c82 |
275
.config/cspell.config.yaml
Normal file
275
.config/cspell.config.yaml
Normal file
@@ -0,0 +1,275 @@
|
||||
ignorePaths:
|
||||
- build/**
|
||||
- src/libxrpl/crypto
|
||||
- src/test/** # Will be removed in the future
|
||||
- CMakeUserPresets.json
|
||||
- Doxyfile
|
||||
- docs/**/*.puml
|
||||
- cmake/**
|
||||
- LICENSE.md
|
||||
language: en
|
||||
allowCompoundWords: true
|
||||
ignoreRandomStrings: true
|
||||
minWordLength: 5
|
||||
dictionaries:
|
||||
- cpp
|
||||
- en_US
|
||||
- en_GB
|
||||
ignoreRegExpList:
|
||||
- /[rs][1-9A-HJ-NP-Za-km-z]{25,34}/g # addresses and seeds
|
||||
- /(XRPL|BEAST)_[A-Z_0-9]+_H_INCLUDED+/g # include guards
|
||||
- /(XRPL|BEAST)_[A-Z_0-9]+_H+/g # include guards
|
||||
- /::[a-z:_]+/g # things from other namespaces
|
||||
- /lib[a-z]+/g # libraries
|
||||
- /[0-9]{4}-[0-9]{2}-[0-9]{2}[,:][A-Za-zÀ-ÖØ-öø-ÿ.\s]+/g # copyright dates
|
||||
- /[0-9]{4}[,:]?\s*[A-Za-zÀ-ÖØ-öø-ÿ.\s]+/g # copyright years
|
||||
- /\[[A-Za-z0-9-]+\]\(https:\/\/github.com\/[A-Za-z0-9-]+\)/g # Github usernames
|
||||
- /-[DWw][a-zA-Z0-9_-]+=/g # compile flags
|
||||
- /[\['"`]-[DWw][a-zA-Z0-9_-]+['"`\]]/g # compile flags
|
||||
suggestWords:
|
||||
- xprl->xrpl
|
||||
- unsynched->unsynced
|
||||
- synched->synced
|
||||
- synch->sync
|
||||
words:
|
||||
- abempty
|
||||
- AMMID
|
||||
- amt
|
||||
- amts
|
||||
- asnode
|
||||
- asynchrony
|
||||
- attestation
|
||||
- authorises
|
||||
- autobridge
|
||||
- autobridged
|
||||
- autobridging
|
||||
- bimap
|
||||
- bindir
|
||||
- bookdir
|
||||
- Bougalis
|
||||
- Britto
|
||||
- Btrfs
|
||||
- canonicality
|
||||
- checkme
|
||||
- choco
|
||||
- chrono
|
||||
- citardauq
|
||||
- clawback
|
||||
- clawbacks
|
||||
- coeffs
|
||||
- coldwallet
|
||||
- compr
|
||||
- conanfile
|
||||
- conanrun
|
||||
- connectability
|
||||
- coro
|
||||
- coros
|
||||
- cowid
|
||||
- cryptocondition
|
||||
- cryptoconditional
|
||||
- cryptoconditions
|
||||
- csprng
|
||||
- ctid
|
||||
- currenttxhash
|
||||
- daria
|
||||
- dcmake
|
||||
- dearmor
|
||||
- deleteme
|
||||
- demultiplexer
|
||||
- deserializaton
|
||||
- desync
|
||||
- desynced
|
||||
- determ
|
||||
- distro
|
||||
- doxyfile
|
||||
- dxrpl
|
||||
- endmacro
|
||||
- exceptioned
|
||||
- Falco
|
||||
- finalizers
|
||||
- firewalled
|
||||
- fmtdur
|
||||
- funclets
|
||||
- gcov
|
||||
- gcovr
|
||||
- ghead
|
||||
- Gnutella
|
||||
- gpgcheck
|
||||
- gpgkey
|
||||
- hotwallet
|
||||
- ifndef
|
||||
- inequation
|
||||
- insuf
|
||||
- insuff
|
||||
- iou
|
||||
- ious
|
||||
- isrdc
|
||||
- jemalloc
|
||||
- jlog
|
||||
- keylet
|
||||
- keylets
|
||||
- keyvadb
|
||||
- ledgerentry
|
||||
- ledgerhash
|
||||
- ledgerindex
|
||||
- leftw
|
||||
- legleux
|
||||
- levelization
|
||||
- levelized
|
||||
- libpb
|
||||
- libxrpl
|
||||
- llection
|
||||
- LOCALGOOD
|
||||
- logwstream
|
||||
- lseq
|
||||
- lsmf
|
||||
- ltype
|
||||
- MEMORYSTATUSEX
|
||||
- Merkle
|
||||
- Metafuncton
|
||||
- misprediction
|
||||
- mptbalance
|
||||
- mptflags
|
||||
- mptid
|
||||
- mptissuance
|
||||
- mptissuanceid
|
||||
- mptoken
|
||||
- mptokenid
|
||||
- mptokenissuance
|
||||
- mptokens
|
||||
- mpts
|
||||
- multisig
|
||||
- multisign
|
||||
- multisigned
|
||||
- Nakamoto
|
||||
- nftid
|
||||
- nftoffer
|
||||
- nftoken
|
||||
- nftokenid
|
||||
- nftokenpages
|
||||
- nftokens
|
||||
- nftpage
|
||||
- nikb
|
||||
- nonxrp
|
||||
- noripple
|
||||
- nudb
|
||||
- nullptr
|
||||
- nunl
|
||||
- Nyffenegger
|
||||
- ostr
|
||||
- partitioner
|
||||
- paychan
|
||||
- paychans
|
||||
- permdex
|
||||
- perminute
|
||||
- permissioned
|
||||
- pointee
|
||||
- preauth
|
||||
- preauthorization
|
||||
- preauthorize
|
||||
- preauthorizes
|
||||
- preclaim
|
||||
- protobuf
|
||||
- protos
|
||||
- ptrs
|
||||
- pyenv
|
||||
- qalloc
|
||||
- queuable
|
||||
- Raphson
|
||||
- replayer
|
||||
- rerere
|
||||
- retriable
|
||||
- RIPD
|
||||
- ripdtop
|
||||
- rippleci
|
||||
- rippled
|
||||
- ripplerpc
|
||||
- rippletest
|
||||
- RLUSD
|
||||
- rngfill
|
||||
- rocksdb
|
||||
- Rohrs
|
||||
- roundings
|
||||
- sahyadri
|
||||
- Satoshi
|
||||
- secp
|
||||
- sendq
|
||||
- seqit
|
||||
- sf
|
||||
- shamap
|
||||
- shamapitem
|
||||
- sidechain
|
||||
- SIGGOOD
|
||||
- sle
|
||||
- sles
|
||||
- soci
|
||||
- socidb
|
||||
- sslws
|
||||
- statsd
|
||||
- STATSDCOLLECTOR
|
||||
- stissue
|
||||
- stnum
|
||||
- stobj
|
||||
- stobject
|
||||
- stpath
|
||||
- stpathset
|
||||
- sttx
|
||||
- stvar
|
||||
- stvector
|
||||
- stxchainattestations
|
||||
- superpeer
|
||||
- superpeers
|
||||
- takergets
|
||||
- takerpays
|
||||
- ters
|
||||
- TMEndpointv2
|
||||
- trixie
|
||||
- tx
|
||||
- txid
|
||||
- txids
|
||||
- txjson
|
||||
- txn
|
||||
- txns
|
||||
- txs
|
||||
- umant
|
||||
- unacquired
|
||||
- unambiguity
|
||||
- unauthorizes
|
||||
- unauthorizing
|
||||
- unergonomic
|
||||
- unfetched
|
||||
- unflatten
|
||||
- unfund
|
||||
- unimpair
|
||||
- unroutable
|
||||
- unscalable
|
||||
- unserviced
|
||||
- unshareable
|
||||
- unshares
|
||||
- unsquelch
|
||||
- unsquelched
|
||||
- unsquelching
|
||||
- unvalidated
|
||||
- unveto
|
||||
- unvetoed
|
||||
- upvotes
|
||||
- USDB
|
||||
- variadics
|
||||
- venv
|
||||
- vfalco
|
||||
- vinnie
|
||||
- wextra
|
||||
- wptr
|
||||
- writeme
|
||||
- wsrch
|
||||
- wthread
|
||||
- xbridge
|
||||
- xchain
|
||||
- ximinez
|
||||
- XMACRO
|
||||
- xrpkuwait
|
||||
- xrpl
|
||||
- xrpld
|
||||
- xrplf
|
||||
- xxhash
|
||||
- xxhasher
|
||||
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -1,5 +1,6 @@
|
||||
# Set default behaviour, in case users don't have core.autocrlf set.
|
||||
#* text=auto
|
||||
# cspell: disable
|
||||
|
||||
# Visual Studio
|
||||
*.sln text eol=crlf
|
||||
|
||||
9
.github/actions/build-deps/action.yml
vendored
9
.github/actions/build-deps/action.yml
vendored
@@ -4,9 +4,6 @@ description: "Install Conan dependencies, optionally forcing a rebuild of all de
|
||||
# Note that actions do not support 'type' and all inputs are strings, see
|
||||
# https://docs.github.com/en/actions/reference/workflows-and-actions/metadata-syntax#inputs.
|
||||
inputs:
|
||||
build_dir:
|
||||
description: "The directory where to build."
|
||||
required: true
|
||||
build_type:
|
||||
description: 'The build type to use ("Debug", "Release").'
|
||||
required: true
|
||||
@@ -28,17 +25,13 @@ runs:
|
||||
- name: Install Conan dependencies
|
||||
shell: bash
|
||||
env:
|
||||
BUILD_DIR: ${{ inputs.build_dir }}
|
||||
BUILD_NPROC: ${{ inputs.build_nproc }}
|
||||
BUILD_OPTION: ${{ inputs.force_build == 'true' && '*' || 'missing' }}
|
||||
BUILD_TYPE: ${{ inputs.build_type }}
|
||||
LOG_VERBOSITY: ${{ inputs.log_verbosity }}
|
||||
run: |
|
||||
echo 'Installing dependencies.'
|
||||
mkdir -p "${BUILD_DIR}"
|
||||
cd "${BUILD_DIR}"
|
||||
conan install \
|
||||
--output-folder . \
|
||||
--build="${BUILD_OPTION}" \
|
||||
--options:host='&:tests=True' \
|
||||
--options:host='&:xrpld=True' \
|
||||
@@ -46,4 +39,4 @@ runs:
|
||||
--conf:all tools.build:jobs=${BUILD_NPROC} \
|
||||
--conf:all tools.build:verbosity="${LOG_VERBOSITY}" \
|
||||
--conf:all tools.compilation:verbosity="${LOG_VERBOSITY}" \
|
||||
..
|
||||
.
|
||||
|
||||
24
.github/actions/print-env/action.yml
vendored
24
.github/actions/print-env/action.yml
vendored
@@ -11,12 +11,6 @@ runs:
|
||||
echo 'Checking environment variables.'
|
||||
set
|
||||
|
||||
echo 'Checking CMake version.'
|
||||
cmake --version
|
||||
|
||||
echo 'Checking Conan version.'
|
||||
conan --version
|
||||
|
||||
- name: Check configuration (Linux and macOS)
|
||||
if: ${{ runner.os == 'Linux' || runner.os == 'macOS' }}
|
||||
shell: bash
|
||||
@@ -27,17 +21,23 @@ runs:
|
||||
echo 'Checking environment variables.'
|
||||
env | sort
|
||||
|
||||
echo 'Checking CMake version.'
|
||||
cmake --version
|
||||
|
||||
echo 'Checking compiler version.'
|
||||
${{ runner.os == 'Linux' && '${CC}' || 'clang' }} --version
|
||||
|
||||
echo 'Checking Conan version.'
|
||||
conan --version
|
||||
|
||||
echo 'Checking Ninja version.'
|
||||
ninja --version
|
||||
|
||||
echo 'Checking nproc version.'
|
||||
nproc --version
|
||||
|
||||
- name: Check configuration (all)
|
||||
shell: bash
|
||||
run: |
|
||||
echo 'Checking Ccache version.'
|
||||
ccache --version
|
||||
|
||||
echo 'Checking CMake version.'
|
||||
cmake --version
|
||||
|
||||
echo 'Checking Conan version.'
|
||||
conan --version
|
||||
|
||||
4
.github/scripts/levelization/README.md
vendored
4
.github/scripts/levelization/README.md
vendored
@@ -81,10 +81,10 @@ It generates many files of [results](results):
|
||||
|
||||
- `rawincludes.txt`: The raw dump of the `#includes`
|
||||
- `paths.txt`: A second dump grouping the source module
|
||||
to the destination module, deduped, and with frequency counts.
|
||||
to the destination module, de-duped, and with frequency counts.
|
||||
- `includes/`: A directory where each file represents a module and
|
||||
contains a list of modules and counts that the module _includes_.
|
||||
- `includedby/`: Similar to `includes/`, but the other way around. Each
|
||||
- `included_by/`: Similar to `includes/`, but the other way around. Each
|
||||
file represents a module and contains a list of modules and counts
|
||||
that _include_ the module.
|
||||
- [`loops.txt`](results/loops.txt): A list of direct loops detected
|
||||
|
||||
6
.github/scripts/levelization/generate.sh
vendored
6
.github/scripts/levelization/generate.sh
vendored
@@ -29,7 +29,7 @@ pushd results
|
||||
oldifs=${IFS}
|
||||
IFS=:
|
||||
mkdir includes
|
||||
mkdir includedby
|
||||
mkdir included_by
|
||||
echo Build levelization paths
|
||||
exec 3< ${includes} # open rawincludes.txt for input
|
||||
while read -r -u 3 file include
|
||||
@@ -59,7 +59,7 @@ do
|
||||
echo $level $includelevel | tee -a paths.txt
|
||||
fi
|
||||
done
|
||||
echo Sort and dedup paths
|
||||
echo Sort and deduplicate paths
|
||||
sort -ds paths.txt | uniq -c | tee sortedpaths.txt
|
||||
mv sortedpaths.txt paths.txt
|
||||
exec 3>&- #close fd 3
|
||||
@@ -71,7 +71,7 @@ exec 4<paths.txt # open paths.txt for input
|
||||
while read -r -u 4 count level include
|
||||
do
|
||||
echo ${include} ${count} | tee -a includes/${level}
|
||||
echo ${level} ${count} | tee -a includedby/${include}
|
||||
echo ${level} ${count} | tee -a included_by/${include}
|
||||
done
|
||||
exec 4>&- #close fd 4
|
||||
|
||||
|
||||
@@ -1,13 +1,3 @@
|
||||
doctest.basics > xrpl.basics
|
||||
doctest.basics > xrpl.protocol
|
||||
doctest.beast > xrpl.basics
|
||||
doctest.core > xrpl.core
|
||||
doctest.core > xrpl.json
|
||||
doctest.csf > test.csf
|
||||
doctest.nodestore > xrpl.nodestore
|
||||
doctest.protocol > xrpl.basics
|
||||
doctest.protocol > xrpl.json
|
||||
doctest.protocol > xrpl.protocol
|
||||
libxrpl.basics > xrpl.basics
|
||||
libxrpl.core > xrpl.basics
|
||||
libxrpl.core > xrpl.core
|
||||
|
||||
6
.github/scripts/rename/README.md
vendored
6
.github/scripts/rename/README.md
vendored
@@ -19,7 +19,7 @@ run from the repository root.
|
||||
1. `.github/scripts/rename/definitions.sh`: This script will rename all
|
||||
definitions, such as include guards, from `RIPPLE_XXX` and `RIPPLED_XXX` to
|
||||
`XRPL_XXX`.
|
||||
2. `.github/scripts/rename/copyright.sh`: This script will remove superflous
|
||||
2. `.github/scripts/rename/copyright.sh`: This script will remove superfluous
|
||||
copyright notices.
|
||||
3. `.github/scripts/rename/cmake.sh`: This script will rename all CMake files
|
||||
from `RippleXXX.cmake` or `RippledXXX.cmake` to `XrplXXX.cmake`, and any
|
||||
@@ -31,6 +31,9 @@ run from the repository root.
|
||||
the `xrpld` binary.
|
||||
5. `.github/scripts/rename/namespace.sh`: This script will rename the C++
|
||||
namespaces from `ripple` to `xrpl`.
|
||||
6. `.github/scripts/rename/config.sh`: This script will rename the config from
|
||||
`rippled.cfg` to `xrpld.cfg`, and updating the code accordingly. The old
|
||||
filename will still be accepted.
|
||||
|
||||
You can run all these scripts from the repository root as follows:
|
||||
|
||||
@@ -40,4 +43,5 @@ You can run all these scripts from the repository root as follows:
|
||||
./.github/scripts/rename/cmake.sh .
|
||||
./.github/scripts/rename/binary.sh .
|
||||
./.github/scripts/rename/namespace.sh .
|
||||
./.github/scripts/rename/config.sh .
|
||||
```
|
||||
|
||||
72
.github/scripts/rename/config.sh
vendored
Executable file
72
.github/scripts/rename/config.sh
vendored
Executable file
@@ -0,0 +1,72 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Exit the script as soon as an error occurs.
|
||||
set -e
|
||||
|
||||
# On MacOS, ensure that GNU sed is installed and available as `gsed`.
|
||||
SED_COMMAND=sed
|
||||
if [[ "${OSTYPE}" == 'darwin'* ]]; then
|
||||
if ! command -v gsed &> /dev/null; then
|
||||
echo "Error: gsed is not installed. Please install it using 'brew install gnu-sed'."
|
||||
exit 1
|
||||
fi
|
||||
SED_COMMAND=gsed
|
||||
fi
|
||||
|
||||
# This script renames the config from `rippled.cfg` to `xrpld.cfg`, and updates
|
||||
# the code accordingly. The old filename will still be accepted.
|
||||
# Usage: .github/scripts/rename/config.sh <repository directory>
|
||||
|
||||
if [ "$#" -ne 1 ]; then
|
||||
echo "Usage: $0 <repository directory>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
DIRECTORY=$1
|
||||
echo "Processing directory: ${DIRECTORY}"
|
||||
if [ ! -d "${DIRECTORY}" ]; then
|
||||
echo "Error: Directory '${DIRECTORY}' does not exist."
|
||||
exit 1
|
||||
fi
|
||||
pushd ${DIRECTORY}
|
||||
|
||||
# Add the xrpld.cfg to the .gitignore.
|
||||
if ! grep -q 'xrpld.cfg' .gitignore; then
|
||||
${SED_COMMAND} -i '/rippled.cfg/a\
|
||||
/xrpld.cfg' .gitignore
|
||||
fi
|
||||
|
||||
# Rename the files.
|
||||
if [ -e rippled.cfg ]; then
|
||||
mv rippled.cfg xrpld.cfg
|
||||
fi
|
||||
if [ -e cfg/rippled-example.cfg ]; then
|
||||
mv cfg/rippled-example.cfg cfg/xrpld-example.cfg
|
||||
fi
|
||||
|
||||
# Rename inside the files.
|
||||
DIRECTORIES=("cfg" "cmake" "include" "src")
|
||||
for DIRECTORY in "${DIRECTORIES[@]}"; do
|
||||
echo "Processing directory: ${DIRECTORY}"
|
||||
|
||||
find "${DIRECTORY}" -type f \( -name "*.h" -o -name "*.hpp" -o -name "*.ipp" -o -name "*.cpp" -o -name "*.cmake" -o -name "*.txt" -o -name "*.cfg" -o -name "*.md" \) | while read -r FILE; do
|
||||
echo "Processing file: ${FILE}"
|
||||
${SED_COMMAND} -i -E 's/rippled(-example)?[ .]cfg/xrpld\1.cfg/g' "${FILE}"
|
||||
done
|
||||
done
|
||||
${SED_COMMAND} -i 's/rippled/xrpld/g' cfg/xrpld-example.cfg
|
||||
${SED_COMMAND} -i 's/rippled/xrpld/g' src/test/core/Config_test.cpp
|
||||
${SED_COMMAND} -i 's/ripplevalidators/xrplvalidators/g' src/test/core/Config_test.cpp # cspell: disable-line
|
||||
${SED_COMMAND} -i 's/rippleConfig/xrpldConfig/g' src/test/core/Config_test.cpp
|
||||
${SED_COMMAND} -i 's@ripple/@xrpld/@g' src/test/core/Config_test.cpp
|
||||
${SED_COMMAND} -i 's/Rippled/File/g' src/test/core/Config_test.cpp
|
||||
|
||||
|
||||
# Restore the old config file name in the code that maintains support for now.
|
||||
${SED_COMMAND} -i 's/configLegacyName = "xrpld.cfg"/configLegacyName = "rippled.cfg"/g' src/xrpld/core/detail/Config.cpp
|
||||
|
||||
# Restore an URL.
|
||||
${SED_COMMAND} -i 's/connect-your-xrpld-to-the-xrp-test-net.html/connect-your-rippled-to-the-xrp-test-net.html/g' cfg/xrpld-example.cfg
|
||||
|
||||
popd
|
||||
echo "Renaming complete."
|
||||
12
.github/scripts/rename/copyright.sh
vendored
12
.github/scripts/rename/copyright.sh
vendored
@@ -50,11 +50,11 @@ for DIRECTORY in "${DIRECTORIES[@]}"; do
|
||||
# Handle the cases where the copyright notice is enclosed in /* ... */
|
||||
# and usually surrounded by //---- and //======.
|
||||
${SED_COMMAND} -z -i -E 's@^//-------+\n+@@' "${FILE}"
|
||||
${SED_COMMAND} -z -i -E 's@^.*Copyright.+(Ripple|Bougalis|Falco|Hinnant|Null|Ritchford|XRPLF).+PERFORMANCE OF THIS SOFTWARE\.\n\*/\n+@@' "${FILE}"
|
||||
${SED_COMMAND} -z -i -E 's@^.*Copyright.+(Ripple|Bougalis|Falco|Hinnant|Null|Ritchford|XRPLF).+PERFORMANCE OF THIS SOFTWARE\.\n\*/\n+@@' "${FILE}" # cspell: ignore Bougalis Falco Hinnant Ritchford
|
||||
${SED_COMMAND} -z -i -E 's@^//=======+\n+@@' "${FILE}"
|
||||
|
||||
# Handle the cases where the copyright notice is commented out with //.
|
||||
${SED_COMMAND} -z -i -E 's@^//\n// Copyright.+Falco \(vinnie dot falco at gmail dot com\)\n//\n+@@' "${FILE}"
|
||||
${SED_COMMAND} -z -i -E 's@^//\n// Copyright.+Falco \(vinnie dot falco at gmail dot com\)\n//\n+@@' "${FILE}" # cspell: ignore Vinnie Falco
|
||||
done
|
||||
done
|
||||
|
||||
@@ -83,16 +83,16 @@ if ! grep -q 'Dev Null' src/xrpld/rpc/handlers/ValidatorInfo.cpp; then
|
||||
echo -e "// Copyright (c) 2019 Dev Null Productions\n\n$(cat src/xrpld/rpc/handlers/ValidatorInfo.cpp)" > src/xrpld/rpc/handlers/ValidatorInfo.cpp
|
||||
fi
|
||||
if ! grep -q 'Bougalis' include/xrpl/basics/SlabAllocator.h; then
|
||||
echo -e "// Copyright (c) 2022, Nikolaos D. Bougalis <nikb@bougalis.net>\n\n$(cat include/xrpl/basics/SlabAllocator.h)" > include/xrpl/basics/SlabAllocator.h
|
||||
echo -e "// Copyright (c) 2022, Nikolaos D. Bougalis <nikb@bougalis.net>\n\n$(cat include/xrpl/basics/SlabAllocator.h)" > include/xrpl/basics/SlabAllocator.h # cspell: ignore Nikolaos Bougalis nikb
|
||||
fi
|
||||
if ! grep -q 'Bougalis' include/xrpl/basics/spinlock.h; then
|
||||
echo -e "// Copyright (c) 2022, Nikolaos D. Bougalis <nikb@bougalis.net>\n\n$(cat include/xrpl/basics/spinlock.h)" > include/xrpl/basics/spinlock.h
|
||||
echo -e "// Copyright (c) 2022, Nikolaos D. Bougalis <nikb@bougalis.net>\n\n$(cat include/xrpl/basics/spinlock.h)" > include/xrpl/basics/spinlock.h # cspell: ignore Nikolaos Bougalis nikb
|
||||
fi
|
||||
if ! grep -q 'Bougalis' include/xrpl/basics/tagged_integer.h; then
|
||||
echo -e "// Copyright (c) 2014, Nikolaos D. Bougalis <nikb@bougalis.net>\n\n$(cat include/xrpl/basics/tagged_integer.h)" > include/xrpl/basics/tagged_integer.h
|
||||
echo -e "// Copyright (c) 2014, Nikolaos D. Bougalis <nikb@bougalis.net>\n\n$(cat include/xrpl/basics/tagged_integer.h)" > include/xrpl/basics/tagged_integer.h # cspell: ignore Nikolaos Bougalis nikb
|
||||
fi
|
||||
if ! grep -q 'Ritchford' include/xrpl/beast/utility/Zero.h; then
|
||||
echo -e "// Copyright (c) 2014, Tom Ritchford <tom@swirly.com>\n\n$(cat include/xrpl/beast/utility/Zero.h)" > include/xrpl/beast/utility/Zero.h
|
||||
echo -e "// Copyright (c) 2014, Tom Ritchford <tom@swirly.com>\n\n$(cat include/xrpl/beast/utility/Zero.h)" > include/xrpl/beast/utility/Zero.h # cspell: ignore Ritchford
|
||||
fi
|
||||
|
||||
# Restore newlines and tabs in string literals in the affected file.
|
||||
|
||||
2
.github/scripts/strategy-matrix/generate.py
vendored
2
.github/scripts/strategy-matrix/generate.py
vendored
@@ -232,6 +232,8 @@ def generate_strategy_matrix(all: bool, config: Config) -> list:
|
||||
f"-{architecture['platform'][architecture['platform'].find('/') + 1 :]}"
|
||||
)
|
||||
config_name += f"-{build_type.lower()}"
|
||||
if "-Dcoverage=ON" in cmake_args:
|
||||
config_name += "-coverage"
|
||||
if "-Dunity=ON" in cmake_args:
|
||||
config_name += "-unity"
|
||||
|
||||
|
||||
56
.github/scripts/strategy-matrix/linux.json
vendored
56
.github/scripts/strategy-matrix/linux.json
vendored
@@ -15,196 +15,196 @@
|
||||
"distro_version": "bookworm",
|
||||
"compiler_name": "gcc",
|
||||
"compiler_version": "12",
|
||||
"image_sha": "0525eae"
|
||||
"image_sha": "cc09fd3"
|
||||
},
|
||||
{
|
||||
"distro_name": "debian",
|
||||
"distro_version": "bookworm",
|
||||
"compiler_name": "gcc",
|
||||
"compiler_version": "13",
|
||||
"image_sha": "0525eae"
|
||||
"image_sha": "cc09fd3"
|
||||
},
|
||||
{
|
||||
"distro_name": "debian",
|
||||
"distro_version": "bookworm",
|
||||
"compiler_name": "gcc",
|
||||
"compiler_version": "14",
|
||||
"image_sha": "0525eae"
|
||||
"image_sha": "cc09fd3"
|
||||
},
|
||||
{
|
||||
"distro_name": "debian",
|
||||
"distro_version": "bookworm",
|
||||
"compiler_name": "gcc",
|
||||
"compiler_version": "15",
|
||||
"image_sha": "0525eae"
|
||||
"image_sha": "cc09fd3"
|
||||
},
|
||||
{
|
||||
"distro_name": "debian",
|
||||
"distro_version": "bookworm",
|
||||
"compiler_name": "clang",
|
||||
"compiler_version": "16",
|
||||
"image_sha": "0525eae"
|
||||
"image_sha": "cc09fd3"
|
||||
},
|
||||
{
|
||||
"distro_name": "debian",
|
||||
"distro_version": "bookworm",
|
||||
"compiler_name": "clang",
|
||||
"compiler_version": "17",
|
||||
"image_sha": "0525eae"
|
||||
"image_sha": "cc09fd3"
|
||||
},
|
||||
{
|
||||
"distro_name": "debian",
|
||||
"distro_version": "bookworm",
|
||||
"compiler_name": "clang",
|
||||
"compiler_version": "18",
|
||||
"image_sha": "0525eae"
|
||||
"image_sha": "cc09fd3"
|
||||
},
|
||||
{
|
||||
"distro_name": "debian",
|
||||
"distro_version": "bookworm",
|
||||
"compiler_name": "clang",
|
||||
"compiler_version": "19",
|
||||
"image_sha": "0525eae"
|
||||
"image_sha": "cc09fd3"
|
||||
},
|
||||
{
|
||||
"distro_name": "debian",
|
||||
"distro_version": "bookworm",
|
||||
"compiler_name": "clang",
|
||||
"compiler_version": "20",
|
||||
"image_sha": "0525eae"
|
||||
"image_sha": "cc09fd3"
|
||||
},
|
||||
{
|
||||
"distro_name": "debian",
|
||||
"distro_version": "trixie",
|
||||
"compiler_name": "gcc",
|
||||
"compiler_version": "14",
|
||||
"image_sha": "0525eae"
|
||||
"image_sha": "cc09fd3"
|
||||
},
|
||||
{
|
||||
"distro_name": "debian",
|
||||
"distro_version": "trixie",
|
||||
"compiler_name": "gcc",
|
||||
"compiler_version": "15",
|
||||
"image_sha": "0525eae"
|
||||
"image_sha": "cc09fd3"
|
||||
},
|
||||
{
|
||||
"distro_name": "debian",
|
||||
"distro_version": "trixie",
|
||||
"compiler_name": "clang",
|
||||
"compiler_version": "20",
|
||||
"image_sha": "0525eae"
|
||||
"image_sha": "cc09fd3"
|
||||
},
|
||||
{
|
||||
"distro_name": "debian",
|
||||
"distro_version": "trixie",
|
||||
"compiler_name": "clang",
|
||||
"compiler_version": "21",
|
||||
"image_sha": "0525eae"
|
||||
"image_sha": "cc09fd3"
|
||||
},
|
||||
{
|
||||
"distro_name": "rhel",
|
||||
"distro_version": "8",
|
||||
"compiler_name": "gcc",
|
||||
"compiler_version": "14",
|
||||
"image_sha": "e1782cd"
|
||||
"image_sha": "cc09fd3"
|
||||
},
|
||||
{
|
||||
"distro_name": "rhel",
|
||||
"distro_version": "8",
|
||||
"compiler_name": "clang",
|
||||
"compiler_version": "any",
|
||||
"image_sha": "e1782cd"
|
||||
"image_sha": "cc09fd3"
|
||||
},
|
||||
{
|
||||
"distro_name": "rhel",
|
||||
"distro_version": "9",
|
||||
"compiler_name": "gcc",
|
||||
"compiler_version": "12",
|
||||
"image_sha": "e1782cd"
|
||||
"image_sha": "cc09fd3"
|
||||
},
|
||||
{
|
||||
"distro_name": "rhel",
|
||||
"distro_version": "9",
|
||||
"compiler_name": "gcc",
|
||||
"compiler_version": "13",
|
||||
"image_sha": "e1782cd"
|
||||
"image_sha": "cc09fd3"
|
||||
},
|
||||
{
|
||||
"distro_name": "rhel",
|
||||
"distro_version": "9",
|
||||
"compiler_name": "gcc",
|
||||
"compiler_version": "14",
|
||||
"image_sha": "e1782cd"
|
||||
"image_sha": "cc09fd3"
|
||||
},
|
||||
{
|
||||
"distro_name": "rhel",
|
||||
"distro_version": "9",
|
||||
"compiler_name": "clang",
|
||||
"compiler_version": "any",
|
||||
"image_sha": "e1782cd"
|
||||
"image_sha": "cc09fd3"
|
||||
},
|
||||
{
|
||||
"distro_name": "rhel",
|
||||
"distro_version": "10",
|
||||
"compiler_name": "gcc",
|
||||
"compiler_version": "14",
|
||||
"image_sha": "e1782cd"
|
||||
"image_sha": "cc09fd3"
|
||||
},
|
||||
{
|
||||
"distro_name": "rhel",
|
||||
"distro_version": "10",
|
||||
"compiler_name": "clang",
|
||||
"compiler_version": "any",
|
||||
"image_sha": "e1782cd"
|
||||
"image_sha": "cc09fd3"
|
||||
},
|
||||
{
|
||||
"distro_name": "ubuntu",
|
||||
"distro_version": "jammy",
|
||||
"compiler_name": "gcc",
|
||||
"compiler_version": "12",
|
||||
"image_sha": "e1782cd"
|
||||
"image_sha": "cc09fd3"
|
||||
},
|
||||
{
|
||||
"distro_name": "ubuntu",
|
||||
"distro_version": "noble",
|
||||
"compiler_name": "gcc",
|
||||
"compiler_version": "13",
|
||||
"image_sha": "e1782cd"
|
||||
"image_sha": "cc09fd3"
|
||||
},
|
||||
{
|
||||
"distro_name": "ubuntu",
|
||||
"distro_version": "noble",
|
||||
"compiler_name": "gcc",
|
||||
"compiler_version": "14",
|
||||
"image_sha": "e1782cd"
|
||||
"image_sha": "cc09fd3"
|
||||
},
|
||||
{
|
||||
"distro_name": "ubuntu",
|
||||
"distro_version": "noble",
|
||||
"compiler_name": "clang",
|
||||
"compiler_version": "16",
|
||||
"image_sha": "e1782cd"
|
||||
"image_sha": "cc09fd3"
|
||||
},
|
||||
{
|
||||
"distro_name": "ubuntu",
|
||||
"distro_version": "noble",
|
||||
"compiler_name": "clang",
|
||||
"compiler_version": "17",
|
||||
"image_sha": "e1782cd"
|
||||
"image_sha": "cc09fd3"
|
||||
},
|
||||
{
|
||||
"distro_name": "ubuntu",
|
||||
"distro_version": "noble",
|
||||
"compiler_name": "clang",
|
||||
"compiler_version": "18",
|
||||
"image_sha": "e1782cd"
|
||||
"image_sha": "cc09fd3"
|
||||
},
|
||||
{
|
||||
"distro_name": "ubuntu",
|
||||
"distro_version": "noble",
|
||||
"compiler_name": "clang",
|
||||
"compiler_version": "19",
|
||||
"image_sha": "e1782cd"
|
||||
"image_sha": "cc09fd3"
|
||||
}
|
||||
],
|
||||
"build_type": ["Debug", "Release"],
|
||||
|
||||
3
.github/workflows/on-pr.yml
vendored
3
.github/workflows/on-pr.yml
vendored
@@ -114,6 +114,9 @@ jobs:
|
||||
matrix:
|
||||
os: [linux, macos, windows]
|
||||
with:
|
||||
# Enable ccache only for events targeting the XRPLF repository, since
|
||||
# other accounts will not have access to our remote cache storage.
|
||||
ccache_enabled: ${{ github.repository_owner == 'XRPLF' }}
|
||||
os: ${{ matrix.os }}
|
||||
secrets:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
6
.github/workflows/on-trigger.yml
vendored
6
.github/workflows/on-trigger.yml
vendored
@@ -68,6 +68,12 @@ jobs:
|
||||
matrix:
|
||||
os: [linux, macos, windows]
|
||||
with:
|
||||
# Enable ccache only for events targeting the XRPLF repository, since
|
||||
# other accounts will not have access to our remote cache storage.
|
||||
# However, we do not enable ccache for events targeting the master or a
|
||||
# release branch, to protect against the rare case that the output
|
||||
# produced by ccache is not identical to a regular compilation.
|
||||
ccache_enabled: ${{ github.repository_owner == 'XRPLF' && !(github.base_ref == 'master' || startsWith(github.base_ref, 'release')) }}
|
||||
os: ${{ matrix.os }}
|
||||
strategy_matrix: ${{ github.event_name == 'schedule' && 'all' || 'minimal' }}
|
||||
secrets:
|
||||
|
||||
2
.github/workflows/pre-commit.yml
vendored
2
.github/workflows/pre-commit.yml
vendored
@@ -9,7 +9,7 @@ on:
|
||||
jobs:
|
||||
# Call the workflow in the XRPLF/actions repo that runs the pre-commit hooks.
|
||||
run-hooks:
|
||||
uses: XRPLF/actions/.github/workflows/pre-commit.yml@34790936fae4c6c751f62ec8c06696f9c1a5753a
|
||||
uses: XRPLF/actions/.github/workflows/pre-commit.yml@5ca417783f0312ab26d6f48b85c78edf1de99bbd
|
||||
with:
|
||||
runs_on: ubuntu-latest
|
||||
container: '{ "image": "ghcr.io/xrplf/ci/tools-rippled-pre-commit:sha-a8c7be1" }'
|
||||
|
||||
4
.github/workflows/publish-docs.yml
vendored
4
.github/workflows/publish-docs.yml
vendored
@@ -22,7 +22,7 @@ defaults:
|
||||
shell: bash
|
||||
|
||||
env:
|
||||
BUILD_DIR: .build
|
||||
BUILD_DIR: build
|
||||
NPROC_SUBTRACT: 2
|
||||
|
||||
jobs:
|
||||
@@ -36,7 +36,7 @@ jobs:
|
||||
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
|
||||
|
||||
- name: Get number of processors
|
||||
uses: XRPLF/actions/.github/actions/get-nproc@046b1620f6bfd6cd0985dc82c3df02786801fe0a
|
||||
uses: XRPLF/actions/get-nproc@2ece4ec6ab7de266859a6f053571425b2bd684b6
|
||||
id: nproc
|
||||
with:
|
||||
subtract: ${{ env.NPROC_SUBTRACT }}
|
||||
|
||||
87
.github/workflows/reusable-build-test-config.yml
vendored
87
.github/workflows/reusable-build-test-config.yml
vendored
@@ -3,11 +3,6 @@ name: Build and test configuration
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
build_dir:
|
||||
description: "The directory where to build."
|
||||
required: true
|
||||
type: string
|
||||
|
||||
build_only:
|
||||
description: 'Whether to only build or to build and test the code ("true", "false").'
|
||||
required: true
|
||||
@@ -15,8 +10,14 @@ on:
|
||||
|
||||
build_type:
|
||||
description: 'The build type to use ("Debug", "Release").'
|
||||
type: string
|
||||
required: true
|
||||
type: string
|
||||
|
||||
ccache_enabled:
|
||||
description: "Whether to enable ccache."
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
cmake_args:
|
||||
description: "Additional arguments to pass to CMake."
|
||||
@@ -26,8 +27,8 @@ on:
|
||||
|
||||
cmake_target:
|
||||
description: "The CMake target to build."
|
||||
type: string
|
||||
required: true
|
||||
type: string
|
||||
|
||||
runs_on:
|
||||
description: Runner to run the job on as a JSON string
|
||||
@@ -59,6 +60,11 @@ defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
env:
|
||||
# Conan installs the generators in the build/generators directory, see the
|
||||
# layout() method in conanfile.py. We then run CMake from the build directory.
|
||||
BUILD_DIR: build
|
||||
|
||||
jobs:
|
||||
build-and-test:
|
||||
name: ${{ inputs.config_name }}
|
||||
@@ -66,26 +72,47 @@ jobs:
|
||||
container: ${{ inputs.image != '' && inputs.image || null }}
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
ENABLED_VOIDSTAR: ${{ contains(inputs.cmake_args, '-Dvoidstar=ON') }}
|
||||
ENABLED_COVERAGE: ${{ contains(inputs.cmake_args, '-Dcoverage=ON') }}
|
||||
# Use a namespace to keep the objects separate for each configuration.
|
||||
CCACHE_NAMESPACE: ${{ inputs.config_name }}
|
||||
# Ccache supports both Redis and HTTP endpoints.
|
||||
# * For Redis, use the following format: redis://ip:port, see
|
||||
# https://github.com/ccache/ccache/wiki/Redis-storage. Note that TLS is
|
||||
# not directly supported by ccache, and requires use of a proxy.
|
||||
# * For HTTP use the following format: http://ip:port/cache when using
|
||||
# nginx as backend or http://ip:port|layout=bazel when using Bazel
|
||||
# Remote Cache, see https://github.com/ccache/ccache/wiki/HTTP-storage.
|
||||
# Note that HTTPS is not directly supported by ccache.
|
||||
CCACHE_REMOTE_ONLY: true
|
||||
CCACHE_REMOTE_STORAGE: http://cache.dev.ripplex.io:8080|layout=bazel
|
||||
# Ignore the creation and modification timestamps on files, since the
|
||||
# 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.
|
||||
COVERAGE_ENABLED: ${{ contains(inputs.cmake_args, '-Dcoverage=ON') }}
|
||||
VOIDSTAR_ENABLED: ${{ contains(inputs.cmake_args, '-Dvoidstar=ON') }}
|
||||
steps:
|
||||
- name: Cleanup workspace (macOS and Windows)
|
||||
if: ${{ runner.os == 'macOS' || runner.os == 'Windows' }}
|
||||
uses: XRPLF/actions/.github/actions/cleanup-workspace@01b244d2718865d427b499822fbd3f15e7197fcc
|
||||
uses: XRPLF/actions/cleanup-workspace@2ece4ec6ab7de266859a6f053571425b2bd684b6
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
|
||||
|
||||
- name: Prepare runner
|
||||
uses: XRPLF/actions/.github/actions/prepare-runner@99685816bb60a95a66852f212f382580e180df3a
|
||||
uses: XRPLF/actions/prepare-runner@121d1de2775d486d46140b9a91b32d5002c08153
|
||||
with:
|
||||
disable_ccache: false
|
||||
enable_ccache: ${{ inputs.ccache_enabled }}
|
||||
|
||||
- name: Set ccache log file
|
||||
if: ${{ inputs.ccache_enabled && runner.debug == '1' }}
|
||||
run: echo "CCACHE_LOGFILE=${{ runner.temp }}/ccache.log" >> "${GITHUB_ENV}"
|
||||
|
||||
- name: Print build environment
|
||||
uses: ./.github/actions/print-env
|
||||
|
||||
- name: Get number of processors
|
||||
uses: XRPLF/actions/.github/actions/get-nproc@046b1620f6bfd6cd0985dc82c3df02786801fe0a
|
||||
uses: XRPLF/actions/get-nproc@2ece4ec6ab7de266859a6f053571425b2bd684b6
|
||||
id: nproc
|
||||
with:
|
||||
subtract: ${{ inputs.nproc_subtract }}
|
||||
@@ -96,7 +123,6 @@ jobs:
|
||||
- name: Build dependencies
|
||||
uses: ./.github/actions/build-deps
|
||||
with:
|
||||
build_dir: ${{ inputs.build_dir }}
|
||||
build_nproc: ${{ steps.nproc.outputs.nproc }}
|
||||
build_type: ${{ inputs.build_type }}
|
||||
# Set the verbosity to "quiet" for Windows to avoid an excessive
|
||||
@@ -104,7 +130,7 @@ jobs:
|
||||
log_verbosity: ${{ runner.os == 'Windows' && 'quiet' || 'verbose' }}
|
||||
|
||||
- name: Configure CMake
|
||||
working-directory: ${{ inputs.build_dir }}
|
||||
working-directory: ${{ env.BUILD_DIR }}
|
||||
env:
|
||||
BUILD_TYPE: ${{ inputs.build_type }}
|
||||
CMAKE_ARGS: ${{ inputs.cmake_args }}
|
||||
@@ -117,7 +143,7 @@ jobs:
|
||||
..
|
||||
|
||||
- name: Build the binary
|
||||
working-directory: ${{ inputs.build_dir }}
|
||||
working-directory: ${{ env.BUILD_DIR }}
|
||||
env:
|
||||
BUILD_NPROC: ${{ steps.nproc.outputs.nproc }}
|
||||
BUILD_TYPE: ${{ inputs.build_type }}
|
||||
@@ -129,11 +155,18 @@ jobs:
|
||||
--parallel "${BUILD_NPROC}" \
|
||||
--target "${CMAKE_TARGET}"
|
||||
|
||||
- name: Show ccache statistics
|
||||
if: ${{ inputs.ccache_enabled }}
|
||||
run: |
|
||||
ccache --show-stats -vv
|
||||
if [ '${{ runner.debug }}' = '1' ]; then
|
||||
cat "${CCACHE_LOGFILE}"
|
||||
curl ${CCACHE_REMOTE_STORAGE%|*}/status || true
|
||||
fi
|
||||
|
||||
- name: Upload the binary (Linux)
|
||||
if: ${{ github.repository_owner == 'XRPLF' && runner.os == 'Linux' }}
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
env:
|
||||
BUILD_DIR: ${{ inputs.build_dir }}
|
||||
with:
|
||||
name: xrpld-${{ inputs.config_name }}
|
||||
path: ${{ env.BUILD_DIR }}/xrpld
|
||||
@@ -142,7 +175,7 @@ jobs:
|
||||
|
||||
- name: Check linking (Linux)
|
||||
if: ${{ runner.os == 'Linux' }}
|
||||
working-directory: ${{ inputs.build_dir }}
|
||||
working-directory: ${{ env.BUILD_DIR }}
|
||||
run: |
|
||||
ldd ./xrpld
|
||||
if [ "$(ldd ./xrpld | grep -E '(libstdc\+\+|libgcc)' | wc -l)" -eq 0 ]; then
|
||||
@@ -153,14 +186,14 @@ jobs:
|
||||
fi
|
||||
|
||||
- name: Verify presence of instrumentation (Linux)
|
||||
if: ${{ runner.os == 'Linux' && env.ENABLED_VOIDSTAR == 'true' }}
|
||||
working-directory: ${{ inputs.build_dir }}
|
||||
if: ${{ runner.os == 'Linux' && env.VOIDSTAR_ENABLED == 'true' }}
|
||||
working-directory: ${{ env.BUILD_DIR }}
|
||||
run: |
|
||||
./xrpld --version | grep libvoidstar
|
||||
|
||||
- name: Run the separate tests
|
||||
if: ${{ !inputs.build_only }}
|
||||
working-directory: ${{ inputs.build_dir }}
|
||||
working-directory: ${{ env.BUILD_DIR }}
|
||||
# Windows locks some of the build files while running tests, and parallel jobs can collide
|
||||
env:
|
||||
BUILD_TYPE: ${{ inputs.build_type }}
|
||||
@@ -173,7 +206,7 @@ jobs:
|
||||
|
||||
- name: Run the embedded tests
|
||||
if: ${{ !inputs.build_only }}
|
||||
working-directory: ${{ runner.os == 'Windows' && format('{0}/{1}', inputs.build_dir, inputs.build_type) || inputs.build_dir }}
|
||||
working-directory: ${{ runner.os == 'Windows' && format('{0}/{1}', env.BUILD_DIR, inputs.build_type) || env.BUILD_DIR }}
|
||||
env:
|
||||
BUILD_NPROC: ${{ steps.nproc.outputs.nproc }}
|
||||
run: |
|
||||
@@ -188,8 +221,8 @@ jobs:
|
||||
netstat -an
|
||||
|
||||
- name: Prepare coverage report
|
||||
if: ${{ !inputs.build_only && env.ENABLED_COVERAGE == 'true' }}
|
||||
working-directory: ${{ inputs.build_dir }}
|
||||
if: ${{ !inputs.build_only && env.COVERAGE_ENABLED == 'true' }}
|
||||
working-directory: ${{ env.BUILD_DIR }}
|
||||
env:
|
||||
BUILD_NPROC: ${{ steps.nproc.outputs.nproc }}
|
||||
BUILD_TYPE: ${{ inputs.build_type }}
|
||||
@@ -201,13 +234,13 @@ jobs:
|
||||
--target coverage
|
||||
|
||||
- name: Upload coverage report
|
||||
if: ${{ github.repository_owner == 'XRPLF' && !inputs.build_only && env.ENABLED_COVERAGE == 'true' }}
|
||||
if: ${{ github.repository_owner == 'XRPLF' && !inputs.build_only && env.COVERAGE_ENABLED == 'true' }}
|
||||
uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24 # v5.4.3
|
||||
with:
|
||||
disable_search: true
|
||||
disable_telem: true
|
||||
fail_ci_if_error: true
|
||||
files: ${{ inputs.build_dir }}/coverage.xml
|
||||
files: ${{ env.BUILD_DIR }}/coverage.xml
|
||||
plugins: noop
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
verbose: true
|
||||
|
||||
13
.github/workflows/reusable-build-test.yml
vendored
13
.github/workflows/reusable-build-test.yml
vendored
@@ -8,21 +8,24 @@ name: Build and test
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
build_dir:
|
||||
description: "The directory where to build."
|
||||
ccache_enabled:
|
||||
description: "Whether to enable ccache."
|
||||
required: false
|
||||
type: string
|
||||
default: ".build"
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
os:
|
||||
description: 'The operating system to use for the build ("linux", "macos", "windows").'
|
||||
required: true
|
||||
type: string
|
||||
|
||||
strategy_matrix:
|
||||
# TODO: Support additional strategies, e.g. "ubuntu" for generating all Ubuntu configurations.
|
||||
description: 'The strategy matrix to use for generating the configurations ("minimal", "all").'
|
||||
required: false
|
||||
type: string
|
||||
default: "minimal"
|
||||
|
||||
secrets:
|
||||
CODECOV_TOKEN:
|
||||
description: "The Codecov token to use for uploading coverage reports."
|
||||
@@ -46,9 +49,9 @@ jobs:
|
||||
matrix: ${{ fromJson(needs.generate-matrix.outputs.matrix) }}
|
||||
max-parallel: 10
|
||||
with:
|
||||
build_dir: ${{ inputs.build_dir }}
|
||||
build_only: ${{ matrix.build_only }}
|
||||
build_type: ${{ matrix.build_type }}
|
||||
ccache_enabled: ${{ inputs.ccache_enabled }}
|
||||
cmake_args: ${{ matrix.cmake_args }}
|
||||
cmake_target: ${{ matrix.cmake_target }}
|
||||
runs_on: ${{ toJSON(matrix.architecture.runner) }}
|
||||
|
||||
2
.github/workflows/reusable-check-rename.yml
vendored
2
.github/workflows/reusable-check-rename.yml
vendored
@@ -29,6 +29,8 @@ jobs:
|
||||
run: .github/scripts/rename/binary.sh .
|
||||
- name: Check namespaces
|
||||
run: .github/scripts/rename/namespace.sh .
|
||||
- name: Check config name
|
||||
run: .github/scripts/rename/config.sh .
|
||||
- name: Check for differences
|
||||
env:
|
||||
MESSAGE: |
|
||||
|
||||
9
.github/workflows/upload-conan-deps.yml
vendored
9
.github/workflows/upload-conan-deps.yml
vendored
@@ -64,21 +64,21 @@ jobs:
|
||||
steps:
|
||||
- name: Cleanup workspace (macOS and Windows)
|
||||
if: ${{ runner.os == 'macOS' || runner.os == 'Windows' }}
|
||||
uses: XRPLF/actions/.github/actions/cleanup-workspace@01b244d2718865d427b499822fbd3f15e7197fcc
|
||||
uses: XRPLF/actions/cleanup-workspace@2ece4ec6ab7de266859a6f053571425b2bd684b6
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
|
||||
|
||||
- name: Prepare runner
|
||||
uses: XRPLF/actions/.github/actions/prepare-runner@99685816bb60a95a66852f212f382580e180df3a
|
||||
uses: XRPLF/actions/prepare-runner@65da1c59e81965eeb257caa3587b9d45066fb925
|
||||
with:
|
||||
disable_ccache: false
|
||||
enable_ccache: false
|
||||
|
||||
- name: Print build environment
|
||||
uses: ./.github/actions/print-env
|
||||
|
||||
- name: Get number of processors
|
||||
uses: XRPLF/actions/.github/actions/get-nproc@046b1620f6bfd6cd0985dc82c3df02786801fe0a
|
||||
uses: XRPLF/actions/get-nproc@2ece4ec6ab7de266859a6f053571425b2bd684b6
|
||||
id: nproc
|
||||
with:
|
||||
subtract: ${{ env.NPROC_SUBTRACT }}
|
||||
@@ -92,7 +92,6 @@ jobs:
|
||||
- name: Build dependencies
|
||||
uses: ./.github/actions/build-deps
|
||||
with:
|
||||
build_dir: .build
|
||||
build_nproc: ${{ steps.nproc.outputs.nproc }}
|
||||
build_type: ${{ matrix.build_type }}
|
||||
force_build: ${{ github.event_name == 'schedule' || github.event.inputs.force_source_build == 'true' }}
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,4 +1,5 @@
|
||||
# .gitignore
|
||||
# cspell: disable
|
||||
|
||||
# Macintosh Desktop Services Store files.
|
||||
.DS_Store
|
||||
@@ -35,6 +36,7 @@ gmon.out
|
||||
|
||||
# Customized configs.
|
||||
/rippled.cfg
|
||||
/xrpld.cfg
|
||||
/validators.txt
|
||||
|
||||
# Locally patched Conan recipes
|
||||
|
||||
@@ -36,6 +36,21 @@ repos:
|
||||
hooks:
|
||||
- id: black
|
||||
|
||||
- repo: https://github.com/streetsidesoftware/cspell-cli
|
||||
rev: v9.2.0
|
||||
hooks:
|
||||
- id: cspell # Spell check changed files
|
||||
exclude: .config/cspell.config.yaml
|
||||
- id: cspell # Spell check the commit message
|
||||
name: check commit message spelling
|
||||
args:
|
||||
- --no-must-find-files
|
||||
- --no-progress
|
||||
- --no-summary
|
||||
- --files
|
||||
- .git/COMMIT_EDITMSG
|
||||
stages: [commit-msg]
|
||||
|
||||
exclude: |
|
||||
(?x)^(
|
||||
external/.*|
|
||||
|
||||
@@ -28,6 +28,9 @@ elseif(MSVC)
|
||||
add_compile_options(/wd4068) # Ignore unknown pragmas
|
||||
endif()
|
||||
|
||||
# Enable ccache to speed up builds.
|
||||
include(Ccache)
|
||||
|
||||
# make GIT_COMMIT_HASH define available to all sources
|
||||
find_package(Git)
|
||||
if(Git_FOUND)
|
||||
@@ -147,5 +150,4 @@ include(XrplValidatorKeys)
|
||||
if(tests)
|
||||
include(CTest)
|
||||
add_subdirectory(src/tests/libxrpl)
|
||||
add_subdirectory(src/doctest)
|
||||
endif()
|
||||
|
||||
@@ -555,16 +555,16 @@ Rippled uses a linear workflow model that can be summarized as:
|
||||
git fetch --multiple upstreams user1 user2 user3 [...]
|
||||
git checkout -B release-next --no-track upstream/develop
|
||||
|
||||
# Only do an ff-only merge if prbranch1 is either already
|
||||
# Only do an ff-only merge if pr-branch1 is either already
|
||||
# squashed, or needs to be merged with separate commits,
|
||||
# and has no merge commits.
|
||||
# Use -S on the ff-only merge if prbranch1 isn't signed.
|
||||
git merge [-S] --ff-only user1/prbranch1
|
||||
# Use -S on the ff-only merge if pr-branch1 isn't signed.
|
||||
git merge [-S] --ff-only user1/pr-branch1
|
||||
|
||||
git merge --squash user2/prbranch2
|
||||
git merge --squash user2/pr-branch2
|
||||
git commit -S # Use the commit message provided on the PR
|
||||
|
||||
git merge --squash user3/prbranch3
|
||||
git merge --squash user3/pr-branch3
|
||||
git commit -S # Use the commit message provided on the PR
|
||||
|
||||
[...]
|
||||
@@ -876,7 +876,7 @@ git push --delete upstream-push master-next
|
||||
|
||||
#### Special cases: point releases, hotfixes, etc.
|
||||
|
||||
On occassion, a bug or issue is discovered in a version that already
|
||||
On occasion, a bug or issue is discovered in a version that already
|
||||
had a final release. Most of the time, development will have started
|
||||
on the next version, and will usually have changes in `develop`
|
||||
and often in `release`.
|
||||
|
||||
@@ -42,7 +42,7 @@ For more information on responsible disclosure, please read this [Wikipedia arti
|
||||
|
||||
## Report Handling Process
|
||||
|
||||
Please report the bug directly to us and limit further disclosure. If you want to prove that you knew the bug as of a given time, consider using a cryptographic precommitment: hash the content of your report and publish the hash on a medium of your choice (e.g. on Twitter or as a memo in a transaction) as "proof" that you had written the text at a given point in time.
|
||||
Please report the bug directly to us and limit further disclosure. If you want to prove that you knew the bug as of a given time, consider using a cryptographic pre-commitment: hash the content of your report and publish the hash on a medium of your choice (e.g. on Twitter or as a memo in a transaction) as "proof" that you had written the text at a given point in time.
|
||||
|
||||
Once we receive a report, we:
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#
|
||||
# Default validators.txt
|
||||
#
|
||||
# This file is located in the same folder as your rippled.cfg file
|
||||
# This file is located in the same folder as your xrpld.cfg file
|
||||
# and defines which validators your server trusts not to collude.
|
||||
#
|
||||
# This file is UTF-8 with DOS, UNIX, or Mac style line endings.
|
||||
|
||||
@@ -29,18 +29,18 @@
|
||||
#
|
||||
# Purpose
|
||||
#
|
||||
# This file documents and provides examples of all rippled server process
|
||||
# configuration options. When the rippled server instance is launched, it
|
||||
# This file documents and provides examples of all xrpld server process
|
||||
# configuration options. When the xrpld server instance is launched, it
|
||||
# looks for a file with the following name:
|
||||
#
|
||||
# rippled.cfg
|
||||
# xrpld.cfg
|
||||
#
|
||||
# For more information on where the rippled server instance searches for the
|
||||
# For more information on where the xrpld server instance searches for the
|
||||
# file, visit:
|
||||
#
|
||||
# https://xrpl.org/commandline-usage.html#generic-options
|
||||
#
|
||||
# This file should be named rippled.cfg. This file is UTF-8 with DOS, UNIX,
|
||||
# This file should be named xrpld.cfg. This file is UTF-8 with DOS, UNIX,
|
||||
# or Mac style end of lines. Blank lines and lines beginning with '#' are
|
||||
# ignored. Undefined sections are reserved. No escapes are currently defined.
|
||||
#
|
||||
@@ -89,8 +89,8 @@
|
||||
#
|
||||
#
|
||||
#
|
||||
# rippled offers various server protocols to clients making inbound
|
||||
# connections. The listening ports rippled uses are "universal" ports
|
||||
# xrpld offers various server protocols to clients making inbound
|
||||
# connections. The listening ports xrpld uses are "universal" ports
|
||||
# which may be configured to handshake in one or more of the available
|
||||
# supported protocols. These universal ports simplify administration:
|
||||
# A single open port can be used for multiple protocols.
|
||||
@@ -103,7 +103,7 @@
|
||||
#
|
||||
# A list of port names and key/value pairs. A port name must start with a
|
||||
# letter and contain only letters and numbers. The name is not case-sensitive.
|
||||
# For each name in this list, rippled will look for a configuration file
|
||||
# For each name in this list, xrpld will look for a configuration file
|
||||
# section with the same name and use it to create a listening port. The
|
||||
# name is informational only; the choice of name does not affect the function
|
||||
# of the listening port.
|
||||
@@ -134,7 +134,7 @@
|
||||
# ip = 127.0.0.1
|
||||
# protocol = http
|
||||
#
|
||||
# When rippled is used as a command line client (for example, issuing a
|
||||
# When xrpld is used as a command line client (for example, issuing a
|
||||
# server stop command), the first port advertising the http or https
|
||||
# protocol will be used to make the connection.
|
||||
#
|
||||
@@ -175,7 +175,7 @@
|
||||
# same time. It is possible have both Websockets and Secure Websockets
|
||||
# together in one port.
|
||||
#
|
||||
# NOTE If no ports support the peer protocol, rippled cannot
|
||||
# NOTE If no ports support the peer protocol, xrpld cannot
|
||||
# receive incoming peer connections or become a superpeer.
|
||||
#
|
||||
# limit = <number>
|
||||
@@ -194,7 +194,7 @@
|
||||
# required. IP address restrictions, if any, will be checked in addition
|
||||
# to the credentials specified here.
|
||||
#
|
||||
# When acting in the client role, rippled will supply these credentials
|
||||
# When acting in the client role, xrpld will supply these credentials
|
||||
# using HTTP's Basic Authentication headers when making outbound HTTP/S
|
||||
# requests.
|
||||
#
|
||||
@@ -218,7 +218,7 @@
|
||||
# administrative commands.
|
||||
#
|
||||
# NOTE A common configuration value for the admin field is "localhost".
|
||||
# If you are listening on all IPv4/IPv6 addresses by specifing
|
||||
# If you are listening on all IPv4/IPv6 addresses by specifying
|
||||
# ip = :: then you can use admin = ::ffff:127.0.0.1,::1 to allow
|
||||
# administrative access from both IPv4 and IPv6 localhost
|
||||
# connections.
|
||||
@@ -237,7 +237,7 @@
|
||||
# WS, or WSS protocol interfaces. If administrative commands are
|
||||
# disabled for a port, these credentials have no effect.
|
||||
#
|
||||
# When acting in the client role, rippled will supply these credentials
|
||||
# When acting in the client role, xrpld will supply these credentials
|
||||
# in the submitted JSON for any administrative command requests when
|
||||
# invoking JSON-RPC commands on remote servers.
|
||||
#
|
||||
@@ -258,7 +258,7 @@
|
||||
# resource controls will default to those for non-administrative users.
|
||||
#
|
||||
# The secure_gateway IP addresses are intended to represent
|
||||
# proxies. Since rippled trusts these hosts, they must be
|
||||
# proxies. Since xrpld trusts these hosts, they must be
|
||||
# responsible for properly authenticating the remote user.
|
||||
#
|
||||
# If some IP addresses are included for both "admin" and
|
||||
@@ -272,7 +272,7 @@
|
||||
# Use the specified files when configuring SSL on the port.
|
||||
#
|
||||
# NOTE If no files are specified and secure protocols are selected,
|
||||
# rippled will generate an internal self-signed certificate.
|
||||
# xrpld will generate an internal self-signed certificate.
|
||||
#
|
||||
# The files have these meanings:
|
||||
#
|
||||
@@ -297,12 +297,12 @@
|
||||
# Control the ciphers which the server will support over SSL on the port,
|
||||
# specified using the OpenSSL "cipher list format".
|
||||
#
|
||||
# NOTE If unspecified, rippled will automatically configure a modern
|
||||
# NOTE If unspecified, xrpld will automatically configure a modern
|
||||
# cipher suite. This default suite should be widely supported.
|
||||
#
|
||||
# You should not modify this string unless you have a specific
|
||||
# reason and cryptographic expertise. Incorrect modification may
|
||||
# keep rippled from connecting to other instances of rippled or
|
||||
# keep xrpld from connecting to other instances of xrpld or
|
||||
# prevent RPC and WebSocket clients from connecting.
|
||||
#
|
||||
# send_queue_limit = [1..65535]
|
||||
@@ -382,7 +382,7 @@
|
||||
#-----------------
|
||||
#
|
||||
# These settings control security and access attributes of the Peer to Peer
|
||||
# server section of the rippled process. Peer Protocol implements the
|
||||
# server section of the xrpld process. Peer Protocol implements the
|
||||
# Ripple Payment protocol. It is over peer connections that transactions
|
||||
# and validations are passed from to machine to machine, to determine the
|
||||
# contents of validated ledgers.
|
||||
@@ -396,7 +396,7 @@
|
||||
# true - enables compression
|
||||
# false - disables compression [default].
|
||||
#
|
||||
# The rippled server can save bandwidth by compressing its peer-to-peer communications,
|
||||
# The xrpld server can save bandwidth by compressing its peer-to-peer communications,
|
||||
# at a cost of greater CPU usage. If you enable link compression,
|
||||
# the server automatically compresses communications with peer servers
|
||||
# that also have link compression enabled.
|
||||
@@ -432,7 +432,7 @@
|
||||
#
|
||||
# [ips_fixed]
|
||||
#
|
||||
# List of IP addresses or hostnames to which rippled should always attempt to
|
||||
# List of IP addresses or hostnames to which xrpld should always attempt to
|
||||
# maintain peer connections with. This is useful for manually forming private
|
||||
# networks, for example to configure a validation server that connects to the
|
||||
# Ripple network through a public-facing server, or for building a set
|
||||
@@ -573,7 +573,7 @@
|
||||
#
|
||||
# minimum_txn_in_ledger_standalone = <number>
|
||||
#
|
||||
# Like minimum_txn_in_ledger when rippled is running in standalone
|
||||
# Like minimum_txn_in_ledger when xrpld is running in standalone
|
||||
# mode. Default: 1000.
|
||||
#
|
||||
# target_txn_in_ledger = <number>
|
||||
@@ -710,7 +710,7 @@
|
||||
#
|
||||
# [validator_token]
|
||||
#
|
||||
# This is an alternative to [validation_seed] that allows rippled to perform
|
||||
# This is an alternative to [validation_seed] that allows xrpld to perform
|
||||
# validation without having to store the validator keys on the network
|
||||
# connected server. The field should contain a single token in the form of a
|
||||
# base64-encoded blob.
|
||||
@@ -745,7 +745,7 @@
|
||||
#
|
||||
# Specify the file by its name or path.
|
||||
# Unless an absolute path is specified, it will be considered relative to
|
||||
# the folder in which the rippled.cfg file is located.
|
||||
# the folder in which the xrpld.cfg file is located.
|
||||
#
|
||||
# Examples:
|
||||
# /home/ripple/validators.txt
|
||||
@@ -840,7 +840,7 @@
|
||||
#
|
||||
# 0: Disable the ledger replay feature [default]
|
||||
# 1: Enable the ledger replay feature. With this feature enabled, when
|
||||
# acquiring a ledger from the network, a rippled node only downloads
|
||||
# acquiring a ledger from the network, a xrpld node only downloads
|
||||
# the ledger header and the transactions instead of the whole ledger.
|
||||
# And the ledger is built by applying the transactions to the parent
|
||||
# ledger.
|
||||
@@ -851,7 +851,7 @@
|
||||
#
|
||||
#----------------
|
||||
#
|
||||
# The rippled server instance uses HTTPS GET requests in a variety of
|
||||
# The xrpld server instance uses HTTPS GET requests in a variety of
|
||||
# circumstances, including but not limited to contacting trusted domains to
|
||||
# fetch information such as mapping an email address to a Ripple Payment
|
||||
# Network address.
|
||||
@@ -891,7 +891,7 @@
|
||||
#
|
||||
#------------
|
||||
#
|
||||
# rippled creates 4 SQLite database to hold bookkeeping information
|
||||
# xrpld creates 4 SQLite database to hold bookkeeping information
|
||||
# about transactions, local credentials, and various other things.
|
||||
# It also creates the NodeDB, which holds all the objects that
|
||||
# make up the current and historical ledgers.
|
||||
@@ -902,7 +902,7 @@
|
||||
# the performance of the server.
|
||||
#
|
||||
# Partial pathnames will be considered relative to the location of
|
||||
# the rippled.cfg file.
|
||||
# the xrpld.cfg file.
|
||||
#
|
||||
# [node_db] Settings for the Node Database (required)
|
||||
#
|
||||
@@ -920,11 +920,11 @@
|
||||
# type = NuDB
|
||||
#
|
||||
# NuDB is a high-performance database written by Ripple Labs and optimized
|
||||
# for rippled and solid-state drives.
|
||||
# for xrpld and solid-state drives.
|
||||
#
|
||||
# NuDB maintains its high speed regardless of the amount of history
|
||||
# stored. Online delete may be selected, but is not required. NuDB is
|
||||
# available on all platforms that rippled runs on.
|
||||
# available on all platforms that xrpld runs on.
|
||||
#
|
||||
# type = RocksDB
|
||||
#
|
||||
@@ -1049,7 +1049,7 @@
|
||||
#
|
||||
# recovery_wait_seconds
|
||||
# The online delete process checks periodically
|
||||
# that rippled is still in sync with the network,
|
||||
# that xrpld is still in sync with the network,
|
||||
# and that the validated ledger is less than
|
||||
# 'age_threshold_seconds' old. If not, then continue
|
||||
# sleeping for this number of seconds and
|
||||
@@ -1069,8 +1069,8 @@
|
||||
# The server creates and maintains 4 to 5 bookkeeping SQLite databases in
|
||||
# the 'database_path' location. If you omit this configuration setting,
|
||||
# the server creates a directory called "db" located in the same place as
|
||||
# your rippled.cfg file.
|
||||
# Partial pathnames are relative to the location of the rippled executable.
|
||||
# your xrpld.cfg file.
|
||||
# Partial pathnames are relative to the location of the xrpld executable.
|
||||
#
|
||||
# [sqlite] Tuning settings for the SQLite databases (optional)
|
||||
#
|
||||
@@ -1120,7 +1120,7 @@
|
||||
# The default is "wal", which uses a write-ahead
|
||||
# log to implement database transactions.
|
||||
# Alternately, "memory" saves disk I/O, but if
|
||||
# rippled crashes during a transaction, the
|
||||
# xrpld crashes during a transaction, the
|
||||
# database is likely to be corrupted.
|
||||
# See https://www.sqlite.org/pragma.html#pragma_journal_mode
|
||||
# for more details about the available options.
|
||||
@@ -1130,7 +1130,7 @@
|
||||
# synchronous Valid values: off, normal, full, extra
|
||||
# The default is "normal", which works well with
|
||||
# the "wal" journal mode. Alternatively, "off"
|
||||
# allows rippled to continue as soon as data is
|
||||
# allows xrpld to continue as soon as data is
|
||||
# passed to the OS, which can significantly
|
||||
# increase speed, but risks data corruption if
|
||||
# the host computer crashes before writing that
|
||||
@@ -1144,7 +1144,7 @@
|
||||
# The default is "file", which will use files
|
||||
# for temporary database tables and indices.
|
||||
# Alternatively, "memory" may save I/O, but
|
||||
# rippled does not currently use many, if any,
|
||||
# xrpld does not currently use many, if any,
|
||||
# of these temporary objects.
|
||||
# See https://www.sqlite.org/pragma.html#pragma_temp_store
|
||||
# for more details about the available options.
|
||||
@@ -1173,7 +1173,7 @@
|
||||
#
|
||||
# These settings are designed to help server administrators diagnose
|
||||
# problems, and obtain detailed information about the activities being
|
||||
# performed by the rippled process.
|
||||
# performed by the xrpld process.
|
||||
#
|
||||
#
|
||||
#
|
||||
@@ -1190,7 +1190,7 @@
|
||||
#
|
||||
# Configuration parameters for the Beast. Insight stats collection module.
|
||||
#
|
||||
# Insight is a module that collects information from the areas of rippled
|
||||
# Insight is a module that collects information from the areas of xrpld
|
||||
# that have instrumentation. The configuration parameters control where the
|
||||
# collection metrics are sent. The parameters are expressed as key = value
|
||||
# pairs with no white space. The main parameter is the choice of server:
|
||||
@@ -1199,7 +1199,7 @@
|
||||
#
|
||||
# Choice of server to send metrics to. Currently the only choice is
|
||||
# "statsd" which sends UDP packets to a StatsD daemon, which must be
|
||||
# running while rippled is running. More information on StatsD is
|
||||
# running while xrpld is running. More information on StatsD is
|
||||
# available here:
|
||||
# https://github.com/b/statsd_spec
|
||||
#
|
||||
@@ -1209,7 +1209,7 @@
|
||||
# in the format, n.n.n.n:port.
|
||||
#
|
||||
# "prefix" A string prepended to each collected metric. This is used
|
||||
# to distinguish between different running instances of rippled.
|
||||
# to distinguish between different running instances of xrpld.
|
||||
#
|
||||
# If this section is missing, or the server type is unspecified or unknown,
|
||||
# statistics are not collected or reported.
|
||||
@@ -1236,7 +1236,7 @@
|
||||
#
|
||||
# Example:
|
||||
# [perf]
|
||||
# perf_log=/var/log/rippled/perf.log
|
||||
# perf_log=/var/log/xrpld/perf.log
|
||||
# log_interval=2
|
||||
#
|
||||
#-------------------------------------------------------------------------------
|
||||
@@ -1246,7 +1246,7 @@
|
||||
#----------
|
||||
#
|
||||
# The vote settings configure settings for the entire Ripple network.
|
||||
# While a single instance of rippled cannot unilaterally enforce network-wide
|
||||
# While a single instance of xrpld cannot unilaterally enforce network-wide
|
||||
# settings, these choices become part of the instance's vote during the
|
||||
# consensus process for each voting ledger.
|
||||
#
|
||||
@@ -1260,7 +1260,7 @@
|
||||
# The reference transaction is the simplest form of transaction.
|
||||
# It represents an XRP payment between two parties.
|
||||
#
|
||||
# If this parameter is unspecified, rippled will use an internal
|
||||
# If this parameter is unspecified, xrpld will use an internal
|
||||
# default. Don't change this without understanding the consequences.
|
||||
#
|
||||
# Example:
|
||||
@@ -1272,7 +1272,7 @@
|
||||
# account's XRP balance that is at or below the reserve may only be
|
||||
# spent on transaction fees, and not transferred out of the account.
|
||||
#
|
||||
# If this parameter is unspecified, rippled will use an internal
|
||||
# If this parameter is unspecified, xrpld will use an internal
|
||||
# default. Don't change this without understanding the consequences.
|
||||
#
|
||||
# Example:
|
||||
@@ -1284,7 +1284,7 @@
|
||||
# each ledger item owned by the account. Ledger items an account may
|
||||
# own include trust lines, open orders, and tickets.
|
||||
#
|
||||
# If this parameter is unspecified, rippled will use an internal
|
||||
# If this parameter is unspecified, xrpld will use an internal
|
||||
# default. Don't change this without understanding the consequences.
|
||||
#
|
||||
# Example:
|
||||
@@ -1326,7 +1326,7 @@
|
||||
# tool instead.
|
||||
#
|
||||
# This flag has no effect on the "sign" and "sign_for" command line options
|
||||
# that rippled makes available.
|
||||
# that xrpld makes available.
|
||||
#
|
||||
# The default value of this field is "false"
|
||||
#
|
||||
@@ -1405,7 +1405,7 @@
|
||||
#--------------------
|
||||
#
|
||||
# Administrators can use these values as a starting point for configuring
|
||||
# their instance of rippled, but each value should be checked to make sure
|
||||
# their instance of xrpld, but each value should be checked to make sure
|
||||
# it meets the business requirements for the organization.
|
||||
#
|
||||
# Server
|
||||
@@ -1415,7 +1415,7 @@
|
||||
# "peer"
|
||||
#
|
||||
# Peer protocol open to everyone. This is required to accept
|
||||
# incoming rippled connections. This does not affect automatic
|
||||
# incoming xrpld connections. This does not affect automatic
|
||||
# or manual outgoing Peer protocol connections.
|
||||
#
|
||||
# "rpc"
|
||||
@@ -1432,7 +1432,7 @@
|
||||
#
|
||||
# ETL commands for Clio. We recommend setting secure_gateway
|
||||
# in this section to a comma-separated list of the addresses
|
||||
# of your Clio servers, in order to bypass rippled's rate limiting.
|
||||
# of your Clio servers, in order to bypass xrpld's rate limiting.
|
||||
#
|
||||
# This port is commented out but can be enabled by removing
|
||||
# the '#' from each corresponding line including the entry under [server]
|
||||
@@ -1449,8 +1449,8 @@
|
||||
# NOTE
|
||||
#
|
||||
# To accept connections on well known ports such as 80 (HTTP) or
|
||||
# 443 (HTTPS), most operating systems will require rippled to
|
||||
# run with administrator privileges, or else rippled will not start.
|
||||
# 443 (HTTPS), most operating systems will require xrpld to
|
||||
# run with administrator privileges, or else xrpld will not start.
|
||||
|
||||
[server]
|
||||
port_rpc_admin_local
|
||||
@@ -1496,7 +1496,7 @@ secure_gateway = 127.0.0.1
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
# This is primary persistent datastore for rippled. This includes transaction
|
||||
# This is primary persistent datastore for xrpld. This includes transaction
|
||||
# metadata, account states, and ledger headers. Helpful information can be
|
||||
# found at https://xrpl.org/capacity-planning.html#node-db-type
|
||||
# type=NuDB is recommended for non-validators with fast SSDs. Validators or
|
||||
@@ -1511,19 +1511,19 @@ secure_gateway = 127.0.0.1
|
||||
# deletion.
|
||||
[node_db]
|
||||
type=NuDB
|
||||
path=/var/lib/rippled/db/nudb
|
||||
path=/var/lib/xrpld/db/nudb
|
||||
nudb_block_size=4096
|
||||
online_delete=512
|
||||
advisory_delete=0
|
||||
|
||||
[database_path]
|
||||
/var/lib/rippled/db
|
||||
/var/lib/xrpld/db
|
||||
|
||||
|
||||
# This needs to be an absolute directory reference, not a relative one.
|
||||
# Modify this value as required.
|
||||
[debug_logfile]
|
||||
/var/log/rippled/debug.log
|
||||
/var/log/xrpld/debug.log
|
||||
|
||||
# To use the XRP test network
|
||||
# (see https://xrpl.org/connect-your-rippled-to-the-xrp-test-net.html),
|
||||
@@ -1533,7 +1533,7 @@ advisory_delete=0
|
||||
|
||||
# File containing trusted validator keys or validator list publishers.
|
||||
# Unless an absolute path is specified, it will be considered relative to the
|
||||
# folder in which the rippled.cfg file is located.
|
||||
# folder in which the xrpld.cfg file is located.
|
||||
[validators_file]
|
||||
validators.txt
|
||||
|
||||
57
cmake/Ccache.cmake
Normal file
57
cmake/Ccache.cmake
Normal file
@@ -0,0 +1,57 @@
|
||||
find_program(CCACHE_PATH "ccache")
|
||||
if (NOT CCACHE_PATH)
|
||||
return()
|
||||
endif ()
|
||||
|
||||
# For Linux and macOS we can use the ccache binary directly.
|
||||
if (NOT MSVC)
|
||||
set(CMAKE_C_COMPILER_LAUNCHER "${CCACHE_PATH}")
|
||||
set(CMAKE_CXX_COMPILER_LAUNCHER "${CCACHE_PATH}")
|
||||
message(STATUS "Found ccache: ${CCACHE_PATH}")
|
||||
return()
|
||||
endif ()
|
||||
|
||||
# For Windows more effort is required. The code below is a modified version of
|
||||
# https://github.com/ccache/ccache/wiki/MS-Visual-Studio#usage-with-cmake.
|
||||
if ("${CCACHE_PATH}" MATCHES "chocolatey")
|
||||
message(DEBUG "Ccache path: ${CCACHE_PATH}")
|
||||
# Chocolatey uses a shim executable that we cannot use directly, in which
|
||||
# case we have to find the executable it points to. If we cannot find the
|
||||
# target executable then we cannot use ccache.
|
||||
find_program(BASH_PATH "bash")
|
||||
if (NOT BASH_PATH)
|
||||
message(WARNING "Could not find bash.")
|
||||
return()
|
||||
endif ()
|
||||
|
||||
execute_process(
|
||||
COMMAND bash -c "export LC_ALL='en_US.UTF-8'; ${CCACHE_PATH} --shimgen-noop | grep -oP 'path to executable: \\K.+' | head -c -1"
|
||||
OUTPUT_VARIABLE CCACHE_PATH)
|
||||
|
||||
if (NOT CCACHE_PATH)
|
||||
message(WARNING "Could not find ccache target.")
|
||||
return()
|
||||
endif ()
|
||||
file(TO_CMAKE_PATH "${CCACHE_PATH}" CCACHE_PATH)
|
||||
endif ()
|
||||
message(STATUS "Found ccache: ${CCACHE_PATH}")
|
||||
|
||||
# Tell cmake to use ccache for compiling with Visual Studio.
|
||||
file(COPY_FILE
|
||||
${CCACHE_PATH} ${CMAKE_BINARY_DIR}/cl.exe
|
||||
ONLY_IF_DIFFERENT)
|
||||
set(CMAKE_VS_GLOBALS
|
||||
"CLToolExe=cl.exe"
|
||||
"CLToolPath=${CMAKE_BINARY_DIR}"
|
||||
"TrackFileAccess=false"
|
||||
"UseMultiToolTask=true")
|
||||
|
||||
# By default Visual Studio generators will use /Zi to capture debug information,
|
||||
# which is not compatible with ccache, so tell it to use /Z7 instead.
|
||||
if (MSVC)
|
||||
foreach (var_
|
||||
CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE
|
||||
CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE)
|
||||
string (REPLACE "/Zi" "/Z7" ${var_} "${${var_}}")
|
||||
endforeach ()
|
||||
endif ()
|
||||
@@ -44,6 +44,7 @@ if (MSVC)
|
||||
# omit debug info completely under CI (not needed)
|
||||
if (is_ci)
|
||||
string (REPLACE "/Zi" " " ${var_} "${${var_}}")
|
||||
string (REPLACE "/Z7" " " ${var_} "${${var_}}")
|
||||
endif ()
|
||||
endforeach ()
|
||||
|
||||
@@ -149,7 +150,7 @@ elseif (use_gold AND is_gcc)
|
||||
ERROR_QUIET OUTPUT_VARIABLE LD_VERSION)
|
||||
#[=========================================================[
|
||||
NOTE: THE gold linker inserts -rpath as DT_RUNPATH by
|
||||
default intead of DT_RPATH, so you might have slightly
|
||||
default instead of DT_RPATH, so you might have slightly
|
||||
unexpected runtime ld behavior if you were expecting
|
||||
DT_RPATH. Specify --disable-new-dtags to gold if you do
|
||||
not want the default DT_RUNPATH behavior. This rpath
|
||||
|
||||
@@ -206,7 +206,7 @@ if(xrpld)
|
||||
)
|
||||
exclude_if_included(xrpld)
|
||||
# define a macro for tests that might need to
|
||||
# be exluded or run differently in CI environment
|
||||
# be excluded or run differently in CI environment
|
||||
if(is_ci)
|
||||
target_compile_definitions(xrpld PRIVATE XRPL_RUNNING_IN_CI)
|
||||
endif ()
|
||||
|
||||
@@ -62,7 +62,7 @@ if (is_root_project AND TARGET xrpld)
|
||||
message (\"-- Skipping : \$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/\${DEST}/\${NEWNAME}\")
|
||||
endif ()
|
||||
endmacro()
|
||||
copy_if_not_exists(\"${CMAKE_CURRENT_SOURCE_DIR}/cfg/rippled-example.cfg\" etc rippled.cfg)
|
||||
copy_if_not_exists(\"${CMAKE_CURRENT_SOURCE_DIR}/cfg/xrpld-example.cfg\" etc xrpld.cfg)
|
||||
copy_if_not_exists(\"${CMAKE_CURRENT_SOURCE_DIR}/cfg/validators-example.txt\" etc validators.txt)
|
||||
")
|
||||
install(CODE "
|
||||
|
||||
@@ -68,6 +68,21 @@ if(is_linux)
|
||||
option(perf "Enables flags that assist with perf recording" OFF)
|
||||
option(use_gold "enables detection of gold (binutils) linker" ON)
|
||||
option(use_mold "enables detection of mold (binutils) linker" ON)
|
||||
# Set a default value for the log flag based on the build type.
|
||||
# This provides a sensible default (on for debug, off for release)
|
||||
# while still allowing the user to override it for any build.
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
set(TRUNCATED_LOGS_DEFAULT ON)
|
||||
else()
|
||||
set(TRUNCATED_LOGS_DEFAULT OFF)
|
||||
endif()
|
||||
option(TRUNCATED_THREAD_NAME_LOGS
|
||||
"Show warnings about truncated thread names on Linux."
|
||||
${TRUNCATED_LOGS_DEFAULT}
|
||||
)
|
||||
if(TRUNCATED_THREAD_NAME_LOGS)
|
||||
add_compile_definitions(TRUNCATED_THREAD_NAME_LOGS)
|
||||
endif()
|
||||
else()
|
||||
# we are not ready to allow shared-libs on windows because it would require
|
||||
# export declarations. On macos it's more feasible, but static openssl
|
||||
|
||||
@@ -182,12 +182,10 @@ class Xrpl(ConanFile):
|
||||
libxrpl.libs = [
|
||||
"xrpl",
|
||||
"xrpl.libpb",
|
||||
"ed25519",
|
||||
"secp256k1",
|
||||
]
|
||||
# TODO: Fix the protobufs to include each other relative to
|
||||
# `include/`, not `include/ripple/proto/`.
|
||||
libxrpl.includedirs = ["include", "include/ripple/proto"]
|
||||
# `include/`, not `include/xrpl/proto/`.
|
||||
libxrpl.includedirs = ["include", "include/xrpl/proto"]
|
||||
libxrpl.requires = [
|
||||
"boost::headers",
|
||||
"boost::chrono",
|
||||
|
||||
@@ -134,7 +134,7 @@ validation messages (_PAV_) received from each validator on the node's UNL. Note
|
||||
that the node will only count the validation messages that agree with its own
|
||||
validations.
|
||||
|
||||
We define the **PAV** as the **P**ercentage of **A**greed **V**alidation
|
||||
We define the **PAV** as the Percentage of Agreed Validation
|
||||
messages received for the last N ledgers, where N = 256 by default.
|
||||
|
||||
When the PAV drops below the **_low-water mark_**, the validator is considered
|
||||
|
||||
@@ -43,14 +43,14 @@ alt phase == OPEN
|
||||
alt sqn%256==0
|
||||
CA -[#green]> RM: <font color=green>getValidations
|
||||
CA -[#green]> CA: <font color=green>create UNLModify Tx
|
||||
hnote over CA#lightgreen: use validatations of the last 256 ledgers\nto figure out UNLModify Tx candidates.\nIf any, create UNLModify Tx, and add to TxSet.
|
||||
hnote over CA#lightgreen: use validations of the last 256 ledgers\nto figure out UNLModify Tx candidates.\nIf any, create UNLModify Tx, and add to TxSet.
|
||||
end
|
||||
CA -> GC
|
||||
GC -> CA: propose
|
||||
deactivate CA
|
||||
end
|
||||
else phase == ESTABLISH
|
||||
hnote over GC: receive peer postions
|
||||
hnote over GC: receive peer positions
|
||||
GC -> GC : update our position
|
||||
GC -> CA : propose \n(if position changed)
|
||||
GC -> GC : check if have consensus
|
||||
|
||||
@@ -189,7 +189,7 @@ validations. It checks this on every call to `timerEntry`.
|
||||
- _Wrong Ledger_ indicates the node is not working on the correct prior ledger
|
||||
and does not have it available. It requests that ledger from the network, but
|
||||
continues to work towards consensus this round while waiting. If it had been
|
||||
_proposing_, it will send a special "bowout" proposal to its peers to indicate
|
||||
_proposing_, it will send a special "bow-out" proposal to its peers to indicate
|
||||
its change in mode for the rest of this round. For the duration of the round,
|
||||
it defers to peer positions for determining the consensus outcome as if it
|
||||
were just _observing_.
|
||||
@@ -515,7 +515,7 @@ are excerpts of the generic consensus implementation and of helper types that wi
|
||||
interact with the concrete implementing class.
|
||||
|
||||
```{.cpp}
|
||||
// Represents a transction under dispute this round
|
||||
// Represents a transaction under dispute this round
|
||||
template <class Tx_t, class NodeID_t> class DisputedTx;
|
||||
|
||||
// Represents how the node participates in Consensus this round
|
||||
|
||||
@@ -58,7 +58,7 @@ concept CAdoptTag = std::is_same_v<T, SharedIntrusiveAdoptIncrementStrongTag> ||
|
||||
When the strong pointer count goes to zero, the "partialDestructor" is
|
||||
called. This can be used to destroy as much of the object as possible while
|
||||
still retaining the reference counts. For example, for SHAMapInnerNodes the
|
||||
children may be reset in that function. Note that std::shared_poiner WILL
|
||||
children may be reset in that function. Note that std::shared_pointer WILL
|
||||
run the destructor when the strong count reaches zero, but may not free the
|
||||
memory used by the object until the weak count reaches zero. In rippled, we
|
||||
typically allocate shared pointers with the `make_shared` function. When
|
||||
|
||||
@@ -301,7 +301,7 @@ IntrusiveRefCounts::addWeakReleaseStrongRef() const
|
||||
// change the counts and flags (the count could be atomically changed, but
|
||||
// the flags depend on the current value of the counts).
|
||||
//
|
||||
// Note: If this becomes a perf bottleneck, the `partialDestoryStartedMask`
|
||||
// Note: If this becomes a perf bottleneck, the `partialDestroyStartedMask`
|
||||
// may be able to be set non-atomically. But it is easier to reason about
|
||||
// the code if the flag is set atomically.
|
||||
while (1)
|
||||
|
||||
@@ -221,7 +221,8 @@ public:
|
||||
private:
|
||||
enum {
|
||||
// Maximum line length for log messages.
|
||||
// If the message exceeds this length it will be truncated with elipses.
|
||||
// If the message exceeds this length it will be truncated with
|
||||
// ellipses.
|
||||
maximumMessageCharacters = 12 * 1024
|
||||
};
|
||||
|
||||
|
||||
@@ -152,8 +152,8 @@ public:
|
||||
|
||||
/** Return a "sub slice" of given length starting at the given position
|
||||
|
||||
Note that the subslice encompasses the range [pos, pos + rcount),
|
||||
where rcount is the smaller of count and size() - pos.
|
||||
Note that the subslice encompasses the range [pos, pos + rCount),
|
||||
where rCount is the smaller of count and size() - pos.
|
||||
|
||||
@param pos position of the first character
|
||||
@count requested length
|
||||
|
||||
@@ -31,7 +31,7 @@ template <class Iterator>
|
||||
std::optional<Blob>
|
||||
strUnHex(std::size_t strSize, Iterator begin, Iterator end)
|
||||
{
|
||||
static constexpr std::array<int, 256> const unxtab = []() {
|
||||
static constexpr std::array<int, 256> const digitLookupTable = []() {
|
||||
std::array<int, 256> t{};
|
||||
|
||||
for (auto& x : t)
|
||||
@@ -57,7 +57,7 @@ strUnHex(std::size_t strSize, Iterator begin, Iterator end)
|
||||
|
||||
if (strSize & 1)
|
||||
{
|
||||
int c = unxtab[*iter++];
|
||||
int c = digitLookupTable[*iter++];
|
||||
|
||||
if (c < 0)
|
||||
return {};
|
||||
@@ -67,12 +67,12 @@ strUnHex(std::size_t strSize, Iterator begin, Iterator end)
|
||||
|
||||
while (iter != end)
|
||||
{
|
||||
int cHigh = unxtab[*iter++];
|
||||
int cHigh = digitLookupTable[*iter++];
|
||||
|
||||
if (cHigh < 0)
|
||||
return {};
|
||||
|
||||
int cLow = unxtab[*iter++];
|
||||
int cLow = digitLookupTable[*iter++];
|
||||
|
||||
if (cLow < 0)
|
||||
return {};
|
||||
|
||||
@@ -3189,11 +3189,12 @@ operator==(aged_unordered_container<
|
||||
{
|
||||
if (size() != other.size())
|
||||
return false;
|
||||
for (auto iter(cbegin()), last(cend()), olast(other.cend()); iter != last;
|
||||
for (auto iter(cbegin()), last(cend()), otherLast(other.cend());
|
||||
iter != last;
|
||||
++iter)
|
||||
{
|
||||
auto oiter(other.find(extract(*iter)));
|
||||
if (oiter == olast)
|
||||
auto otherIter(other.find(extract(*iter)));
|
||||
if (otherIter == otherLast)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#ifndef BEAST_CORE_CURRENT_THREAD_NAME_H_INCLUDED
|
||||
#define BEAST_CORE_CURRENT_THREAD_NAME_H_INCLUDED
|
||||
|
||||
#include <boost/predef.h>
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
@@ -16,6 +18,31 @@ namespace beast {
|
||||
void
|
||||
setCurrentThreadName(std::string_view newThreadName);
|
||||
|
||||
#if BOOST_OS_LINUX
|
||||
|
||||
// On Linux, thread names are limited to 16 bytes including the null terminator.
|
||||
// Maximum number of characters is therefore 15.
|
||||
constexpr std::size_t maxThreadNameLength = 15;
|
||||
|
||||
/** Sets the name of the caller thread with compile-time size checking.
|
||||
@tparam N The size of the string literal including null terminator
|
||||
@param newThreadName A string literal to set as the thread name
|
||||
|
||||
This template overload enforces that thread names are at most 16 characters
|
||||
(including null terminator) at compile time, matching Linux's limit.
|
||||
*/
|
||||
template <std::size_t N>
|
||||
void
|
||||
setCurrentThreadName(char const (&newThreadName)[N])
|
||||
{
|
||||
static_assert(
|
||||
N <= maxThreadNameLength + 1,
|
||||
"Thread name cannot exceed 15 characters");
|
||||
|
||||
setCurrentThreadName(std::string_view(newThreadName, N - 1));
|
||||
}
|
||||
#endif
|
||||
|
||||
/** Returns the name of the caller thread.
|
||||
|
||||
The name returned is the name as set by a call to setCurrentThreadName().
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace beast {
|
||||
|
||||
namespace detail {
|
||||
|
||||
// These specializatons get called by the non-member functions to do the work
|
||||
// These specializations get called by the non-member functions to do the work
|
||||
template <class Out, class In>
|
||||
struct LexicalCast;
|
||||
|
||||
|
||||
@@ -203,7 +203,7 @@ struct is_contiguously_hashable<T[N], HashAlgorithm>
|
||||
Throws:
|
||||
Never
|
||||
Effect:
|
||||
Returns the reslting hash of all the input data.
|
||||
Returns the resulting hash of all the input data.
|
||||
*/
|
||||
/** @{ */
|
||||
|
||||
|
||||
@@ -376,7 +376,7 @@ public:
|
||||
print statement examples
|
||||
"parent.child" prints child and all of its children
|
||||
"parent.child." start at the parent and print down to child
|
||||
"parent.grandchild" prints nothing- grandchild not direct discendent
|
||||
"parent.grandchild" prints nothing- grandchild not direct descendent
|
||||
"parent.grandchild." starts at the parent and prints down to grandchild
|
||||
"parent.grandchild.*" starts at parent, print through grandchild
|
||||
children
|
||||
|
||||
@@ -40,7 +40,7 @@ public:
|
||||
using microseconds = std::chrono::microseconds;
|
||||
|
||||
/**
|
||||
* Configuration from [perf] section of rippled.cfg.
|
||||
* Configuration from [perf] section of xrpld.cfg.
|
||||
*/
|
||||
struct Setup
|
||||
{
|
||||
|
||||
@@ -1,445 +0,0 @@
|
||||
#ifndef XRPL_JSON_OBJECT_H_INCLUDED
|
||||
#define XRPL_JSON_OBJECT_H_INCLUDED
|
||||
|
||||
#include <xrpl/json/Writer.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace Json {
|
||||
|
||||
/**
|
||||
Collection is a base class for Array and Object, classes which provide the
|
||||
facade of JSON collections for the O(1) JSON writer, while still using no
|
||||
heap memory and only a very small amount of stack.
|
||||
|
||||
From http://json.org, JSON has two types of collection: array, and object.
|
||||
Everything else is a *scalar* - a number, a string, a boolean, the special
|
||||
value null, or a legacy Json::Value.
|
||||
|
||||
Collections must write JSON "as-it-goes" in order to get the strong
|
||||
performance guarantees. This puts restrictions upon API users:
|
||||
|
||||
1. Only one collection can be open for change at any one time.
|
||||
|
||||
This condition is enforced automatically and a std::logic_error thrown if
|
||||
it is violated.
|
||||
|
||||
2. A tag may only be used once in an Object.
|
||||
|
||||
Some objects have many tags, so this condition might be a little
|
||||
expensive. Enforcement of this condition is turned on in debug builds and
|
||||
a std::logic_error is thrown when the tag is added for a second time.
|
||||
|
||||
Code samples:
|
||||
|
||||
Writer writer;
|
||||
|
||||
// An empty object.
|
||||
{
|
||||
Object::Root (writer);
|
||||
}
|
||||
// Outputs {}
|
||||
|
||||
// An object with one scalar value.
|
||||
{
|
||||
Object::Root root (writer);
|
||||
write["hello"] = "world";
|
||||
}
|
||||
// Outputs {"hello":"world"}
|
||||
|
||||
// Same, using chaining.
|
||||
{
|
||||
Object::Root (writer)["hello"] = "world";
|
||||
}
|
||||
// Output is the same.
|
||||
|
||||
// Add several scalars, with chaining.
|
||||
{
|
||||
Object::Root (writer)
|
||||
.set ("hello", "world")
|
||||
.set ("flag", false)
|
||||
.set ("x", 42);
|
||||
}
|
||||
// Outputs {"hello":"world","flag":false,"x":42}
|
||||
|
||||
// Add an array.
|
||||
{
|
||||
Object::Root root (writer);
|
||||
{
|
||||
auto array = root.setArray ("hands");
|
||||
array.append ("left");
|
||||
array.append ("right");
|
||||
}
|
||||
}
|
||||
// Outputs {"hands":["left", "right"]}
|
||||
|
||||
// Same, using chaining.
|
||||
{
|
||||
Object::Root (writer)
|
||||
.setArray ("hands")
|
||||
.append ("left")
|
||||
.append ("right");
|
||||
}
|
||||
// Output is the same.
|
||||
|
||||
// Add an object.
|
||||
{
|
||||
Object::Root root (writer);
|
||||
{
|
||||
auto object = root.setObject ("hands");
|
||||
object["left"] = false;
|
||||
object["right"] = true;
|
||||
}
|
||||
}
|
||||
// Outputs {"hands":{"left":false,"right":true}}
|
||||
|
||||
// Same, using chaining.
|
||||
{
|
||||
Object::Root (writer)
|
||||
.setObject ("hands")
|
||||
.set ("left", false)
|
||||
.set ("right", true);
|
||||
}
|
||||
}
|
||||
// Outputs {"hands":{"left":false,"right":true}}
|
||||
|
||||
|
||||
Typical ways to make mistakes and get a std::logic_error:
|
||||
|
||||
Writer writer;
|
||||
Object::Root root (writer);
|
||||
|
||||
// Repeat a tag.
|
||||
{
|
||||
root ["hello"] = "world";
|
||||
root ["hello"] = "there"; // THROWS! in a debug build.
|
||||
}
|
||||
|
||||
// Open a subcollection, then set something else.
|
||||
{
|
||||
auto object = root.setObject ("foo");
|
||||
root ["hello"] = "world"; // THROWS!
|
||||
}
|
||||
|
||||
// Open two subcollections at a time.
|
||||
{
|
||||
auto object = root.setObject ("foo");
|
||||
auto array = root.setArray ("bar"); // THROWS!!
|
||||
}
|
||||
|
||||
For more examples, check the unit tests.
|
||||
*/
|
||||
|
||||
class Collection
|
||||
{
|
||||
public:
|
||||
Collection(Collection&& c) noexcept;
|
||||
Collection&
|
||||
operator=(Collection&& c) noexcept;
|
||||
Collection() = delete;
|
||||
|
||||
~Collection();
|
||||
|
||||
protected:
|
||||
// A null parent means "no parent at all".
|
||||
// Writers cannot be null.
|
||||
Collection(Collection* parent, Writer*);
|
||||
void
|
||||
checkWritable(std::string const& label);
|
||||
|
||||
Collection* parent_;
|
||||
Writer* writer_;
|
||||
bool enabled_;
|
||||
};
|
||||
|
||||
class Array;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Represents a JSON object being written to a Writer. */
|
||||
class Object : protected Collection
|
||||
{
|
||||
public:
|
||||
/** Object::Root is the only Collection that has a public constructor. */
|
||||
class Root;
|
||||
|
||||
/** Set a scalar value in the Object for a key.
|
||||
|
||||
A JSON scalar is a single value - a number, string, boolean, nullptr or
|
||||
a Json::Value.
|
||||
|
||||
`set()` throws an exception if this object is disabled (which means that
|
||||
one of its children is enabled).
|
||||
|
||||
In a debug build, `set()` also throws an exception if the key has
|
||||
already been set() before.
|
||||
|
||||
An operator[] is provided to allow writing `object["key"] = scalar;`.
|
||||
*/
|
||||
template <typename Scalar>
|
||||
void
|
||||
set(std::string const& key, Scalar const&);
|
||||
|
||||
void
|
||||
set(std::string const& key, Json::Value const&);
|
||||
|
||||
// Detail class and method used to implement operator[].
|
||||
class Proxy;
|
||||
|
||||
Proxy
|
||||
operator[](std::string const& key);
|
||||
Proxy
|
||||
operator[](Json::StaticString const& key);
|
||||
|
||||
/** Make a new Object at a key and return it.
|
||||
|
||||
This Object is disabled until that sub-object is destroyed.
|
||||
Throws an exception if this Object was already disabled.
|
||||
*/
|
||||
Object
|
||||
setObject(std::string const& key);
|
||||
|
||||
/** Make a new Array at a key and return it.
|
||||
|
||||
This Object is disabled until that sub-array is destroyed.
|
||||
Throws an exception if this Object was already disabled.
|
||||
*/
|
||||
Array
|
||||
setArray(std::string const& key);
|
||||
|
||||
protected:
|
||||
friend class Array;
|
||||
Object(Collection* parent, Writer* w) : Collection(parent, w)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class Object::Root : public Object
|
||||
{
|
||||
public:
|
||||
/** Each Object::Root must be constructed with its own unique Writer. */
|
||||
Root(Writer&);
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Represents a JSON array being written to a Writer. */
|
||||
class Array : private Collection
|
||||
{
|
||||
public:
|
||||
/** Append a scalar to the Arrary.
|
||||
|
||||
Throws an exception if this array is disabled (which means that one of
|
||||
its sub-collections is enabled).
|
||||
*/
|
||||
template <typename Scalar>
|
||||
void
|
||||
append(Scalar const&);
|
||||
|
||||
/**
|
||||
Appends a Json::Value to an array.
|
||||
Throws an exception if this Array was disabled.
|
||||
*/
|
||||
void
|
||||
append(Json::Value const&);
|
||||
|
||||
/** Append a new Object and return it.
|
||||
|
||||
This Array is disabled until that sub-object is destroyed.
|
||||
Throws an exception if this Array was disabled.
|
||||
*/
|
||||
Object
|
||||
appendObject();
|
||||
|
||||
/** Append a new Array and return it.
|
||||
|
||||
This Array is disabled until that sub-array is destroyed.
|
||||
Throws an exception if this Array was already disabled.
|
||||
*/
|
||||
Array
|
||||
appendArray();
|
||||
|
||||
protected:
|
||||
friend class Object;
|
||||
Array(Collection* parent, Writer* w) : Collection(parent, w)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Generic accessor functions to allow Json::Value and Collection to
|
||||
// interoperate.
|
||||
|
||||
/** Add a new subarray at a named key in a Json object. */
|
||||
Json::Value&
|
||||
setArray(Json::Value&, Json::StaticString const& key);
|
||||
|
||||
/** Add a new subarray at a named key in a Json object. */
|
||||
Array
|
||||
setArray(Object&, Json::StaticString const& key);
|
||||
|
||||
/** Add a new subobject at a named key in a Json object. */
|
||||
Json::Value&
|
||||
addObject(Json::Value&, Json::StaticString const& key);
|
||||
|
||||
/** Add a new subobject at a named key in a Json object. */
|
||||
Object
|
||||
addObject(Object&, Json::StaticString const& key);
|
||||
|
||||
/** Append a new subarray to a Json array. */
|
||||
Json::Value&
|
||||
appendArray(Json::Value&);
|
||||
|
||||
/** Append a new subarray to a Json array. */
|
||||
Array
|
||||
appendArray(Array&);
|
||||
|
||||
/** Append a new subobject to a Json object. */
|
||||
Json::Value&
|
||||
appendObject(Json::Value&);
|
||||
|
||||
/** Append a new subobject to a Json object. */
|
||||
Object
|
||||
appendObject(Array&);
|
||||
|
||||
/** Copy all the keys and values from one object into another. */
|
||||
void
|
||||
copyFrom(Json::Value& to, Json::Value const& from);
|
||||
|
||||
/** Copy all the keys and values from one object into another. */
|
||||
void
|
||||
copyFrom(Object& to, Json::Value const& from);
|
||||
|
||||
/** An Object that contains its own Writer. */
|
||||
class WriterObject
|
||||
{
|
||||
public:
|
||||
WriterObject(Output const& output)
|
||||
: writer_(std::make_unique<Writer>(output))
|
||||
, object_(std::make_unique<Object::Root>(*writer_))
|
||||
{
|
||||
}
|
||||
|
||||
WriterObject(WriterObject&& other) = default;
|
||||
|
||||
Object*
|
||||
operator->()
|
||||
{
|
||||
return object_.get();
|
||||
}
|
||||
|
||||
Object&
|
||||
operator*()
|
||||
{
|
||||
return *object_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<Writer> writer_;
|
||||
std::unique_ptr<Object::Root> object_;
|
||||
};
|
||||
|
||||
WriterObject
|
||||
stringWriterObject(std::string&);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Implementation details.
|
||||
|
||||
// Detail class for Object::operator[].
|
||||
class Object::Proxy
|
||||
{
|
||||
private:
|
||||
Object& object_;
|
||||
std::string const key_;
|
||||
|
||||
public:
|
||||
Proxy(Object& object, std::string const& key);
|
||||
|
||||
template <class T>
|
||||
void
|
||||
operator=(T const& t)
|
||||
{
|
||||
object_.set(key_, t);
|
||||
// Note: This function shouldn't return *this, because it's a trap.
|
||||
//
|
||||
// In Json::Value, foo[jss::key] returns a reference to a
|
||||
// mutable Json::Value contained _inside_ foo. But in the case of
|
||||
// Json::Object, where we write once only, there isn't any such
|
||||
// reference that can be returned. Returning *this would return an
|
||||
// object "a level higher" than in Json::Value, leading to obscure bugs,
|
||||
// particularly in generic code.
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <typename Scalar>
|
||||
void
|
||||
Array::append(Scalar const& value)
|
||||
{
|
||||
checkWritable("append");
|
||||
if (writer_)
|
||||
writer_->append(value);
|
||||
}
|
||||
|
||||
template <typename Scalar>
|
||||
void
|
||||
Object::set(std::string const& key, Scalar const& value)
|
||||
{
|
||||
checkWritable("set");
|
||||
if (writer_)
|
||||
writer_->set(key, value);
|
||||
}
|
||||
|
||||
inline Json::Value&
|
||||
setArray(Json::Value& json, Json::StaticString const& key)
|
||||
{
|
||||
return (json[key] = Json::arrayValue);
|
||||
}
|
||||
|
||||
inline Array
|
||||
setArray(Object& json, Json::StaticString const& key)
|
||||
{
|
||||
return json.setArray(std::string(key));
|
||||
}
|
||||
|
||||
inline Json::Value&
|
||||
addObject(Json::Value& json, Json::StaticString const& key)
|
||||
{
|
||||
return (json[key] = Json::objectValue);
|
||||
}
|
||||
|
||||
inline Object
|
||||
addObject(Object& object, Json::StaticString const& key)
|
||||
{
|
||||
return object.setObject(std::string(key));
|
||||
}
|
||||
|
||||
inline Json::Value&
|
||||
appendArray(Json::Value& json)
|
||||
{
|
||||
return json.append(Json::arrayValue);
|
||||
}
|
||||
|
||||
inline Array
|
||||
appendArray(Array& json)
|
||||
{
|
||||
return json.appendArray();
|
||||
}
|
||||
|
||||
inline Json::Value&
|
||||
appendObject(Json::Value& json)
|
||||
{
|
||||
return json.append(Json::objectValue);
|
||||
}
|
||||
|
||||
inline Object
|
||||
appendObject(Array& json)
|
||||
{
|
||||
return json.appendObject();
|
||||
}
|
||||
|
||||
} // namespace Json
|
||||
|
||||
#endif
|
||||
@@ -1,8 +1,6 @@
|
||||
#ifndef XRPL_JSON_JSON_READER_H_INCLUDED
|
||||
#define XRPL_JSON_JSON_READER_H_INCLUDED
|
||||
|
||||
#define CPPTL_JSON_READER_H_INCLUDED
|
||||
|
||||
#include <xrpl/json/json_forwards.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
|
||||
@@ -68,7 +66,7 @@ public:
|
||||
* error occurred during parsing.
|
||||
*/
|
||||
std::string
|
||||
getFormatedErrorMessages() const;
|
||||
getFormattedErrorMessages() const;
|
||||
|
||||
static constexpr unsigned nest_limit{25};
|
||||
|
||||
@@ -231,4 +229,4 @@ operator>>(std::istream&, Value&);
|
||||
|
||||
} // namespace Json
|
||||
|
||||
#endif // CPPTL_JSON_READER_H_INCLUDED
|
||||
#endif // XRPL_JSON_JSON_READER_H_INCLUDED
|
||||
|
||||
@@ -44,7 +44,7 @@ enum ValueType {
|
||||
class StaticString
|
||||
{
|
||||
public:
|
||||
constexpr explicit StaticString(char const* czstring) : str_(czstring)
|
||||
constexpr explicit StaticString(char const* czString) : str_(czString)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -682,4 +682,4 @@ public:
|
||||
|
||||
} // namespace Json
|
||||
|
||||
#endif // CPPTL_JSON_H_INCLUDED
|
||||
#endif // XRPL_JSON_JSON_VALUE_H_INCLUDED
|
||||
|
||||
@@ -90,7 +90,7 @@ private:
|
||||
void
|
||||
writeArrayValue(Value const& value);
|
||||
bool
|
||||
isMultineArray(Value const& value);
|
||||
isMultilineArray(Value const& value);
|
||||
void
|
||||
pushValue(std::string const& value);
|
||||
void
|
||||
@@ -157,7 +157,7 @@ private:
|
||||
void
|
||||
writeArrayValue(Value const& value);
|
||||
bool
|
||||
isMultineArray(Value const& value);
|
||||
isMultilineArray(Value const& value);
|
||||
void
|
||||
pushValue(std::string const& value);
|
||||
void
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace xrpl {
|
||||
namespace credentials {
|
||||
|
||||
// These function will be used by the code that use DepositPreauth / Credentials
|
||||
// (and any future preauthorization modes) as part of authorization (all the
|
||||
// (and any future pre-authorization modes) as part of authorization (all the
|
||||
// transfer funds transactions)
|
||||
|
||||
// Check if credential sfExpiration field has passed ledger's parentCloseTime
|
||||
@@ -41,7 +41,8 @@ checkFields(STTx const& tx, beast::Journal j);
|
||||
|
||||
// Accessing the ledger to check if provided credentials are valid. Do not use
|
||||
// in doApply (only in preclaim) since it does not remove expired credentials.
|
||||
// If you call it in prelaim, you also must call verifyDepositPreauth in doApply
|
||||
// If you call it in preclaim, you also must call verifyDepositPreauth in
|
||||
// doApply
|
||||
TER
|
||||
valid(
|
||||
STTx const& tx,
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
namespace xrpl {
|
||||
namespace NodeStore {
|
||||
|
||||
/** Simple NodeStore Scheduler that just peforms the tasks synchronously. */
|
||||
/** Simple NodeStore Scheduler that just performs the tasks synchronously. */
|
||||
class DummyScheduler : public Scheduler
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -55,7 +55,7 @@ public:
|
||||
HyperLevelDB, LevelDBFactory, SQLite, MDB
|
||||
|
||||
If the fastBackendParameter is omitted or empty, no ephemeral database
|
||||
is used. If the scheduler parameter is omited or unspecified, a
|
||||
is used. If the scheduler parameter is omitted or unspecified, a
|
||||
synchronous scheduler is used which performs all tasks immediately on
|
||||
the caller's thread.
|
||||
|
||||
|
||||
@@ -96,7 +96,7 @@ Facebook's RocksDB database, builds on LevelDB.
|
||||
|
||||
Use SQLite.
|
||||
|
||||
'path' speficies where the backend will store its data files.
|
||||
'path' specifies where the backend will store its data files.
|
||||
|
||||
Choices for 'compression'
|
||||
|
||||
@@ -130,7 +130,7 @@ newer versions of RocksDB (TBD).
|
||||
## Discussion
|
||||
|
||||
RocksDBQuickFactory is intended to provide a testbed for comparing potential
|
||||
rocksdb performance with the existing recommended configuration in rippled.cfg.
|
||||
rocksdb performance with the existing recommended configuration in xrpld.cfg.
|
||||
Through various executions and profiling some conclusions are presented below.
|
||||
|
||||
- If the write ahead log is enabled, insert speed soon clogs up under load. The
|
||||
@@ -161,7 +161,7 @@ Through various executions and profiling some conclusions are presented below.
|
||||
|
||||
- Multiple runs of the benchmarks can yield surprisingly different results. This
|
||||
can perhaps be attributed to the asynchronous nature of rocksdb's compaction
|
||||
process. The benchmarks are artifical and create highly unlikely write load to
|
||||
process. The benchmarks are artificial and create highly unlikely write load to
|
||||
create the dataset to measure different read access patterns. Therefore multiple
|
||||
runs of the benchmarks are required to get a feel for the effectiveness of the
|
||||
changes. This contrasts sharply with the keyvadb benchmarking were highly
|
||||
|
||||
@@ -9,7 +9,7 @@ import "org/xrpl/rpc/v1/get_ledger_entry.proto";
|
||||
import "org/xrpl/rpc/v1/get_ledger_data.proto";
|
||||
import "org/xrpl/rpc/v1/get_ledger_diff.proto";
|
||||
|
||||
// These methods are binary only methods for retrieiving arbitrary ledger state
|
||||
// These methods are binary only methods for retrieving arbitrary ledger state
|
||||
// via gRPC. These methods are used by clio, but can also be
|
||||
// used by any client that wants to extract ledger state in an efficient manner.
|
||||
// They do not directly mimic the JSON equivalent methods.
|
||||
|
||||
@@ -17,9 +17,9 @@ enum MessageType {
|
||||
mtHAVE_SET = 35;
|
||||
mtVALIDATION = 41;
|
||||
mtGET_OBJECTS = 42;
|
||||
mtVALIDATORLIST = 54;
|
||||
mtVALIDATOR_LIST = 54;
|
||||
mtSQUELCH = 55;
|
||||
mtVALIDATORLISTCOLLECTION = 56;
|
||||
mtVALIDATOR_LIST_COLLECTION = 56;
|
||||
mtPROOF_PATH_REQ = 57;
|
||||
mtPROOF_PATH_RESPONSE = 58;
|
||||
mtREPLAY_DELTA_REQ = 59;
|
||||
@@ -308,7 +308,7 @@ message TMSquelch {
|
||||
}
|
||||
|
||||
enum TMLedgerMapType {
|
||||
lmTRANASCTION = 1; // transaction map
|
||||
lmTRANSACTION = 1; // transaction map
|
||||
lmACCOUNT_STATE = 2; // account state map
|
||||
}
|
||||
|
||||
|
||||
@@ -58,14 +58,14 @@ static_assert(apiMaximumSupportedVersion >= apiMinimumSupportedVersion);
|
||||
static_assert(apiBetaVersion >= apiMaximumSupportedVersion);
|
||||
static_assert(apiMaximumValidVersion >= apiMaximumSupportedVersion);
|
||||
|
||||
template <class JsonObject>
|
||||
void
|
||||
setVersion(JsonObject& parent, unsigned int apiVersion, bool betaEnabled)
|
||||
inline void
|
||||
setVersion(Json::Value& parent, unsigned int apiVersion, bool betaEnabled)
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
apiVersion != apiInvalidVersion,
|
||||
"xrpl::RPC::setVersion : input is valid");
|
||||
auto& retObj = addObject(parent, jss::version);
|
||||
|
||||
auto& retObj = parent[jss::version] = Json::objectValue;
|
||||
|
||||
if (apiVersion == apiVersionIfUnspecified)
|
||||
{
|
||||
|
||||
@@ -209,33 +209,11 @@ get_error_info(error_code_i code);
|
||||
|
||||
/** Add or update the json update to reflect the error code. */
|
||||
/** @{ */
|
||||
template <class JsonValue>
|
||||
void
|
||||
inject_error(error_code_i code, JsonValue& json)
|
||||
{
|
||||
ErrorInfo const& info(get_error_info(code));
|
||||
json[jss::error] = info.token;
|
||||
json[jss::error_code] = info.code;
|
||||
json[jss::error_message] = info.message;
|
||||
}
|
||||
inject_error(error_code_i code, Json::Value& json);
|
||||
|
||||
template <class JsonValue>
|
||||
void
|
||||
inject_error(int code, JsonValue& json)
|
||||
{
|
||||
inject_error(error_code_i(code), json);
|
||||
}
|
||||
|
||||
template <class JsonValue>
|
||||
void
|
||||
inject_error(error_code_i code, std::string const& message, JsonValue& json)
|
||||
{
|
||||
ErrorInfo const& info(get_error_info(code));
|
||||
json[jss::error] = info.token;
|
||||
json[jss::error_code] = info.code;
|
||||
json[jss::error_message] = message;
|
||||
}
|
||||
|
||||
inject_error(error_code_i code, std::string const& message, Json::Value& json);
|
||||
/** @} */
|
||||
|
||||
/** Returns a new json object that reflects the error code. */
|
||||
|
||||
@@ -67,9 +67,6 @@ enum class HashPrefix : std::uint32_t {
|
||||
/** Payment Channel Claim */
|
||||
paymentChannelClaim = detail::make_hash_prefix('C', 'L', 'M'),
|
||||
|
||||
/** Credentials signature */
|
||||
credential = detail::make_hash_prefix('C', 'R', 'D'),
|
||||
|
||||
/** Batch */
|
||||
batch = detail::make_hash_prefix('B', 'C', 'H'),
|
||||
};
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace xrpl {
|
||||
|
||||
Arithmetic operations can throw std::overflow_error during normalization
|
||||
if the amount exceeds the largest representable amount, but underflows
|
||||
will silently trunctate to zero.
|
||||
will silently truncate to zero.
|
||||
*/
|
||||
class IOUAmount : private boost::totally_ordered<IOUAmount>,
|
||||
private boost::additive<IOUAmount>
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
namespace xrpl {
|
||||
|
||||
class SeqProxy;
|
||||
/** Keylet computation funclets.
|
||||
/** Keylet computation functions.
|
||||
|
||||
Entries in the ledger are located using 256-bit locators. The locators are
|
||||
calculated using a wide range of parameters specific to the entry whose
|
||||
|
||||
@@ -29,7 +29,7 @@ enum GranularPermissionType : std::uint32_t {
|
||||
#pragma pop_macro("PERMISSION")
|
||||
};
|
||||
|
||||
enum Delegation { delegatable, notDelegatable };
|
||||
enum Delegation { delegable, notDelegable };
|
||||
|
||||
class Permission
|
||||
{
|
||||
@@ -38,7 +38,7 @@ private:
|
||||
|
||||
std::unordered_map<std::uint16_t, uint256> txFeatureMap_;
|
||||
|
||||
std::unordered_map<std::uint16_t, Delegation> delegatableTx_;
|
||||
std::unordered_map<std::uint16_t, Delegation> delegableTx_;
|
||||
|
||||
std::unordered_map<std::string, GranularPermissionType>
|
||||
granularPermissionMap_;
|
||||
@@ -71,8 +71,7 @@ public:
|
||||
getTxFeature(TxType txType) const;
|
||||
|
||||
bool
|
||||
isDelegatable(std::uint32_t const& permissionValue, Rules const& rules)
|
||||
const;
|
||||
isDelegable(std::uint32_t const& permissionValue, Rules const& rules) const;
|
||||
|
||||
// for tx level permission, permission value is equal to tx type plus one
|
||||
uint32_t
|
||||
|
||||
@@ -179,7 +179,7 @@ static constexpr int loanPaymentsPerFeeIncrement = 5;
|
||||
*
|
||||
* This limit is enforced during the loan payment process, and thus is not
|
||||
* estimated. If the limit is hit, no further payments or overpayments will be
|
||||
* processed, no matter how much of the transation Amount is left, but the
|
||||
* processed, no matter how much of the transaction Amount is left, but the
|
||||
* transaction will succeed with the payments that have been processed up to
|
||||
* that point.
|
||||
*
|
||||
|
||||
@@ -210,7 +210,7 @@ public:
|
||||
|
||||
private:
|
||||
// The ceil_in and ceil_out methods that deal in TAmount all convert
|
||||
// their arguments to STAoumout and convert the result back to TAmount.
|
||||
// their arguments to STAmount and convert the result back to TAmount.
|
||||
// This helper function takes care of all the conversion operations.
|
||||
template <
|
||||
class In,
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace xrpl {
|
||||
bool
|
||||
isRpcError(Json::Value jvResult);
|
||||
Json::Value
|
||||
rpcError(int iError);
|
||||
rpcError(error_code_i iError);
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
|
||||
@@ -277,7 +277,7 @@ constexpr std::uint32_t const tfLoanOverpayment = 0x00010000;
|
||||
// interest and fees, or it will fail. False: Not a full payment.
|
||||
constexpr std::uint32_t const tfLoanFullPayment = 0x00020000;
|
||||
// tfLoanLatePayment: True, indicates that the payment is late,
|
||||
// and includes late iterest and fees. If the loan is not late,
|
||||
// and includes late interest and fees. If the loan is not late,
|
||||
// it will fail. False: not a late payment. If the current payment
|
||||
// is overdue, the transaction will fail.
|
||||
constexpr std::uint32_t const tfLoanLatePayment = 0x00040000;
|
||||
|
||||
@@ -33,12 +33,12 @@ struct AttestationBase
|
||||
// Account on the sending chain that triggered the event (sent the
|
||||
// transaction)
|
||||
AccountID sendingAccount;
|
||||
// Amount transfered on the sending chain
|
||||
// Amount transferred on the sending chain
|
||||
STAmount sendingAmount;
|
||||
// Account on the destination chain that collects a share of the attestation
|
||||
// reward
|
||||
AccountID rewardAccount;
|
||||
// Amount was transfered on the locking chain
|
||||
// Amount was transferred on the locking chain
|
||||
bool wasLockingChainSend;
|
||||
|
||||
explicit AttestationBase(
|
||||
@@ -354,7 +354,7 @@ struct XChainCreateAccountAttestation
|
||||
XChainCreateAccountAttestation const& rhs);
|
||||
};
|
||||
|
||||
// Attestations from witness servers for a particular claimid and bridge.
|
||||
// Attestations from witness servers for a particular claim ID and bridge.
|
||||
// Only one attestation per signature is allowed.
|
||||
template <class TAttestation>
|
||||
class XChainAttestationsBase
|
||||
|
||||
@@ -42,7 +42,7 @@ concept ValidConstructSTArgs =
|
||||
class STVar
|
||||
{
|
||||
private:
|
||||
// The largest "small object" we can accomodate
|
||||
// The largest "small object" we can accommodate
|
||||
static std::size_t constexpr max_size = 72;
|
||||
|
||||
std::aligned_storage<max_size>::type d_;
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
// Add new amendments to the top of this list.
|
||||
// Keep it sorted in reverse chronological order.
|
||||
|
||||
XRPL_FEATURE(DefragDirectories, Supported::no, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (BatchInnerSigs, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(LendingProtocol, Supported::no, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(PermissionDelegationV1_1, Supported::no, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (DirectoryLimit, Supported::yes, VoteBehavior::DefaultNo)
|
||||
|
||||
@@ -237,7 +237,7 @@ LEDGER_ENTRY(ltOFFER, 0x006f, Offer, offer, ({
|
||||
{sfAdditionalBooks, soeOPTIONAL},
|
||||
}))
|
||||
|
||||
/** A ledger object which describes a deposit preauthorization.
|
||||
/** A ledger object which describes a deposit pre-authorization.
|
||||
|
||||
\sa keylet::depositPreauth
|
||||
*/
|
||||
@@ -577,7 +577,7 @@ LEDGER_ENTRY(ltLOAN, 0x0089, Loan, loan, ({
|
||||
// - TrueTotalLoanValue = PaymentRemaining * PeriodicPayment
|
||||
// The unrounded true total value of the loan.
|
||||
//
|
||||
// - TrueTotalPrincialOutstanding can be computed using the algorithm
|
||||
// - TrueTotalPrincipalOutstanding can be computed using the algorithm
|
||||
// in the ripple::detail::loanPrincipalFromPeriodicPayment function.
|
||||
//
|
||||
// - TrueTotalInterestOutstanding = TrueTotalLoanValue -
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#endif
|
||||
|
||||
/**
|
||||
* TRANSACTION(tag, value, name, delegatable, amendments, privileges, fields)
|
||||
* TRANSACTION(tag, value, name, delegable, amendments, privileges, fields)
|
||||
*
|
||||
* To ease maintenance, you may replace any unneeded values with "..."
|
||||
* e.g. #define TRANSACTION(tag, value, name, ...)
|
||||
@@ -25,7 +25,7 @@
|
||||
# include <xrpld/app/tx/detail/Payment.h>
|
||||
#endif
|
||||
TRANSACTION(ttPAYMENT, 0, Payment,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
uint256{},
|
||||
createAcct,
|
||||
({
|
||||
@@ -45,7 +45,7 @@ TRANSACTION(ttPAYMENT, 0, Payment,
|
||||
# include <xrpld/app/tx/detail/Escrow.h>
|
||||
#endif
|
||||
TRANSACTION(ttESCROW_CREATE, 1, EscrowCreate,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
uint256{},
|
||||
noPriv,
|
||||
({
|
||||
@@ -59,7 +59,7 @@ TRANSACTION(ttESCROW_CREATE, 1, EscrowCreate,
|
||||
|
||||
/** This transaction type completes an existing escrow. */
|
||||
TRANSACTION(ttESCROW_FINISH, 2, EscrowFinish,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
uint256{},
|
||||
noPriv,
|
||||
({
|
||||
@@ -76,7 +76,7 @@ TRANSACTION(ttESCROW_FINISH, 2, EscrowFinish,
|
||||
# include <xrpld/app/tx/detail/SetAccount.h>
|
||||
#endif
|
||||
TRANSACTION(ttACCOUNT_SET, 3, AccountSet,
|
||||
Delegation::notDelegatable,
|
||||
Delegation::notDelegable,
|
||||
uint256{},
|
||||
noPriv,
|
||||
({
|
||||
@@ -97,7 +97,7 @@ TRANSACTION(ttACCOUNT_SET, 3, AccountSet,
|
||||
# include <xrpld/app/tx/detail/Escrow.h>
|
||||
#endif
|
||||
TRANSACTION(ttESCROW_CANCEL, 4, EscrowCancel,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
uint256{},
|
||||
noPriv,
|
||||
({
|
||||
@@ -110,7 +110,7 @@ TRANSACTION(ttESCROW_CANCEL, 4, EscrowCancel,
|
||||
# include <xrpld/app/tx/detail/SetRegularKey.h>
|
||||
#endif
|
||||
TRANSACTION(ttREGULAR_KEY_SET, 5, SetRegularKey,
|
||||
Delegation::notDelegatable,
|
||||
Delegation::notDelegable,
|
||||
uint256{},
|
||||
noPriv,
|
||||
({
|
||||
@@ -124,7 +124,7 @@ TRANSACTION(ttREGULAR_KEY_SET, 5, SetRegularKey,
|
||||
# include <xrpld/app/tx/detail/CreateOffer.h>
|
||||
#endif
|
||||
TRANSACTION(ttOFFER_CREATE, 7, OfferCreate,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
uint256{},
|
||||
noPriv,
|
||||
({
|
||||
@@ -140,7 +140,7 @@ TRANSACTION(ttOFFER_CREATE, 7, OfferCreate,
|
||||
# include <xrpld/app/tx/detail/CancelOffer.h>
|
||||
#endif
|
||||
TRANSACTION(ttOFFER_CANCEL, 8, OfferCancel,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
uint256{},
|
||||
noPriv,
|
||||
({
|
||||
@@ -154,7 +154,7 @@ TRANSACTION(ttOFFER_CANCEL, 8, OfferCancel,
|
||||
# include <xrpld/app/tx/detail/CreateTicket.h>
|
||||
#endif
|
||||
TRANSACTION(ttTICKET_CREATE, 10, TicketCreate,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
uint256{},
|
||||
noPriv,
|
||||
({
|
||||
@@ -170,7 +170,7 @@ TRANSACTION(ttTICKET_CREATE, 10, TicketCreate,
|
||||
# include <xrpld/app/tx/detail/SetSignerList.h>
|
||||
#endif
|
||||
TRANSACTION(ttSIGNER_LIST_SET, 12, SignerListSet,
|
||||
Delegation::notDelegatable,
|
||||
Delegation::notDelegable,
|
||||
uint256{},
|
||||
noPriv,
|
||||
({
|
||||
@@ -183,7 +183,7 @@ TRANSACTION(ttSIGNER_LIST_SET, 12, SignerListSet,
|
||||
# include <xrpld/app/tx/detail/PayChan.h>
|
||||
#endif
|
||||
TRANSACTION(ttPAYCHAN_CREATE, 13, PaymentChannelCreate,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
uint256{},
|
||||
noPriv,
|
||||
({
|
||||
@@ -197,7 +197,7 @@ TRANSACTION(ttPAYCHAN_CREATE, 13, PaymentChannelCreate,
|
||||
|
||||
/** This transaction type funds an existing unidirectional XRP payment channel. */
|
||||
TRANSACTION(ttPAYCHAN_FUND, 14, PaymentChannelFund,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
uint256{},
|
||||
noPriv,
|
||||
({
|
||||
@@ -208,7 +208,7 @@ TRANSACTION(ttPAYCHAN_FUND, 14, PaymentChannelFund,
|
||||
|
||||
/** This transaction type submits a claim against an existing unidirectional payment channel. */
|
||||
TRANSACTION(ttPAYCHAN_CLAIM, 15, PaymentChannelClaim,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
uint256{},
|
||||
noPriv,
|
||||
({
|
||||
@@ -225,7 +225,7 @@ TRANSACTION(ttPAYCHAN_CLAIM, 15, PaymentChannelClaim,
|
||||
# include <xrpld/app/tx/detail/CreateCheck.h>
|
||||
#endif
|
||||
TRANSACTION(ttCHECK_CREATE, 16, CheckCreate,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
uint256{},
|
||||
noPriv,
|
||||
({
|
||||
@@ -241,7 +241,7 @@ TRANSACTION(ttCHECK_CREATE, 16, CheckCreate,
|
||||
# include <xrpld/app/tx/detail/CashCheck.h>
|
||||
#endif
|
||||
TRANSACTION(ttCHECK_CASH, 17, CheckCash,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
uint256{},
|
||||
noPriv,
|
||||
({
|
||||
@@ -255,7 +255,7 @@ TRANSACTION(ttCHECK_CASH, 17, CheckCash,
|
||||
# include <xrpld/app/tx/detail/CancelCheck.h>
|
||||
#endif
|
||||
TRANSACTION(ttCHECK_CANCEL, 18, CheckCancel,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
uint256{},
|
||||
noPriv,
|
||||
({
|
||||
@@ -267,7 +267,7 @@ TRANSACTION(ttCHECK_CANCEL, 18, CheckCancel,
|
||||
# include <xrpld/app/tx/detail/DepositPreauth.h>
|
||||
#endif
|
||||
TRANSACTION(ttDEPOSIT_PREAUTH, 19, DepositPreauth,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
uint256{},
|
||||
noPriv,
|
||||
({
|
||||
@@ -282,7 +282,7 @@ TRANSACTION(ttDEPOSIT_PREAUTH, 19, DepositPreauth,
|
||||
# include <xrpld/app/tx/detail/SetTrust.h>
|
||||
#endif
|
||||
TRANSACTION(ttTRUST_SET, 20, TrustSet,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
uint256{},
|
||||
noPriv,
|
||||
({
|
||||
@@ -296,7 +296,7 @@ TRANSACTION(ttTRUST_SET, 20, TrustSet,
|
||||
# include <xrpld/app/tx/detail/DeleteAccount.h>
|
||||
#endif
|
||||
TRANSACTION(ttACCOUNT_DELETE, 21, AccountDelete,
|
||||
Delegation::notDelegatable,
|
||||
Delegation::notDelegable,
|
||||
uint256{},
|
||||
mustDeleteAcct,
|
||||
({
|
||||
@@ -312,7 +312,7 @@ TRANSACTION(ttACCOUNT_DELETE, 21, AccountDelete,
|
||||
# include <xrpld/app/tx/detail/NFTokenMint.h>
|
||||
#endif
|
||||
TRANSACTION(ttNFTOKEN_MINT, 25, NFTokenMint,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
uint256{},
|
||||
changeNFTCounts,
|
||||
({
|
||||
@@ -330,7 +330,7 @@ TRANSACTION(ttNFTOKEN_MINT, 25, NFTokenMint,
|
||||
# include <xrpld/app/tx/detail/NFTokenBurn.h>
|
||||
#endif
|
||||
TRANSACTION(ttNFTOKEN_BURN, 26, NFTokenBurn,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
uint256{},
|
||||
changeNFTCounts,
|
||||
({
|
||||
@@ -343,7 +343,7 @@ TRANSACTION(ttNFTOKEN_BURN, 26, NFTokenBurn,
|
||||
# include <xrpld/app/tx/detail/NFTokenCreateOffer.h>
|
||||
#endif
|
||||
TRANSACTION(ttNFTOKEN_CREATE_OFFER, 27, NFTokenCreateOffer,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
uint256{},
|
||||
noPriv,
|
||||
({
|
||||
@@ -359,7 +359,7 @@ TRANSACTION(ttNFTOKEN_CREATE_OFFER, 27, NFTokenCreateOffer,
|
||||
# include <xrpld/app/tx/detail/NFTokenCancelOffer.h>
|
||||
#endif
|
||||
TRANSACTION(ttNFTOKEN_CANCEL_OFFER, 28, NFTokenCancelOffer,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
uint256{},
|
||||
noPriv,
|
||||
({
|
||||
@@ -371,7 +371,7 @@ TRANSACTION(ttNFTOKEN_CANCEL_OFFER, 28, NFTokenCancelOffer,
|
||||
# include <xrpld/app/tx/detail/NFTokenAcceptOffer.h>
|
||||
#endif
|
||||
TRANSACTION(ttNFTOKEN_ACCEPT_OFFER, 29, NFTokenAcceptOffer,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
uint256{},
|
||||
noPriv,
|
||||
({
|
||||
@@ -385,7 +385,7 @@ TRANSACTION(ttNFTOKEN_ACCEPT_OFFER, 29, NFTokenAcceptOffer,
|
||||
# include <xrpld/app/tx/detail/Clawback.h>
|
||||
#endif
|
||||
TRANSACTION(ttCLAWBACK, 30, Clawback,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
featureClawback,
|
||||
noPriv,
|
||||
({
|
||||
@@ -398,7 +398,7 @@ TRANSACTION(ttCLAWBACK, 30, Clawback,
|
||||
# include <xrpld/app/tx/detail/AMMClawback.h>
|
||||
#endif
|
||||
TRANSACTION(ttAMM_CLAWBACK, 31, AMMClawback,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
featureAMMClawback,
|
||||
mayDeleteAcct | overrideFreeze,
|
||||
({
|
||||
@@ -413,7 +413,7 @@ TRANSACTION(ttAMM_CLAWBACK, 31, AMMClawback,
|
||||
# include <xrpld/app/tx/detail/AMMCreate.h>
|
||||
#endif
|
||||
TRANSACTION(ttAMM_CREATE, 35, AMMCreate,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
featureAMM,
|
||||
createPseudoAcct,
|
||||
({
|
||||
@@ -427,7 +427,7 @@ TRANSACTION(ttAMM_CREATE, 35, AMMCreate,
|
||||
# include <xrpld/app/tx/detail/AMMDeposit.h>
|
||||
#endif
|
||||
TRANSACTION(ttAMM_DEPOSIT, 36, AMMDeposit,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
featureAMM,
|
||||
noPriv,
|
||||
({
|
||||
@@ -445,7 +445,7 @@ TRANSACTION(ttAMM_DEPOSIT, 36, AMMDeposit,
|
||||
# include <xrpld/app/tx/detail/AMMWithdraw.h>
|
||||
#endif
|
||||
TRANSACTION(ttAMM_WITHDRAW, 37, AMMWithdraw,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
featureAMM,
|
||||
mayDeleteAcct,
|
||||
({
|
||||
@@ -462,7 +462,7 @@ TRANSACTION(ttAMM_WITHDRAW, 37, AMMWithdraw,
|
||||
# include <xrpld/app/tx/detail/AMMVote.h>
|
||||
#endif
|
||||
TRANSACTION(ttAMM_VOTE, 38, AMMVote,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
featureAMM,
|
||||
noPriv,
|
||||
({
|
||||
@@ -476,7 +476,7 @@ TRANSACTION(ttAMM_VOTE, 38, AMMVote,
|
||||
# include <xrpld/app/tx/detail/AMMBid.h>
|
||||
#endif
|
||||
TRANSACTION(ttAMM_BID, 39, AMMBid,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
featureAMM,
|
||||
noPriv,
|
||||
({
|
||||
@@ -492,7 +492,7 @@ TRANSACTION(ttAMM_BID, 39, AMMBid,
|
||||
# include <xrpld/app/tx/detail/AMMDelete.h>
|
||||
#endif
|
||||
TRANSACTION(ttAMM_DELETE, 40, AMMDelete,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
featureAMM,
|
||||
mustDeleteAcct,
|
||||
({
|
||||
@@ -505,7 +505,7 @@ TRANSACTION(ttAMM_DELETE, 40, AMMDelete,
|
||||
# include <xrpld/app/tx/detail/XChainBridge.h>
|
||||
#endif
|
||||
TRANSACTION(ttXCHAIN_CREATE_CLAIM_ID, 41, XChainCreateClaimID,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
featureXChainBridge,
|
||||
noPriv,
|
||||
({
|
||||
@@ -516,7 +516,7 @@ TRANSACTION(ttXCHAIN_CREATE_CLAIM_ID, 41, XChainCreateClaimID,
|
||||
|
||||
/** This transactions initiates a crosschain transaction */
|
||||
TRANSACTION(ttXCHAIN_COMMIT, 42, XChainCommit,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
featureXChainBridge,
|
||||
noPriv,
|
||||
({
|
||||
@@ -528,7 +528,7 @@ TRANSACTION(ttXCHAIN_COMMIT, 42, XChainCommit,
|
||||
|
||||
/** This transaction completes a crosschain transaction */
|
||||
TRANSACTION(ttXCHAIN_CLAIM, 43, XChainClaim,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
featureXChainBridge,
|
||||
noPriv,
|
||||
({
|
||||
@@ -541,7 +541,7 @@ TRANSACTION(ttXCHAIN_CLAIM, 43, XChainClaim,
|
||||
|
||||
/** This transaction initiates a crosschain account create transaction */
|
||||
TRANSACTION(ttXCHAIN_ACCOUNT_CREATE_COMMIT, 44, XChainAccountCreateCommit,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
featureXChainBridge,
|
||||
noPriv,
|
||||
({
|
||||
@@ -553,7 +553,7 @@ TRANSACTION(ttXCHAIN_ACCOUNT_CREATE_COMMIT, 44, XChainAccountCreateCommit,
|
||||
|
||||
/** This transaction adds an attestation to a claim */
|
||||
TRANSACTION(ttXCHAIN_ADD_CLAIM_ATTESTATION, 45, XChainAddClaimAttestation,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
featureXChainBridge,
|
||||
createAcct,
|
||||
({
|
||||
@@ -574,7 +574,7 @@ TRANSACTION(ttXCHAIN_ADD_CLAIM_ATTESTATION, 45, XChainAddClaimAttestation,
|
||||
/** This transaction adds an attestation to an account */
|
||||
TRANSACTION(ttXCHAIN_ADD_ACCOUNT_CREATE_ATTESTATION, 46,
|
||||
XChainAddAccountCreateAttestation,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
featureXChainBridge,
|
||||
createAcct,
|
||||
({
|
||||
@@ -595,7 +595,7 @@ TRANSACTION(ttXCHAIN_ADD_ACCOUNT_CREATE_ATTESTATION, 46,
|
||||
|
||||
/** This transaction modifies a sidechain */
|
||||
TRANSACTION(ttXCHAIN_MODIFY_BRIDGE, 47, XChainModifyBridge,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
featureXChainBridge,
|
||||
noPriv,
|
||||
({
|
||||
@@ -606,7 +606,7 @@ TRANSACTION(ttXCHAIN_MODIFY_BRIDGE, 47, XChainModifyBridge,
|
||||
|
||||
/** This transactions creates a sidechain */
|
||||
TRANSACTION(ttXCHAIN_CREATE_BRIDGE, 48, XChainCreateBridge,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
featureXChainBridge,
|
||||
noPriv,
|
||||
({
|
||||
@@ -620,7 +620,7 @@ TRANSACTION(ttXCHAIN_CREATE_BRIDGE, 48, XChainCreateBridge,
|
||||
# include <xrpld/app/tx/detail/DID.h>
|
||||
#endif
|
||||
TRANSACTION(ttDID_SET, 49, DIDSet,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
featureDID,
|
||||
noPriv,
|
||||
({
|
||||
@@ -631,7 +631,7 @@ TRANSACTION(ttDID_SET, 49, DIDSet,
|
||||
|
||||
/** This transaction type deletes a DID */
|
||||
TRANSACTION(ttDID_DELETE, 50, DIDDelete,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
featureDID,
|
||||
noPriv,
|
||||
({}))
|
||||
@@ -641,7 +641,7 @@ TRANSACTION(ttDID_DELETE, 50, DIDDelete,
|
||||
# include <xrpld/app/tx/detail/SetOracle.h>
|
||||
#endif
|
||||
TRANSACTION(ttORACLE_SET, 51, OracleSet,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
featurePriceOracle,
|
||||
noPriv,
|
||||
({
|
||||
@@ -658,7 +658,7 @@ TRANSACTION(ttORACLE_SET, 51, OracleSet,
|
||||
# include <xrpld/app/tx/detail/DeleteOracle.h>
|
||||
#endif
|
||||
TRANSACTION(ttORACLE_DELETE, 52, OracleDelete,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
featurePriceOracle,
|
||||
noPriv,
|
||||
({
|
||||
@@ -670,7 +670,7 @@ TRANSACTION(ttORACLE_DELETE, 52, OracleDelete,
|
||||
# include <xrpld/app/tx/detail/LedgerStateFix.h>
|
||||
#endif
|
||||
TRANSACTION(ttLEDGER_STATE_FIX, 53, LedgerStateFix,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
fixNFTokenPageLinks,
|
||||
noPriv,
|
||||
({
|
||||
@@ -683,7 +683,7 @@ TRANSACTION(ttLEDGER_STATE_FIX, 53, LedgerStateFix,
|
||||
# include <xrpld/app/tx/detail/MPTokenIssuanceCreate.h>
|
||||
#endif
|
||||
TRANSACTION(ttMPTOKEN_ISSUANCE_CREATE, 54, MPTokenIssuanceCreate,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
featureMPTokensV1,
|
||||
createMPTIssuance,
|
||||
({
|
||||
@@ -700,7 +700,7 @@ TRANSACTION(ttMPTOKEN_ISSUANCE_CREATE, 54, MPTokenIssuanceCreate,
|
||||
# include <xrpld/app/tx/detail/MPTokenIssuanceDestroy.h>
|
||||
#endif
|
||||
TRANSACTION(ttMPTOKEN_ISSUANCE_DESTROY, 55, MPTokenIssuanceDestroy,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
featureMPTokensV1,
|
||||
destroyMPTIssuance,
|
||||
({
|
||||
@@ -712,7 +712,7 @@ TRANSACTION(ttMPTOKEN_ISSUANCE_DESTROY, 55, MPTokenIssuanceDestroy,
|
||||
# include <xrpld/app/tx/detail/MPTokenIssuanceSet.h>
|
||||
#endif
|
||||
TRANSACTION(ttMPTOKEN_ISSUANCE_SET, 56, MPTokenIssuanceSet,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
featureMPTokensV1,
|
||||
noPriv,
|
||||
({
|
||||
@@ -729,7 +729,7 @@ TRANSACTION(ttMPTOKEN_ISSUANCE_SET, 56, MPTokenIssuanceSet,
|
||||
# include <xrpld/app/tx/detail/MPTokenAuthorize.h>
|
||||
#endif
|
||||
TRANSACTION(ttMPTOKEN_AUTHORIZE, 57, MPTokenAuthorize,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
featureMPTokensV1,
|
||||
mustAuthorizeMPT,
|
||||
({
|
||||
@@ -742,7 +742,7 @@ TRANSACTION(ttMPTOKEN_AUTHORIZE, 57, MPTokenAuthorize,
|
||||
# include <xrpld/app/tx/detail/Credentials.h>
|
||||
#endif
|
||||
TRANSACTION(ttCREDENTIAL_CREATE, 58, CredentialCreate,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
featureCredentials,
|
||||
noPriv,
|
||||
({
|
||||
@@ -754,7 +754,7 @@ TRANSACTION(ttCREDENTIAL_CREATE, 58, CredentialCreate,
|
||||
|
||||
/** This transaction type accept an Credential object */
|
||||
TRANSACTION(ttCREDENTIAL_ACCEPT, 59, CredentialAccept,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
featureCredentials,
|
||||
noPriv,
|
||||
({
|
||||
@@ -764,7 +764,7 @@ TRANSACTION(ttCREDENTIAL_ACCEPT, 59, CredentialAccept,
|
||||
|
||||
/** This transaction type delete an Credential object */
|
||||
TRANSACTION(ttCREDENTIAL_DELETE, 60, CredentialDelete,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
featureCredentials,
|
||||
noPriv,
|
||||
({
|
||||
@@ -778,7 +778,7 @@ TRANSACTION(ttCREDENTIAL_DELETE, 60, CredentialDelete,
|
||||
# include <xrpld/app/tx/detail/NFTokenModify.h>
|
||||
#endif
|
||||
TRANSACTION(ttNFTOKEN_MODIFY, 61, NFTokenModify,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
featureDynamicNFT,
|
||||
noPriv,
|
||||
({
|
||||
@@ -792,7 +792,7 @@ TRANSACTION(ttNFTOKEN_MODIFY, 61, NFTokenModify,
|
||||
# include <xrpld/app/tx/detail/PermissionedDomainSet.h>
|
||||
#endif
|
||||
TRANSACTION(ttPERMISSIONED_DOMAIN_SET, 62, PermissionedDomainSet,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
featurePermissionedDomains,
|
||||
noPriv,
|
||||
({
|
||||
@@ -805,7 +805,7 @@ TRANSACTION(ttPERMISSIONED_DOMAIN_SET, 62, PermissionedDomainSet,
|
||||
# include <xrpld/app/tx/detail/PermissionedDomainDelete.h>
|
||||
#endif
|
||||
TRANSACTION(ttPERMISSIONED_DOMAIN_DELETE, 63, PermissionedDomainDelete,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
featurePermissionedDomains,
|
||||
noPriv,
|
||||
({
|
||||
@@ -817,7 +817,7 @@ TRANSACTION(ttPERMISSIONED_DOMAIN_DELETE, 63, PermissionedDomainDelete,
|
||||
# include <xrpld/app/tx/detail/DelegateSet.h>
|
||||
#endif
|
||||
TRANSACTION(ttDELEGATE_SET, 64, DelegateSet,
|
||||
Delegation::notDelegatable,
|
||||
Delegation::notDelegable,
|
||||
featurePermissionDelegationV1_1,
|
||||
noPriv,
|
||||
({
|
||||
@@ -830,7 +830,7 @@ TRANSACTION(ttDELEGATE_SET, 64, DelegateSet,
|
||||
# include <xrpld/app/tx/detail/VaultCreate.h>
|
||||
#endif
|
||||
TRANSACTION(ttVAULT_CREATE, 65, VaultCreate,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
featureSingleAssetVault,
|
||||
createPseudoAcct | createMPTIssuance | mustModifyVault,
|
||||
({
|
||||
@@ -848,7 +848,7 @@ TRANSACTION(ttVAULT_CREATE, 65, VaultCreate,
|
||||
# include <xrpld/app/tx/detail/VaultSet.h>
|
||||
#endif
|
||||
TRANSACTION(ttVAULT_SET, 66, VaultSet,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
featureSingleAssetVault,
|
||||
mustModifyVault,
|
||||
({
|
||||
@@ -863,7 +863,7 @@ TRANSACTION(ttVAULT_SET, 66, VaultSet,
|
||||
# include <xrpld/app/tx/detail/VaultDelete.h>
|
||||
#endif
|
||||
TRANSACTION(ttVAULT_DELETE, 67, VaultDelete,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
featureSingleAssetVault,
|
||||
mustDeleteAcct | destroyMPTIssuance | mustModifyVault,
|
||||
({
|
||||
@@ -875,7 +875,7 @@ TRANSACTION(ttVAULT_DELETE, 67, VaultDelete,
|
||||
# include <xrpld/app/tx/detail/VaultDeposit.h>
|
||||
#endif
|
||||
TRANSACTION(ttVAULT_DEPOSIT, 68, VaultDeposit,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
featureSingleAssetVault,
|
||||
mayAuthorizeMPT | mustModifyVault,
|
||||
({
|
||||
@@ -888,7 +888,7 @@ TRANSACTION(ttVAULT_DEPOSIT, 68, VaultDeposit,
|
||||
# include <xrpld/app/tx/detail/VaultWithdraw.h>
|
||||
#endif
|
||||
TRANSACTION(ttVAULT_WITHDRAW, 69, VaultWithdraw,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
featureSingleAssetVault,
|
||||
mayDeleteMPT | mayAuthorizeMPT | mustModifyVault,
|
||||
({
|
||||
@@ -903,7 +903,7 @@ TRANSACTION(ttVAULT_WITHDRAW, 69, VaultWithdraw,
|
||||
# include <xrpld/app/tx/detail/VaultClawback.h>
|
||||
#endif
|
||||
TRANSACTION(ttVAULT_CLAWBACK, 70, VaultClawback,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
featureSingleAssetVault,
|
||||
mayDeleteMPT | mustModifyVault,
|
||||
({
|
||||
@@ -917,7 +917,7 @@ TRANSACTION(ttVAULT_CLAWBACK, 70, VaultClawback,
|
||||
# include <xrpld/app/tx/detail/Batch.h>
|
||||
#endif
|
||||
TRANSACTION(ttBATCH, 71, Batch,
|
||||
Delegation::notDelegatable,
|
||||
Delegation::notDelegable,
|
||||
featureBatch,
|
||||
noPriv,
|
||||
({
|
||||
@@ -932,7 +932,7 @@ TRANSACTION(ttBATCH, 71, Batch,
|
||||
# include <xrpld/app/tx/detail/LoanBrokerSet.h>
|
||||
#endif
|
||||
TRANSACTION(ttLOAN_BROKER_SET, 74, LoanBrokerSet,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
featureLendingProtocol,
|
||||
createPseudoAcct | mayAuthorizeMPT, ({
|
||||
{sfVaultID, soeREQUIRED},
|
||||
@@ -949,7 +949,7 @@ TRANSACTION(ttLOAN_BROKER_SET, 74, LoanBrokerSet,
|
||||
# include <xrpld/app/tx/detail/LoanBrokerDelete.h>
|
||||
#endif
|
||||
TRANSACTION(ttLOAN_BROKER_DELETE, 75, LoanBrokerDelete,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
featureLendingProtocol,
|
||||
mustDeleteAcct | mayAuthorizeMPT, ({
|
||||
{sfLoanBrokerID, soeREQUIRED},
|
||||
@@ -960,7 +960,7 @@ TRANSACTION(ttLOAN_BROKER_DELETE, 75, LoanBrokerDelete,
|
||||
# include <xrpld/app/tx/detail/LoanBrokerCoverDeposit.h>
|
||||
#endif
|
||||
TRANSACTION(ttLOAN_BROKER_COVER_DEPOSIT, 76, LoanBrokerCoverDeposit,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
featureLendingProtocol,
|
||||
noPriv, ({
|
||||
{sfLoanBrokerID, soeREQUIRED},
|
||||
@@ -972,7 +972,7 @@ TRANSACTION(ttLOAN_BROKER_COVER_DEPOSIT, 76, LoanBrokerCoverDeposit,
|
||||
# include <xrpld/app/tx/detail/LoanBrokerCoverWithdraw.h>
|
||||
#endif
|
||||
TRANSACTION(ttLOAN_BROKER_COVER_WITHDRAW, 77, LoanBrokerCoverWithdraw,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
featureLendingProtocol,
|
||||
mayAuthorizeMPT, ({
|
||||
{sfLoanBrokerID, soeREQUIRED},
|
||||
@@ -987,7 +987,7 @@ TRANSACTION(ttLOAN_BROKER_COVER_WITHDRAW, 77, LoanBrokerCoverWithdraw,
|
||||
# include <xrpld/app/tx/detail/LoanBrokerCoverClawback.h>
|
||||
#endif
|
||||
TRANSACTION(ttLOAN_BROKER_COVER_CLAWBACK, 78, LoanBrokerCoverClawback,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
featureLendingProtocol,
|
||||
noPriv, ({
|
||||
{sfLoanBrokerID, soeOPTIONAL},
|
||||
@@ -999,7 +999,7 @@ TRANSACTION(ttLOAN_BROKER_COVER_CLAWBACK, 78, LoanBrokerCoverClawback,
|
||||
# include <xrpld/app/tx/detail/LoanSet.h>
|
||||
#endif
|
||||
TRANSACTION(ttLOAN_SET, 80, LoanSet,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
featureLendingProtocol,
|
||||
mayAuthorizeMPT | mustModifyVault, ({
|
||||
{sfLoanBrokerID, soeREQUIRED},
|
||||
@@ -1026,7 +1026,7 @@ TRANSACTION(ttLOAN_SET, 80, LoanSet,
|
||||
# include <xrpld/app/tx/detail/LoanDelete.h>
|
||||
#endif
|
||||
TRANSACTION(ttLOAN_DELETE, 81, LoanDelete,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
featureLendingProtocol,
|
||||
noPriv, ({
|
||||
{sfLoanID, soeREQUIRED},
|
||||
@@ -1037,7 +1037,7 @@ TRANSACTION(ttLOAN_DELETE, 81, LoanDelete,
|
||||
# include <xrpld/app/tx/detail/LoanManage.h>
|
||||
#endif
|
||||
TRANSACTION(ttLOAN_MANAGE, 82, LoanManage,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
featureLendingProtocol,
|
||||
// All of the LoanManage options will modify the vault, but the
|
||||
// transaction can succeed without options, essentially making it
|
||||
@@ -1051,7 +1051,7 @@ TRANSACTION(ttLOAN_MANAGE, 82, LoanManage,
|
||||
# include <xrpld/app/tx/detail/LoanPay.h>
|
||||
#endif
|
||||
TRANSACTION(ttLOAN_PAY, 84, LoanPay,
|
||||
Delegation::delegatable,
|
||||
Delegation::delegable,
|
||||
featureLendingProtocol,
|
||||
mayAuthorizeMPT | mustModifyVault, ({
|
||||
{sfLoanID, soeREQUIRED},
|
||||
@@ -1066,7 +1066,7 @@ TRANSACTION(ttLOAN_PAY, 84, LoanPay,
|
||||
# include <xrpld/app/tx/detail/Change.h>
|
||||
#endif
|
||||
TRANSACTION(ttAMENDMENT, 100, EnableAmendment,
|
||||
Delegation::notDelegatable,
|
||||
Delegation::notDelegable,
|
||||
uint256{},
|
||||
noPriv,
|
||||
({
|
||||
@@ -1078,7 +1078,7 @@ TRANSACTION(ttAMENDMENT, 100, EnableAmendment,
|
||||
For details, see: https://xrpl.org/fee-voting.html
|
||||
*/
|
||||
TRANSACTION(ttFEE, 101, SetFee,
|
||||
Delegation::notDelegatable,
|
||||
Delegation::notDelegable,
|
||||
uint256{},
|
||||
noPriv,
|
||||
({
|
||||
@@ -1099,7 +1099,7 @@ TRANSACTION(ttFEE, 101, SetFee,
|
||||
For details, see: https://xrpl.org/negative-unl.html
|
||||
*/
|
||||
TRANSACTION(ttUNL_MODIFY, 102, UNLModify,
|
||||
Delegation::notDelegatable,
|
||||
Delegation::notDelegable,
|
||||
uint256{},
|
||||
noPriv,
|
||||
({
|
||||
|
||||
@@ -66,7 +66,7 @@ values over time: this is implemented by the DecayingSample class.
|
||||
Each server in a cluster creates a list of IP addresses of end points
|
||||
that are imposing a significant load. This list is called Gossip, which
|
||||
is passed to other nodes in that cluster. Gossip helps individual
|
||||
servers in the cluster identify IP addreses that might be unduly loading
|
||||
servers in the cluster identify IP addresses that might be unduly loading
|
||||
the entire cluster. Again the recourse of the individual servers is to
|
||||
drop connections to those IP addresses that occur commonly in the gossip.
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ private:
|
||||
// List of all active admin entries
|
||||
EntryIntrusiveList admin_;
|
||||
|
||||
// List of all inactve entries
|
||||
// List of all inactive entries
|
||||
EntryIntrusiveList inactive_;
|
||||
|
||||
// All imported gossip data
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
// Before boost 1.70, get_lowest_layer required an explicit templat parameter
|
||||
// Before boost 1.70, get_lowest_layer required an explicit template parameter
|
||||
template <class T>
|
||||
decltype(auto)
|
||||
get_lowest_layer(T& t) noexcept
|
||||
|
||||
@@ -226,7 +226,7 @@ The `fetchNodeNT()` method goes through three phases:
|
||||
|
||||
Any SHAMapLeafNode that is immutable has a sequence number of zero
|
||||
(sharable). When a mutable `SHAMap` is created then its SHAMapTreeNodes are
|
||||
given non-zero sequence numbers (unsharable). But all nodes in the
|
||||
given non-zero sequence numbers (unshareable). But all nodes in the
|
||||
TreeNodeCache are immutable, so if one is found here, its sequence number
|
||||
will be 0.
|
||||
|
||||
|
||||
@@ -125,13 +125,13 @@ intrusive_ptr_release(SHAMapItem const* x)
|
||||
{
|
||||
auto p = reinterpret_cast<std::uint8_t const*>(x);
|
||||
|
||||
// The SHAMapItem constuctor isn't trivial (because the destructor
|
||||
// The SHAMapItem constructor isn't trivial (because the destructor
|
||||
// for CountedObject isn't) so we can't avoid calling it here, but
|
||||
// plan for a future where we might not need to.
|
||||
if constexpr (!std::is_trivially_destructible_v<SHAMapItem>)
|
||||
std::destroy_at(x);
|
||||
|
||||
// If the slabber doens't claim this pointer, it was allocated
|
||||
// If the slabber doesn't claim this pointer, it was allocated
|
||||
// manually, so we free it manually.
|
||||
if (!detail::slabber.deallocate(const_cast<std::uint8_t*>(p)))
|
||||
delete[] p;
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
# CMake configuration for doctest-based tests
|
||||
# These are converted from the beast unit_test framework
|
||||
|
||||
include(XrplAddTest)
|
||||
|
||||
find_package(doctest REQUIRED)
|
||||
|
||||
# Custom target for all doctest tests defined in this file
|
||||
add_custom_target(xrpl.doctests)
|
||||
|
||||
# Common library dependencies
|
||||
add_library(xrpl.imports.doctest INTERFACE)
|
||||
target_link_libraries(xrpl.imports.doctest INTERFACE
|
||||
doctest::doctest
|
||||
xrpl.libxrpl
|
||||
)
|
||||
|
||||
# Include xrpld sources for tests that need app-level functionality
|
||||
target_include_directories(xrpl.imports.doctest INTERFACE
|
||||
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/src>
|
||||
)
|
||||
|
||||
# Link against xrpld libraries for tests that need app-level functionality
|
||||
target_link_libraries(xrpl.imports.doctest INTERFACE
|
||||
Xrpl::boost
|
||||
Xrpl::opts
|
||||
Xrpl::libs
|
||||
)
|
||||
|
||||
# Compiler flags for strict checking
|
||||
set(DOCTEST_COMPILE_FLAGS
|
||||
-m64
|
||||
-g
|
||||
-fPIE
|
||||
-Wno-unknown-warning-option
|
||||
-Wall
|
||||
-Wdeprecated
|
||||
-Wno-deprecated-declarations
|
||||
-Wextra
|
||||
-Wno-unused-parameter
|
||||
-Werror
|
||||
-fstack-protector
|
||||
-Wno-sign-compare
|
||||
-Wno-unused-but-set-variable
|
||||
)
|
||||
|
||||
# Helper function to add a doctest module
|
||||
function(xrpl_add_doctest name)
|
||||
file(GLOB_RECURSE sources CONFIGURE_DEPENDS
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/${name}/*.cpp"
|
||||
)
|
||||
|
||||
set(target xrpl.doctest.${name})
|
||||
add_executable(${target} ${sources})
|
||||
target_link_libraries(${target} PRIVATE xrpl.imports.doctest)
|
||||
target_compile_options(${target} PRIVATE ${DOCTEST_COMPILE_FLAGS})
|
||||
|
||||
set_target_properties(${target} PROPERTIES
|
||||
UNITY_BUILD_MODE GROUP
|
||||
UNITY_BUILD_BATCH_SIZE 0
|
||||
)
|
||||
|
||||
add_test(NAME ${target} COMMAND ${target})
|
||||
add_dependencies(xrpl.doctests ${target})
|
||||
endfunction()
|
||||
|
||||
# One test executable for each module
|
||||
xrpl_add_doctest(basics)
|
||||
xrpl_add_doctest(beast)
|
||||
xrpl_add_doctest(core)
|
||||
xrpl_add_doctest(csf)
|
||||
xrpl_add_doctest(nodestore)
|
||||
xrpl_add_doctest(protocol)
|
||||
@@ -1,171 +0,0 @@
|
||||
# Doctest Migration Documentation
|
||||
|
||||
This document describes the migration of unit tests from the beast `unit_test` framework to the doctest framework.
|
||||
|
||||
## Overview
|
||||
|
||||
Tests were migrated from `src/test/` (beast unit_test format) to `src/doctest/` (doctest format), following the pattern established in `src/tests/libxrpl/`.
|
||||
|
||||
## Build Configuration
|
||||
|
||||
### CMakeLists.txt Structure
|
||||
|
||||
Created `src/doctest/CMakeLists.txt` with:
|
||||
- Helper function `xrpl_add_doctest(name)` that creates per-module executables
|
||||
- Compiler flags: `-m64 -g -std=c++20 -fPIE -Wno-unknown-warning-option -Wall -Wdeprecated -Wno-deprecated-declarations -Wextra -Wno-unused-parameter -Werror -fstack-protector -Wno-sign-compare -Wno-unused-but-set-variable -MD -MT -MF`
|
||||
- Six module targets: `xrpl.doctest.basics`, `xrpl.doctest.beast`, `xrpl.doctest.core`, `xrpl.doctest.csf`, `xrpl.doctest.nodestore`, `xrpl.doctest.protocol`
|
||||
|
||||
### Module Structure
|
||||
|
||||
Each module has its own `main.cpp` following the pre-migrated test pattern:
|
||||
```
|
||||
src/doctest/
|
||||
├── basics/main.cpp
|
||||
├── beast/main.cpp
|
||||
├── core/main.cpp
|
||||
├── csf/main.cpp
|
||||
├── nodestore/main.cpp
|
||||
└── protocol/main.cpp
|
||||
```
|
||||
|
||||
## Framework Conversion Patterns
|
||||
|
||||
| Beast Unit Test | Doctest Equivalent |
|
||||
|-----------------|-------------------|
|
||||
| `#include <xrpl/beast/unit_test.h>` | `#include <doctest/doctest.h>` |
|
||||
| `BEAST_EXPECT(expr)` | `CHECK(expr)` |
|
||||
| `BEAST_EXPECTS(expr, msg)` | `CHECK_MESSAGE(expr, msg)` |
|
||||
| `testcase("name")` | `SUBCASE("name")` |
|
||||
| `class X : public unit_test::suite { ... }` | Free functions with `TEST_CASE` |
|
||||
| `BEAST_DEFINE_TESTSUITE(Name, Module, Lib)` | `TEST_CASE("Name")` |
|
||||
| `pass()` / `fail()` | `CHECK(true)` / `CHECK(false)` |
|
||||
|
||||
## Namespace Changes
|
||||
|
||||
- Changed from `namespace ripple` to `namespace xrpl` where applicable
|
||||
- Header paths changed from `xrpld/` to `xrpl/` (e.g., `xrpld/app/` → `xrpl/protocol/`)
|
||||
|
||||
## Common Migration Issues and Solutions
|
||||
|
||||
### 1. CHECK Macro with Complex Expressions
|
||||
|
||||
**Problem**: Doctest's CHECK macro doesn't support `&&` or `||` in expressions.
|
||||
|
||||
```cpp
|
||||
// Doesn't work
|
||||
CHECK(a && b);
|
||||
|
||||
// Solution: Split into separate checks
|
||||
CHECK(a);
|
||||
CHECK(b);
|
||||
```
|
||||
|
||||
### 2. CHECK Macro with Custom Iterator Comparisons
|
||||
|
||||
**Problem**: CHECK wraps expressions in `Expression_lhs<>` which breaks template argument deduction for custom comparison operators (especially boost::intrusive iterators).
|
||||
|
||||
```cpp
|
||||
// Doesn't compile
|
||||
CHECK(iter != container.end());
|
||||
|
||||
// Solution: Store result in bool first
|
||||
bool notEnd = (iter != container.end());
|
||||
CHECK(notEnd);
|
||||
```
|
||||
|
||||
### 3. Constructor Argument Order
|
||||
|
||||
Some container constructors have different argument order than initially assumed:
|
||||
|
||||
```cpp
|
||||
// Wrong order
|
||||
Container c(clock, first, last);
|
||||
|
||||
// Correct order (iterators before clock)
|
||||
Container c(first, last, clock);
|
||||
```
|
||||
|
||||
### 4. Return Type Differences
|
||||
|
||||
For map types with `P&&` insert overloads, return types differ:
|
||||
|
||||
```cpp
|
||||
// Use if constexpr to handle both cases
|
||||
if constexpr (!IsMulti && IsMap)
|
||||
{
|
||||
auto result = c.insert(c.end(), value); // returns pair<iterator, bool>
|
||||
CHECK(result.first != c.end());
|
||||
}
|
||||
else
|
||||
{
|
||||
auto it = c.insert(c.end(), value); // returns iterator
|
||||
CHECK(it != c.end());
|
||||
}
|
||||
```
|
||||
|
||||
## Files Migrated
|
||||
|
||||
### basics/ (13 files)
|
||||
- Buffer.cpp, Expected.cpp, IOUAmount.cpp, KeyCache.cpp, Number.cpp
|
||||
- StringUtilities.cpp, TaggedCache.cpp, Units.cpp, XRPAmount.cpp
|
||||
- base58.cpp, base_uint.cpp, hardened_hash.cpp, join.cpp
|
||||
|
||||
### beast/ (11 files)
|
||||
- CurrentThreadName.cpp, IPEndpoint.cpp, Journal.cpp, LexicalCast.cpp
|
||||
- PropertyStream.cpp, SemanticVersion.cpp, aged_associative_container.cpp
|
||||
- basic_seconds_clock.cpp, beast_Zero.cpp, xxhasher.cpp
|
||||
|
||||
### core/ (1 file)
|
||||
- Workers.cpp
|
||||
|
||||
### csf/ (4 files)
|
||||
- BasicNetwork.cpp, Digraph.cpp, Histogram.cpp, Scheduler.cpp
|
||||
|
||||
### nodestore/ (1 file)
|
||||
- varint.cpp
|
||||
|
||||
### protocol/ (14 files)
|
||||
- ApiVersion.cpp, BuildInfo.cpp, Issue.cpp, MultiApiJson.cpp
|
||||
- PublicKey.cpp, Quality.cpp, STAccount.cpp, STInteger.cpp
|
||||
- STNumber.cpp, SecretKey.cpp, Seed.cpp, SeqProxy.cpp
|
||||
- Serializer.cpp, TER.cpp
|
||||
|
||||
## Test Results Summary
|
||||
|
||||
| Module | Test Cases | Assertions |
|
||||
|--------|------------|------------|
|
||||
| basics | 61 | 2,638,582 |
|
||||
| beast | 48 | 162,715 |
|
||||
| core | 6 | 66 |
|
||||
| csf | 8 | 101 |
|
||||
| nodestore | 1 | 68 |
|
||||
| protocol | 73 | 20,372 |
|
||||
| **Total** | **197** | **2,821,904** |
|
||||
|
||||
## Running Tests
|
||||
|
||||
```bash
|
||||
# Build all doctest targets
|
||||
cd .build
|
||||
cmake --build . --target xrpl.doctests
|
||||
|
||||
# Run individual module
|
||||
./src/doctest/xrpl.doctest.basics
|
||||
./src/doctest/xrpl.doctest.beast
|
||||
./src/doctest/xrpl.doctest.core
|
||||
./src/doctest/xrpl.doctest.csf
|
||||
./src/doctest/xrpl.doctest.nodestore
|
||||
./src/doctest/xrpl.doctest.protocol
|
||||
|
||||
# Run all tests
|
||||
for test in src/doctest/xrpl.doctest.*; do ./$test; done
|
||||
```
|
||||
|
||||
## Tests Not Migrated
|
||||
|
||||
Some tests were not migrated due to dependencies:
|
||||
- **Manual tests** requiring user interaction (e.g., `DetectCrash_test`)
|
||||
- **Tests using xrpld infrastructure** (`test/jtx.h`, `unit_test/SuiteJournal.h`)
|
||||
- **Complex async tests** using boost coroutines
|
||||
- **Tests with FileDirGuard** or other test-specific utilities
|
||||
|
||||
@@ -1,257 +0,0 @@
|
||||
#include <xrpl/basics/Buffer.h>
|
||||
|
||||
#include <doctest/doctest.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
|
||||
using namespace xrpl;
|
||||
|
||||
namespace {
|
||||
bool
|
||||
sane(Buffer const& b)
|
||||
{
|
||||
if (b.size() == 0)
|
||||
return b.data() == nullptr;
|
||||
|
||||
return b.data() != nullptr;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST_SUITE_BEGIN("Buffer");
|
||||
|
||||
TEST_CASE("basic operations")
|
||||
{
|
||||
std::uint8_t const data[] = {
|
||||
0xa8, 0xa1, 0x38, 0x45, 0x23, 0xec, 0xe4, 0x23, 0x71, 0x6d, 0x2a,
|
||||
0x18, 0xb4, 0x70, 0xcb, 0xf5, 0xac, 0x2d, 0x89, 0x4d, 0x19, 0x9c,
|
||||
0xf0, 0x2c, 0x15, 0xd1, 0xf9, 0x9b, 0x66, 0xd2, 0x30, 0xd3};
|
||||
|
||||
Buffer b0;
|
||||
CHECK(sane(b0));
|
||||
CHECK(b0.empty());
|
||||
|
||||
Buffer b1{0};
|
||||
CHECK(sane(b1));
|
||||
CHECK(b1.empty());
|
||||
std::memcpy(b1.alloc(16), data, 16);
|
||||
CHECK(sane(b1));
|
||||
CHECK(!b1.empty());
|
||||
CHECK(b1.size() == 16);
|
||||
|
||||
Buffer b2{b1.size()};
|
||||
CHECK(sane(b2));
|
||||
CHECK(!b2.empty());
|
||||
CHECK(b2.size() == b1.size());
|
||||
std::memcpy(b2.data(), data + 16, 16);
|
||||
|
||||
Buffer b3{data, sizeof(data)};
|
||||
CHECK(sane(b3));
|
||||
CHECK(!b3.empty());
|
||||
CHECK(b3.size() == sizeof(data));
|
||||
CHECK(std::memcmp(b3.data(), data, b3.size()) == 0);
|
||||
|
||||
// Check equality and inequality comparisons
|
||||
CHECK(b0 == b0);
|
||||
CHECK(b0 != b1);
|
||||
CHECK(b1 == b1);
|
||||
CHECK(b1 != b2);
|
||||
CHECK(b2 != b3);
|
||||
|
||||
SUBCASE("Copy Construction / Assignment")
|
||||
{
|
||||
Buffer x{b0};
|
||||
CHECK(x == b0);
|
||||
CHECK(sane(x));
|
||||
Buffer y{b1};
|
||||
CHECK(y == b1);
|
||||
CHECK(sane(y));
|
||||
x = b2;
|
||||
CHECK(x == b2);
|
||||
CHECK(sane(x));
|
||||
x = y;
|
||||
CHECK(x == y);
|
||||
CHECK(sane(x));
|
||||
y = b3;
|
||||
CHECK(y == b3);
|
||||
CHECK(sane(y));
|
||||
x = b0;
|
||||
CHECK(x == b0);
|
||||
CHECK(sane(x));
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wself-assign-overloaded"
|
||||
#endif
|
||||
|
||||
x = x;
|
||||
CHECK(x == b0);
|
||||
CHECK(sane(x));
|
||||
y = y;
|
||||
CHECK(y == b3);
|
||||
CHECK(sane(y));
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
}
|
||||
|
||||
SUBCASE("Move Construction / Assignment")
|
||||
{
|
||||
static_assert(std::is_nothrow_move_constructible<Buffer>::value, "");
|
||||
static_assert(std::is_nothrow_move_assignable<Buffer>::value, "");
|
||||
|
||||
{ // Move-construct from empty buf
|
||||
Buffer x;
|
||||
Buffer y{std::move(x)};
|
||||
CHECK(sane(x));
|
||||
CHECK(x.empty());
|
||||
CHECK(sane(y));
|
||||
CHECK(y.empty());
|
||||
CHECK(x == y);
|
||||
}
|
||||
|
||||
{ // Move-construct from non-empty buf
|
||||
Buffer x{b1};
|
||||
Buffer y{std::move(x)};
|
||||
CHECK(sane(x));
|
||||
CHECK(x.empty());
|
||||
CHECK(sane(y));
|
||||
CHECK(y == b1);
|
||||
}
|
||||
|
||||
{ // Move assign empty buf to empty buf
|
||||
Buffer x;
|
||||
Buffer y;
|
||||
|
||||
x = std::move(y);
|
||||
CHECK(sane(x));
|
||||
CHECK(x.empty());
|
||||
CHECK(sane(y));
|
||||
CHECK(y.empty());
|
||||
}
|
||||
|
||||
{ // Move assign non-empty buf to empty buf
|
||||
Buffer x;
|
||||
Buffer y{b1};
|
||||
|
||||
x = std::move(y);
|
||||
CHECK(sane(x));
|
||||
CHECK(x == b1);
|
||||
CHECK(sane(y));
|
||||
CHECK(y.empty());
|
||||
}
|
||||
|
||||
{ // Move assign empty buf to non-empty buf
|
||||
Buffer x{b1};
|
||||
Buffer y;
|
||||
|
||||
x = std::move(y);
|
||||
CHECK(sane(x));
|
||||
CHECK(x.empty());
|
||||
CHECK(sane(y));
|
||||
CHECK(y.empty());
|
||||
}
|
||||
|
||||
{ // Move assign non-empty buf to non-empty buf
|
||||
Buffer x{b1};
|
||||
Buffer y{b2};
|
||||
Buffer z{b3};
|
||||
|
||||
x = std::move(y);
|
||||
CHECK(sane(x));
|
||||
CHECK(!x.empty());
|
||||
CHECK(sane(y));
|
||||
CHECK(y.empty());
|
||||
|
||||
x = std::move(z);
|
||||
CHECK(sane(x));
|
||||
CHECK(!x.empty());
|
||||
CHECK(sane(z));
|
||||
CHECK(z.empty());
|
||||
}
|
||||
}
|
||||
|
||||
SUBCASE("Slice Conversion / Construction / Assignment")
|
||||
{
|
||||
Buffer w{static_cast<Slice>(b0)};
|
||||
CHECK(sane(w));
|
||||
CHECK(w == b0);
|
||||
|
||||
Buffer x{static_cast<Slice>(b1)};
|
||||
CHECK(sane(x));
|
||||
CHECK(x == b1);
|
||||
|
||||
Buffer y{static_cast<Slice>(b2)};
|
||||
CHECK(sane(y));
|
||||
CHECK(y == b2);
|
||||
|
||||
Buffer z{static_cast<Slice>(b3)};
|
||||
CHECK(sane(z));
|
||||
CHECK(z == b3);
|
||||
|
||||
// Assign empty slice to empty buffer
|
||||
w = static_cast<Slice>(b0);
|
||||
CHECK(sane(w));
|
||||
CHECK(w == b0);
|
||||
|
||||
// Assign non-empty slice to empty buffer
|
||||
w = static_cast<Slice>(b1);
|
||||
CHECK(sane(w));
|
||||
CHECK(w == b1);
|
||||
|
||||
// Assign non-empty slice to non-empty buffer
|
||||
x = static_cast<Slice>(b2);
|
||||
CHECK(sane(x));
|
||||
CHECK(x == b2);
|
||||
|
||||
// Assign non-empty slice to non-empty buffer
|
||||
y = static_cast<Slice>(z);
|
||||
CHECK(sane(y));
|
||||
CHECK(y == z);
|
||||
|
||||
// Assign empty slice to non-empty buffer:
|
||||
z = static_cast<Slice>(b0);
|
||||
CHECK(sane(z));
|
||||
CHECK(z == b0);
|
||||
}
|
||||
|
||||
SUBCASE("Allocation, Deallocation and Clearing")
|
||||
{
|
||||
auto test = [](Buffer const& b, std::size_t i) {
|
||||
Buffer x{b};
|
||||
|
||||
// Try to allocate some number of bytes, possibly
|
||||
// zero (which means clear) and sanity check
|
||||
x(i);
|
||||
CHECK(sane(x));
|
||||
CHECK(x.size() == i);
|
||||
CHECK((x.data() == nullptr) == (i == 0));
|
||||
|
||||
// Try to allocate some more data (always non-zero)
|
||||
x(i + 1);
|
||||
CHECK(sane(x));
|
||||
CHECK(x.size() == i + 1);
|
||||
CHECK(x.data() != nullptr);
|
||||
|
||||
// Try to clear:
|
||||
x.clear();
|
||||
CHECK(sane(x));
|
||||
CHECK(x.size() == 0);
|
||||
CHECK(x.data() == nullptr);
|
||||
|
||||
// Try to clear again:
|
||||
x.clear();
|
||||
CHECK(sane(x));
|
||||
CHECK(x.size() == 0);
|
||||
CHECK(x.data() == nullptr);
|
||||
};
|
||||
|
||||
for (std::size_t i = 0; i < 16; ++i)
|
||||
{
|
||||
test(b0, i);
|
||||
test(b1, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
@@ -1,228 +0,0 @@
|
||||
#include <xrpl/basics/Expected.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
|
||||
#include <doctest/doctest.h>
|
||||
|
||||
#if BOOST_VERSION >= 107500
|
||||
#include <boost/json.hpp> // Not part of boost before version 1.75
|
||||
#endif // BOOST_VERSION
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
|
||||
using namespace xrpl;
|
||||
|
||||
TEST_SUITE_BEGIN("Expected");
|
||||
|
||||
TEST_CASE("non-error const construction")
|
||||
{
|
||||
auto const expected = []() -> Expected<std::string, TER> {
|
||||
return "Valid value";
|
||||
}();
|
||||
CHECK(expected);
|
||||
CHECK(expected.has_value());
|
||||
CHECK(expected.value() == "Valid value");
|
||||
CHECK(*expected == "Valid value");
|
||||
CHECK(expected->at(0) == 'V');
|
||||
|
||||
bool throwOccurred = false;
|
||||
try
|
||||
{
|
||||
// There's no error, so should throw.
|
||||
[[maybe_unused]] TER const t = expected.error();
|
||||
}
|
||||
catch (std::runtime_error const& e)
|
||||
{
|
||||
CHECK(e.what() == std::string("bad expected access"));
|
||||
throwOccurred = true;
|
||||
}
|
||||
CHECK(throwOccurred);
|
||||
}
|
||||
|
||||
TEST_CASE("non-error non-const construction")
|
||||
{
|
||||
auto expected = []() -> Expected<std::string, TER> {
|
||||
return "Valid value";
|
||||
}();
|
||||
CHECK(expected);
|
||||
CHECK(expected.has_value());
|
||||
CHECK(expected.value() == "Valid value");
|
||||
CHECK(*expected == "Valid value");
|
||||
CHECK(expected->at(0) == 'V');
|
||||
std::string mv = std::move(*expected);
|
||||
CHECK(mv == "Valid value");
|
||||
|
||||
bool throwOccurred = false;
|
||||
try
|
||||
{
|
||||
// There's no error, so should throw.
|
||||
[[maybe_unused]] TER const t = expected.error();
|
||||
}
|
||||
catch (std::runtime_error const& e)
|
||||
{
|
||||
CHECK(e.what() == std::string("bad expected access"));
|
||||
throwOccurred = true;
|
||||
}
|
||||
CHECK(throwOccurred);
|
||||
}
|
||||
|
||||
TEST_CASE("non-error overlapping type construction")
|
||||
{
|
||||
auto expected = []() -> Expected<std::uint32_t, std::uint16_t> {
|
||||
return 1;
|
||||
}();
|
||||
CHECK(expected);
|
||||
CHECK(expected.has_value());
|
||||
CHECK(expected.value() == 1);
|
||||
CHECK(*expected == 1);
|
||||
|
||||
bool throwOccurred = false;
|
||||
try
|
||||
{
|
||||
// There's no error, so should throw.
|
||||
[[maybe_unused]] std::uint16_t const t = expected.error();
|
||||
}
|
||||
catch (std::runtime_error const& e)
|
||||
{
|
||||
CHECK(e.what() == std::string("bad expected access"));
|
||||
throwOccurred = true;
|
||||
}
|
||||
CHECK(throwOccurred);
|
||||
}
|
||||
|
||||
TEST_CASE("error construction from rvalue")
|
||||
{
|
||||
auto const expected = []() -> Expected<std::string, TER> {
|
||||
return Unexpected(telLOCAL_ERROR);
|
||||
}();
|
||||
CHECK(!expected);
|
||||
CHECK(!expected.has_value());
|
||||
CHECK(expected.error() == telLOCAL_ERROR);
|
||||
|
||||
bool throwOccurred = false;
|
||||
try
|
||||
{
|
||||
// There's no result, so should throw.
|
||||
[[maybe_unused]] std::string const s = *expected;
|
||||
}
|
||||
catch (std::runtime_error const& e)
|
||||
{
|
||||
CHECK(e.what() == std::string("bad expected access"));
|
||||
throwOccurred = true;
|
||||
}
|
||||
CHECK(throwOccurred);
|
||||
}
|
||||
|
||||
TEST_CASE("error construction from lvalue")
|
||||
{
|
||||
auto const err(telLOCAL_ERROR);
|
||||
auto expected = [&err]() -> Expected<std::string, TER> {
|
||||
return Unexpected(err);
|
||||
}();
|
||||
CHECK(!expected);
|
||||
CHECK(!expected.has_value());
|
||||
CHECK(expected.error() == telLOCAL_ERROR);
|
||||
|
||||
bool throwOccurred = false;
|
||||
try
|
||||
{
|
||||
// There's no result, so should throw.
|
||||
[[maybe_unused]] std::size_t const s = expected->size();
|
||||
}
|
||||
catch (std::runtime_error const& e)
|
||||
{
|
||||
CHECK(e.what() == std::string("bad expected access"));
|
||||
throwOccurred = true;
|
||||
}
|
||||
CHECK(throwOccurred);
|
||||
}
|
||||
|
||||
TEST_CASE("error construction from const char*")
|
||||
{
|
||||
auto const expected = []() -> Expected<int, char const*> {
|
||||
return Unexpected("Not what is expected!");
|
||||
}();
|
||||
CHECK(!expected);
|
||||
CHECK(!expected.has_value());
|
||||
CHECK(expected.error() == std::string("Not what is expected!"));
|
||||
}
|
||||
|
||||
TEST_CASE("error construction of string from const char*")
|
||||
{
|
||||
auto expected = []() -> Expected<int, std::string> {
|
||||
return Unexpected("Not what is expected!");
|
||||
}();
|
||||
CHECK(!expected);
|
||||
CHECK(!expected.has_value());
|
||||
CHECK(expected.error() == "Not what is expected!");
|
||||
std::string const s(std::move(expected.error()));
|
||||
CHECK(s == "Not what is expected!");
|
||||
}
|
||||
|
||||
TEST_CASE("non-error const construction of Expected<void, T>")
|
||||
{
|
||||
auto const expected = []() -> Expected<void, std::string> { return {}; }();
|
||||
CHECK(expected);
|
||||
bool throwOccurred = false;
|
||||
try
|
||||
{
|
||||
// There's no error, so should throw.
|
||||
[[maybe_unused]] std::size_t const s = expected.error().size();
|
||||
}
|
||||
catch (std::runtime_error const& e)
|
||||
{
|
||||
CHECK(e.what() == std::string("bad expected access"));
|
||||
throwOccurred = true;
|
||||
}
|
||||
CHECK(throwOccurred);
|
||||
}
|
||||
|
||||
TEST_CASE("non-error non-const construction of Expected<void, T>")
|
||||
{
|
||||
auto expected = []() -> Expected<void, std::string> { return {}; }();
|
||||
CHECK(expected);
|
||||
bool throwOccurred = false;
|
||||
try
|
||||
{
|
||||
// There's no error, so should throw.
|
||||
[[maybe_unused]] std::size_t const s = expected.error().size();
|
||||
}
|
||||
catch (std::runtime_error const& e)
|
||||
{
|
||||
CHECK(e.what() == std::string("bad expected access"));
|
||||
throwOccurred = true;
|
||||
}
|
||||
CHECK(throwOccurred);
|
||||
}
|
||||
|
||||
TEST_CASE("error const construction of Expected<void, T>")
|
||||
{
|
||||
auto const expected = []() -> Expected<void, std::string> {
|
||||
return Unexpected("Not what is expected!");
|
||||
}();
|
||||
CHECK(!expected);
|
||||
CHECK(expected.error() == "Not what is expected!");
|
||||
}
|
||||
|
||||
TEST_CASE("error non-const construction of Expected<void, T>")
|
||||
{
|
||||
auto expected = []() -> Expected<void, std::string> {
|
||||
return Unexpected("Not what is expected!");
|
||||
}();
|
||||
CHECK(!expected);
|
||||
CHECK(expected.error() == "Not what is expected!");
|
||||
std::string const s(std::move(expected.error()));
|
||||
CHECK(s == "Not what is expected!");
|
||||
}
|
||||
|
||||
#if BOOST_VERSION >= 107500
|
||||
TEST_CASE("boost::json::value construction")
|
||||
{
|
||||
auto expected = []() -> Expected<boost::json::value, std::string> {
|
||||
return boost::json::object{{"oops", "me array now"}};
|
||||
}();
|
||||
CHECK(expected);
|
||||
CHECK(!expected.value().is_array());
|
||||
}
|
||||
#endif // BOOST_VERSION
|
||||
|
||||
TEST_SUITE_END();
|
||||
@@ -1,220 +0,0 @@
|
||||
#include <xrpl/protocol/IOUAmount.h>
|
||||
|
||||
#include <doctest/doctest.h>
|
||||
|
||||
using namespace xrpl;
|
||||
|
||||
TEST_SUITE_BEGIN("IOUAmount");
|
||||
|
||||
TEST_CASE("zero")
|
||||
{
|
||||
IOUAmount const z(0, 0);
|
||||
|
||||
CHECK(z.mantissa() == 0);
|
||||
CHECK(z.exponent() == -100);
|
||||
CHECK(!z);
|
||||
CHECK(z.signum() == 0);
|
||||
CHECK(z == beast::zero);
|
||||
|
||||
CHECK((z + z) == z);
|
||||
CHECK((z - z) == z);
|
||||
CHECK(z == -z);
|
||||
|
||||
IOUAmount const zz(beast::zero);
|
||||
CHECK(z == zz);
|
||||
|
||||
// https://github.com/XRPLF/rippled/issues/5170
|
||||
IOUAmount const zzz{};
|
||||
CHECK(zzz == beast::zero);
|
||||
}
|
||||
|
||||
TEST_CASE("signum")
|
||||
{
|
||||
IOUAmount const neg(-1, 0);
|
||||
CHECK(neg.signum() < 0);
|
||||
|
||||
IOUAmount const zer(0, 0);
|
||||
CHECK(zer.signum() == 0);
|
||||
|
||||
IOUAmount const pos(1, 0);
|
||||
CHECK(pos.signum() > 0);
|
||||
}
|
||||
|
||||
TEST_CASE("beast::Zero Comparisons")
|
||||
{
|
||||
using beast::zero;
|
||||
|
||||
{
|
||||
IOUAmount z(zero);
|
||||
CHECK(z == zero);
|
||||
CHECK(z >= zero);
|
||||
CHECK(z <= zero);
|
||||
CHECK(!(z != zero));
|
||||
CHECK(!(z > zero));
|
||||
CHECK(!(z < zero));
|
||||
}
|
||||
|
||||
{
|
||||
IOUAmount const neg(-2, 0);
|
||||
CHECK(neg < zero);
|
||||
CHECK(neg <= zero);
|
||||
CHECK(neg != zero);
|
||||
CHECK(!(neg == zero));
|
||||
}
|
||||
|
||||
{
|
||||
IOUAmount const pos(2, 0);
|
||||
CHECK(pos > zero);
|
||||
CHECK(pos >= zero);
|
||||
CHECK(pos != zero);
|
||||
CHECK(!(pos == zero));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("IOU Comparisons")
|
||||
{
|
||||
IOUAmount const n(-2, 0);
|
||||
IOUAmount const z(0, 0);
|
||||
IOUAmount const p(2, 0);
|
||||
|
||||
CHECK(z == z);
|
||||
CHECK(z >= z);
|
||||
CHECK(z <= z);
|
||||
CHECK(z == -z);
|
||||
CHECK(!(z > z));
|
||||
CHECK(!(z < z));
|
||||
CHECK(!(z != z));
|
||||
CHECK(!(z != -z));
|
||||
|
||||
CHECK(n < z);
|
||||
CHECK(n <= z);
|
||||
CHECK(n != z);
|
||||
CHECK(!(n > z));
|
||||
CHECK(!(n >= z));
|
||||
CHECK(!(n == z));
|
||||
|
||||
CHECK(p > z);
|
||||
CHECK(p >= z);
|
||||
CHECK(p != z);
|
||||
CHECK(!(p < z));
|
||||
CHECK(!(p <= z));
|
||||
CHECK(!(p == z));
|
||||
|
||||
CHECK(n < p);
|
||||
CHECK(n <= p);
|
||||
CHECK(n != p);
|
||||
CHECK(!(n > p));
|
||||
CHECK(!(n >= p));
|
||||
CHECK(!(n == p));
|
||||
|
||||
CHECK(p > n);
|
||||
CHECK(p >= n);
|
||||
CHECK(p != n);
|
||||
CHECK(!(p < n));
|
||||
CHECK(!(p <= n));
|
||||
CHECK(!(p == n));
|
||||
|
||||
CHECK(p > -p);
|
||||
CHECK(p >= -p);
|
||||
CHECK(p != -p);
|
||||
|
||||
CHECK(n < -n);
|
||||
CHECK(n <= -n);
|
||||
CHECK(n != -n);
|
||||
}
|
||||
|
||||
TEST_CASE("IOU strings")
|
||||
{
|
||||
CHECK(to_string(IOUAmount(-2, 0)) == "-2");
|
||||
CHECK(to_string(IOUAmount(0, 0)) == "0");
|
||||
CHECK(to_string(IOUAmount(2, 0)) == "2");
|
||||
CHECK(to_string(IOUAmount(25, -3)) == "0.025");
|
||||
CHECK(to_string(IOUAmount(-25, -3)) == "-0.025");
|
||||
CHECK(to_string(IOUAmount(25, 1)) == "250");
|
||||
CHECK(to_string(IOUAmount(-25, 1)) == "-250");
|
||||
CHECK(to_string(IOUAmount(2, 20)) == "2000000000000000e5");
|
||||
CHECK(to_string(IOUAmount(-2, -20)) == "-2000000000000000e-35");
|
||||
}
|
||||
|
||||
TEST_CASE("mulRatio")
|
||||
{
|
||||
/* The range for the mantissa when normalized */
|
||||
constexpr std::int64_t minMantissa = 1000000000000000ull;
|
||||
constexpr std::int64_t maxMantissa = 9999999999999999ull;
|
||||
/* The range for the exponent when normalized */
|
||||
constexpr int minExponent = -96;
|
||||
constexpr int maxExponent = 80;
|
||||
constexpr auto maxUInt = std::numeric_limits<std::uint32_t>::max();
|
||||
|
||||
{
|
||||
// multiply by a number that would overflow the mantissa, then
|
||||
// divide by the same number, and check we didn't lose any value
|
||||
IOUAmount bigMan(maxMantissa, 0);
|
||||
CHECK(bigMan == mulRatio(bigMan, maxUInt, maxUInt, true));
|
||||
// rounding mode shouldn't matter as the result is exact
|
||||
CHECK(bigMan == mulRatio(bigMan, maxUInt, maxUInt, false));
|
||||
}
|
||||
{
|
||||
// Similar test as above, but for negative values
|
||||
IOUAmount bigMan(-maxMantissa, 0);
|
||||
CHECK(bigMan == mulRatio(bigMan, maxUInt, maxUInt, true));
|
||||
// rounding mode shouldn't matter as the result is exact
|
||||
CHECK(bigMan == mulRatio(bigMan, maxUInt, maxUInt, false));
|
||||
}
|
||||
|
||||
{
|
||||
// small amounts
|
||||
IOUAmount tiny(minMantissa, minExponent);
|
||||
// Round up should give the smallest allowable number
|
||||
CHECK(tiny == mulRatio(tiny, 1, maxUInt, true));
|
||||
CHECK(tiny == mulRatio(tiny, maxUInt - 1, maxUInt, true));
|
||||
// rounding down should be zero
|
||||
CHECK(beast::zero == mulRatio(tiny, 1, maxUInt, false));
|
||||
CHECK(beast::zero == mulRatio(tiny, maxUInt - 1, maxUInt, false));
|
||||
|
||||
// tiny negative numbers
|
||||
IOUAmount tinyNeg(-minMantissa, minExponent);
|
||||
// Round up should give zero
|
||||
CHECK(beast::zero == mulRatio(tinyNeg, 1, maxUInt, true));
|
||||
CHECK(beast::zero == mulRatio(tinyNeg, maxUInt - 1, maxUInt, true));
|
||||
// rounding down should be tiny
|
||||
CHECK(tinyNeg == mulRatio(tinyNeg, 1, maxUInt, false));
|
||||
CHECK(tinyNeg == mulRatio(tinyNeg, maxUInt - 1, maxUInt, false));
|
||||
}
|
||||
|
||||
{ // rounding
|
||||
{
|
||||
IOUAmount one(1, 0);
|
||||
auto const rup = mulRatio(one, maxUInt - 1, maxUInt, true);
|
||||
auto const rdown = mulRatio(one, maxUInt - 1, maxUInt, false);
|
||||
CHECK(rup.mantissa() - rdown.mantissa() == 1);
|
||||
}
|
||||
{
|
||||
IOUAmount big(maxMantissa, maxExponent);
|
||||
auto const rup = mulRatio(big, maxUInt - 1, maxUInt, true);
|
||||
auto const rdown = mulRatio(big, maxUInt - 1, maxUInt, false);
|
||||
CHECK(rup.mantissa() - rdown.mantissa() == 1);
|
||||
}
|
||||
|
||||
{
|
||||
IOUAmount negOne(-1, 0);
|
||||
auto const rup = mulRatio(negOne, maxUInt - 1, maxUInt, true);
|
||||
auto const rdown = mulRatio(negOne, maxUInt - 1, maxUInt, false);
|
||||
CHECK(rup.mantissa() - rdown.mantissa() == 1);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// division by zero
|
||||
IOUAmount one(1, 0);
|
||||
CHECK_THROWS([&] { mulRatio(one, 1, 0, true); }());
|
||||
}
|
||||
|
||||
{
|
||||
// overflow
|
||||
IOUAmount big(maxMantissa, maxExponent);
|
||||
CHECK_THROWS([&] { mulRatio(big, 2, 0, true); }());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
@@ -1,74 +0,0 @@
|
||||
#include <xrpl/basics/TaggedCache.h>
|
||||
#include <xrpl/basics/TaggedCache.ipp>
|
||||
#include <xrpl/basics/chrono.h>
|
||||
#include <xrpl/protocol/Protocol.h>
|
||||
|
||||
#include <doctest/doctest.h>
|
||||
|
||||
using namespace xrpl;
|
||||
|
||||
TEST_SUITE_BEGIN("KeyCache");
|
||||
|
||||
TEST_CASE("KeyCache operations")
|
||||
{
|
||||
using namespace std::chrono_literals;
|
||||
TestStopwatch clock;
|
||||
clock.set(0);
|
||||
|
||||
using Key = std::string;
|
||||
using Cache = TaggedCache<Key, int, true>;
|
||||
|
||||
beast::Journal j{beast::Journal::getNullSink()};
|
||||
|
||||
SUBCASE("Insert, retrieve, and age item")
|
||||
{
|
||||
Cache c("test", LedgerIndex(1), 2s, clock, j);
|
||||
|
||||
CHECK(c.size() == 0);
|
||||
CHECK(c.insert("one"));
|
||||
CHECK(!c.insert("one"));
|
||||
CHECK(c.size() == 1);
|
||||
CHECK(c.touch_if_exists("one"));
|
||||
++clock;
|
||||
c.sweep();
|
||||
CHECK(c.size() == 1);
|
||||
++clock;
|
||||
c.sweep();
|
||||
CHECK(c.size() == 0);
|
||||
CHECK(!c.touch_if_exists("one"));
|
||||
}
|
||||
|
||||
SUBCASE("Insert two items, have one expire")
|
||||
{
|
||||
Cache c("test", LedgerIndex(2), 2s, clock, j);
|
||||
|
||||
CHECK(c.insert("one"));
|
||||
CHECK(c.size() == 1);
|
||||
CHECK(c.insert("two"));
|
||||
CHECK(c.size() == 2);
|
||||
++clock;
|
||||
c.sweep();
|
||||
CHECK(c.size() == 2);
|
||||
CHECK(c.touch_if_exists("two"));
|
||||
++clock;
|
||||
c.sweep();
|
||||
CHECK(c.size() == 1);
|
||||
}
|
||||
|
||||
SUBCASE("Insert three items (1 over limit), sweep")
|
||||
{
|
||||
Cache c("test", LedgerIndex(2), 3s, clock, j);
|
||||
|
||||
CHECK(c.insert("one"));
|
||||
++clock;
|
||||
CHECK(c.insert("two"));
|
||||
++clock;
|
||||
CHECK(c.insert("three"));
|
||||
++clock;
|
||||
CHECK(c.size() == 3);
|
||||
c.sweep();
|
||||
CHECK(c.size() < 3);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
@@ -1,416 +0,0 @@
|
||||
#include <xrpl/basics/Number.h>
|
||||
#include <xrpl/protocol/IOUAmount.h>
|
||||
#include <xrpl/protocol/STAmount.h>
|
||||
|
||||
#include <doctest/doctest.h>
|
||||
|
||||
#include <sstream>
|
||||
#include <tuple>
|
||||
|
||||
using namespace xrpl;
|
||||
|
||||
TEST_SUITE_BEGIN("Number");
|
||||
|
||||
TEST_CASE("zero")
|
||||
{
|
||||
Number const z{0, 0};
|
||||
|
||||
CHECK(z.mantissa() == 0);
|
||||
CHECK(z.exponent() == Number{}.exponent());
|
||||
|
||||
CHECK((z + z) == z);
|
||||
CHECK((z - z) == z);
|
||||
CHECK(z == -z);
|
||||
}
|
||||
|
||||
TEST_CASE("limits")
|
||||
{
|
||||
bool caught = false;
|
||||
try
|
||||
{
|
||||
Number x{10'000'000'000'000'000, 32768};
|
||||
}
|
||||
catch (std::overflow_error const&)
|
||||
{
|
||||
caught = true;
|
||||
}
|
||||
CHECK(caught);
|
||||
Number x{10'000'000'000'000'000, 32767};
|
||||
CHECK((x == Number{1'000'000'000'000'000, 32768}));
|
||||
Number z{1'000'000'000'000'000, -32769};
|
||||
CHECK(z == Number{});
|
||||
Number y{1'000'000'000'000'001'500, 32000};
|
||||
CHECK((y == Number{1'000'000'000'000'002, 32003}));
|
||||
Number m{std::numeric_limits<std::int64_t>::min()};
|
||||
CHECK((m == Number{-9'223'372'036'854'776, 3}));
|
||||
Number M{std::numeric_limits<std::int64_t>::max()};
|
||||
CHECK((M == Number{9'223'372'036'854'776, 3}));
|
||||
caught = false;
|
||||
try
|
||||
{
|
||||
Number q{99'999'999'999'999'999, 32767};
|
||||
}
|
||||
catch (std::overflow_error const&)
|
||||
{
|
||||
caught = true;
|
||||
}
|
||||
CHECK(caught);
|
||||
}
|
||||
|
||||
TEST_CASE("add")
|
||||
{
|
||||
using Case = std::tuple<Number, Number, Number>;
|
||||
Case c[]{
|
||||
{Number{1'000'000'000'000'000, -15},
|
||||
Number{6'555'555'555'555'555, -29},
|
||||
Number{1'000'000'000'000'066, -15}},
|
||||
{Number{-1'000'000'000'000'000, -15},
|
||||
Number{-6'555'555'555'555'555, -29},
|
||||
Number{-1'000'000'000'000'066, -15}},
|
||||
{Number{-1'000'000'000'000'000, -15},
|
||||
Number{6'555'555'555'555'555, -29},
|
||||
Number{-9'999'999'999'999'344, -16}},
|
||||
{Number{-6'555'555'555'555'555, -29},
|
||||
Number{1'000'000'000'000'000, -15},
|
||||
Number{9'999'999'999'999'344, -16}},
|
||||
{Number{}, Number{5}, Number{5}},
|
||||
{Number{5'555'555'555'555'555, -32768},
|
||||
Number{-5'555'555'555'555'554, -32768},
|
||||
Number{0}},
|
||||
{Number{-9'999'999'999'999'999, -31},
|
||||
Number{1'000'000'000'000'000, -15},
|
||||
Number{9'999'999'999'999'990, -16}}};
|
||||
for (auto const& [x, y, z] : c)
|
||||
CHECK(x + y == z);
|
||||
bool caught = false;
|
||||
try
|
||||
{
|
||||
Number{9'999'999'999'999'999, 32768} +
|
||||
Number{5'000'000'000'000'000, 32767};
|
||||
}
|
||||
catch (std::overflow_error const&)
|
||||
{
|
||||
caught = true;
|
||||
}
|
||||
CHECK(caught);
|
||||
}
|
||||
|
||||
TEST_CASE("sub")
|
||||
{
|
||||
using Case = std::tuple<Number, Number, Number>;
|
||||
Case c[]{
|
||||
{Number{1'000'000'000'000'000, -15},
|
||||
Number{6'555'555'555'555'555, -29},
|
||||
Number{9'999'999'999'999'344, -16}},
|
||||
{Number{6'555'555'555'555'555, -29},
|
||||
Number{1'000'000'000'000'000, -15},
|
||||
Number{-9'999'999'999'999'344, -16}},
|
||||
{Number{1'000'000'000'000'000, -15},
|
||||
Number{1'000'000'000'000'000, -15},
|
||||
Number{0}},
|
||||
{Number{1'000'000'000'000'000, -15},
|
||||
Number{1'000'000'000'000'001, -15},
|
||||
Number{-1'000'000'000'000'000, -30}},
|
||||
{Number{1'000'000'000'000'001, -15},
|
||||
Number{1'000'000'000'000'000, -15},
|
||||
Number{1'000'000'000'000'000, -30}}};
|
||||
for (auto const& [x, y, z] : c)
|
||||
CHECK(x - y == z);
|
||||
}
|
||||
|
||||
TEST_CASE("mul")
|
||||
{
|
||||
using Case = std::tuple<Number, Number, Number>;
|
||||
saveNumberRoundMode save{Number::setround(Number::to_nearest)};
|
||||
{
|
||||
Case c[]{
|
||||
{Number{7}, Number{8}, Number{56}},
|
||||
{Number{1414213562373095, -15},
|
||||
Number{1414213562373095, -15},
|
||||
Number{2000000000000000, -15}},
|
||||
{Number{-1414213562373095, -15},
|
||||
Number{1414213562373095, -15},
|
||||
Number{-2000000000000000, -15}},
|
||||
{Number{-1414213562373095, -15},
|
||||
Number{-1414213562373095, -15},
|
||||
Number{2000000000000000, -15}},
|
||||
{Number{3214285714285706, -15},
|
||||
Number{3111111111111119, -15},
|
||||
Number{1000000000000000, -14}},
|
||||
{Number{1000000000000000, -32768},
|
||||
Number{1000000000000000, -32768},
|
||||
Number{0}}};
|
||||
for (auto const& [x, y, z] : c)
|
||||
CHECK(x * y == z);
|
||||
}
|
||||
Number::setround(Number::towards_zero);
|
||||
{
|
||||
Case c[]{
|
||||
{Number{7}, Number{8}, Number{56}},
|
||||
{Number{1414213562373095, -15},
|
||||
Number{1414213562373095, -15},
|
||||
Number{1999999999999999, -15}}};
|
||||
for (auto const& [x, y, z] : c)
|
||||
CHECK(x * y == z);
|
||||
}
|
||||
bool caught = false;
|
||||
try
|
||||
{
|
||||
Number{9'999'999'999'999'999, 32768} *
|
||||
Number{5'000'000'000'000'000, 32767};
|
||||
}
|
||||
catch (std::overflow_error const&)
|
||||
{
|
||||
caught = true;
|
||||
}
|
||||
CHECK(caught);
|
||||
}
|
||||
|
||||
TEST_CASE("div")
|
||||
{
|
||||
using Case = std::tuple<Number, Number, Number>;
|
||||
saveNumberRoundMode save{Number::setround(Number::to_nearest)};
|
||||
{
|
||||
Case c[]{
|
||||
{Number{1}, Number{2}, Number{5, -1}},
|
||||
{Number{1}, Number{10}, Number{1, -1}},
|
||||
{Number{1}, Number{-10}, Number{-1, -1}},
|
||||
{Number{0}, Number{100}, Number{0}},
|
||||
{Number{1414213562373095, -10},
|
||||
Number{1414213562373095, -10},
|
||||
Number{1}},
|
||||
{Number{9'999'999'999'999'999},
|
||||
Number{1'000'000'000'000'000},
|
||||
Number{9'999'999'999'999'999, -15}},
|
||||
{Number{2}, Number{3}, Number{6'666'666'666'666'667, -16}},
|
||||
{Number{-2}, Number{3}, Number{-6'666'666'666'666'667, -16}}};
|
||||
for (auto const& [x, y, z] : c)
|
||||
CHECK(x / y == z);
|
||||
}
|
||||
bool caught = false;
|
||||
try
|
||||
{
|
||||
Number{1000000000000000, -15} / Number{0};
|
||||
}
|
||||
catch (std::overflow_error const&)
|
||||
{
|
||||
caught = true;
|
||||
}
|
||||
CHECK(caught);
|
||||
}
|
||||
|
||||
TEST_CASE("root")
|
||||
{
|
||||
using Case = std::tuple<Number, unsigned, Number>;
|
||||
Case c[]{
|
||||
{Number{2}, 2, Number{1414213562373095, -15}},
|
||||
{Number{2'000'000}, 2, Number{1414213562373095, -12}},
|
||||
{Number{2, -30}, 2, Number{1414213562373095, -30}},
|
||||
{Number{-27}, 3, Number{-3}},
|
||||
{Number{1}, 5, Number{1}},
|
||||
{Number{-1}, 0, Number{1}},
|
||||
{Number{5, -1}, 0, Number{0}},
|
||||
{Number{0}, 5, Number{0}},
|
||||
{Number{5625, -4}, 2, Number{75, -2}}};
|
||||
for (auto const& [x, y, z] : c)
|
||||
CHECK((root(x, y) == z));
|
||||
bool caught = false;
|
||||
try
|
||||
{
|
||||
(void)root(Number{-2}, 0);
|
||||
}
|
||||
catch (std::overflow_error const&)
|
||||
{
|
||||
caught = true;
|
||||
}
|
||||
CHECK(caught);
|
||||
caught = false;
|
||||
try
|
||||
{
|
||||
(void)root(Number{-2}, 4);
|
||||
}
|
||||
catch (std::overflow_error const&)
|
||||
{
|
||||
caught = true;
|
||||
}
|
||||
CHECK(caught);
|
||||
}
|
||||
|
||||
TEST_CASE("power1")
|
||||
{
|
||||
using Case = std::tuple<Number, unsigned, Number>;
|
||||
Case c[]{
|
||||
{Number{64}, 0, Number{1}},
|
||||
{Number{64}, 1, Number{64}},
|
||||
{Number{64}, 2, Number{4096}},
|
||||
{Number{-64}, 2, Number{4096}},
|
||||
{Number{64}, 3, Number{262144}},
|
||||
{Number{-64}, 3, Number{-262144}}};
|
||||
for (auto const& [x, y, z] : c)
|
||||
CHECK((power(x, y) == z));
|
||||
}
|
||||
|
||||
TEST_CASE("power2")
|
||||
{
|
||||
using Case = std::tuple<Number, unsigned, unsigned, Number>;
|
||||
Case c[]{
|
||||
{Number{1}, 3, 7, Number{1}},
|
||||
{Number{-1}, 1, 0, Number{1}},
|
||||
{Number{-1, -1}, 1, 0, Number{0}},
|
||||
{Number{16}, 0, 5, Number{1}},
|
||||
{Number{34}, 3, 3, Number{34}},
|
||||
{Number{4}, 3, 2, Number{8}}};
|
||||
for (auto const& [x, n, d, z] : c)
|
||||
CHECK((power(x, n, d) == z));
|
||||
bool caught = false;
|
||||
try
|
||||
{
|
||||
(void)power(Number{7}, 0, 0);
|
||||
}
|
||||
catch (std::overflow_error const&)
|
||||
{
|
||||
caught = true;
|
||||
}
|
||||
CHECK(caught);
|
||||
caught = false;
|
||||
try
|
||||
{
|
||||
(void)power(Number{7}, 1, 0);
|
||||
}
|
||||
catch (std::overflow_error const&)
|
||||
{
|
||||
caught = true;
|
||||
}
|
||||
CHECK(caught);
|
||||
caught = false;
|
||||
try
|
||||
{
|
||||
(void)power(Number{-1, -1}, 3, 2);
|
||||
}
|
||||
catch (std::overflow_error const&)
|
||||
{
|
||||
caught = true;
|
||||
}
|
||||
CHECK(caught);
|
||||
}
|
||||
|
||||
TEST_CASE("conversions")
|
||||
{
|
||||
IOUAmount x{5, 6};
|
||||
Number y = x;
|
||||
CHECK((y == Number{5, 6}));
|
||||
IOUAmount z{y};
|
||||
CHECK(x == z);
|
||||
XRPAmount xrp{500};
|
||||
STAmount st = xrp;
|
||||
Number n = st;
|
||||
CHECK(XRPAmount{n} == xrp);
|
||||
IOUAmount x0{0, 0};
|
||||
Number y0 = x0;
|
||||
CHECK((y0 == Number{0}));
|
||||
IOUAmount z0{y0};
|
||||
CHECK(x0 == z0);
|
||||
XRPAmount xrp0{0};
|
||||
Number n0 = xrp0;
|
||||
CHECK(n0 == Number{0});
|
||||
XRPAmount xrp1{n0};
|
||||
CHECK(xrp1 == xrp0);
|
||||
}
|
||||
|
||||
TEST_CASE("squelch")
|
||||
{
|
||||
Number limit{1, -6};
|
||||
CHECK((squelch(Number{2, -6}, limit) == Number{2, -6}));
|
||||
CHECK((squelch(Number{1, -6}, limit) == Number{1, -6}));
|
||||
CHECK((squelch(Number{9, -7}, limit) == Number{0}));
|
||||
CHECK((squelch(Number{-2, -6}, limit) == Number{-2, -6}));
|
||||
CHECK((squelch(Number{-1, -6}, limit) == Number{-1, -6}));
|
||||
CHECK((squelch(Number{-9, -7}, limit) == Number{0}));
|
||||
}
|
||||
|
||||
TEST_CASE("toString")
|
||||
{
|
||||
CHECK(to_string(Number(-2, 0)) == "-2");
|
||||
CHECK(to_string(Number(0, 0)) == "0");
|
||||
CHECK(to_string(Number(2, 0)) == "2");
|
||||
CHECK(to_string(Number(25, -3)) == "0.025");
|
||||
CHECK(to_string(Number(-25, -3)) == "-0.025");
|
||||
CHECK(to_string(Number(25, 1)) == "250");
|
||||
CHECK(to_string(Number(-25, 1)) == "-250");
|
||||
CHECK(to_string(Number(2, 20)) == "2000000000000000e5");
|
||||
CHECK(to_string(Number(-2, -20)) == "-2000000000000000e-35");
|
||||
}
|
||||
|
||||
TEST_CASE("relationals")
|
||||
{
|
||||
CHECK(!(Number{100} < Number{10}));
|
||||
CHECK(Number{100} > Number{10});
|
||||
CHECK(Number{100} >= Number{10});
|
||||
CHECK(!(Number{100} <= Number{10}));
|
||||
}
|
||||
|
||||
TEST_CASE("stream")
|
||||
{
|
||||
Number x{100};
|
||||
std::ostringstream os;
|
||||
os << x;
|
||||
CHECK(os.str() == to_string(x));
|
||||
}
|
||||
|
||||
TEST_CASE("inc_dec")
|
||||
{
|
||||
Number x{100};
|
||||
Number y = +x;
|
||||
CHECK(x == y);
|
||||
CHECK(x++ == y);
|
||||
CHECK(x == Number{101});
|
||||
CHECK(x-- == Number{101});
|
||||
CHECK(x == y);
|
||||
}
|
||||
|
||||
TEST_CASE("toSTAmount")
|
||||
{
|
||||
NumberSO stNumberSO{true};
|
||||
Issue const issue;
|
||||
Number const n{7'518'783'80596, -5};
|
||||
saveNumberRoundMode const save{Number::setround(Number::to_nearest)};
|
||||
auto res2 = STAmount{issue, n.mantissa(), n.exponent()};
|
||||
CHECK(res2 == STAmount{7518784});
|
||||
|
||||
Number::setround(Number::towards_zero);
|
||||
res2 = STAmount{issue, n.mantissa(), n.exponent()};
|
||||
CHECK(res2 == STAmount{7518783});
|
||||
|
||||
Number::setround(Number::downward);
|
||||
res2 = STAmount{issue, n.mantissa(), n.exponent()};
|
||||
CHECK(res2 == STAmount{7518783});
|
||||
|
||||
Number::setround(Number::upward);
|
||||
res2 = STAmount{issue, n.mantissa(), n.exponent()};
|
||||
CHECK(res2 == STAmount{7518784});
|
||||
}
|
||||
|
||||
TEST_CASE("truncate")
|
||||
{
|
||||
CHECK(Number(25, +1).truncate() == Number(250, 0));
|
||||
CHECK(Number(25, 0).truncate() == Number(25, 0));
|
||||
CHECK(Number(25, -1).truncate() == Number(2, 0));
|
||||
CHECK(Number(25, -2).truncate() == Number(0, 0));
|
||||
CHECK(Number(99, -2).truncate() == Number(0, 0));
|
||||
|
||||
CHECK(Number(-25, +1).truncate() == Number(-250, 0));
|
||||
CHECK(Number(-25, 0).truncate() == Number(-25, 0));
|
||||
CHECK(Number(-25, -1).truncate() == Number(-2, 0));
|
||||
CHECK(Number(-25, -2).truncate() == Number(0, 0));
|
||||
CHECK(Number(-99, -2).truncate() == Number(0, 0));
|
||||
|
||||
CHECK(Number(0, 0).truncate() == Number(0, 0));
|
||||
CHECK(Number(0, 30000).truncate() == Number(0, 0));
|
||||
CHECK(Number(0, -30000).truncate() == Number(0, 0));
|
||||
CHECK(Number(100, -30000).truncate() == Number(0, 0));
|
||||
CHECK(Number(100, -30000).truncate() == Number(0, 0));
|
||||
CHECK(Number(-100, -30000).truncate() == Number(0, 0));
|
||||
CHECK(Number(-100, -30000).truncate() == Number(0, 0));
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
@@ -1,284 +0,0 @@
|
||||
#include <xrpl/basics/Slice.h>
|
||||
#include <xrpl/basics/StringUtilities.h>
|
||||
#include <xrpl/basics/ToString.h>
|
||||
|
||||
#include <doctest/doctest.h>
|
||||
|
||||
using namespace xrpl;
|
||||
|
||||
namespace {
|
||||
void
|
||||
testUnHexSuccess(std::string const& strIn, std::string const& strExpected)
|
||||
{
|
||||
auto rv = strUnHex(strIn);
|
||||
CHECK(rv);
|
||||
CHECK(makeSlice(*rv) == makeSlice(strExpected));
|
||||
}
|
||||
|
||||
void
|
||||
testUnHexFailure(std::string const& strIn)
|
||||
{
|
||||
auto rv = strUnHex(strIn);
|
||||
CHECK(!rv);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST_SUITE_BEGIN("StringUtilities");
|
||||
|
||||
TEST_CASE("strUnHex")
|
||||
{
|
||||
testUnHexSuccess("526970706c6544", "RippleD");
|
||||
testUnHexSuccess("A", "\n");
|
||||
testUnHexSuccess("0A", "\n");
|
||||
testUnHexSuccess("D0A", "\r\n");
|
||||
testUnHexSuccess("0D0A", "\r\n");
|
||||
testUnHexSuccess("200D0A", " \r\n");
|
||||
testUnHexSuccess("282A2B2C2D2E2F29", "(*+,-./)");
|
||||
|
||||
// Check for things which contain some or only invalid characters
|
||||
testUnHexFailure("123X");
|
||||
testUnHexFailure("V");
|
||||
testUnHexFailure("XRP");
|
||||
}
|
||||
|
||||
TEST_CASE("parseUrl")
|
||||
{
|
||||
// Expected passes.
|
||||
{
|
||||
parsedURL pUrl;
|
||||
CHECK(parseUrl(pUrl, "scheme://"));
|
||||
CHECK(pUrl.scheme == "scheme");
|
||||
CHECK(pUrl.username.empty());
|
||||
CHECK(pUrl.password.empty());
|
||||
CHECK(pUrl.domain.empty());
|
||||
CHECK(!pUrl.port);
|
||||
CHECK(pUrl.path.empty());
|
||||
}
|
||||
|
||||
{
|
||||
parsedURL pUrl;
|
||||
CHECK(parseUrl(pUrl, "scheme:///"));
|
||||
CHECK(pUrl.scheme == "scheme");
|
||||
CHECK(pUrl.username.empty());
|
||||
CHECK(pUrl.password.empty());
|
||||
CHECK(pUrl.domain.empty());
|
||||
CHECK(!pUrl.port);
|
||||
CHECK(pUrl.path == "/");
|
||||
}
|
||||
|
||||
{
|
||||
parsedURL pUrl;
|
||||
CHECK(parseUrl(pUrl, "lower://domain"));
|
||||
CHECK(pUrl.scheme == "lower");
|
||||
CHECK(pUrl.username.empty());
|
||||
CHECK(pUrl.password.empty());
|
||||
CHECK(pUrl.domain == "domain");
|
||||
CHECK(!pUrl.port);
|
||||
CHECK(pUrl.path.empty());
|
||||
}
|
||||
|
||||
{
|
||||
parsedURL pUrl;
|
||||
CHECK(parseUrl(pUrl, "UPPER://domain:234/"));
|
||||
CHECK(pUrl.scheme == "upper");
|
||||
CHECK(pUrl.username.empty());
|
||||
CHECK(pUrl.password.empty());
|
||||
CHECK(pUrl.domain == "domain");
|
||||
CHECK(*pUrl.port == 234);
|
||||
CHECK(pUrl.path == "/");
|
||||
}
|
||||
|
||||
{
|
||||
parsedURL pUrl;
|
||||
CHECK(parseUrl(pUrl, "Mixed://domain/path"));
|
||||
CHECK(pUrl.scheme == "mixed");
|
||||
CHECK(pUrl.username.empty());
|
||||
CHECK(pUrl.password.empty());
|
||||
CHECK(pUrl.domain == "domain");
|
||||
CHECK(!pUrl.port);
|
||||
CHECK(pUrl.path == "/path");
|
||||
}
|
||||
|
||||
{
|
||||
parsedURL pUrl;
|
||||
CHECK(parseUrl(pUrl, "scheme://[::1]:123/path"));
|
||||
CHECK(pUrl.scheme == "scheme");
|
||||
CHECK(pUrl.username.empty());
|
||||
CHECK(pUrl.password.empty());
|
||||
CHECK(pUrl.domain == "::1");
|
||||
CHECK(*pUrl.port == 123);
|
||||
CHECK(pUrl.path == "/path");
|
||||
}
|
||||
|
||||
{
|
||||
parsedURL pUrl;
|
||||
CHECK(parseUrl(pUrl, "scheme://user:pass@domain:123/abc:321"));
|
||||
CHECK(pUrl.scheme == "scheme");
|
||||
CHECK(pUrl.username == "user");
|
||||
CHECK(pUrl.password == "pass");
|
||||
CHECK(pUrl.domain == "domain");
|
||||
CHECK(*pUrl.port == 123);
|
||||
CHECK(pUrl.path == "/abc:321");
|
||||
}
|
||||
|
||||
{
|
||||
parsedURL pUrl;
|
||||
CHECK(parseUrl(pUrl, "scheme://user@domain:123/abc:321"));
|
||||
CHECK(pUrl.scheme == "scheme");
|
||||
CHECK(pUrl.username == "user");
|
||||
CHECK(pUrl.password.empty());
|
||||
CHECK(pUrl.domain == "domain");
|
||||
CHECK(*pUrl.port == 123);
|
||||
CHECK(pUrl.path == "/abc:321");
|
||||
}
|
||||
|
||||
{
|
||||
parsedURL pUrl;
|
||||
CHECK(parseUrl(pUrl, "scheme://:pass@domain:123/abc:321"));
|
||||
CHECK(pUrl.scheme == "scheme");
|
||||
CHECK(pUrl.username.empty());
|
||||
CHECK(pUrl.password == "pass");
|
||||
CHECK(pUrl.domain == "domain");
|
||||
CHECK(*pUrl.port == 123);
|
||||
CHECK(pUrl.path == "/abc:321");
|
||||
}
|
||||
|
||||
{
|
||||
parsedURL pUrl;
|
||||
CHECK(parseUrl(pUrl, "scheme://domain:123/abc:321"));
|
||||
CHECK(pUrl.scheme == "scheme");
|
||||
CHECK(pUrl.username.empty());
|
||||
CHECK(pUrl.password.empty());
|
||||
CHECK(pUrl.domain == "domain");
|
||||
CHECK(*pUrl.port == 123);
|
||||
CHECK(pUrl.path == "/abc:321");
|
||||
}
|
||||
|
||||
{
|
||||
parsedURL pUrl;
|
||||
CHECK(parseUrl(pUrl, "scheme://user:pass@domain/abc:321"));
|
||||
CHECK(pUrl.scheme == "scheme");
|
||||
CHECK(pUrl.username == "user");
|
||||
CHECK(pUrl.password == "pass");
|
||||
CHECK(pUrl.domain == "domain");
|
||||
CHECK(!pUrl.port);
|
||||
CHECK(pUrl.path == "/abc:321");
|
||||
}
|
||||
|
||||
{
|
||||
parsedURL pUrl;
|
||||
CHECK(parseUrl(pUrl, "scheme://user@domain/abc:321"));
|
||||
CHECK(pUrl.scheme == "scheme");
|
||||
CHECK(pUrl.username == "user");
|
||||
CHECK(pUrl.password.empty());
|
||||
CHECK(pUrl.domain == "domain");
|
||||
CHECK(!pUrl.port);
|
||||
CHECK(pUrl.path == "/abc:321");
|
||||
}
|
||||
|
||||
{
|
||||
parsedURL pUrl;
|
||||
CHECK(parseUrl(pUrl, "scheme://:pass@domain/abc:321"));
|
||||
CHECK(pUrl.scheme == "scheme");
|
||||
CHECK(pUrl.username.empty());
|
||||
CHECK(pUrl.password == "pass");
|
||||
CHECK(pUrl.domain == "domain");
|
||||
CHECK(!pUrl.port);
|
||||
CHECK(pUrl.path == "/abc:321");
|
||||
}
|
||||
|
||||
{
|
||||
parsedURL pUrl;
|
||||
CHECK(parseUrl(pUrl, "scheme://domain/abc:321"));
|
||||
CHECK(pUrl.scheme == "scheme");
|
||||
CHECK(pUrl.username.empty());
|
||||
CHECK(pUrl.password.empty());
|
||||
CHECK(pUrl.domain == "domain");
|
||||
CHECK(!pUrl.port);
|
||||
CHECK(pUrl.path == "/abc:321");
|
||||
}
|
||||
|
||||
{
|
||||
parsedURL pUrl;
|
||||
CHECK(parseUrl(pUrl, "scheme:///path/to/file"));
|
||||
CHECK(pUrl.scheme == "scheme");
|
||||
CHECK(pUrl.username.empty());
|
||||
CHECK(pUrl.password.empty());
|
||||
CHECK(pUrl.domain.empty());
|
||||
CHECK(!pUrl.port);
|
||||
CHECK(pUrl.path == "/path/to/file");
|
||||
}
|
||||
|
||||
{
|
||||
parsedURL pUrl;
|
||||
CHECK(parseUrl(pUrl, "scheme://user:pass@domain/path/with/an@sign"));
|
||||
CHECK(pUrl.scheme == "scheme");
|
||||
CHECK(pUrl.username == "user");
|
||||
CHECK(pUrl.password == "pass");
|
||||
CHECK(pUrl.domain == "domain");
|
||||
CHECK(!pUrl.port);
|
||||
CHECK(pUrl.path == "/path/with/an@sign");
|
||||
}
|
||||
|
||||
{
|
||||
parsedURL pUrl;
|
||||
CHECK(parseUrl(pUrl, "scheme://domain/path/with/an@sign"));
|
||||
CHECK(pUrl.scheme == "scheme");
|
||||
CHECK(pUrl.username.empty());
|
||||
CHECK(pUrl.password.empty());
|
||||
CHECK(pUrl.domain == "domain");
|
||||
CHECK(!pUrl.port);
|
||||
CHECK(pUrl.path == "/path/with/an@sign");
|
||||
}
|
||||
|
||||
{
|
||||
parsedURL pUrl;
|
||||
CHECK(parseUrl(pUrl, "scheme://:999/"));
|
||||
CHECK(pUrl.scheme == "scheme");
|
||||
CHECK(pUrl.username.empty());
|
||||
CHECK(pUrl.password.empty());
|
||||
CHECK(pUrl.domain == ":999");
|
||||
CHECK(!pUrl.port);
|
||||
CHECK(pUrl.path == "/");
|
||||
}
|
||||
|
||||
{
|
||||
parsedURL pUrl;
|
||||
CHECK(parseUrl(pUrl, "http://::1:1234/validators"));
|
||||
CHECK(pUrl.scheme == "http");
|
||||
CHECK(pUrl.username.empty());
|
||||
CHECK(pUrl.password.empty());
|
||||
CHECK(pUrl.domain == "::0.1.18.52");
|
||||
CHECK(!pUrl.port);
|
||||
CHECK(pUrl.path == "/validators");
|
||||
}
|
||||
|
||||
// Expected fails.
|
||||
{
|
||||
parsedURL pUrl;
|
||||
CHECK(!parseUrl(pUrl, ""));
|
||||
CHECK(!parseUrl(pUrl, "nonsense"));
|
||||
CHECK(!parseUrl(pUrl, "://"));
|
||||
CHECK(!parseUrl(pUrl, ":///"));
|
||||
CHECK(!parseUrl(pUrl, "scheme://user:pass@domain:65536/abc:321"));
|
||||
CHECK(!parseUrl(pUrl, "UPPER://domain:23498765/"));
|
||||
CHECK(!parseUrl(pUrl, "UPPER://domain:0/"));
|
||||
CHECK(!parseUrl(pUrl, "UPPER://domain:+7/"));
|
||||
CHECK(!parseUrl(pUrl, "UPPER://domain:-7234/"));
|
||||
CHECK(!parseUrl(pUrl, "UPPER://domain:@#$56!/"));
|
||||
}
|
||||
|
||||
{
|
||||
std::string strUrl("s://" + std::string(8192, ':'));
|
||||
parsedURL pUrl;
|
||||
CHECK(!parseUrl(pUrl, strUrl));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("toString")
|
||||
{
|
||||
auto result = to_string("hello");
|
||||
CHECK(result == "hello");
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
@@ -1,119 +0,0 @@
|
||||
#include <xrpl/basics/TaggedCache.h>
|
||||
#include <xrpl/basics/TaggedCache.ipp>
|
||||
#include <xrpl/basics/chrono.h>
|
||||
#include <xrpl/protocol/Protocol.h>
|
||||
|
||||
#include <doctest/doctest.h>
|
||||
|
||||
using namespace xrpl;
|
||||
|
||||
TEST_SUITE_BEGIN("TaggedCache");
|
||||
|
||||
TEST_CASE("TaggedCache operations")
|
||||
{
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
TestStopwatch clock;
|
||||
clock.set(0);
|
||||
|
||||
using Key = LedgerIndex;
|
||||
using Value = std::string;
|
||||
using Cache = TaggedCache<Key, Value>;
|
||||
|
||||
beast::Journal j{beast::Journal::getNullSink()};
|
||||
|
||||
Cache c("test", 1, 1s, clock, j);
|
||||
|
||||
SUBCASE("Insert, retrieve, and age item")
|
||||
{
|
||||
CHECK(c.getCacheSize() == 0);
|
||||
CHECK(c.getTrackSize() == 0);
|
||||
CHECK(!c.insert(1, "one"));
|
||||
CHECK(c.getCacheSize() == 1);
|
||||
CHECK(c.getTrackSize() == 1);
|
||||
|
||||
{
|
||||
std::string s;
|
||||
CHECK(c.retrieve(1, s));
|
||||
CHECK(s == "one");
|
||||
}
|
||||
|
||||
++clock;
|
||||
c.sweep();
|
||||
CHECK(c.getCacheSize() == 0);
|
||||
CHECK(c.getTrackSize() == 0);
|
||||
}
|
||||
|
||||
SUBCASE("Insert item, maintain strong pointer, age it")
|
||||
{
|
||||
CHECK(!c.insert(2, "two"));
|
||||
CHECK(c.getCacheSize() == 1);
|
||||
CHECK(c.getTrackSize() == 1);
|
||||
|
||||
{
|
||||
auto p = c.fetch(2);
|
||||
CHECK(p != nullptr);
|
||||
++clock;
|
||||
c.sweep();
|
||||
CHECK(c.getCacheSize() == 0);
|
||||
CHECK(c.getTrackSize() == 1);
|
||||
}
|
||||
|
||||
// Make sure its gone now that our reference is gone
|
||||
++clock;
|
||||
c.sweep();
|
||||
CHECK(c.getCacheSize() == 0);
|
||||
CHECK(c.getTrackSize() == 0);
|
||||
}
|
||||
|
||||
SUBCASE("Insert same key/value pair and canonicalize")
|
||||
{
|
||||
CHECK(!c.insert(3, "three"));
|
||||
|
||||
{
|
||||
auto const p1 = c.fetch(3);
|
||||
auto p2 = std::make_shared<Value>("three");
|
||||
c.canonicalize_replace_client(3, p2);
|
||||
CHECK(p1.get() == p2.get());
|
||||
}
|
||||
++clock;
|
||||
c.sweep();
|
||||
CHECK(c.getCacheSize() == 0);
|
||||
CHECK(c.getTrackSize() == 0);
|
||||
}
|
||||
|
||||
SUBCASE("Put object, keep strong pointer, advance clock, canonicalize")
|
||||
{
|
||||
// Put an object in
|
||||
CHECK(!c.insert(4, "four"));
|
||||
CHECK(c.getCacheSize() == 1);
|
||||
CHECK(c.getTrackSize() == 1);
|
||||
|
||||
{
|
||||
// Keep a strong pointer to it
|
||||
auto const p1 = c.fetch(4);
|
||||
CHECK(p1 != nullptr);
|
||||
CHECK(c.getCacheSize() == 1);
|
||||
CHECK(c.getTrackSize() == 1);
|
||||
// Advance the clock a lot
|
||||
++clock;
|
||||
c.sweep();
|
||||
CHECK(c.getCacheSize() == 0);
|
||||
CHECK(c.getTrackSize() == 1);
|
||||
// Canonicalize a new object with the same key
|
||||
auto p2 = std::make_shared<std::string>("four");
|
||||
CHECK(c.canonicalize_replace_client(4, p2));
|
||||
CHECK(c.getCacheSize() == 1);
|
||||
CHECK(c.getTrackSize() == 1);
|
||||
// Make sure we get the original object
|
||||
CHECK(p1.get() == p2.get());
|
||||
}
|
||||
|
||||
++clock;
|
||||
c.sweep();
|
||||
CHECK(c.getCacheSize() == 0);
|
||||
CHECK(c.getTrackSize() == 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
@@ -1,332 +0,0 @@
|
||||
#include <xrpl/protocol/SystemParameters.h>
|
||||
#include <xrpl/protocol/Units.h>
|
||||
|
||||
#include <doctest/doctest.h>
|
||||
|
||||
using namespace xrpl;
|
||||
|
||||
TEST_SUITE_BEGIN("Units");
|
||||
|
||||
TEST_CASE("Initial XRP")
|
||||
{
|
||||
CHECK(INITIAL_XRP.drops() == 100'000'000'000'000'000);
|
||||
CHECK(INITIAL_XRP == XRPAmount{100'000'000'000'000'000});
|
||||
}
|
||||
|
||||
TEST_CASE("Types")
|
||||
{
|
||||
using FeeLevel32 = FeeLevel<std::uint32_t>;
|
||||
|
||||
SUBCASE("XRPAmount with uint32 FeeLevel")
|
||||
{
|
||||
XRPAmount x{100};
|
||||
CHECK(x.drops() == 100);
|
||||
CHECK((std::is_same_v<decltype(x)::unit_type, unit::dropTag>));
|
||||
auto y = 4u * x;
|
||||
CHECK(y.value() == 400);
|
||||
CHECK((std::is_same_v<decltype(y)::unit_type, unit::dropTag>));
|
||||
|
||||
auto z = 4 * y;
|
||||
CHECK(z.value() == 1600);
|
||||
CHECK((std::is_same_v<decltype(z)::unit_type, unit::dropTag>));
|
||||
|
||||
FeeLevel32 f{10};
|
||||
FeeLevel32 baseFee{100};
|
||||
|
||||
auto drops = mulDiv(baseFee, x, f);
|
||||
|
||||
CHECK(drops);
|
||||
CHECK(drops.value() == 1000);
|
||||
CHECK((std::is_same_v<
|
||||
std::remove_reference_t<decltype(*drops)>::unit_type,
|
||||
unit::dropTag>));
|
||||
|
||||
CHECK((std::is_same_v<
|
||||
std::remove_reference_t<decltype(*drops)>,
|
||||
XRPAmount>));
|
||||
}
|
||||
|
||||
SUBCASE("XRPAmount with uint64 FeeLevel")
|
||||
{
|
||||
XRPAmount x{100};
|
||||
CHECK(x.value() == 100);
|
||||
CHECK((std::is_same_v<decltype(x)::unit_type, unit::dropTag>));
|
||||
auto y = 4u * x;
|
||||
CHECK(y.value() == 400);
|
||||
CHECK((std::is_same_v<decltype(y)::unit_type, unit::dropTag>));
|
||||
|
||||
FeeLevel64 f{10};
|
||||
FeeLevel64 baseFee{100};
|
||||
|
||||
auto drops = mulDiv(baseFee, x, f);
|
||||
|
||||
CHECK(drops);
|
||||
CHECK(drops.value() == 1000);
|
||||
CHECK((std::is_same_v<
|
||||
std::remove_reference_t<decltype(*drops)>::unit_type,
|
||||
unit::dropTag>));
|
||||
CHECK((std::is_same_v<
|
||||
std::remove_reference_t<decltype(*drops)>,
|
||||
XRPAmount>));
|
||||
}
|
||||
|
||||
SUBCASE("FeeLevel64 operations")
|
||||
{
|
||||
FeeLevel64 x{1024};
|
||||
CHECK(x.value() == 1024);
|
||||
CHECK((std::is_same_v<decltype(x)::unit_type, unit::feelevelTag>));
|
||||
std::uint64_t m = 4;
|
||||
auto y = m * x;
|
||||
CHECK(y.value() == 4096);
|
||||
CHECK((std::is_same_v<decltype(y)::unit_type, unit::feelevelTag>));
|
||||
|
||||
XRPAmount basefee{10};
|
||||
FeeLevel64 referencefee{256};
|
||||
|
||||
auto drops = mulDiv(x, basefee, referencefee);
|
||||
|
||||
CHECK(drops);
|
||||
CHECK(drops.value() == 40);
|
||||
CHECK((std::is_same_v<
|
||||
std::remove_reference_t<decltype(*drops)>::unit_type,
|
||||
unit::dropTag>));
|
||||
CHECK((std::is_same_v<
|
||||
std::remove_reference_t<decltype(*drops)>,
|
||||
XRPAmount>));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Json")
|
||||
{
|
||||
using FeeLevel32 = FeeLevel<std::uint32_t>;
|
||||
|
||||
SUBCASE("FeeLevel32 max")
|
||||
{
|
||||
FeeLevel32 x{std::numeric_limits<std::uint32_t>::max()};
|
||||
auto y = x.jsonClipped();
|
||||
CHECK(y.type() == Json::uintValue);
|
||||
CHECK(y == Json::Value{x.fee()});
|
||||
}
|
||||
|
||||
SUBCASE("FeeLevel32 min")
|
||||
{
|
||||
FeeLevel32 x{std::numeric_limits<std::uint32_t>::min()};
|
||||
auto y = x.jsonClipped();
|
||||
CHECK(y.type() == Json::uintValue);
|
||||
CHECK(y == Json::Value{x.fee()});
|
||||
}
|
||||
|
||||
SUBCASE("FeeLevel64 max")
|
||||
{
|
||||
FeeLevel64 x{std::numeric_limits<std::uint64_t>::max()};
|
||||
auto y = x.jsonClipped();
|
||||
CHECK(y.type() == Json::uintValue);
|
||||
CHECK(y == Json::Value{std::numeric_limits<std::uint32_t>::max()});
|
||||
}
|
||||
|
||||
SUBCASE("FeeLevel64 min")
|
||||
{
|
||||
FeeLevel64 x{std::numeric_limits<std::uint64_t>::min()};
|
||||
auto y = x.jsonClipped();
|
||||
CHECK(y.type() == Json::uintValue);
|
||||
CHECK(y == Json::Value{0});
|
||||
}
|
||||
|
||||
SUBCASE("FeeLevelDouble max")
|
||||
{
|
||||
FeeLevelDouble x{std::numeric_limits<double>::max()};
|
||||
auto y = x.jsonClipped();
|
||||
CHECK(y.type() == Json::realValue);
|
||||
CHECK(y == Json::Value{std::numeric_limits<double>::max()});
|
||||
}
|
||||
|
||||
SUBCASE("FeeLevelDouble min")
|
||||
{
|
||||
FeeLevelDouble x{std::numeric_limits<double>::min()};
|
||||
auto y = x.jsonClipped();
|
||||
CHECK(y.type() == Json::realValue);
|
||||
CHECK(y == Json::Value{std::numeric_limits<double>::min()});
|
||||
}
|
||||
|
||||
SUBCASE("XRPAmount max")
|
||||
{
|
||||
XRPAmount x{std::numeric_limits<std::int64_t>::max()};
|
||||
auto y = x.jsonClipped();
|
||||
CHECK(y.type() == Json::intValue);
|
||||
CHECK(y == Json::Value{std::numeric_limits<std::int32_t>::max()});
|
||||
}
|
||||
|
||||
SUBCASE("XRPAmount min")
|
||||
{
|
||||
XRPAmount x{std::numeric_limits<std::int64_t>::min()};
|
||||
auto y = x.jsonClipped();
|
||||
CHECK(y.type() == Json::intValue);
|
||||
CHECK(y == Json::Value{std::numeric_limits<std::int32_t>::min()});
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Functions")
|
||||
{
|
||||
using FeeLevel32 = FeeLevel<std::uint32_t>;
|
||||
|
||||
SUBCASE("FeeLevel64 functions")
|
||||
{
|
||||
auto make = [&](auto x) -> FeeLevel64 { return x; };
|
||||
auto explicitmake = [&](auto x) -> FeeLevel64 { return FeeLevel64{x}; };
|
||||
|
||||
[[maybe_unused]] FeeLevel64 defaulted;
|
||||
FeeLevel64 test{0};
|
||||
CHECK(test.fee() == 0);
|
||||
|
||||
test = explicitmake(beast::zero);
|
||||
CHECK(test.fee() == 0);
|
||||
|
||||
test = beast::zero;
|
||||
CHECK(test.fee() == 0);
|
||||
|
||||
test = explicitmake(100u);
|
||||
CHECK(test.fee() == 100);
|
||||
|
||||
FeeLevel64 const targetSame{200u};
|
||||
FeeLevel32 const targetOther{300u};
|
||||
test = make(targetSame);
|
||||
CHECK(test.fee() == 200);
|
||||
CHECK(test == targetSame);
|
||||
CHECK(test < FeeLevel64{1000});
|
||||
CHECK(test > FeeLevel64{100});
|
||||
test = make(targetOther);
|
||||
CHECK(test.fee() == 300);
|
||||
CHECK(test == targetOther);
|
||||
|
||||
test = std::uint64_t(200);
|
||||
CHECK(test.fee() == 200);
|
||||
test = std::uint32_t(300);
|
||||
CHECK(test.fee() == 300);
|
||||
|
||||
test = targetSame;
|
||||
CHECK(test.fee() == 200);
|
||||
test = targetOther.fee();
|
||||
CHECK(test.fee() == 300);
|
||||
CHECK(test == targetOther);
|
||||
|
||||
test = targetSame * 2;
|
||||
CHECK(test.fee() == 400);
|
||||
test = 3 * targetSame;
|
||||
CHECK(test.fee() == 600);
|
||||
test = targetSame / 10;
|
||||
CHECK(test.fee() == 20);
|
||||
|
||||
test += targetSame;
|
||||
CHECK(test.fee() == 220);
|
||||
|
||||
test -= targetSame;
|
||||
CHECK(test.fee() == 20);
|
||||
|
||||
test++;
|
||||
CHECK(test.fee() == 21);
|
||||
++test;
|
||||
CHECK(test.fee() == 22);
|
||||
test--;
|
||||
CHECK(test.fee() == 21);
|
||||
--test;
|
||||
CHECK(test.fee() == 20);
|
||||
|
||||
test *= 5;
|
||||
CHECK(test.fee() == 100);
|
||||
test /= 2;
|
||||
CHECK(test.fee() == 50);
|
||||
test %= 13;
|
||||
CHECK(test.fee() == 11);
|
||||
|
||||
CHECK(test);
|
||||
test = 0;
|
||||
CHECK(!test);
|
||||
CHECK(test.signum() == 0);
|
||||
test = targetSame;
|
||||
CHECK(test.signum() == 1);
|
||||
CHECK(to_string(test) == "200");
|
||||
}
|
||||
|
||||
SUBCASE("FeeLevelDouble functions")
|
||||
{
|
||||
auto make = [&](auto x) -> FeeLevelDouble { return x; };
|
||||
auto explicitmake = [&](auto x) -> FeeLevelDouble {
|
||||
return FeeLevelDouble{x};
|
||||
};
|
||||
|
||||
[[maybe_unused]] FeeLevelDouble defaulted;
|
||||
FeeLevelDouble test{0};
|
||||
CHECK(test.fee() == 0);
|
||||
|
||||
test = explicitmake(beast::zero);
|
||||
CHECK(test.fee() == 0);
|
||||
|
||||
test = beast::zero;
|
||||
CHECK(test.fee() == 0);
|
||||
|
||||
test = explicitmake(100.0);
|
||||
CHECK(test.fee() == 100);
|
||||
|
||||
FeeLevelDouble const targetSame{200.0};
|
||||
FeeLevel64 const targetOther{300};
|
||||
test = make(targetSame);
|
||||
CHECK(test.fee() == 200);
|
||||
CHECK(test == targetSame);
|
||||
CHECK(test < FeeLevelDouble{1000.0});
|
||||
CHECK(test > FeeLevelDouble{100.0});
|
||||
test = targetOther.fee();
|
||||
CHECK(test.fee() == 300);
|
||||
CHECK(test == targetOther);
|
||||
|
||||
test = 200.0;
|
||||
CHECK(test.fee() == 200);
|
||||
test = std::uint64_t(300);
|
||||
CHECK(test.fee() == 300);
|
||||
|
||||
test = targetSame;
|
||||
CHECK(test.fee() == 200);
|
||||
|
||||
test = targetSame * 2;
|
||||
CHECK(test.fee() == 400);
|
||||
test = 3 * targetSame;
|
||||
CHECK(test.fee() == 600);
|
||||
test = targetSame / 10;
|
||||
CHECK(test.fee() == 20);
|
||||
|
||||
test += targetSame;
|
||||
CHECK(test.fee() == 220);
|
||||
|
||||
test -= targetSame;
|
||||
CHECK(test.fee() == 20);
|
||||
|
||||
test++;
|
||||
CHECK(test.fee() == 21);
|
||||
++test;
|
||||
CHECK(test.fee() == 22);
|
||||
test--;
|
||||
CHECK(test.fee() == 21);
|
||||
--test;
|
||||
CHECK(test.fee() == 20);
|
||||
|
||||
test *= 5;
|
||||
CHECK(test.fee() == 100);
|
||||
test /= 2;
|
||||
CHECK(test.fee() == 50);
|
||||
|
||||
// legal with signed
|
||||
test = -test;
|
||||
CHECK(test.fee() == -50);
|
||||
CHECK(test.signum() == -1);
|
||||
CHECK(to_string(test) == "-50.000000");
|
||||
|
||||
CHECK(test);
|
||||
test = 0;
|
||||
CHECK(!test);
|
||||
CHECK(test.signum() == 0);
|
||||
test = targetSame;
|
||||
CHECK(test.signum() == 1);
|
||||
CHECK(to_string(test) == "200.000000");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
@@ -1,283 +0,0 @@
|
||||
#include <xrpl/protocol/XRPAmount.h>
|
||||
|
||||
#include <doctest/doctest.h>
|
||||
|
||||
using namespace xrpl;
|
||||
|
||||
TEST_SUITE_BEGIN("XRPAmount");
|
||||
|
||||
TEST_CASE("signum")
|
||||
{
|
||||
for (auto i : {-1, 0, 1})
|
||||
{
|
||||
XRPAmount const x(i);
|
||||
|
||||
if (i < 0)
|
||||
CHECK(x.signum() < 0);
|
||||
else if (i > 0)
|
||||
CHECK(x.signum() > 0);
|
||||
else
|
||||
CHECK(x.signum() == 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("beast::Zero Comparisons")
|
||||
{
|
||||
using beast::zero;
|
||||
|
||||
for (auto i : {-1, 0, 1})
|
||||
{
|
||||
XRPAmount const x(i);
|
||||
|
||||
CHECK((i == 0) == (x == zero));
|
||||
CHECK((i != 0) == (x != zero));
|
||||
CHECK((i < 0) == (x < zero));
|
||||
CHECK((i > 0) == (x > zero));
|
||||
CHECK((i <= 0) == (x <= zero));
|
||||
CHECK((i >= 0) == (x >= zero));
|
||||
|
||||
CHECK((0 == i) == (zero == x));
|
||||
CHECK((0 != i) == (zero != x));
|
||||
CHECK((0 < i) == (zero < x));
|
||||
CHECK((0 > i) == (zero > x));
|
||||
CHECK((0 <= i) == (zero <= x));
|
||||
CHECK((0 >= i) == (zero >= x));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("XRP Comparisons")
|
||||
{
|
||||
for (auto i : {-1, 0, 1})
|
||||
{
|
||||
XRPAmount const x(i);
|
||||
|
||||
for (auto j : {-1, 0, 1})
|
||||
{
|
||||
XRPAmount const y(j);
|
||||
|
||||
CHECK((i == j) == (x == y));
|
||||
CHECK((i != j) == (x != y));
|
||||
CHECK((i < j) == (x < y));
|
||||
CHECK((i > j) == (x > y));
|
||||
CHECK((i <= j) == (x <= y));
|
||||
CHECK((i >= j) == (x >= y));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Addition & Subtraction")
|
||||
{
|
||||
for (auto i : {-1, 0, 1})
|
||||
{
|
||||
XRPAmount const x(i);
|
||||
|
||||
for (auto j : {-1, 0, 1})
|
||||
{
|
||||
XRPAmount const y(j);
|
||||
|
||||
CHECK(XRPAmount(i + j) == (x + y));
|
||||
CHECK(XRPAmount(i - j) == (x - y));
|
||||
|
||||
CHECK((x + y) == (y + x)); // addition is commutative
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("decimalXRP")
|
||||
{
|
||||
// Tautology
|
||||
CHECK(DROPS_PER_XRP.decimalXRP() == 1);
|
||||
|
||||
XRPAmount test{1};
|
||||
CHECK(test.decimalXRP() == 0.000001);
|
||||
|
||||
test = -test;
|
||||
CHECK(test.decimalXRP() == -0.000001);
|
||||
|
||||
test = 100'000'000;
|
||||
CHECK(test.decimalXRP() == 100);
|
||||
|
||||
test = -test;
|
||||
CHECK(test.decimalXRP() == -100);
|
||||
}
|
||||
|
||||
TEST_CASE("functions")
|
||||
{
|
||||
// Explicitly test every defined function for the XRPAmount class
|
||||
// since some of them are templated, but not used anywhere else.
|
||||
auto make = [&](auto x) -> XRPAmount { return XRPAmount{x}; };
|
||||
|
||||
XRPAmount defaulted;
|
||||
(void)defaulted;
|
||||
XRPAmount test{0};
|
||||
CHECK(test.drops() == 0);
|
||||
|
||||
test = make(beast::zero);
|
||||
CHECK(test.drops() == 0);
|
||||
|
||||
test = beast::zero;
|
||||
CHECK(test.drops() == 0);
|
||||
|
||||
test = make(100);
|
||||
CHECK(test.drops() == 100);
|
||||
|
||||
test = make(100u);
|
||||
CHECK(test.drops() == 100);
|
||||
|
||||
XRPAmount const targetSame{200u};
|
||||
test = make(targetSame);
|
||||
CHECK(test.drops() == 200);
|
||||
CHECK(test == targetSame);
|
||||
CHECK(test < XRPAmount{1000});
|
||||
CHECK(test > XRPAmount{100});
|
||||
|
||||
test = std::int64_t(200);
|
||||
CHECK(test.drops() == 200);
|
||||
test = std::uint32_t(300);
|
||||
CHECK(test.drops() == 300);
|
||||
|
||||
test = targetSame;
|
||||
CHECK(test.drops() == 200);
|
||||
auto testOther = test.dropsAs<std::uint32_t>();
|
||||
CHECK(testOther);
|
||||
CHECK(*testOther == 200);
|
||||
test = std::numeric_limits<std::uint64_t>::max();
|
||||
testOther = test.dropsAs<std::uint32_t>();
|
||||
CHECK(!testOther);
|
||||
test = -1;
|
||||
testOther = test.dropsAs<std::uint32_t>();
|
||||
CHECK(!testOther);
|
||||
|
||||
test = targetSame * 2;
|
||||
CHECK(test.drops() == 400);
|
||||
test = 3 * targetSame;
|
||||
CHECK(test.drops() == 600);
|
||||
test = 20;
|
||||
CHECK(test.drops() == 20);
|
||||
|
||||
test += targetSame;
|
||||
CHECK(test.drops() == 220);
|
||||
|
||||
test -= targetSame;
|
||||
CHECK(test.drops() == 20);
|
||||
|
||||
test *= 5;
|
||||
CHECK(test.drops() == 100);
|
||||
test = 50;
|
||||
CHECK(test.drops() == 50);
|
||||
test -= 39;
|
||||
CHECK(test.drops() == 11);
|
||||
|
||||
// legal with signed
|
||||
test = -test;
|
||||
CHECK(test.drops() == -11);
|
||||
CHECK(test.signum() == -1);
|
||||
CHECK(to_string(test) == "-11");
|
||||
|
||||
CHECK(test);
|
||||
test = 0;
|
||||
CHECK(!test);
|
||||
CHECK(test.signum() == 0);
|
||||
test = targetSame;
|
||||
CHECK(test.signum() == 1);
|
||||
CHECK(to_string(test) == "200");
|
||||
}
|
||||
|
||||
TEST_CASE("mulRatio")
|
||||
{
|
||||
constexpr auto maxUInt32 = std::numeric_limits<std::uint32_t>::max();
|
||||
constexpr auto maxXRP = std::numeric_limits<XRPAmount::value_type>::max();
|
||||
constexpr auto minXRP = std::numeric_limits<XRPAmount::value_type>::min();
|
||||
|
||||
{
|
||||
// multiply by a number that would overflow then divide by the same
|
||||
// number, and check we didn't lose any value
|
||||
XRPAmount big(maxXRP);
|
||||
CHECK(big == mulRatio(big, maxUInt32, maxUInt32, true));
|
||||
// rounding mode shouldn't matter as the result is exact
|
||||
CHECK(big == mulRatio(big, maxUInt32, maxUInt32, false));
|
||||
|
||||
// multiply and divide by values that would overflow if done
|
||||
// naively, and check that it gives the correct answer
|
||||
big -= 0xf; // Subtract a little so it's divisable by 4
|
||||
CHECK(mulRatio(big, 3, 4, false).value() == (big.value() / 4) * 3);
|
||||
CHECK(mulRatio(big, 3, 4, true).value() == (big.value() / 4) * 3);
|
||||
CHECK((big.value() * 3) / 4 != (big.value() / 4) * 3);
|
||||
}
|
||||
|
||||
{
|
||||
// Similar test as above, but for negative values
|
||||
XRPAmount big(minXRP);
|
||||
CHECK(big == mulRatio(big, maxUInt32, maxUInt32, true));
|
||||
// rounding mode shouldn't matter as the result is exact
|
||||
CHECK(big == mulRatio(big, maxUInt32, maxUInt32, false));
|
||||
|
||||
// multiply and divide by values that would overflow if done
|
||||
// naively, and check that it gives the correct answer
|
||||
CHECK(mulRatio(big, 3, 4, false).value() == (big.value() / 4) * 3);
|
||||
CHECK(mulRatio(big, 3, 4, true).value() == (big.value() / 4) * 3);
|
||||
CHECK((big.value() * 3) / 4 != (big.value() / 4) * 3);
|
||||
}
|
||||
|
||||
{
|
||||
// small amounts
|
||||
XRPAmount tiny(1);
|
||||
// Round up should give the smallest allowable number
|
||||
CHECK(tiny == mulRatio(tiny, 1, maxUInt32, true));
|
||||
// rounding down should be zero
|
||||
CHECK(beast::zero == mulRatio(tiny, 1, maxUInt32, false));
|
||||
CHECK(beast::zero == mulRatio(tiny, maxUInt32 - 1, maxUInt32, false));
|
||||
|
||||
// tiny negative numbers
|
||||
XRPAmount tinyNeg(-1);
|
||||
// Round up should give zero
|
||||
CHECK(beast::zero == mulRatio(tinyNeg, 1, maxUInt32, true));
|
||||
CHECK(beast::zero == mulRatio(tinyNeg, maxUInt32 - 1, maxUInt32, true));
|
||||
// rounding down should be tiny
|
||||
CHECK(tinyNeg == mulRatio(tinyNeg, maxUInt32 - 1, maxUInt32, false));
|
||||
}
|
||||
|
||||
{ // rounding
|
||||
{
|
||||
XRPAmount one(1);
|
||||
auto const rup = mulRatio(one, maxUInt32 - 1, maxUInt32, true);
|
||||
auto const rdown = mulRatio(one, maxUInt32 - 1, maxUInt32, false);
|
||||
CHECK(rup.drops() - rdown.drops() == 1);
|
||||
}
|
||||
|
||||
{
|
||||
XRPAmount big(maxXRP);
|
||||
auto const rup = mulRatio(big, maxUInt32 - 1, maxUInt32, true);
|
||||
auto const rdown = mulRatio(big, maxUInt32 - 1, maxUInt32, false);
|
||||
CHECK(rup.drops() - rdown.drops() == 1);
|
||||
}
|
||||
|
||||
{
|
||||
XRPAmount negOne(-1);
|
||||
auto const rup = mulRatio(negOne, maxUInt32 - 1, maxUInt32, true);
|
||||
auto const rdown =
|
||||
mulRatio(negOne, maxUInt32 - 1, maxUInt32, false);
|
||||
CHECK(rup.drops() - rdown.drops() == 1);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// division by zero
|
||||
XRPAmount one(1);
|
||||
CHECK_THROWS([&] { mulRatio(one, 1, 0, true); }());
|
||||
}
|
||||
|
||||
{
|
||||
// overflow
|
||||
XRPAmount big(maxXRP);
|
||||
CHECK_THROWS([&] { mulRatio(big, 2, 1, true); }());
|
||||
}
|
||||
|
||||
{
|
||||
// underflow
|
||||
XRPAmount bigNegative(minXRP + 10);
|
||||
CHECK(mulRatio(bigNegative, 2, 1, true) == minXRP);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
@@ -1,432 +0,0 @@
|
||||
// base58 doctest - converted from src/test/basics/base58_test.cpp
|
||||
|
||||
#ifndef _MSC_VER
|
||||
|
||||
#include <xrpl/protocol/detail/b58_utils.h>
|
||||
#include <xrpl/protocol/tokens.h>
|
||||
|
||||
#include <boost/multiprecision/cpp_int.hpp>
|
||||
#include <boost/random.hpp>
|
||||
|
||||
#include <doctest/doctest.h>
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <random>
|
||||
#include <span>
|
||||
#include <sstream>
|
||||
|
||||
namespace xrpl {
|
||||
namespace test {
|
||||
namespace {
|
||||
|
||||
[[nodiscard]] inline auto
|
||||
randEngine() -> std::mt19937&
|
||||
{
|
||||
static std::mt19937 r = [] {
|
||||
std::random_device rd;
|
||||
return std::mt19937{rd()};
|
||||
}();
|
||||
return r;
|
||||
}
|
||||
|
||||
constexpr int numTokenTypeIndexes = 9;
|
||||
|
||||
[[nodiscard]] inline auto
|
||||
tokenTypeAndSize(int i) -> std::tuple<xrpl::TokenType, std::size_t>
|
||||
{
|
||||
assert(i < numTokenTypeIndexes);
|
||||
|
||||
switch (i)
|
||||
{
|
||||
using enum xrpl::TokenType;
|
||||
case 0:
|
||||
return {None, 20};
|
||||
case 1:
|
||||
return {NodePublic, 32};
|
||||
case 2:
|
||||
return {NodePublic, 33};
|
||||
case 3:
|
||||
return {NodePrivate, 32};
|
||||
case 4:
|
||||
return {AccountID, 20};
|
||||
case 5:
|
||||
return {AccountPublic, 32};
|
||||
case 6:
|
||||
return {AccountPublic, 33};
|
||||
case 7:
|
||||
return {AccountSecret, 32};
|
||||
case 8:
|
||||
return {FamilySeed, 16};
|
||||
default:
|
||||
throw std::invalid_argument(
|
||||
"Invalid token selection passed to tokenTypeAndSize() "
|
||||
"in " __FILE__);
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] inline auto
|
||||
randomTokenTypeAndSize() -> std::tuple<xrpl::TokenType, std::size_t>
|
||||
{
|
||||
using namespace xrpl;
|
||||
auto& rng = randEngine();
|
||||
std::uniform_int_distribution<> d(0, 8);
|
||||
return tokenTypeAndSize(d(rng));
|
||||
}
|
||||
|
||||
// Return the token type and subspan of `d` to use as test data.
|
||||
[[nodiscard]] inline auto
|
||||
randomB256TestData(std::span<std::uint8_t> d)
|
||||
-> std::tuple<xrpl::TokenType, std::span<std::uint8_t>>
|
||||
{
|
||||
auto& rng = randEngine();
|
||||
std::uniform_int_distribution<std::uint8_t> dist(0, 255);
|
||||
auto [tokType, tokSize] = randomTokenTypeAndSize();
|
||||
std::generate(d.begin(), d.begin() + tokSize, [&] { return dist(rng); });
|
||||
return {tokType, d.subspan(0, tokSize)};
|
||||
}
|
||||
|
||||
inline void
|
||||
printAsChar(std::span<std::uint8_t> a, std::span<std::uint8_t> b)
|
||||
{
|
||||
auto asString = [](std::span<std::uint8_t> s) {
|
||||
std::string r;
|
||||
r.resize(s.size());
|
||||
std::copy(s.begin(), s.end(), r.begin());
|
||||
return r;
|
||||
};
|
||||
auto sa = asString(a);
|
||||
auto sb = asString(b);
|
||||
std::cerr << "\n\n" << sa << "\n" << sb << "\n";
|
||||
}
|
||||
|
||||
inline void
|
||||
printAsInt(std::span<std::uint8_t> a, std::span<std::uint8_t> b)
|
||||
{
|
||||
auto asString = [](std::span<std::uint8_t> s) -> std::string {
|
||||
std::stringstream sstr;
|
||||
for (auto i : s)
|
||||
{
|
||||
sstr << std::setw(3) << int(i) << ',';
|
||||
}
|
||||
return sstr.str();
|
||||
};
|
||||
auto sa = asString(a);
|
||||
auto sb = asString(b);
|
||||
std::cerr << "\n\n" << sa << "\n" << sb << "\n";
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace multiprecision_utils {
|
||||
|
||||
boost::multiprecision::checked_uint512_t
|
||||
toBoostMP(std::span<std::uint64_t> in)
|
||||
{
|
||||
boost::multiprecision::checked_uint512_t mbp = 0;
|
||||
for (auto i = in.rbegin(); i != in.rend(); ++i)
|
||||
{
|
||||
mbp <<= 64;
|
||||
mbp += *i;
|
||||
}
|
||||
return mbp;
|
||||
}
|
||||
|
||||
std::vector<std::uint64_t>
|
||||
randomBigInt(std::uint8_t minSize = 1, std::uint8_t maxSize = 5)
|
||||
{
|
||||
auto eng = randEngine();
|
||||
std::uniform_int_distribution<std::uint8_t> numCoeffDist(minSize, maxSize);
|
||||
std::uniform_int_distribution<std::uint64_t> dist;
|
||||
auto const numCoeff = numCoeffDist(eng);
|
||||
std::vector<std::uint64_t> coeffs;
|
||||
coeffs.reserve(numCoeff);
|
||||
for (int i = 0; i < numCoeff; ++i)
|
||||
{
|
||||
coeffs.push_back(dist(eng));
|
||||
}
|
||||
return coeffs;
|
||||
}
|
||||
} // namespace multiprecision_utils
|
||||
|
||||
} // namespace test
|
||||
} // namespace xrpl
|
||||
|
||||
TEST_SUITE_BEGIN("base58");
|
||||
|
||||
TEST_CASE("b58_multiprecision")
|
||||
{
|
||||
using namespace boost::multiprecision;
|
||||
using namespace xrpl::test;
|
||||
using namespace xrpl;
|
||||
|
||||
constexpr std::size_t iters = 100000;
|
||||
auto eng = randEngine();
|
||||
std::uniform_int_distribution<std::uint64_t> dist;
|
||||
std::uniform_int_distribution<std::uint64_t> dist1(1);
|
||||
|
||||
for (int i = 0; i < iters; ++i)
|
||||
{
|
||||
std::uint64_t const d = dist(eng);
|
||||
if (!d)
|
||||
continue;
|
||||
auto bigInt = multiprecision_utils::randomBigInt();
|
||||
auto const boostBigInt = multiprecision_utils::toBoostMP(
|
||||
std::span<std::uint64_t>(bigInt.data(), bigInt.size()));
|
||||
|
||||
auto const refDiv = boostBigInt / d;
|
||||
auto const refMod = boostBigInt % d;
|
||||
|
||||
auto const mod = b58_fast::detail::inplace_bigint_div_rem(
|
||||
std::span<uint64_t>(bigInt.data(), bigInt.size()), d);
|
||||
auto const foundDiv = multiprecision_utils::toBoostMP(bigInt);
|
||||
CHECK(refMod.convert_to<std::uint64_t>() == mod);
|
||||
CHECK(foundDiv == refDiv);
|
||||
}
|
||||
for (int i = 0; i < iters; ++i)
|
||||
{
|
||||
std::uint64_t const d = dist(eng);
|
||||
auto bigInt = multiprecision_utils::randomBigInt(/*minSize*/ 2);
|
||||
if (bigInt[bigInt.size() - 1] ==
|
||||
std::numeric_limits<std::uint64_t>::max())
|
||||
{
|
||||
bigInt[bigInt.size() - 1] -= 1; // Prevent overflow
|
||||
}
|
||||
auto const boostBigInt = multiprecision_utils::toBoostMP(
|
||||
std::span<std::uint64_t>(bigInt.data(), bigInt.size()));
|
||||
|
||||
auto const refAdd = boostBigInt + d;
|
||||
|
||||
auto const result = b58_fast::detail::inplace_bigint_add(
|
||||
std::span<uint64_t>(bigInt.data(), bigInt.size()), d);
|
||||
CHECK(result == TokenCodecErrc::success);
|
||||
auto const foundAdd = multiprecision_utils::toBoostMP(bigInt);
|
||||
CHECK(refAdd == foundAdd);
|
||||
}
|
||||
for (int i = 0; i < iters; ++i)
|
||||
{
|
||||
std::uint64_t const d = dist1(eng);
|
||||
// Force overflow
|
||||
std::vector<std::uint64_t> bigInt(
|
||||
5, std::numeric_limits<std::uint64_t>::max());
|
||||
|
||||
auto const boostBigInt = multiprecision_utils::toBoostMP(
|
||||
std::span<std::uint64_t>(bigInt.data(), bigInt.size()));
|
||||
|
||||
auto const refAdd = boostBigInt + d;
|
||||
|
||||
auto const result = b58_fast::detail::inplace_bigint_add(
|
||||
std::span<uint64_t>(bigInt.data(), bigInt.size()), d);
|
||||
CHECK(result == TokenCodecErrc::overflowAdd);
|
||||
auto const foundAdd = multiprecision_utils::toBoostMP(bigInt);
|
||||
CHECK(refAdd != foundAdd);
|
||||
}
|
||||
for (int i = 0; i < iters; ++i)
|
||||
{
|
||||
std::uint64_t const d = dist(eng);
|
||||
auto bigInt = multiprecision_utils::randomBigInt(/* minSize */ 2);
|
||||
// inplace mul requires the most significant coeff to be zero to
|
||||
// hold the result.
|
||||
bigInt[bigInt.size() - 1] = 0;
|
||||
auto const boostBigInt = multiprecision_utils::toBoostMP(
|
||||
std::span<std::uint64_t>(bigInt.data(), bigInt.size()));
|
||||
|
||||
auto const refMul = boostBigInt * d;
|
||||
|
||||
auto const result = b58_fast::detail::inplace_bigint_mul(
|
||||
std::span<uint64_t>(bigInt.data(), bigInt.size()), d);
|
||||
CHECK(result == TokenCodecErrc::success);
|
||||
auto const foundMul = multiprecision_utils::toBoostMP(bigInt);
|
||||
CHECK(refMul == foundMul);
|
||||
}
|
||||
for (int i = 0; i < iters; ++i)
|
||||
{
|
||||
std::uint64_t const d = dist1(eng);
|
||||
// Force overflow
|
||||
std::vector<std::uint64_t> bigInt(
|
||||
5, std::numeric_limits<std::uint64_t>::max());
|
||||
auto const boostBigInt = multiprecision_utils::toBoostMP(
|
||||
std::span<std::uint64_t>(bigInt.data(), bigInt.size()));
|
||||
|
||||
auto const refMul = boostBigInt * d;
|
||||
|
||||
auto const result = b58_fast::detail::inplace_bigint_mul(
|
||||
std::span<uint64_t>(bigInt.data(), bigInt.size()), d);
|
||||
CHECK(result == TokenCodecErrc::inputTooLarge);
|
||||
auto const foundMul = multiprecision_utils::toBoostMP(bigInt);
|
||||
CHECK(refMul != foundMul);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("fast_matches_ref")
|
||||
{
|
||||
using namespace xrpl::test;
|
||||
using namespace xrpl;
|
||||
|
||||
auto testRawEncode = [&](std::span<std::uint8_t> const& b256Data) {
|
||||
std::array<std::uint8_t, 64> b58ResultBuf[2];
|
||||
std::array<std::span<std::uint8_t>, 2> b58Result;
|
||||
|
||||
std::array<std::uint8_t, 64> b256ResultBuf[2];
|
||||
std::array<std::span<std::uint8_t>, 2> b256Result;
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
std::span const outBuf{b58ResultBuf[i]};
|
||||
if (i == 0)
|
||||
{
|
||||
auto const r =
|
||||
xrpl::b58_fast::detail::b256_to_b58_be(b256Data, outBuf);
|
||||
REQUIRE(r);
|
||||
b58Result[i] = r.value();
|
||||
}
|
||||
else
|
||||
{
|
||||
std::array<std::uint8_t, 128> tmpBuf;
|
||||
std::string const s = xrpl::b58_ref::detail::encodeBase58(
|
||||
b256Data.data(),
|
||||
b256Data.size(),
|
||||
tmpBuf.data(),
|
||||
tmpBuf.size());
|
||||
REQUIRE(s.size());
|
||||
b58Result[i] = outBuf.subspan(0, s.size());
|
||||
std::copy(s.begin(), s.end(), b58Result[i].begin());
|
||||
}
|
||||
}
|
||||
REQUIRE(b58Result[0].size() == b58Result[1].size());
|
||||
CHECK(
|
||||
memcmp(
|
||||
b58Result[0].data(),
|
||||
b58Result[1].data(),
|
||||
b58Result[0].size()) == 0);
|
||||
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
std::span const outBuf{
|
||||
b256ResultBuf[i].data(), b256ResultBuf[i].size()};
|
||||
if (i == 0)
|
||||
{
|
||||
std::string const in(
|
||||
b58Result[i].data(),
|
||||
b58Result[i].data() + b58Result[i].size());
|
||||
auto const r =
|
||||
xrpl::b58_fast::detail::b58_to_b256_be(in, outBuf);
|
||||
REQUIRE(r);
|
||||
b256Result[i] = r.value();
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string const st(b58Result[i].begin(), b58Result[i].end());
|
||||
std::string const s = xrpl::b58_ref::detail::decodeBase58(st);
|
||||
REQUIRE(s.size());
|
||||
b256Result[i] = outBuf.subspan(0, s.size());
|
||||
std::copy(s.begin(), s.end(), b256Result[i].begin());
|
||||
}
|
||||
}
|
||||
|
||||
REQUIRE(b256Result[0].size() == b256Result[1].size());
|
||||
CHECK(
|
||||
memcmp(
|
||||
b256Result[0].data(),
|
||||
b256Result[1].data(),
|
||||
b256Result[0].size()) == 0);
|
||||
};
|
||||
|
||||
auto testTokenEncode = [&](xrpl::TokenType const tokType,
|
||||
std::span<std::uint8_t> const& b256Data) {
|
||||
std::array<std::uint8_t, 64> b58ResultBuf[2];
|
||||
std::array<std::span<std::uint8_t>, 2> b58Result;
|
||||
|
||||
std::array<std::uint8_t, 64> b256ResultBuf[2];
|
||||
std::array<std::span<std::uint8_t>, 2> b256Result;
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
std::span const outBuf{
|
||||
b58ResultBuf[i].data(), b58ResultBuf[i].size()};
|
||||
if (i == 0)
|
||||
{
|
||||
auto const r = xrpl::b58_fast::encodeBase58Token(
|
||||
tokType, b256Data, outBuf);
|
||||
REQUIRE(r);
|
||||
b58Result[i] = r.value();
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string const s = xrpl::b58_ref::encodeBase58Token(
|
||||
tokType, b256Data.data(), b256Data.size());
|
||||
REQUIRE(s.size());
|
||||
b58Result[i] = outBuf.subspan(0, s.size());
|
||||
std::copy(s.begin(), s.end(), b58Result[i].begin());
|
||||
}
|
||||
}
|
||||
REQUIRE(b58Result[0].size() == b58Result[1].size());
|
||||
CHECK(
|
||||
memcmp(
|
||||
b58Result[0].data(),
|
||||
b58Result[1].data(),
|
||||
b58Result[0].size()) == 0);
|
||||
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
std::span const outBuf{
|
||||
b256ResultBuf[i].data(), b256ResultBuf[i].size()};
|
||||
if (i == 0)
|
||||
{
|
||||
std::string const in(
|
||||
b58Result[i].data(),
|
||||
b58Result[i].data() + b58Result[i].size());
|
||||
auto const r =
|
||||
xrpl::b58_fast::decodeBase58Token(tokType, in, outBuf);
|
||||
REQUIRE(r);
|
||||
b256Result[i] = r.value();
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string const st(b58Result[i].begin(), b58Result[i].end());
|
||||
std::string const s =
|
||||
xrpl::b58_ref::decodeBase58Token(st, tokType);
|
||||
REQUIRE(s.size());
|
||||
b256Result[i] = outBuf.subspan(0, s.size());
|
||||
std::copy(s.begin(), s.end(), b256Result[i].begin());
|
||||
}
|
||||
}
|
||||
|
||||
REQUIRE(b256Result[0].size() == b256Result[1].size());
|
||||
CHECK(
|
||||
memcmp(
|
||||
b256Result[0].data(),
|
||||
b256Result[1].data(),
|
||||
b256Result[0].size()) == 0);
|
||||
};
|
||||
|
||||
auto testIt = [&](xrpl::TokenType const tokType,
|
||||
std::span<std::uint8_t> const& b256Data) {
|
||||
testRawEncode(b256Data);
|
||||
testTokenEncode(tokType, b256Data);
|
||||
};
|
||||
|
||||
// test every token type with data where every byte is the same and the
|
||||
// bytes range from 0-255
|
||||
for (int i = 0; i < numTokenTypeIndexes; ++i)
|
||||
{
|
||||
std::array<std::uint8_t, 128> b256DataBuf;
|
||||
auto const [tokType, tokSize] = tokenTypeAndSize(i);
|
||||
for (int d = 0; d <= 255; ++d)
|
||||
{
|
||||
memset(b256DataBuf.data(), d, tokSize);
|
||||
testIt(tokType, std::span(b256DataBuf.data(), tokSize));
|
||||
}
|
||||
}
|
||||
|
||||
// test with random data
|
||||
constexpr std::size_t iters = 100000;
|
||||
for (int i = 0; i < iters; ++i)
|
||||
{
|
||||
std::array<std::uint8_t, 128> b256DataBuf;
|
||||
auto const [tokType, b256Data] = randomB256TestData(b256DataBuf);
|
||||
testIt(tokType, b256Data);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
|
||||
#endif // _MSC_VER
|
||||
@@ -1,323 +0,0 @@
|
||||
#include <xrpl/basics/Blob.h>
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/basics/hardened_hash.h>
|
||||
|
||||
#include <boost/endian/conversion.hpp>
|
||||
|
||||
#include <doctest/doctest.h>
|
||||
|
||||
#include <complex>
|
||||
#include <type_traits>
|
||||
#include <unordered_set>
|
||||
|
||||
using namespace xrpl;
|
||||
|
||||
// a non-hashing Hasher that just copies the bytes.
|
||||
// Used to test hash_append in base_uint
|
||||
template <std::size_t Bits>
|
||||
struct nonhash
|
||||
{
|
||||
static constexpr auto const endian = boost::endian::order::big;
|
||||
static constexpr std::size_t WIDTH = Bits / 8;
|
||||
|
||||
std::array<std::uint8_t, WIDTH> data_;
|
||||
|
||||
nonhash() = default;
|
||||
|
||||
void
|
||||
operator()(void const* key, std::size_t len) noexcept
|
||||
{
|
||||
assert(len == WIDTH);
|
||||
memcpy(data_.data(), key, len);
|
||||
}
|
||||
|
||||
explicit
|
||||
operator std::size_t() noexcept
|
||||
{
|
||||
return WIDTH;
|
||||
}
|
||||
};
|
||||
|
||||
using test96 = base_uint<96>;
|
||||
static_assert(std::is_copy_constructible<test96>::value);
|
||||
static_assert(std::is_copy_assignable<test96>::value);
|
||||
|
||||
TEST_SUITE_BEGIN("base_uint");
|
||||
|
||||
TEST_CASE("comparisons 64-bit")
|
||||
{
|
||||
static constexpr std::
|
||||
array<std::pair<std::string_view, std::string_view>, 6>
|
||||
test_args{
|
||||
{{"0000000000000000", "0000000000000001"},
|
||||
{"0000000000000000", "ffffffffffffffff"},
|
||||
{"1234567812345678", "2345678923456789"},
|
||||
{"8000000000000000", "8000000000000001"},
|
||||
{"aaaaaaaaaaaaaaa9", "aaaaaaaaaaaaaaaa"},
|
||||
{"fffffffffffffffe", "ffffffffffffffff"}}};
|
||||
|
||||
for (auto const& arg : test_args)
|
||||
{
|
||||
xrpl::base_uint<64> const u{arg.first}, v{arg.second};
|
||||
CHECK(u < v);
|
||||
CHECK(u <= v);
|
||||
CHECK(u != v);
|
||||
CHECK(!(u == v));
|
||||
CHECK(!(u > v));
|
||||
CHECK(!(u >= v));
|
||||
CHECK(!(v < u));
|
||||
CHECK(!(v <= u));
|
||||
CHECK(v != u);
|
||||
CHECK(!(v == u));
|
||||
CHECK(v > u);
|
||||
CHECK(v >= u);
|
||||
CHECK(u == u);
|
||||
CHECK(v == v);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("comparisons 96-bit")
|
||||
{
|
||||
static constexpr std::
|
||||
array<std::pair<std::string_view, std::string_view>, 6>
|
||||
test_args{{
|
||||
{"000000000000000000000000", "000000000000000000000001"},
|
||||
{"000000000000000000000000", "ffffffffffffffffffffffff"},
|
||||
{"0123456789ab0123456789ab", "123456789abc123456789abc"},
|
||||
{"555555555555555555555555", "55555555555a555555555555"},
|
||||
{"aaaaaaaaaaaaaaa9aaaaaaaa", "aaaaaaaaaaaaaaaaaaaaaaaa"},
|
||||
{"fffffffffffffffffffffffe", "ffffffffffffffffffffffff"},
|
||||
}};
|
||||
|
||||
for (auto const& arg : test_args)
|
||||
{
|
||||
xrpl::base_uint<96> const u{arg.first}, v{arg.second};
|
||||
CHECK(u < v);
|
||||
CHECK(u <= v);
|
||||
CHECK(u != v);
|
||||
CHECK(!(u == v));
|
||||
CHECK(!(u > v));
|
||||
CHECK(!(u >= v));
|
||||
CHECK(!(v < u));
|
||||
CHECK(!(v <= u));
|
||||
CHECK(v != u);
|
||||
CHECK(!(v == u));
|
||||
CHECK(v > u);
|
||||
CHECK(v >= u);
|
||||
CHECK(u == u);
|
||||
CHECK(v == v);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("general purpose tests")
|
||||
{
|
||||
static_assert(!std::is_constructible<test96, std::complex<double>>::value);
|
||||
static_assert(!std::is_assignable<test96&, std::complex<double>>::value);
|
||||
|
||||
// used to verify set insertion (hashing required)
|
||||
std::unordered_set<test96, hardened_hash<>> uset;
|
||||
|
||||
Blob raw{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
|
||||
CHECK(test96::bytes == raw.size());
|
||||
|
||||
test96 u{raw};
|
||||
uset.insert(u);
|
||||
CHECK(raw.size() == u.size());
|
||||
CHECK(to_string(u) == "0102030405060708090A0B0C");
|
||||
CHECK(to_short_string(u) == "01020304...");
|
||||
CHECK(*u.data() == 1);
|
||||
CHECK(u.signum() == 1);
|
||||
CHECK(!!u);
|
||||
CHECK(!u.isZero());
|
||||
CHECK(u.isNonZero());
|
||||
unsigned char t = 0;
|
||||
for (auto& d : u)
|
||||
{
|
||||
CHECK(d == ++t);
|
||||
}
|
||||
|
||||
// Test hash_append by "hashing" with a no-op hasher (h)
|
||||
// and then extracting the bytes that were written during hashing
|
||||
// back into another base_uint (w) for comparison with the original
|
||||
nonhash<96> h;
|
||||
hash_append(h, u);
|
||||
test96 w{std::vector<std::uint8_t>(h.data_.begin(), h.data_.end())};
|
||||
CHECK(w == u);
|
||||
|
||||
test96 v{~u};
|
||||
uset.insert(v);
|
||||
CHECK(to_string(v) == "FEFDFCFBFAF9F8F7F6F5F4F3");
|
||||
CHECK(to_short_string(v) == "FEFDFCFB...");
|
||||
CHECK(*v.data() == 0xfe);
|
||||
CHECK(v.signum() == 1);
|
||||
CHECK(!!v);
|
||||
CHECK(!v.isZero());
|
||||
CHECK(v.isNonZero());
|
||||
t = 0xff;
|
||||
for (auto& d : v)
|
||||
{
|
||||
CHECK(d == --t);
|
||||
}
|
||||
|
||||
CHECK(u < v);
|
||||
CHECK(v > u);
|
||||
|
||||
v = u;
|
||||
CHECK(v == u);
|
||||
|
||||
test96 z{beast::zero};
|
||||
uset.insert(z);
|
||||
CHECK(to_string(z) == "000000000000000000000000");
|
||||
CHECK(to_short_string(z) == "00000000...");
|
||||
CHECK(*z.data() == 0);
|
||||
CHECK(*z.begin() == 0);
|
||||
CHECK(*std::prev(z.end(), 1) == 0);
|
||||
CHECK(z.signum() == 0);
|
||||
CHECK(!z);
|
||||
CHECK(z.isZero());
|
||||
CHECK(!z.isNonZero());
|
||||
for (auto& d : z)
|
||||
{
|
||||
CHECK(d == 0);
|
||||
}
|
||||
|
||||
test96 n{z};
|
||||
n++;
|
||||
CHECK(n == test96(1));
|
||||
n--;
|
||||
CHECK(n == beast::zero);
|
||||
CHECK(n == z);
|
||||
n--;
|
||||
CHECK(to_string(n) == "FFFFFFFFFFFFFFFFFFFFFFFF");
|
||||
CHECK(to_short_string(n) == "FFFFFFFF...");
|
||||
n = beast::zero;
|
||||
CHECK(n == z);
|
||||
|
||||
test96 zp1{z};
|
||||
zp1++;
|
||||
test96 zm1{z};
|
||||
zm1--;
|
||||
test96 x{zm1 ^ zp1};
|
||||
uset.insert(x);
|
||||
CHECK(to_string(x) == "FFFFFFFFFFFFFFFFFFFFFFFE");
|
||||
CHECK(to_short_string(x) == "FFFFFFFF...");
|
||||
|
||||
CHECK(uset.size() == 4);
|
||||
|
||||
test96 tmp;
|
||||
CHECK(tmp.parseHex(to_string(u)));
|
||||
CHECK(tmp == u);
|
||||
tmp = z;
|
||||
|
||||
// fails with extra char
|
||||
CHECK(!tmp.parseHex("A" + to_string(u)));
|
||||
tmp = z;
|
||||
|
||||
// fails with extra char at end
|
||||
CHECK(!tmp.parseHex(to_string(u) + "A"));
|
||||
|
||||
// fails with a non-hex character at some point in the string:
|
||||
tmp = z;
|
||||
|
||||
for (std::size_t i = 0; i != 24; ++i)
|
||||
{
|
||||
std::string x = to_string(z);
|
||||
x[i] = ('G' + (i % 10));
|
||||
CHECK(!tmp.parseHex(x));
|
||||
}
|
||||
|
||||
// Walking 1s:
|
||||
for (std::size_t i = 0; i != 24; ++i)
|
||||
{
|
||||
std::string s1 = "000000000000000000000000";
|
||||
s1[i] = '1';
|
||||
|
||||
CHECK(tmp.parseHex(s1));
|
||||
CHECK(to_string(tmp) == s1);
|
||||
}
|
||||
|
||||
// Walking 0s:
|
||||
for (std::size_t i = 0; i != 24; ++i)
|
||||
{
|
||||
std::string s1 = "111111111111111111111111";
|
||||
s1[i] = '0';
|
||||
|
||||
CHECK(tmp.parseHex(s1));
|
||||
CHECK(to_string(tmp) == s1);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("constexpr constructors")
|
||||
{
|
||||
static_assert(test96{}.signum() == 0);
|
||||
static_assert(test96("0").signum() == 0);
|
||||
static_assert(test96("000000000000000000000000").signum() == 0);
|
||||
static_assert(test96("000000000000000000000001").signum() == 1);
|
||||
static_assert(test96("800000000000000000000000").signum() == 1);
|
||||
|
||||
// Using the constexpr constructor in a non-constexpr context
|
||||
// with an error in the parsing throws an exception.
|
||||
{
|
||||
// Invalid length for string.
|
||||
bool caught = false;
|
||||
try
|
||||
{
|
||||
// Try to prevent constant evaluation.
|
||||
std::vector<char> str(23, '7');
|
||||
std::string_view sView(str.data(), str.size());
|
||||
[[maybe_unused]] test96 t96(sView);
|
||||
}
|
||||
catch (std::invalid_argument const& e)
|
||||
{
|
||||
CHECK(e.what() == std::string("invalid length for hex string"));
|
||||
caught = true;
|
||||
}
|
||||
CHECK(caught);
|
||||
}
|
||||
{
|
||||
// Invalid character in string.
|
||||
bool caught = false;
|
||||
try
|
||||
{
|
||||
// Try to prevent constant evaluation.
|
||||
std::vector<char> str(23, '7');
|
||||
str.push_back('G');
|
||||
std::string_view sView(str.data(), str.size());
|
||||
[[maybe_unused]] test96 t96(sView);
|
||||
}
|
||||
catch (std::range_error const& e)
|
||||
{
|
||||
CHECK(e.what() == std::string("invalid hex character"));
|
||||
caught = true;
|
||||
}
|
||||
CHECK(caught);
|
||||
}
|
||||
|
||||
// Verify that constexpr base_uints interpret a string the same
|
||||
// way parseHex() does.
|
||||
struct StrBaseUint
|
||||
{
|
||||
char const* const str;
|
||||
test96 tst;
|
||||
|
||||
constexpr StrBaseUint(char const* s) : str(s), tst(s)
|
||||
{
|
||||
}
|
||||
};
|
||||
constexpr StrBaseUint testCases[] = {
|
||||
"000000000000000000000000",
|
||||
"000000000000000000000001",
|
||||
"fedcba9876543210ABCDEF91",
|
||||
"19FEDCBA0123456789abcdef",
|
||||
"800000000000000000000000",
|
||||
"fFfFfFfFfFfFfFfFfFfFfFfF"};
|
||||
|
||||
for (StrBaseUint const& t : testCases)
|
||||
{
|
||||
test96 t96;
|
||||
CHECK(t96.parseHex(t.str));
|
||||
CHECK(t96 == t.tst);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
@@ -1,132 +0,0 @@
|
||||
#include <xrpl/basics/hardened_hash.h>
|
||||
|
||||
#include <doctest/doctest.h>
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <iomanip>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
using namespace xrpl;
|
||||
|
||||
namespace {
|
||||
|
||||
template <class T>
|
||||
class test_user_type_member
|
||||
{
|
||||
private:
|
||||
T t;
|
||||
|
||||
public:
|
||||
explicit test_user_type_member(T const& t_ = T()) : t(t_)
|
||||
{
|
||||
}
|
||||
|
||||
template <class Hasher>
|
||||
friend void
|
||||
hash_append(Hasher& h, test_user_type_member const& a) noexcept
|
||||
{
|
||||
using beast::hash_append;
|
||||
hash_append(h, a.t);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class test_user_type_free
|
||||
{
|
||||
private:
|
||||
T t;
|
||||
|
||||
public:
|
||||
explicit test_user_type_free(T const& t_ = T()) : t(t_)
|
||||
{
|
||||
}
|
||||
|
||||
template <class Hasher>
|
||||
friend void
|
||||
hash_append(Hasher& h, test_user_type_free const& a) noexcept
|
||||
{
|
||||
using beast::hash_append;
|
||||
hash_append(h, a.t);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
using test_hardened_unordered_set = std::unordered_set<T, hardened_hash<>>;
|
||||
|
||||
template <class T>
|
||||
using test_hardened_unordered_map = std::unordered_map<T, int, hardened_hash<>>;
|
||||
|
||||
template <class T>
|
||||
using test_hardened_unordered_multiset =
|
||||
std::unordered_multiset<T, hardened_hash<>>;
|
||||
|
||||
template <class T>
|
||||
using test_hardened_unordered_multimap =
|
||||
std::unordered_multimap<T, int, hardened_hash<>>;
|
||||
|
||||
template <class T>
|
||||
void
|
||||
check()
|
||||
{
|
||||
T t{};
|
||||
hardened_hash<>()(t);
|
||||
}
|
||||
|
||||
template <template <class T> class U>
|
||||
void
|
||||
check_user_type()
|
||||
{
|
||||
check<U<bool>>();
|
||||
check<U<char>>();
|
||||
check<U<signed char>>();
|
||||
check<U<unsigned char>>();
|
||||
check<U<wchar_t>>();
|
||||
check<U<short>>();
|
||||
check<U<unsigned short>>();
|
||||
check<U<int>>();
|
||||
check<U<unsigned int>>();
|
||||
check<U<long>>();
|
||||
check<U<long long>>();
|
||||
check<U<unsigned long>>();
|
||||
check<U<unsigned long long>>();
|
||||
check<U<float>>();
|
||||
check<U<double>>();
|
||||
check<U<long double>>();
|
||||
}
|
||||
|
||||
template <template <class T> class C>
|
||||
void
|
||||
check_container()
|
||||
{
|
||||
{
|
||||
C<test_user_type_member<std::string>> c;
|
||||
(void)c;
|
||||
}
|
||||
|
||||
{
|
||||
C<test_user_type_free<std::string>> c;
|
||||
(void)c;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_SUITE_BEGIN("hardened_hash");
|
||||
|
||||
TEST_CASE("user types")
|
||||
{
|
||||
check_user_type<test_user_type_member>();
|
||||
check_user_type<test_user_type_free>();
|
||||
}
|
||||
|
||||
TEST_CASE("containers")
|
||||
{
|
||||
check_container<test_hardened_unordered_set>();
|
||||
check_container<test_hardened_unordered_map>();
|
||||
check_container<test_hardened_unordered_multiset>();
|
||||
check_container<test_hardened_unordered_multimap>();
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
@@ -1,77 +0,0 @@
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/basics/join.h>
|
||||
|
||||
#include <doctest/doctest.h>
|
||||
|
||||
#include <array>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace xrpl;
|
||||
|
||||
TEST_SUITE_BEGIN("join");
|
||||
|
||||
TEST_CASE("CollectionAndDelimiter")
|
||||
{
|
||||
auto test = [](auto collectionanddelimiter, std::string expected) {
|
||||
std::stringstream ss;
|
||||
// Put something else in the buffer before and after to ensure that
|
||||
// the << operator returns the stream correctly.
|
||||
ss << "(" << collectionanddelimiter << ")";
|
||||
auto const str = ss.str();
|
||||
CHECK(str.substr(1, str.length() - 2) == expected);
|
||||
CHECK(str.front() == '(');
|
||||
CHECK(str.back() == ')');
|
||||
};
|
||||
|
||||
// C++ array
|
||||
test(
|
||||
CollectionAndDelimiter(std::array<int, 4>{2, -1, 5, 10}, "/"),
|
||||
"2/-1/5/10");
|
||||
// One item C++ array edge case
|
||||
test(
|
||||
CollectionAndDelimiter(std::array<std::string, 1>{"test"}, " & "),
|
||||
"test");
|
||||
// Empty C++ array edge case
|
||||
test(CollectionAndDelimiter(std::array<int, 0>{}, ","), "");
|
||||
{
|
||||
// C-style array
|
||||
char letters[4]{'w', 'a', 's', 'd'};
|
||||
test(CollectionAndDelimiter(letters, std::to_string(0)), "w0a0s0d");
|
||||
}
|
||||
{
|
||||
// Auto sized C-style array
|
||||
std::string words[]{"one", "two", "three", "four"};
|
||||
test(CollectionAndDelimiter(words, "\n"), "one\ntwo\nthree\nfour");
|
||||
}
|
||||
{
|
||||
// One item C-style array edge case
|
||||
std::string words[]{"thing"};
|
||||
test(CollectionAndDelimiter(words, "\n"), "thing");
|
||||
}
|
||||
// Initializer list
|
||||
test(
|
||||
CollectionAndDelimiter(std::initializer_list<size_t>{19, 25}, "+"),
|
||||
"19+25");
|
||||
// vector
|
||||
test(
|
||||
CollectionAndDelimiter(std::vector<int>{0, 42}, std::to_string(99)),
|
||||
"09942");
|
||||
// empty vector edge case
|
||||
test(CollectionAndDelimiter(std::vector<uint256>{}, ","), "");
|
||||
// C-style string
|
||||
test(CollectionAndDelimiter("string", " "), "s t r i n g");
|
||||
// Empty C-style string edge case
|
||||
test(CollectionAndDelimiter("", "*"), "");
|
||||
// Single char C-style string edge case
|
||||
test(CollectionAndDelimiter("x", "*"), "x");
|
||||
// std::string
|
||||
test(CollectionAndDelimiter(std::string{"string"}, "-"), "s-t-r-i-n-g");
|
||||
// Empty std::string edge case
|
||||
test(CollectionAndDelimiter(std::string{""}, "*"), "");
|
||||
// Single char std::string edge case
|
||||
test(CollectionAndDelimiter(std::string{"y"}, "*"), "y");
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
@@ -1,2 +0,0 @@
|
||||
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
|
||||
#include <doctest/doctest.h>
|
||||
@@ -1,69 +0,0 @@
|
||||
#include <xrpl/beast/core/CurrentThreadName.h>
|
||||
|
||||
#include <doctest/doctest.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
|
||||
TEST_SUITE_BEGIN("CurrentThreadName");
|
||||
|
||||
namespace {
|
||||
|
||||
void
|
||||
exerciseName(
|
||||
std::string myName,
|
||||
std::atomic<bool>* stop,
|
||||
std::atomic<int>* state)
|
||||
{
|
||||
// Verify that upon creation a thread has no name.
|
||||
auto const initialThreadName = beast::getCurrentThreadName();
|
||||
|
||||
// Set the new name.
|
||||
beast::setCurrentThreadName(myName);
|
||||
|
||||
// Indicate to caller that the name is set.
|
||||
*state = 1;
|
||||
|
||||
// If there is an initial thread name then we failed.
|
||||
if (!initialThreadName.empty())
|
||||
return;
|
||||
|
||||
// Wait until all threads have their names.
|
||||
while (!*stop)
|
||||
;
|
||||
|
||||
// Make sure the thread name that we set before is still there
|
||||
// (not overwritten by, for instance, another thread).
|
||||
if (beast::getCurrentThreadName() == myName)
|
||||
*state = 2;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("Thread names are preserved")
|
||||
{
|
||||
// Make two different threads with two different names. Make sure
|
||||
// that the expected thread names are still there when the thread
|
||||
// exits.
|
||||
std::atomic<bool> stop{false};
|
||||
|
||||
std::atomic<int> stateA{0};
|
||||
std::thread tA(exerciseName, "tA", &stop, &stateA);
|
||||
|
||||
std::atomic<int> stateB{0};
|
||||
std::thread tB(exerciseName, "tB", &stop, &stateB);
|
||||
|
||||
// Wait until both threads have set their names.
|
||||
while (stateA == 0 || stateB == 0)
|
||||
;
|
||||
|
||||
stop = true;
|
||||
tA.join();
|
||||
tB.join();
|
||||
|
||||
// Both threads should still have the expected name when they exit.
|
||||
CHECK(stateA == 2);
|
||||
CHECK(stateB == 2);
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
@@ -1,458 +0,0 @@
|
||||
// IPEndpoint doctest - converted from src/test/beast/IPEndpoint_test.cpp
|
||||
|
||||
#include <xrpl/basics/random.h>
|
||||
#include <xrpl/beast/net/IPEndpoint.h>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/asio/ip/address.hpp>
|
||||
#include <boost/predef.h>
|
||||
|
||||
#include <doctest/doctest.h>
|
||||
|
||||
#include <sstream>
|
||||
#include <unordered_set>
|
||||
|
||||
TEST_SUITE_BEGIN("IPEndpoint");
|
||||
|
||||
namespace {
|
||||
|
||||
using namespace beast::IP;
|
||||
|
||||
Endpoint
|
||||
randomEP(bool v4 = true)
|
||||
{
|
||||
using namespace xrpl;
|
||||
auto dv4 = []() -> AddressV4::bytes_type {
|
||||
return {
|
||||
{static_cast<std::uint8_t>(rand_int<int>(1, UINT8_MAX)),
|
||||
static_cast<std::uint8_t>(rand_int<int>(1, UINT8_MAX)),
|
||||
static_cast<std::uint8_t>(rand_int<int>(1, UINT8_MAX)),
|
||||
static_cast<std::uint8_t>(rand_int<int>(1, UINT8_MAX))}};
|
||||
};
|
||||
auto dv6 = []() -> AddressV6::bytes_type {
|
||||
return {
|
||||
{static_cast<std::uint8_t>(rand_int<int>(1, UINT8_MAX)),
|
||||
static_cast<std::uint8_t>(rand_int<int>(1, UINT8_MAX)),
|
||||
static_cast<std::uint8_t>(rand_int<int>(1, UINT8_MAX)),
|
||||
static_cast<std::uint8_t>(rand_int<int>(1, UINT8_MAX)),
|
||||
static_cast<std::uint8_t>(rand_int<int>(1, UINT8_MAX)),
|
||||
static_cast<std::uint8_t>(rand_int<int>(1, UINT8_MAX)),
|
||||
static_cast<std::uint8_t>(rand_int<int>(1, UINT8_MAX)),
|
||||
static_cast<std::uint8_t>(rand_int<int>(1, UINT8_MAX)),
|
||||
static_cast<std::uint8_t>(rand_int<int>(1, UINT8_MAX)),
|
||||
static_cast<std::uint8_t>(rand_int<int>(1, UINT8_MAX)),
|
||||
static_cast<std::uint8_t>(rand_int<int>(1, UINT8_MAX)),
|
||||
static_cast<std::uint8_t>(rand_int<int>(1, UINT8_MAX)),
|
||||
static_cast<std::uint8_t>(rand_int<int>(1, UINT8_MAX)),
|
||||
static_cast<std::uint8_t>(rand_int<int>(1, UINT8_MAX)),
|
||||
static_cast<std::uint8_t>(rand_int<int>(1, UINT8_MAX)),
|
||||
static_cast<std::uint8_t>(rand_int<int>(1, UINT8_MAX))}};
|
||||
};
|
||||
return Endpoint{
|
||||
v4 ? Address{AddressV4{dv4()}} : Address{AddressV6{dv6()}},
|
||||
rand_int<std::uint16_t>(1, UINT16_MAX)};
|
||||
}
|
||||
|
||||
void
|
||||
shouldParseAddrV4(
|
||||
std::string const& s,
|
||||
std::uint32_t value,
|
||||
std::string const& normal = "")
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
Address const result{boost::asio::ip::make_address(s, ec)};
|
||||
REQUIRE_MESSAGE(!ec, ec.message());
|
||||
REQUIRE_MESSAGE(result.is_v4(), s.c_str());
|
||||
REQUIRE_MESSAGE(result.to_v4().to_uint() == value, s.c_str());
|
||||
CHECK_MESSAGE(
|
||||
result.to_string() == (normal.empty() ? s : normal), s.c_str());
|
||||
}
|
||||
|
||||
void
|
||||
failParseAddr(std::string const& s)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
auto a = boost::asio::ip::make_address(s, ec);
|
||||
CHECK_MESSAGE(ec, s.c_str());
|
||||
}
|
||||
|
||||
void
|
||||
shouldParseEPV4(
|
||||
std::string const& s,
|
||||
AddressV4::bytes_type const& value,
|
||||
std::uint16_t p,
|
||||
std::string const& normal = "")
|
||||
{
|
||||
auto const result = Endpoint::from_string_checked(s);
|
||||
REQUIRE(result);
|
||||
REQUIRE(result->address().is_v4());
|
||||
REQUIRE(result->address().to_v4() == AddressV4{value});
|
||||
CHECK(result->port() == p);
|
||||
CHECK(to_string(*result) == (normal.empty() ? s : normal));
|
||||
}
|
||||
|
||||
void
|
||||
shouldParseEPV6(
|
||||
std::string const& s,
|
||||
AddressV6::bytes_type const& value,
|
||||
std::uint16_t p,
|
||||
std::string const& normal = "")
|
||||
{
|
||||
auto result = Endpoint::from_string_checked(s);
|
||||
REQUIRE(result);
|
||||
REQUIRE(result->address().is_v6());
|
||||
REQUIRE(result->address().to_v6() == AddressV6{value});
|
||||
CHECK(result->port() == p);
|
||||
CHECK(to_string(*result) == (normal.empty() ? s : normal));
|
||||
}
|
||||
|
||||
void
|
||||
failParseEP(std::string s)
|
||||
{
|
||||
auto a1 = Endpoint::from_string(s);
|
||||
CHECK_MESSAGE(is_unspecified(a1), s.c_str());
|
||||
|
||||
auto a2 = Endpoint::from_string(s);
|
||||
CHECK_MESSAGE(is_unspecified(a2), s.c_str());
|
||||
|
||||
boost::replace_last(s, ":", " ");
|
||||
auto a3 = Endpoint::from_string(s);
|
||||
CHECK_MESSAGE(is_unspecified(a3), s.c_str());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool
|
||||
parse(std::string const& text, T& t)
|
||||
{
|
||||
std::istringstream stream{text};
|
||||
stream >> t;
|
||||
return !stream.fail();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
shouldPass(std::string const& text, std::string const& normal = "")
|
||||
{
|
||||
T t;
|
||||
CHECK(parse(text, t));
|
||||
CHECK_MESSAGE(
|
||||
to_string(t) == (normal.empty() ? text : normal), text.c_str());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
shouldFail(std::string const& text)
|
||||
{
|
||||
T t;
|
||||
CHECK_FALSE_MESSAGE(parse(text, t), text.c_str());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("AddressV4")
|
||||
{
|
||||
CHECK(AddressV4{}.to_uint() == 0);
|
||||
CHECK(is_unspecified(AddressV4{}));
|
||||
CHECK(AddressV4{0x01020304}.to_uint() == 0x01020304);
|
||||
|
||||
{
|
||||
AddressV4::bytes_type d = {{1, 2, 3, 4}};
|
||||
CHECK(AddressV4{d}.to_uint() == 0x01020304);
|
||||
CHECK_FALSE(is_unspecified(AddressV4{d}));
|
||||
}
|
||||
|
||||
AddressV4 const v1{1};
|
||||
CHECK(AddressV4{v1}.to_uint() == 1);
|
||||
|
||||
{
|
||||
AddressV4 v;
|
||||
v = v1;
|
||||
CHECK(v.to_uint() == v1.to_uint());
|
||||
}
|
||||
|
||||
{
|
||||
AddressV4 v;
|
||||
auto d = v.to_bytes();
|
||||
d[0] = 1;
|
||||
d[1] = 2;
|
||||
d[2] = 3;
|
||||
d[3] = 4;
|
||||
v = AddressV4{d};
|
||||
CHECK(v.to_uint() == 0x01020304);
|
||||
}
|
||||
|
||||
CHECK(AddressV4(0x01020304).to_string() == "1.2.3.4");
|
||||
|
||||
shouldParseAddrV4("1.2.3.4", 0x01020304);
|
||||
shouldParseAddrV4("255.255.255.255", 0xffffffff);
|
||||
shouldParseAddrV4("0.0.0.0", 0);
|
||||
|
||||
failParseAddr(".");
|
||||
failParseAddr("..");
|
||||
failParseAddr("...");
|
||||
failParseAddr("....");
|
||||
#if BOOST_OS_WINDOWS
|
||||
// WINDOWS bug in asio - I don't think these should parse
|
||||
// at all, and in-fact they do not on mac/linux
|
||||
shouldParseAddrV4("1", 0x00000001, "0.0.0.1");
|
||||
shouldParseAddrV4("1.2", 0x01000002, "1.0.0.2");
|
||||
shouldParseAddrV4("1.2.3", 0x01020003, "1.2.0.3");
|
||||
#else
|
||||
failParseAddr("1");
|
||||
failParseAddr("1.2");
|
||||
failParseAddr("1.2.3");
|
||||
#endif
|
||||
failParseAddr("1.");
|
||||
failParseAddr("1.2.");
|
||||
failParseAddr("1.2.3.");
|
||||
failParseAddr("256.0.0.0");
|
||||
failParseAddr("-1.2.3.4");
|
||||
}
|
||||
|
||||
TEST_CASE("AddressV4::Bytes")
|
||||
{
|
||||
AddressV4::bytes_type d1 = {{10, 0, 0, 1}};
|
||||
AddressV4 v4{d1};
|
||||
CHECK(v4.to_bytes()[0] == 10);
|
||||
CHECK(v4.to_bytes()[1] == 0);
|
||||
CHECK(v4.to_bytes()[2] == 0);
|
||||
CHECK(v4.to_bytes()[3] == 1);
|
||||
|
||||
CHECK((~((0xff) << 16)) == 0xff00ffff);
|
||||
|
||||
auto d2 = v4.to_bytes();
|
||||
d2[1] = 10;
|
||||
v4 = AddressV4{d2};
|
||||
CHECK(v4.to_bytes()[0] == 10);
|
||||
CHECK(v4.to_bytes()[1] == 10);
|
||||
CHECK(v4.to_bytes()[2] == 0);
|
||||
CHECK(v4.to_bytes()[3] == 1);
|
||||
}
|
||||
|
||||
TEST_CASE("Address")
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
Address result{boost::asio::ip::make_address("1.2.3.4", ec)};
|
||||
AddressV4::bytes_type d = {{1, 2, 3, 4}};
|
||||
CHECK(!ec);
|
||||
CHECK(result.is_v4());
|
||||
CHECK(result.to_v4() == AddressV4{d});
|
||||
}
|
||||
|
||||
TEST_CASE("Endpoint")
|
||||
{
|
||||
shouldParseEPV4("1.2.3.4", {{1, 2, 3, 4}}, 0);
|
||||
shouldParseEPV4("1.2.3.4:5", {{1, 2, 3, 4}}, 5);
|
||||
shouldParseEPV4("1.2.3.4 5", {{1, 2, 3, 4}}, 5, "1.2.3.4:5");
|
||||
// leading, trailing space
|
||||
shouldParseEPV4(" 1.2.3.4:5", {{1, 2, 3, 4}}, 5, "1.2.3.4:5");
|
||||
shouldParseEPV4("1.2.3.4:5 ", {{1, 2, 3, 4}}, 5, "1.2.3.4:5");
|
||||
shouldParseEPV4("1.2.3.4 ", {{1, 2, 3, 4}}, 0, "1.2.3.4");
|
||||
shouldParseEPV4(" 1.2.3.4", {{1, 2, 3, 4}}, 0, "1.2.3.4");
|
||||
shouldParseEPV6(
|
||||
"2001:db8:a0b:12f0::1",
|
||||
{{32, 01, 13, 184, 10, 11, 18, 240, 0, 0, 0, 0, 0, 0, 0, 1}},
|
||||
0);
|
||||
shouldParseEPV6(
|
||||
"[2001:db8:a0b:12f0::1]:8",
|
||||
{{32, 01, 13, 184, 10, 11, 18, 240, 0, 0, 0, 0, 0, 0, 0, 1}},
|
||||
8);
|
||||
shouldParseEPV6(
|
||||
"[2001:2002:2003:2004:2005:2006:2007:2008]:65535",
|
||||
{{32, 1, 32, 2, 32, 3, 32, 4, 32, 5, 32, 6, 32, 7, 32, 8}},
|
||||
65535);
|
||||
shouldParseEPV6(
|
||||
"2001:2002:2003:2004:2005:2006:2007:2008 65535",
|
||||
{{32, 1, 32, 2, 32, 3, 32, 4, 32, 5, 32, 6, 32, 7, 32, 8}},
|
||||
65535,
|
||||
"[2001:2002:2003:2004:2005:2006:2007:2008]:65535");
|
||||
|
||||
Endpoint ep;
|
||||
|
||||
AddressV4::bytes_type d = {{127, 0, 0, 1}};
|
||||
ep = Endpoint(AddressV4{d}, 80);
|
||||
CHECK(!is_unspecified(ep));
|
||||
CHECK(!is_public(ep));
|
||||
CHECK(is_private(ep));
|
||||
CHECK(!is_multicast(ep));
|
||||
CHECK(is_loopback(ep));
|
||||
CHECK(to_string(ep) == "127.0.0.1:80");
|
||||
// same address as v4 mapped in ipv6
|
||||
ep = Endpoint(
|
||||
boost::asio::ip::make_address_v6(
|
||||
boost::asio::ip::v4_mapped, AddressV4{d}),
|
||||
80);
|
||||
CHECK(!is_unspecified(ep));
|
||||
CHECK(!is_public(ep));
|
||||
CHECK(is_private(ep));
|
||||
CHECK(!is_multicast(ep));
|
||||
CHECK(!is_loopback(ep)); // mapped loopback is not a loopback
|
||||
CHECK(to_string(ep) == "[::ffff:127.0.0.1]:80");
|
||||
|
||||
d = {{10, 0, 0, 1}};
|
||||
ep = Endpoint(AddressV4{d});
|
||||
CHECK(get_class(ep.to_v4()) == 'A');
|
||||
CHECK(!is_unspecified(ep));
|
||||
CHECK(!is_public(ep));
|
||||
CHECK(is_private(ep));
|
||||
CHECK(!is_multicast(ep));
|
||||
CHECK(!is_loopback(ep));
|
||||
CHECK(to_string(ep) == "10.0.0.1");
|
||||
// same address as v4 mapped in ipv6
|
||||
ep = Endpoint(boost::asio::ip::make_address_v6(
|
||||
boost::asio::ip::v4_mapped, AddressV4{d}));
|
||||
CHECK(
|
||||
get_class(boost::asio::ip::make_address_v4(
|
||||
boost::asio::ip::v4_mapped, ep.to_v6())) == 'A');
|
||||
CHECK(!is_unspecified(ep));
|
||||
CHECK(!is_public(ep));
|
||||
CHECK(is_private(ep));
|
||||
CHECK(!is_multicast(ep));
|
||||
CHECK(!is_loopback(ep));
|
||||
CHECK(to_string(ep) == "::ffff:10.0.0.1");
|
||||
|
||||
d = {{166, 78, 151, 147}};
|
||||
ep = Endpoint(AddressV4{d});
|
||||
CHECK(!is_unspecified(ep));
|
||||
CHECK(is_public(ep));
|
||||
CHECK(!is_private(ep));
|
||||
CHECK(!is_multicast(ep));
|
||||
CHECK(!is_loopback(ep));
|
||||
CHECK(to_string(ep) == "166.78.151.147");
|
||||
// same address as v4 mapped in ipv6
|
||||
ep = Endpoint(boost::asio::ip::make_address_v6(
|
||||
boost::asio::ip::v4_mapped, AddressV4{d}));
|
||||
CHECK(!is_unspecified(ep));
|
||||
CHECK(is_public(ep));
|
||||
CHECK(!is_private(ep));
|
||||
CHECK(!is_multicast(ep));
|
||||
CHECK(!is_loopback(ep));
|
||||
CHECK(to_string(ep) == "::ffff:166.78.151.147");
|
||||
|
||||
// a private IPv6
|
||||
AddressV6::bytes_type d2 = {
|
||||
{253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}};
|
||||
ep = Endpoint(AddressV6{d2});
|
||||
CHECK(!is_unspecified(ep));
|
||||
CHECK(!is_public(ep));
|
||||
CHECK(is_private(ep));
|
||||
CHECK(!is_multicast(ep));
|
||||
CHECK(!is_loopback(ep));
|
||||
CHECK(to_string(ep) == "fd00::1");
|
||||
|
||||
{
|
||||
ep = Endpoint::from_string("192.0.2.112");
|
||||
CHECK(!is_unspecified(ep));
|
||||
CHECK(ep == Endpoint::from_string("192.0.2.112"));
|
||||
|
||||
auto const ep1 = Endpoint::from_string("192.0.2.112:2016");
|
||||
CHECK(!is_unspecified(ep1));
|
||||
CHECK(ep.address() == ep1.address());
|
||||
CHECK(ep1.port() == 2016);
|
||||
|
||||
auto const ep2 = Endpoint::from_string("192.0.2.112:2016");
|
||||
CHECK(!is_unspecified(ep2));
|
||||
CHECK(ep.address() == ep2.address());
|
||||
CHECK(ep2.port() == 2016);
|
||||
CHECK(ep1 == ep2);
|
||||
|
||||
auto const ep3 = Endpoint::from_string("192.0.2.112 2016");
|
||||
CHECK(!is_unspecified(ep3));
|
||||
CHECK(ep.address() == ep3.address());
|
||||
CHECK(ep3.port() == 2016);
|
||||
CHECK(ep2 == ep3);
|
||||
|
||||
auto const ep4 = Endpoint::from_string("192.0.2.112 2016");
|
||||
CHECK(!is_unspecified(ep4));
|
||||
CHECK(ep.address() == ep4.address());
|
||||
CHECK(ep4.port() == 2016);
|
||||
CHECK(ep3 == ep4);
|
||||
|
||||
CHECK(to_string(ep1) == to_string(ep2));
|
||||
CHECK(to_string(ep1) == to_string(ep3));
|
||||
CHECK(to_string(ep1) == to_string(ep4));
|
||||
}
|
||||
|
||||
{
|
||||
ep = Endpoint::from_string("[::]:2017");
|
||||
CHECK(is_unspecified(ep));
|
||||
CHECK(ep.port() == 2017);
|
||||
CHECK(ep.address() == AddressV6{});
|
||||
}
|
||||
|
||||
// Failures:
|
||||
failParseEP("192.0.2.112:port");
|
||||
failParseEP("ip:port");
|
||||
failParseEP("");
|
||||
failParseEP("1.2.3.256");
|
||||
|
||||
#if BOOST_OS_WINDOWS
|
||||
// windows asio bugs...false positives
|
||||
shouldParseEPV4("255", {{0, 0, 0, 255}}, 0, "0.0.0.255");
|
||||
shouldParseEPV4("512", {{0, 0, 2, 0}}, 0, "0.0.2.0");
|
||||
shouldParseEPV4("1.2.3:80", {{1, 2, 0, 3}}, 80, "1.2.0.3:80");
|
||||
#else
|
||||
failParseEP("255");
|
||||
failParseEP("512");
|
||||
failParseEP("1.2.3:80");
|
||||
#endif
|
||||
|
||||
failParseEP("1.2.3.4:65536");
|
||||
failParseEP("1.2.3.4:89119");
|
||||
failParseEP("1.2.3:89119");
|
||||
failParseEP("[::1]:89119");
|
||||
failParseEP("[::az]:1");
|
||||
failParseEP("[1234:5678:90ab:cdef:1234:5678:90ab:cdef:1111]:1");
|
||||
failParseEP("[1234:5678:90ab:cdef:1234:5678:90ab:cdef:1111]:12345");
|
||||
failParseEP("abcdef:12345");
|
||||
failParseEP("[abcdef]:12345");
|
||||
failParseEP("foo.org 12345");
|
||||
|
||||
// test with hashed container
|
||||
std::unordered_set<Endpoint> eps;
|
||||
constexpr auto items{100};
|
||||
float max_lf{0};
|
||||
for (auto i = 0; i < items; ++i)
|
||||
{
|
||||
eps.insert(randomEP(xrpl::rand_int(0, 1) == 1));
|
||||
max_lf = std::max(max_lf, eps.load_factor());
|
||||
}
|
||||
CHECK(eps.bucket_count() >= items);
|
||||
CHECK(max_lf > 0.90);
|
||||
}
|
||||
|
||||
TEST_CASE("Parse Endpoint")
|
||||
{
|
||||
shouldPass<Endpoint>("0.0.0.0");
|
||||
shouldPass<Endpoint>("192.168.0.1");
|
||||
shouldPass<Endpoint>("168.127.149.132");
|
||||
shouldPass<Endpoint>("168.127.149.132:80");
|
||||
shouldPass<Endpoint>("168.127.149.132:54321");
|
||||
shouldPass<Endpoint>("2001:db8:a0b:12f0::1");
|
||||
shouldPass<Endpoint>("[2001:db8:a0b:12f0::1]:8");
|
||||
shouldPass<Endpoint>("2001:db8:a0b:12f0::1 8", "[2001:db8:a0b:12f0::1]:8");
|
||||
shouldPass<Endpoint>("[::1]:8");
|
||||
shouldPass<Endpoint>("[2001:2002:2003:2004:2005:2006:2007:2008]:65535");
|
||||
|
||||
shouldFail<Endpoint>("1.2.3.256");
|
||||
shouldFail<Endpoint>("");
|
||||
#if BOOST_OS_WINDOWS
|
||||
// windows asio bugs...false positives
|
||||
shouldPass<Endpoint>("512", "0.0.2.0");
|
||||
shouldPass<Endpoint>("255", "0.0.0.255");
|
||||
shouldPass<Endpoint>("1.2.3:80", "1.2.0.3:80");
|
||||
#else
|
||||
shouldFail<Endpoint>("512");
|
||||
shouldFail<Endpoint>("255");
|
||||
shouldFail<Endpoint>("1.2.3:80");
|
||||
#endif
|
||||
shouldFail<Endpoint>("1.2.3:65536");
|
||||
shouldFail<Endpoint>("1.2.3:72131");
|
||||
shouldFail<Endpoint>("[::1]:89119");
|
||||
shouldFail<Endpoint>("[::az]:1");
|
||||
shouldFail<Endpoint>("[1234:5678:90ab:cdef:1234:5678:90ab:cdef:1111]:1");
|
||||
shouldFail<Endpoint>(
|
||||
"[1234:5678:90ab:cdef:1234:5678:90ab:cdef:1111]:12345");
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
@@ -1,95 +0,0 @@
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
|
||||
#include <doctest/doctest.h>
|
||||
|
||||
using namespace beast;
|
||||
|
||||
TEST_SUITE_BEGIN("Journal");
|
||||
|
||||
namespace {
|
||||
|
||||
class TestSink : public Journal::Sink
|
||||
{
|
||||
private:
|
||||
int m_count;
|
||||
|
||||
public:
|
||||
TestSink() : Sink(severities::kWarning, false), m_count(0)
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
count() const
|
||||
{
|
||||
return m_count;
|
||||
}
|
||||
|
||||
void
|
||||
reset()
|
||||
{
|
||||
m_count = 0;
|
||||
}
|
||||
|
||||
void
|
||||
write(severities::Severity level, std::string const&) override
|
||||
{
|
||||
if (level >= threshold())
|
||||
++m_count;
|
||||
}
|
||||
|
||||
void
|
||||
writeAlways(severities::Severity level, std::string const&) override
|
||||
{
|
||||
++m_count;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("Journal threshold kInfo")
|
||||
{
|
||||
TestSink sink;
|
||||
|
||||
using namespace beast::severities;
|
||||
sink.threshold(kInfo);
|
||||
|
||||
Journal j(sink);
|
||||
|
||||
j.trace() << " ";
|
||||
CHECK(sink.count() == 0);
|
||||
j.debug() << " ";
|
||||
CHECK(sink.count() == 0);
|
||||
j.info() << " ";
|
||||
CHECK(sink.count() == 1);
|
||||
j.warn() << " ";
|
||||
CHECK(sink.count() == 2);
|
||||
j.error() << " ";
|
||||
CHECK(sink.count() == 3);
|
||||
j.fatal() << " ";
|
||||
CHECK(sink.count() == 4);
|
||||
}
|
||||
|
||||
TEST_CASE("Journal threshold kDebug")
|
||||
{
|
||||
TestSink sink;
|
||||
|
||||
using namespace beast::severities;
|
||||
sink.threshold(kDebug);
|
||||
|
||||
Journal j(sink);
|
||||
|
||||
j.trace() << " ";
|
||||
CHECK(sink.count() == 0);
|
||||
j.debug() << " ";
|
||||
CHECK(sink.count() == 1);
|
||||
j.info() << " ";
|
||||
CHECK(sink.count() == 2);
|
||||
j.warn() << " ";
|
||||
CHECK(sink.count() == 3);
|
||||
j.error() << " ";
|
||||
CHECK(sink.count() == 4);
|
||||
j.fatal() << " ";
|
||||
CHECK(sink.count() == 5);
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
@@ -1,254 +0,0 @@
|
||||
#include <xrpl/beast/core/LexicalCast.h>
|
||||
#include <xrpl/beast/xor_shift_engine.h>
|
||||
|
||||
#include <doctest/doctest.h>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
using namespace beast;
|
||||
|
||||
TEST_SUITE_BEGIN("LexicalCast");
|
||||
|
||||
namespace {
|
||||
|
||||
template <class IntType>
|
||||
IntType
|
||||
nextRandomInt(xor_shift_engine& r)
|
||||
{
|
||||
return static_cast<IntType>(r());
|
||||
}
|
||||
|
||||
template <class IntType>
|
||||
void
|
||||
testInteger(IntType in)
|
||||
{
|
||||
std::string s;
|
||||
IntType out(in + 1);
|
||||
|
||||
CHECK(lexicalCastChecked(s, in));
|
||||
CHECK(lexicalCastChecked(out, s));
|
||||
CHECK(out == in);
|
||||
}
|
||||
|
||||
template <class IntType>
|
||||
void
|
||||
testIntegers(xor_shift_engine& r)
|
||||
{
|
||||
for (int i = 0; i < 1000; ++i)
|
||||
{
|
||||
IntType const value(nextRandomInt<IntType>(r));
|
||||
testInteger(value);
|
||||
}
|
||||
|
||||
testInteger(std::numeric_limits<IntType>::min());
|
||||
testInteger(std::numeric_limits<IntType>::max());
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void
|
||||
tryBadConvert(std::string const& s)
|
||||
{
|
||||
T out;
|
||||
CHECK_FALSE(lexicalCastChecked(out, s));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool
|
||||
tryEdgeCase(std::string const& s)
|
||||
{
|
||||
T ret;
|
||||
|
||||
bool const result = lexicalCastChecked(ret, s);
|
||||
|
||||
if (!result)
|
||||
return false;
|
||||
|
||||
return s == std::to_string(ret);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void
|
||||
testThrowConvert(std::string const& s, bool success)
|
||||
{
|
||||
bool result = !success;
|
||||
T out;
|
||||
|
||||
try
|
||||
{
|
||||
out = lexicalCastThrow<T>(s);
|
||||
result = true;
|
||||
}
|
||||
catch (BadLexicalCast const&)
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
|
||||
CHECK(result == success);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("random integers")
|
||||
{
|
||||
std::int64_t const seedValue = 50;
|
||||
xor_shift_engine r(seedValue);
|
||||
|
||||
SUBCASE("int")
|
||||
{
|
||||
testIntegers<int>(r);
|
||||
}
|
||||
SUBCASE("unsigned int")
|
||||
{
|
||||
testIntegers<unsigned int>(r);
|
||||
}
|
||||
SUBCASE("short")
|
||||
{
|
||||
testIntegers<short>(r);
|
||||
}
|
||||
SUBCASE("unsigned short")
|
||||
{
|
||||
testIntegers<unsigned short>(r);
|
||||
}
|
||||
SUBCASE("int32_t")
|
||||
{
|
||||
testIntegers<std::int32_t>(r);
|
||||
}
|
||||
SUBCASE("uint32_t")
|
||||
{
|
||||
testIntegers<std::uint32_t>(r);
|
||||
}
|
||||
SUBCASE("int64_t")
|
||||
{
|
||||
testIntegers<std::int64_t>(r);
|
||||
}
|
||||
SUBCASE("uint64_t")
|
||||
{
|
||||
testIntegers<std::uint64_t>(r);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("pathologies")
|
||||
{
|
||||
CHECK_THROWS_AS(
|
||||
lexicalCastThrow<int>("\xef\xbc\x91\xef\xbc\x90"), BadLexicalCast);
|
||||
}
|
||||
|
||||
TEST_CASE("conversion overflows")
|
||||
{
|
||||
tryBadConvert<std::uint64_t>("99999999999999999999");
|
||||
tryBadConvert<std::uint32_t>("4294967300");
|
||||
tryBadConvert<std::uint16_t>("75821");
|
||||
}
|
||||
|
||||
TEST_CASE("conversion underflows")
|
||||
{
|
||||
tryBadConvert<std::uint32_t>("-1");
|
||||
|
||||
tryBadConvert<std::int64_t>("-99999999999999999999");
|
||||
tryBadConvert<std::int32_t>("-4294967300");
|
||||
tryBadConvert<std::int16_t>("-75821");
|
||||
}
|
||||
|
||||
TEST_CASE("conversion edge cases")
|
||||
{
|
||||
CHECK(tryEdgeCase<std::uint64_t>("18446744073709551614"));
|
||||
CHECK(tryEdgeCase<std::uint64_t>("18446744073709551615"));
|
||||
CHECK_FALSE(tryEdgeCase<std::uint64_t>("18446744073709551616"));
|
||||
|
||||
CHECK(tryEdgeCase<std::int64_t>("9223372036854775806"));
|
||||
CHECK(tryEdgeCase<std::int64_t>("9223372036854775807"));
|
||||
CHECK_FALSE(tryEdgeCase<std::int64_t>("9223372036854775808"));
|
||||
|
||||
CHECK(tryEdgeCase<std::int64_t>("-9223372036854775807"));
|
||||
CHECK(tryEdgeCase<std::int64_t>("-9223372036854775808"));
|
||||
CHECK_FALSE(tryEdgeCase<std::int64_t>("-9223372036854775809"));
|
||||
|
||||
CHECK(tryEdgeCase<std::uint32_t>("4294967294"));
|
||||
CHECK(tryEdgeCase<std::uint32_t>("4294967295"));
|
||||
CHECK_FALSE(tryEdgeCase<std::uint32_t>("4294967296"));
|
||||
|
||||
CHECK(tryEdgeCase<std::int32_t>("2147483646"));
|
||||
CHECK(tryEdgeCase<std::int32_t>("2147483647"));
|
||||
CHECK_FALSE(tryEdgeCase<std::int32_t>("2147483648"));
|
||||
|
||||
CHECK(tryEdgeCase<std::int32_t>("-2147483647"));
|
||||
CHECK(tryEdgeCase<std::int32_t>("-2147483648"));
|
||||
CHECK_FALSE(tryEdgeCase<std::int32_t>("-2147483649"));
|
||||
|
||||
CHECK(tryEdgeCase<std::uint16_t>("65534"));
|
||||
CHECK(tryEdgeCase<std::uint16_t>("65535"));
|
||||
CHECK_FALSE(tryEdgeCase<std::uint16_t>("65536"));
|
||||
|
||||
CHECK(tryEdgeCase<std::int16_t>("32766"));
|
||||
CHECK(tryEdgeCase<std::int16_t>("32767"));
|
||||
CHECK_FALSE(tryEdgeCase<std::int16_t>("32768"));
|
||||
|
||||
CHECK(tryEdgeCase<std::int16_t>("-32767"));
|
||||
CHECK(tryEdgeCase<std::int16_t>("-32768"));
|
||||
CHECK_FALSE(tryEdgeCase<std::int16_t>("-32769"));
|
||||
}
|
||||
|
||||
TEST_CASE("throwing conversion")
|
||||
{
|
||||
testThrowConvert<std::uint64_t>("99999999999999999999", false);
|
||||
testThrowConvert<std::uint64_t>("9223372036854775806", true);
|
||||
|
||||
testThrowConvert<std::uint32_t>("4294967290", true);
|
||||
testThrowConvert<std::uint32_t>("42949672900", false);
|
||||
testThrowConvert<std::uint32_t>("429496729000", false);
|
||||
testThrowConvert<std::uint32_t>("4294967290000", false);
|
||||
|
||||
testThrowConvert<std::int32_t>("5294967295", false);
|
||||
testThrowConvert<std::int32_t>("-2147483644", true);
|
||||
|
||||
testThrowConvert<std::int16_t>("66666", false);
|
||||
testThrowConvert<std::int16_t>("-5711", true);
|
||||
}
|
||||
|
||||
TEST_CASE("zero conversion")
|
||||
{
|
||||
SUBCASE("signed")
|
||||
{
|
||||
std::int32_t out;
|
||||
|
||||
CHECK(lexicalCastChecked(out, "-0"));
|
||||
CHECK(lexicalCastChecked(out, "0"));
|
||||
CHECK(lexicalCastChecked(out, "+0"));
|
||||
}
|
||||
|
||||
SUBCASE("unsigned")
|
||||
{
|
||||
std::uint32_t out;
|
||||
|
||||
CHECK_FALSE(lexicalCastChecked(out, "-0"));
|
||||
CHECK(lexicalCastChecked(out, "0"));
|
||||
CHECK(lexicalCastChecked(out, "+0"));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("entire range")
|
||||
{
|
||||
std::int32_t i = std::numeric_limits<std::int16_t>::min();
|
||||
std::string const empty("");
|
||||
|
||||
while (i <= std::numeric_limits<std::int16_t>::max())
|
||||
{
|
||||
std::int16_t j = static_cast<std::int16_t>(i);
|
||||
|
||||
auto actual = std::to_string(j);
|
||||
|
||||
auto result = lexicalCast(j, empty);
|
||||
|
||||
CHECK(result == actual);
|
||||
|
||||
if (result == actual)
|
||||
{
|
||||
auto number = lexicalCast<std::int16_t>(result);
|
||||
CHECK(number == j);
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
@@ -1,216 +0,0 @@
|
||||
#include <xrpl/beast/utility/PropertyStream.h>
|
||||
|
||||
#include <doctest/doctest.h>
|
||||
|
||||
using namespace beast;
|
||||
using Source = PropertyStream::Source;
|
||||
|
||||
TEST_SUITE_BEGIN("PropertyStream");
|
||||
|
||||
namespace {
|
||||
|
||||
void
|
||||
test_peel_name(
|
||||
std::string s,
|
||||
std::string const& expected,
|
||||
std::string const& expected_remainder)
|
||||
{
|
||||
std::string const peeled_name = Source::peel_name(&s);
|
||||
CHECK(peeled_name == expected);
|
||||
CHECK(s == expected_remainder);
|
||||
}
|
||||
|
||||
void
|
||||
test_peel_leading_slash(
|
||||
std::string s,
|
||||
std::string const& expected,
|
||||
bool should_be_found)
|
||||
{
|
||||
bool const found(Source::peel_leading_slash(&s));
|
||||
CHECK(found == should_be_found);
|
||||
CHECK(s == expected);
|
||||
}
|
||||
|
||||
void
|
||||
test_peel_trailing_slashstar(
|
||||
std::string s,
|
||||
std::string const& expected_remainder,
|
||||
bool should_be_found)
|
||||
{
|
||||
bool const found(Source::peel_trailing_slashstar(&s));
|
||||
CHECK(found == should_be_found);
|
||||
CHECK(s == expected_remainder);
|
||||
}
|
||||
|
||||
void
|
||||
test_find_one(Source& root, Source* expected, std::string const& name)
|
||||
{
|
||||
Source* source(root.find_one(name));
|
||||
CHECK(source == expected);
|
||||
}
|
||||
|
||||
void
|
||||
test_find_path(Source& root, std::string const& path, Source* expected)
|
||||
{
|
||||
Source* source(root.find_path(path));
|
||||
CHECK(source == expected);
|
||||
}
|
||||
|
||||
void
|
||||
test_find_one_deep(Source& root, std::string const& name, Source* expected)
|
||||
{
|
||||
Source* source(root.find_one_deep(name));
|
||||
CHECK(source == expected);
|
||||
}
|
||||
|
||||
void
|
||||
test_find(Source& root, std::string path, Source* expected, bool expected_star)
|
||||
{
|
||||
auto const result(root.find(path));
|
||||
CHECK(result.first == expected);
|
||||
CHECK(result.second == expected_star);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("peel_name")
|
||||
{
|
||||
test_peel_name("a", "a", "");
|
||||
test_peel_name("foo/bar", "foo", "bar");
|
||||
test_peel_name("foo/goo/bar", "foo", "goo/bar");
|
||||
test_peel_name("", "", "");
|
||||
}
|
||||
|
||||
TEST_CASE("peel_leading_slash")
|
||||
{
|
||||
test_peel_leading_slash("foo/", "foo/", false);
|
||||
test_peel_leading_slash("foo", "foo", false);
|
||||
test_peel_leading_slash("/foo/", "foo/", true);
|
||||
test_peel_leading_slash("/foo", "foo", true);
|
||||
}
|
||||
|
||||
TEST_CASE("peel_trailing_slashstar")
|
||||
{
|
||||
test_peel_trailing_slashstar("/foo/goo/*", "/foo/goo", true);
|
||||
test_peel_trailing_slashstar("foo/goo/*", "foo/goo", true);
|
||||
test_peel_trailing_slashstar("/foo/goo/", "/foo/goo", false);
|
||||
test_peel_trailing_slashstar("foo/goo", "foo/goo", false);
|
||||
test_peel_trailing_slashstar("", "", false);
|
||||
test_peel_trailing_slashstar("/", "", false);
|
||||
test_peel_trailing_slashstar("/*", "", true);
|
||||
test_peel_trailing_slashstar("//", "/", false);
|
||||
test_peel_trailing_slashstar("**", "*", true);
|
||||
test_peel_trailing_slashstar("*/", "*", false);
|
||||
}
|
||||
|
||||
TEST_CASE("find_one")
|
||||
{
|
||||
Source a("a");
|
||||
Source b("b");
|
||||
Source c("c");
|
||||
Source d("d");
|
||||
Source e("e");
|
||||
Source f("f");
|
||||
Source g("g");
|
||||
|
||||
// a { b { d { f }, e }, c { g } }
|
||||
a.add(b);
|
||||
a.add(c);
|
||||
c.add(g);
|
||||
b.add(d);
|
||||
b.add(e);
|
||||
d.add(f);
|
||||
|
||||
test_find_one(a, &b, "b");
|
||||
test_find_one(a, nullptr, "d");
|
||||
test_find_one(b, &e, "e");
|
||||
test_find_one(d, &f, "f");
|
||||
}
|
||||
|
||||
TEST_CASE("find_path")
|
||||
{
|
||||
Source a("a");
|
||||
Source b("b");
|
||||
Source c("c");
|
||||
Source d("d");
|
||||
Source e("e");
|
||||
Source f("f");
|
||||
Source g("g");
|
||||
|
||||
a.add(b);
|
||||
a.add(c);
|
||||
c.add(g);
|
||||
b.add(d);
|
||||
b.add(e);
|
||||
d.add(f);
|
||||
|
||||
test_find_path(a, "a", nullptr);
|
||||
test_find_path(a, "e", nullptr);
|
||||
test_find_path(a, "a/b", nullptr);
|
||||
test_find_path(a, "a/b/e", nullptr);
|
||||
test_find_path(a, "b/e/g", nullptr);
|
||||
test_find_path(a, "b/e/f", nullptr);
|
||||
test_find_path(a, "b", &b);
|
||||
test_find_path(a, "b/e", &e);
|
||||
test_find_path(a, "b/d/f", &f);
|
||||
}
|
||||
|
||||
TEST_CASE("find_one_deep")
|
||||
{
|
||||
Source a("a");
|
||||
Source b("b");
|
||||
Source c("c");
|
||||
Source d("d");
|
||||
Source e("e");
|
||||
Source f("f");
|
||||
Source g("g");
|
||||
|
||||
a.add(b);
|
||||
a.add(c);
|
||||
c.add(g);
|
||||
b.add(d);
|
||||
b.add(e);
|
||||
d.add(f);
|
||||
|
||||
test_find_one_deep(a, "z", nullptr);
|
||||
test_find_one_deep(a, "g", &g);
|
||||
test_find_one_deep(a, "b", &b);
|
||||
test_find_one_deep(a, "d", &d);
|
||||
test_find_one_deep(a, "f", &f);
|
||||
}
|
||||
|
||||
TEST_CASE("find")
|
||||
{
|
||||
Source a("a");
|
||||
Source b("b");
|
||||
Source c("c");
|
||||
Source d("d");
|
||||
Source e("e");
|
||||
Source f("f");
|
||||
Source g("g");
|
||||
|
||||
a.add(b);
|
||||
a.add(c);
|
||||
c.add(g);
|
||||
b.add(d);
|
||||
b.add(e);
|
||||
d.add(f);
|
||||
|
||||
test_find(a, "", &a, false);
|
||||
test_find(a, "*", &a, true);
|
||||
test_find(a, "/b", &b, false);
|
||||
test_find(a, "b", &b, false);
|
||||
test_find(a, "d", &d, false);
|
||||
test_find(a, "/b*", &b, true);
|
||||
test_find(a, "b*", &b, true);
|
||||
test_find(a, "d*", &d, true);
|
||||
test_find(a, "/b/*", &b, true);
|
||||
test_find(a, "b/*", &b, true);
|
||||
test_find(a, "d/*", &d, true);
|
||||
test_find(a, "a", nullptr, false);
|
||||
test_find(a, "/d", nullptr, false);
|
||||
test_find(a, "/d*", nullptr, true);
|
||||
test_find(a, "/d/*", nullptr, true);
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
@@ -1,248 +0,0 @@
|
||||
#include <xrpl/beast/core/SemanticVersion.h>
|
||||
|
||||
#include <doctest/doctest.h>
|
||||
|
||||
using namespace beast;
|
||||
|
||||
TEST_SUITE_BEGIN("SemanticVersion");
|
||||
|
||||
using identifier_list = SemanticVersion::identifier_list;
|
||||
|
||||
namespace {
|
||||
|
||||
void
|
||||
checkPass(std::string const& input, bool shouldPass = true)
|
||||
{
|
||||
SemanticVersion v;
|
||||
|
||||
if (shouldPass)
|
||||
{
|
||||
CHECK(v.parse(input));
|
||||
CHECK(v.print() == input);
|
||||
}
|
||||
else
|
||||
{
|
||||
CHECK_FALSE(v.parse(input));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
checkFail(std::string const& input)
|
||||
{
|
||||
checkPass(input, false);
|
||||
}
|
||||
|
||||
// check input and input with appended metadata
|
||||
void
|
||||
checkMeta(std::string const& input, bool shouldPass)
|
||||
{
|
||||
checkPass(input, shouldPass);
|
||||
|
||||
checkPass(input + "+a", shouldPass);
|
||||
checkPass(input + "+1", shouldPass);
|
||||
checkPass(input + "+a.b", shouldPass);
|
||||
checkPass(input + "+ab.cd", shouldPass);
|
||||
|
||||
checkFail(input + "!");
|
||||
checkFail(input + "+");
|
||||
checkFail(input + "++");
|
||||
checkFail(input + "+!");
|
||||
checkFail(input + "+.");
|
||||
checkFail(input + "+a.!");
|
||||
}
|
||||
|
||||
void
|
||||
checkMetaFail(std::string const& input)
|
||||
{
|
||||
checkMeta(input, false);
|
||||
}
|
||||
|
||||
// check input, input with appended release data,
|
||||
// input with appended metadata, and input with both
|
||||
// appended release data and appended metadata
|
||||
void
|
||||
checkRelease(std::string const& input, bool shouldPass = true)
|
||||
{
|
||||
checkMeta(input, shouldPass);
|
||||
|
||||
checkMeta(input + "-1", shouldPass);
|
||||
checkMeta(input + "-a", shouldPass);
|
||||
checkMeta(input + "-a1", shouldPass);
|
||||
checkMeta(input + "-a1.b1", shouldPass);
|
||||
checkMeta(input + "-ab.cd", shouldPass);
|
||||
checkMeta(input + "--", shouldPass);
|
||||
|
||||
checkMetaFail(input + "+");
|
||||
checkMetaFail(input + "!");
|
||||
checkMetaFail(input + "-");
|
||||
checkMetaFail(input + "-!");
|
||||
checkMetaFail(input + "-.");
|
||||
checkMetaFail(input + "-a.!");
|
||||
checkMetaFail(input + "-0.a");
|
||||
}
|
||||
|
||||
// Checks the major.minor.version string alone and with all
|
||||
// possible combinations of release identifiers and metadata.
|
||||
void
|
||||
check(std::string const& input, bool shouldPass = true)
|
||||
{
|
||||
checkRelease(input, shouldPass);
|
||||
}
|
||||
|
||||
void
|
||||
negcheck(std::string const& input)
|
||||
{
|
||||
check(input, false);
|
||||
}
|
||||
|
||||
identifier_list
|
||||
ids()
|
||||
{
|
||||
return identifier_list();
|
||||
}
|
||||
|
||||
identifier_list
|
||||
ids(std::string const& s1)
|
||||
{
|
||||
identifier_list v;
|
||||
v.push_back(s1);
|
||||
return v;
|
||||
}
|
||||
|
||||
identifier_list
|
||||
ids(std::string const& s1, std::string const& s2)
|
||||
{
|
||||
identifier_list v;
|
||||
v.push_back(s1);
|
||||
v.push_back(s2);
|
||||
return v;
|
||||
}
|
||||
|
||||
identifier_list
|
||||
ids(std::string const& s1, std::string const& s2, std::string const& s3)
|
||||
{
|
||||
identifier_list v;
|
||||
v.push_back(s1);
|
||||
v.push_back(s2);
|
||||
v.push_back(s3);
|
||||
return v;
|
||||
}
|
||||
|
||||
// Checks the decomposition of the input into appropriate values
|
||||
void
|
||||
checkValues(
|
||||
std::string const& input,
|
||||
int majorVersion,
|
||||
int minorVersion,
|
||||
int patchVersion,
|
||||
identifier_list const& preReleaseIdentifiers = identifier_list(),
|
||||
identifier_list const& metaData = identifier_list())
|
||||
{
|
||||
SemanticVersion v;
|
||||
|
||||
CHECK(v.parse(input));
|
||||
|
||||
CHECK(v.majorVersion == majorVersion);
|
||||
CHECK(v.minorVersion == minorVersion);
|
||||
CHECK(v.patchVersion == patchVersion);
|
||||
|
||||
CHECK(v.preReleaseIdentifiers == preReleaseIdentifiers);
|
||||
CHECK(v.metaData == metaData);
|
||||
}
|
||||
|
||||
// makes sure the left version is less than the right
|
||||
void
|
||||
checkLessInternal(std::string const& lhs, std::string const& rhs)
|
||||
{
|
||||
SemanticVersion left;
|
||||
SemanticVersion right;
|
||||
|
||||
CHECK(left.parse(lhs));
|
||||
CHECK(right.parse(rhs));
|
||||
|
||||
CHECK(compare(left, left) == 0);
|
||||
CHECK(compare(right, right) == 0);
|
||||
CHECK(compare(left, right) < 0);
|
||||
CHECK(compare(right, left) > 0);
|
||||
|
||||
CHECK(left < right);
|
||||
CHECK(right > left);
|
||||
CHECK(left == left);
|
||||
CHECK(right == right);
|
||||
}
|
||||
|
||||
void
|
||||
checkLess(std::string const& lhs, std::string const& rhs)
|
||||
{
|
||||
checkLessInternal(lhs, rhs);
|
||||
checkLessInternal(lhs + "+meta", rhs);
|
||||
checkLessInternal(lhs, rhs + "+meta");
|
||||
checkLessInternal(lhs + "+meta", rhs + "+meta");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("parsing")
|
||||
{
|
||||
check("0.0.0");
|
||||
check("1.2.3");
|
||||
check("2147483647.2147483647.2147483647"); // max int
|
||||
|
||||
// negative values
|
||||
negcheck("-1.2.3");
|
||||
negcheck("1.-2.3");
|
||||
negcheck("1.2.-3");
|
||||
|
||||
// missing parts
|
||||
negcheck("");
|
||||
negcheck("1");
|
||||
negcheck("1.");
|
||||
negcheck("1.2");
|
||||
negcheck("1.2.");
|
||||
negcheck(".2.3");
|
||||
|
||||
// whitespace
|
||||
negcheck(" 1.2.3");
|
||||
negcheck("1 .2.3");
|
||||
negcheck("1.2 .3");
|
||||
negcheck("1.2.3 ");
|
||||
|
||||
// leading zeroes
|
||||
negcheck("01.2.3");
|
||||
negcheck("1.02.3");
|
||||
negcheck("1.2.03");
|
||||
}
|
||||
|
||||
TEST_CASE("values")
|
||||
{
|
||||
checkValues("0.1.2", 0, 1, 2);
|
||||
checkValues("1.2.3", 1, 2, 3);
|
||||
checkValues("1.2.3-rc1", 1, 2, 3, ids("rc1"));
|
||||
checkValues("1.2.3-rc1.debug", 1, 2, 3, ids("rc1", "debug"));
|
||||
checkValues("1.2.3-rc1.debug.asm", 1, 2, 3, ids("rc1", "debug", "asm"));
|
||||
checkValues("1.2.3+full", 1, 2, 3, ids(), ids("full"));
|
||||
checkValues("1.2.3+full.prod", 1, 2, 3, ids(), ids("full", "prod"));
|
||||
checkValues(
|
||||
"1.2.3+full.prod.x86", 1, 2, 3, ids(), ids("full", "prod", "x86"));
|
||||
checkValues(
|
||||
"1.2.3-rc1.debug.asm+full.prod.x86",
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
ids("rc1", "debug", "asm"),
|
||||
ids("full", "prod", "x86"));
|
||||
}
|
||||
|
||||
TEST_CASE("comparisons")
|
||||
{
|
||||
checkLess("1.0.0-alpha", "1.0.0-alpha.1");
|
||||
checkLess("1.0.0-alpha.1", "1.0.0-alpha.beta");
|
||||
checkLess("1.0.0-alpha.beta", "1.0.0-beta");
|
||||
checkLess("1.0.0-beta", "1.0.0-beta.2");
|
||||
checkLess("1.0.0-beta.2", "1.0.0-beta.11");
|
||||
checkLess("1.0.0-beta.11", "1.0.0-rc.1");
|
||||
checkLess("1.0.0-rc.1", "1.0.0");
|
||||
checkLess("0.9.9", "1.0.0");
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user