mirror of
https://github.com/Xahau/xahaud.git
synced 2026-04-29 15:37:46 +00:00
Compare commits
43 Commits
tequdev-pa
...
add-clang-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e633922226 | ||
|
|
15c7ad6f78 | ||
|
|
1f12b9ec5a | ||
|
|
1a3210f3ab | ||
|
|
44b9dcfaee | ||
|
|
ad0531ad6c | ||
|
|
e580f7cfc0 | ||
|
|
094f011006 | ||
|
|
ecf0d68a64 | ||
|
|
775b6c14a0 | ||
|
|
7ea6f432c9 | ||
|
|
22a81a050f | ||
|
|
cd252504ad | ||
|
|
d8ccb1db81 | ||
|
|
27ec068050 | ||
|
|
2b6c92ecb1 | ||
|
|
e559008fc8 | ||
|
|
7ced4de6f2 | ||
|
|
3571a403f6 | ||
|
|
87dab64e0c | ||
|
|
c730e1d5f0 | ||
|
|
9bf2bc0420 | ||
|
|
be1a34c7e9 | ||
|
|
06b4344cc0 | ||
|
|
7a11eb6c15 | ||
|
|
c1a35510f4 | ||
|
|
7c4b1bafeb | ||
|
|
ccfa6da70a | ||
|
|
139f1bd32b | ||
|
|
a3b00d57a2 | ||
|
|
b822b66825 | ||
|
|
6684075a28 | ||
|
|
cc28fcf190 | ||
|
|
ddca64815d | ||
|
|
60df462bc2 | ||
|
|
4755a37cad | ||
|
|
df652b457b | ||
|
|
0651332bb3 | ||
|
|
5286bae753 | ||
|
|
4b9ef8db22 | ||
|
|
360546d555 | ||
|
|
4efcbd1eaa | ||
|
|
4c90598462 |
46
.github/actions/xahau-ga-build/action.yml
vendored
46
.github/actions/xahau-ga-build/action.yml
vendored
@@ -21,7 +21,7 @@ inputs:
|
||||
required: false
|
||||
default: ''
|
||||
compiler-id:
|
||||
description: 'Unique identifier for compiler/version combination used for cache keys'
|
||||
description: 'Unique identifier: compiler-version-stdlib[-gccversion] (e.g. clang-14-libstdcxx-gcc11, gcc-13-libstdcxx)'
|
||||
required: false
|
||||
default: ''
|
||||
cache_version:
|
||||
@@ -36,6 +36,17 @@ inputs:
|
||||
description: 'Main branch name for restore keys'
|
||||
required: false
|
||||
default: 'dev'
|
||||
stdlib:
|
||||
description: 'C++ standard library to use'
|
||||
required: true
|
||||
type: choice
|
||||
options:
|
||||
- libstdcxx
|
||||
- libcxx
|
||||
clang_gcc_toolchain:
|
||||
description: 'GCC version to use for Clang toolchain (e.g. 11, 13)'
|
||||
required: false
|
||||
default: ''
|
||||
|
||||
runs:
|
||||
using: 'composite'
|
||||
@@ -93,6 +104,38 @@ runs:
|
||||
CCACHE_ARGS="-DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache"
|
||||
fi
|
||||
|
||||
# Configure C++ standard library if specified
|
||||
# libstdcxx used for clang-14/16 to work around missing lexicographical_compare_three_way in libc++
|
||||
# libcxx can be used with clang-17+ which has full C++20 support
|
||||
# Note: -stdlib flag is Clang-specific, GCC always uses libstdc++
|
||||
CMAKE_CXX_FLAGS=""
|
||||
if [[ "${{ inputs.cxx }}" == clang* ]]; then
|
||||
# Only Clang needs the -stdlib flag
|
||||
if [ "${{ inputs.stdlib }}" = "libstdcxx" ]; then
|
||||
CMAKE_CXX_FLAGS="-stdlib=libstdc++"
|
||||
elif [ "${{ inputs.stdlib }}" = "libcxx" ]; then
|
||||
CMAKE_CXX_FLAGS="-stdlib=libc++"
|
||||
fi
|
||||
fi
|
||||
# GCC always uses libstdc++ and doesn't need/support the -stdlib flag
|
||||
|
||||
# Configure GCC toolchain for Clang if specified
|
||||
if [ -n "${{ inputs.clang_gcc_toolchain }}" ] && [[ "${{ inputs.cxx }}" == clang* ]]; then
|
||||
# Extract Clang version from compiler executable name (e.g., clang++-14 -> 14)
|
||||
clang_version=$(echo "${{ inputs.cxx }}" | grep -oE '[0-9]+$')
|
||||
|
||||
# Clang 16+ supports --gcc-install-dir (precise path specification)
|
||||
# Clang <16 only has --gcc-toolchain (uses discovery heuristics)
|
||||
if [ -n "$clang_version" ] && [ "$clang_version" -ge "16" ]; then
|
||||
# Clang 16+ uses --gcc-install-dir (canonical, precise)
|
||||
CMAKE_CXX_FLAGS="$CMAKE_CXX_FLAGS --gcc-install-dir=/usr/lib/gcc/x86_64-linux-gnu/${{ inputs.clang_gcc_toolchain }}"
|
||||
else
|
||||
# Clang 14-15 uses --gcc-toolchain (deprecated but necessary)
|
||||
# Note: This still uses discovery, so we hide newer GCC versions in the workflow
|
||||
CMAKE_CXX_FLAGS="$CMAKE_CXX_FLAGS --gcc-toolchain=/usr"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Run CMake configure
|
||||
# Note: conanfile.py hardcodes 'build/generators' as the output path.
|
||||
# If we're in a 'build' folder, Conan detects this and uses just 'generators/'
|
||||
@@ -101,6 +144,7 @@ runs:
|
||||
cmake .. \
|
||||
-G "${{ inputs.generator }}" \
|
||||
$CCACHE_ARGS \
|
||||
${CMAKE_CXX_FLAGS:+-DCMAKE_CXX_FLAGS="$CMAKE_CXX_FLAGS"} \
|
||||
-DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake \
|
||||
-DCMAKE_BUILD_TYPE=${{ inputs.configuration }}
|
||||
|
||||
|
||||
12
.github/actions/xahau-ga-dependencies/action.yml
vendored
12
.github/actions/xahau-ga-dependencies/action.yml
vendored
@@ -10,7 +10,7 @@ inputs:
|
||||
required: false
|
||||
default: '.build'
|
||||
compiler-id:
|
||||
description: 'Unique identifier for compiler/version combination used for cache keys'
|
||||
description: 'Unique identifier: compiler-version-stdlib[-gccversion] (e.g. clang-14-libstdcxx-gcc11, gcc-13-libstdcxx)'
|
||||
required: false
|
||||
default: ''
|
||||
cache_version:
|
||||
@@ -25,6 +25,13 @@ inputs:
|
||||
description: 'Main branch name for restore keys'
|
||||
required: false
|
||||
default: 'dev'
|
||||
stdlib:
|
||||
description: 'C++ standard library for Conan configuration (note: also in compiler-id)'
|
||||
required: true
|
||||
type: choice
|
||||
options:
|
||||
- libstdcxx
|
||||
- libcxx
|
||||
|
||||
outputs:
|
||||
cache-hit:
|
||||
@@ -70,6 +77,7 @@ runs:
|
||||
path: |
|
||||
~/.conan
|
||||
~/.conan2
|
||||
# Note: compiler-id format is compiler-version-stdlib[-gccversion]
|
||||
key: ${{ runner.os }}-conan-v${{ inputs.cache_version }}-${{ inputs.compiler-id }}-${{ hashFiles('**/conanfile.txt', '**/conanfile.py') }}-${{ inputs.configuration }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-conan-v${{ inputs.cache_version }}-${{ inputs.compiler-id }}-${{ hashFiles('**/conanfile.txt', '**/conanfile.py') }}-
|
||||
@@ -84,6 +92,8 @@ runs:
|
||||
|
||||
- name: Install dependencies
|
||||
shell: bash
|
||||
env:
|
||||
CONAN_REQUEST_TIMEOUT: 180 # Increase timeout to 3 minutes for slow mirrors
|
||||
run: |
|
||||
# Create build directory
|
||||
mkdir -p ${{ inputs.build_dir }}
|
||||
|
||||
223
.github/workflows/xahau-ga-nix.yml
vendored
223
.github/workflows/xahau-ga-nix.yml
vendored
@@ -13,21 +13,146 @@ concurrency:
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build-job:
|
||||
matrix-setup:
|
||||
runs-on: ubuntu-latest
|
||||
container: python:3-slim
|
||||
outputs:
|
||||
matrix: ${{ steps.set-matrix.outputs.matrix }}
|
||||
steps:
|
||||
- name: Generate build matrix
|
||||
id: set-matrix
|
||||
shell: python
|
||||
run: |
|
||||
import json
|
||||
import os
|
||||
|
||||
# Full matrix with all 6 compiler configurations
|
||||
# Each configuration includes all parameters needed by the build job
|
||||
full_matrix = [
|
||||
{
|
||||
"compiler_id": "gcc-11-libstdcxx",
|
||||
"compiler": "gcc",
|
||||
"cc": "gcc-11",
|
||||
"cxx": "g++-11",
|
||||
"compiler_version": 11,
|
||||
"stdlib": "libstdcxx",
|
||||
"configuration": "Debug"
|
||||
},
|
||||
{
|
||||
"compiler_id": "gcc-13-libstdcxx",
|
||||
"compiler": "gcc",
|
||||
"cc": "gcc-13",
|
||||
"cxx": "g++-13",
|
||||
"compiler_version": 13,
|
||||
"stdlib": "libstdcxx",
|
||||
"configuration": "Debug"
|
||||
},
|
||||
{
|
||||
"compiler_id": "clang-14-libstdcxx-gcc11",
|
||||
"compiler": "clang",
|
||||
"cc": "clang-14",
|
||||
"cxx": "clang++-14",
|
||||
"compiler_version": 14,
|
||||
"stdlib": "libstdcxx",
|
||||
"clang_gcc_toolchain": 11,
|
||||
"configuration": "Debug"
|
||||
},
|
||||
{
|
||||
"compiler_id": "clang-16-libstdcxx-gcc13",
|
||||
"compiler": "clang",
|
||||
"cc": "clang-16",
|
||||
"cxx": "clang++-16",
|
||||
"compiler_version": 16,
|
||||
"stdlib": "libstdcxx",
|
||||
"clang_gcc_toolchain": 13,
|
||||
"configuration": "Debug"
|
||||
},
|
||||
{
|
||||
"compiler_id": "clang-17-libcxx",
|
||||
"compiler": "clang",
|
||||
"cc": "clang-17",
|
||||
"cxx": "clang++-17",
|
||||
"compiler_version": 17,
|
||||
"stdlib": "libcxx",
|
||||
"configuration": "Debug"
|
||||
},
|
||||
{
|
||||
# Clang 18 - testing if it's faster than Clang 17 with libc++
|
||||
# Requires patching Conan v1 settings.yml to add version 18
|
||||
"compiler_id": "clang-18-libcxx",
|
||||
"compiler": "clang",
|
||||
"cc": "clang-18",
|
||||
"cxx": "clang++-18",
|
||||
"compiler_version": 18,
|
||||
"stdlib": "libcxx",
|
||||
"configuration": "Debug"
|
||||
}
|
||||
]
|
||||
|
||||
# Minimal matrix for PRs and feature branches
|
||||
minimal_matrix = [
|
||||
full_matrix[1], # gcc-13 (middle-ground gcc)
|
||||
full_matrix[2] # clang-14 (mature, stable clang)
|
||||
]
|
||||
|
||||
# Determine which matrix to use based on the target branch
|
||||
ref = "${{ github.ref }}"
|
||||
base_ref = "${{ github.base_ref }}" # For PRs, this is the target branch
|
||||
event_name = "${{ github.event_name }}"
|
||||
commit_message = """${{ github.event.head_commit.message }}"""
|
||||
pr_title = """${{ github.event.pull_request.title }}"""
|
||||
|
||||
# Debug logging
|
||||
print(f"Event: {event_name}")
|
||||
print(f"Ref: {ref}")
|
||||
print(f"Base ref: {base_ref}")
|
||||
print(f"PR title: {pr_title}")
|
||||
print(f"Commit message: {commit_message}")
|
||||
|
||||
# Check for override tags in commit message or PR title
|
||||
force_full = "[ci-nix-full-matrix]" in commit_message or "[ci-nix-full-matrix]" in pr_title
|
||||
print(f"Force full matrix: {force_full}")
|
||||
|
||||
# Check if this is targeting a main branch
|
||||
# For PRs: check base_ref (target branch)
|
||||
# For pushes: check ref (current branch)
|
||||
main_branches = ["refs/heads/dev", "refs/heads/release", "refs/heads/candidate"]
|
||||
|
||||
if force_full:
|
||||
# Override: always use full matrix if tag is present
|
||||
use_full = True
|
||||
elif event_name == "pull_request":
|
||||
# For PRs, base_ref is just the branch name (e.g., "dev", not "refs/heads/dev")
|
||||
# Check if the PR targets release or candidate (more critical branches)
|
||||
use_full = base_ref in ["release", "candidate"]
|
||||
else:
|
||||
# For pushes, ref is the full reference (e.g., "refs/heads/dev")
|
||||
use_full = ref in main_branches
|
||||
|
||||
# Select the appropriate matrix
|
||||
if use_full:
|
||||
if force_full:
|
||||
print(f"Using FULL matrix (6 configs) - forced by [ci-nix-full-matrix] tag")
|
||||
else:
|
||||
print(f"Using FULL matrix (6 configs) - targeting main branch")
|
||||
matrix = full_matrix
|
||||
else:
|
||||
print(f"Using MINIMAL matrix (2 configs) - feature branch/PR")
|
||||
matrix = minimal_matrix
|
||||
|
||||
# Output the matrix as JSON
|
||||
output = json.dumps({"include": matrix})
|
||||
with open(os.environ['GITHUB_OUTPUT'], 'a') as f:
|
||||
f.write(f"matrix={output}\n")
|
||||
|
||||
build:
|
||||
needs: matrix-setup
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
artifact_name: ${{ steps.set-artifact-name.outputs.artifact_name }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
compiler: [gcc]
|
||||
configuration: [Debug]
|
||||
include:
|
||||
- compiler: gcc
|
||||
cc: gcc-13
|
||||
cxx: g++-13
|
||||
compiler_id: gcc-13
|
||||
compiler_version: 13
|
||||
matrix: ${{ fromJSON(needs.matrix-setup.outputs.matrix) }}
|
||||
env:
|
||||
build_dir: .build
|
||||
# Bump this number to invalidate all caches globally.
|
||||
@@ -41,8 +166,70 @@ jobs:
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y ninja-build ${{ matrix.cc }} ${{ matrix.cxx }} ccache
|
||||
|
||||
# Install the specific GCC version needed for Clang
|
||||
if [ -n "${{ matrix.clang_gcc_toolchain }}" ]; then
|
||||
echo "=== Installing GCC ${{ matrix.clang_gcc_toolchain }} for Clang ==="
|
||||
sudo apt-get install -y gcc-${{ matrix.clang_gcc_toolchain }} g++-${{ matrix.clang_gcc_toolchain }} libstdc++-${{ matrix.clang_gcc_toolchain }}-dev
|
||||
|
||||
echo "=== GCC versions available after installation ==="
|
||||
ls -la /usr/lib/gcc/x86_64-linux-gnu/ | grep -E "^d"
|
||||
fi
|
||||
|
||||
# For Clang < 16 with --gcc-toolchain, hide newer GCC versions
|
||||
# This is needed because --gcc-toolchain still picks the highest version
|
||||
#
|
||||
# THE GREAT GCC HIDING TRICK (for Clang < 16):
|
||||
# Clang versions before 16 don't have --gcc-install-dir, only --gcc-toolchain
|
||||
# which is deprecated and still uses discovery heuristics that ALWAYS pick
|
||||
# the highest version number. So we play a sneaky game...
|
||||
#
|
||||
# We rename newer GCC versions to very low integers (1, 2, 3...) which makes
|
||||
# Clang think they're ancient GCC versions. Since 11 > 3 > 2 > 1, Clang will
|
||||
# pick GCC 11 over our renamed versions. It's dumb but it works!
|
||||
#
|
||||
# Example: GCC 12→1, GCC 13→2, GCC 14→3, so Clang picks 11 (highest number)
|
||||
if [ -n "${{ matrix.clang_gcc_toolchain }}" ] && [ "${{ matrix.compiler_version }}" -lt "16" ]; then
|
||||
echo "=== Hiding GCC versions newer than ${{ matrix.clang_gcc_toolchain }} for Clang < 16 ==="
|
||||
target_version=${{ matrix.clang_gcc_toolchain }}
|
||||
counter=1 # Start with 1 - these will be seen as "GCC version 1, 2, 3" etc
|
||||
for dir in /usr/lib/gcc/x86_64-linux-gnu/*/; do
|
||||
if [ -d "$dir" ]; then
|
||||
version=$(basename "$dir")
|
||||
# Check if version is numeric and greater than target
|
||||
if [[ "$version" =~ ^[0-9]+$ ]] && [ "$version" -gt "$target_version" ]; then
|
||||
echo "Hiding GCC $version -> renaming to $counter (will be seen as GCC version $counter)"
|
||||
# Safety check: ensure target doesn't already exist
|
||||
if [ ! -e "/usr/lib/gcc/x86_64-linux-gnu/$counter" ]; then
|
||||
sudo mv "$dir" "/usr/lib/gcc/x86_64-linux-gnu/$counter"
|
||||
else
|
||||
echo "ERROR: Cannot rename GCC $version - /usr/lib/gcc/x86_64-linux-gnu/$counter already exists"
|
||||
exit 1
|
||||
fi
|
||||
counter=$((counter + 1))
|
||||
fi
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# Verify what Clang will use
|
||||
if [ -n "${{ matrix.clang_gcc_toolchain }}" ]; then
|
||||
echo "=== Verifying GCC toolchain selection ==="
|
||||
echo "Available GCC versions:"
|
||||
ls -la /usr/lib/gcc/x86_64-linux-gnu/ | grep -E "^d.*[0-9]+$" || true
|
||||
|
||||
echo ""
|
||||
echo "Clang's detected GCC installation:"
|
||||
${{ matrix.cxx }} -v -E -x c++ /dev/null -o /dev/null 2>&1 | grep "Found candidate GCC installation" || true
|
||||
fi
|
||||
|
||||
# Install libc++ dev packages if using libc++ (not needed for libstdc++)
|
||||
if [ "${{ matrix.stdlib }}" = "libcxx" ]; then
|
||||
sudo apt-get install -y libc++-${{ matrix.compiler_version }}-dev libc++abi-${{ matrix.compiler_version }}-dev
|
||||
fi
|
||||
|
||||
# Install Conan 2
|
||||
pip install --upgrade "conan>=2.0"
|
||||
pip install --upgrade "conan>=2.0,<3"
|
||||
|
||||
- name: Configure ccache
|
||||
uses: ./.github/actions/xahau-configure-ccache
|
||||
@@ -57,14 +244,21 @@ jobs:
|
||||
# Create the default profile directory if it doesn't exist
|
||||
mkdir -p ~/.conan2/profiles
|
||||
|
||||
# Determine the correct libcxx based on stdlib parameter
|
||||
if [ "${{ matrix.stdlib }}" = "libcxx" ]; then
|
||||
LIBCXX="libc++"
|
||||
else
|
||||
LIBCXX="libstdc++11"
|
||||
fi
|
||||
|
||||
# Create profile with our specific settings
|
||||
cat > ~/.conan2/profiles/default <<EOF
|
||||
[settings]
|
||||
arch=x86_64
|
||||
build_type=Release
|
||||
build_type=${{ matrix.configuration }}
|
||||
compiler=${{ matrix.compiler }}
|
||||
compiler.cppstd=20
|
||||
compiler.libcxx=libstdc++11
|
||||
compiler.libcxx=${LIBCXX}
|
||||
compiler.version=${{ matrix.compiler_version }}
|
||||
os=Linux
|
||||
|
||||
@@ -99,6 +293,7 @@ jobs:
|
||||
compiler-id: ${{ matrix.compiler_id }}
|
||||
cache_version: ${{ env.CACHE_VERSION }}
|
||||
main_branch: ${{ env.MAIN_BRANCH_NAME }}
|
||||
stdlib: ${{ matrix.stdlib }}
|
||||
|
||||
- name: Build
|
||||
uses: ./.github/actions/xahau-ga-build
|
||||
@@ -111,6 +306,8 @@ jobs:
|
||||
compiler-id: ${{ matrix.compiler_id }}
|
||||
cache_version: ${{ env.CACHE_VERSION }}
|
||||
main_branch: ${{ env.MAIN_BRANCH_NAME }}
|
||||
stdlib: ${{ matrix.stdlib }}
|
||||
clang_gcc_toolchain: ${{ matrix.clang_gcc_toolchain || '' }}
|
||||
|
||||
- name: Set artifact name
|
||||
id: set-artifact-name
|
||||
|
||||
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@@ -8,6 +8,6 @@
|
||||
"editor.semanticHighlighting.enabled": true,
|
||||
"editor.tabSize": 4,
|
||||
"editor.defaultFormatter": "xaver.clang-format",
|
||||
"editor.formatOnSave": false
|
||||
"editor.formatOnSave": true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,6 +50,12 @@ target_sources (xrpl_core PRIVATE
|
||||
src/ripple/beast/utility/src/beast_Journal.cpp
|
||||
src/ripple/beast/utility/src/beast_PropertyStream.cpp)
|
||||
|
||||
# Conditionally add enhanced logging source when BEAST_ENHANCED_LOGGING is enabled
|
||||
if(DEFINED BEAST_ENHANCED_LOGGING AND BEAST_ENHANCED_LOGGING)
|
||||
target_sources(xrpl_core PRIVATE
|
||||
src/ripple/beast/utility/src/beast_EnhancedLogging.cpp)
|
||||
endif()
|
||||
|
||||
#[===============================[
|
||||
core sources
|
||||
#]===============================]
|
||||
@@ -155,6 +161,13 @@ target_link_libraries (xrpl_core
|
||||
ed25519::ed25519
|
||||
date::date
|
||||
Ripple::opts)
|
||||
|
||||
# Link date-tz library when enhanced logging is enabled
|
||||
if(DEFINED BEAST_ENHANCED_LOGGING AND BEAST_ENHANCED_LOGGING)
|
||||
if(TARGET date::date-tz)
|
||||
target_link_libraries(xrpl_core PUBLIC date::date-tz)
|
||||
endif()
|
||||
endif()
|
||||
#[=================================[
|
||||
main/core headers installation
|
||||
#]=================================]
|
||||
|
||||
@@ -33,6 +33,25 @@ if(Git_FOUND)
|
||||
endif()
|
||||
endif() #git
|
||||
|
||||
# make SOURCE_ROOT_PATH define available for logging
|
||||
set(SOURCE_ROOT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/src/")
|
||||
add_definitions(-DSOURCE_ROOT_PATH="${SOURCE_ROOT_PATH}")
|
||||
|
||||
# BEAST_ENHANCED_LOGGING option - adds file:line numbers and formatting to logs
|
||||
# Default to ON for Debug builds, OFF for Release
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
option(BEAST_ENHANCED_LOGGING "Include file and line numbers in log messages" ON)
|
||||
else()
|
||||
option(BEAST_ENHANCED_LOGGING "Include file and line numbers in log messages" OFF)
|
||||
endif()
|
||||
|
||||
if(BEAST_ENHANCED_LOGGING)
|
||||
add_definitions(-DBEAST_ENHANCED_LOGGING=1)
|
||||
message(STATUS "Log line numbers enabled")
|
||||
else()
|
||||
message(STATUS "Log line numbers disabled")
|
||||
endif()
|
||||
|
||||
if(thread_safety_analysis)
|
||||
add_compile_options(-Wthread-safety -D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS -DRIPPLE_ENABLE_THREAD_SAFETY_ANNOTATIONS)
|
||||
add_compile_options("-stdlib=libc++")
|
||||
|
||||
@@ -26,7 +26,7 @@ class Xrpl(ConanFile):
|
||||
}
|
||||
|
||||
requires = [
|
||||
'date/3.0.1',
|
||||
'date/3.0.3',
|
||||
'libarchive/3.6.0',
|
||||
'lz4/1.9.4',
|
||||
'grpc/1.50.1',
|
||||
@@ -52,7 +52,7 @@ class Xrpl(ConanFile):
|
||||
'tool_requires_b2': False,
|
||||
|
||||
'cassandra-cpp-driver/*:shared': False,
|
||||
'date/*:header_only': True,
|
||||
'date/*:header_only': False,
|
||||
'grpc/*:shared': False,
|
||||
'grpc/*:secure': True,
|
||||
'libarchive/*:shared': False,
|
||||
|
||||
@@ -156,34 +156,22 @@ deserializeManifest(Slice s, beast::Journal journal)
|
||||
}
|
||||
}
|
||||
|
||||
template <class Stream>
|
||||
Stream&
|
||||
logMftAct(
|
||||
Stream& s,
|
||||
std::string const& action,
|
||||
PublicKey const& pk,
|
||||
std::uint32_t seq)
|
||||
{
|
||||
s << "Manifest: " << action
|
||||
<< ";Pk: " << toBase58(TokenType::NodePublic, pk) << ";Seq: " << seq
|
||||
<< ";";
|
||||
return s;
|
||||
}
|
||||
// Helper macros to format manifest log messages while preserving line numbers
|
||||
#define LOG_MANIFEST_ACTION(stream, action, pk, seq) \
|
||||
do \
|
||||
{ \
|
||||
JLOG(stream) << "Manifest: " << action \
|
||||
<< ";Pk: " << toBase58(TokenType::NodePublic, pk) \
|
||||
<< ";Seq: " << seq << ";"; \
|
||||
} while (0)
|
||||
|
||||
template <class Stream>
|
||||
Stream&
|
||||
logMftAct(
|
||||
Stream& s,
|
||||
std::string const& action,
|
||||
PublicKey const& pk,
|
||||
std::uint32_t seq,
|
||||
std::uint32_t oldSeq)
|
||||
{
|
||||
s << "Manifest: " << action
|
||||
<< ";Pk: " << toBase58(TokenType::NodePublic, pk) << ";Seq: " << seq
|
||||
<< ";OldSeq: " << oldSeq << ";";
|
||||
return s;
|
||||
}
|
||||
#define LOG_MANIFEST_ACTION_WITH_OLD(stream, action, pk, seq, oldSeq) \
|
||||
do \
|
||||
{ \
|
||||
JLOG(stream) << "Manifest: " << action \
|
||||
<< ";Pk: " << toBase58(TokenType::NodePublic, pk) \
|
||||
<< ";Seq: " << seq << ";OldSeq: " << oldSeq << ";"; \
|
||||
} while (0)
|
||||
|
||||
bool
|
||||
Manifest::verify() const
|
||||
@@ -381,7 +369,7 @@ ManifestCache::applyManifest(Manifest m)
|
||||
// several cases including when we receive manifests from a peer who
|
||||
// doesn't have the latest data.
|
||||
if (auto stream = j_.debug())
|
||||
logMftAct(
|
||||
LOG_MANIFEST_ACTION_WITH_OLD(
|
||||
stream,
|
||||
"Stale",
|
||||
m.masterKey,
|
||||
@@ -393,7 +381,7 @@ ManifestCache::applyManifest(Manifest m)
|
||||
if (checkSignature && !m.verify())
|
||||
{
|
||||
if (auto stream = j_.warn())
|
||||
logMftAct(stream, "Invalid", m.masterKey, m.sequence);
|
||||
LOG_MANIFEST_ACTION(stream, "Invalid", m.masterKey, m.sequence);
|
||||
return ManifestDisposition::invalid;
|
||||
}
|
||||
|
||||
@@ -407,7 +395,7 @@ ManifestCache::applyManifest(Manifest m)
|
||||
bool const revoked = m.revoked();
|
||||
|
||||
if (auto stream = j_.warn(); stream && revoked)
|
||||
logMftAct(stream, "Revoked", m.masterKey, m.sequence);
|
||||
LOG_MANIFEST_ACTION(stream, "Revoked", m.masterKey, m.sequence);
|
||||
|
||||
// Sanity check: the master key of this manifest should not be used as
|
||||
// the ephemeral key of another manifest:
|
||||
@@ -476,7 +464,7 @@ ManifestCache::applyManifest(Manifest m)
|
||||
if (iter == map_.end())
|
||||
{
|
||||
if (auto stream = j_.info())
|
||||
logMftAct(stream, "AcceptedNew", m.masterKey, m.sequence);
|
||||
LOG_MANIFEST_ACTION(stream, "AcceptedNew", m.masterKey, m.sequence);
|
||||
|
||||
if (!revoked)
|
||||
signingToMasterKeys_[m.signingKey] = m.masterKey;
|
||||
@@ -489,7 +477,7 @@ ManifestCache::applyManifest(Manifest m)
|
||||
// An ephemeral key was revoked and superseded by a new key. This is
|
||||
// expected, but should happen infrequently.
|
||||
if (auto stream = j_.info())
|
||||
logMftAct(
|
||||
LOG_MANIFEST_ACTION_WITH_OLD(
|
||||
stream,
|
||||
"AcceptedUpdate",
|
||||
m.masterKey,
|
||||
@@ -584,4 +572,9 @@ ManifestCache::save(
|
||||
|
||||
saveManifests(*db, dbTable, isTrusted, map_, j_);
|
||||
}
|
||||
|
||||
// Clean up macros to avoid namespace pollution
|
||||
#undef LOG_MANIFEST_ACTION
|
||||
#undef LOG_MANIFEST_ACTION_WITH_OLD
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
@@ -221,7 +221,8 @@ public:
|
||||
|
||||
if (!ledger->info().accountHash.isNonZero())
|
||||
{
|
||||
JLOG(j.fatal()) << "AH is zero: " << getJson({*ledger, {}});
|
||||
JLOG(j.fatal())
|
||||
<< "AH is zero: " << getJson({*ledger, {}}).asString();
|
||||
assert(false);
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <ripple/protocol/STArray.h>
|
||||
#include <ripple/protocol/STObject.h>
|
||||
#include <ripple/protocol/STTx.h>
|
||||
#include <ripple/protocol/TxFlags.h>
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <exception>
|
||||
@@ -665,6 +666,13 @@ SetHook::preflight(PreflightContext const& ctx)
|
||||
if (!isTesSuccess(ret))
|
||||
return ret;
|
||||
|
||||
if (ctx.rules.enabled(fixInvalidTxFlags) &&
|
||||
ctx.tx.getFlags() & tfUniversalMask)
|
||||
{
|
||||
JLOG(ctx.j.trace()) << "SetHook: Invalid flags set.";
|
||||
return temINVALID_FLAG;
|
||||
}
|
||||
|
||||
if (!ctx.tx.isFieldPresent(sfHooks))
|
||||
{
|
||||
JLOG(ctx.j.trace())
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <ripple/protocol/STArray.h>
|
||||
#include <ripple/protocol/STObject.h>
|
||||
#include <ripple/protocol/STTx.h>
|
||||
#include <ripple/protocol/TxFlags.h>
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
|
||||
@@ -81,6 +82,13 @@ SetSignerList::preflight(PreflightContext const& ctx)
|
||||
if (auto const ret = preflight1(ctx); !isTesSuccess(ret))
|
||||
return ret;
|
||||
|
||||
if (ctx.rules.enabled(fixInvalidTxFlags) &&
|
||||
(ctx.tx.getFlags() & tfUniversalMask))
|
||||
{
|
||||
JLOG(ctx.j.trace()) << "SetSignerList: invalid flags.";
|
||||
return temINVALID_FLAG;
|
||||
}
|
||||
|
||||
auto const result = determineOperation(ctx.tx, ctx.flags, ctx.j);
|
||||
|
||||
if (!isTesSuccess(std::get<0>(result)))
|
||||
|
||||
@@ -249,13 +249,22 @@ private:
|
||||
// Wraps a Journal::Stream to skip evaluation of
|
||||
// expensive argument lists if the stream is not active.
|
||||
#ifndef JLOG
|
||||
#ifdef BEAST_ENHANCED_LOGGING
|
||||
#define JLOG(x) \
|
||||
if (!x) \
|
||||
if (!(x)) \
|
||||
{ \
|
||||
} \
|
||||
else \
|
||||
(x).withLocation(__FILE__, __LINE__)
|
||||
#else
|
||||
#define JLOG(x) \
|
||||
if (!(x)) \
|
||||
{ \
|
||||
} \
|
||||
else \
|
||||
x
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Debug logging:
|
||||
|
||||
@@ -17,11 +17,19 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <date/date.h>
|
||||
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/basics/chrono.h>
|
||||
#include <ripple/basics/contract.h>
|
||||
#ifdef BEAST_ENHANCED_LOGGING
|
||||
#include <ripple/beast/utility/EnhancedLogging.h>
|
||||
#include <date/tz.h>
|
||||
#endif
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
#include <fstream>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
@@ -316,11 +324,46 @@ Logs::format(
|
||||
{
|
||||
output.reserve(message.size() + partition.size() + 100);
|
||||
|
||||
output = to_string(std::chrono::system_clock::now());
|
||||
#ifdef BEAST_ENHANCED_LOGGING
|
||||
// Environment variables are used instead of config file because:
|
||||
// 1. Logging starts before config parsing (needed to debug config issues)
|
||||
// 2. This is a developer feature - devs can easily set env vars
|
||||
// 3. Allows per-run overrides without editing config files
|
||||
static const char* fmt = []() {
|
||||
const char* env = std::getenv("LOG_DATE_FORMAT");
|
||||
return env ? env : "%Y-%b-%d %T %Z"; // Default format
|
||||
}();
|
||||
|
||||
// Check if we should use local time
|
||||
static const bool useLocalTime = []() {
|
||||
const char* env = std::getenv("LOG_DATE_LOCAL");
|
||||
return env && std::strcmp(env, "1") == 0;
|
||||
}();
|
||||
|
||||
if (useLocalTime)
|
||||
{
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto local = date::make_zoned(date::current_zone(), now);
|
||||
output = date::format(fmt, local);
|
||||
}
|
||||
else
|
||||
{
|
||||
output = date::format(fmt, std::chrono::system_clock::now());
|
||||
}
|
||||
#else
|
||||
output = to_string(std::chrono::system_clock::now());
|
||||
#endif
|
||||
|
||||
if (!output.empty()) // Allow setting date format to an empty string
|
||||
output += " ";
|
||||
|
||||
output += " ";
|
||||
if (!partition.empty())
|
||||
{
|
||||
#ifdef BEAST_ENHANCED_LOGGING
|
||||
output += beast::detail::get_log_highlight_color();
|
||||
#endif
|
||||
output += partition + ":";
|
||||
}
|
||||
|
||||
using namespace beast::severities;
|
||||
switch (severity)
|
||||
@@ -348,6 +391,10 @@ Logs::format(
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef BEAST_ENHANCED_LOGGING
|
||||
output += "\033[0m";
|
||||
#endif
|
||||
|
||||
output += message;
|
||||
|
||||
// Limit the maximum length of the output
|
||||
|
||||
85
src/ripple/beast/utility/EnhancedLogging.h
Normal file
85
src/ripple/beast/utility/EnhancedLogging.h
Normal file
@@ -0,0 +1,85 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_UTILITY_ENHANCEDLOGGING_H_INCLUDED
|
||||
#define BEAST_UTILITY_ENHANCEDLOGGING_H_INCLUDED
|
||||
|
||||
#include <cstddef> // for size_t
|
||||
#include <iosfwd> // for std::ostream
|
||||
|
||||
namespace beast {
|
||||
namespace detail {
|
||||
|
||||
// Check if we should use colors - cached at startup
|
||||
bool
|
||||
should_log_use_colors();
|
||||
|
||||
// Get the log highlight color - can be overridden via
|
||||
// LOG_HIGHLIGHT_COLOR
|
||||
const char*
|
||||
get_log_highlight_color();
|
||||
|
||||
// Strip source root path from __FILE__ at compile time
|
||||
// IMPORTANT: This MUST stay in the header as constexpr for compile-time
|
||||
// evaluation!
|
||||
constexpr const char*
|
||||
strip_source_root(const char* file)
|
||||
{
|
||||
#ifdef SOURCE_ROOT_PATH
|
||||
constexpr const char* sourceRoot = SOURCE_ROOT_PATH;
|
||||
constexpr auto strlen_constexpr = [](const char* s) constexpr
|
||||
{
|
||||
const char* p = s;
|
||||
while (*p)
|
||||
++p;
|
||||
return p - s;
|
||||
};
|
||||
constexpr auto strncmp_constexpr =
|
||||
[](const char* a, const char* b, size_t n) constexpr
|
||||
{
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
{
|
||||
if (a[i] != b[i])
|
||||
return a[i] - b[i];
|
||||
if (a[i] == '\0')
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
constexpr size_t sourceRootLen = strlen_constexpr(sourceRoot);
|
||||
return (strncmp_constexpr(file, sourceRoot, sourceRootLen) == 0)
|
||||
? file + sourceRootLen
|
||||
: file;
|
||||
#else
|
||||
return file;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Check if location info should be shown - cached at startup
|
||||
bool
|
||||
should_show_location();
|
||||
|
||||
// Helper to write location string (no leading/trailing space)
|
||||
void
|
||||
log_write_location_string(std::ostream& os, const char* file, int line);
|
||||
|
||||
} // namespace detail
|
||||
} // namespace beast
|
||||
|
||||
#endif
|
||||
@@ -146,6 +146,10 @@ private:
|
||||
|
||||
ScopedStream(Sink& sink, Severity level);
|
||||
|
||||
#ifdef BEAST_ENHANCED_LOGGING
|
||||
ScopedStream(Sink& sink, Severity level, const char* file, int line);
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
ScopedStream(Stream const& stream, T const& t);
|
||||
|
||||
@@ -173,6 +177,10 @@ private:
|
||||
Sink& m_sink;
|
||||
Severity const m_level;
|
||||
std::ostringstream mutable m_ostream;
|
||||
#ifdef BEAST_ENHANCED_LOGGING
|
||||
const char* file_ = nullptr;
|
||||
int line_ = 0;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifndef __INTELLISENSE__
|
||||
@@ -191,6 +199,33 @@ private:
|
||||
//--------------------------------------------------------------------------
|
||||
public:
|
||||
/** Provide a light-weight way to check active() before string formatting */
|
||||
|
||||
#ifdef BEAST_ENHANCED_LOGGING
|
||||
/** Stream with location information that prepends file:line to the first
|
||||
* message */
|
||||
class StreamWithLocation
|
||||
{
|
||||
public:
|
||||
StreamWithLocation(Stream const& stream, const char* file, int line)
|
||||
: file_(file), line_(line), stream_(stream)
|
||||
{
|
||||
}
|
||||
|
||||
/** Override to inject file:line before the first output */
|
||||
template <typename T>
|
||||
ScopedStream
|
||||
operator<<(T const& t) const;
|
||||
|
||||
ScopedStream
|
||||
operator<<(std::ostream& manip(std::ostream&)) const;
|
||||
|
||||
private:
|
||||
const char* file_;
|
||||
int line_;
|
||||
const Stream& stream_;
|
||||
};
|
||||
#endif
|
||||
|
||||
class Stream
|
||||
{
|
||||
public:
|
||||
@@ -255,6 +290,15 @@ public:
|
||||
operator<<(T const& t) const;
|
||||
/** @} */
|
||||
|
||||
#ifdef BEAST_ENHANCED_LOGGING
|
||||
/** Create a StreamWithLocation that prepends file:line info */
|
||||
StreamWithLocation
|
||||
withLocation(const char* file, int line) const
|
||||
{
|
||||
return StreamWithLocation(*this, file, line);
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
Sink& m_sink;
|
||||
Severity m_level;
|
||||
@@ -354,6 +398,8 @@ static_assert(std::is_nothrow_destructible<Journal>::value == true, "");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <typename T>
|
||||
Journal::ScopedStream::ScopedStream(Journal::Stream const& stream, T const& t)
|
||||
: ScopedStream(stream.sink(), stream.level())
|
||||
@@ -378,6 +424,21 @@ Journal::Stream::operator<<(T const& t) const
|
||||
return ScopedStream(*this, t);
|
||||
}
|
||||
|
||||
#ifdef BEAST_ENHANCED_LOGGING
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <typename T>
|
||||
Journal::ScopedStream
|
||||
Journal::StreamWithLocation::operator<<(T const& t) const
|
||||
{
|
||||
// Create a ScopedStream with location info
|
||||
ScopedStream scoped(stream_.sink(), stream_.level(), file_, line_);
|
||||
scoped.ostream() << t;
|
||||
return scoped;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <class CharT, class Traits = std::char_traits<CharT>>
|
||||
|
||||
114
src/ripple/beast/utility/src/beast_EnhancedLogging.cpp
Normal file
114
src/ripple/beast/utility/src/beast_EnhancedLogging.cpp
Normal file
@@ -0,0 +1,114 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/beast/utility/EnhancedLogging.h>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <ostream>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace beast {
|
||||
namespace detail {
|
||||
|
||||
// Check if we should use colors - cached at startup
|
||||
bool
|
||||
should_log_use_colors()
|
||||
{
|
||||
static const bool use_colors = []() {
|
||||
// Honor NO_COLOR environment variable (standard)
|
||||
if (std::getenv("NO_COLOR"))
|
||||
return false;
|
||||
|
||||
// Honor FORCE_COLOR to override terminal detection
|
||||
if (std::getenv("FORCE_COLOR"))
|
||||
return true;
|
||||
|
||||
// Check if stderr is a terminal
|
||||
return isatty(STDERR_FILENO) != 0;
|
||||
}();
|
||||
return use_colors;
|
||||
}
|
||||
|
||||
// Get the log highlight color - can be overridden via
|
||||
// LOG_HIGHLIGHT_COLOR
|
||||
const char*
|
||||
get_log_highlight_color()
|
||||
{
|
||||
static const char* escape = []() {
|
||||
const char* env = std::getenv("LOG_HIGHLIGHT_COLOR");
|
||||
if (!env)
|
||||
return "\033[36m"; // Default: cyan
|
||||
|
||||
// Simple map of color names to escape sequences
|
||||
if (std::strcmp(env, "red") == 0)
|
||||
return "\033[31m";
|
||||
if (std::strcmp(env, "green") == 0)
|
||||
return "\033[32m";
|
||||
if (std::strcmp(env, "yellow") == 0)
|
||||
return "\033[33m";
|
||||
if (std::strcmp(env, "blue") == 0)
|
||||
return "\033[34m";
|
||||
if (std::strcmp(env, "magenta") == 0)
|
||||
return "\033[35m";
|
||||
if (std::strcmp(env, "cyan") == 0)
|
||||
return "\033[36m";
|
||||
if (std::strcmp(env, "white") == 0)
|
||||
return "\033[37m";
|
||||
if (std::strcmp(env, "gray") == 0 || std::strcmp(env, "grey") == 0)
|
||||
return "\033[90m"; // Bright black (gray)
|
||||
if (std::strcmp(env, "orange") == 0)
|
||||
return "\033[93m"; // Bright yellow (appears orange-ish)
|
||||
if (std::strcmp(env, "none") == 0)
|
||||
return "";
|
||||
|
||||
// Default to cyan if unknown color name
|
||||
return "\033[36m";
|
||||
}();
|
||||
return escape;
|
||||
}
|
||||
|
||||
// Check if location info should be shown - cached at startup
|
||||
bool
|
||||
should_show_location()
|
||||
{
|
||||
static const bool show = []() {
|
||||
const char* env = std::getenv("LOG_DISABLE");
|
||||
// Show location by default, hide if LOG_DISABLE=1
|
||||
return !env || std::strcmp(env, "1") != 0;
|
||||
}();
|
||||
return show;
|
||||
}
|
||||
|
||||
// Helper to write location string (no leading/trailing space)
|
||||
void
|
||||
log_write_location_string(std::ostream& os, const char* file, int line)
|
||||
{
|
||||
if (detail::should_log_use_colors())
|
||||
{
|
||||
os << detail::get_log_highlight_color() << "["
|
||||
<< detail::strip_source_root(file) << ":" << line << "]\033[0m";
|
||||
}
|
||||
else
|
||||
{
|
||||
os << "[" << detail::strip_source_root(file) << ":" << line << "]";
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace beast
|
||||
@@ -19,6 +19,11 @@
|
||||
|
||||
#include <ripple/beast/utility/Journal.h>
|
||||
#include <cassert>
|
||||
#ifdef BEAST_ENHANCED_LOGGING
|
||||
#include <ripple/beast/utility/EnhancedLogging.h>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#endif
|
||||
|
||||
namespace beast {
|
||||
|
||||
@@ -131,9 +136,36 @@ Journal::ScopedStream::ScopedStream(
|
||||
m_ostream << manip;
|
||||
}
|
||||
|
||||
#ifdef BEAST_ENHANCED_LOGGING
|
||||
Journal::ScopedStream::ScopedStream(
|
||||
Sink& sink,
|
||||
Severity level,
|
||||
const char* file,
|
||||
int line)
|
||||
: m_sink(sink), m_level(level), file_(file), line_(line)
|
||||
{
|
||||
// Modifiers applied from all ctors
|
||||
m_ostream << std::boolalpha << std::showbase;
|
||||
}
|
||||
#endif
|
||||
|
||||
Journal::ScopedStream::~ScopedStream()
|
||||
{
|
||||
std::string const& s(m_ostream.str());
|
||||
std::string s(m_ostream.str());
|
||||
|
||||
#ifdef BEAST_ENHANCED_LOGGING
|
||||
// Add suffix if location is enabled
|
||||
if (file_ && detail::should_show_location() && !s.empty() && s != "\n")
|
||||
{
|
||||
std::ostringstream combined;
|
||||
combined << s;
|
||||
if (!s.empty() && s.back() != ' ')
|
||||
combined << " ";
|
||||
detail::log_write_location_string(combined, file_, line_);
|
||||
s = combined.str();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!s.empty())
|
||||
{
|
||||
if (s == "\n")
|
||||
@@ -157,4 +189,18 @@ Journal::Stream::operator<<(std::ostream& manip(std::ostream&)) const
|
||||
return ScopedStream(*this, manip);
|
||||
}
|
||||
|
||||
#ifdef BEAST_ENHANCED_LOGGING
|
||||
|
||||
// Implementation moved to use new constructor
|
||||
Journal::ScopedStream
|
||||
Journal::StreamWithLocation::operator<<(
|
||||
std::ostream& manip(std::ostream&)) const
|
||||
{
|
||||
// Create a ScopedStream with location info
|
||||
ScopedStream scoped(stream_.sink(), stream_.level(), file_, line_);
|
||||
scoped.ostream() << manip;
|
||||
return scoped;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace beast
|
||||
|
||||
@@ -239,19 +239,17 @@ verifyHandshake(
|
||||
throw std::runtime_error("Invalid server domain");
|
||||
}
|
||||
|
||||
// Check the network. Omitting Network-ID (on either side ours, or theirs)
|
||||
// means NID=0
|
||||
// Check network ID, treating absent/empty as default network 0
|
||||
{
|
||||
uint32_t peer_nid = 0;
|
||||
std::uint32_t nid{0};
|
||||
|
||||
if (auto const iter = headers.find("Network-ID"); iter != headers.end())
|
||||
{
|
||||
if (!beast::lexicalCastChecked(
|
||||
peer_nid, std::string(iter->value())))
|
||||
if (!beast::lexicalCastChecked(nid, std::string(iter->value())))
|
||||
throw std::runtime_error("Invalid peer network identifier");
|
||||
}
|
||||
|
||||
uint32_t our_nid = networkID ? *networkID : 0;
|
||||
if (peer_nid != our_nid)
|
||||
if (networkID.value_or(0) != nid)
|
||||
throw std::runtime_error("Peer is on a different network");
|
||||
}
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ namespace detail {
|
||||
// Feature.cpp. Because it's only used to reserve storage, and determine how
|
||||
// large to make the FeatureBitset, it MAY be larger. It MUST NOT be less than
|
||||
// the actual number of amendments. A LogicError on startup will verify this.
|
||||
static constexpr std::size_t numFeatures = 85;
|
||||
static constexpr std::size_t numFeatures = 86;
|
||||
|
||||
/** Amendments that this server supports and the default voting behavior.
|
||||
Whether they are enabled depends on the Rules defined in the validated
|
||||
@@ -373,6 +373,7 @@ extern uint256 const fixProvisionalDoubleThreading;
|
||||
extern uint256 const featureClawback;
|
||||
extern uint256 const featureDeepFreeze;
|
||||
extern uint256 const featureIOUIssuerWeakTSH;
|
||||
extern uint256 const fixInvalidTxFlags;
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
|
||||
@@ -479,6 +479,7 @@ REGISTER_FEATURE(Clawback, Supported::yes, VoteBehavior::De
|
||||
REGISTER_FIX (fixProvisionalDoubleThreading, Supported::yes, VoteBehavior::DefaultYes);
|
||||
REGISTER_FEATURE(DeepFreeze, Supported::yes, VoteBehavior::DefaultNo);
|
||||
REGISTER_FEATURE(IOUIssuerWeakTSH, Supported::yes, VoteBehavior::DefaultNo);
|
||||
REGISTER_FIX (fixInvalidTxFlags, Supported::yes, VoteBehavior::DefaultYes);
|
||||
|
||||
// The following amendments are obsolete, but must remain supported
|
||||
// because they could potentially get enabled.
|
||||
|
||||
@@ -5203,8 +5203,8 @@ class Import_test : public beast::unit_test::suite
|
||||
std::string ns_str =
|
||||
"CAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECA"
|
||||
"FE";
|
||||
Json::Value jv = ripple::test::jtx::hook(
|
||||
issuer, {{hso(createCodeHex)}}, hsfOVERRIDE | hsfCOLLECT);
|
||||
Json::Value jv =
|
||||
ripple::test::jtx::hook(issuer, {{hso(createCodeHex)}}, 0);
|
||||
jv[jss::Hooks][0U][jss::Hook][jss::HookNamespace] = ns_str;
|
||||
jv[jss::Hooks][0U][jss::Hook][jss::HookOn] =
|
||||
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDFFFFFFFFFFFFFFFFFFBFFF"
|
||||
|
||||
@@ -1659,6 +1659,36 @@ public:
|
||||
BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
|
||||
}
|
||||
|
||||
void
|
||||
test_signerListSetFlags(FeatureBitset features)
|
||||
{
|
||||
using namespace test::jtx;
|
||||
|
||||
for (bool const withFixInvalidTxFlags : {false, true})
|
||||
{
|
||||
Env env{
|
||||
*this,
|
||||
withFixInvalidTxFlags ? features
|
||||
: features - fixInvalidTxFlags};
|
||||
Account const alice{"alice"};
|
||||
|
||||
env.fund(XRP(1000), alice);
|
||||
env.close();
|
||||
|
||||
bool const enabled = features[fixInvalidTxFlags];
|
||||
testcase(
|
||||
std::string("SignerListSet flag, fix ") +
|
||||
(withFixInvalidTxFlags ? "enabled" : "disabled"));
|
||||
|
||||
ter const expected(
|
||||
withFixInvalidTxFlags ? TER(temINVALID_FLAG) : TER(tesSUCCESS));
|
||||
env(signers(alice, 2, {{bogie, 1}, {ghost, 1}}),
|
||||
expected,
|
||||
txflags(tfPassive));
|
||||
env.close();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testAll(FeatureBitset features)
|
||||
{
|
||||
@@ -1695,6 +1725,9 @@ public:
|
||||
testAll(all - featureMultiSignReserve - featureExpandedSignerList);
|
||||
testAll(all - featureExpandedSignerList);
|
||||
testAll(all);
|
||||
|
||||
test_signerListSetFlags(all);
|
||||
|
||||
test_amendmentTransition();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -364,6 +364,35 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testInvalidTxFlags(FeatureBitset features)
|
||||
{
|
||||
testcase("Checks invalid tx flags");
|
||||
using namespace jtx;
|
||||
|
||||
for (bool const withFixInvalidTxFlags : {false, true})
|
||||
{
|
||||
Env env{
|
||||
*this,
|
||||
withFixInvalidTxFlags ? features
|
||||
: features - fixInvalidTxFlags};
|
||||
|
||||
auto const alice = Account{"alice"};
|
||||
env.fund(XRP(10000), alice);
|
||||
env.close();
|
||||
|
||||
Json::Value jv =
|
||||
ripple::test::jtx::hook(alice, {{{hso_delete()}}}, 0);
|
||||
jv[jss::Flags] = tfUniversalMask;
|
||||
|
||||
env(jv,
|
||||
M("Invalid SetHook flags"),
|
||||
HSFEE,
|
||||
withFixInvalidTxFlags ? ter(temINVALID_FLAG) : ter(tesSUCCESS));
|
||||
env.close();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testGrants(FeatureBitset features)
|
||||
{
|
||||
@@ -12737,6 +12766,7 @@ public:
|
||||
testHooksOwnerDir(features);
|
||||
testHooksDisabled(features);
|
||||
testTxStructure(features);
|
||||
testInvalidTxFlags(features);
|
||||
testInferHookSetOperation();
|
||||
testParams(features);
|
||||
testGrants(features);
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <ripple/beast/utility/Journal.h>
|
||||
#include <ripple/protocol/STLedgerEntry.h>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <regex>
|
||||
#include <test/jtx.h>
|
||||
#include <test/jtx/Env.h>
|
||||
|
||||
@@ -90,10 +91,26 @@ class Invariants_test : public beast::unit_test::suite
|
||||
{
|
||||
terActual = ac.checkInvariants(terActual, fee);
|
||||
BEAST_EXPECT(terExpect == terActual);
|
||||
BEAST_EXPECT(
|
||||
sink.messages().str().starts_with("Invariant failed:") ||
|
||||
sink.messages().str().starts_with(
|
||||
"Transaction caused an exception"));
|
||||
// Handle both with and without BEAST_ENHANCED_LOGGING
|
||||
auto const msg = sink.messages().str();
|
||||
bool hasExpectedPrefix = false;
|
||||
|
||||
#ifdef BEAST_ENHANCED_LOGGING
|
||||
// When BEAST_ENHANCED_LOGGING is enabled, messages may include ANSI
|
||||
// color codes and start with [file:line]. Just search for the
|
||||
// message content.
|
||||
hasExpectedPrefix =
|
||||
msg.find("Invariant failed:") != std::string::npos ||
|
||||
msg.find("Transaction caused an exception") !=
|
||||
std::string::npos;
|
||||
#else
|
||||
// Without BEAST_ENHANCED_LOGGING, messages start directly with the
|
||||
// text
|
||||
hasExpectedPrefix = msg.starts_with("Invariant failed:") ||
|
||||
msg.starts_with("Transaction caused an exception");
|
||||
#endif
|
||||
|
||||
BEAST_EXPECT(hasExpectedPrefix);
|
||||
for (auto const& m : expect_logs)
|
||||
{
|
||||
if (sink.messages().str().find(m) == std::string::npos)
|
||||
|
||||
@@ -523,8 +523,7 @@ class AccountTx_test : public beast::unit_test::suite
|
||||
"0B";
|
||||
Json::Value jhv = hso(updateHookHex);
|
||||
jhv[jss::Flags] = hsfOVERRIDE;
|
||||
Json::Value jv =
|
||||
ripple::test::jtx::hook(account, {{jhv}}, hsfOVERRIDE);
|
||||
Json::Value jv = ripple::test::jtx::hook(account, {{jhv}}, 0);
|
||||
return jv;
|
||||
};
|
||||
env(updateHook(alice), HSFEE, sig(alie));
|
||||
@@ -553,8 +552,7 @@ class AccountTx_test : public beast::unit_test::suite
|
||||
"000000";
|
||||
jhv[jss::HookNamespace] = to_string(uint256{beast::zero});
|
||||
jhv[jss::HookHash] = to_string(hookHash);
|
||||
Json::Value jv =
|
||||
ripple::test::jtx::hook(account, {{jhv}}, hsfOVERRIDE);
|
||||
Json::Value jv = ripple::test::jtx::hook(account, {{jhv}}, 0);
|
||||
return jv;
|
||||
};
|
||||
uint256 const hid = hh(env, alice);
|
||||
@@ -563,8 +561,8 @@ class AccountTx_test : public beast::unit_test::suite
|
||||
|
||||
// Delete Hook
|
||||
auto deleteHook = [](test::jtx::Account const& account) {
|
||||
Json::Value jv = ripple::test::jtx::hook(
|
||||
account, {{hso_delete()}}, hsfOVERRIDE);
|
||||
Json::Value jv =
|
||||
ripple::test::jtx::hook(account, {{hso_delete()}}, 0);
|
||||
return jv;
|
||||
};
|
||||
env(deleteHook(alice), HSFEE, sig(alie));
|
||||
|
||||
Reference in New Issue
Block a user