mirror of
https://github.com/Xahau/xahaud.git
synced 2026-10-26 21:57:12 +00:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
68387927e0 | ||
|
|
aab273c575 |
No files matched your search
@@ -19,15 +19,6 @@ coverage:
|
||||
default:
|
||||
target: auto
|
||||
threshold: 2%
|
||||
paths:
|
||||
# PeerImp is historically hard to exercise in the current unit-test
|
||||
# harness. Keep this list narrow; new testable code should remain
|
||||
# covered by the default patch gate.
|
||||
- "!src/xrpld/overlay/detail/PeerImp.cpp"
|
||||
historically-untested:
|
||||
target: 0%
|
||||
paths:
|
||||
- "src/xrpld/overlay/detail/PeerImp.cpp"
|
||||
changes: false
|
||||
|
||||
github_checks:
|
||||
|
||||
@@ -50,10 +50,6 @@ inputs:
|
||||
options:
|
||||
- libstdcxx
|
||||
- libcxx
|
||||
conan_deps_cxxflags:
|
||||
description: 'Extra cxxflags applied to Conan dependency package builds only (NOT the rippled build). JSON object keyed by Conan package pattern, e.g. {"grpc/*":["-Wno-foo"]}. Maps to <pattern>:tools.build:cxxflags.'
|
||||
required: false
|
||||
default: '{}'
|
||||
|
||||
outputs:
|
||||
cache-hit:
|
||||
@@ -85,8 +81,6 @@ runs:
|
||||
|
||||
- name: Configure Conan
|
||||
shell: bash
|
||||
env:
|
||||
CONAN_DEPS_CXXFLAGS: ${{ inputs.conan_deps_cxxflags }}
|
||||
run: |
|
||||
# Create the default profile directory if it doesn't exist
|
||||
mkdir -p ~/.conan2/profiles
|
||||
@@ -111,14 +105,7 @@ runs:
|
||||
os=${{ inputs.os }}
|
||||
EOF
|
||||
|
||||
# [buildenv] + [conf] sections.
|
||||
# Linux pins compiler executables; macOS uses the system toolchain.
|
||||
# conan_deps_cxxflags (matrix-driven) optionally adds package-pattern
|
||||
# scoped tools.build:cxxflags for Conan dependency builds only - typically
|
||||
# grpc workarounds for newer clang's stricter diagnostics. Because these
|
||||
# are profile-pattern scoped (e.g. grpc/*:...), they do NOT affect the
|
||||
# consumer/rippled toolchain generated for the main build.
|
||||
NEED_CONF=0
|
||||
# Add buildenv and conf sections for Linux (not needed for macOS)
|
||||
if [ "${{ inputs.os }}" = "Linux" ] && [ -n "${{ inputs.cc }}" ]; then
|
||||
cat >> ~/.conan2/profiles/default <<EOF
|
||||
|
||||
@@ -129,38 +116,16 @@ runs:
|
||||
[conf]
|
||||
tools.build:compiler_executables={"c": "/usr/bin/${{ inputs.cc }}", "cpp": "/usr/bin/${{ inputs.cxx }}"}
|
||||
EOF
|
||||
NEED_CONF=1
|
||||
fi
|
||||
|
||||
if [ -n "${CONAN_DEPS_CXXFLAGS}" ] && [ "${CONAN_DEPS_CXXFLAGS}" != "{}" ]; then
|
||||
CONAN_DEPS_CXXFLAGS_LINES="$(python3 - <<'PY'
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
# Add macOS-specific conf if needed
|
||||
if [ "${{ inputs.os }}" = "Macos" ]; then
|
||||
cat >> ~/.conan2/profiles/default <<EOF
|
||||
|
||||
raw = os.environ["CONAN_DEPS_CXXFLAGS"]
|
||||
data = json.loads(raw)
|
||||
if not isinstance(data, dict):
|
||||
sys.exit("conan_deps_cxxflags must be a JSON object like {\"grpc/*\": [\"-Wno-...\"]}")
|
||||
|
||||
for pattern, flags in data.items():
|
||||
if not isinstance(pattern, str) or not pattern:
|
||||
sys.exit("conan_deps_cxxflags keys must be non-empty Conan package patterns")
|
||||
if pattern == "&":
|
||||
sys.exit("conan_deps_cxxflags must target dependency package patterns, not the consumer (&)")
|
||||
if not isinstance(flags, list) or not all(isinstance(flag, str) for flag in flags):
|
||||
sys.exit(f"{pattern}: cxxflags must be a JSON string list")
|
||||
if flags:
|
||||
print(f"{pattern}:tools.build:cxxflags={json.dumps(flags, separators=(',', ':'))}")
|
||||
PY
|
||||
)"
|
||||
if [ -n "${CONAN_DEPS_CXXFLAGS_LINES}" ] && [ "$NEED_CONF" = "0" ]; then
|
||||
echo "" >> ~/.conan2/profiles/default
|
||||
echo "[conf]" >> ~/.conan2/profiles/default
|
||||
fi
|
||||
if [ -n "${CONAN_DEPS_CXXFLAGS_LINES}" ]; then
|
||||
printf '%s\n' "${CONAN_DEPS_CXXFLAGS_LINES}" >> ~/.conan2/profiles/default
|
||||
fi
|
||||
[conf]
|
||||
# Workaround for gRPC with newer Apple Clang
|
||||
tools.build:cxxflags=["-Wno-missing-template-arg-list-after-template-kw"]
|
||||
EOF
|
||||
fi
|
||||
|
||||
# Display profile for verification
|
||||
|
||||
@@ -107,9 +107,6 @@ jobs:
|
||||
compiler: apple-clang
|
||||
compiler_version: ${{ steps.detect-compiler.outputs.compiler_version }}
|
||||
stdlib: libcxx
|
||||
# grpc 1.50.1 trips clang-19+ -Werror=missing-template-arg-list-after-template-kw
|
||||
# on Apple Clang. Drop when grpc is bumped past the fix.
|
||||
conan_deps_cxxflags: '{"grpc/*":["-Wno-missing-template-arg-list-after-template-kw"]}'
|
||||
|
||||
- name: Build
|
||||
uses: ./.github/actions/xahau-ga-build
|
||||
|
||||
@@ -72,26 +72,15 @@ jobs:
|
||||
"job_type": "build"
|
||||
},
|
||||
{
|
||||
# Latest stable Clang for the most accurate source-based
|
||||
# coverage mapping (newer language features, fewer bugs in
|
||||
# llvm-cov region inference). Pulled from apt.llvm.org since
|
||||
# Ubuntu 24.04 default repos cap at clang-18.
|
||||
"compiler_id": "clang-20-libcxx",
|
||||
"compiler": "clang",
|
||||
"cc": "clang-20",
|
||||
"cxx": "clang++-20",
|
||||
"compiler_version": 20,
|
||||
"stdlib": "libcxx",
|
||||
"compiler_id": "gcc-13-libstdcxx",
|
||||
"compiler": "gcc",
|
||||
"cc": "gcc-13",
|
||||
"cxx": "g++-13",
|
||||
"gcov": "gcov-13",
|
||||
"compiler_version": 13,
|
||||
"stdlib": "default",
|
||||
"configuration": "Debug",
|
||||
"job_type": "coverage",
|
||||
"coverage_tool": "llvm",
|
||||
"coverage_format": "lcov",
|
||||
# grpc 1.50.1 uses `Foo::template Bar(...)` without an
|
||||
# angle-bracket arg list; clang-19+ promoted that to
|
||||
# -Werror. Drop when grpc is bumped past the fix.
|
||||
"conan_deps_cxxflags": {
|
||||
"grpc/*": ["-Wno-missing-template-arg-list-after-template-kw"]
|
||||
}
|
||||
"job_type": "coverage"
|
||||
},
|
||||
{
|
||||
"compiler_id": "clang-14-libstdcxx-gcc11",
|
||||
@@ -142,7 +131,7 @@ jobs:
|
||||
# Minimal matrix for PRs and feature branches
|
||||
minimal_matrix = [
|
||||
full_matrix[1], # gcc-13 (middle-ground gcc)
|
||||
full_matrix[2], # clang-20 llvm-cov coverage
|
||||
full_matrix[2], # gcc-13 coverage
|
||||
full_matrix[3] # clang-14 (mature, stable clang)
|
||||
]
|
||||
|
||||
@@ -218,9 +207,9 @@ jobs:
|
||||
# Select the appropriate matrix
|
||||
if use_full:
|
||||
if force_full:
|
||||
print(f"Using FULL matrix (7 configs (build x6 + clang-20 llvm-cov coverage)) - forced by [ci-nix-full-matrix] tag")
|
||||
print(f"Using FULL matrix (7 configs) - forced by [ci-nix-full-matrix] tag")
|
||||
else:
|
||||
print(f"Using FULL matrix (7 configs (build x6 + clang-20 llvm-cov coverage)) - targeting main branch")
|
||||
print(f"Using FULL matrix (7 configs) - targeting main branch")
|
||||
matrix = full_matrix
|
||||
else:
|
||||
print(f"Using MINIMAL matrix (3 configs) - feature branch/PR")
|
||||
@@ -268,25 +257,9 @@ jobs:
|
||||
|
||||
- name: Install build dependencies
|
||||
run: |
|
||||
# Bump apt's default 3 retries; papers over short upstream blips
|
||||
# like the recurring ppa.launchpadcontent.net outages.
|
||||
echo 'Acquire::Retries "5";' > /etc/apt/apt.conf.d/80-retries
|
||||
apt-get update
|
||||
apt-get install -y software-properties-common
|
||||
add-apt-repository ppa:ubuntu-toolchain-r/test -y
|
||||
|
||||
# apt.llvm.org for Clang versions newer than what Ubuntu 24.04 ships
|
||||
# (24.04 default repos cap at clang-18). The bootstrap script adds
|
||||
# the LLVM apt source for the requested version and runs apt-get update.
|
||||
if [ "${{ matrix.compiler }}" = "clang" ] && [ "${{ matrix.compiler_version }}" -ge 19 ]; then
|
||||
apt-get install -y wget gnupg lsb-release
|
||||
wget -qO /tmp/llvm.sh https://apt.llvm.org/llvm.sh
|
||||
chmod +x /tmp/llvm.sh
|
||||
# `all` installs clang + libllvm + lldb + lld + the llvm-N package
|
||||
# (which provides llvm-profdata-N / llvm-cov-N for coverage runs).
|
||||
/tmp/llvm.sh ${{ matrix.compiler_version }} all
|
||||
fi
|
||||
|
||||
apt-get update
|
||||
apt-get install -y git python3 python-is-python3 pipx
|
||||
pipx ensurepath
|
||||
@@ -359,16 +332,10 @@ jobs:
|
||||
pipx install "conan>=2.0,<3"
|
||||
echo "$HOME/.local/bin" >> $GITHUB_PATH
|
||||
|
||||
# Install coverage tooling
|
||||
# Install gcovr for coverage jobs
|
||||
if [ "${{ matrix.job_type }}" = "coverage" ]; then
|
||||
pipx install "gcovr>=7,<9"
|
||||
apt-get install -y curl lcov
|
||||
if [ "${{ matrix.coverage_tool }}" = "llvm" ]; then
|
||||
# Native LLVM source-based coverage: llvm-profdata + llvm-cov.
|
||||
# The clang-N package doesn't pull these in; the llvm-N package does.
|
||||
apt-get install -y "llvm-${{ matrix.compiler_version }}"
|
||||
else
|
||||
pipx install "gcovr>=7,<9"
|
||||
fi
|
||||
fi
|
||||
|
||||
- name: Check environment
|
||||
@@ -381,15 +348,10 @@ jobs:
|
||||
which ${{ matrix.cxx }} && ${{ matrix.cxx }} --version || echo "${{ matrix.cxx }} not found"
|
||||
which ccache && ccache --version || echo "ccache not found"
|
||||
|
||||
# Check coverage tooling
|
||||
# Check gcovr for coverage jobs
|
||||
if [ "${{ matrix.job_type }}" = "coverage" ]; then
|
||||
if [ "${{ matrix.coverage_tool }}" = "llvm" ]; then
|
||||
which "llvm-profdata-${{ matrix.compiler_version }}" && "llvm-profdata-${{ matrix.compiler_version }}" --version || echo "llvm-profdata not found"
|
||||
which "llvm-cov-${{ matrix.compiler_version }}" && "llvm-cov-${{ matrix.compiler_version }}" --version || echo "llvm-cov not found"
|
||||
else
|
||||
which gcov && gcov --version || echo "gcov not found"
|
||||
which gcovr && gcovr --version || echo "gcovr not found"
|
||||
fi
|
||||
which gcov && gcov --version || echo "gcov not found"
|
||||
which gcovr && gcovr --version || echo "gcovr not found"
|
||||
fi
|
||||
|
||||
echo "---- Full Environment ----"
|
||||
@@ -416,7 +378,6 @@ jobs:
|
||||
cc: ${{ matrix.cc }}
|
||||
cxx: ${{ matrix.cxx }}
|
||||
stdlib: ${{ matrix.stdlib }}
|
||||
conan_deps_cxxflags: ${{ matrix.conan_deps_cxxflags && toJson(matrix.conan_deps_cxxflags) || '{}' }}
|
||||
gha_cache_enabled: 'false' # Disable caching for self hosted runner
|
||||
|
||||
- name: Build
|
||||
@@ -449,9 +410,8 @@ jobs:
|
||||
cache_version: ${{ env.CACHE_VERSION }}
|
||||
main_branch: ${{ env.MAIN_BRANCH_NAME }}
|
||||
stdlib: ${{ matrix.stdlib }}
|
||||
# Coverage builds are slower due to instrumentation; use fewer parallel jobs to avoid flakiness.
|
||||
# Use *_FLAGS_DEBUG so the build action's stdlib flag (e.g. -stdlib=libc++) in CMAKE_CXX_FLAGS isn't clobbered.
|
||||
cmake-args: '-Dcoverage=ON -Dcoverage_tool=${{ matrix.coverage_tool }} -Dcoverage_format=${{ matrix.coverage_format }} -Dcoverage_test_parallelism=$(($(nproc)/2)) -DCODE_COVERAGE_VERBOSE=ON -DCMAKE_CXX_FLAGS_DEBUG="-g -O0" -DCMAKE_C_FLAGS_DEBUG="-g -O0"'
|
||||
# Coverage builds are slower due to instrumentation; use fewer parallel jobs to avoid flakiness
|
||||
cmake-args: '-Dcoverage=ON -Dcoverage_format=xml -Dcoverage_test_parallelism=$(($(nproc)/2)) -DCODE_COVERAGE_VERBOSE=ON -DCMAKE_CXX_FLAGS="-O0" -DCMAKE_C_FLAGS="-O0"'
|
||||
cmake-target: 'coverage'
|
||||
ccache_max_size: '100G'
|
||||
|
||||
@@ -483,26 +443,22 @@ jobs:
|
||||
- name: Move coverage report
|
||||
if: matrix.job_type == 'coverage'
|
||||
shell: bash
|
||||
env:
|
||||
COVERAGE_FILE: ${{ matrix.coverage_tool == 'llvm' && 'coverage.lcov' || 'coverage.xml' }}
|
||||
run: |
|
||||
mv "${{ env.build_dir }}/${COVERAGE_FILE}" ./
|
||||
echo "COVERAGE_FILE=${COVERAGE_FILE}" >> "$GITHUB_ENV"
|
||||
mv "${{ env.build_dir }}/coverage.xml" ./
|
||||
|
||||
- name: Archive coverage report
|
||||
if: matrix.job_type == 'coverage'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ env.COVERAGE_FILE }}-${{ matrix.compiler_id }}
|
||||
path: ${{ env.COVERAGE_FILE }}
|
||||
name: coverage.xml
|
||||
path: coverage.xml
|
||||
retention-days: 30
|
||||
|
||||
- name: Upload coverage report
|
||||
if: matrix.job_type == 'coverage'
|
||||
uses: codecov/codecov-action@v5
|
||||
with:
|
||||
files: ${{ env.COVERAGE_FILE }}
|
||||
flags: ${{ matrix.coverage_tool }}
|
||||
files: coverage.xml
|
||||
fail_ci_if_error: true
|
||||
disable_search: true
|
||||
verbose: true
|
||||
|
||||
@@ -1,156 +0,0 @@
|
||||
#[===================================================================[
|
||||
Native LLVM source-based code coverage helper.
|
||||
|
||||
Drives the -fprofile-instr-generate / -fcoverage-mapping pipeline:
|
||||
1. Run instrumented binary with LLVM_PROFILE_FILE=...%m-%p.profraw
|
||||
2. llvm-profdata merge -sparse -> coverage.profdata
|
||||
3. llvm-cov export/show/report -> final report
|
||||
|
||||
Output filename per coverage_format:
|
||||
lcov -> coverage.lcov
|
||||
json -> coverage.json
|
||||
txt | text -> coverage.txt
|
||||
html | html-details -> <NAME>/index.html
|
||||
#]===================================================================]
|
||||
|
||||
include(CMakeParseArguments)
|
||||
|
||||
# Locate llvm-profdata / llvm-cov, preferring versioned variants matching the
|
||||
# Clang we're building with so we don't accidentally pair clang-20 with
|
||||
# llvm-cov-14 (profile format mismatch -> hard failure).
|
||||
function(_find_llvm_cov_tools)
|
||||
if(LLVM_PROFDATA_PATH AND LLVM_COV_PATH)
|
||||
return()
|
||||
endif()
|
||||
|
||||
string(REGEX MATCH "^[0-9]+" _major "${CMAKE_CXX_COMPILER_VERSION}")
|
||||
|
||||
set(_pd_names llvm-profdata)
|
||||
set(_cov_names llvm-cov)
|
||||
if(_major)
|
||||
list(PREPEND _pd_names "llvm-profdata-${_major}")
|
||||
list(PREPEND _cov_names "llvm-cov-${_major}")
|
||||
endif()
|
||||
|
||||
# Only delegate to xcrun when the *compiler* is AppleClang. On macOS with
|
||||
# Homebrew/system clang-N, xcrun would resolve to Xcode's llvm tools which
|
||||
# could be a different version - exactly the mismatch we want to avoid.
|
||||
if(APPLE AND CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
|
||||
execute_process(COMMAND xcrun -f llvm-profdata
|
||||
OUTPUT_VARIABLE _pd_xcrun OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
ERROR_QUIET RESULT_VARIABLE _pd_rc)
|
||||
if(_pd_rc EQUAL 0 AND _pd_xcrun)
|
||||
set(LLVM_PROFDATA_PATH "${_pd_xcrun}" CACHE FILEPATH "llvm-profdata" FORCE)
|
||||
endif()
|
||||
execute_process(COMMAND xcrun -f llvm-cov
|
||||
OUTPUT_VARIABLE _cov_xcrun OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
ERROR_QUIET RESULT_VARIABLE _cov_rc)
|
||||
if(_cov_rc EQUAL 0 AND _cov_xcrun)
|
||||
set(LLVM_COV_PATH "${_cov_xcrun}" CACHE FILEPATH "llvm-cov" FORCE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT LLVM_PROFDATA_PATH)
|
||||
find_program(LLVM_PROFDATA_PATH NAMES ${_pd_names})
|
||||
endif()
|
||||
if(NOT LLVM_COV_PATH)
|
||||
find_program(LLVM_COV_PATH NAMES ${_cov_names})
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(setup_target_for_coverage_llvm)
|
||||
set(oneValueArgs NAME FORMAT)
|
||||
set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES)
|
||||
cmake_parse_arguments(Cov "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||
|
||||
_find_llvm_cov_tools()
|
||||
if(NOT LLVM_PROFDATA_PATH)
|
||||
message(FATAL_ERROR "llvm-profdata not found (needed for coverage_tool=llvm)")
|
||||
endif()
|
||||
if(NOT LLVM_COV_PATH)
|
||||
message(FATAL_ERROR "llvm-cov not found (needed for coverage_tool=llvm)")
|
||||
endif()
|
||||
|
||||
if(NOT Cov_FORMAT)
|
||||
set(Cov_FORMAT lcov)
|
||||
endif()
|
||||
|
||||
set(_profraw_dir "${PROJECT_BINARY_DIR}/${Cov_NAME}-profraw")
|
||||
set(_profdata "${PROJECT_BINARY_DIR}/${Cov_NAME}.profdata")
|
||||
|
||||
# Resolve binary path: accept either an absolute path or a bare target name
|
||||
# (resolved against PROJECT_BINARY_DIR). Splice the resolved path back into
|
||||
# Cov_EXECUTABLE so the run command invokes it via absolute path - bare
|
||||
# names aren't on PATH and the build dir isn't `.` either.
|
||||
list(GET Cov_EXECUTABLE 0 _exec_name)
|
||||
if(IS_ABSOLUTE "${_exec_name}")
|
||||
set(_binary "${_exec_name}")
|
||||
else()
|
||||
set(_binary "${PROJECT_BINARY_DIR}/${_exec_name}")
|
||||
list(REMOVE_AT Cov_EXECUTABLE 0)
|
||||
list(PREPEND Cov_EXECUTABLE "${_binary}")
|
||||
endif()
|
||||
|
||||
# llvm-cov takes a single -ignore-filename-regex; OR our excludes together.
|
||||
set(_ignore_regex "")
|
||||
foreach(EXC IN LISTS Cov_EXCLUDE)
|
||||
if(_ignore_regex)
|
||||
string(APPEND _ignore_regex "|")
|
||||
endif()
|
||||
string(APPEND _ignore_regex "${EXC}")
|
||||
endforeach()
|
||||
set(_filter "")
|
||||
if(_ignore_regex)
|
||||
set(_filter "-ignore-filename-regex='${_ignore_regex}'")
|
||||
endif()
|
||||
|
||||
# Pick llvm-cov subcommand + output file for the requested format. Each
|
||||
# branch builds a single shell command string that we'll hand to bash -c.
|
||||
if(Cov_FORMAT STREQUAL "lcov")
|
||||
set(_output "${PROJECT_BINARY_DIR}/coverage.lcov")
|
||||
set(_report_sh "${LLVM_COV_PATH} export -instr-profile='${_profdata}' -format=lcov ${_filter} '${_binary}' > '${_output}'")
|
||||
elseif(Cov_FORMAT STREQUAL "json")
|
||||
set(_output "${PROJECT_BINARY_DIR}/coverage.json")
|
||||
set(_report_sh "${LLVM_COV_PATH} export -instr-profile='${_profdata}' -format=text ${_filter} '${_binary}' > '${_output}'")
|
||||
elseif(Cov_FORMAT STREQUAL "txt" OR Cov_FORMAT STREQUAL "text")
|
||||
set(_output "${PROJECT_BINARY_DIR}/coverage.txt")
|
||||
set(_report_sh "${LLVM_COV_PATH} report -instr-profile='${_profdata}' ${_filter} '${_binary}' > '${_output}'")
|
||||
elseif(Cov_FORMAT STREQUAL "html" OR Cov_FORMAT STREQUAL "html-details")
|
||||
set(_output "${PROJECT_BINARY_DIR}/${Cov_NAME}/index.html")
|
||||
set(_report_sh "${LLVM_COV_PATH} show -instr-profile='${_profdata}' -format=html -output-dir='${PROJECT_BINARY_DIR}/${Cov_NAME}' ${_filter} '${_binary}'")
|
||||
else()
|
||||
message(FATAL_ERROR "coverage_tool=llvm: unsupported coverage_format '${Cov_FORMAT}' (use lcov|json|txt|html)")
|
||||
endif()
|
||||
|
||||
set(_merge_sh "${LLVM_PROFDATA_PATH} merge -sparse -o '${_profdata}' '${_profraw_dir}'/*.profraw")
|
||||
|
||||
if(CODE_COVERAGE_VERBOSE)
|
||||
message(STATUS "[coverage:llvm] binary: ${_binary}")
|
||||
message(STATUS "[coverage:llvm] profraw: ${_profraw_dir}")
|
||||
message(STATUS "[coverage:llvm] profdata: ${_profdata}")
|
||||
message(STATUS "[coverage:llvm] format: ${Cov_FORMAT}")
|
||||
message(STATUS "[coverage:llvm] output: ${_output}")
|
||||
if(_ignore_regex)
|
||||
message(STATUS "[coverage:llvm] ignore: ${_ignore_regex}")
|
||||
endif()
|
||||
message(STATUS "[coverage:llvm] merge: ${_merge_sh}")
|
||||
message(STATUS "[coverage:llvm] report: ${_report_sh}")
|
||||
endif()
|
||||
|
||||
# %m: hash of the binary, %p: pid. Wipe the dir up front so stale profraw
|
||||
# files can't leak into a fresh merge.
|
||||
add_custom_target(${Cov_NAME}
|
||||
COMMAND ${CMAKE_COMMAND} -E rm -rf "${_profraw_dir}"
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory "${_profraw_dir}"
|
||||
COMMAND ${CMAKE_COMMAND} -E env
|
||||
"LLVM_PROFILE_FILE=${_profraw_dir}/rippled-%m-%p.profraw"
|
||||
${Cov_EXECUTABLE} ${Cov_EXECUTABLE_ARGS}
|
||||
COMMAND bash -c "${_merge_sh}"
|
||||
COMMAND bash -c "${_report_sh}"
|
||||
BYPRODUCTS ${_output}
|
||||
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
|
||||
DEPENDS ${Cov_DEPENDENCIES}
|
||||
VERBATIM
|
||||
COMMENT "Running llvm-cov (${Cov_FORMAT}) -> ${_output}"
|
||||
)
|
||||
endfunction()
|
||||
@@ -11,21 +11,6 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(coverage_tool STREQUAL "llvm")
|
||||
include(CodeCoverageLLVM)
|
||||
|
||||
setup_target_for_coverage_llvm(
|
||||
NAME coverage
|
||||
FORMAT ${coverage_format}
|
||||
EXECUTABLE rippled
|
||||
EXECUTABLE_ARGS --unittest$<$<BOOL:${coverage_test}>:=${coverage_test}> --unittest-jobs ${coverage_test_parallelism} --quiet --unittest-log
|
||||
EXCLUDE "src/test" "include/xrpl/beast/test" "include/xrpl/beast/unit_test" "${CMAKE_BINARY_DIR}/pb-xrpl.libpb"
|
||||
DEPENDENCIES rippled
|
||||
)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# coverage_tool == "gcov" (default): existing gcovr-driven pipeline.
|
||||
include(CodeCoverage)
|
||||
|
||||
# The instructions for these commands come from the `CodeCoverage` module,
|
||||
|
||||
@@ -28,17 +28,15 @@ target_compile_options (opts
|
||||
$<$<AND:$<BOOL:${is_gcc}>,$<COMPILE_LANGUAGE:CXX>>:-Wsuggest-override>
|
||||
$<$<BOOL:${is_gcc}>:-Wno-maybe-uninitialized>
|
||||
$<$<BOOL:${perf}>:-fno-omit-frame-pointer>
|
||||
$<$<AND:$<BOOL:${is_gcc}>,$<BOOL:${coverage}>,$<STREQUAL:${coverage_tool},gcov>>:-g --coverage -fprofile-abs-path>
|
||||
$<$<AND:$<BOOL:${is_clang}>,$<BOOL:${coverage}>,$<STREQUAL:${coverage_tool},gcov>>:-g --coverage>
|
||||
$<$<AND:$<BOOL:${is_clang}>,$<BOOL:${coverage}>,$<STREQUAL:${coverage_tool},llvm>>:-g -fprofile-instr-generate -fcoverage-mapping>
|
||||
$<$<AND:$<BOOL:${is_gcc}>,$<BOOL:${coverage}>>:-g --coverage -fprofile-abs-path>
|
||||
$<$<AND:$<BOOL:${is_clang}>,$<BOOL:${coverage}>>:-g --coverage>
|
||||
$<$<BOOL:${profile}>:-pg>
|
||||
$<$<AND:$<BOOL:${is_gcc}>,$<BOOL:${profile}>>:-p>)
|
||||
|
||||
target_link_libraries (opts
|
||||
INTERFACE
|
||||
$<$<AND:$<BOOL:${is_gcc}>,$<BOOL:${coverage}>,$<STREQUAL:${coverage_tool},gcov>>:-g --coverage -fprofile-abs-path>
|
||||
$<$<AND:$<BOOL:${is_clang}>,$<BOOL:${coverage}>,$<STREQUAL:${coverage_tool},gcov>>:-g --coverage>
|
||||
$<$<AND:$<BOOL:${is_clang}>,$<BOOL:${coverage}>,$<STREQUAL:${coverage_tool},llvm>>:-g -fprofile-instr-generate -fcoverage-mapping>
|
||||
$<$<AND:$<BOOL:${is_gcc}>,$<BOOL:${coverage}>>:-g --coverage -fprofile-abs-path>
|
||||
$<$<AND:$<BOOL:${is_clang}>,$<BOOL:${coverage}>>:-g --coverage>
|
||||
$<$<BOOL:${profile}>:-pg>
|
||||
$<$<AND:$<BOOL:${is_gcc}>,$<BOOL:${profile}>>:-p>)
|
||||
|
||||
|
||||
@@ -29,25 +29,13 @@ if(is_gcc OR is_clang)
|
||||
"Unit tests parallelism for the purpose of coverage report.")
|
||||
set(coverage_format "html-details" CACHE STRING
|
||||
"Output format of the coverage report.")
|
||||
set(coverage_tool "gcov" CACHE STRING
|
||||
"Coverage instrumentation tool: 'gcov' (default, gcc/clang via --coverage + gcovr) or 'llvm' (clang only, native source-based coverage via -fprofile-instr-generate).")
|
||||
set_property(CACHE coverage_tool PROPERTY STRINGS "gcov" "llvm")
|
||||
if(NOT coverage_tool MATCHES "^(gcov|llvm)$")
|
||||
message(FATAL_ERROR "coverage_tool must be 'gcov' or 'llvm', got '${coverage_tool}'")
|
||||
endif()
|
||||
set(coverage_extra_args "" CACHE STRING
|
||||
"Additional arguments to pass to gcovr (gcov tool only).")
|
||||
"Additional arguments to pass to gcovr.")
|
||||
set(coverage_test "" CACHE STRING
|
||||
"On gcc & clang, the specific unit test(s) to run for coverage. Default is all tests.")
|
||||
if(coverage_test AND NOT coverage)
|
||||
set(coverage ON CACHE BOOL "gcc/clang only" FORCE)
|
||||
endif()
|
||||
# Validate after coverage_test may have flipped coverage on, otherwise
|
||||
# `-Dcoverage_tool=llvm -Dcoverage_test=Foo` on gcc would silently slip
|
||||
# past the Clang guard and produce a broken instrumentation combo.
|
||||
if(coverage AND coverage_tool STREQUAL "llvm" AND NOT is_clang)
|
||||
message(FATAL_ERROR "coverage_tool=llvm requires Clang (got ${CMAKE_CXX_COMPILER_ID})")
|
||||
endif()
|
||||
option(wextra "compile with extra gcc/clang warnings enabled" ON)
|
||||
else()
|
||||
set(profile OFF CACHE BOOL "gcc/clang only" FORCE)
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
// If you add an amendment here, then do not forget to increment `numFeatures`
|
||||
// in include/xrpl/protocol/Feature.h.
|
||||
|
||||
XRPL_FEATURE(HookOnV2_1, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(OnChainManifests, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (HookMap, Supported::yes, VoteBehavior::DefaultYes)
|
||||
XRPL_FIX (GuardDepth32, Supported::yes, VoteBehavior::DefaultNo)
|
||||
@@ -46,7 +45,7 @@ XRPL_FEATURE(HookAPISerializedType240, Supported::yes, VoteBehavior::DefaultNo
|
||||
XRPL_FEATURE(PermissionedDomains, Supported::no, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(DynamicNFT, Supported::no, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(Credentials, Supported::no, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(AMMClawback, Supported::no, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(AMMClawback, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(MPTokensV1, Supported::no, VoteBehavior::DefaultNo)
|
||||
// InvariantsV1_1 will be changes to Supported::yes when all the
|
||||
// invariants expected to be included under it are complete.
|
||||
@@ -66,8 +65,7 @@ XRPL_FEATURE(XChainBridge, Supported::no, VoteBehavior::DefaultNo
|
||||
XRPL_FEATURE(AMM, Supported::no, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (ReducedOffersV1, Supported::yes, VoteBehavior::DefaultYes)
|
||||
XRPL_FEATURE(HooksUpdate2, Supported::yes, VoteBehavior::DefaultNo)
|
||||
// replaced to HookOnV2_1
|
||||
XRPL_FEATURE(HookOnV2, Supported::no, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(HookOnV2, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (HookAPI20251128, Supported::yes, VoteBehavior::DefaultYes)
|
||||
XRPL_FIX (CronStacking, Supported::yes, VoteBehavior::DefaultYes)
|
||||
XRPL_FEATURE(ExtendedHookState, Supported::yes, VoteBehavior::DefaultNo)
|
||||
|
||||
@@ -292,9 +292,7 @@ JSS(duration_us); // out: NetworkOPs
|
||||
JSS(effective); // out: ValidatorList
|
||||
// in: UNL
|
||||
JSS(elapsed_seconds);
|
||||
JSS(enabled); // out: AmendmentTable (on-ledger);
|
||||
// ServerDefinitions (this server)
|
||||
JSS(ledger_enabled); // out: ServerDefinitions (on-ledger)
|
||||
JSS(enabled); // out: AmendmentTable
|
||||
JSS(engine_result); // out: NetworkOPs, TransactionSign, Submit
|
||||
JSS(engine_result_code); // out: NetworkOPs, TransactionSign, Submit
|
||||
JSS(engine_result_message); // out: NetworkOPs, TransactionSign, Submit
|
||||
|
||||
@@ -150,15 +150,12 @@ private:
|
||||
|
||||
env.fund(XRP(20'000), alice, bob, carol, gw1, gw2);
|
||||
env.fund(XRP(20'000), dan);
|
||||
env.close();
|
||||
env.trust(USD1(20'000), alice, bob, carol, dan);
|
||||
env.trust(USD2(1'000), alice, bob, carol, dan);
|
||||
env.close();
|
||||
|
||||
env(pay(gw1, dan, USD1(10'050)));
|
||||
env(pay(gw1, bob, USD1(50)));
|
||||
env(pay(gw2, bob, USD2(50)));
|
||||
env.close();
|
||||
|
||||
AMM ammDan(env, dan, XRP(10'000), USD1(10'050));
|
||||
|
||||
|
||||
@@ -104,8 +104,8 @@ class LedgerMaster_test : public beast::unit_test::suite
|
||||
startLegSeq, txnIndex);
|
||||
BEAST_EXPECT(
|
||||
*result ==
|
||||
uint256("DCAECE52F028B9D0F7CA43CBE15AB4EF7B84A8EF5D455238992E1E"
|
||||
"DF2BDA1637"));
|
||||
uint256("0CC11AD1AD89661689F6B6148D82CB6A7101DA4D66EC843670262D"
|
||||
"0B618F5745"));
|
||||
}
|
||||
// success (second tx)
|
||||
{
|
||||
@@ -114,8 +114,8 @@ class LedgerMaster_test : public beast::unit_test::suite
|
||||
startLegSeq + 1, txnIndex);
|
||||
BEAST_EXPECT(
|
||||
*result ==
|
||||
uint256("722BD5EC9E4AE36E724B6223F5A5887927AADFD0B18A3053AAE57F"
|
||||
"434F8C9FE8"));
|
||||
uint256("DCAECE52F028B9D0F7CA43CBE15AB4EF7B84A8EF5D455238992E1E"
|
||||
"DF2BDA1637"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1174,11 +1174,11 @@ class MPToken_test : public beast::unit_test::suite
|
||||
JsonOptions::none)[sfAffectedNodes.fieldName];
|
||||
// Issuer got 10 in the transfer fees
|
||||
BEAST_EXPECT(
|
||||
meta[0u][sfModifiedNode.fieldName][sfFinalFields.fieldName]
|
||||
meta[2u][sfModifiedNode.fieldName][sfFinalFields.fieldName]
|
||||
[sfOutstandingAmount.fieldName] == "9990");
|
||||
// Destination account got 9'990
|
||||
BEAST_EXPECT(
|
||||
meta[3u][sfModifiedNode.fieldName][sfFinalFields.fieldName]
|
||||
meta[0u][sfModifiedNode.fieldName][sfFinalFields.fieldName]
|
||||
[sfMPTAmount.fieldName] == "9990");
|
||||
// Source account spent 10'000
|
||||
BEAST_EXPECT(
|
||||
@@ -1910,8 +1910,8 @@ class MPToken_test : public beast::unit_test::suite
|
||||
env.tx()->getJson(JsonOptions::none)[jss::hash].asString()};
|
||||
BEAST_EXPECTS(
|
||||
txHash ==
|
||||
"61041108F0DAD50BAFD2F7B1102AC70B283EBDCED194CEBAF04D0184E4A70B"
|
||||
"02",
|
||||
"42175D43E3D236A86B0F1B07182A1B2C78AD382372CFA09A48239C395FFFEE"
|
||||
"30",
|
||||
txHash);
|
||||
Json::Value const meta = env.rpc("tx", txHash)[jss::result][jss::meta];
|
||||
auto const id = meta[jss::mpt_issuance_id].asString();
|
||||
@@ -1919,7 +1919,7 @@ class MPToken_test : public beast::unit_test::suite
|
||||
BEAST_EXPECT(meta.isMember(jss::mpt_issuance_id));
|
||||
BEAST_EXPECT(id == to_string(mptAlice.issuanceID()));
|
||||
BEAST_EXPECTS(
|
||||
id == "00000002AE123A8556F3CF91154711376AFB0F894F832B3D", id);
|
||||
id == "00000001AE123A8556F3CF91154711376AFB0F894F832B3D", id);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -8279,16 +8279,16 @@ private:
|
||||
|
||||
// validate the emitted txn ids
|
||||
std::vector<std::string> const txIds = {
|
||||
"2FBEF981BAC322225D13C274D0118FECC1B93A89EDBC0AB3CBD8B30A1591024E",
|
||||
"3C0A12F6A322486ABDA4180DC2B424BD252FD2FA6A33553B0B5D1526C020C475",
|
||||
"AFFD55D757136FC0BE665F16E0D8CFBDC0D37CF85B5D3329BE1DBD3A44BB281C",
|
||||
"BBE43C01068CE511DBF24F84A928E481451FF448AF2493E1A9BE099628D1F523",
|
||||
"45970753F7B52448C23D66E5E19DBBC65F5BE6055C04AC3BA9896D7D67891DB1",
|
||||
"97F4E09B2AEF4D798D378B1390B0624A68F304247B358334167E93217D502A16",
|
||||
"770D3B786C8E3BEF560D9589B02557B0BDFC1C7FD15C6CF42E86068A6A411EFC",
|
||||
"239DFA86EE8391418170D7FDF5AA8B8EEE0BBEF5E9F928BC29C23EEF6F1858AD",
|
||||
"9FAA93AC6340C87B5C722FF0E8D4D3F39B9A0CA5E9799EC4CE316BFD5E379540",
|
||||
"8672B2D8AA5E9EF86929B8662FE436541B2F739052732020B874BC304601C4DB",
|
||||
"9610F73CDD6590EB6B3C82E5EC55D4B4C80CD7128B98AA556F7EC9DD96AE7056",
|
||||
"2F4582A29272390C0C25A80D4A3BCE5A14ACE6D86D8D0CB2C57719EB6FA881AE",
|
||||
"89A301CFEF0DD781AB9032A6A2DCE0937BC0119D2CDD06033B8B2FD80968E519",
|
||||
"DD8721B59024E168480B4DF8F8E93778601F0BD2E77FC991F3DA1182F5AD8B1E",
|
||||
"5D735C2EE3CB8289F8E11621FDC9565F9D6D67F3AE59D65332EACE591D67945F",
|
||||
"F02470E01731C968881AF4CBDEC90BB9E1F7AB0BE1CC22AF15451FB6D191096D",
|
||||
"8AD65E541DECD49B1693F8C17DFD8A2B906F49C673C4FD2034FF772E2BE50C30",
|
||||
"9F225229059CCC6257814D03C107884CF588C1C246A89ADFC16E50DF671B834C",
|
||||
"13C2A54A14BADF3648CED05175E1CCAD713F7E5EA56D9735CF8813CD5551F281",
|
||||
"87C60F41A96554587CED289F83F52DEE3CF670EEB189B067E6066B9A06056ADF",
|
||||
};
|
||||
Json::Value params;
|
||||
params[jss::transaction] =
|
||||
|
||||
+29
-342
@@ -1355,16 +1355,11 @@ public:
|
||||
auto const baseFee = drops[jss::base_fee_no_hooks];
|
||||
BEAST_EXPECT(baseFee == to_string(feeDrops));
|
||||
auto const openLedgerFee = drops[jss::open_ledger_fee];
|
||||
BEAST_EXPECTS(
|
||||
openLedgerFee == expected,
|
||||
"openLedgerFee: " + openLedgerFee.asString() +
|
||||
", expected: " + expected);
|
||||
BEAST_EXPECT(openLedgerFee == expected);
|
||||
|
||||
// verify hooks fee
|
||||
auto const hooksFee = jrr[jss::result][jss::fee_hooks_feeunits];
|
||||
BEAST_EXPECTS(
|
||||
hooksFee == expected,
|
||||
"hooksFee: " + hooksFee.asString() + ", expected: " + expected);
|
||||
BEAST_EXPECT(hooksFee == expected);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1374,8 +1369,7 @@ public:
|
||||
using namespace jtx;
|
||||
Env env{*this, features};
|
||||
|
||||
bool const hookOnV2 = env.current()->rules().enabled(featureHookOnV2) ||
|
||||
env.current()->rules().enabled(featureHookOnV2_1);
|
||||
bool const hookOnV2 = env.current()->rules().enabled(featureHookOnV2);
|
||||
|
||||
auto const alice = Account{"alice"};
|
||||
auto const bob = Account{"bob"};
|
||||
@@ -1538,10 +1532,12 @@ public:
|
||||
jv.removeMember(jss::HookOn);
|
||||
jv[jss::HookOnIncoming] =
|
||||
"0000000000000000000000000000000000000000000000000000000000"
|
||||
"000000";
|
||||
"0000"
|
||||
"00";
|
||||
jv[jss::HookOnOutgoing] =
|
||||
"0000000000000000000000000000000000000000000000000000000000"
|
||||
"000001";
|
||||
"0000"
|
||||
"01";
|
||||
env(ripple::test::jtx::hook(alice, {{jv}}, 0),
|
||||
M("Execution: Install"),
|
||||
HSFEE);
|
||||
@@ -1606,10 +1602,12 @@ public:
|
||||
jv.removeMember(jss::HookOn);
|
||||
jv[jss::HookOnIncoming] =
|
||||
"fffffffffffffffffffffffffffffffffffffff7ffffffffffffffffff"
|
||||
"bfffff"; // Invoke high
|
||||
"bfff"
|
||||
"ff"; // Invoke high
|
||||
jv[jss::HookOnOutgoing] =
|
||||
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
|
||||
"bffffe"; // Payment high
|
||||
"bfff"
|
||||
"fe"; // Payment high
|
||||
env(ripple::test::jtx::hook(alice, {{jv}}, 0),
|
||||
M("Execution: Install"),
|
||||
HSFEE);
|
||||
@@ -1620,7 +1618,8 @@ public:
|
||||
jv[jss::Flags] = hsfOVERRIDE;
|
||||
jv[jss::HookOn] =
|
||||
"0000000000000000000000000000000000000000000000000000000000"
|
||||
"000000";
|
||||
"0000"
|
||||
"00";
|
||||
env(ripple::test::jtx::hook(alice, {{jv}}, 0),
|
||||
M("Execution: Install"),
|
||||
HSFEE);
|
||||
@@ -1654,285 +1653,18 @@ public:
|
||||
deleteHook(alice);
|
||||
}
|
||||
|
||||
for (auto const& withFix : {false, true})
|
||||
{
|
||||
// test featureHookOnV2_1 preflight
|
||||
auto f = features - featureHookOnV2 - featureHookOnV2_1;
|
||||
if (withFix)
|
||||
f = f | featureHookOnV2_1;
|
||||
else
|
||||
f = f | featureHookOnV2;
|
||||
Env env{*this, f};
|
||||
|
||||
env.fund(XRP(10000), alice, bob);
|
||||
env.close();
|
||||
|
||||
TER const expected =
|
||||
env.current()->rules().enabled(featureHookOnV2_1)
|
||||
? TER(temMALFORMED)
|
||||
: TER(tesSUCCESS);
|
||||
|
||||
// 0. only one direction HookOn is not allowed
|
||||
for (auto const& key : {jss::HookOnIncoming, jss::HookOnOutgoing})
|
||||
{
|
||||
auto noopJv = Json::Value{};
|
||||
noopJv[key] =
|
||||
"fffffffffffffffffffffffffffffffffffffff7ffffffffffffffffff"
|
||||
"bfffff";
|
||||
|
||||
env(ripple::test::jtx::hook(alice, {{noopJv}}, 0),
|
||||
M("Lone direction HookOn NOOP"),
|
||||
HSFEE,
|
||||
ter(expected));
|
||||
env.close();
|
||||
|
||||
if (!withFix)
|
||||
BEAST_EXPECT(!env.le(keylet::hook(alice)));
|
||||
}
|
||||
|
||||
// 1. Create Hook with HookOnIncoming/Outgoing to alice
|
||||
auto jv = hso(accept_wasm);
|
||||
jv.removeMember(jss::HookOn);
|
||||
jv[jss::HookOnIncoming] =
|
||||
"fffffffffffffffffffffffffffffffffffffff7ffffffffffffffffff"
|
||||
"bfffff"; // Invoke high
|
||||
jv[jss::HookOnOutgoing] =
|
||||
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
|
||||
"bffffe"; // Payment high
|
||||
env(ripple::test::jtx::hook(alice, {{jv}}, 0), HSFEE);
|
||||
env.close();
|
||||
|
||||
// 2. Install Hook with HookOn, Incoming/Outgoing to bob
|
||||
jv = Json::Value{};
|
||||
jv[jss::HookHash] = accept_hash_str;
|
||||
jv[jss::Flags] = hsfOVERRIDE;
|
||||
jv[jss::HookOn] =
|
||||
"0000000000000000000000000000000000000000000000000000000000"
|
||||
"000000";
|
||||
jv[jss::HookOnIncoming] =
|
||||
"fffffffffffffffffffffffffffffffffffffff7ffffffffffffffffff"
|
||||
"bfffff"; // Invoke high
|
||||
jv[jss::HookOnOutgoing] =
|
||||
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
|
||||
"bffffe"; // Payment high
|
||||
env(ripple::test::jtx::hook(bob, {{jv}}, 0), HSFEE, ter(expected));
|
||||
env.close();
|
||||
|
||||
// 3. Update Hook with HookOn, Incoming/Outgoing to alice
|
||||
jv = Json::Value{};
|
||||
jv[jss::HookOn] =
|
||||
"0000000000000000000000000000000000000000000000000000000000"
|
||||
"000000";
|
||||
jv[jss::HookOnIncoming] =
|
||||
"fffffffffffffffffffffffffffffffffffffff7ffffffffffffffffff"
|
||||
"bfffff"; // Invoke high
|
||||
jv[jss::HookOnOutgoing] =
|
||||
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
|
||||
"bffffe"; // Payment high
|
||||
env(ripple::test::jtx::hook(alice, {{jv}}, 0),
|
||||
HSFEE,
|
||||
ter(expected));
|
||||
env.close();
|
||||
}
|
||||
|
||||
for (auto const& withFix : {false, true})
|
||||
{
|
||||
// test featureHookOnV2_1 install/update
|
||||
auto f = features - featureHookOnV2 - featureHookOnV2_1;
|
||||
if (withFix)
|
||||
f = f | featureHookOnV2_1;
|
||||
else
|
||||
f = f | featureHookOnV2;
|
||||
|
||||
{
|
||||
// install:: HookDefinition: HookOn -> Hook:Incoming/Outgoing
|
||||
// update:: Hook: HookOn -> Hook:Incoming/Outgoing
|
||||
Env env{*this, f};
|
||||
|
||||
env.fund(XRP(10000), alice, bob);
|
||||
env.close();
|
||||
|
||||
// Create Hook with HookOn to alice
|
||||
auto jv = hso(accept_wasm);
|
||||
jv.removeMember(jss::HookOn);
|
||||
jv[jss::HookOn] =
|
||||
"0000000000000000000000000000000000000000000000000000000000"
|
||||
"000000";
|
||||
env(ripple::test::jtx::hook(alice, {{jv}}, 0), HSFEE);
|
||||
env.close();
|
||||
|
||||
// Install Hook with Incoming/Outgoing to bob
|
||||
jv = Json::Value{};
|
||||
jv[jss::HookHash] = accept_hash_str;
|
||||
jv[jss::Flags] = hsfOVERRIDE;
|
||||
jv[jss::HookOnIncoming] =
|
||||
"fffffffffffffffffffffffffffffffffffffff7ffffffffffffffffff"
|
||||
"bfffff"; // Invoke high
|
||||
jv[jss::HookOnOutgoing] =
|
||||
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
|
||||
"bffffe"; // Payment high
|
||||
env(ripple::test::jtx::hook(bob, {{jv}}, 0), HSFEE);
|
||||
env.close();
|
||||
{
|
||||
auto const hooksObj = env.le(keylet::hook(bob));
|
||||
BEAST_EXPECT(hooksObj && hooksObj->isFieldPresent(sfHooks));
|
||||
auto const& hooks = hooksObj->getFieldArray(sfHooks);
|
||||
BEAST_EXPECT(hooks.size() == 1);
|
||||
auto const& h = hooks[0];
|
||||
BEAST_EXPECT(!h.isFieldPresent(sfHookOn));
|
||||
BEAST_EXPECT(h.isFieldPresent(sfHookOnOutgoing));
|
||||
BEAST_EXPECT(h.isFieldPresent(sfHookOnIncoming));
|
||||
}
|
||||
|
||||
// Update Hook with HookOn, Incoming/Outgoing to alice
|
||||
jv = Json::Value{};
|
||||
jv[jss::HookOnIncoming] =
|
||||
"fffffffffffffffffffffffffffffffffffffff7ffffffffffffffffff"
|
||||
"bfffff"; // Invoke high
|
||||
jv[jss::HookOnOutgoing] =
|
||||
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
|
||||
"bffffe"; // Payment high
|
||||
env(ripple::test::jtx::hook(alice, {{jv}}, 0), HSFEE);
|
||||
env.close();
|
||||
{
|
||||
auto const hooksObj = env.le(keylet::hook(alice));
|
||||
BEAST_EXPECT(hooksObj && hooksObj->isFieldPresent(sfHooks));
|
||||
auto const& hooks = hooksObj->getFieldArray(sfHooks);
|
||||
BEAST_EXPECT(hooks.size() == 1);
|
||||
auto const& h = hooks[0];
|
||||
BEAST_EXPECT(!h.isFieldPresent(sfHookOn));
|
||||
BEAST_EXPECT(h.isFieldPresent(sfHookOnOutgoing));
|
||||
BEAST_EXPECT(h.isFieldPresent(sfHookOnIncoming));
|
||||
}
|
||||
|
||||
// Re-update Hook with HookOn, Incoming/Outgoing to alice
|
||||
jv = Json::Value{};
|
||||
jv[jss::HookOn] =
|
||||
"fffffffffffffffffffffffffffffffffffffff7ffffffffffffffffff"
|
||||
"bfffff";
|
||||
env(ripple::test::jtx::hook(alice, {{jv}}, 0), HSFEE);
|
||||
env.close();
|
||||
{
|
||||
auto const hooksObj = env.le(keylet::hook(alice));
|
||||
BEAST_EXPECT(hooksObj && hooksObj->isFieldPresent(sfHooks));
|
||||
auto const& hooks = hooksObj->getFieldArray(sfHooks);
|
||||
BEAST_EXPECT(hooks.size() == 1);
|
||||
auto const& h = hooks[0];
|
||||
BEAST_EXPECT(h.isFieldPresent(sfHookOn));
|
||||
if (withFix)
|
||||
{
|
||||
BEAST_EXPECT(!h.isFieldPresent(sfHookOnOutgoing));
|
||||
BEAST_EXPECT(!h.isFieldPresent(sfHookOnIncoming));
|
||||
}
|
||||
else
|
||||
{
|
||||
BEAST_EXPECT(h.isFieldPresent(sfHookOnOutgoing));
|
||||
BEAST_EXPECT(h.isFieldPresent(sfHookOnIncoming));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// install:: HookDefinition: Incoming/Outgoing -> Hook:HookOn
|
||||
// update:: Hook: Incoming/Outgoing -> Hook:HookOn
|
||||
Env env{*this, f};
|
||||
|
||||
env.fund(XRP(10000), alice, bob);
|
||||
env.close();
|
||||
|
||||
// Create Hook with HookOn to alice
|
||||
auto jv = hso(accept_wasm);
|
||||
jv.removeMember(jss::HookOn);
|
||||
jv[jss::HookOnIncoming] =
|
||||
"fffffffffffffffffffffffffffffffffffffff7ffffffffffffffffff"
|
||||
"bfffff"; // Invoke high
|
||||
jv[jss::HookOnOutgoing] =
|
||||
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
|
||||
"bffffe"; // Payment high
|
||||
env(ripple::test::jtx::hook(alice, {{jv}}, 0), HSFEE);
|
||||
env.close();
|
||||
|
||||
// Install Hook with Incoming/Outgoing to bob
|
||||
jv = Json::Value{};
|
||||
jv[jss::HookHash] = accept_hash_str;
|
||||
jv[jss::Flags] = hsfOVERRIDE;
|
||||
jv[jss::HookOn] =
|
||||
"0000000000000000000000000000000000000000000000000000000000"
|
||||
"000000";
|
||||
env(ripple::test::jtx::hook(bob, {{jv}}, 0), HSFEE);
|
||||
env.close();
|
||||
{
|
||||
auto const hooksObj = env.le(keylet::hook(bob));
|
||||
BEAST_EXPECT(hooksObj && hooksObj->isFieldPresent(sfHooks));
|
||||
auto const& hooks = hooksObj->getFieldArray(sfHooks);
|
||||
BEAST_EXPECT(hooks.size() == 1);
|
||||
auto const& h = hooks[0];
|
||||
BEAST_EXPECT(h.isFieldPresent(sfHookOn));
|
||||
BEAST_EXPECT(!h.isFieldPresent(sfHookOnOutgoing));
|
||||
BEAST_EXPECT(!h.isFieldPresent(sfHookOnIncoming));
|
||||
}
|
||||
|
||||
// Update Hook with HookOn, Incoming/Outgoing to alice
|
||||
jv = Json::Value{};
|
||||
jv[jss::HookOn] =
|
||||
"0000000000000000000000000000000000000000000000000000000000"
|
||||
"000000";
|
||||
env(ripple::test::jtx::hook(alice, {{jv}}, 0), HSFEE);
|
||||
env.close();
|
||||
{
|
||||
auto const hooksObj = env.le(keylet::hook(alice));
|
||||
BEAST_EXPECT(hooksObj && hooksObj->isFieldPresent(sfHooks));
|
||||
auto const& hooks = hooksObj->getFieldArray(sfHooks);
|
||||
BEAST_EXPECT(hooks.size() == 1);
|
||||
auto const& h = hooks[0];
|
||||
if (withFix)
|
||||
BEAST_EXPECT(h.isFieldPresent(sfHookOn));
|
||||
// Cause different results between gcc and clang due to
|
||||
// undefined behavior so we don't test it
|
||||
// else
|
||||
// BEAST_EXPECT(!h.isFieldPresent(sfHookOn));
|
||||
BEAST_EXPECT(!h.isFieldPresent(sfHookOnOutgoing));
|
||||
BEAST_EXPECT(!h.isFieldPresent(sfHookOnIncoming));
|
||||
}
|
||||
|
||||
// Re-update Hook with HookOn, Incoming/Outgoing to alice
|
||||
jv = Json::Value{};
|
||||
jv[jss::HookOnIncoming] =
|
||||
"fffffffffffffffffffffffffffffffffffffff7ffffffffffffffffff"
|
||||
"bffff0"; // Invoke high
|
||||
jv[jss::HookOnOutgoing] =
|
||||
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
|
||||
"bffff1"; // Payment high
|
||||
env(ripple::test::jtx::hook(alice, {{jv}}, 0), HSFEE);
|
||||
env.close();
|
||||
{
|
||||
auto const hooksObj = env.le(keylet::hook(alice));
|
||||
BEAST_EXPECT(hooksObj && hooksObj->isFieldPresent(sfHooks));
|
||||
auto const& hooks = hooksObj->getFieldArray(sfHooks);
|
||||
BEAST_EXPECT(hooks.size() == 1);
|
||||
auto const& h = hooks[0];
|
||||
if (withFix)
|
||||
BEAST_EXPECT(!h.isFieldPresent(sfHookOn));
|
||||
// Cause different results between gcc and clang due to
|
||||
// undefined behavior so we don't test it
|
||||
// else
|
||||
// BEAST_EXPECT(h.isFieldPresent(sfHookOn));
|
||||
BEAST_EXPECT(h.isFieldPresent(sfHookOnOutgoing));
|
||||
BEAST_EXPECT(h.isFieldPresent(sfHookOnIncoming));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fee RPC
|
||||
{
|
||||
auto jv = hso(accept_wasm);
|
||||
jv.removeMember(jss::HookOn);
|
||||
jv[jss::HookOnIncoming] =
|
||||
"fffffffffffffffffffffffffffffffffffffff7ffffffffffffffffff"
|
||||
"bfffff"; // Invoke high
|
||||
"bfff"
|
||||
"ff"; // Invoke high
|
||||
jv[jss::HookOnOutgoing] =
|
||||
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
|
||||
"bffffe"; // Payment high
|
||||
"bfff"
|
||||
"fe"; // Payment high
|
||||
env(ripple::test::jtx::hook(alice, {{jv}}, 0), HSFEE);
|
||||
env.close();
|
||||
|
||||
@@ -3271,37 +3003,25 @@ public:
|
||||
testInferHookSetOperation()
|
||||
{
|
||||
testcase("Test operation inference");
|
||||
using namespace jtx;
|
||||
|
||||
auto const alice = Account{"alice"};
|
||||
Env env{*this};
|
||||
env.fund(XRP(10000), alice);
|
||||
env(noop(alice));
|
||||
|
||||
SetHookCtx shCtx{
|
||||
.j = env.app().journal("SetHook"),
|
||||
.tx = *(env.tx()),
|
||||
.app = env.app(),
|
||||
.rules = env.current()->rules()};
|
||||
|
||||
// hsoNOOP
|
||||
{
|
||||
STObject hso{sfHook};
|
||||
BEAST_EXPECT(SetHook::inferOperation(shCtx, hso) == hsoNOOP);
|
||||
BEAST_EXPECT(SetHook::inferOperation(hso) == hsoNOOP);
|
||||
}
|
||||
|
||||
// hsoCREATE
|
||||
{
|
||||
STObject hso{sfHook};
|
||||
hso.setFieldVL(sfCreateCode, {1}); // non-empty create code
|
||||
BEAST_EXPECT(SetHook::inferOperation(shCtx, hso) == hsoCREATE);
|
||||
BEAST_EXPECT(SetHook::inferOperation(hso) == hsoCREATE);
|
||||
}
|
||||
|
||||
// hsoDELETE
|
||||
{
|
||||
STObject hso{sfHook};
|
||||
hso.setFieldVL(sfCreateCode, ripple::Blob{}); // empty create code
|
||||
BEAST_EXPECT(SetHook::inferOperation(shCtx, hso) == hsoDELETE);
|
||||
BEAST_EXPECT(SetHook::inferOperation(hso) == hsoDELETE);
|
||||
}
|
||||
|
||||
// hsoINSTALL
|
||||
@@ -3309,7 +3029,7 @@ public:
|
||||
STObject hso{sfHook};
|
||||
hso.setFieldH256(
|
||||
sfHookHash, uint256{beast::zero}); // all zeros hook hash
|
||||
BEAST_EXPECT(SetHook::inferOperation(shCtx, hso) == hsoINSTALL);
|
||||
BEAST_EXPECT(SetHook::inferOperation(hso) == hsoINSTALL);
|
||||
}
|
||||
|
||||
// hsoNSDELETE
|
||||
@@ -3318,14 +3038,14 @@ public:
|
||||
hso.setFieldH256(
|
||||
sfHookNamespace, uint256{beast::zero}); // all zeros hook hash
|
||||
hso.setFieldU32(sfFlags, hsfNSDELETE);
|
||||
BEAST_EXPECT(SetHook::inferOperation(shCtx, hso) == hsoNSDELETE);
|
||||
BEAST_EXPECT(SetHook::inferOperation(hso) == hsoNSDELETE);
|
||||
}
|
||||
|
||||
// hsoUPDATE
|
||||
{
|
||||
STObject hso{sfHook};
|
||||
hso.setFieldH256(sfHookOn, UINT256_BIT[0]);
|
||||
BEAST_EXPECT(SetHook::inferOperation(shCtx, hso) == hsoUPDATE);
|
||||
BEAST_EXPECT(SetHook::inferOperation(hso) == hsoUPDATE);
|
||||
}
|
||||
|
||||
// hsoINVALID
|
||||
@@ -3334,39 +3054,7 @@ public:
|
||||
hso.setFieldVL(sfCreateCode, {1}); // non-empty create code
|
||||
hso.setFieldH256(
|
||||
sfHookHash, uint256{beast::zero}); // all zeros hook hash
|
||||
BEAST_EXPECT(SetHook::inferOperation(shCtx, hso) == hsoINVALID);
|
||||
|
||||
for (auto fix : {true, false})
|
||||
{
|
||||
auto feature = supported_amendments() - featureHookOnV2 -
|
||||
featureHookOnV2_1;
|
||||
if (fix)
|
||||
feature = feature | featureHookOnV2_1;
|
||||
else
|
||||
feature = feature | featureHookOnV2;
|
||||
Env env{*this, feature};
|
||||
SetHookCtx shCtx{
|
||||
.j = env.app().journal("SetHook"),
|
||||
.tx = *env.tx(),
|
||||
.app = env.app(),
|
||||
.rules = env.current()->rules()};
|
||||
|
||||
STObject hso2{sfHook};
|
||||
hso2.setFieldH256(
|
||||
sfHookOnOutgoing,
|
||||
uint256{beast::zero}); // all zeros hook on outgoing
|
||||
BEAST_EXPECT(
|
||||
SetHook::inferOperation(shCtx, hso2) ==
|
||||
(fix ? hsoINVALID : hsoNOOP));
|
||||
|
||||
STObject hso3{sfHook};
|
||||
hso3.setFieldH256(
|
||||
sfHookOnIncoming,
|
||||
uint256{beast::zero}); // all zeros hook on incoming
|
||||
BEAST_EXPECT(
|
||||
SetHook::inferOperation(shCtx, hso3) ==
|
||||
(fix ? hsoINVALID : hsoNOOP));
|
||||
}
|
||||
BEAST_EXPECT(SetHook::inferOperation(hso) == hsoINVALID);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4589,10 +4277,10 @@ public:
|
||||
|
||||
uint8_t expected1[49] = {
|
||||
0xEDU, 0x20U, 0x2EU, 0x00U, 0x00U, 0x00U, 0x01U, 0x3DU, 0x00U, 0x00U,
|
||||
0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x01U, 0x5BU, 0xBCU, 0x09U, 0x95U,
|
||||
0xFDU, 0x03U, 0x0FU, 0xF1U, 0x85U, 0xF4U, 0xECU, 0xACU, 0x94U, 0xDBU,
|
||||
0x02U, 0x19U, 0x26U, 0xFEU, 0x58U, 0xD4U, 0x8DU, 0x48U, 0x21U, 0xCCU,
|
||||
0x82U, 0x2EU, 0x4AU, 0x6AU, 0xC9U, 0xC8U, 0xC6U, 0x7CU, 0x88U
|
||||
0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x01U, 0x5BU, 0xB8U, 0x05U, 0xD6U,
|
||||
0xC3U, 0x52U, 0xDFU, 0x7AU, 0x27U, 0x76U, 0x6DU, 0xC0U, 0x20U, 0x47U,
|
||||
0xB7U, 0x64U, 0x22U, 0x5AU, 0xB7U, 0x5DU, 0xF3U, 0xFAU, 0x0DU, 0xE3U,
|
||||
0xBDU, 0xC6U, 0x40U, 0xBAU, 0xD0U, 0x0AU, 0x66U, 0xEBU, 0x68U,
|
||||
};
|
||||
// 0x5CU
|
||||
// EmitNonce 32bytes
|
||||
@@ -15387,8 +15075,7 @@ public:
|
||||
testNSDeletePartial(features);
|
||||
testPageCap(features);
|
||||
|
||||
testHookOnV2((features | featureHookOnV2) - featureHookOnV2_1);
|
||||
testHookOnV2((features | featureHookOnV2_1) - featureHookOnV2);
|
||||
testHookOnV2(features);
|
||||
testHookName(features);
|
||||
|
||||
testFillCopy(features);
|
||||
|
||||
@@ -1613,10 +1613,10 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
|
||||
|
||||
uint8_t expected1[49] = {
|
||||
0xEDU, 0x20U, 0x2EU, 0x00U, 0x00U, 0x00U, 0x01U, 0x3DU, 0x00U, 0x00U,
|
||||
0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x01U, 0x5BU, 0xBCU, 0x09U, 0x95U,
|
||||
0xFDU, 0x03U, 0x0FU, 0xF1U, 0x85U, 0xF4U, 0xECU, 0xACU, 0x94U, 0xDBU,
|
||||
0x02U, 0x19U, 0x26U, 0xFEU, 0x58U, 0xD4U, 0x8DU, 0x48U, 0x21U, 0xCCU,
|
||||
0x82U, 0x2EU, 0x4AU, 0x6AU, 0xC9U, 0xC8U, 0xC6U, 0x7CU, 0x88U
|
||||
0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x01U, 0x5BU, 0xB8U, 0x05U, 0xD6U,
|
||||
0xC3U, 0x52U, 0xDFU, 0x7AU, 0x27U, 0x76U, 0x6DU, 0xC0U, 0x20U, 0x47U,
|
||||
0xB7U, 0x64U, 0x22U, 0x5AU, 0xB7U, 0x5DU, 0xF3U, 0xFAU, 0x0DU, 0xE3U,
|
||||
0xBDU, 0xC6U, 0x40U, 0xBAU, 0xD0U, 0x0AU, 0x66U, 0xEBU, 0x68U,
|
||||
};
|
||||
// 0x5CU
|
||||
// EmitNonce 32bytes
|
||||
@@ -1763,10 +1763,10 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
|
||||
0x36U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U,
|
||||
0x00U, 0x00U, 0x00U, 0xEDU, 0x20U, 0x2EU, 0x00U, 0x00U, 0x00U, 0x01U,
|
||||
0x3DU, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x01U, 0x5BU,
|
||||
0xBCU, 0x09U, 0x95U, 0xFDU, 0x03U, 0x0FU, 0xF1U, 0x85U, 0xF4U, 0xECU,
|
||||
0xACU, 0x94U, 0xDBU, 0x02U, 0x19U, 0x26U, 0xFEU, 0x58U, 0xD4U, 0x8DU,
|
||||
0x48U, 0x21U, 0xCCU, 0x82U, 0x2EU, 0x4AU, 0x6AU, 0xC9U, 0xC8U, 0xC6U,
|
||||
0x7CU, 0x88U, 0x68U, 0x6FU, 0x6FU, 0x6BU, 0x5FU, 0x68U, 0x61U, 0x73U,
|
||||
0xB8U, 0x05U, 0xD6U, 0xC3U, 0x52U, 0xDFU, 0x7AU, 0x27U, 0x76U, 0x6DU,
|
||||
0xC0U, 0x20U, 0x47U, 0xB7U, 0x64U, 0x22U, 0x5AU, 0xB7U, 0x5DU, 0xF3U,
|
||||
0xFAU, 0x0DU, 0xE3U, 0xBDU, 0xC6U, 0x40U, 0xBAU, 0xD0U, 0x0AU, 0x66U,
|
||||
0xEBU, 0x68U, 0x68U, 0x6FU, 0x6FU, 0x6BU, 0x5FU, 0x68U, 0x61U, 0x73U,
|
||||
0x68U, 0x28U, 0x28U, 0x75U, 0x69U, 0x6EU, 0x74U, 0x33U, 0x32U, 0x5FU,
|
||||
0x74U, 0x29U, 0x65U, 0x78U, 0x70U, 0x65U, 0x63U, 0x74U, 0x65U, 0x64U,
|
||||
0x5FU, 0x68U, 0x6FU, 0x6FU, 0x6BU, 0x5FU, 0x68U, 0x61U, 0x73U, 0x68U,
|
||||
|
||||
@@ -980,7 +980,6 @@ struct URIToken_test : public beast::unit_test::suite
|
||||
|
||||
// setup env
|
||||
env.fund(XRP(1000), alice, bob, gw);
|
||||
env.close();
|
||||
env.trust(USD(100000), alice, bob);
|
||||
env.close();
|
||||
env(pay(gw, alice, USD(1000)));
|
||||
|
||||
@@ -37,36 +37,20 @@ namespace test {
|
||||
|
||||
static char const* bobs_account_objects[] = {
|
||||
R"json({
|
||||
"Account" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
|
||||
"BookDirectory" : "50AD0A9E54D2B381288D535EB724E4275FFBF41580D28A925D038D7EA4C68000",
|
||||
"BookNode" : "0",
|
||||
"Flags" : 65536,
|
||||
"LedgerEntryType" : "Offer",
|
||||
"OwnerNode" : "0",
|
||||
"Sequence" : 4,
|
||||
"TakerGets" : {
|
||||
"currency" : "USD",
|
||||
"issuer" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
|
||||
"value" : "1"
|
||||
},
|
||||
"TakerPays" : "100000000",
|
||||
"index" : "A984D036A0E562433A8377CA57D1A1E056E58C0D04818F8DFD3A1AA3F217DD82"
|
||||
})json",
|
||||
R"json({
|
||||
"Account" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
|
||||
"BookDirectory" : "B025997A323F5C3E03DDF1334471F5984ABDE31C59D463525D038D7EA4C68000",
|
||||
"BookNode" : "0",
|
||||
"Flags" : 65536,
|
||||
"LedgerEntryType" : "Offer",
|
||||
"OwnerNode" : "0",
|
||||
"Sequence" : 5,
|
||||
"TakerGets" : {
|
||||
"currency" : "USD",
|
||||
"issuer" : "r32rQHyesiTtdWFU7UJVtff4nCR5SHCbJW",
|
||||
"value" : "1"
|
||||
},
|
||||
"TakerPays" : "100000000",
|
||||
"index" : "CAFE32332D752387B01083B60CC63069BA4A969C9730836929F841450F6A718E"
|
||||
"Account" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
|
||||
"BookDirectory" : "B025997A323F5C3E03DDF1334471F5984ABDE31C59D463525D038D7EA4C68000",
|
||||
"BookNode" : "0",
|
||||
"Flags" : 65536,
|
||||
"LedgerEntryType" : "Offer",
|
||||
"OwnerNode" : "0",
|
||||
"Sequence" : 4,
|
||||
"TakerGets" : {
|
||||
"currency" : "USD",
|
||||
"issuer" : "r32rQHyesiTtdWFU7UJVtff4nCR5SHCbJW",
|
||||
"value" : "1"
|
||||
},
|
||||
"TakerPays" : "100000000",
|
||||
"index" : "A984D036A0E562433A8377CA57D1A1E056E58C0D04818F8DFD3A1AA3F217DD82"
|
||||
})json",
|
||||
R"json({
|
||||
"Balance" : {
|
||||
@@ -111,6 +95,22 @@ static char const* bobs_account_objects[] = {
|
||||
},
|
||||
"LowNode" : "0",
|
||||
"index" : "D89BC239086183EB9458C396E643795C1134963E6550E682A190A5F021766D43"
|
||||
})json",
|
||||
R"json({
|
||||
"Account" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
|
||||
"BookDirectory" : "50AD0A9E54D2B381288D535EB724E4275FFBF41580D28A925D038D7EA4C68000",
|
||||
"BookNode" : "0",
|
||||
"Flags" : 65536,
|
||||
"LedgerEntryType" : "Offer",
|
||||
"OwnerNode" : "0",
|
||||
"Sequence" : 3,
|
||||
"TakerGets" : {
|
||||
"currency" : "USD",
|
||||
"issuer" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
|
||||
"value" : "1"
|
||||
},
|
||||
"TakerPays" : "100000000",
|
||||
"index" : "E11029302EE744401427793A4F37BCB18F698D55C96851BEC5ABBD6242CF03D7"
|
||||
})json"};
|
||||
|
||||
class AccountObjects_test : public beast::unit_test::suite
|
||||
@@ -332,7 +332,7 @@ public:
|
||||
auto& aobj = resp[jss::result][jss::account_objects][i];
|
||||
aobj.removeMember("PreviousTxnID");
|
||||
aobj.removeMember("PreviousTxnLgrSeq");
|
||||
BEAST_EXPECT(aobj == bobj[i + 2]);
|
||||
BEAST_EXPECT(aobj == bobj[i + 1]);
|
||||
}
|
||||
}
|
||||
// test stepped one-at-a-time with limit=1, resume from prev marker
|
||||
|
||||
@@ -117,9 +117,9 @@ public:
|
||||
BEAST_EXPECT(jroOuter[0u][jss::quality] == "100000000");
|
||||
BEAST_EXPECT(jroOuter[0u][jss::taker_gets][jss::currency] == "USD");
|
||||
BEAST_EXPECT(
|
||||
jroOuter[0u][jss::taker_gets][jss::issuer] == gw.human());
|
||||
BEAST_EXPECT(jroOuter[0u][jss::taker_gets][jss::value] == "2");
|
||||
BEAST_EXPECT(jroOuter[0u][jss::taker_pays] == "200000000");
|
||||
jroOuter[0u][jss::taker_gets][jss::issuer] == bob.human());
|
||||
BEAST_EXPECT(jroOuter[0u][jss::taker_gets][jss::value] == "1");
|
||||
BEAST_EXPECT(jroOuter[0u][jss::taker_pays] == "100000000");
|
||||
|
||||
BEAST_EXPECT(jroOuter[1u][jss::quality] == "5000000");
|
||||
BEAST_EXPECT(jroOuter[1u][jss::taker_gets][jss::currency] == "USD");
|
||||
@@ -131,9 +131,9 @@ public:
|
||||
BEAST_EXPECT(jroOuter[2u][jss::quality] == "100000000");
|
||||
BEAST_EXPECT(jroOuter[2u][jss::taker_gets][jss::currency] == "USD");
|
||||
BEAST_EXPECT(
|
||||
jroOuter[2u][jss::taker_gets][jss::issuer] == bob.human());
|
||||
BEAST_EXPECT(jroOuter[2u][jss::taker_gets][jss::value] == "1");
|
||||
BEAST_EXPECT(jroOuter[2u][jss::taker_pays] == "100000000");
|
||||
jroOuter[2u][jss::taker_gets][jss::issuer] == gw.human());
|
||||
BEAST_EXPECT(jroOuter[2u][jss::taker_gets][jss::value] == "2");
|
||||
BEAST_EXPECT(jroOuter[2u][jss::taker_pays] == "200000000");
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -163,7 +163,7 @@ public:
|
||||
void
|
||||
testNoParams(FeatureBitset features)
|
||||
{
|
||||
testcase("Default Env: config-forced, none on-ledger");
|
||||
testcase("No Params, None Enabled");
|
||||
|
||||
using namespace test::jtx;
|
||||
Env env{*this};
|
||||
@@ -178,6 +178,8 @@ public:
|
||||
{
|
||||
if (!BEAST_EXPECT(feature.isMember(jss::name)))
|
||||
return;
|
||||
// default config - so all should be disabled, and
|
||||
// supported. Some may be vetoed.
|
||||
bool expectVeto =
|
||||
(votes.at(feature[jss::name].asString()) ==
|
||||
VoteBehavior::DefaultNo);
|
||||
@@ -186,12 +188,8 @@ public:
|
||||
VoteBehavior::Obsolete);
|
||||
BEAST_EXPECTS(
|
||||
feature.isMember(jss::enabled) &&
|
||||
feature[jss::enabled].asBool(),
|
||||
!feature[jss::enabled].asBool(),
|
||||
feature[jss::name].asString() + " enabled");
|
||||
BEAST_EXPECTS(
|
||||
feature.isMember(jss::ledger_enabled) &&
|
||||
!feature[jss::ledger_enabled].asBool(),
|
||||
feature[jss::name].asString() + " ledger_enabled");
|
||||
BEAST_EXPECTS(
|
||||
feature.isMember(jss::vetoed) &&
|
||||
feature[jss::vetoed].isBool() == !expectObsolete &&
|
||||
@@ -210,7 +208,7 @@ public:
|
||||
void
|
||||
testSomeEnabled(FeatureBitset features)
|
||||
{
|
||||
testcase("Two config-forced, none on-ledger");
|
||||
testcase("No Params, Some Enabled");
|
||||
|
||||
using namespace test::jtx;
|
||||
Env env{
|
||||
@@ -230,10 +228,7 @@ public:
|
||||
(void)id.parseHex(it.key().asString().c_str());
|
||||
if (!BEAST_EXPECT((*it).isMember(jss::name)))
|
||||
return;
|
||||
bool const expectOnLedger =
|
||||
env.app().getAmendmentTable().isEnabled(id);
|
||||
bool const expectForced =
|
||||
id == featureDepositAuth || id == featureDepositPreauth;
|
||||
bool expectEnabled = env.app().getAmendmentTable().isEnabled(id);
|
||||
bool expectSupported =
|
||||
env.app().getAmendmentTable().isSupported(id);
|
||||
bool expectVeto =
|
||||
@@ -244,14 +239,9 @@ public:
|
||||
VoteBehavior::Obsolete);
|
||||
BEAST_EXPECTS(
|
||||
(*it).isMember(jss::enabled) &&
|
||||
(*it)[jss::enabled].asBool() ==
|
||||
(expectOnLedger || expectForced),
|
||||
(*it)[jss::enabled].asBool() == expectEnabled,
|
||||
(*it)[jss::name].asString() + " enabled");
|
||||
BEAST_EXPECTS(
|
||||
(*it).isMember(jss::ledger_enabled) &&
|
||||
(*it)[jss::ledger_enabled].asBool() == expectOnLedger,
|
||||
(*it)[jss::name].asString() + " ledger_enabled");
|
||||
if (expectOnLedger)
|
||||
if (expectEnabled)
|
||||
BEAST_EXPECTS(
|
||||
!(*it).isMember(jss::vetoed),
|
||||
(*it)[jss::name].asString() + " vetoed");
|
||||
@@ -370,122 +360,12 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testConfigForced(FeatureBitset features)
|
||||
{
|
||||
testcase("Config-forced features ([features] stanza)");
|
||||
|
||||
using namespace test::jtx;
|
||||
|
||||
auto const forced = featurePriceOracle;
|
||||
auto const forcedHex = to_string(forced);
|
||||
|
||||
Env env{*this, FeatureBitset(forced)};
|
||||
|
||||
auto jrr = env.rpc("server_definitions")[jss::result];
|
||||
if (!BEAST_EXPECT(jrr.isMember(jss::features)))
|
||||
return;
|
||||
|
||||
bool sawForced = false;
|
||||
for (auto it = jrr[jss::features].begin();
|
||||
it != jrr[jss::features].end();
|
||||
++it)
|
||||
{
|
||||
auto const& f = *it;
|
||||
auto const name = f[jss::name].asString();
|
||||
|
||||
if (!BEAST_EXPECTS(
|
||||
f.isMember(jss::enabled) && f.isMember(jss::ledger_enabled),
|
||||
name + " enabled/ledger_enabled"))
|
||||
return;
|
||||
|
||||
BEAST_EXPECTS(
|
||||
!f[jss::ledger_enabled].asBool(), name + " ledger_enabled");
|
||||
|
||||
if (it.key().asString() == forcedHex)
|
||||
{
|
||||
sawForced = true;
|
||||
BEAST_EXPECTS(f[jss::enabled].asBool(), name + " enabled");
|
||||
}
|
||||
else
|
||||
{
|
||||
BEAST_EXPECTS(!f[jss::enabled].asBool(), name + " enabled");
|
||||
}
|
||||
}
|
||||
BEAST_EXPECT(sawForced);
|
||||
}
|
||||
|
||||
void
|
||||
testOnLedger(FeatureBitset features)
|
||||
{
|
||||
testcase("On-ledger plus one config-forced");
|
||||
|
||||
using namespace test::jtx;
|
||||
|
||||
// Veto XahauGenesis: FRESH would otherwise enable it via pseudo-tx.
|
||||
auto const forced = featurePriceOracle;
|
||||
auto const forcedHex = to_string(forced);
|
||||
|
||||
Env env{
|
||||
*this,
|
||||
envconfig([](std::unique_ptr<Config> cfg) {
|
||||
cfg->START_UP = Config::FRESH;
|
||||
cfg->section(SECTION_VETO_AMENDMENTS)
|
||||
.append(to_string(featureXahauGenesis) + " XahauGenesis");
|
||||
return cfg;
|
||||
}),
|
||||
FeatureBitset(forced)};
|
||||
|
||||
auto jrr = env.rpc("server_definitions")[jss::result];
|
||||
if (!BEAST_EXPECT(jrr.isMember(jss::features)))
|
||||
return;
|
||||
|
||||
bool sawOnLedger = false;
|
||||
bool sawForced = false;
|
||||
for (auto it = jrr[jss::features].begin();
|
||||
it != jrr[jss::features].end();
|
||||
++it)
|
||||
{
|
||||
uint256 id;
|
||||
(void)id.parseHex(it.key().asString().c_str());
|
||||
auto const& f = *it;
|
||||
auto const name = f[jss::name].asString();
|
||||
|
||||
if (!BEAST_EXPECTS(
|
||||
f.isMember(jss::enabled) && f.isMember(jss::ledger_enabled),
|
||||
name + " enabled/ledger_enabled"))
|
||||
return;
|
||||
|
||||
bool const onLedger = env.app().getAmendmentTable().isEnabled(id);
|
||||
bool const isForced = it.key().asString() == forcedHex;
|
||||
|
||||
BEAST_EXPECTS(
|
||||
f[jss::ledger_enabled].asBool() == onLedger,
|
||||
name + " ledger_enabled");
|
||||
BEAST_EXPECTS(
|
||||
f[jss::enabled].asBool() == (onLedger || isForced),
|
||||
name + " enabled");
|
||||
|
||||
if (onLedger)
|
||||
sawOnLedger = true;
|
||||
if (isForced)
|
||||
{
|
||||
sawForced = true;
|
||||
BEAST_EXPECTS(!onLedger, name + " forced not on-ledger");
|
||||
}
|
||||
}
|
||||
BEAST_EXPECT(sawOnLedger);
|
||||
BEAST_EXPECT(sawForced);
|
||||
}
|
||||
|
||||
void
|
||||
testServerFeatures(FeatureBitset features)
|
||||
{
|
||||
testNoParams(features);
|
||||
testSomeEnabled(features);
|
||||
testWithMajorities(features);
|
||||
testConfigForced(features);
|
||||
testOnLedger(features);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -252,7 +252,12 @@ applyCreate(
|
||||
auto sleAMMRoot = std::make_shared<SLE>(keylet::account(*ammAccount));
|
||||
sleAMMRoot->setAccountID(sfAccount, *ammAccount);
|
||||
sleAMMRoot->setFieldAmount(sfBalance, STAmount{});
|
||||
std::uint32_t const seqno = newAccountSeqNo(ctx_.view());
|
||||
std::uint32_t const seqno{
|
||||
ctx_.view().rules().enabled(featureXahauGenesis)
|
||||
? ctx_.view().info().parentCloseTime.time_since_epoch().count()
|
||||
: ctx_.view().rules().enabled(featureDeletableAccounts)
|
||||
? ctx_.view().seq()
|
||||
: 1};
|
||||
sleAMMRoot->setFieldU32(sfSequence, seqno);
|
||||
// Ignore reserves requirement, disable the master key, allow default
|
||||
// rippling (AMM LPToken can be used in payments and offer crossing but
|
||||
|
||||
@@ -554,7 +554,8 @@ Change::activateXahauGenesis()
|
||||
{
|
||||
sle = std::make_shared<SLE>(kl);
|
||||
sle->setAccountID(sfAccount, accid);
|
||||
std::uint32_t const seqno = newAccountSeqNo(sb);
|
||||
std::uint32_t const seqno{
|
||||
sb.info().parentCloseTime.time_since_epoch().count()};
|
||||
sle->setFieldU32(sfSequence, seqno);
|
||||
}
|
||||
|
||||
|
||||
@@ -243,7 +243,8 @@ GenesisMint::doApply()
|
||||
if (created)
|
||||
{
|
||||
// Create the account.
|
||||
std::uint32_t const seqno = newAccountSeqNo(view());
|
||||
std::uint32_t const seqno{
|
||||
view().info().parentCloseTime.time_since_epoch().count()};
|
||||
|
||||
sle = std::make_shared<SLE>(k);
|
||||
sle->setAccountID(sfAccount, id);
|
||||
|
||||
@@ -1307,7 +1307,12 @@ Import::doApply()
|
||||
if (create)
|
||||
{
|
||||
// Create the account.
|
||||
std::uint32_t const seqno = newAccountSeqNo(view());
|
||||
std::uint32_t const seqno{
|
||||
view().rules().enabled(featureXahauGenesis)
|
||||
? view().info().parentCloseTime.time_since_epoch().count()
|
||||
: view().rules().enabled(featureDeletableAccounts)
|
||||
? view().seq()
|
||||
: 1};
|
||||
|
||||
sle = std::make_shared<SLE>(keylet::account(id));
|
||||
sle->setAccountID(sfAccount, id);
|
||||
|
||||
@@ -1041,7 +1041,11 @@ ValidNewAccountRoot::finalize(
|
||||
tt == ttXCHAIN_ADD_ACCOUNT_CREATE_ATTESTATION) &&
|
||||
isTesSuccess(result))
|
||||
{
|
||||
std::uint32_t const startingSeq = newAccountSeqNo(view);
|
||||
std::uint32_t const startingSeq{
|
||||
view.rules().enabled(featureXahauGenesis)
|
||||
? view.info().parentCloseTime.time_since_epoch().count()
|
||||
: view.rules().enabled(featureDeletableAccounts) ? view.seq()
|
||||
: 1};
|
||||
|
||||
if (accountSeq_ != startingSeq)
|
||||
{
|
||||
|
||||
@@ -354,7 +354,12 @@ Payment::doApply()
|
||||
|
||||
if (!sleDst)
|
||||
{
|
||||
std::uint32_t const seqno = newAccountSeqNo(view());
|
||||
std::uint32_t const seqno{
|
||||
view().rules().enabled(featureXahauGenesis)
|
||||
? view().info().parentCloseTime.time_since_epoch().count()
|
||||
: view().rules().enabled(featureDeletableAccounts)
|
||||
? view().seq()
|
||||
: 1};
|
||||
|
||||
// Create the account.
|
||||
sleDst = std::make_shared<SLE>(k);
|
||||
|
||||
@@ -328,7 +328,11 @@ Remit::doApply()
|
||||
nativeRemit += accountReserve;
|
||||
|
||||
// Create the account.
|
||||
std::uint32_t const seqno = newAccountSeqNo(sb);
|
||||
std::uint32_t const seqno{
|
||||
sb.rules().enabled(featureXahauGenesis)
|
||||
? sb.info().parentCloseTime.time_since_epoch().count()
|
||||
: sb.rules().enabled(featureDeletableAccounts) ? sb.seq()
|
||||
: 1};
|
||||
|
||||
sleDstAcc = std::make_shared<SLE>(keylet::account(dstAccID));
|
||||
sleDstAcc->setAccountID(sfAccount, dstAccID);
|
||||
|
||||
@@ -207,7 +207,7 @@ validateHookParams(SetHookCtx& ctx, STArray const& hookParams)
|
||||
// infer which operation the user is attempting to execute from the present and
|
||||
// absent fields
|
||||
HookSetOperation
|
||||
SetHook::inferOperation(SetHookCtx& ctx, STObject const& hookSetObj)
|
||||
SetHook::inferOperation(STObject const& hookSetObj)
|
||||
{
|
||||
uint64_t wasmByteCount = hookSetObj.isFieldPresent(sfCreateCode)
|
||||
? hookSetObj.getFieldVL(sfCreateCode).size()
|
||||
@@ -216,12 +216,7 @@ SetHook::inferOperation(SetHookCtx& ctx, STObject const& hookSetObj)
|
||||
bool hasHash = hookSetObj.isFieldPresent(sfHookHash);
|
||||
bool hasCode = hookSetObj.isFieldPresent(sfCreateCode);
|
||||
|
||||
bool invalidHookOn = ctx.rules.enabled(featureHookOnV2_1) &&
|
||||
hookSetObj.isFieldPresent(sfHookOnOutgoing) !=
|
||||
hookSetObj.isFieldPresent(sfHookOnIncoming);
|
||||
|
||||
if ((hasHash && hasCode) || invalidHookOn) // Both HookHash and CreateCode
|
||||
// or invalid HookOn: invalid
|
||||
if (hasHash && hasCode) // Both HookHash and CreateCode: invalid
|
||||
return hsoINVALID;
|
||||
else if (hasHash) // Hookhash only: install
|
||||
return hsoINSTALL;
|
||||
@@ -249,62 +244,6 @@ SetHook::inferOperation(SetHookCtx& ctx, STObject const& hookSetObj)
|
||||
: hsoUPDATE;
|
||||
}
|
||||
|
||||
bool
|
||||
validateHookOn(SetHookCtx& ctx, STObject const& hookSetObj)
|
||||
{
|
||||
if (!hookSetObj.isFieldPresent(sfHookOn))
|
||||
{
|
||||
if (!ctx.rules.enabled(featureHookOnV2) &&
|
||||
!ctx.rules.enabled(featureHookOnV2_1))
|
||||
{
|
||||
JLOG(ctx.j.trace())
|
||||
<< "HookSet(" << hook::log::HOOKON_MISSING << ")[" << HS_ACC()
|
||||
<< "]: Malformed transaction: SetHook must include "
|
||||
"sfHookOn before featureHookOnV2_1 is enabled.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!hookSetObj.isFieldPresent(sfHookOnOutgoing) ||
|
||||
!hookSetObj.isFieldPresent(sfHookOnIncoming))
|
||||
{
|
||||
JLOG(ctx.j.trace())
|
||||
<< "HookSet(" << hook::log::HOOKON_MISSING << ")[" << HS_ACC()
|
||||
<< "]: Malformed transaction: SetHook must include "
|
||||
"sfHookOnOutgoing and sfHookOnIncoming "
|
||||
"when creating a new hook without sfHookOn.";
|
||||
return false;
|
||||
}
|
||||
|
||||
auto const outgoing = hookSetObj.getFieldH256(sfHookOnOutgoing);
|
||||
auto const incoming = hookSetObj.getFieldH256(sfHookOnIncoming);
|
||||
if (outgoing == incoming)
|
||||
{
|
||||
JLOG(ctx.j.trace())
|
||||
<< "HookSet(" << hook::log::HOOKON_MISSING << ")[" << HS_ACC()
|
||||
<< "]: Malformed transaction: SetHook outgoing and "
|
||||
"incoming hookon must be different.";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (hookSetObj.isFieldPresent(sfHookOnOutgoing) ||
|
||||
hookSetObj.isFieldPresent(sfHookOnIncoming))
|
||||
{
|
||||
JLOG(ctx.j.trace())
|
||||
<< "HookSet(" << hook::log::HOOKON_MISSING << ")[" << HS_ACC()
|
||||
<< "]: Malformed transaction: SetHook must no"
|
||||
"include sfHookOnOutgoing and sfHookOnIncoming "
|
||||
"when creating a new hook with sfHookOn.";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// This is a context-free validation, it does not take into account the current
|
||||
// state of the ledger returns < valid, instruction count > may throw
|
||||
// overflow_error
|
||||
@@ -315,7 +254,7 @@ SetHook::validateHookSetEntry(SetHookCtx& ctx, STObject const& hookSetObj)
|
||||
? hookSetObj.getFieldU32(sfFlags)
|
||||
: 0;
|
||||
|
||||
switch (inferOperation(ctx, hookSetObj))
|
||||
switch (inferOperation(hookSetObj))
|
||||
{
|
||||
case hsoNOOP: {
|
||||
return true;
|
||||
@@ -424,13 +363,6 @@ SetHook::validateHookSetEntry(SetHookCtx& ctx, STObject const& hookSetObj)
|
||||
// hookon may be present if the user so chooses
|
||||
// flags may be present if the user so chooses
|
||||
|
||||
if (ctx.rules.enabled(featureHookOnV2_1) &&
|
||||
(hookSetObj.isFieldPresent(sfHookOn) ||
|
||||
hookSetObj.isFieldPresent(sfHookOnOutgoing) ||
|
||||
hookSetObj.isFieldPresent(sfHookOnIncoming)) &&
|
||||
!validateHookOn(ctx, hookSetObj))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -475,13 +407,6 @@ SetHook::validateHookSetEntry(SetHookCtx& ctx, STObject const& hookSetObj)
|
||||
// hookon may be present if the user so chooses
|
||||
// flags may be present if the user so chooses
|
||||
|
||||
if (ctx.rules.enabled(featureHookOnV2_1) &&
|
||||
(hookSetObj.isFieldPresent(sfHookOn) ||
|
||||
hookSetObj.isFieldPresent(sfHookOnOutgoing) ||
|
||||
hookSetObj.isFieldPresent(sfHookOnIncoming)) &&
|
||||
!validateHookOn(ctx, hookSetObj))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -531,8 +456,56 @@ SetHook::validateHookSetEntry(SetHookCtx& ctx, STObject const& hookSetObj)
|
||||
}
|
||||
|
||||
// validate sfHookOn
|
||||
if (!validateHookOn(ctx, hookSetObj))
|
||||
return false;
|
||||
if (!hookSetObj.isFieldPresent(sfHookOn))
|
||||
{
|
||||
if (!ctx.rules.enabled(featureHookOnV2))
|
||||
{
|
||||
JLOG(ctx.j.trace())
|
||||
<< "HookSet(" << hook::log::HOOKON_MISSING << ")["
|
||||
<< HS_ACC()
|
||||
<< "]: Malformed transaction: SetHook must include "
|
||||
"sfHookOn before featureHookOnV2 is enabled.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!hookSetObj.isFieldPresent(sfHookOnOutgoing) ||
|
||||
!hookSetObj.isFieldPresent(sfHookOnIncoming))
|
||||
{
|
||||
JLOG(ctx.j.trace())
|
||||
<< "HookSet(" << hook::log::HOOKON_MISSING << ")["
|
||||
<< HS_ACC()
|
||||
<< "]: Malformed transaction: SetHook must include "
|
||||
"sfHookOnOutgoing and sfHookOnIncoming "
|
||||
"when creating a new hook without sfHookOn.";
|
||||
return false;
|
||||
}
|
||||
|
||||
auto const outgoing = hookSetObj.getFieldH256(sfHookOnOutgoing);
|
||||
auto const incoming = hookSetObj.getFieldH256(sfHookOnIncoming);
|
||||
if (outgoing == incoming)
|
||||
{
|
||||
JLOG(ctx.j.trace())
|
||||
<< "HookSet(" << hook::log::HOOKON_MISSING << ")["
|
||||
<< HS_ACC()
|
||||
<< "]: Malformed transaction: SetHook outgoing and "
|
||||
"incoming hookon must be different.";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (hookSetObj.isFieldPresent(sfHookOnOutgoing) ||
|
||||
hookSetObj.isFieldPresent(sfHookOnIncoming))
|
||||
{
|
||||
JLOG(ctx.j.trace())
|
||||
<< "HookSet(" << hook::log::HOOKON_MISSING << ")["
|
||||
<< HS_ACC()
|
||||
<< "]: Malformed transaction: SetHook must no"
|
||||
"include sfHookOnOutgoing and sfHookOnIncoming "
|
||||
"when creating a new hook with sfHookOn.";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// validate sfHookCanEmit
|
||||
// HookCanEmit field is an optional field for backward compatibility
|
||||
@@ -1432,7 +1405,7 @@ SetHook::setHook()
|
||||
HookSetOperation op = hsoNOOP;
|
||||
|
||||
if (hookSetObj)
|
||||
op = inferOperation(ctx, hookSetObj->get());
|
||||
op = inferOperation(hookSetObj->get());
|
||||
|
||||
// these flags are not able to be passed onto the ledger object
|
||||
int newFlags = 0;
|
||||
@@ -1654,23 +1627,10 @@ SetHook::setHook()
|
||||
newHook.setFieldH256(sfHookNamespace, *newNamespace);
|
||||
}
|
||||
|
||||
if (ctx.rules.enabled(featureHookOnV2_1))
|
||||
{
|
||||
// sanity check
|
||||
if (newHookOn && (newHookOnOutgoing || newHookOnIncoming))
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
if ((!newHookOnOutgoing && newHookOnIncoming) ||
|
||||
(newHookOnOutgoing && !newHookOnIncoming))
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
// set the hookon field if it differs from definition
|
||||
if (newHookOn)
|
||||
{
|
||||
if ((!view().rules().enabled(featureHookOnV2_1) ||
|
||||
defHookOn.has_value()) &&
|
||||
*defHookOn == *newHookOn)
|
||||
if (*defHookOn == *newHookOn)
|
||||
{
|
||||
if (newHook.isFieldPresent(sfHookOn))
|
||||
newHook.makeFieldAbsent(sfHookOn);
|
||||
@@ -1705,22 +1665,6 @@ SetHook::setHook()
|
||||
sfHookOnIncoming, *newHookOnIncoming);
|
||||
}
|
||||
|
||||
if (ctx.rules.enabled(featureHookOnV2_1))
|
||||
{
|
||||
if (newHookOn)
|
||||
{
|
||||
if (newHook.isFieldPresent(sfHookOnIncoming))
|
||||
newHook.makeFieldAbsent(sfHookOnIncoming);
|
||||
if (newHook.isFieldPresent(sfHookOnOutgoing))
|
||||
newHook.makeFieldAbsent(sfHookOnOutgoing);
|
||||
}
|
||||
if (newHookOnOutgoing || newHookOnIncoming)
|
||||
{
|
||||
if (newHook.isFieldPresent(sfHookOn))
|
||||
newHook.makeFieldAbsent(sfHookOn);
|
||||
}
|
||||
}
|
||||
|
||||
// set the hookcanemit field if it differs from definition
|
||||
if (newHookCanEmit)
|
||||
{
|
||||
@@ -1899,8 +1843,7 @@ SetHook::setHook()
|
||||
newHookDef->setFieldH256(sfHookHash, *createHookHash);
|
||||
|
||||
// only HookOn or (HookOnOutgoing and HookOnIncoming)
|
||||
if ((!view().rules().enabled(featureHookOnV2) &&
|
||||
!view().rules().enabled(featureHookOnV2_1)) ||
|
||||
if (!view().rules().enabled(featureHookOnV2) ||
|
||||
(!newHookOnOutgoing && !newHookOnIncoming))
|
||||
newHookDef->setFieldH256(sfHookOn, *newHookOn);
|
||||
else
|
||||
|
||||
@@ -86,7 +86,7 @@ public:
|
||||
calculateBaseFee(ReadView const& view, STTx const& tx);
|
||||
|
||||
static HookSetOperation
|
||||
inferOperation(SetHookCtx& ctx, STObject const& hookSetObj);
|
||||
inferOperation(STObject const& hookSetObj);
|
||||
|
||||
static HookSetValidation
|
||||
validateHookSetEntry(SetHookCtx& ctx, STObject const& hookSetObj);
|
||||
|
||||
@@ -481,7 +481,11 @@ transferHelper(
|
||||
}
|
||||
|
||||
// Create the account.
|
||||
std::uint32_t const seqno = newAccountSeqNo(psb);
|
||||
std::uint32_t const seqno{
|
||||
psb.rules().enabled(featureXahauGenesis)
|
||||
? psb.info().parentCloseTime.time_since_epoch().count()
|
||||
: psb.rules().enabled(featureDeletableAccounts) ? psb.seq()
|
||||
: 1};
|
||||
|
||||
sleDst = std::make_shared<SLE>(dstK);
|
||||
sleDst->setAccountID(sfAccount, dst);
|
||||
|
||||
@@ -1266,24 +1266,6 @@ deleteAMMTrustLine(
|
||||
std::optional<AccountID> const& ammAccountID,
|
||||
beast::Journal j);
|
||||
|
||||
[[nodiscard]] inline std::uint32_t
|
||||
newAccountSeqNo(ReadView const& view)
|
||||
{
|
||||
auto const time = view.info().parentCloseTime.time_since_epoch().count();
|
||||
return view.rules().enabled(featureXahauGenesis)
|
||||
// TEQU:
|
||||
// When creating accounts in GenesisLedger, we previously set
|
||||
// the account Sequence to 0. However, since this conflicts with
|
||||
// the PseudoAccount requirements, we are changing it to 1.
|
||||
// There will be no impact on networks that are already running,
|
||||
// and for future networks, there won't be any impact unless you
|
||||
// create accounts via GenesisLedger.
|
||||
// This specifically addresses an issue that comes up during
|
||||
// unittests.
|
||||
? (time == 0 ? 1 : time)
|
||||
: view.rules().enabled(featureDeletableAccounts) ? view.seq() : 1;
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
@@ -22,10 +22,12 @@
|
||||
#include <xrpld/app/main/Application.h>
|
||||
#include <xrpld/app/misc/AmendmentTable.h>
|
||||
#include <xrpld/app/misc/NetworkOPs.h>
|
||||
#include <xrpld/core/Config.h>
|
||||
#include <xrpld/rpc/detail/TransactionSign.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
#include <xrpl/json/json_writer.h>
|
||||
#include <xrpl/protocol/LedgerFormats.h>
|
||||
#include <xrpl/protocol/RPCErr.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/TxFlags.h>
|
||||
#include <xrpl/protocol/digest.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
@@ -33,6 +35,14 @@
|
||||
#include <magic_enum.hpp>
|
||||
#include <sstream>
|
||||
|
||||
#define MAGIC_ENUM(x, _min, _max) \
|
||||
template <> \
|
||||
struct magic_enum::customize::enum_range<x> \
|
||||
{ \
|
||||
static constexpr int min = _min; \
|
||||
static constexpr int max = _max; \
|
||||
};
|
||||
|
||||
#define MAGIC_ENUM_16(x) \
|
||||
template <> \
|
||||
struct magic_enum::customize::enum_range<x> \
|
||||
@@ -48,6 +58,15 @@
|
||||
static constexpr bool is_flags = true; \
|
||||
};
|
||||
|
||||
MAGIC_ENUM(ripple::SerializedTypeID, -2, 10004);
|
||||
MAGIC_ENUM(ripple::LedgerEntryType, 0, 255);
|
||||
MAGIC_ENUM(ripple::TELcodes, -399, 300);
|
||||
MAGIC_ENUM(ripple::TEMcodes, -299, -200);
|
||||
MAGIC_ENUM(ripple::TEFcodes, -199, -100);
|
||||
MAGIC_ENUM(ripple::TERcodes, -99, -1);
|
||||
MAGIC_ENUM(ripple::TEScodes, 0, 1);
|
||||
MAGIC_ENUM(ripple::TECcodes, 100, 255);
|
||||
MAGIC_ENUM_16(ripple::TxType);
|
||||
MAGIC_ENUM_FLAG(ripple::UniversalFlags);
|
||||
MAGIC_ENUM_FLAG(ripple::AccountSetFlags);
|
||||
MAGIC_ENUM_FLAG(ripple::OfferCreateFlags);
|
||||
@@ -173,19 +192,24 @@ private:
|
||||
|
||||
ret[jss::TYPES]["Done"] = -1;
|
||||
std::map<int32_t, std::string> type_map{{-1, "Done"}};
|
||||
for (auto const& [rawName, typeValue] : sTypeMap)
|
||||
for (auto const& entry : magic_enum::enum_entries<SerializedTypeID>())
|
||||
{
|
||||
std::string typeName =
|
||||
translate(std::string(rawName).substr(4) /* remove STI_ */);
|
||||
ret[jss::TYPES][typeName] = typeValue;
|
||||
type_map[typeValue] = typeName;
|
||||
const auto name = entry.second;
|
||||
std::string type_name =
|
||||
translate(name.data() + 4 /* remove STI_ */);
|
||||
int32_t type_value = static_cast<int32_t>(entry.first);
|
||||
ret[jss::TYPES][type_name] = type_value;
|
||||
type_map[type_value] = type_name;
|
||||
}
|
||||
|
||||
ret[jss::LEDGER_ENTRY_TYPES] = Json::objectValue;
|
||||
ret[jss::LEDGER_ENTRY_TYPES][jss::Invalid] = -1;
|
||||
for (auto const& f : LedgerFormats::getInstance())
|
||||
for (auto const& entry : magic_enum::enum_entries<LedgerEntryType>())
|
||||
{
|
||||
ret[jss::LEDGER_ENTRY_TYPES][f.getName()] = f.getType();
|
||||
const auto name = entry.second;
|
||||
std::string type_name = translate(name.data() + 2 /* remove lt_ */);
|
||||
int32_t type_value = static_cast<int32_t>(entry.first);
|
||||
ret[jss::LEDGER_ENTRY_TYPES][type_name] = type_value;
|
||||
}
|
||||
|
||||
ret[jss::FIELDS] = Json::arrayValue;
|
||||
@@ -302,16 +326,71 @@ private:
|
||||
}
|
||||
|
||||
ret[jss::TRANSACTION_RESULTS] = Json::objectValue;
|
||||
for (auto const& [code, terInfo] : transResults())
|
||||
for (auto const& entry : magic_enum::enum_entries<TELcodes>())
|
||||
{
|
||||
ret[jss::TRANSACTION_RESULTS][terInfo.first] = code;
|
||||
const auto name = entry.second;
|
||||
ret[jss::TRANSACTION_RESULTS][STR(name)] =
|
||||
static_cast<int32_t>(entry.first);
|
||||
}
|
||||
for (auto const& entry : magic_enum::enum_entries<TEMcodes>())
|
||||
{
|
||||
const auto name = entry.second;
|
||||
ret[jss::TRANSACTION_RESULTS][STR(name)] =
|
||||
static_cast<int32_t>(entry.first);
|
||||
}
|
||||
for (auto const& entry : magic_enum::enum_entries<TEFcodes>())
|
||||
{
|
||||
const auto name = entry.second;
|
||||
ret[jss::TRANSACTION_RESULTS][STR(name)] =
|
||||
static_cast<int32_t>(entry.first);
|
||||
}
|
||||
for (auto const& entry : magic_enum::enum_entries<TERcodes>())
|
||||
{
|
||||
const auto name = entry.second;
|
||||
ret[jss::TRANSACTION_RESULTS][STR(name)] =
|
||||
static_cast<int32_t>(entry.first);
|
||||
}
|
||||
for (auto const& entry : magic_enum::enum_entries<TEScodes>())
|
||||
{
|
||||
const auto name = entry.second;
|
||||
ret[jss::TRANSACTION_RESULTS][STR(name)] =
|
||||
static_cast<int32_t>(entry.first);
|
||||
}
|
||||
for (auto const& entry : magic_enum::enum_entries<TECcodes>())
|
||||
{
|
||||
const auto name = entry.second;
|
||||
ret[jss::TRANSACTION_RESULTS][STR(name)] =
|
||||
static_cast<int32_t>(entry.first);
|
||||
}
|
||||
|
||||
auto const translate_tt = [](std::string inp) -> std::string {
|
||||
if (inp == "Amendment")
|
||||
return "EnableAmendment";
|
||||
if (inp == "Fee")
|
||||
return "SetFee";
|
||||
if (inp == "PaychanClaim")
|
||||
return "PaymentChannelClaim";
|
||||
if (inp == "PaychanCreate")
|
||||
return "PaymentChannelCreate";
|
||||
if (inp == "PaychanFund")
|
||||
return "PaymentChannelFund";
|
||||
if (inp == "RegularKeySet")
|
||||
return "SetRegularKey";
|
||||
if (inp == "HookSet")
|
||||
return "SetHook";
|
||||
if (inp == "RemarksSet")
|
||||
return "SetRemarks";
|
||||
return inp;
|
||||
};
|
||||
|
||||
ret[jss::TRANSACTION_TYPES] = Json::objectValue;
|
||||
ret[jss::TRANSACTION_TYPES][jss::Invalid] = -1;
|
||||
for (auto const& f : TxFormats::getInstance())
|
||||
for (auto const& entry : magic_enum::enum_entries<TxType>())
|
||||
{
|
||||
ret[jss::TRANSACTION_TYPES][f.getName()] = f.getType();
|
||||
const auto name = entry.second;
|
||||
std::string type_name = translate_tt(translate(name.data() + 2));
|
||||
int32_t type_value = static_cast<int32_t>(entry.first);
|
||||
ret[jss::TRANSACTION_TYPES][type_name] = type_value;
|
||||
}
|
||||
|
||||
// Transaction Flags:
|
||||
@@ -466,25 +545,6 @@ doServerDefinitions(RPC::JsonContext& context)
|
||||
features[to_string(h)][jss::majority] =
|
||||
t.time_since_epoch().count();
|
||||
|
||||
// getJson's enabled is on-ledger; [features] also apply here.
|
||||
for (auto const& name : features.getMemberNames())
|
||||
{
|
||||
Json::Value& entry = features[name];
|
||||
entry[jss::ledger_enabled] = entry[jss::enabled].asBool();
|
||||
}
|
||||
for (auto const& h : context.app.config().features)
|
||||
{
|
||||
Json::Value& entry = features[to_string(h)];
|
||||
if (!entry.isMember(jss::name))
|
||||
{
|
||||
if (auto const fname = featureToName(h); !fname.empty())
|
||||
entry[jss::name] = fname;
|
||||
}
|
||||
if (!entry.isMember(jss::ledger_enabled))
|
||||
entry[jss::ledger_enabled] = false;
|
||||
entry[jss::enabled] = true;
|
||||
}
|
||||
|
||||
lastFeatures = features;
|
||||
{
|
||||
const std::string out = Json::FastWriter().write(features);
|
||||
|
||||
Reference in new issue
Block a user