mirror of
https://github.com/XRPLF/rippled.git
synced 2026-03-18 18:52:33 +00:00
Compare commits
45 Commits
pratik/ote
...
bthomee/io
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f783a15bc8 | ||
|
|
5a94948a04 | ||
|
|
57e4cbbcd9 | ||
|
|
b92a9a3053 | ||
|
|
dcaef828b4 | ||
|
|
6fbeb04d9e | ||
|
|
2a325e7e2c | ||
|
|
808e814489 | ||
|
|
9e14707e77 | ||
|
|
f586382622 | ||
|
|
95a45d7442 | ||
|
|
5fc4ab3e37 | ||
|
|
b129b71c33 | ||
|
|
013c2d6a56 | ||
|
|
72f4cb097f | ||
|
|
b523770486 | ||
|
|
a5185890ff | ||
|
|
0a9513e7f3 | ||
|
|
78b2d70a11 | ||
|
|
252c6768df | ||
|
|
5ae97fa8ae | ||
|
|
eff344faf9 | ||
|
|
7e7b71d84c | ||
|
|
ffea3977f0 | ||
|
|
47a235b7be | ||
|
|
f5e2415c98 | ||
|
|
1a4c359351 | ||
|
|
e4dbaf5efc | ||
|
|
983816248a | ||
|
|
b585dc78bb | ||
|
|
918185e18f | ||
|
|
1738a69619 | ||
|
|
1bf9e6e7da | ||
|
|
0446bef7e5 | ||
|
|
7a3bf1692d | ||
|
|
c1d108e565 | ||
|
|
1ba1bf9ade | ||
|
|
7dd3e0b3cc | ||
|
|
2b14ee3018 | ||
|
|
ce31a7ed16 | ||
|
|
91a23cf80b | ||
|
|
e460ea0840 | ||
|
|
46d5c67a8d | ||
|
|
ce9ccf844a | ||
|
|
c791cae1ec |
71
.clang-tidy
71
.clang-tidy
@@ -8,6 +8,7 @@ Checks: "-*,
|
||||
bugprone-chained-comparison,
|
||||
bugprone-compare-pointer-to-member-virtual-function,
|
||||
bugprone-copy-constructor-init,
|
||||
bugprone-crtp-constructor-accessibility,
|
||||
bugprone-dangling-handle,
|
||||
bugprone-dynamic-static-initializers,
|
||||
bugprone-empty-catch,
|
||||
@@ -59,19 +60,29 @@ Checks: "-*,
|
||||
bugprone-suspicious-string-compare,
|
||||
bugprone-suspicious-stringview-data-usage,
|
||||
bugprone-swapped-arguments,
|
||||
bugprone-switch-missing-default-case,
|
||||
bugprone-terminating-continue,
|
||||
bugprone-throw-keyword-missing,
|
||||
bugprone-too-small-loop-variable,
|
||||
# bugprone-unchecked-optional-access, # see https://github.com/XRPLF/rippled/pull/6502
|
||||
bugprone-undefined-memory-manipulation,
|
||||
bugprone-undelegated-constructor,
|
||||
bugprone-unhandled-exception-at-new,
|
||||
bugprone-unhandled-self-assignment,
|
||||
bugprone-unique-ptr-array-mismatch,
|
||||
bugprone-unsafe-functions,
|
||||
bugprone-use-after-move,
|
||||
bugprone-unused-raii,
|
||||
bugprone-unused-return-value,
|
||||
bugprone-unused-local-non-trivial-variable,
|
||||
bugprone-virtual-near-miss,
|
||||
cppcoreguidelines-init-variables,
|
||||
cppcoreguidelines-misleading-capture-default-by-value,
|
||||
cppcoreguidelines-no-suspend-with-lock,
|
||||
cppcoreguidelines-pro-type-member-init,
|
||||
cppcoreguidelines-pro-type-static-cast-downcast,
|
||||
cppcoreguidelines-rvalue-reference-param-not-moved,
|
||||
cppcoreguidelines-use-default-member-init,
|
||||
cppcoreguidelines-virtual-class-destructor,
|
||||
hicpp-ignored-remove-result,
|
||||
misc-definitions-in-headers,
|
||||
@@ -81,62 +92,48 @@ Checks: "-*,
|
||||
misc-throw-by-value-catch-by-reference,
|
||||
misc-unused-alias-decls,
|
||||
misc-unused-using-decls,
|
||||
readability-duplicate-include,
|
||||
readability-enum-initial-value,
|
||||
readability-misleading-indentation,
|
||||
readability-non-const-parameter,
|
||||
readability-redundant-declaration,
|
||||
readability-reference-to-constructed-temporary,
|
||||
modernize-deprecated-headers,
|
||||
modernize-make-shared,
|
||||
modernize-make-unique,
|
||||
performance-implicit-conversion-in-loop,
|
||||
performance-move-constructor-init,
|
||||
performance-trivially-destructible
|
||||
performance-trivially-destructible,
|
||||
readability-avoid-nested-conditional-operator,
|
||||
readability-avoid-return-with-void-value,
|
||||
readability-braces-around-statements,
|
||||
readability-const-return-type,
|
||||
readability-container-contains,
|
||||
readability-container-size-empty,
|
||||
readability-duplicate-include,
|
||||
readability-else-after-return,
|
||||
readability-enum-initial-value,
|
||||
readability-make-member-function-const,
|
||||
readability-misleading-indentation,
|
||||
readability-non-const-parameter,
|
||||
readability-redundant-casting,
|
||||
readability-redundant-declaration,
|
||||
readability-redundant-inline-specifier,
|
||||
readability-redundant-member-init,
|
||||
readability-redundant-string-init,
|
||||
readability-reference-to-constructed-temporary,
|
||||
readability-static-definition-in-anonymous-namespace,
|
||||
readability-use-std-min-max
|
||||
"
|
||||
# ---
|
||||
# checks that have some issues that need to be resolved:
|
||||
#
|
||||
# bugprone-crtp-constructor-accessibility,
|
||||
# bugprone-move-forwarding-reference,
|
||||
# bugprone-switch-missing-default-case,
|
||||
# bugprone-unused-raii,
|
||||
# bugprone-unused-return-value,
|
||||
# bugprone-use-after-move,
|
||||
#
|
||||
# cppcoreguidelines-misleading-capture-default-by-value,
|
||||
# cppcoreguidelines-init-variables,
|
||||
# cppcoreguidelines-pro-type-member-init,
|
||||
# cppcoreguidelines-pro-type-static-cast-downcast,
|
||||
# cppcoreguidelines-use-default-member-init,
|
||||
# cppcoreguidelines-rvalue-reference-param-not-moved,
|
||||
#
|
||||
# llvm-namespace-comment,
|
||||
# misc-const-correctness,
|
||||
# misc-include-cleaner,
|
||||
# misc-redundant-expression,
|
||||
#
|
||||
# readability-avoid-nested-conditional-operator,
|
||||
# readability-avoid-return-with-void-value,
|
||||
# readability-braces-around-statements,
|
||||
# readability-container-contains,
|
||||
# readability-container-size-empty,
|
||||
# readability-convert-member-functions-to-static,
|
||||
# readability-const-return-type,
|
||||
# readability-else-after-return,
|
||||
# readability-implicit-bool-conversion,
|
||||
# readability-inconsistent-declaration-parameter-name,
|
||||
# readability-identifier-naming,
|
||||
# readability-make-member-function-const,
|
||||
# readability-math-missing-parentheses,
|
||||
# readability-redundant-inline-specifier,
|
||||
# readability-redundant-member-init,
|
||||
# readability-redundant-casting,
|
||||
# readability-redundant-string-init,
|
||||
# readability-simplify-boolean-expr,
|
||||
# readability-static-definition-in-anonymous-namespace,
|
||||
# readability-suspicious-call-argument,
|
||||
# readability-use-std-min-max,
|
||||
# readability-static-accessed-through-instance,
|
||||
#
|
||||
# modernize-concat-nested-namespaces,
|
||||
@@ -160,7 +157,7 @@ Checks: "-*,
|
||||
# ---
|
||||
#
|
||||
CheckOptions:
|
||||
# readability-braces-around-statements.ShortStatementLines: 2
|
||||
readability-braces-around-statements.ShortStatementLines: 2
|
||||
# readability-identifier-naming.MacroDefinitionCase: UPPER_CASE
|
||||
# readability-identifier-naming.ClassCase: CamelCase
|
||||
# readability-identifier-naming.StructCase: CamelCase
|
||||
@@ -195,7 +192,7 @@ CheckOptions:
|
||||
# readability-identifier-naming.PublicMemberSuffix: ""
|
||||
# readability-identifier-naming.FunctionIgnoredRegexp: ".*tag_invoke.*"
|
||||
bugprone-unsafe-functions.ReportMoreUnsafeFunctions: true
|
||||
# bugprone-unused-return-value.CheckedReturnTypes: ::std::error_code;::std::error_condition;::std::errc
|
||||
bugprone-unused-return-value.CheckedReturnTypes: ::std::error_code;::std::error_condition;::std::errc
|
||||
# misc-include-cleaner.IgnoreHeaders: '.*/(detail|impl)/.*;.*(expected|unexpected).*;.*ranges_lower_bound\.h;time.h;stdlib.h;__chrono/.*;fmt/chrono.h;boost/uuid/uuid_hash.hpp'
|
||||
#
|
||||
# HeaderFilterRegex: '^.*/(src|tests)/.*\.(h|hpp)$'
|
||||
|
||||
16
.github/pull_request_template.md
vendored
16
.github/pull_request_template.md
vendored
@@ -29,22 +29,6 @@ If a refactor, how is this better than the previous implementation?
|
||||
If there is a spec or design document for this feature, please link it here.
|
||||
-->
|
||||
|
||||
### Type of Change
|
||||
|
||||
<!--
|
||||
Please check [x] relevant options, delete irrelevant ones.
|
||||
-->
|
||||
|
||||
- [ ] Bug fix (non-breaking change which fixes an issue)
|
||||
- [ ] New feature (non-breaking change which adds functionality)
|
||||
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
|
||||
- [ ] Refactor (non-breaking change that only restructures code)
|
||||
- [ ] Performance (increase or change in throughput and/or latency)
|
||||
- [ ] Tests (you added tests for code that already exists, or your new feature included in this PR)
|
||||
- [ ] Documentation update
|
||||
- [ ] Chore (no impact to binary, e.g. `.gitignore`, formatting, dropping support for older tooling)
|
||||
- [ ] Release
|
||||
|
||||
### API Impact
|
||||
|
||||
<!--
|
||||
|
||||
6
.github/scripts/levelization/README.md
vendored
6
.github/scripts/levelization/README.md
vendored
@@ -70,7 +70,7 @@ that `test` code should _never_ be included in `xrpl` or `xrpld` code.)
|
||||
|
||||
## Validation
|
||||
|
||||
The [levelization](generate.sh) script takes no parameters,
|
||||
The [levelization](generate.py) script takes no parameters,
|
||||
reads no environment variables, and can be run from any directory,
|
||||
as long as it is in the expected location in the rippled repo.
|
||||
It can be run at any time from within a checked out repo, and will
|
||||
@@ -104,7 +104,7 @@ It generates many files of [results](results):
|
||||
Github Actions workflow to test that levelization loops haven't
|
||||
changed. Unfortunately, if changes are detected, it can't tell if
|
||||
they are improvements or not, so if you have resolved any issues or
|
||||
done anything else to improve levelization, run `levelization.sh`,
|
||||
done anything else to improve levelization, run `generate.py`,
|
||||
and commit the updated results.
|
||||
|
||||
The `loops.txt` and `ordering.txt` files relate the modules
|
||||
@@ -128,7 +128,7 @@ The committed files hide the detailed values intentionally, to
|
||||
prevent false alarms and merging issues, and because it's easy to
|
||||
get those details locally.
|
||||
|
||||
1. Run `levelization.sh`
|
||||
1. Run `generate.py`
|
||||
2. Grep the modules in `paths.txt`.
|
||||
- For example, if a cycle is found `A ~= B`, simply `grep -w
|
||||
A .github/scripts/levelization/results/paths.txt | grep -w B`
|
||||
|
||||
335
.github/scripts/levelization/generate.py
vendored
Normal file
335
.github/scripts/levelization/generate.py
vendored
Normal file
@@ -0,0 +1,335 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
Usage: generate.py
|
||||
This script takes no parameters, and can be called from any directory in the file system.
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, Tuple, Set, Optional
|
||||
|
||||
# Compile regex patterns once at module level
|
||||
INCLUDE_PATTERN = re.compile(r"^\s*#include.*/.*\.h")
|
||||
INCLUDE_PATH_PATTERN = re.compile(r'[<"]([^>"]+)[>"]')
|
||||
|
||||
|
||||
def dictionary_sort_key(s: str) -> str:
|
||||
"""
|
||||
Create a sort key that mimics 'sort -d' (dictionary order).
|
||||
Dictionary order only considers blanks and alphanumeric characters.
|
||||
This means punctuation like '.' is ignored during sorting.
|
||||
"""
|
||||
# Keep only alphanumeric characters and spaces
|
||||
return "".join(c for c in s if c.isalnum() or c.isspace())
|
||||
|
||||
|
||||
def get_level(file_path: str) -> str:
|
||||
"""
|
||||
Extract the level from a file path (second and third directory components).
|
||||
Equivalent to bash: cut -d/ -f 2,3
|
||||
|
||||
Examples:
|
||||
src/xrpld/app/main.cpp -> xrpld.app
|
||||
src/libxrpl/protocol/STObject.cpp -> libxrpl.protocol
|
||||
include/xrpl/basics/base_uint.h -> xrpl.basics
|
||||
"""
|
||||
parts = file_path.split("/")
|
||||
|
||||
# Get fields 2 and 3 (indices 1 and 2 in 0-based indexing)
|
||||
if len(parts) >= 3:
|
||||
level = f"{parts[1]}/{parts[2]}"
|
||||
elif len(parts) >= 2:
|
||||
level = f"{parts[1]}/toplevel"
|
||||
else:
|
||||
level = file_path
|
||||
|
||||
# If the "level" indicates a file, cut off the filename
|
||||
if "." in level.split("/")[-1]: # Avoid Path object creation
|
||||
# Use the "toplevel" label as a workaround for `sort`
|
||||
# inconsistencies between different utility versions
|
||||
level = level.rsplit("/", 1)[0] + "/toplevel"
|
||||
|
||||
return level.replace("/", ".")
|
||||
|
||||
|
||||
def extract_include_level(include_line: str) -> Optional[str]:
|
||||
"""
|
||||
Extract the include path from an #include directive.
|
||||
Gets the first two directory components from the include path.
|
||||
Equivalent to bash: cut -d/ -f 1,2
|
||||
|
||||
Examples:
|
||||
#include <xrpl/basics/base_uint.h> -> xrpl.basics
|
||||
#include "xrpld/app/main/Application.h" -> xrpld.app
|
||||
"""
|
||||
# Remove everything before the quote or angle bracket
|
||||
match = INCLUDE_PATH_PATTERN.search(include_line)
|
||||
if not match:
|
||||
return None
|
||||
|
||||
include_path = match.group(1)
|
||||
parts = include_path.split("/")
|
||||
|
||||
# Get first two fields (indices 0 and 1)
|
||||
if len(parts) >= 2:
|
||||
include_level = f"{parts[0]}/{parts[1]}"
|
||||
else:
|
||||
include_level = include_path
|
||||
|
||||
# If the "includelevel" indicates a file, cut off the filename
|
||||
if "." in include_level.split("/")[-1]: # Avoid Path object creation
|
||||
include_level = include_level.rsplit("/", 1)[0] + "/toplevel"
|
||||
|
||||
return include_level.replace("/", ".")
|
||||
|
||||
|
||||
def find_repository_directories(
|
||||
start_path: Path, depth_limit: int = 10
|
||||
) -> Tuple[Path, List[Path]]:
|
||||
"""
|
||||
Find the repository root by looking for src or include folders.
|
||||
Walks up the directory tree from the start path.
|
||||
"""
|
||||
current = start_path.resolve()
|
||||
|
||||
# Walk up the directory tree
|
||||
for _ in range(depth_limit): # Limit search depth to prevent infinite loops
|
||||
src_path = current / "src"
|
||||
include_path = current / "include"
|
||||
# Check if this directory has src or include folders
|
||||
has_src = src_path.exists()
|
||||
has_include = include_path.exists()
|
||||
|
||||
if has_src or has_include:
|
||||
return current, [src_path, include_path]
|
||||
|
||||
# Move up one level
|
||||
parent = current.parent
|
||||
if parent == current: # Reached filesystem root
|
||||
break
|
||||
current = parent
|
||||
|
||||
# If we couldn't find it, raise an error
|
||||
raise RuntimeError(
|
||||
"Could not find repository root. "
|
||||
"Expected to find a directory containing 'src' and/or 'include' folders."
|
||||
)
|
||||
|
||||
|
||||
def main():
|
||||
# Change to the script's directory
|
||||
script_dir = Path(__file__).parent.resolve()
|
||||
os.chdir(script_dir)
|
||||
|
||||
# Clean up and create results directory.
|
||||
results_dir = script_dir / "results"
|
||||
if results_dir.exists():
|
||||
import shutil
|
||||
|
||||
shutil.rmtree(results_dir)
|
||||
results_dir.mkdir()
|
||||
|
||||
# Find the repository root by searching for src and include directories.
|
||||
try:
|
||||
repo_root, scan_dirs = find_repository_directories(script_dir)
|
||||
|
||||
print(f"Found repository root: {repo_root}")
|
||||
print(f"Scanning directories:")
|
||||
for scan_dir in scan_dirs:
|
||||
print(f" - {scan_dir.relative_to(repo_root)}")
|
||||
except RuntimeError as e:
|
||||
print(f"Error: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
print("\nScanning for raw includes...")
|
||||
# Find all #include directives
|
||||
raw_includes: List[Tuple[str, str]] = []
|
||||
rawincludes_file = results_dir / "rawincludes.txt"
|
||||
|
||||
# Write to file as we go to avoid storing everything in memory.
|
||||
with open(rawincludes_file, "w", buffering=8192) as raw_f:
|
||||
for dir_path in scan_dirs:
|
||||
print(f" Scanning {dir_path.relative_to(repo_root)}...")
|
||||
|
||||
for file_path in dir_path.rglob("*"):
|
||||
if not file_path.is_file():
|
||||
continue
|
||||
|
||||
try:
|
||||
rel_path_str = str(file_path.relative_to(repo_root))
|
||||
|
||||
# Read file with a large buffer for performance.
|
||||
with open(
|
||||
file_path,
|
||||
"r",
|
||||
encoding="utf-8",
|
||||
errors="ignore",
|
||||
buffering=8192,
|
||||
) as f:
|
||||
for line in f:
|
||||
# Quick check before regex
|
||||
if "#include" not in line or "boost" in line:
|
||||
continue
|
||||
|
||||
if INCLUDE_PATTERN.match(line):
|
||||
line_stripped = line.strip()
|
||||
entry = f"{rel_path_str}:{line_stripped}\n"
|
||||
print(entry, end="")
|
||||
raw_f.write(entry)
|
||||
raw_includes.append((rel_path_str, line_stripped))
|
||||
except Exception as e:
|
||||
print(f"Error reading {file_path}: {e}", file=sys.stderr)
|
||||
|
||||
# Build levelization paths and count directly (no need to sort first).
|
||||
print("Build levelization paths")
|
||||
path_counts: Dict[Tuple[str, str], int] = defaultdict(int)
|
||||
|
||||
for file_path, include_line in raw_includes:
|
||||
include_level = extract_include_level(include_line)
|
||||
if not include_level:
|
||||
continue
|
||||
|
||||
level = get_level(file_path)
|
||||
if level != include_level:
|
||||
path_counts[(level, include_level)] += 1
|
||||
|
||||
# Sort and deduplicate paths (using dictionary order like bash 'sort -d').
|
||||
print("Sort and deduplicate paths")
|
||||
|
||||
paths_file = results_dir / "paths.txt"
|
||||
with open(paths_file, "w") as f:
|
||||
# Sort using dictionary order: only alphanumeric and spaces matter
|
||||
sorted_items = sorted(
|
||||
path_counts.items(),
|
||||
key=lambda x: (dictionary_sort_key(x[0][0]), dictionary_sort_key(x[0][1])),
|
||||
)
|
||||
for (level, include_level), count in sorted_items:
|
||||
line = f"{count:7} {level} {include_level}\n"
|
||||
print(line.rstrip())
|
||||
f.write(line)
|
||||
|
||||
# Split into flat-file database
|
||||
print("Split into flat-file database")
|
||||
includes_dir = results_dir / "includes"
|
||||
included_by_dir = results_dir / "included_by"
|
||||
includes_dir.mkdir()
|
||||
included_by_dir.mkdir()
|
||||
|
||||
# Batch writes by grouping data first to avoid repeated file opens.
|
||||
includes_data: Dict[str, List[Tuple[str, int]]] = defaultdict(list)
|
||||
included_by_data: Dict[str, List[Tuple[str, int]]] = defaultdict(list)
|
||||
|
||||
# Process in sorted order to match bash script behaviour (dictionary order).
|
||||
sorted_items = sorted(
|
||||
path_counts.items(),
|
||||
key=lambda x: (dictionary_sort_key(x[0][0]), dictionary_sort_key(x[0][1])),
|
||||
)
|
||||
for (level, include_level), count in sorted_items:
|
||||
includes_data[level].append((include_level, count))
|
||||
included_by_data[include_level].append((level, count))
|
||||
|
||||
# Write all includes files in sorted order (dictionary order).
|
||||
for level in sorted(includes_data.keys(), key=dictionary_sort_key):
|
||||
entries = includes_data[level]
|
||||
with open(includes_dir / level, "w") as f:
|
||||
for include_level, count in entries:
|
||||
line = f"{include_level} {count}\n"
|
||||
print(line.rstrip())
|
||||
f.write(line)
|
||||
|
||||
# Write all included_by files in sorted order (dictionary order).
|
||||
for include_level in sorted(included_by_data.keys(), key=dictionary_sort_key):
|
||||
entries = included_by_data[include_level]
|
||||
with open(included_by_dir / include_level, "w") as f:
|
||||
for level, count in entries:
|
||||
line = f"{level} {count}\n"
|
||||
print(line.rstrip())
|
||||
f.write(line)
|
||||
|
||||
# Search for loops
|
||||
print("Search for loops")
|
||||
loops_file = results_dir / "loops.txt"
|
||||
ordering_file = results_dir / "ordering.txt"
|
||||
|
||||
loops_found: Set[Tuple[str, str]] = set()
|
||||
|
||||
# Pre-load all include files into memory to avoid repeated I/O.
|
||||
# This is the biggest optimisation - we were reading files repeatedly in nested loops.
|
||||
# Use list of tuples to preserve file order.
|
||||
includes_cache: Dict[str, List[Tuple[str, int]]] = {}
|
||||
includes_lookup: Dict[str, Dict[str, int]] = {} # For fast lookup
|
||||
|
||||
# Note: bash script uses 'for source in *' which uses standard glob sorting,
|
||||
# NOT dictionary order. So we use standard sorted() here, not dictionary_sort_key.
|
||||
for include_file in sorted(includes_dir.iterdir(), key=lambda p: p.name):
|
||||
if not include_file.is_file():
|
||||
continue
|
||||
|
||||
includes_cache[include_file.name] = []
|
||||
includes_lookup[include_file.name] = {}
|
||||
with open(include_file, "r") as f:
|
||||
for line in f:
|
||||
parts = line.strip().split()
|
||||
if len(parts) >= 2:
|
||||
include_name = parts[0]
|
||||
include_count = int(parts[1])
|
||||
includes_cache[include_file.name].append(
|
||||
(include_name, include_count)
|
||||
)
|
||||
includes_lookup[include_file.name][include_name] = include_count
|
||||
|
||||
with open(loops_file, "w", buffering=8192) as loops_f, open(
|
||||
ordering_file, "w", buffering=8192
|
||||
) as ordering_f:
|
||||
|
||||
# Use standard sorting to match bash glob expansion 'for source in *'.
|
||||
for source in sorted(includes_cache.keys()):
|
||||
source_includes = includes_cache[source]
|
||||
|
||||
for include, include_freq in source_includes:
|
||||
# Check if include file exists and references source
|
||||
if include not in includes_lookup:
|
||||
continue
|
||||
|
||||
source_freq = includes_lookup[include].get(source)
|
||||
|
||||
if source_freq is not None:
|
||||
# Found a loop
|
||||
loop_key = tuple(sorted([source, include]))
|
||||
if loop_key in loops_found:
|
||||
continue
|
||||
loops_found.add(loop_key)
|
||||
|
||||
loops_f.write(f"Loop: {source} {include}\n")
|
||||
|
||||
# If the counts are close, indicate that the two modules are
|
||||
# on the same level, though they shouldn't be.
|
||||
diff = include_freq - source_freq
|
||||
if diff > 3:
|
||||
loops_f.write(f" {source} > {include}\n\n")
|
||||
elif diff < -3:
|
||||
loops_f.write(f" {include} > {source}\n\n")
|
||||
elif source_freq == include_freq:
|
||||
loops_f.write(f" {include} == {source}\n\n")
|
||||
else:
|
||||
loops_f.write(f" {include} ~= {source}\n\n")
|
||||
else:
|
||||
ordering_f.write(f"{source} > {include}\n")
|
||||
|
||||
# Print results
|
||||
print("\nOrdering:")
|
||||
with open(ordering_file, "r") as f:
|
||||
print(f.read(), end="")
|
||||
|
||||
print("\nLoops:")
|
||||
with open(loops_file, "r") as f:
|
||||
print(f.read(), end="")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
130
.github/scripts/levelization/generate.sh
vendored
130
.github/scripts/levelization/generate.sh
vendored
@@ -1,130 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Usage: generate.sh
|
||||
# This script takes no parameters, reads no environment variables,
|
||||
# and can be run from any directory, as long as it is in the expected
|
||||
# location in the repo.
|
||||
|
||||
pushd $( dirname $0 )
|
||||
|
||||
if [ -v PS1 ]
|
||||
then
|
||||
# if the shell is interactive, clean up any flotsam before analyzing
|
||||
git clean -ix
|
||||
fi
|
||||
|
||||
# Ensure all sorting is ASCII-order consistently across platforms.
|
||||
export LANG=C
|
||||
|
||||
rm -rfv results
|
||||
mkdir results
|
||||
includes="$( pwd )/results/rawincludes.txt"
|
||||
pushd ../../..
|
||||
echo Raw includes:
|
||||
grep -r '^[ ]*#include.*/.*\.h' include src | \
|
||||
grep -v boost | tee ${includes}
|
||||
popd
|
||||
pushd results
|
||||
|
||||
oldifs=${IFS}
|
||||
IFS=:
|
||||
mkdir includes
|
||||
mkdir included_by
|
||||
echo Build levelization paths
|
||||
exec 3< ${includes} # open rawincludes.txt for input
|
||||
while read -r -u 3 file include
|
||||
do
|
||||
level=$( echo ${file} | cut -d/ -f 2,3 )
|
||||
# If the "level" indicates a file, cut off the filename
|
||||
if [[ "${level##*.}" != "${level}" ]]
|
||||
then
|
||||
# Use the "toplevel" label as a workaround for `sort`
|
||||
# inconsistencies between different utility versions
|
||||
level="$( dirname ${level} )/toplevel"
|
||||
fi
|
||||
level=$( echo ${level} | tr '/' '.' )
|
||||
|
||||
includelevel=$( echo ${include} | sed 's/.*["<]//; s/[">].*//' | \
|
||||
cut -d/ -f 1,2 )
|
||||
if [[ "${includelevel##*.}" != "${includelevel}" ]]
|
||||
then
|
||||
# Use the "toplevel" label as a workaround for `sort`
|
||||
# inconsistencies between different utility versions
|
||||
includelevel="$( dirname ${includelevel} )/toplevel"
|
||||
fi
|
||||
includelevel=$( echo ${includelevel} | tr '/' '.' )
|
||||
|
||||
if [[ "$level" != "$includelevel" ]]
|
||||
then
|
||||
echo $level $includelevel | tee -a paths.txt
|
||||
fi
|
||||
done
|
||||
echo Sort and deduplicate paths
|
||||
sort -ds paths.txt | uniq -c | tee sortedpaths.txt
|
||||
mv sortedpaths.txt paths.txt
|
||||
exec 3>&- #close fd 3
|
||||
IFS=${oldifs}
|
||||
unset oldifs
|
||||
|
||||
echo Split into flat-file database
|
||||
exec 4<paths.txt # open paths.txt for input
|
||||
while read -r -u 4 count level include
|
||||
do
|
||||
echo ${include} ${count} | tee -a includes/${level}
|
||||
echo ${level} ${count} | tee -a included_by/${include}
|
||||
done
|
||||
exec 4>&- #close fd 4
|
||||
|
||||
loops="$( pwd )/loops.txt"
|
||||
ordering="$( pwd )/ordering.txt"
|
||||
pushd includes
|
||||
echo Search for loops
|
||||
# Redirect stdout to a file
|
||||
exec 4>&1
|
||||
exec 1>"${loops}"
|
||||
for source in *
|
||||
do
|
||||
if [[ -f "$source" ]]
|
||||
then
|
||||
exec 5<"${source}" # open for input
|
||||
while read -r -u 5 include includefreq
|
||||
do
|
||||
if [[ -f $include ]]
|
||||
then
|
||||
if grep -q -w $source $include
|
||||
then
|
||||
if grep -q -w "Loop: $include $source" "${loops}"
|
||||
then
|
||||
continue
|
||||
fi
|
||||
sourcefreq=$( grep -w $source $include | cut -d\ -f2 )
|
||||
echo "Loop: $source $include"
|
||||
# If the counts are close, indicate that the two modules are
|
||||
# on the same level, though they shouldn't be
|
||||
if [[ $(( $includefreq - $sourcefreq )) -gt 3 ]]
|
||||
then
|
||||
echo -e " $source > $include\n"
|
||||
elif [[ $(( $sourcefreq - $includefreq )) -gt 3 ]]
|
||||
then
|
||||
echo -e " $include > $source\n"
|
||||
elif [[ $sourcefreq -eq $includefreq ]]
|
||||
then
|
||||
echo -e " $include == $source\n"
|
||||
else
|
||||
echo -e " $include ~= $source\n"
|
||||
fi
|
||||
else
|
||||
echo "$source > $include" >> "${ordering}"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
exec 5>&- #close fd 5
|
||||
fi
|
||||
done
|
||||
exec 1>&4 #close fd 1
|
||||
exec 4>&- #close fd 4
|
||||
cat "${ordering}"
|
||||
cat "${loops}"
|
||||
popd
|
||||
popd
|
||||
popd
|
||||
@@ -134,6 +134,7 @@ test.peerfinder > xrpld.core
|
||||
test.peerfinder > xrpld.peerfinder
|
||||
test.peerfinder > xrpl.protocol
|
||||
test.protocol > test.toplevel
|
||||
test.protocol > test.unit_test
|
||||
test.protocol > xrpl.basics
|
||||
test.protocol > xrpl.json
|
||||
test.protocol > xrpl.protocol
|
||||
@@ -171,6 +172,7 @@ test.shamap > xrpl.shamap
|
||||
test.toplevel > test.csf
|
||||
test.toplevel > xrpl.json
|
||||
test.unit_test > xrpl.basics
|
||||
test.unit_test > xrpl.protocol
|
||||
tests.libxrpl > xrpl.basics
|
||||
tests.libxrpl > xrpl.json
|
||||
tests.libxrpl > xrpl.net
|
||||
|
||||
5
.github/workflows/check-pr-title.yml
vendored
5
.github/workflows/check-pr-title.yml
vendored
@@ -1,10 +1,13 @@
|
||||
name: Check PR title
|
||||
|
||||
on:
|
||||
merge_group:
|
||||
types:
|
||||
- checks_requested
|
||||
pull_request:
|
||||
types: [opened, edited, reopened, synchronize]
|
||||
branches: [develop]
|
||||
|
||||
jobs:
|
||||
check_title:
|
||||
uses: XRPLF/actions/.github/workflows/check-pr-title.yml@943eb8277e8f4b010fde0c826ce4154c36c39509
|
||||
uses: XRPLF/actions/.github/workflows/check-pr-title.yml@c6311685db43aa07971c4a6764320fecbc2acdcd
|
||||
|
||||
3
.github/workflows/pre-commit.yml
vendored
3
.github/workflows/pre-commit.yml
vendored
@@ -1,6 +1,9 @@
|
||||
name: Run pre-commit hooks
|
||||
|
||||
on:
|
||||
merge_group:
|
||||
types:
|
||||
- checks_requested
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
|
||||
18
.github/workflows/reusable-build-test-config.yml
vendored
18
.github/workflows/reusable-build-test-config.yml
vendored
@@ -76,7 +76,7 @@ jobs:
|
||||
name: ${{ inputs.config_name }}
|
||||
runs-on: ${{ fromJSON(inputs.runs_on) }}
|
||||
container: ${{ inputs.image != '' && inputs.image || null }}
|
||||
timeout-minutes: 60
|
||||
timeout-minutes: ${{ inputs.sanitizers != '' && 360 || 60 }}
|
||||
env:
|
||||
# Use a namespace to keep the objects separate for each configuration.
|
||||
CCACHE_NAMESPACE: ${{ inputs.config_name }}
|
||||
@@ -204,11 +204,17 @@ jobs:
|
||||
|
||||
- name: Set sanitizer options
|
||||
if: ${{ !inputs.build_only && env.SANITIZERS_ENABLED == 'true' }}
|
||||
env:
|
||||
CONFIG_NAME: ${{ inputs.config_name }}
|
||||
run: |
|
||||
echo "ASAN_OPTIONS=print_stacktrace=1:detect_container_overflow=0:suppressions=${GITHUB_WORKSPACE}/sanitizers/suppressions/asan.supp" >> ${GITHUB_ENV}
|
||||
echo "TSAN_OPTIONS=second_deadlock_stack=1:halt_on_error=0:suppressions=${GITHUB_WORKSPACE}/sanitizers/suppressions/tsan.supp" >> ${GITHUB_ENV}
|
||||
echo "UBSAN_OPTIONS=suppressions=${GITHUB_WORKSPACE}/sanitizers/suppressions/ubsan.supp" >> ${GITHUB_ENV}
|
||||
echo "LSAN_OPTIONS=suppressions=${GITHUB_WORKSPACE}/sanitizers/suppressions/lsan.supp" >> ${GITHUB_ENV}
|
||||
ASAN_OPTS="include=${GITHUB_WORKSPACE}/sanitizers/suppressions/runtime-asan-options.txt:suppressions=${GITHUB_WORKSPACE}/sanitizers/suppressions/asan.supp"
|
||||
if [[ "${CONFIG_NAME}" == *gcc* ]]; then
|
||||
ASAN_OPTS="${ASAN_OPTS}:alloc_dealloc_mismatch=0"
|
||||
fi
|
||||
echo "ASAN_OPTIONS=${ASAN_OPTS}" >> ${GITHUB_ENV}
|
||||
echo "TSAN_OPTIONS=include=${GITHUB_WORKSPACE}/sanitizers/suppressions/runtime-tsan-options.txt:suppressions=${GITHUB_WORKSPACE}/sanitizers/suppressions/tsan.supp" >> ${GITHUB_ENV}
|
||||
echo "UBSAN_OPTIONS=include=${GITHUB_WORKSPACE}/sanitizers/suppressions/runtime-ubsan-options.txt:suppressions=${GITHUB_WORKSPACE}/sanitizers/suppressions/ubsan.supp" >> ${GITHUB_ENV}
|
||||
echo "LSAN_OPTIONS=include=${GITHUB_WORKSPACE}/sanitizers/suppressions/runtime-lsan-options.txt:suppressions=${GITHUB_WORKSPACE}/sanitizers/suppressions/lsan.supp" >> ${GITHUB_ENV}
|
||||
|
||||
- name: Run the separate tests
|
||||
if: ${{ !inputs.build_only }}
|
||||
@@ -230,6 +236,8 @@ jobs:
|
||||
BUILD_NPROC: ${{ steps.nproc.outputs.nproc }}
|
||||
run: |
|
||||
set -o pipefail
|
||||
# Coverage builds are slower due to instrumentation; use fewer parallel jobs to avoid flakiness
|
||||
[ "$COVERAGE_ENABLED" = "true" ] && BUILD_NPROC=$(( BUILD_NPROC - 2 ))
|
||||
./xrpld --unittest --unittest-jobs "${BUILD_NPROC}" 2>&1 | tee unittest.log
|
||||
|
||||
- name: Show test failure summary
|
||||
|
||||
@@ -20,7 +20,7 @@ jobs:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- name: Check levelization
|
||||
run: .github/scripts/levelization/generate.sh
|
||||
run: python .github/scripts/levelization/generate.py
|
||||
- name: Check for differences
|
||||
env:
|
||||
MESSAGE: |
|
||||
@@ -32,7 +32,7 @@ jobs:
|
||||
removed from loops.txt, it's probably an improvement, while if
|
||||
something was added, it's probably a regression.
|
||||
|
||||
Run '.github/scripts/levelization/generate.sh' in your repo, commit
|
||||
Run '.github/scripts/levelization/generate.py' in your repo, commit
|
||||
and push the changes. See .github/scripts/levelization/README.md for
|
||||
more info.
|
||||
run: |
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -75,6 +75,9 @@ DerivedData
|
||||
/.claude
|
||||
/CLAUDE.md
|
||||
|
||||
# Python
|
||||
__pycache__
|
||||
|
||||
# Direnv's directory
|
||||
/.direnv
|
||||
|
||||
|
||||
@@ -35,6 +35,10 @@ This section contains changes targeting a future version.
|
||||
- `LEDGER_ENTRY_FLAGS`: Maps ledger entry type names to their flags and flag values.
|
||||
- `ACCOUNT_SET_FLAGS`: Maps AccountSet flag names (asf flags) to their numeric values.
|
||||
|
||||
### Bugfixes
|
||||
|
||||
- Peer Crawler: The `port` field in `overlay.active[]` now consistently returns an integer instead of a string for outbound peers. [#6318](https://github.com/XRPLF/rippled/pull/6318)
|
||||
|
||||
## XRP Ledger server version 3.1.0
|
||||
|
||||
[Version 3.1.0](https://github.com/XRPLF/rippled/releases/tag/3.1.0) was released on Jan 27, 2026.
|
||||
|
||||
@@ -127,26 +127,6 @@ tl;dr
|
||||
> 6. Wrap the body at 72 characters.
|
||||
> 7. Use the body to explain what and why vs. how.
|
||||
|
||||
In addition to those guidelines, please add one of the following
|
||||
prefixes to the subject line if appropriate.
|
||||
|
||||
- `fix:` - The primary purpose is to fix an existing bug.
|
||||
- `perf:` - The primary purpose is performance improvements.
|
||||
- `refactor:` - The changes refactor code without affecting
|
||||
functionality.
|
||||
- `test:` - The changes _only_ affect unit tests.
|
||||
- `docs:` - The changes _only_ affect documentation. This can
|
||||
include code comments in addition to `.md` files like this one.
|
||||
- `build:` - The changes _only_ affect the build process,
|
||||
including CMake and/or Conan settings.
|
||||
- `chore:` - Other tasks that don't affect the binary, but don't fit
|
||||
any of the other cases. e.g. formatting, git settings, updating
|
||||
Github Actions jobs.
|
||||
|
||||
Whenever possible, when updating commits after the PR is open, please
|
||||
add the PR number to the end of the subject line. e.g. `test: Add
|
||||
unit tests for Feature X (#1234)`.
|
||||
|
||||
## Pull requests
|
||||
|
||||
In general, pull requests use `develop` as the base branch.
|
||||
@@ -180,6 +160,23 @@ credibility of the existing approvals is insufficient.
|
||||
Pull requests must be merged by [squash-and-merge][squash]
|
||||
to preserve a linear history for the `develop` branch.
|
||||
|
||||
### Type of Change
|
||||
|
||||
In addition to those guidelines, please start your PR title with one of the following:
|
||||
|
||||
- `build:` - The changes _only_ affect the build process, including CMake and/or Conan settings.
|
||||
- `feat`: New feature (change which adds functionality).
|
||||
- `fix:` - The primary purpose is to fix an existing bug.
|
||||
- `docs:` - The changes _only_ affect documentation.
|
||||
- `test:` - The changes _only_ affect unit tests.
|
||||
- `ci`: Continuous Integration (changes to our CI configuration files and scripts).
|
||||
- `style`: Code style (formatting).
|
||||
- `refactor:` - The changes refactor code without affecting functionality.
|
||||
- `perf:` - The primary purpose is performance improvements.
|
||||
- `chore:` - Other tasks that don't affect the binary, but don't fit any of the other cases. e.g. `git` settings, `clang-tidy`, removing dead code, dropping support for older tooling.
|
||||
|
||||
First letter after the type prefix should be capitalized, and the type prefix should be followed by a colon and a space. e.g. `feat: Add support for Borrowing Protocol`.
|
||||
|
||||
### "Ready to merge"
|
||||
|
||||
A pull request should only have the "Ready to merge" label added when it
|
||||
|
||||
@@ -118,7 +118,7 @@ if(MSVC)
|
||||
NOMINMAX
|
||||
# TODO: Resolve these warnings, don't just silence them
|
||||
_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS
|
||||
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:Debug>>:_CRTDBG_MAP_ALLOC>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:Debug>,$<NOT:$<BOOL:${is_ci}>>>:_CRTDBG_MAP_ALLOC>
|
||||
)
|
||||
target_link_libraries(common INTERFACE -errorreport:none -machine:X64)
|
||||
else()
|
||||
|
||||
@@ -23,7 +23,7 @@ target_compile_definitions(
|
||||
BOOST_FILESYSTEM_NO_DEPRECATED
|
||||
>
|
||||
$<$<NOT:$<BOOL:${boost_show_deprecated}>>:
|
||||
BOOST_COROUTINES_NO_DEPRECATION_WARNING
|
||||
BOOST_COROUTINES2_NO_DEPRECATION_WARNING
|
||||
BOOST_BEAST_ALLOW_DEPRECATED
|
||||
BOOST_FILESYSTEM_DEPRECATED
|
||||
>
|
||||
|
||||
@@ -7,7 +7,7 @@ find_package(
|
||||
COMPONENTS
|
||||
chrono
|
||||
container
|
||||
coroutine
|
||||
context
|
||||
date_time
|
||||
filesystem
|
||||
json
|
||||
@@ -26,7 +26,7 @@ target_link_libraries(
|
||||
Boost::headers
|
||||
Boost::chrono
|
||||
Boost::container
|
||||
Boost::coroutine
|
||||
Boost::context
|
||||
Boost::date_time
|
||||
Boost::filesystem
|
||||
Boost::json
|
||||
@@ -38,23 +38,26 @@ target_link_libraries(
|
||||
if(Boost_COMPILER)
|
||||
target_link_libraries(xrpl_boost INTERFACE Boost::disable_autolinking)
|
||||
endif()
|
||||
if(SANITIZERS_ENABLED AND is_clang)
|
||||
# TODO: gcc does not support -fsanitize-blacklist...can we do something else for gcc ?
|
||||
if(NOT Boost_INCLUDE_DIRS AND TARGET Boost::headers)
|
||||
get_target_property(
|
||||
Boost_INCLUDE_DIRS
|
||||
Boost::headers
|
||||
INTERFACE_INCLUDE_DIRECTORIES
|
||||
)
|
||||
endif()
|
||||
message(STATUS "Adding [${Boost_INCLUDE_DIRS}] to sanitizer blacklist")
|
||||
file(
|
||||
WRITE ${CMAKE_CURRENT_BINARY_DIR}/san_bl.txt
|
||||
"src:${Boost_INCLUDE_DIRS}/*"
|
||||
)
|
||||
target_compile_options(
|
||||
opts
|
||||
INTERFACE # ignore boost headers for sanitizing
|
||||
-fsanitize-blacklist=${CMAKE_CURRENT_BINARY_DIR}/san_bl.txt
|
||||
|
||||
# GCC 14+ has a false positive -Wuninitialized warning in Boost.Coroutine2's
|
||||
# state.hpp when compiled with -O3. This is due to GCC's intentional behavior
|
||||
# change (Bug #98871, #119388) where warnings from inlined system header code
|
||||
# are no longer suppressed by -isystem. The warning occurs in operator|= in
|
||||
# boost/coroutine2/detail/state.hpp when inlined from push_control_block::destroy().
|
||||
# See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=119388
|
||||
if(is_gcc AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 14)
|
||||
target_compile_options(xrpl_boost INTERFACE -Wno-uninitialized)
|
||||
endif()
|
||||
|
||||
# Boost.Context's ucontext backend has ASAN fiber-switching annotations
|
||||
# (start/finish_switch_fiber) that are compiled in when BOOST_USE_ASAN is defined.
|
||||
# This tells ASAN about coroutine stack switches, preventing false positive
|
||||
# stack-use-after-scope errors. BOOST_USE_UCONTEXT ensures the ucontext backend
|
||||
# is selected (fcontext does not support ASAN annotations).
|
||||
# These defines must match what Boost was compiled with (see conan/profiles/sanitizers).
|
||||
if(enable_asan)
|
||||
target_compile_definitions(
|
||||
xrpl_boost
|
||||
INTERFACE BOOST_USE_ASAN BOOST_USE_UCONTEXT
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -7,16 +7,21 @@ include(default)
|
||||
{% if compiler == "gcc" %}
|
||||
{% if "address" in sanitizers or "thread" in sanitizers or "undefinedbehavior" in sanitizers %}
|
||||
{% set sanitizer_list = [] %}
|
||||
{% set defines = [] %}
|
||||
{% set model_code = "" %}
|
||||
{% set extra_cxxflags = ["-fno-omit-frame-pointer", "-O1", "-Wno-stringop-overflow"] %}
|
||||
|
||||
{% if "address" in sanitizers %}
|
||||
{% set _ = sanitizer_list.append("address") %}
|
||||
{% set model_code = "-mcmodel=large" %}
|
||||
{% set _ = defines.append("BOOST_USE_ASAN")%}
|
||||
{% set _ = defines.append("BOOST_USE_UCONTEXT")%}
|
||||
{% elif "thread" in sanitizers %}
|
||||
{% set _ = sanitizer_list.append("thread") %}
|
||||
{% set model_code = "-mcmodel=medium" %}
|
||||
{% set _ = extra_cxxflags.append("-Wno-tsan") %}
|
||||
{% set _ = defines.append("BOOST_USE_TSAN")%}
|
||||
{% set _ = defines.append("BOOST_USE_UCONTEXT")%}
|
||||
{% endif %}
|
||||
|
||||
{% if "undefinedbehavior" in sanitizers %}
|
||||
@@ -29,16 +34,22 @@ include(default)
|
||||
tools.build:cxxflags+=['{{sanitizer_flags}} {{" ".join(extra_cxxflags)}}']
|
||||
tools.build:sharedlinkflags+=['{{sanitizer_flags}}']
|
||||
tools.build:exelinkflags+=['{{sanitizer_flags}}']
|
||||
tools.build:defines+={{defines}}
|
||||
{% endif %}
|
||||
{% elif compiler == "apple-clang" or compiler == "clang" %}
|
||||
{% if "address" in sanitizers or "thread" in sanitizers or "undefinedbehavior" in sanitizers %}
|
||||
{% set sanitizer_list = [] %}
|
||||
{% set defines = [] %}
|
||||
{% set extra_cxxflags = ["-fno-omit-frame-pointer", "-O1"] %}
|
||||
|
||||
{% if "address" in sanitizers %}
|
||||
{% set _ = sanitizer_list.append("address") %}
|
||||
{% set _ = defines.append("BOOST_USE_ASAN")%}
|
||||
{% set _ = defines.append("BOOST_USE_UCONTEXT")%}
|
||||
{% elif "thread" in sanitizers %}
|
||||
{% set _ = sanitizer_list.append("thread") %}
|
||||
{% set _ = defines.append("BOOST_USE_TSAN")%}
|
||||
{% set _ = defines.append("BOOST_USE_UCONTEXT")%}
|
||||
{% endif %}
|
||||
|
||||
{% if "undefinedbehavior" in sanitizers %}
|
||||
@@ -52,8 +63,24 @@ include(default)
|
||||
tools.build:cxxflags+=['{{sanitizer_flags}} {{" ".join(extra_cxxflags)}}']
|
||||
tools.build:sharedlinkflags+=['{{sanitizer_flags}}']
|
||||
tools.build:exelinkflags+=['{{sanitizer_flags}}']
|
||||
tools.build:defines+={{defines}}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
tools.info.package_id:confs+=["tools.build:cxxflags", "tools.build:exelinkflags", "tools.build:sharedlinkflags"]
|
||||
tools.info.package_id:confs+=["tools.build:cxxflags", "tools.build:exelinkflags", "tools.build:sharedlinkflags", "tools.build:defines"]
|
||||
|
||||
[options]
|
||||
{% if sanitizers %}
|
||||
{% if "address" in sanitizers %}
|
||||
# Build Boost.Context with ucontext backend (not fcontext) so that
|
||||
# ASAN fiber-switching annotations (__sanitizer_start/finish_switch_fiber)
|
||||
# are compiled into the library. fcontext (assembly) has no ASAN support.
|
||||
# define=BOOST_USE_ASAN=1 is critical: it must be defined when building
|
||||
# Boost.Context itself so the ucontext backend compiles in the ASAN annotations.
|
||||
boost/*:extra_b2_flags=context-impl=ucontext address-sanitizer=on define=BOOST_USE_ASAN=1
|
||||
boost/*:without_context=False
|
||||
# Boost stacktrace fails to build with some sanitizers
|
||||
boost/*:without_stacktrace=True
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
12
conanfile.py
12
conanfile.py
@@ -1,4 +1,5 @@
|
||||
import re
|
||||
import os
|
||||
|
||||
from conan.tools.cmake import CMake, CMakeToolchain, cmake_layout
|
||||
|
||||
@@ -57,6 +58,9 @@ class Xrpl(ConanFile):
|
||||
"tests": False,
|
||||
"unity": False,
|
||||
"xrpld": False,
|
||||
"boost/*:without_context": False,
|
||||
"boost/*:without_coroutine": True,
|
||||
"boost/*:without_coroutine2": False,
|
||||
"date/*:header_only": True,
|
||||
"ed25519/*:shared": False,
|
||||
"grpc/*:shared": False,
|
||||
@@ -126,6 +130,12 @@ class Xrpl(ConanFile):
|
||||
if self.settings.compiler in ["clang", "gcc"]:
|
||||
self.options["boost"].without_cobalt = True
|
||||
|
||||
# Check if environment variable exists
|
||||
if "SANITIZERS" in os.environ:
|
||||
sanitizers = os.environ["SANITIZERS"]
|
||||
if "address" in sanitizers.lower():
|
||||
self.default_options["fPIC"] = False
|
||||
|
||||
def requirements(self):
|
||||
# Conan 2 requires transitive headers to be specified
|
||||
transitive_headers_opt = (
|
||||
@@ -196,7 +206,7 @@ class Xrpl(ConanFile):
|
||||
"boost::headers",
|
||||
"boost::chrono",
|
||||
"boost::container",
|
||||
"boost::coroutine",
|
||||
"boost::context",
|
||||
"boost::date_time",
|
||||
"boost::filesystem",
|
||||
"boost::json",
|
||||
|
||||
@@ -99,6 +99,7 @@ words:
|
||||
- endmacro
|
||||
- exceptioned
|
||||
- Falco
|
||||
- fcontext
|
||||
- finalizers
|
||||
- firewalled
|
||||
- fmtdur
|
||||
@@ -111,6 +112,7 @@ words:
|
||||
- gpgcheck
|
||||
- gpgkey
|
||||
- hotwallet
|
||||
- hwaddress
|
||||
- hwrap
|
||||
- ifndef
|
||||
- inequation
|
||||
|
||||
8
docs/build/sanitizers.md
vendored
8
docs/build/sanitizers.md
vendored
@@ -89,8 +89,8 @@ cmake --build . --parallel 4
|
||||
**IMPORTANT**: ASAN with Boost produces many false positives. Use these options:
|
||||
|
||||
```bash
|
||||
export ASAN_OPTIONS="print_stacktrace=1:detect_container_overflow=0:suppressions=path/to/asan.supp:halt_on_error=0:log_path=asan.log"
|
||||
export LSAN_OPTIONS="suppressions=path/to/lsan.supp:halt_on_error=0:log_path=lsan.log"
|
||||
export ASAN_OPTIONS="include=sanitizers/suppressions/runtime-asan-options.txt:suppressions=sanitizers/suppressions/asan.supp"
|
||||
export LSAN_OPTIONS="include=sanitizers/suppressions/runtime-lsan-options.txt:suppressions=sanitizers/suppressions/lsan.supp"
|
||||
|
||||
# Run tests
|
||||
./xrpld --unittest --unittest-jobs=5
|
||||
@@ -108,7 +108,7 @@ export LSAN_OPTIONS="suppressions=path/to/lsan.supp:halt_on_error=0:log_path=lsa
|
||||
### ThreadSanitizer (TSan)
|
||||
|
||||
```bash
|
||||
export TSAN_OPTIONS="suppressions=path/to/tsan.supp halt_on_error=0 log_path=tsan.log"
|
||||
export TSAN_OPTIONS="include=sanitizers/suppressions/runtime-tsan-options.txt:suppressions=sanitizers/suppressions/tsan.supp"
|
||||
|
||||
# Run tests
|
||||
./xrpld --unittest --unittest-jobs=5
|
||||
@@ -129,7 +129,7 @@ More details [here](https://github.com/google/sanitizers/wiki/AddressSanitizerLe
|
||||
### UndefinedBehaviorSanitizer (UBSan)
|
||||
|
||||
```bash
|
||||
export UBSAN_OPTIONS="suppressions=path/to/ubsan.supp:print_stacktrace=1:halt_on_error=0:log_path=ubsan.log"
|
||||
export UBSAN_OPTIONS="include=sanitizers/suppressions/runtime-ubsan-options.txt:suppressions=sanitizers/suppressions/ubsan.supp"
|
||||
|
||||
# Run tests
|
||||
./xrpld --unittest --unittest-jobs=5
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/basics/sanitizers.h>
|
||||
#include <xrpl/beast/type_name.h>
|
||||
|
||||
#include <exception>
|
||||
@@ -23,16 +24,28 @@ LogThrow(std::string const& title);
|
||||
When called from within a catch block, it will pass
|
||||
control to the next matching exception handler, if any.
|
||||
Otherwise, std::terminate will be called.
|
||||
|
||||
ASAN can't handle sudden jumps in control flow very well. This
|
||||
function is marked as XRPL_NO_SANITIZE_ADDRESS to prevent it from
|
||||
triggering false positives, since it throws.
|
||||
*/
|
||||
[[noreturn]] inline void
|
||||
[[noreturn]] XRPL_NO_SANITIZE_ADDRESS inline void
|
||||
Rethrow()
|
||||
{
|
||||
LogThrow("Re-throwing exception");
|
||||
throw;
|
||||
}
|
||||
|
||||
/*
|
||||
Logs and throws an exception of type E.
|
||||
|
||||
ASAN can't handle sudden jumps in control flow very well. This
|
||||
function is marked as XRPL_NO_SANITIZE_ADDRESS to prevent it from
|
||||
triggering false positives, since it throws.
|
||||
*/
|
||||
|
||||
template <class E, class... Args>
|
||||
[[noreturn]] inline void
|
||||
[[noreturn]] XRPL_NO_SANITIZE_ADDRESS inline void
|
||||
Throw(Args&&... args)
|
||||
{
|
||||
static_assert(
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace xrpl {
|
||||
@@ -70,4 +72,31 @@ unsafe_cast(Src s) noexcept
|
||||
return unsafe_cast<Dest>(static_cast<std::underlying_type_t<Src>>(s));
|
||||
}
|
||||
|
||||
template <class Dest, class Src>
|
||||
requires std::is_pointer_v<Dest>
|
||||
inline Dest
|
||||
safe_downcast(Src* s) noexcept
|
||||
{
|
||||
#ifdef NDEBUG
|
||||
return static_cast<Dest>(s); // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast)
|
||||
#else
|
||||
auto* result = dynamic_cast<Dest>(s);
|
||||
XRPL_ASSERT(result != nullptr, "xrpl::safe_downcast : pointer downcast is valid");
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class Dest, class Src>
|
||||
requires std::is_lvalue_reference_v<Dest>
|
||||
inline Dest
|
||||
safe_downcast(Src& s) noexcept
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
XRPL_ASSERT(
|
||||
dynamic_cast<std::add_pointer_t<std::remove_reference_t<Dest>>>(&s) != nullptr,
|
||||
"xrpl::safe_downcast : reference downcast is valid");
|
||||
#endif
|
||||
return static_cast<Dest>(s); // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast)
|
||||
}
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
13
include/xrpl/basics/sanitizers.h
Normal file
13
include/xrpl/basics/sanitizers.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
// Helper to disable ASan/HwASan for specific functions
|
||||
/*
|
||||
ASAN flags some false positives with sudden jumps in control flow, like
|
||||
exceptions, or when encountering coroutine stack switches. This macro can be used to disable ASAN
|
||||
intrumentation for specific functions.
|
||||
*/
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#define XRPL_NO_SANITIZE_ADDRESS __attribute__((no_sanitize("address", "hwaddress")))
|
||||
#else
|
||||
#define XRPL_NO_SANITIZE_ADDRESS
|
||||
#endif
|
||||
@@ -43,8 +43,8 @@ private:
|
||||
template <typename>
|
||||
friend class ListIterator;
|
||||
|
||||
ListNode* m_next;
|
||||
ListNode* m_prev;
|
||||
ListNode* m_next = nullptr;
|
||||
ListNode* m_prev = nullptr;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -567,7 +567,7 @@ private:
|
||||
}
|
||||
|
||||
private:
|
||||
size_type m_size;
|
||||
size_type m_size = 0u;
|
||||
Node m_head;
|
||||
Node m_tail;
|
||||
};
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/basics/ByteUtilities.h>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
template <class F>
|
||||
@@ -11,16 +9,18 @@ JobQueue::Coro::Coro(Coro_create_t, JobQueue& jq, JobType type, std::string cons
|
||||
, name_(name)
|
||||
, running_(false)
|
||||
, coro_(
|
||||
// Stack size of 1MB wasn't sufficient for deep calls. ASAN tests flagged the issue. Hence
|
||||
// increasing the size to 1.5MB.
|
||||
boost::context::protected_fixedsize_stack(1536 * 1024),
|
||||
[this, fn = std::forward<F>(f)](
|
||||
boost::coroutines::asymmetric_coroutine<void>::push_type& do_yield) {
|
||||
boost::coroutines2::asymmetric_coroutine<void>::push_type& do_yield) {
|
||||
yield_ = &do_yield;
|
||||
yield();
|
||||
fn(shared_from_this());
|
||||
#ifndef NDEBUG
|
||||
finished_ = true;
|
||||
#endif
|
||||
},
|
||||
boost::coroutines::attributes(megabytes(1)))
|
||||
})
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,8 @@
|
||||
#include <xrpl/core/detail/Workers.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
|
||||
#include <boost/coroutine/all.hpp>
|
||||
#include <boost/context/protected_fixedsize_stack.hpp>
|
||||
#include <boost/coroutine2/all.hpp>
|
||||
|
||||
#include <set>
|
||||
|
||||
@@ -48,8 +49,8 @@ public:
|
||||
std::mutex mutex_;
|
||||
std::mutex mutex_run_;
|
||||
std::condition_variable cv_;
|
||||
boost::coroutines::asymmetric_coroutine<void>::pull_type coro_;
|
||||
boost::coroutines::asymmetric_coroutine<void>::push_type* yield_;
|
||||
boost::coroutines2::coroutine<void>::pull_type coro_;
|
||||
boost::coroutines2::coroutine<void>::push_type* yield_;
|
||||
#ifndef NDEBUG
|
||||
bool finished_ = false;
|
||||
#endif
|
||||
|
||||
@@ -421,7 +421,7 @@ private:
|
||||
ObjectValues* map_{nullptr};
|
||||
} value_;
|
||||
ValueType type_ : 8;
|
||||
int allocated_ : 1; // Notes: if declared as bool, bitfield is useless.
|
||||
int allocated_ : 1 {}; // Notes: if declared as bool, bitfield is useless.
|
||||
};
|
||||
|
||||
inline Value
|
||||
|
||||
@@ -108,7 +108,7 @@ private:
|
||||
std::string indentString_;
|
||||
int rightMargin_;
|
||||
int indentSize_;
|
||||
bool addChildValues_;
|
||||
bool addChildValues_{};
|
||||
};
|
||||
|
||||
/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a
|
||||
@@ -175,7 +175,7 @@ private:
|
||||
std::string indentString_;
|
||||
int rightMargin_;
|
||||
std::string indentation_;
|
||||
bool addChildValues_;
|
||||
bool addChildValues_{};
|
||||
};
|
||||
|
||||
std::string
|
||||
|
||||
@@ -49,7 +49,7 @@ validDomain(ReadView const& view, uint256 domainID, AccountID const& subject);
|
||||
// This function is only called when we about to return tecNO_PERMISSION
|
||||
// because all the checks for the DepositPreauth authorization failed.
|
||||
TER
|
||||
authorizedDepositPreauth(ApplyView const& view, STVector256 const& ctx, AccountID const& dst);
|
||||
authorizedDepositPreauth(ReadView const& view, STVector256 const& ctx, AccountID const& dst);
|
||||
|
||||
// Sort credentials array, return empty set if there are duplicates
|
||||
std::set<std::pair<AccountID, Slice>>
|
||||
@@ -74,7 +74,7 @@ verifyDepositPreauth(
|
||||
ApplyView& view,
|
||||
AccountID const& src,
|
||||
AccountID const& dst,
|
||||
std::shared_ptr<SLE> const& sleDst,
|
||||
std::shared_ptr<SLE const> const& sleDst,
|
||||
beast::Journal j);
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -29,6 +29,18 @@ public:
|
||||
bool sslVerify,
|
||||
beast::Journal j);
|
||||
|
||||
/** Destroys the global SSL context created by initializeSSLContext().
|
||||
*
|
||||
* This releases the underlying boost::asio::ssl::context and any
|
||||
* associated OpenSSL resources. Must not be called while any
|
||||
* HTTPClient requests are in flight.
|
||||
*
|
||||
* @note Currently only called from tests during teardown. In production,
|
||||
* the SSL context lives for the lifetime of the process.
|
||||
*/
|
||||
static void
|
||||
cleanupSSLContext();
|
||||
|
||||
static void
|
||||
get(bool bSSL,
|
||||
boost::asio::io_context& io_context,
|
||||
|
||||
@@ -138,6 +138,9 @@ public:
|
||||
/** Returns the number of file descriptors the backend expects to need. */
|
||||
virtual int
|
||||
fdRequired() const = 0;
|
||||
|
||||
/** The number of hardware threads to use for compression of a batch. */
|
||||
static unsigned int const numHardwareThreads;
|
||||
};
|
||||
|
||||
} // namespace NodeStore
|
||||
|
||||
@@ -64,6 +64,49 @@
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
// Feature names must not exceed this length (in characters, excluding the null terminator).
|
||||
static constexpr std::size_t maxFeatureNameSize = 63;
|
||||
// Reserve this exact feature-name length (in characters/bytes, excluding the null terminator)
|
||||
// so that a 32-byte uint256 (for example, in WASM or other interop contexts) can be used
|
||||
// as a compact, fixed-size feature selector without conflicting with human-readable names.
|
||||
static constexpr std::size_t reservedFeatureNameSize = 32;
|
||||
|
||||
// Both validFeatureNameSize and validFeatureName are consteval functions that can be used in
|
||||
// static_asserts to validate feature names at compile time. They are only used inside
|
||||
// enforceValidFeatureName in Feature.cpp, but are exposed here for testing. The expected
|
||||
// parameter `auto fn` is a constexpr lambda which returns a const char*, making it available
|
||||
// for compile-time evaluation. Read more in https://accu.org/journals/overload/30/172/wu/
|
||||
consteval auto
|
||||
validFeatureNameSize(auto fn) -> bool
|
||||
{
|
||||
constexpr char const* n = fn();
|
||||
// Note, std::strlen is not constexpr, we need to implement our own here.
|
||||
constexpr std::size_t N = [](auto n) {
|
||||
std::size_t ret = 0;
|
||||
for (auto ptr = n; *ptr != '\0'; ret++, ++ptr)
|
||||
;
|
||||
return ret;
|
||||
}(n);
|
||||
return N != reservedFeatureNameSize && //
|
||||
N <= maxFeatureNameSize;
|
||||
}
|
||||
|
||||
consteval auto
|
||||
validFeatureName(auto fn) -> bool
|
||||
{
|
||||
constexpr char const* n = fn();
|
||||
// Prevent the use of visually confusable characters and enforce that feature names
|
||||
// are always valid ASCII. This is needed because C++ allows Unicode identifiers.
|
||||
// Characters below 0x20 are nonprintable control characters, and characters with the 0x80 bit
|
||||
// set are non-ASCII (e.g. UTF-8 encoding of Unicode), so both are disallowed.
|
||||
for (auto ptr = n; *ptr != '\0'; ++ptr)
|
||||
{
|
||||
if (*ptr & 0x80 || *ptr < 0x20)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
enum class VoteBehavior : int { Obsolete = -1, DefaultNo = 0, DefaultYes };
|
||||
enum class AmendmentSupport : int { Retired = -1, Supported = 0, Unsupported };
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ public:
|
||||
std::optional<TxType>
|
||||
getGranularTxType(GranularPermissionType const& gpType) const;
|
||||
|
||||
std::optional<std::reference_wrapper<uint256 const>> const
|
||||
std::optional<std::reference_wrapper<uint256 const>>
|
||||
getTxFeature(TxType txType) const;
|
||||
|
||||
bool
|
||||
|
||||
@@ -209,7 +209,7 @@ std::size_t constexpr maxDIDDocumentLength = 256;
|
||||
std::size_t constexpr maxDIDURILength = 256;
|
||||
|
||||
/** The maximum length of an Attestation inside a DID */
|
||||
std::size_t constexpr maxDIDAttestationLength = 256;
|
||||
std::size_t constexpr maxDIDDataLength = 256;
|
||||
|
||||
/** The maximum length of a domain */
|
||||
std::size_t constexpr maxDomainLength = 256;
|
||||
|
||||
@@ -44,7 +44,7 @@ protected:
|
||||
// All the constructed public keys are valid, non-empty and contain 33
|
||||
// bytes of data.
|
||||
static constexpr std::size_t size_ = 33;
|
||||
std::uint8_t buf_[size_]; // should be large enough
|
||||
std::uint8_t buf_[size_]{}; // should be large enough
|
||||
|
||||
public:
|
||||
using const_iterator = std::uint8_t const*;
|
||||
|
||||
@@ -24,7 +24,7 @@ public:
|
||||
STAccount();
|
||||
|
||||
STAccount(SField const& n);
|
||||
STAccount(SField const& n, Buffer&& v);
|
||||
STAccount(SField const& n, Buffer const& v);
|
||||
STAccount(SerialIter& sit, SField const& name);
|
||||
STAccount(SField const& n, AccountID const& v);
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ class STObject : public STBase, public CountedObject<STObject>
|
||||
using list_type = std::vector<detail::STVar>;
|
||||
|
||||
list_type v_;
|
||||
SOTemplate const* mType;
|
||||
SOTemplate const* mType{};
|
||||
|
||||
public:
|
||||
using iterator = boost::transform_iterator<Transform, STObject::list_type::const_iterator>;
|
||||
@@ -401,7 +401,7 @@ public:
|
||||
getStyle(SField const& field) const;
|
||||
|
||||
bool
|
||||
hasMatchingEntry(STBase const&);
|
||||
hasMatchingEntry(STBase const&) const;
|
||||
|
||||
bool
|
||||
operator==(STObject const& o) const;
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
enum TxnSql : char {
|
||||
enum class TxnSql : char {
|
||||
txnSqlNew = 'N',
|
||||
txnSqlConflict = 'C',
|
||||
txnSqlHeld = 'H',
|
||||
@@ -83,6 +83,9 @@ public:
|
||||
std::uint32_t
|
||||
getSeqValue() const;
|
||||
|
||||
AccountID
|
||||
getFeePayer() const;
|
||||
|
||||
boost::container::flat_set<AccountID>
|
||||
getMentionedAccounts() const;
|
||||
|
||||
@@ -122,7 +125,7 @@ public:
|
||||
getMetaSQL(
|
||||
Serializer rawTxn,
|
||||
std::uint32_t inLedger,
|
||||
char status,
|
||||
TxnSql status,
|
||||
std::string const& escapedMetaData) const;
|
||||
|
||||
std::vector<uint256> const&
|
||||
|
||||
@@ -16,8 +16,11 @@ namespace xrpl {
|
||||
/** A secret key. */
|
||||
class SecretKey
|
||||
{
|
||||
public:
|
||||
static constexpr std::size_t size_ = 32;
|
||||
|
||||
private:
|
||||
std::uint8_t buf_[32];
|
||||
std::uint8_t buf_[size_]{};
|
||||
|
||||
public:
|
||||
using const_iterator = std::uint8_t const*;
|
||||
@@ -27,9 +30,14 @@ public:
|
||||
SecretKey&
|
||||
operator=(SecretKey const&) = default;
|
||||
|
||||
bool
|
||||
operator==(SecretKey const&) = delete;
|
||||
bool
|
||||
operator!=(SecretKey const&) = delete;
|
||||
|
||||
~SecretKey();
|
||||
|
||||
SecretKey(std::array<std::uint8_t, 32> const& data);
|
||||
SecretKey(std::array<std::uint8_t, size_> const& data);
|
||||
SecretKey(Slice const& slice);
|
||||
|
||||
std::uint8_t const*
|
||||
@@ -78,16 +86,10 @@ public:
|
||||
};
|
||||
|
||||
inline bool
|
||||
operator==(SecretKey const& lhs, SecretKey const& rhs)
|
||||
{
|
||||
return lhs.size() == rhs.size() && std::memcmp(lhs.data(), rhs.data(), rhs.size()) == 0;
|
||||
}
|
||||
operator==(SecretKey const& lhs, SecretKey const& rhs) = delete;
|
||||
|
||||
inline bool
|
||||
operator!=(SecretKey const& lhs, SecretKey const& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
operator!=(SecretKey const& lhs, SecretKey const& rhs) = delete;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace xrpl {
|
||||
class Seed
|
||||
{
|
||||
private:
|
||||
std::array<uint8_t, 16> buf_;
|
||||
std::array<uint8_t, 16> buf_{};
|
||||
|
||||
public:
|
||||
using const_iterator = std::array<uint8_t, 16>::const_iterator;
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace xrpl {
|
||||
static inline std::string const&
|
||||
systemName()
|
||||
{
|
||||
static std::string const name = "ripple";
|
||||
static std::string const name = "xrpld";
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ private:
|
||||
// The largest "small object" we can accommodate
|
||||
static std::size_t constexpr max_size = 72;
|
||||
|
||||
std::aligned_storage<max_size>::type d_;
|
||||
std::aligned_storage<max_size>::type d_ = {};
|
||||
STBase* p_ = nullptr;
|
||||
|
||||
public:
|
||||
|
||||
@@ -42,7 +42,7 @@ TRANSACTION(ttPAYMENT, 0, Payment,
|
||||
|
||||
/** This transaction type creates an escrow object. */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpl/tx/transactors/escrow/Escrow.h>
|
||||
# include <xrpl/tx/transactors/escrow/EscrowCreate.h>
|
||||
#endif
|
||||
TRANSACTION(ttESCROW_CREATE, 1, EscrowCreate,
|
||||
Delegation::delegable,
|
||||
@@ -58,6 +58,9 @@ TRANSACTION(ttESCROW_CREATE, 1, EscrowCreate,
|
||||
}))
|
||||
|
||||
/** This transaction type completes an existing escrow. */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpl/tx/transactors/escrow/EscrowFinish.h>
|
||||
#endif
|
||||
TRANSACTION(ttESCROW_FINISH, 2, EscrowFinish,
|
||||
Delegation::delegable,
|
||||
uint256{},
|
||||
@@ -94,7 +97,7 @@ TRANSACTION(ttACCOUNT_SET, 3, AccountSet,
|
||||
|
||||
/** This transaction type cancels an existing escrow. */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpl/tx/transactors/escrow/Escrow.h>
|
||||
# include <xrpl/tx/transactors/escrow/EscrowCancel.h>
|
||||
#endif
|
||||
TRANSACTION(ttESCROW_CANCEL, 4, EscrowCancel,
|
||||
Delegation::delegable,
|
||||
@@ -180,7 +183,7 @@ TRANSACTION(ttSIGNER_LIST_SET, 12, SignerListSet,
|
||||
|
||||
/** This transaction type creates a new unidirectional XRP payment channel. */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpl/tx/transactors/payment_channel/PayChan.h>
|
||||
# include <xrpl/tx/transactors/payment_channel/PayChanCreate.h>
|
||||
#endif
|
||||
TRANSACTION(ttPAYCHAN_CREATE, 13, PaymentChannelCreate,
|
||||
Delegation::delegable,
|
||||
@@ -196,6 +199,9 @@ TRANSACTION(ttPAYCHAN_CREATE, 13, PaymentChannelCreate,
|
||||
}))
|
||||
|
||||
/** This transaction type funds an existing unidirectional XRP payment channel. */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpl/tx/transactors/payment_channel/PayChanFund.h>
|
||||
#endif
|
||||
TRANSACTION(ttPAYCHAN_FUND, 14, PaymentChannelFund,
|
||||
Delegation::delegable,
|
||||
uint256{},
|
||||
@@ -207,6 +213,9 @@ TRANSACTION(ttPAYCHAN_FUND, 14, PaymentChannelFund,
|
||||
}))
|
||||
|
||||
/** This transaction type submits a claim against an existing unidirectional payment channel. */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpl/tx/transactors/payment_channel/PayChanClaim.h>
|
||||
#endif
|
||||
TRANSACTION(ttPAYCHAN_CLAIM, 15, PaymentChannelClaim,
|
||||
Delegation::delegable,
|
||||
uint256{},
|
||||
@@ -617,7 +626,7 @@ TRANSACTION(ttXCHAIN_CREATE_BRIDGE, 48, XChainCreateBridge,
|
||||
|
||||
/** This transaction type creates or updates a DID */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpl/tx/transactors/did/DID.h>
|
||||
# include <xrpl/tx/transactors/did/DIDSet.h>
|
||||
#endif
|
||||
TRANSACTION(ttDID_SET, 49, DIDSet,
|
||||
Delegation::delegable,
|
||||
@@ -630,6 +639,9 @@ TRANSACTION(ttDID_SET, 49, DIDSet,
|
||||
}))
|
||||
|
||||
/** This transaction type deletes a DID */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpl/tx/transactors/did/DIDDelete.h>
|
||||
#endif
|
||||
TRANSACTION(ttDID_DELETE, 50, DIDDelete,
|
||||
Delegation::delegable,
|
||||
featureDID,
|
||||
@@ -739,7 +751,7 @@ TRANSACTION(ttMPTOKEN_AUTHORIZE, 57, MPTokenAuthorize,
|
||||
|
||||
/** This transaction type create an Credential instance */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpl/tx/transactors/credentials/Credentials.h>
|
||||
# include <xrpl/tx/transactors/credentials/CredentialCreate.h>
|
||||
#endif
|
||||
TRANSACTION(ttCREDENTIAL_CREATE, 58, CredentialCreate,
|
||||
Delegation::delegable,
|
||||
@@ -753,6 +765,9 @@ TRANSACTION(ttCREDENTIAL_CREATE, 58, CredentialCreate,
|
||||
}))
|
||||
|
||||
/** This transaction type accept an Credential object */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpl/tx/transactors/credentials/CredentialAccept.h>
|
||||
#endif
|
||||
TRANSACTION(ttCREDENTIAL_ACCEPT, 59, CredentialAccept,
|
||||
Delegation::delegable,
|
||||
featureCredentials,
|
||||
@@ -763,6 +778,9 @@ TRANSACTION(ttCREDENTIAL_ACCEPT, 59, CredentialAccept,
|
||||
}))
|
||||
|
||||
/** This transaction type delete an Credential object */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpl/tx/transactors/credentials/CredentialDelete.h>
|
||||
#endif
|
||||
TRANSACTION(ttCREDENTIAL_DELETE, 60, CredentialDelete,
|
||||
Delegation::delegable,
|
||||
featureCredentials,
|
||||
@@ -830,7 +848,7 @@ TRANSACTION(ttDELEGATE_SET, 64, DelegateSet,
|
||||
# include <xrpl/tx/transactors/vault/VaultCreate.h>
|
||||
#endif
|
||||
TRANSACTION(ttVAULT_CREATE, 65, VaultCreate,
|
||||
Delegation::delegable,
|
||||
Delegation::notDelegable,
|
||||
featureSingleAssetVault,
|
||||
createPseudoAcct | createMPTIssuance | mustModifyVault,
|
||||
({
|
||||
@@ -848,7 +866,7 @@ TRANSACTION(ttVAULT_CREATE, 65, VaultCreate,
|
||||
# include <xrpl/tx/transactors/vault/VaultSet.h>
|
||||
#endif
|
||||
TRANSACTION(ttVAULT_SET, 66, VaultSet,
|
||||
Delegation::delegable,
|
||||
Delegation::notDelegable,
|
||||
featureSingleAssetVault,
|
||||
mustModifyVault,
|
||||
({
|
||||
@@ -863,7 +881,7 @@ TRANSACTION(ttVAULT_SET, 66, VaultSet,
|
||||
# include <xrpl/tx/transactors/vault/VaultDelete.h>
|
||||
#endif
|
||||
TRANSACTION(ttVAULT_DELETE, 67, VaultDelete,
|
||||
Delegation::delegable,
|
||||
Delegation::notDelegable,
|
||||
featureSingleAssetVault,
|
||||
mustDeleteAcct | destroyMPTIssuance | mustModifyVault,
|
||||
({
|
||||
@@ -875,7 +893,7 @@ TRANSACTION(ttVAULT_DELETE, 67, VaultDelete,
|
||||
# include <xrpl/tx/transactors/vault/VaultDeposit.h>
|
||||
#endif
|
||||
TRANSACTION(ttVAULT_DEPOSIT, 68, VaultDeposit,
|
||||
Delegation::delegable,
|
||||
Delegation::notDelegable,
|
||||
featureSingleAssetVault,
|
||||
mayAuthorizeMPT | mustModifyVault,
|
||||
({
|
||||
@@ -888,7 +906,7 @@ TRANSACTION(ttVAULT_DEPOSIT, 68, VaultDeposit,
|
||||
# include <xrpl/tx/transactors/vault/VaultWithdraw.h>
|
||||
#endif
|
||||
TRANSACTION(ttVAULT_WITHDRAW, 69, VaultWithdraw,
|
||||
Delegation::delegable,
|
||||
Delegation::notDelegable,
|
||||
featureSingleAssetVault,
|
||||
mayDeleteMPT | mayAuthorizeMPT | mustModifyVault,
|
||||
({
|
||||
@@ -903,7 +921,7 @@ TRANSACTION(ttVAULT_WITHDRAW, 69, VaultWithdraw,
|
||||
# include <xrpl/tx/transactors/vault/VaultClawback.h>
|
||||
#endif
|
||||
TRANSACTION(ttVAULT_CLAWBACK, 70, VaultClawback,
|
||||
Delegation::delegable,
|
||||
Delegation::notDelegable,
|
||||
featureSingleAssetVault,
|
||||
mayDeleteMPT | mustModifyVault,
|
||||
({
|
||||
@@ -932,7 +950,7 @@ TRANSACTION(ttBATCH, 71, Batch,
|
||||
# include <xrpl/tx/transactors/lending/LoanBrokerSet.h>
|
||||
#endif
|
||||
TRANSACTION(ttLOAN_BROKER_SET, 74, LoanBrokerSet,
|
||||
Delegation::delegable,
|
||||
Delegation::notDelegable,
|
||||
featureLendingProtocol,
|
||||
createPseudoAcct | mayAuthorizeMPT, ({
|
||||
{sfVaultID, soeREQUIRED},
|
||||
@@ -949,7 +967,7 @@ TRANSACTION(ttLOAN_BROKER_SET, 74, LoanBrokerSet,
|
||||
# include <xrpl/tx/transactors/lending/LoanBrokerDelete.h>
|
||||
#endif
|
||||
TRANSACTION(ttLOAN_BROKER_DELETE, 75, LoanBrokerDelete,
|
||||
Delegation::delegable,
|
||||
Delegation::notDelegable,
|
||||
featureLendingProtocol,
|
||||
mustDeleteAcct | mayAuthorizeMPT, ({
|
||||
{sfLoanBrokerID, soeREQUIRED},
|
||||
@@ -960,7 +978,7 @@ TRANSACTION(ttLOAN_BROKER_DELETE, 75, LoanBrokerDelete,
|
||||
# include <xrpl/tx/transactors/lending/LoanBrokerCoverDeposit.h>
|
||||
#endif
|
||||
TRANSACTION(ttLOAN_BROKER_COVER_DEPOSIT, 76, LoanBrokerCoverDeposit,
|
||||
Delegation::delegable,
|
||||
Delegation::notDelegable,
|
||||
featureLendingProtocol,
|
||||
noPriv, ({
|
||||
{sfLoanBrokerID, soeREQUIRED},
|
||||
@@ -972,7 +990,7 @@ TRANSACTION(ttLOAN_BROKER_COVER_DEPOSIT, 76, LoanBrokerCoverDeposit,
|
||||
# include <xrpl/tx/transactors/lending/LoanBrokerCoverWithdraw.h>
|
||||
#endif
|
||||
TRANSACTION(ttLOAN_BROKER_COVER_WITHDRAW, 77, LoanBrokerCoverWithdraw,
|
||||
Delegation::delegable,
|
||||
Delegation::notDelegable,
|
||||
featureLendingProtocol,
|
||||
mayAuthorizeMPT, ({
|
||||
{sfLoanBrokerID, soeREQUIRED},
|
||||
@@ -987,7 +1005,7 @@ TRANSACTION(ttLOAN_BROKER_COVER_WITHDRAW, 77, LoanBrokerCoverWithdraw,
|
||||
# include <xrpl/tx/transactors/lending/LoanBrokerCoverClawback.h>
|
||||
#endif
|
||||
TRANSACTION(ttLOAN_BROKER_COVER_CLAWBACK, 78, LoanBrokerCoverClawback,
|
||||
Delegation::delegable,
|
||||
Delegation::notDelegable,
|
||||
featureLendingProtocol,
|
||||
noPriv, ({
|
||||
{sfLoanBrokerID, soeOPTIONAL},
|
||||
@@ -999,7 +1017,7 @@ TRANSACTION(ttLOAN_BROKER_COVER_CLAWBACK, 78, LoanBrokerCoverClawback,
|
||||
# include <xrpl/tx/transactors/lending/LoanSet.h>
|
||||
#endif
|
||||
TRANSACTION(ttLOAN_SET, 80, LoanSet,
|
||||
Delegation::delegable,
|
||||
Delegation::notDelegable,
|
||||
featureLendingProtocol,
|
||||
mayAuthorizeMPT | mustModifyVault, ({
|
||||
{sfLoanBrokerID, soeREQUIRED},
|
||||
@@ -1026,7 +1044,7 @@ TRANSACTION(ttLOAN_SET, 80, LoanSet,
|
||||
# include <xrpl/tx/transactors/lending/LoanDelete.h>
|
||||
#endif
|
||||
TRANSACTION(ttLOAN_DELETE, 81, LoanDelete,
|
||||
Delegation::delegable,
|
||||
Delegation::notDelegable,
|
||||
featureLendingProtocol,
|
||||
noPriv, ({
|
||||
{sfLoanID, soeREQUIRED},
|
||||
@@ -1037,7 +1055,7 @@ TRANSACTION(ttLOAN_DELETE, 81, LoanDelete,
|
||||
# include <xrpl/tx/transactors/lending/LoanManage.h>
|
||||
#endif
|
||||
TRANSACTION(ttLOAN_MANAGE, 82, LoanManage,
|
||||
Delegation::delegable,
|
||||
Delegation::notDelegable,
|
||||
featureLendingProtocol,
|
||||
// All of the LoanManage options will modify the vault, but the
|
||||
// transaction can succeed without options, essentially making it
|
||||
@@ -1051,7 +1069,7 @@ TRANSACTION(ttLOAN_MANAGE, 82, LoanManage,
|
||||
# include <xrpl/tx/transactors/lending/LoanPay.h>
|
||||
#endif
|
||||
TRANSACTION(ttLOAN_PAY, 84, LoanPay,
|
||||
Delegation::delegable,
|
||||
Delegation::notDelegable,
|
||||
featureLendingProtocol,
|
||||
mayAuthorizeMPT | mustModifyVault, ({
|
||||
{sfLoanID, soeREQUIRED},
|
||||
|
||||
@@ -40,7 +40,7 @@ public:
|
||||
operator result_type() noexcept;
|
||||
|
||||
private:
|
||||
char ctx_[96];
|
||||
char ctx_[96]{};
|
||||
};
|
||||
|
||||
/** SHA-512 digest
|
||||
@@ -63,7 +63,7 @@ public:
|
||||
operator result_type() noexcept;
|
||||
|
||||
private:
|
||||
char ctx_[216];
|
||||
char ctx_[216]{};
|
||||
};
|
||||
|
||||
/** SHA-256 digest
|
||||
@@ -86,7 +86,7 @@ public:
|
||||
operator result_type() noexcept;
|
||||
|
||||
private:
|
||||
char ctx_[112];
|
||||
char ctx_[112]{};
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -112,6 +112,7 @@ JSS(accounts); // in: LedgerEntry, Subscribe,
|
||||
// handlers/Ledger, Unsubscribe
|
||||
JSS(accounts_proposed); // in: Subscribe, Unsubscribe
|
||||
JSS(action);
|
||||
JSS(active); // out: OverlayImpl
|
||||
JSS(acquiring); // out: LedgerRequest
|
||||
JSS(address); // out: PeerImp
|
||||
JSS(affected); // out: AcceptedLedgerTx
|
||||
@@ -300,6 +301,7 @@ JSS(id); // websocket.
|
||||
JSS(ident); // in: AccountCurrencies, AccountInfo,
|
||||
// OwnerInfo
|
||||
JSS(ignore_default); // in: AccountLines
|
||||
JSS(in); // out: OverlayImpl
|
||||
JSS(inLedger); // out: tx/Transaction
|
||||
JSS(inbound); // out: PeerImp
|
||||
JSS(index); // in: LedgerEntry
|
||||
@@ -464,6 +466,7 @@ JSS(open_ledger_level); // out: TxQ
|
||||
JSS(optionality); // out: server_definitions
|
||||
JSS(oracles); // in: get_aggregate_price
|
||||
JSS(oracle_document_id); // in: get_aggregate_price
|
||||
JSS(out); // out: OverlayImpl
|
||||
JSS(owner); // in: LedgerEntry, out: NetworkOPs
|
||||
JSS(owner_funds); // in/out: Ledger, NetworkOPs, AcceptedLedgerTx
|
||||
JSS(page_index);
|
||||
|
||||
@@ -173,7 +173,7 @@ public:
|
||||
send(Json::Value const& jvObj, bool broadcast) = 0;
|
||||
|
||||
std::uint64_t
|
||||
getSeq();
|
||||
getSeq() const;
|
||||
|
||||
void
|
||||
onSendEmpty();
|
||||
|
||||
@@ -114,8 +114,7 @@ protected:
|
||||
beast::Journal const j_;
|
||||
|
||||
AccountID const account_;
|
||||
XRPAmount mPriorBalance; // Balance before fees.
|
||||
XRPAmount mSourceBalance; // Balance after fees.
|
||||
XRPAmount preFeeBalance_{}; // Balance before fees.
|
||||
|
||||
virtual ~Transactor() = default;
|
||||
Transactor(Transactor const&) = delete;
|
||||
|
||||
@@ -213,7 +213,7 @@ public:
|
||||
, flags(ctx_.flags)
|
||||
, j(ctx_.j)
|
||||
, ter(ter_)
|
||||
, likelyToClaimFee(ter == tesSUCCESS || isTecClaimHardFail(ter, flags))
|
||||
, likelyToClaimFee(isTesSuccess(ter) || isTecClaimHardFail(ter, flags))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,33 @@ namespace xrpl {
|
||||
* communicate the interface required of any invariant checker. Any invariant
|
||||
* check implementation should implement the public methods documented here.
|
||||
*
|
||||
* ## Rules for implementing `finalize`
|
||||
*
|
||||
* ### Invariants must run regardless of transaction result
|
||||
*
|
||||
* An invariant's `finalize` method MUST perform meaningful checks even when
|
||||
* the transaction has failed (i.e., `!isTesSuccess(tec)`). The following
|
||||
* pattern is almost certainly wrong and must never be used:
|
||||
*
|
||||
* @code
|
||||
* // WRONG: skipping all checks on failure defeats the purpose of invariants
|
||||
* if (!isTesSuccess(tec))
|
||||
* return true;
|
||||
* @endcode
|
||||
*
|
||||
* The entire purpose of invariants is to detect and prevent the impossible.
|
||||
* A bug or exploit could cause a failed transaction to mutate ledger state in
|
||||
* unexpected ways. Invariants are the last line of defense against such
|
||||
* scenarios.
|
||||
*
|
||||
* In general: an invariant that expects a domain-specific state change to
|
||||
* occur (e.g., a new object being created) should only expect that change
|
||||
* when the transaction succeeded. A failed VaultCreate must not have created
|
||||
* a Vault. A failed LoanSet must not have created a Loan.
|
||||
*
|
||||
* Also be aware that failed transactions, regardless of type, carry no
|
||||
* Privileges. Any privilege-gated checks must therefore also be applied to
|
||||
* failed transactions.
|
||||
*/
|
||||
class InvariantChecker_PROTOTYPE
|
||||
{
|
||||
@@ -48,7 +75,11 @@ public:
|
||||
|
||||
/**
|
||||
* @brief called after all ledger entries have been visited to determine
|
||||
* the final status of the check
|
||||
* the final status of the check.
|
||||
*
|
||||
* This method MUST perform meaningful checks even when `tec` indicates a
|
||||
* failed transaction. See the class-level documentation for the rules
|
||||
* governing how failed transactions must be handled.
|
||||
*
|
||||
* @param tx the transaction being applied
|
||||
* @param tec the current TER result of the transaction
|
||||
@@ -101,7 +132,7 @@ public:
|
||||
visitEntry(bool, std::shared_ptr<SLE const> const&, std::shared_ptr<SLE const> const&);
|
||||
|
||||
bool
|
||||
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&);
|
||||
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&) const;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -121,7 +152,7 @@ public:
|
||||
visitEntry(bool, std::shared_ptr<SLE const> const&, std::shared_ptr<SLE const> const&);
|
||||
|
||||
bool
|
||||
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&);
|
||||
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&) const;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -167,7 +198,7 @@ public:
|
||||
visitEntry(bool, std::shared_ptr<SLE const> const&, std::shared_ptr<SLE const> const&);
|
||||
|
||||
bool
|
||||
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&);
|
||||
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&) const;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -184,7 +215,7 @@ public:
|
||||
visitEntry(bool, std::shared_ptr<SLE const> const&, std::shared_ptr<SLE const> const&);
|
||||
|
||||
bool
|
||||
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&);
|
||||
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&) const;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -202,7 +233,7 @@ public:
|
||||
visitEntry(bool, std::shared_ptr<SLE const> const&, std::shared_ptr<SLE const> const&);
|
||||
|
||||
bool
|
||||
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&);
|
||||
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&) const;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -221,7 +252,7 @@ public:
|
||||
visitEntry(bool, std::shared_ptr<SLE const> const&, std::shared_ptr<SLE const> const&);
|
||||
|
||||
bool
|
||||
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&);
|
||||
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&) const;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -240,7 +271,7 @@ public:
|
||||
visitEntry(bool, std::shared_ptr<SLE const> const&, std::shared_ptr<SLE const> const&);
|
||||
|
||||
bool
|
||||
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&);
|
||||
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&) const;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -256,7 +287,7 @@ public:
|
||||
visitEntry(bool, std::shared_ptr<SLE const> const&, std::shared_ptr<SLE const> const&);
|
||||
|
||||
bool
|
||||
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&);
|
||||
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&) const;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -276,7 +307,7 @@ public:
|
||||
visitEntry(bool, std::shared_ptr<SLE const> const&, std::shared_ptr<SLE const> const&);
|
||||
|
||||
bool
|
||||
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&);
|
||||
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&) const;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -297,7 +328,7 @@ public:
|
||||
visitEntry(bool, std::shared_ptr<SLE const> const&, std::shared_ptr<SLE const> const&);
|
||||
|
||||
bool
|
||||
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&);
|
||||
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&) const;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -25,7 +25,7 @@ public:
|
||||
visitEntry(bool, std::shared_ptr<SLE const> const&, std::shared_ptr<SLE const> const&);
|
||||
|
||||
bool
|
||||
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&);
|
||||
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&) const;
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -36,7 +36,7 @@ public:
|
||||
visitEntry(bool, std::shared_ptr<SLE const> const&, std::shared_ptr<SLE const> const&);
|
||||
|
||||
bool
|
||||
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&);
|
||||
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&) const;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -64,7 +64,7 @@ public:
|
||||
visitEntry(bool, std::shared_ptr<SLE const> const&, std::shared_ptr<SLE const> const&);
|
||||
|
||||
bool
|
||||
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&);
|
||||
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&) const;
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -22,7 +22,7 @@ private:
|
||||
uint256 m_dir;
|
||||
uint256 m_index;
|
||||
std::shared_ptr<SLE> m_entry;
|
||||
Quality m_quality;
|
||||
Quality m_quality{};
|
||||
|
||||
public:
|
||||
/** Create the iterator. */
|
||||
|
||||
29
include/xrpl/tx/transactors/credentials/CredentialAccept.h
Normal file
29
include/xrpl/tx/transactors/credentials/CredentialAccept.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/tx/Transactor.h>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
class CredentialAccept : public Transactor
|
||||
{
|
||||
public:
|
||||
static constexpr ConsequencesFactoryType ConsequencesFactory{Normal};
|
||||
|
||||
explicit CredentialAccept(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static std::uint32_t
|
||||
getFlagsMask(PreflightContext const& ctx);
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
29
include/xrpl/tx/transactors/credentials/CredentialCreate.h
Normal file
29
include/xrpl/tx/transactors/credentials/CredentialCreate.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/tx/Transactor.h>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
class CredentialCreate : public Transactor
|
||||
{
|
||||
public:
|
||||
static constexpr ConsequencesFactoryType ConsequencesFactory{Normal};
|
||||
|
||||
explicit CredentialCreate(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static std::uint32_t
|
||||
getFlagsMask(PreflightContext const& ctx);
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
29
include/xrpl/tx/transactors/credentials/CredentialDelete.h
Normal file
29
include/xrpl/tx/transactors/credentials/CredentialDelete.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/tx/Transactor.h>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
class CredentialDelete : public Transactor
|
||||
{
|
||||
public:
|
||||
static constexpr ConsequencesFactoryType ConsequencesFactory{Normal};
|
||||
|
||||
explicit CredentialDelete(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static std::uint32_t
|
||||
getFlagsMask(PreflightContext const& ctx);
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -1,77 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/tx/Transactor.h>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
class CredentialCreate : public Transactor
|
||||
{
|
||||
public:
|
||||
static constexpr ConsequencesFactoryType ConsequencesFactory{Normal};
|
||||
|
||||
explicit CredentialCreate(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static std::uint32_t
|
||||
getFlagsMask(PreflightContext const& ctx);
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class CredentialDelete : public Transactor
|
||||
{
|
||||
public:
|
||||
static constexpr ConsequencesFactoryType ConsequencesFactory{Normal};
|
||||
|
||||
explicit CredentialDelete(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static std::uint32_t
|
||||
getFlagsMask(PreflightContext const& ctx);
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class CredentialAccept : public Transactor
|
||||
{
|
||||
public:
|
||||
static constexpr ConsequencesFactoryType ConsequencesFactory{Normal};
|
||||
|
||||
explicit CredentialAccept(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static std::uint32_t
|
||||
getFlagsMask(PreflightContext const& ctx);
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -370,7 +370,7 @@ changeSpotPriceQuality(
|
||||
if (!amounts)
|
||||
{
|
||||
JLOG(j.trace()) << "changeSpotPrice calc failed: " << to_string(pool.in) << " "
|
||||
<< to_string(pool.out) << " " << quality << " " << tfee << std::endl;
|
||||
<< to_string(pool.out) << " " << quality << " " << tfee;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
@@ -639,9 +639,9 @@ getRoundedAsset(Rules const& rules, STAmount const& balance, A const& frac, IsDe
|
||||
STAmount
|
||||
getRoundedAsset(
|
||||
Rules const& rules,
|
||||
std::function<Number()>&& noRoundCb,
|
||||
std::function<Number()> const& noRoundCb,
|
||||
STAmount const& balance,
|
||||
std::function<Number()>&& productCb,
|
||||
std::function<Number()> const& productCb,
|
||||
IsDeposit isDeposit);
|
||||
|
||||
/** Round AMM deposit/withdrawal LPToken amount. Deposit/withdrawal formulas
|
||||
@@ -672,9 +672,9 @@ getRoundedLPTokens(
|
||||
STAmount
|
||||
getRoundedLPTokens(
|
||||
Rules const& rules,
|
||||
std::function<Number()>&& noRoundCb,
|
||||
std::function<Number()> const& noRoundCb,
|
||||
STAmount const& lptAMMBalance,
|
||||
std::function<Number()>&& productCb,
|
||||
std::function<Number()> const& productCb,
|
||||
IsDeposit isDeposit);
|
||||
|
||||
/* Next two functions adjust asset in/out amount to factor in the adjusted
|
||||
|
||||
@@ -4,24 +4,6 @@
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
class DIDSet : public Transactor
|
||||
{
|
||||
public:
|
||||
static constexpr ConsequencesFactoryType ConsequencesFactory{Normal};
|
||||
|
||||
explicit DIDSet(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class DIDDelete : public Transactor
|
||||
{
|
||||
public:
|
||||
23
include/xrpl/tx/transactors/did/DIDSet.h
Normal file
23
include/xrpl/tx/transactors/did/DIDSet.h
Normal file
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/tx/Transactor.h>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
class DIDSet : public Transactor
|
||||
{
|
||||
public:
|
||||
static constexpr ConsequencesFactoryType ConsequencesFactory{Normal};
|
||||
|
||||
explicit DIDSet(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -1,80 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/tx/Transactor.h>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
class EscrowCreate : public Transactor
|
||||
{
|
||||
public:
|
||||
static constexpr ConsequencesFactoryType ConsequencesFactory{Custom};
|
||||
|
||||
explicit EscrowCreate(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static TxConsequences
|
||||
makeTxConsequences(PreflightContext const& ctx);
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class EscrowFinish : public Transactor
|
||||
{
|
||||
public:
|
||||
static constexpr ConsequencesFactoryType ConsequencesFactory{Normal};
|
||||
|
||||
explicit EscrowFinish(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static bool
|
||||
checkExtraFeatures(PreflightContext const& ctx);
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static NotTEC
|
||||
preflightSigValidated(PreflightContext const& ctx);
|
||||
|
||||
static XRPAmount
|
||||
calculateBaseFee(ReadView const& view, STTx const& tx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class EscrowCancel : public Transactor
|
||||
{
|
||||
public:
|
||||
static constexpr ConsequencesFactoryType ConsequencesFactory{Normal};
|
||||
|
||||
explicit EscrowCancel(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
26
include/xrpl/tx/transactors/escrow/EscrowCancel.h
Normal file
26
include/xrpl/tx/transactors/escrow/EscrowCancel.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/tx/Transactor.h>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
class EscrowCancel : public Transactor
|
||||
{
|
||||
public:
|
||||
static constexpr ConsequencesFactoryType ConsequencesFactory{Normal};
|
||||
|
||||
explicit EscrowCancel(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
29
include/xrpl/tx/transactors/escrow/EscrowCreate.h
Normal file
29
include/xrpl/tx/transactors/escrow/EscrowCreate.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/tx/Transactor.h>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
class EscrowCreate : public Transactor
|
||||
{
|
||||
public:
|
||||
static constexpr ConsequencesFactoryType ConsequencesFactory{Custom};
|
||||
|
||||
explicit EscrowCreate(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static TxConsequences
|
||||
makeTxConsequences(PreflightContext const& ctx);
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
35
include/xrpl/tx/transactors/escrow/EscrowFinish.h
Normal file
35
include/xrpl/tx/transactors/escrow/EscrowFinish.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/tx/Transactor.h>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
class EscrowFinish : public Transactor
|
||||
{
|
||||
public:
|
||||
static constexpr ConsequencesFactoryType ConsequencesFactory{Normal};
|
||||
|
||||
explicit EscrowFinish(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static bool
|
||||
checkExtraFeatures(PreflightContext const& ctx);
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static NotTEC
|
||||
preflightSigValidated(PreflightContext const& ctx);
|
||||
|
||||
static XRPAmount
|
||||
calculateBaseFee(ReadView const& view, STTx const& tx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
#include <xrpl/protocol/TxFlags.h>
|
||||
#include <xrpl/protocol/nft.h>
|
||||
#include <xrpl/tx/Transactor.h>
|
||||
|
||||
@@ -54,7 +55,7 @@ removeToken(
|
||||
ApplyView& view,
|
||||
AccountID const& owner,
|
||||
uint256 const& nftokenID,
|
||||
std::shared_ptr<SLE>&& page);
|
||||
std::shared_ptr<SLE> const& page);
|
||||
|
||||
/** Deletes the given token offer.
|
||||
|
||||
@@ -95,7 +96,7 @@ tokenOfferCreatePreflight(
|
||||
std::uint16_t nftFlags,
|
||||
Rules const& rules,
|
||||
std::optional<AccountID> const& owner = std::nullopt,
|
||||
std::uint32_t txFlags = lsfSellNFToken);
|
||||
std::uint32_t txFlags = tfSellNFToken);
|
||||
|
||||
/** Preclaim checks shared by NFTokenCreateOffer and NFTokenMint */
|
||||
TER
|
||||
@@ -109,7 +110,7 @@ tokenOfferCreatePreclaim(
|
||||
std::uint16_t xferFee,
|
||||
beast::Journal j,
|
||||
std::optional<AccountID> const& owner = std::nullopt,
|
||||
std::uint32_t txFlags = lsfSellNFToken);
|
||||
std::uint32_t txFlags = tfSellNFToken);
|
||||
|
||||
/** doApply implementation shared by NFTokenCreateOffer and NFTokenMint */
|
||||
TER
|
||||
@@ -123,7 +124,7 @@ tokenOfferCreateApply(
|
||||
uint256 const& nftokenID,
|
||||
XRPAmount const& priorBalance,
|
||||
beast::Journal j,
|
||||
std::uint32_t txFlags = lsfSellNFToken);
|
||||
std::uint32_t txFlags = tfSellNFToken);
|
||||
|
||||
TER
|
||||
checkTrustlineAuthorized(
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/tx/Transactor.h>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
class PayChanCreate : public Transactor
|
||||
{
|
||||
public:
|
||||
static constexpr ConsequencesFactoryType ConsequencesFactory{Custom};
|
||||
|
||||
explicit PayChanCreate(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static TxConsequences
|
||||
makeTxConsequences(PreflightContext const& ctx);
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
};
|
||||
|
||||
using PaymentChannelCreate = PayChanCreate;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class PayChanFund : public Transactor
|
||||
{
|
||||
public:
|
||||
static constexpr ConsequencesFactoryType ConsequencesFactory{Custom};
|
||||
|
||||
explicit PayChanFund(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static TxConsequences
|
||||
makeTxConsequences(PreflightContext const& ctx);
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
};
|
||||
|
||||
using PaymentChannelFund = PayChanFund;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class PayChanClaim : public Transactor
|
||||
{
|
||||
public:
|
||||
static constexpr ConsequencesFactoryType ConsequencesFactory{Normal};
|
||||
|
||||
explicit PayChanClaim(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static bool
|
||||
checkExtraFeatures(PreflightContext const& ctx);
|
||||
|
||||
static std::uint32_t
|
||||
getFlagsMask(PreflightContext const& ctx);
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
};
|
||||
|
||||
using PaymentChannelClaim = PayChanClaim;
|
||||
|
||||
} // namespace xrpl
|
||||
34
include/xrpl/tx/transactors/payment_channel/PayChanClaim.h
Normal file
34
include/xrpl/tx/transactors/payment_channel/PayChanClaim.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/tx/Transactor.h>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
class PayChanClaim : public Transactor
|
||||
{
|
||||
public:
|
||||
static constexpr ConsequencesFactoryType ConsequencesFactory{Normal};
|
||||
|
||||
explicit PayChanClaim(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static bool
|
||||
checkExtraFeatures(PreflightContext const& ctx);
|
||||
|
||||
static std::uint32_t
|
||||
getFlagsMask(PreflightContext const& ctx);
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
};
|
||||
|
||||
using PaymentChannelClaim = PayChanClaim;
|
||||
|
||||
} // namespace xrpl
|
||||
31
include/xrpl/tx/transactors/payment_channel/PayChanCreate.h
Normal file
31
include/xrpl/tx/transactors/payment_channel/PayChanCreate.h
Normal file
@@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/tx/Transactor.h>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
class PayChanCreate : public Transactor
|
||||
{
|
||||
public:
|
||||
static constexpr ConsequencesFactoryType ConsequencesFactory{Custom};
|
||||
|
||||
explicit PayChanCreate(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static TxConsequences
|
||||
makeTxConsequences(PreflightContext const& ctx);
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
};
|
||||
|
||||
using PaymentChannelCreate = PayChanCreate;
|
||||
|
||||
} // namespace xrpl
|
||||
28
include/xrpl/tx/transactors/payment_channel/PayChanFund.h
Normal file
28
include/xrpl/tx/transactors/payment_channel/PayChanFund.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/tx/Transactor.h>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
class PayChanFund : public Transactor
|
||||
{
|
||||
public:
|
||||
static constexpr ConsequencesFactoryType ConsequencesFactory{Custom};
|
||||
|
||||
explicit PayChanFund(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static TxConsequences
|
||||
makeTxConsequences(PreflightContext const& ctx);
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
};
|
||||
|
||||
using PaymentChannelFund = PayChanFund;
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -1,24 +1,6 @@
|
||||
# The idea is to empty this file gradually by fixing the underlying issues and removing suppressions.
|
||||
#
|
||||
# ASAN_OPTIONS="print_stacktrace=1:detect_container_overflow=0:suppressions=sanitizers/suppressions/asan.supp:halt_on_error=0"
|
||||
#
|
||||
# The detect_container_overflow=0 option disables false positives from:
|
||||
# - Boost intrusive containers (slist_iterator.hpp, hashtable.hpp, aged_unordered_container.h)
|
||||
# - Boost context/coroutine stack switching (Workers.cpp, thread.h)
|
||||
#
|
||||
# See: https://github.com/google/sanitizers/wiki/AddressSanitizerContainerOverflow
|
||||
|
||||
# Boost
|
||||
interceptor_name:boost/asio
|
||||
|
||||
# Leaks in Doctest tests: xrpl.test.*
|
||||
interceptor_name:src/libxrpl/net/HTTPClient.cpp
|
||||
interceptor_name:src/libxrpl/net/RegisterSSLCerts.cpp
|
||||
interceptor_name:src/tests/libxrpl/net/HTTPClient.cpp
|
||||
interceptor_name:xrpl/net/AutoSocket.h
|
||||
interceptor_name:xrpl/net/HTTPClient.h
|
||||
interceptor_name:xrpl/net/HTTPClientSSLContext.h
|
||||
interceptor_name:xrpl/net/RegisterSSLCerts.h
|
||||
|
||||
# Suppress false positive stack-buffer errors in thread stack allocation
|
||||
# Related to ASan's __asan_handle_no_return warnings (github.com/google/sanitizers/issues/189)
|
||||
|
||||
@@ -1,16 +1,5 @@
|
||||
# The idea is to empty this file gradually by fixing the underlying issues and removing suppresions.
|
||||
|
||||
# Suppress leaks detected by asan in rippled code.
|
||||
leak:src/libxrpl/net/HTTPClient.cpp
|
||||
leak:src/libxrpl/net/RegisterSSLCerts.cpp
|
||||
leak:src/tests/libxrpl/net/HTTPClient.cpp
|
||||
leak:xrpl/net/AutoSocket.h
|
||||
leak:xrpl/net/HTTPClient.h
|
||||
leak:xrpl/net/HTTPClientSSLContext.h
|
||||
leak:xrpl/net/RegisterSSLCerts.h
|
||||
leak:ripple::HTTPClient
|
||||
leak:ripple::HTTPClientImp
|
||||
|
||||
# Suppress leaks detected by asan in boost code.
|
||||
leak:boost::asio
|
||||
leak:boost/asio
|
||||
|
||||
8
sanitizers/suppressions/runtime-asan-options.txt
Normal file
8
sanitizers/suppressions/runtime-asan-options.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
detect_container_overflow=false
|
||||
detect_stack_use_after_return=false
|
||||
debug=true
|
||||
halt_on_error=false
|
||||
print_stats=true
|
||||
print_cmdline=true
|
||||
use_sigaltstack=0
|
||||
print_stacktrace=1
|
||||
1
sanitizers/suppressions/runtime-lsan-options.txt
Normal file
1
sanitizers/suppressions/runtime-lsan-options.txt
Normal file
@@ -0,0 +1 @@
|
||||
halt_on_error=false
|
||||
3
sanitizers/suppressions/runtime-tsan-options.txt
Normal file
3
sanitizers/suppressions/runtime-tsan-options.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
halt_on_error=false
|
||||
verbosity=1
|
||||
second_deadlock_stack=1
|
||||
1
sanitizers/suppressions/runtime-ubsan-options.txt
Normal file
1
sanitizers/suppressions/runtime-ubsan-options.txt
Normal file
@@ -0,0 +1 @@
|
||||
halt_on_error=false
|
||||
@@ -27,3 +27,11 @@ src:core/JobQueue.cpp
|
||||
src:libxrpl/beast/utility/beast_Journal.cpp
|
||||
src:test/beast/beast_PropertyStream_test.cpp
|
||||
src:src/test/app/Invariants_test.cpp
|
||||
|
||||
# ASan false positive: stack-use-after-scope in ErrorCodes.h inline functions.
|
||||
# When Clang inlines the StaticString overloads (e.g. invalid_field_error(StaticString)),
|
||||
# ASan scope-poisons the temporary std::string before the inlined callee finishes reading
|
||||
# through the const ref. This corrupts the coroutine stack and crashes the Simulate test.
|
||||
# See asan.supp comments for full explanation and planned fix.
|
||||
[address]
|
||||
src:*ErrorCodes.h
|
||||
|
||||
@@ -182,6 +182,17 @@ signed-integer-overflow:src/test/beast/LexicalCast_test.cpp
|
||||
# External library suppressions
|
||||
unsigned-integer-overflow:nudb/detail/xxhash.hpp
|
||||
|
||||
# Loan_test.cpp intentional underflow in test arithmetic
|
||||
unsigned-integer-overflow:src/test/app/Loan_test.cpp
|
||||
undefined:src/test/app/Loan_test.cpp
|
||||
|
||||
# Source tree restructured paths (libxrpl/tx/transactors/)
|
||||
# These duplicate the xrpld/app/tx/detail entries above for the new layout
|
||||
unsigned-integer-overflow:src/libxrpl/tx/transactors/oracle/SetOracle.cpp
|
||||
undefined:src/libxrpl/tx/transactors/oracle/SetOracle.cpp
|
||||
unsigned-integer-overflow:src/libxrpl/tx/transactors/nft/NFTokenMint.cpp
|
||||
undefined:src/libxrpl/tx/transactors/nft/NFTokenMint.cpp
|
||||
|
||||
# Protobuf intentional overflows in hash functions
|
||||
# Protobuf uses intentional unsigned overflow for hash computation (stringpiece.h:393)
|
||||
unsigned-integer-overflow:google/protobuf/stubs/stringpiece.h
|
||||
|
||||
@@ -51,8 +51,8 @@ extractTarLz4(boost::filesystem::path const& src, boost::filesystem::path const&
|
||||
if (archive_write_disk_set_standard_lookup(aw.get()) < ARCHIVE_OK)
|
||||
Throw<std::runtime_error>(archive_error_string(aw.get()));
|
||||
|
||||
int result;
|
||||
struct archive_entry* entry;
|
||||
int result = 0;
|
||||
struct archive_entry* entry = nullptr;
|
||||
while (true)
|
||||
{
|
||||
result = archive_read_next_header(ar.get(), &entry);
|
||||
@@ -67,9 +67,9 @@ extractTarLz4(boost::filesystem::path const& src, boost::filesystem::path const&
|
||||
|
||||
if (archive_entry_size(entry) > 0)
|
||||
{
|
||||
void const* buf;
|
||||
size_t sz;
|
||||
la_int64_t offset;
|
||||
void const* buf = nullptr;
|
||||
size_t sz = 0;
|
||||
la_int64_t offset = 0;
|
||||
while (true)
|
||||
{
|
||||
result = archive_read_data_block(ar.get(), &buf, &sz, &offset);
|
||||
|
||||
@@ -55,7 +55,7 @@ Section::append(std::vector<std::string> const& lines)
|
||||
val = "";
|
||||
break;
|
||||
}
|
||||
else if (val.at(comment - 1) == '\\')
|
||||
if (val.at(comment - 1) == '\\')
|
||||
{
|
||||
// we have an escaped comment char. Erase the escape char
|
||||
// and keep looking
|
||||
@@ -83,9 +83,13 @@ Section::append(std::vector<std::string> const& lines)
|
||||
|
||||
boost::smatch match;
|
||||
if (boost::regex_match(line, match, re1))
|
||||
{
|
||||
set(match[1], match[2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
values_.push_back(line);
|
||||
}
|
||||
|
||||
lines_.push_back(std::move(line));
|
||||
}
|
||||
|
||||
@@ -417,9 +417,13 @@ public:
|
||||
swap(holder_, sink);
|
||||
|
||||
if (holder_)
|
||||
{
|
||||
sink_ = *holder_;
|
||||
}
|
||||
else
|
||||
{
|
||||
sink_ = beast::Journal::getNullSink();
|
||||
}
|
||||
|
||||
return sink;
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ parseStatmRSSkB(std::string const& statm)
|
||||
// /proc/self/statm format: size resident shared text lib data dt
|
||||
// We want the second field (resident) which is in pages
|
||||
std::istringstream iss(statm);
|
||||
long size, resident;
|
||||
long size = 0, resident = 0;
|
||||
if (!(iss >> size >> resident))
|
||||
return -1;
|
||||
|
||||
|
||||
@@ -66,14 +66,12 @@ concept UnsignedMantissa = std::is_unsigned_v<T> || std::is_same_v<T, uint128_t>
|
||||
|
||||
class Number::Guard
|
||||
{
|
||||
std::uint64_t digits_; // 16 decimal guard digits
|
||||
std::uint8_t xbit_ : 1; // has a non-zero digit been shifted off the end
|
||||
std::uint8_t sbit_ : 1; // the sign of the guard digits
|
||||
std::uint64_t digits_{0}; // 16 decimal guard digits
|
||||
std::uint8_t xbit_ : 1 {0}; // has a non-zero digit been shifted off the end
|
||||
std::uint8_t sbit_ : 1 {0}; // the sign of the guard digits
|
||||
|
||||
public:
|
||||
explicit Guard() : digits_{0}, xbit_{0}, sbit_{0}
|
||||
{
|
||||
}
|
||||
explicit Guard() = default;
|
||||
|
||||
// set & test the sign bit
|
||||
void
|
||||
@@ -96,7 +94,7 @@ public:
|
||||
// This enables the client to round towards nearest, and on
|
||||
// tie, round towards even.
|
||||
int
|
||||
round() noexcept;
|
||||
round() const noexcept;
|
||||
|
||||
// Modify the result to the correctly rounded value
|
||||
template <UnsignedMantissa T>
|
||||
@@ -116,7 +114,7 @@ public:
|
||||
|
||||
// Modify the result to the correctly rounded value
|
||||
void
|
||||
doRound(rep& drops, std::string location);
|
||||
doRound(rep& drops, std::string location) const;
|
||||
|
||||
private:
|
||||
void
|
||||
@@ -173,7 +171,7 @@ Number::Guard::pop() noexcept
|
||||
// 0 if Guard is exactly half
|
||||
// 1 if Guard is greater than half
|
||||
int
|
||||
Number::Guard::round() noexcept
|
||||
Number::Guard::round() const noexcept
|
||||
{
|
||||
auto mode = Number::getround();
|
||||
|
||||
@@ -258,7 +256,7 @@ Number::Guard::doRoundUp(
|
||||
}
|
||||
bringIntoRange(negative, mantissa, exponent, minMantissa);
|
||||
if (exponent > maxExponent)
|
||||
throw std::overflow_error(location);
|
||||
Throw<std::overflow_error>(std::string(location));
|
||||
}
|
||||
|
||||
template <UnsignedMantissa T>
|
||||
@@ -284,7 +282,7 @@ Number::Guard::doRoundDown(
|
||||
|
||||
// Modify the result to the correctly rounded value
|
||||
void
|
||||
Number::Guard::doRound(rep& drops, std::string location)
|
||||
Number::Guard::doRound(rep& drops, std::string location) const
|
||||
{
|
||||
auto r = round();
|
||||
if (r == 1 || (r == 0 && (drops & 1) == 1))
|
||||
@@ -298,7 +296,7 @@ Number::Guard::doRound(rep& drops, std::string location)
|
||||
// or "(maxRep + 1) / 10", neither of which will round up when
|
||||
// converting to rep, though the latter might overflow _before_
|
||||
// rounding.
|
||||
throw std::overflow_error(location); // LCOV_EXCL_LINE
|
||||
Throw<std::overflow_error>(std::string(location)); // LCOV_EXCL_LINE
|
||||
}
|
||||
++drops;
|
||||
}
|
||||
@@ -913,9 +911,13 @@ to_string(Number const& amount)
|
||||
|
||||
// Assemble the output:
|
||||
if (pre_from == pre_to)
|
||||
{
|
||||
ret.append(1, '0');
|
||||
}
|
||||
else
|
||||
{
|
||||
ret.append(pre_from, pre_to);
|
||||
}
|
||||
|
||||
if (post_to != post_from)
|
||||
{
|
||||
|
||||
@@ -35,7 +35,6 @@ namespace xrpl {
|
||||
template <class Derived>
|
||||
class AsyncObject
|
||||
{
|
||||
protected:
|
||||
AsyncObject() : m_pending(0)
|
||||
{
|
||||
}
|
||||
@@ -93,6 +92,8 @@ public:
|
||||
private:
|
||||
// The number of handlers pending.
|
||||
std::atomic<int> m_pending;
|
||||
|
||||
friend Derived;
|
||||
};
|
||||
|
||||
class ResolverAsioImpl : public ResolverAsio, public AsyncObject<ResolverAsioImpl>
|
||||
@@ -108,7 +109,7 @@ public:
|
||||
|
||||
std::condition_variable m_cv;
|
||||
std::mutex m_mut;
|
||||
bool m_asyncHandlersCompleted;
|
||||
bool m_asyncHandlersCompleted{true};
|
||||
|
||||
std::atomic<bool> m_stop_called;
|
||||
std::atomic<bool> m_stopped;
|
||||
@@ -135,7 +136,6 @@ public:
|
||||
, m_io_context(io_context)
|
||||
, m_strand(boost::asio::make_strand(io_context))
|
||||
, m_resolver(io_context)
|
||||
, m_asyncHandlersCompleted(true)
|
||||
, m_stop_called(false)
|
||||
, m_stopped(true)
|
||||
{
|
||||
@@ -374,7 +374,7 @@ public:
|
||||
JLOG(m_journal.debug()) << "Queued new job with " << names.size() << " tasks. "
|
||||
<< m_work.size() << " jobs outstanding.";
|
||||
|
||||
if (m_work.size() > 0)
|
||||
if (!m_work.empty())
|
||||
{
|
||||
boost::asio::post(
|
||||
m_io_context,
|
||||
|
||||
@@ -103,7 +103,7 @@ trim_whitespace(std::string str)
|
||||
std::optional<std::uint64_t>
|
||||
to_uint64(std::string const& s)
|
||||
{
|
||||
std::uint64_t result;
|
||||
std::uint64_t result = 0;
|
||||
if (beast::lexicalCastChecked(result, s))
|
||||
return result;
|
||||
return std::nullopt;
|
||||
|
||||
@@ -77,13 +77,13 @@ get_inverse()
|
||||
}
|
||||
|
||||
/// Returns max chars needed to encode a base64 string
|
||||
inline std::size_t constexpr encoded_size(std::size_t n)
|
||||
std::size_t constexpr encoded_size(std::size_t n)
|
||||
{
|
||||
return 4 * ((n + 2) / 3);
|
||||
}
|
||||
|
||||
/// Returns max bytes needed to decode a base64 string
|
||||
inline std::size_t constexpr decoded_size(std::size_t n)
|
||||
std::size_t constexpr decoded_size(std::size_t n)
|
||||
{
|
||||
return ((n / 4) * 3) + 2;
|
||||
}
|
||||
@@ -116,6 +116,7 @@ encode(void* dest, void const* src, std::size_t len)
|
||||
in += 3;
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(bugprone-switch-missing-default-case)
|
||||
switch (len % 3)
|
||||
{
|
||||
case 2:
|
||||
|
||||
@@ -239,6 +239,7 @@ initAuthenticated(
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
|
||||
// NOLINTNEXTLINE(bugprone-unused-return-value)
|
||||
context.use_certificate_file(cert_file, boost::asio::ssl::context::pem, ec);
|
||||
|
||||
if (ec)
|
||||
@@ -271,9 +272,11 @@ initAuthenticated(
|
||||
if (!cert_set)
|
||||
{
|
||||
if (SSL_CTX_use_certificate(ssl, x) != 1)
|
||||
{
|
||||
LogicError(
|
||||
"Problem retrieving SSL certificate from chain "
|
||||
"file.");
|
||||
}
|
||||
|
||||
cert_set = true;
|
||||
}
|
||||
@@ -298,6 +301,7 @@ initAuthenticated(
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
|
||||
// NOLINTNEXTLINE(bugprone-unused-return-value)
|
||||
context.use_private_key_file(key_file, boost::asio::ssl::context::pem, ec);
|
||||
|
||||
if (ec)
|
||||
|
||||
@@ -16,7 +16,7 @@ class seconds_clock_thread
|
||||
{
|
||||
using Clock = basic_seconds_clock::Clock;
|
||||
|
||||
bool stop_;
|
||||
bool stop_{false};
|
||||
std::mutex mut_;
|
||||
std::condition_variable cv_;
|
||||
std::thread thread_;
|
||||
@@ -48,8 +48,7 @@ seconds_clock_thread::~seconds_clock_thread()
|
||||
thread_.join();
|
||||
}
|
||||
|
||||
seconds_clock_thread::seconds_clock_thread()
|
||||
: stop_{false}, tp_{Clock::now().time_since_epoch().count()}
|
||||
seconds_clock_thread::seconds_clock_thread() : tp_{Clock::now().time_since_epoch().count()}
|
||||
{
|
||||
thread_ = std::thread(&seconds_clock_thread::run, this);
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ print_identifiers(SemanticVersion::identifier_list const& list)
|
||||
bool
|
||||
isNumeric(std::string const& s)
|
||||
{
|
||||
int n;
|
||||
int n = 0;
|
||||
|
||||
// Must be convertible to an integer
|
||||
if (!lexicalCastChecked(n, s))
|
||||
@@ -68,7 +68,7 @@ chopUInt(int& value, int limit, std::string& input)
|
||||
if (item.empty())
|
||||
return false;
|
||||
|
||||
int n;
|
||||
int n = 0;
|
||||
|
||||
// Must be convertible to an integer
|
||||
if (!lexicalCastChecked(n, item))
|
||||
@@ -234,27 +234,43 @@ int
|
||||
compare(SemanticVersion const& lhs, SemanticVersion const& rhs)
|
||||
{
|
||||
if (lhs.majorVersion > rhs.majorVersion)
|
||||
{
|
||||
return 1;
|
||||
else if (lhs.majorVersion < rhs.majorVersion)
|
||||
}
|
||||
if (lhs.majorVersion < rhs.majorVersion)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (lhs.minorVersion > rhs.minorVersion)
|
||||
{
|
||||
return 1;
|
||||
else if (lhs.minorVersion < rhs.minorVersion)
|
||||
}
|
||||
if (lhs.minorVersion < rhs.minorVersion)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (lhs.patchVersion > rhs.patchVersion)
|
||||
{
|
||||
return 1;
|
||||
else if (lhs.patchVersion < rhs.patchVersion)
|
||||
}
|
||||
if (lhs.patchVersion < rhs.patchVersion)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (lhs.isPreRelease() || rhs.isPreRelease())
|
||||
{
|
||||
// Pre-releases have a lower precedence
|
||||
if (lhs.isRelease() && rhs.isPreRelease())
|
||||
{
|
||||
return 1;
|
||||
else if (lhs.isPreRelease() && rhs.isRelease())
|
||||
}
|
||||
if (lhs.isPreRelease() && rhs.isRelease())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Compare pre-release identifiers
|
||||
for (int i = 0;
|
||||
@@ -263,18 +279,26 @@ compare(SemanticVersion const& lhs, SemanticVersion const& rhs)
|
||||
{
|
||||
// A larger list of identifiers has a higher precedence
|
||||
if (i >= rhs.preReleaseIdentifiers.size())
|
||||
{
|
||||
return 1;
|
||||
else if (i >= lhs.preReleaseIdentifiers.size())
|
||||
}
|
||||
if (i >= lhs.preReleaseIdentifiers.size())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::string const& left(lhs.preReleaseIdentifiers[i]);
|
||||
std::string const& right(rhs.preReleaseIdentifiers[i]);
|
||||
|
||||
// Numeric identifiers have lower precedence
|
||||
if (!isNumeric(left) && isNumeric(right))
|
||||
{
|
||||
return 1;
|
||||
else if (isNumeric(left) && !isNumeric(right))
|
||||
}
|
||||
if (isNumeric(left) && !isNumeric(right))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (isNumeric(left))
|
||||
{
|
||||
@@ -284,9 +308,13 @@ compare(SemanticVersion const& lhs, SemanticVersion const& rhs)
|
||||
int const iRight(lexicalCastThrow<int>(right));
|
||||
|
||||
if (iLeft > iRight)
|
||||
{
|
||||
return 1;
|
||||
else if (iLeft < iRight)
|
||||
}
|
||||
if (iLeft < iRight)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -104,8 +104,8 @@ private:
|
||||
|
||||
std::shared_ptr<StatsDCollectorImp> m_impl;
|
||||
std::string m_name;
|
||||
CounterImpl::value_type m_value;
|
||||
bool m_dirty;
|
||||
CounterImpl::value_type m_value{0};
|
||||
bool m_dirty{false};
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -162,9 +162,9 @@ private:
|
||||
|
||||
std::shared_ptr<StatsDCollectorImp> m_impl;
|
||||
std::string m_name;
|
||||
GaugeImpl::value_type m_last_value;
|
||||
GaugeImpl::value_type m_value;
|
||||
bool m_dirty;
|
||||
GaugeImpl::value_type m_last_value{0};
|
||||
GaugeImpl::value_type m_value{0};
|
||||
bool m_dirty{false};
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -194,8 +194,8 @@ private:
|
||||
|
||||
std::shared_ptr<StatsDCollectorImp> m_impl;
|
||||
std::string m_name;
|
||||
MeterImpl::value_type m_value;
|
||||
bool m_dirty;
|
||||
MeterImpl::value_type m_value{0};
|
||||
bool m_dirty{false};
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -470,6 +470,7 @@ public:
|
||||
|
||||
m_io_context.run();
|
||||
|
||||
// NOLINTNEXTLINE(bugprone-unused-return-value)
|
||||
m_socket.shutdown(boost::asio::ip::udp::socket::shutdown_send, ec);
|
||||
|
||||
m_socket.close();
|
||||
@@ -504,7 +505,7 @@ StatsDHookImpl::do_process()
|
||||
StatsDCounterImpl::StatsDCounterImpl(
|
||||
std::string const& name,
|
||||
std::shared_ptr<StatsDCollectorImp> const& impl)
|
||||
: m_impl(impl), m_name(name), m_value(0), m_dirty(false)
|
||||
: m_impl(impl), m_name(name)
|
||||
{
|
||||
m_impl->add(*this);
|
||||
}
|
||||
@@ -586,7 +587,7 @@ StatsDEventImpl::do_notify(EventImpl::value_type const& value)
|
||||
StatsDGaugeImpl::StatsDGaugeImpl(
|
||||
std::string const& name,
|
||||
std::shared_ptr<StatsDCollectorImp> const& impl)
|
||||
: m_impl(impl), m_name(name), m_last_value(0), m_value(0), m_dirty(false)
|
||||
: m_impl(impl), m_name(name)
|
||||
{
|
||||
m_impl->add(*this);
|
||||
}
|
||||
@@ -675,7 +676,7 @@ StatsDGaugeImpl::do_process()
|
||||
StatsDMeterImpl::StatsDMeterImpl(
|
||||
std::string const& name,
|
||||
std::shared_ptr<StatsDCollectorImp> const& impl)
|
||||
: m_impl(impl), m_name(name), m_value(0), m_dirty(false)
|
||||
: m_impl(impl), m_name(name)
|
||||
{
|
||||
m_impl->add(*this);
|
||||
}
|
||||
|
||||
@@ -95,10 +95,14 @@ operator>>(std::istream& is, Endpoint& endpoint)
|
||||
char i{0};
|
||||
char readTo{0};
|
||||
is.get(i);
|
||||
if (i == '[') // we are an IPv6 endpoint
|
||||
if (i == '[')
|
||||
{ // we are an IPv6 endpoint
|
||||
readTo = ']';
|
||||
}
|
||||
else
|
||||
{
|
||||
addrStr += i;
|
||||
}
|
||||
|
||||
while (is && is.rdbuf()->in_avail() > 0 && is.get(i))
|
||||
{
|
||||
@@ -159,14 +163,16 @@ operator>>(std::istream& is, Endpoint& endpoint)
|
||||
|
||||
if (is.rdbuf()->in_avail() > 0)
|
||||
{
|
||||
Port port;
|
||||
Port port = 0;
|
||||
is >> port;
|
||||
if (is.fail())
|
||||
return is;
|
||||
endpoint = Endpoint(addr, port);
|
||||
}
|
||||
else
|
||||
{
|
||||
endpoint = Endpoint(addr);
|
||||
}
|
||||
|
||||
return is;
|
||||
}
|
||||
|
||||
@@ -124,9 +124,13 @@ Journal::ScopedStream::~ScopedStream()
|
||||
if (!s.empty())
|
||||
{
|
||||
if (s == "\n")
|
||||
{
|
||||
m_sink.write(m_level, "");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_sink.write(m_level, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace beast {
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
PropertyStream::Item::Item(Source* source) : m_source(source)
|
||||
PropertyStream::Item::Item(Source* source) : ListNode(), m_source(source)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -237,9 +237,13 @@ PropertyStream::Source::write(PropertyStream& stream, std::string const& path)
|
||||
return;
|
||||
|
||||
if (result.second)
|
||||
{
|
||||
result.first->write(stream);
|
||||
}
|
||||
else
|
||||
{
|
||||
result.first->write_one(stream);
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<PropertyStream::Source*, bool>
|
||||
@@ -301,9 +305,13 @@ PropertyStream::Source::peel_name(std::string* path)
|
||||
std::string s(first, pos);
|
||||
|
||||
if (pos != last)
|
||||
{
|
||||
*path = std::string(pos + 1, last);
|
||||
}
|
||||
else
|
||||
{
|
||||
*path = std::string();
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
@@ -371,9 +379,13 @@ void
|
||||
PropertyStream::add(std::string const& key, bool value)
|
||||
{
|
||||
if (value)
|
||||
{
|
||||
add(key, "true");
|
||||
}
|
||||
else
|
||||
{
|
||||
add(key, "false");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -464,9 +476,13 @@ void
|
||||
PropertyStream::add(bool value)
|
||||
{
|
||||
if (value)
|
||||
{
|
||||
add("true");
|
||||
}
|
||||
else
|
||||
{
|
||||
add("false");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -331,7 +331,7 @@ JobQueue::finishJob(JobType type)
|
||||
void
|
||||
JobQueue::processTask(int instance)
|
||||
{
|
||||
JobType type;
|
||||
JobType type = jtINVALID;
|
||||
|
||||
{
|
||||
using namespace std::chrono;
|
||||
|
||||
@@ -205,11 +205,9 @@ Workers::Worker::run()
|
||||
// We got paused
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Undo our decrement
|
||||
++m_workers.m_pauseCount;
|
||||
}
|
||||
|
||||
// Undo our decrement
|
||||
++m_workers.m_pauseCount;
|
||||
}
|
||||
|
||||
// We couldn't pause so we must have gotten
|
||||
|
||||
@@ -198,10 +198,10 @@ char const* RFC1751::s_dictionary[2048] = {
|
||||
unsigned long
|
||||
RFC1751::extract(char const* s, int start, int length)
|
||||
{
|
||||
unsigned char cl;
|
||||
unsigned char cc;
|
||||
unsigned char cr;
|
||||
unsigned long x;
|
||||
unsigned char cl = 0;
|
||||
unsigned char cc = 0;
|
||||
unsigned char cr = 0;
|
||||
unsigned long x = 0;
|
||||
|
||||
XRPL_ASSERT(length <= 11, "xrpl::RFC1751::extract : maximum length");
|
||||
XRPL_ASSERT(start >= 0, "xrpl::RFC1751::extract : minimum start");
|
||||
@@ -226,7 +226,7 @@ void
|
||||
RFC1751::btoe(std::string& strHuman, std::string const& strData)
|
||||
{
|
||||
char caBuffer[9]; /* add in room for the parity 2 bits*/
|
||||
int p, i;
|
||||
int p = 0, i = 0;
|
||||
|
||||
memcpy(caBuffer, strData.c_str(), 8);
|
||||
|
||||
@@ -245,11 +245,11 @@ RFC1751::btoe(std::string& strHuman, std::string const& strData)
|
||||
void
|
||||
RFC1751::insert(char* s, int x, int start, int length)
|
||||
{
|
||||
unsigned char cl;
|
||||
unsigned char cc;
|
||||
unsigned char cr;
|
||||
unsigned long y;
|
||||
int shift;
|
||||
unsigned char cl = 0;
|
||||
unsigned char cc = 0;
|
||||
unsigned char cr = 0;
|
||||
unsigned long y = 0;
|
||||
int shift = 0;
|
||||
|
||||
XRPL_ASSERT(length <= 11, "xrpl::RFC1751::insert : maximum length");
|
||||
XRPL_ASSERT(start >= 0, "xrpl::RFC1751::insert : minimum start");
|
||||
@@ -285,13 +285,21 @@ RFC1751::standard(std::string& strWord)
|
||||
for (auto& letter : strWord)
|
||||
{
|
||||
if (islower(static_cast<unsigned char>(letter)))
|
||||
{
|
||||
letter = toupper(static_cast<unsigned char>(letter));
|
||||
}
|
||||
else if (letter == '1')
|
||||
{
|
||||
letter = 'L';
|
||||
}
|
||||
else if (letter == '0')
|
||||
{
|
||||
letter = 'O';
|
||||
}
|
||||
else if (letter == '5')
|
||||
{
|
||||
letter = 'S';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -336,7 +344,7 @@ RFC1751::etob(std::string& strData, std::vector<std::string> vsHuman)
|
||||
if (6 != vsHuman.size())
|
||||
return -1;
|
||||
|
||||
int i, p = 0;
|
||||
int i = 0, p = 0;
|
||||
char b[9] = {0};
|
||||
|
||||
for (auto& strWord : vsHuman)
|
||||
|
||||
@@ -30,7 +30,7 @@ csprng_engine::~csprng_engine()
|
||||
void
|
||||
csprng_engine::mix_entropy(void* buffer, std::size_t count)
|
||||
{
|
||||
std::array<std::random_device::result_type, 128> entropy;
|
||||
std::array<std::random_device::result_type, 128> entropy{};
|
||||
|
||||
{
|
||||
// On every platform we support, std::random_device
|
||||
@@ -71,7 +71,7 @@ csprng_engine::operator()(void* ptr, std::size_t count)
|
||||
csprng_engine::result_type
|
||||
csprng_engine::operator()()
|
||||
{
|
||||
result_type ret;
|
||||
result_type ret = 0;
|
||||
(*this)(&ret, sizeof(result_type));
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ std::map<char, char const*> jsonSpecialCharacterEscape = {
|
||||
{'\r', "\\r"},
|
||||
{'\t', "\\t"}};
|
||||
|
||||
static size_t const jsonEscapeLength = 2;
|
||||
size_t const jsonEscapeLength = 2;
|
||||
|
||||
// All other JSON punctuation.
|
||||
char const closeBrace = '}';
|
||||
@@ -36,7 +36,7 @@ char const openBrace = '{';
|
||||
char const openBracket = '[';
|
||||
char const quote = '"';
|
||||
|
||||
static auto const integralFloatsBecomeInts = false;
|
||||
auto const integralFloatsBecomeInts = false;
|
||||
|
||||
size_t
|
||||
lengthWithoutTrailingZeros(std::string const& s)
|
||||
@@ -137,9 +137,13 @@ public:
|
||||
check(false, "Not an " + ((type == array ? "array: " : "object: ") + message));
|
||||
}
|
||||
if (stack_.top().isFirst)
|
||||
{
|
||||
stack_.top().isFirst = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
output_({&comma, 1});
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -196,7 +200,7 @@ private:
|
||||
explicit Collection() = default;
|
||||
|
||||
/** What type of collection are we in? */
|
||||
Writer::CollectionType type;
|
||||
Writer::CollectionType type = Writer::CollectionType::array;
|
||||
|
||||
/** Is this the first entry in a collection?
|
||||
* If false, we have to emit a , before we write the next entry. */
|
||||
|
||||
@@ -94,7 +94,7 @@ Reader::parse(char const* beginDoc, char const* endDoc, Value& root)
|
||||
|
||||
nodes_.push(&root);
|
||||
bool successful = readValue(0);
|
||||
Token token;
|
||||
Token token{};
|
||||
skipCommentTokens(token);
|
||||
|
||||
if (!root.isNull() && !root.isArray() && !root.isObject())
|
||||
@@ -114,7 +114,7 @@ Reader::parse(char const* beginDoc, char const* endDoc, Value& root)
|
||||
bool
|
||||
Reader::readValue(unsigned depth)
|
||||
{
|
||||
Token token;
|
||||
Token token{};
|
||||
skipCommentTokens(token);
|
||||
if (depth > nest_limit)
|
||||
return addError("Syntax error: maximum nesting depth exceeded", token);
|
||||
@@ -278,9 +278,13 @@ Reader::skipSpaces()
|
||||
Char c = *current_;
|
||||
|
||||
if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
|
||||
{
|
||||
++current_;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -293,8 +297,10 @@ Reader::match(Location pattern, int patternLength)
|
||||
int index = patternLength;
|
||||
|
||||
while (index--)
|
||||
{
|
||||
if (current_[index] != pattern[index])
|
||||
return false;
|
||||
}
|
||||
|
||||
current_ += patternLength;
|
||||
return true;
|
||||
@@ -384,9 +390,13 @@ Reader::readString()
|
||||
c = getNextChar();
|
||||
|
||||
if (c == '\\')
|
||||
{
|
||||
getNextChar();
|
||||
}
|
||||
else if (c == '"')
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return c == '"';
|
||||
@@ -395,7 +405,7 @@ Reader::readString()
|
||||
bool
|
||||
Reader::readObject(Token& tokenStart, unsigned depth)
|
||||
{
|
||||
Token tokenName;
|
||||
Token tokenName{};
|
||||
std::string name;
|
||||
currentValue() = Value(objectValue);
|
||||
|
||||
@@ -420,7 +430,7 @@ Reader::readObject(Token& tokenStart, unsigned depth)
|
||||
if (!decodeString(tokenName, name))
|
||||
return recoverFromError(tokenObjectEnd);
|
||||
|
||||
Token colon;
|
||||
Token colon{};
|
||||
|
||||
if (!readToken(colon) || colon.type_ != tokenMemberSeparator)
|
||||
{
|
||||
@@ -440,7 +450,7 @@ Reader::readObject(Token& tokenStart, unsigned depth)
|
||||
if (!ok) // error already set
|
||||
return recoverFromError(tokenObjectEnd);
|
||||
|
||||
Token comma;
|
||||
Token comma{};
|
||||
|
||||
if (!readToken(comma) ||
|
||||
(comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
|
||||
@@ -470,7 +480,7 @@ Reader::readArray(Token& tokenStart, unsigned depth)
|
||||
|
||||
if (*current_ == ']') // empty array
|
||||
{
|
||||
Token endArray;
|
||||
Token endArray{};
|
||||
readToken(endArray);
|
||||
return true;
|
||||
}
|
||||
@@ -487,7 +497,7 @@ Reader::readArray(Token& tokenStart, unsigned depth)
|
||||
if (!ok) // error already set
|
||||
return recoverFromError(tokenArrayEnd);
|
||||
|
||||
Token token;
|
||||
Token token{};
|
||||
// Accept Comment after last item in the array.
|
||||
ok = readToken(token);
|
||||
|
||||
@@ -578,9 +588,13 @@ Reader::decodeNumber(Token& token)
|
||||
|
||||
// If it's representable as a signed integer, construct it as one.
|
||||
if (value <= Value::maxInt)
|
||||
{
|
||||
currentValue() = static_cast<Value::Int>(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
currentValue() = static_cast<Value::UInt>(value);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -591,7 +605,7 @@ Reader::decodeDouble(Token& token)
|
||||
{
|
||||
double value = 0;
|
||||
int const bufferSize = 32;
|
||||
int count;
|
||||
int count = 0;
|
||||
int length = int(token.end_ - token.start_);
|
||||
// Sanity check to avoid buffer overflow exploits.
|
||||
if (length < 0)
|
||||
@@ -646,8 +660,10 @@ Reader::decodeString(Token& token, std::string& decoded)
|
||||
Char c = *current++;
|
||||
|
||||
if (c == '"')
|
||||
{
|
||||
break;
|
||||
else if (c == '\\')
|
||||
}
|
||||
if (c == '\\')
|
||||
{
|
||||
if (current == end)
|
||||
return addError("Empty escape sequence in string", token, current);
|
||||
@@ -689,7 +705,7 @@ Reader::decodeString(Token& token, std::string& decoded)
|
||||
break;
|
||||
|
||||
case 'u': {
|
||||
unsigned int unicode;
|
||||
unsigned int unicode = 0;
|
||||
|
||||
if (!decodeUnicodeCodePoint(token, current, end, unicode))
|
||||
return false;
|
||||
@@ -721,19 +737,23 @@ Reader::decodeUnicodeCodePoint(Token& token, Location& current, Location end, un
|
||||
{
|
||||
// surrogate pairs
|
||||
if (end - current < 6)
|
||||
{
|
||||
return addError(
|
||||
"additional six characters expected to parse unicode surrogate "
|
||||
"pair.",
|
||||
token,
|
||||
current);
|
||||
}
|
||||
|
||||
unsigned int surrogatePair;
|
||||
unsigned int surrogatePair = 0;
|
||||
|
||||
if (*current != '\\' || *(current + 1) != 'u')
|
||||
{
|
||||
return addError(
|
||||
"expecting another \\u token to begin the second half of a unicode surrogate pair",
|
||||
token,
|
||||
current);
|
||||
}
|
||||
|
||||
current += 2; // skip two characters checked above
|
||||
|
||||
@@ -754,8 +774,10 @@ Reader::decodeUnicodeEscapeSequence(
|
||||
unsigned int& unicode)
|
||||
{
|
||||
if (end - current < 4)
|
||||
{
|
||||
return addError(
|
||||
"Bad unicode escape sequence in string: four digits expected.", token, current);
|
||||
}
|
||||
|
||||
unicode = 0;
|
||||
|
||||
@@ -765,17 +787,25 @@ Reader::decodeUnicodeEscapeSequence(
|
||||
unicode *= 16;
|
||||
|
||||
if (c >= '0' && c <= '9')
|
||||
{
|
||||
unicode += c - '0';
|
||||
}
|
||||
else if (c >= 'a' && c <= 'f')
|
||||
{
|
||||
unicode += c - 'a' + 10;
|
||||
}
|
||||
else if (c >= 'A' && c <= 'F')
|
||||
{
|
||||
unicode += c - 'A' + 10;
|
||||
}
|
||||
else
|
||||
{
|
||||
return addError(
|
||||
"Bad unicode escape sequence in string: hexadecimal digit "
|
||||
"expected.",
|
||||
token,
|
||||
current);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -796,7 +826,7 @@ bool
|
||||
Reader::recoverFromError(TokenType skipUntilToken)
|
||||
{
|
||||
int errorCount = int(errors_.size());
|
||||
Token skip;
|
||||
Token skip{};
|
||||
|
||||
while (true)
|
||||
{
|
||||
@@ -867,7 +897,7 @@ Reader::getLocationLineAndColumn(Location location, int& line, int& column) cons
|
||||
std::string
|
||||
Reader::getLocationLineAndColumn(Location location) const
|
||||
{
|
||||
int line, column;
|
||||
int line = 0, column = 0;
|
||||
getLocationLineAndColumn(location, line, column);
|
||||
return "Line " + std::to_string(line) + ", Column " + std::to_string(column);
|
||||
}
|
||||
|
||||
@@ -98,8 +98,11 @@ Value::CZString::CZString(CZString const& other)
|
||||
other.index_ != noDuplication && other.cstr_ != 0
|
||||
? valueAllocator()->makeMemberName(other.cstr_)
|
||||
: other.cstr_)
|
||||
, index_(
|
||||
other.cstr_ ? (other.index_ == noDuplication ? noDuplication : duplicate) : other.index_)
|
||||
, index_([&]() -> int {
|
||||
if (!other.cstr_)
|
||||
return other.index_;
|
||||
return other.index_ == noDuplication ? noDuplication : duplicate;
|
||||
}())
|
||||
{
|
||||
}
|
||||
|
||||
@@ -157,7 +160,7 @@ Value::CZString::isStaticString() const
|
||||
* memset( this, 0, sizeof(Value) )
|
||||
* This optimization is used in ValueInternalMap fast allocator.
|
||||
*/
|
||||
Value::Value(ValueType type) : type_(type), allocated_(0)
|
||||
Value::Value(ValueType type) : type_(type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
@@ -225,7 +228,7 @@ Value::Value(std::string const& value) : type_(stringValue), allocated_(true)
|
||||
valueAllocator()->duplicateStringValue(value.c_str(), (unsigned int)value.length());
|
||||
}
|
||||
|
||||
Value::Value(StaticString const& value) : type_(stringValue), allocated_(false)
|
||||
Value::Value(StaticString const& value) : type_(stringValue)
|
||||
{
|
||||
value_.string_ = const_cast<char*>(value.c_str());
|
||||
}
|
||||
@@ -254,7 +257,9 @@ Value::Value(Value const& other) : type_(other.type_)
|
||||
allocated_ = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
value_.string_ = 0;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
@@ -351,7 +356,9 @@ integerCmp(Int i, UInt ui)
|
||||
return -1;
|
||||
|
||||
// Now we can safely compare.
|
||||
return (i < ui) ? -1 : (i == ui) ? 0 : 1;
|
||||
if (i < ui)
|
||||
return -1;
|
||||
return (i == ui) ? 0 : 1;
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -360,9 +367,13 @@ operator<(Value const& x, Value const& y)
|
||||
if (auto signum = x.type_ - y.type_)
|
||||
{
|
||||
if (x.type_ == intValue && y.type_ == uintValue)
|
||||
{
|
||||
signum = integerCmp(x.value_.int_, y.value_.uint_);
|
||||
}
|
||||
else if (x.type_ == uintValue && y.type_ == intValue)
|
||||
{
|
||||
signum = -integerCmp(y.value_.int_, x.value_.uint_);
|
||||
}
|
||||
return signum < 0;
|
||||
}
|
||||
|
||||
@@ -696,7 +707,7 @@ Value::asBool() const
|
||||
|
||||
case arrayValue:
|
||||
case objectValue:
|
||||
return value_.map_->size() != 0;
|
||||
return !value_.map_->empty();
|
||||
|
||||
// LCOV_EXCL_START
|
||||
default:
|
||||
@@ -743,10 +754,10 @@ Value::isConvertibleTo(ValueType other) const
|
||||
(other == nullValue && (!value_.string_ || value_.string_[0] == 0));
|
||||
|
||||
case arrayValue:
|
||||
return other == arrayValue || (other == nullValue && value_.map_->size() == 0);
|
||||
return other == arrayValue || (other == nullValue && value_.map_->empty());
|
||||
|
||||
case objectValue:
|
||||
return other == objectValue || (other == nullValue && value_.map_->size() == 0);
|
||||
return other == objectValue || (other == nullValue && value_.map_->empty());
|
||||
|
||||
// LCOV_EXCL_START
|
||||
default:
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace Json {
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
ValueIteratorBase::ValueIteratorBase() : current_(), isNull_(true)
|
||||
ValueIteratorBase::ValueIteratorBase() : isNull_(true)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -304,7 +304,9 @@ StyledWriter::writeValue(Value const& value)
|
||||
Value::Members members(value.getMemberNames());
|
||||
|
||||
if (members.empty())
|
||||
{
|
||||
pushValue("{}");
|
||||
}
|
||||
else
|
||||
{
|
||||
writeWithIndent("{");
|
||||
@@ -339,7 +341,9 @@ StyledWriter::writeArrayValue(Value const& value)
|
||||
unsigned size = value.size();
|
||||
|
||||
if (size == 0)
|
||||
{
|
||||
pushValue("[]");
|
||||
}
|
||||
else
|
||||
{
|
||||
bool isArrayMultiLine = isMultilineArray(value);
|
||||
@@ -356,7 +360,9 @@ StyledWriter::writeArrayValue(Value const& value)
|
||||
Value const& childValue = value[index];
|
||||
|
||||
if (hasChildValue)
|
||||
{
|
||||
writeWithIndent(childValues_[index]);
|
||||
}
|
||||
else
|
||||
{
|
||||
writeIndent();
|
||||
@@ -429,9 +435,13 @@ void
|
||||
StyledWriter::pushValue(std::string const& value)
|
||||
{
|
||||
if (addChildValues_)
|
||||
{
|
||||
childValues_.push_back(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
document_ += value;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -529,7 +539,9 @@ StyledStreamWriter::writeValue(Value const& value)
|
||||
Value::Members members(value.getMemberNames());
|
||||
|
||||
if (members.empty())
|
||||
{
|
||||
pushValue("{}");
|
||||
}
|
||||
else
|
||||
{
|
||||
writeWithIndent("{");
|
||||
@@ -564,7 +576,9 @@ StyledStreamWriter::writeArrayValue(Value const& value)
|
||||
unsigned size = value.size();
|
||||
|
||||
if (size == 0)
|
||||
{
|
||||
pushValue("[]");
|
||||
}
|
||||
else
|
||||
{
|
||||
bool isArrayMultiLine = isMultilineArray(value);
|
||||
@@ -581,7 +595,9 @@ StyledStreamWriter::writeArrayValue(Value const& value)
|
||||
Value const& childValue = value[index];
|
||||
|
||||
if (hasChildValue)
|
||||
{
|
||||
writeWithIndent(childValues_[index]);
|
||||
}
|
||||
else
|
||||
{
|
||||
writeIndent();
|
||||
@@ -654,9 +670,13 @@ void
|
||||
StyledStreamWriter::pushValue(std::string const& value)
|
||||
{
|
||||
if (addChildValues_)
|
||||
{
|
||||
childValues_.push_back(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
*document_ << value;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user