mirror of
https://github.com/Xahau/xahaud.git
synced 2026-07-01 19:41:59 +00:00
Compare commits
345 Commits
feature-ex
...
HookAPISer
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8f244d888d | ||
|
|
3c49f80013 | ||
|
|
090e4ad25e | ||
|
|
7a0c914ce9 | ||
|
|
d712345c84 | ||
|
|
cc70d48e91 | ||
|
|
01e7ee4f03 | ||
|
|
222772d99b | ||
|
|
9e6135ba42 | ||
|
|
f0329b4054 | ||
|
|
5a9baed9d0 | ||
|
|
8d1aadd23d | ||
|
|
8d2a5e3c4e | ||
|
|
f6fe33103c | ||
|
|
b9d966dd32 | ||
|
|
7e92374436 | ||
|
|
7ef8473c85 | ||
|
|
64fb39d033 | ||
|
|
859391327d | ||
|
|
9ec631b1d8 | ||
|
|
b9ed90e08b | ||
|
|
066f8ed9ef | ||
|
|
3487e2de67 | ||
|
|
1da00892d3 | ||
|
|
75636ee5c4 | ||
|
|
d1528021e2 | ||
|
|
d1395d0f41 | ||
|
|
b4f79257cb | ||
|
|
43a4a3a3e2 | ||
|
|
117bdb1c42 | ||
|
|
87e41a7888 | ||
|
|
df3bf8a958 | ||
|
|
c5fa112e16 | ||
|
|
d2e21da7a3 | ||
|
|
1f0bbdb288 | ||
|
|
5cc56d5f15 | ||
|
|
0a9d3d3d75 | ||
|
|
0d192d48ce | ||
|
|
574dc20641 | ||
|
|
3367f40ef5 | ||
|
|
7080d292e6 | ||
|
|
85a1eb5dba | ||
|
|
534ed875a2 | ||
|
|
72b85d75c9 | ||
|
|
9229ed779f | ||
|
|
e9f671043d | ||
|
|
37669452f6 | ||
|
|
d4fd40c471 | ||
|
|
51aae2ce36 | ||
|
|
c4106a2752 | ||
|
|
e955909a40 | ||
|
|
396587c160 | ||
|
|
c065bc4938 | ||
|
|
2470926a1d | ||
|
|
c35890d5f8 | ||
|
|
248d485aed | ||
|
|
846965e77c | ||
|
|
bf1f4e1a6f | ||
|
|
f8c4639ff4 | ||
|
|
2451d78ae0 | ||
|
|
092f907724 | ||
|
|
33d4a989a2 | ||
|
|
348dab7491 | ||
|
|
6728221831 | ||
|
|
65f4945f22 | ||
|
|
aff89c3457 | ||
|
|
52e1766fb3 | ||
|
|
3166ddc460 | ||
|
|
db1591950d | ||
|
|
0d8c997867 | ||
|
|
41405706b0 | ||
|
|
d7480c6474 | ||
|
|
7b46e26d78 | ||
|
|
5f5a73acbc | ||
|
|
c24f5b10b8 | ||
|
|
601bb7ed0f | ||
|
|
0d3dd400f0 | ||
|
|
4d763b7340 | ||
|
|
63665a6673 | ||
|
|
cbd7d5dc3a | ||
|
|
3e49ee604e | ||
|
|
5e542f5215 | ||
|
|
bdc404837c | ||
|
|
a62919a9cc | ||
|
|
41dcc0fb23 | ||
|
|
b109dbf10f | ||
|
|
01372a67a8 | ||
|
|
2b59176cfd | ||
|
|
a0505ce47d | ||
|
|
91aabaa4aa | ||
|
|
a63008b1be | ||
|
|
33b5ed931c | ||
|
|
ce5c3c98c9 | ||
|
|
aeadad26cb | ||
|
|
74c50ebdab | ||
|
|
1e2c92290d | ||
|
|
0617dc221d | ||
|
|
a4a8295567 | ||
|
|
2a836cbbb8 | ||
|
|
79935d4db8 | ||
|
|
7088c64427 | ||
|
|
27ddfae5e1 | ||
|
|
cf957db8da | ||
|
|
ac532d9d16 | ||
|
|
37614773bb | ||
|
|
c329d71717 | ||
|
|
7de6a70221 | ||
|
|
0fa542f672 | ||
|
|
68705eee2c | ||
|
|
fdbb24d898 | ||
|
|
60a8f3c05b | ||
|
|
5a3a71ecb8 | ||
|
|
16b3221f80 | ||
|
|
dd4b060f09 | ||
|
|
ee78f8d566 | ||
|
|
952ce55223 | ||
|
|
e6893a9422 | ||
|
|
0ba16ef3d6 | ||
|
|
479dd8b57b | ||
|
|
e626b096a3 | ||
|
|
329c0ab1e1 | ||
|
|
997836906c | ||
|
|
71554dce3a | ||
|
|
2395d17a1f | ||
|
|
e862f40636 | ||
|
|
4f8096f378 | ||
|
|
d8a3e65d78 | ||
|
|
c3cc6494dd | ||
|
|
76397fea5c | ||
|
|
291fb21d45 | ||
|
|
727fc8e084 | ||
|
|
acc95ecc56 | ||
|
|
f7592641d1 | ||
|
|
1338b67964 | ||
|
|
9ee638fe7f | ||
|
|
9c1ed41879 | ||
|
|
ab1c217e8d | ||
|
|
e140a0fd0b | ||
|
|
7f3281ff54 | ||
|
|
17d0e23720 | ||
|
|
5675408c51 | ||
|
|
48bb555f92 | ||
|
|
2227a382d6 | ||
|
|
088c1deaf5 | ||
|
|
632f94a8e7 | ||
|
|
6bf4adf42f | ||
|
|
db9af3a8c9 | ||
|
|
ef7e743a0e | ||
|
|
c97f32cbcc | ||
|
|
187634272d | ||
|
|
be49b22c2f | ||
|
|
fd1908f5b6 | ||
|
|
d27bc94249 | ||
|
|
16b4550d93 | ||
|
|
b51411f728 | ||
|
|
6a17c6be3f | ||
|
|
881c5c8b96 | ||
|
|
eaf63accbe | ||
|
|
a26bcf1328 | ||
|
|
b5e309347a | ||
|
|
f04b4e066f | ||
|
|
b0c8296dc0 | ||
|
|
d8d55c2397 | ||
|
|
d62a3ec724 | ||
|
|
f1687f0e1b | ||
|
|
a5787f78a5 | ||
|
|
62c17828d7 | ||
|
|
1dee7d6c4d | ||
|
|
3e95f07a25 | ||
|
|
463dd92c9e | ||
|
|
95e16b0eed | ||
|
|
cb641e4733 | ||
|
|
3cb60afde6 | ||
|
|
a6a71bcc3f | ||
|
|
6c1bc9052d | ||
|
|
6b5a7ec905 | ||
|
|
7e639a1a9d | ||
|
|
cd0141d781 | ||
|
|
34be0ce4fe | ||
|
|
01971ab1b9 | ||
|
|
7996d08d0c | ||
|
|
11ff672df8 | ||
|
|
00fc12faa9 | ||
|
|
f97bf81b16 | ||
|
|
29abe2ae46 | ||
|
|
bb271020df | ||
|
|
a5fb634d53 | ||
|
|
8896ea7220 | ||
|
|
837dd8c4b9 | ||
|
|
323fba5c17 | ||
|
|
723a51921d | ||
|
|
8b83693235 | ||
|
|
beaf794938 | ||
|
|
21a383eeaf | ||
|
|
06394e9d17 | ||
|
|
ea2e503ef8 | ||
|
|
447e6c6c1e | ||
|
|
e5e4925a39 | ||
|
|
3ff7f34d7c | ||
|
|
e1f2e62c08 | ||
|
|
10dcdd87d4 | ||
|
|
6419eaae42 | ||
|
|
1f28001aae | ||
|
|
9d0b94029a | ||
|
|
c3d51f85af | ||
|
|
f15412acb5 | ||
|
|
eea44ad6cb | ||
|
|
2380633d9a | ||
|
|
4400a6eef6 | ||
|
|
17c9e967fd | ||
|
|
3b96cac31c | ||
|
|
fda0b67d9d | ||
|
|
58a24ac1a2 | ||
|
|
0213db8a08 | ||
|
|
fcd0e23326 | ||
|
|
2827748bcf | ||
|
|
4319b1a097 | ||
|
|
6af0cb9bb4 | ||
|
|
2abb48a618 | ||
|
|
8eead5c99c | ||
|
|
3055029ded | ||
|
|
ec23db00e7 | ||
|
|
39b84e073b | ||
|
|
a9afc6c690 | ||
|
|
f9d544caef | ||
|
|
6cf6b42c57 | ||
|
|
534e9989a8 | ||
|
|
7fc312b271 | ||
|
|
8cfea5a9d1 | ||
|
|
c1cb2765ee | ||
|
|
fc305f974b | ||
|
|
04f36c8d63 | ||
|
|
70a3be5ebe | ||
|
|
842f8b0ede | ||
|
|
87368f7f0e | ||
|
|
69e3cdce53 | ||
|
|
37cc0709c7 | ||
|
|
7e64d49bd0 | ||
|
|
bb463bc62f | ||
|
|
a0accf3d6a | ||
|
|
9a1888cc2d | ||
|
|
a342b510e7 | ||
|
|
b588f1a06e | ||
|
|
833a75f57a | ||
|
|
20812b4a2c | ||
|
|
5109b1a117 | ||
|
|
08abc9490d | ||
|
|
71ffc69819 | ||
|
|
c29a632d0c | ||
|
|
a8fe0f62e2 | ||
|
|
59070b4f3e | ||
|
|
880d8a7be8 | ||
|
|
b8854c7437 | ||
|
|
5ab9e2fed5 | ||
|
|
eb7e17e4f8 | ||
|
|
e9287a3d3d | ||
|
|
2572b3204c | ||
|
|
b3de0b6329 | ||
|
|
fe5bf9c12d | ||
|
|
bb2712dd20 | ||
|
|
0a97b9f471 | ||
|
|
469d4e81e4 | ||
|
|
4aa8259353 | ||
|
|
614382cb7e | ||
|
|
2c6dff314b | ||
|
|
b83e66882c | ||
|
|
c569651f83 | ||
|
|
999fc61230 | ||
|
|
9899eda7c2 | ||
|
|
41daa9f64c | ||
|
|
d75a6edc58 | ||
|
|
cc60747344 | ||
|
|
65c7f6f7d0 | ||
|
|
c3a36ad748 | ||
|
|
0a3ce6cf36 | ||
|
|
bedafe5cff | ||
|
|
d7b7bf7a10 | ||
|
|
446a1fdaac | ||
|
|
18ccbf4a53 | ||
|
|
9f2fd23575 | ||
|
|
20a422076d | ||
|
|
7fded60cc9 | ||
|
|
136508e56c | ||
|
|
ef1c26f9f5 | ||
|
|
a8e8d50cb8 | ||
|
|
73933a366b | ||
|
|
92f0efb064 | ||
|
|
11849215b4 | ||
|
|
e9f83a7808 | ||
|
|
8b0cb51d24 | ||
|
|
9838bdf214 | ||
|
|
6cf6416f15 | ||
|
|
5e1dd22bf3 | ||
|
|
dc08a666f9 | ||
|
|
07dda63bd5 | ||
|
|
53cdb040cf | ||
|
|
01890e863a | ||
|
|
6057c65027 | ||
|
|
0815ec39f8 | ||
|
|
c60eb416d2 | ||
|
|
3ea653cccb | ||
|
|
9605fa0e53 | ||
|
|
5741a0d5cb | ||
|
|
11b1602814 | ||
|
|
8667480406 | ||
|
|
cff548bcc8 | ||
|
|
acf7486c8d | ||
|
|
6de5de02cb | ||
|
|
2c5ecfa75d | ||
|
|
bbc943ca10 | ||
|
|
5d3b8976f7 | ||
|
|
cabb9cfd50 | ||
|
|
27c1ab5fba | ||
|
|
0f4bc92f77 | ||
|
|
5f02b98066 | ||
|
|
52d3babf1b | ||
|
|
9a82bf9ec2 | ||
|
|
f94e1c1be2 | ||
|
|
9e1831cacf | ||
|
|
3eb8a64e64 | ||
|
|
61fd0d0164 | ||
|
|
314cf50863 | ||
|
|
00a6922045 | ||
|
|
cd9facd7fa | ||
|
|
39b2e3334a | ||
|
|
f19e254366 | ||
|
|
5e083121da | ||
|
|
683e9ccc1a | ||
|
|
8dbc6db079 | ||
|
|
b7a29cad94 | ||
|
|
7054bf64e9 | ||
|
|
3ddf1c99d5 | ||
|
|
6d5e7e519b | ||
|
|
224ae4e70f | ||
|
|
8531ba5838 | ||
|
|
73550a4bfc | ||
|
|
e353c9d6eb | ||
|
|
b733d274a0 | ||
|
|
346544e371 | ||
|
|
5d2d1d4497 | ||
|
|
0f0ffda053 | ||
|
|
37f7734b25 | ||
|
|
f8dc0cab65 | ||
|
|
3c4731a676 | ||
|
|
995e70c2b0 |
37
.codecov.yml
37
.codecov.yml
@@ -1,37 +0,0 @@
|
||||
codecov:
|
||||
require_ci_to_pass: true
|
||||
|
||||
comment:
|
||||
behavior: default
|
||||
layout: reach,diff,flags,tree,reach
|
||||
show_carryforward_flags: false
|
||||
|
||||
coverage:
|
||||
range: "60..80"
|
||||
precision: 1
|
||||
round: nearest
|
||||
status:
|
||||
project:
|
||||
default:
|
||||
target: 60%
|
||||
threshold: 2%
|
||||
patch:
|
||||
default:
|
||||
target: auto
|
||||
threshold: 2%
|
||||
changes: false
|
||||
|
||||
github_checks:
|
||||
annotations: true
|
||||
|
||||
parsers:
|
||||
cobertura:
|
||||
partials_as_hits: true
|
||||
handle_missing_conditions : true
|
||||
|
||||
slack_app: false
|
||||
|
||||
ignore:
|
||||
- "src/test/"
|
||||
- "include/xrpl/beast/test/"
|
||||
- "include/xrpl/beast/unit_test/"
|
||||
@@ -1,25 +1,8 @@
|
||||
# This feature requires Git >= 2.24
|
||||
# To use it by default in git blame:
|
||||
# git config blame.ignoreRevsFile .git-blame-ignore-revs
|
||||
# Format first-party source according to .clang-format
|
||||
50760c693510894ca368e90369b0cc2dabfd07f3
|
||||
# Reintroduce Clang-Format & Levelization
|
||||
da1d20d6d5d862716125d60899b80fab5302954a
|
||||
# Consolidate external libraries
|
||||
da1d20d6d5d862716125d60899b80fab5302954a
|
||||
# Rename .hpp to .h
|
||||
0345a2645d0f5ad900f4fbbcaff96040d3a887fc
|
||||
# Format formerly .hpp files
|
||||
5a227dc719016e10045e17c9396ad401118044f1
|
||||
# Rewrite includes
|
||||
e61880699997398f5a746e6c4034edc7632661f5
|
||||
# Move CMake directory (#4997)
|
||||
e47b1c1b3b97c3f6d11858ee02f463596e29e7f0
|
||||
# Rearrange sources (#4997)
|
||||
bfafa2bb39e562901736d656806bd700c3699a2f
|
||||
# Rewrite includes (#4997)
|
||||
e61880699997398f5a746e6c4034edc7632661f5
|
||||
# Recompute loops (#4997)
|
||||
d25b5dcd568bb96c18e347d55fac10fe901a1bfb
|
||||
# Reformat code with clang-format-18
|
||||
02749feea88ce61c1f7eeb2d61a57d8ecf07ab11
|
||||
e2384885f5f630c8f0ffe4bf21a169b433a16858
|
||||
241b9ddde9e11beb7480600fd5ed90e1ef109b21
|
||||
760f16f56835663d9286bd29294d074de26a7ba6
|
||||
0eebe6a5f4246fced516d52b83ec4e7f47373edd
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Pre-commit hook that runs the suspicious patterns check on staged files
|
||||
|
||||
# Get the repository's root directory
|
||||
repo_root=$(git rev-parse --show-toplevel)
|
||||
|
||||
# Run the suspicious patterns script in pre-commit mode
|
||||
"$repo_root/suspicious_patterns.sh" --pre-commit
|
||||
|
||||
# Exit with the same code as the script
|
||||
exit $?
|
||||
@@ -1,4 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "Configuring git to use .githooks directory..."
|
||||
git config core.hooksPath .githooks
|
||||
29
.github/actions/xahau-ga-build/action.yml
vendored
29
.github/actions/xahau-ga-build/action.yml
vendored
@@ -2,14 +2,6 @@ name: build
|
||||
description: 'Builds the project with ccache integration'
|
||||
|
||||
inputs:
|
||||
cmake-target:
|
||||
description: 'CMake target to build'
|
||||
required: false
|
||||
default: all
|
||||
cmake-args:
|
||||
description: 'Additional CMake arguments'
|
||||
required: false
|
||||
default: null
|
||||
generator:
|
||||
description: 'CMake generator to use'
|
||||
required: true
|
||||
@@ -28,10 +20,6 @@ inputs:
|
||||
description: 'C++ compiler to use'
|
||||
required: false
|
||||
default: ''
|
||||
gcov:
|
||||
description: 'Gcov to use'
|
||||
required: false
|
||||
default: ''
|
||||
compiler-id:
|
||||
description: 'Unique identifier: compiler-version-stdlib[-gccversion] (e.g. clang-14-libstdcxx-gcc11, gcc-13-libstdcxx)'
|
||||
required: false
|
||||
@@ -53,11 +41,10 @@ inputs:
|
||||
required: false
|
||||
default: 'dev'
|
||||
stdlib:
|
||||
description: 'C++ standard library to use (default = compiler default, e.g. GCC always uses libstdc++)'
|
||||
description: 'C++ standard library to use'
|
||||
required: true
|
||||
type: choice
|
||||
options:
|
||||
- default
|
||||
- libstdcxx
|
||||
- libcxx
|
||||
clang_gcc_toolchain:
|
||||
@@ -100,6 +87,11 @@ runs:
|
||||
export CCACHE_CONFIGPATH="$HOME/.config/ccache/ccache.conf"
|
||||
echo "CCACHE_CONFIGPATH=$CCACHE_CONFIGPATH" >> $GITHUB_ENV
|
||||
|
||||
# Keep config separate from cache_dir so configs aren't swapped when CCACHE_DIR changes between steps
|
||||
mkdir -p ~/.config/ccache
|
||||
export CCACHE_CONFIGPATH="$HOME/.config/ccache/ccache.conf"
|
||||
echo "CCACHE_CONFIGPATH=$CCACHE_CONFIGPATH" >> $GITHUB_ENV
|
||||
|
||||
# Configure ccache settings AFTER cache restore (prevents stale cached config)
|
||||
ccache --set-config=max_size=${{ inputs.ccache_max_size }}
|
||||
ccache --set-config=hash_dir=${{ inputs.ccache_hash_dir }}
|
||||
@@ -130,10 +122,6 @@ runs:
|
||||
export CXX="${{ inputs.cxx }}"
|
||||
fi
|
||||
|
||||
if [ -n "${{ inputs.gcov }}" ]; then
|
||||
ln -sf /usr/bin/${{ inputs.gcov }} /usr/local/bin/gcov
|
||||
fi
|
||||
|
||||
# Create wrapper toolchain that overlays ccache on top of Conan's toolchain
|
||||
# This enables ccache for the main app build without affecting Conan dependency builds
|
||||
if [ "${{ inputs.ccache_enabled }}" = "true" ]; then
|
||||
@@ -197,8 +185,7 @@ runs:
|
||||
-DCMAKE_TOOLCHAIN_FILE:FILEPATH=${TOOLCHAIN_FILE} \
|
||||
-DCMAKE_BUILD_TYPE=${{ inputs.configuration }} \
|
||||
-Dtests=TRUE \
|
||||
-Dxrpld=TRUE \
|
||||
${{ inputs.cmake-args }}
|
||||
-Dxrpld=TRUE
|
||||
|
||||
- name: Show ccache config before build
|
||||
if: inputs.ccache_enabled == 'true'
|
||||
@@ -222,7 +209,7 @@ runs:
|
||||
VERBOSE_FLAG="-- -v"
|
||||
fi
|
||||
|
||||
cmake --build . --config ${{ inputs.configuration }} --parallel $(nproc) --target ${{ inputs.cmake-target }} ${VERBOSE_FLAG}
|
||||
cmake --build . --config ${{ inputs.configuration }} --parallel $(nproc) ${VERBOSE_FLAG}
|
||||
|
||||
- name: Show ccache statistics
|
||||
if: inputs.ccache_enabled == 'true'
|
||||
|
||||
107
.github/workflows/check-genesis-hooks.yml
vendored
107
.github/workflows/check-genesis-hooks.yml
vendored
@@ -1,107 +0,0 @@
|
||||
name: Check Genesis Hooks
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
check-genesis-hooks:
|
||||
runs-on: ubuntu-24.04
|
||||
env:
|
||||
CLANG_VERSION: 18
|
||||
name: Verify xahau.h is in sync with genesis hooks
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
|
||||
# Install binaryen from GitHub Releases (pinned to version 100)
|
||||
- name: Install binaryen (version 100)
|
||||
run: |
|
||||
curl -LO https://github.com/WebAssembly/binaryen/releases/download/version_100/binaryen-version_100-x86_64-linux.tar.gz
|
||||
tar -xzf binaryen-version_100-x86_64-linux.tar.gz
|
||||
sudo cp binaryen-version_100/bin/* /usr/local/bin/
|
||||
wasm-opt --version
|
||||
|
||||
- name: Install clang-format
|
||||
run: |
|
||||
codename=$( lsb_release --codename --short )
|
||||
sudo tee /etc/apt/sources.list.d/llvm.list >/dev/null <<EOF
|
||||
deb http://apt.llvm.org/${codename}/ llvm-toolchain-${codename}-${CLANG_VERSION} main
|
||||
deb-src http://apt.llvm.org/${codename}/ llvm-toolchain-${codename}-${CLANG_VERSION} main
|
||||
EOF
|
||||
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add
|
||||
sudo apt-get update
|
||||
sudo apt-get install clang-format-${CLANG_VERSION}
|
||||
clang-format --version
|
||||
|
||||
# Install wasienv (WebAssembly SDK)
|
||||
- name: Install wasienv
|
||||
run: |
|
||||
# Download install.sh
|
||||
curl -o /tmp/wasienv-install.sh https://raw.githubusercontent.com/wasienv/wasienv/master/install.sh
|
||||
|
||||
# Replace /bin to /local/bin
|
||||
sed -i 's|/bin|/local/bin|g' /tmp/wasienv-install.sh
|
||||
|
||||
# Execute the installed script
|
||||
bash /tmp/wasienv-install.sh
|
||||
|
||||
# Add wasienv to PATH for subsequent steps
|
||||
- name: Setup wasienv
|
||||
run: |
|
||||
echo "$HOME/.wasienv/bin" >> $GITHUB_PATH
|
||||
wasmcc -v || true
|
||||
|
||||
# Build and install hook-cleaner tool
|
||||
- name: Build and install hook-cleaner
|
||||
run: |
|
||||
git clone https://github.com/richardah/hook-cleaner-c.git /tmp/hook-cleaner
|
||||
cd /tmp/hook-cleaner
|
||||
make
|
||||
cp hook-cleaner /usr/local/bin/
|
||||
chmod +x /usr/local/bin/hook-cleaner
|
||||
|
||||
# Build and install guard_checker tool
|
||||
- name: Build and install guard_checker
|
||||
run: |
|
||||
cd include/xrpl/hook
|
||||
make
|
||||
cp guard_checker /usr/local/bin/
|
||||
chmod +x /usr/local/bin/guard_checker
|
||||
|
||||
# Verify all required tools are available
|
||||
- name: Verify required tools
|
||||
run: |
|
||||
echo "Checking tool availability..."
|
||||
command -v wasmcc || (echo "Error: wasmcc not found" && exit 1)
|
||||
command -v wasm-opt || (echo "Error: wasm-opt not found" && exit 1)
|
||||
command -v hook-cleaner || (echo "Error: hook-cleaner not found" && exit 1)
|
||||
command -v guard_checker || (echo "Error: guard_checker not found" && exit 1)
|
||||
command -v xxd || (echo "Error: xxd not found" && exit 1)
|
||||
command -v clang-format || (echo "Error: clang-format not found" && exit 1)
|
||||
echo "All tools verified successfully"
|
||||
|
||||
# Execute build script to regenerate xahau.h
|
||||
- name: Run build_xahau_h.sh
|
||||
run: |
|
||||
cd hook/genesis
|
||||
./build_xahau_h.sh
|
||||
|
||||
# Check if xahau.h has changed (fail if out of sync)
|
||||
- name: Verify xahau.h is in sync
|
||||
run: |
|
||||
if ! git diff --exit-code include/xrpl/hook/xahau.h; then
|
||||
echo ""
|
||||
echo "❌ ERROR: xahau.h is out of sync with genesis hooks"
|
||||
echo ""
|
||||
echo "The generated xahau.h differs from the committed version."
|
||||
echo "Please run the following command and commit the changes:"
|
||||
echo ""
|
||||
echo " cd hook/genesis && ./build_xahau_h.sh"
|
||||
echo ""
|
||||
echo "Diff:"
|
||||
git diff include/xrpl/hook/xahau.h
|
||||
exit 1
|
||||
fi
|
||||
echo "✅ xahau.h is in sync with genesis hooks"
|
||||
2
.github/workflows/clang-format.yml
vendored
2
.github/workflows/clang-format.yml
vendored
@@ -20,7 +20,7 @@ jobs:
|
||||
sudo apt-get update
|
||||
sudo apt-get install clang-format-${CLANG_VERSION}
|
||||
- name: Format first-party sources
|
||||
run: find include src -type f \( -name '*.cpp' -o -name '*.hpp' -o -name '*.h' -o -name '*.ipp' \) -exec clang-format-${CLANG_VERSION} -i {} +
|
||||
run: find include src -type f \( -name '*.cpp' -o -name '*.hpp' -o -name '*.h' -o -name '*.ipp' \) -not -path "src/magic/magic_enum.h" -exec clang-format-${CLANG_VERSION} -i {} +
|
||||
- name: Check for differences
|
||||
id: assert
|
||||
run: |
|
||||
|
||||
4
.github/workflows/levelization.yml
vendored
4
.github/workflows/levelization.yml
vendored
@@ -10,7 +10,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Check levelization
|
||||
run: python Builds/levelization/levelization.py
|
||||
run: Builds/levelization/levelization.sh
|
||||
- name: Check for differences
|
||||
id: assert
|
||||
run: |
|
||||
@@ -40,7 +40,7 @@ jobs:
|
||||
To fix it, you can do one of two things:
|
||||
1. Download and apply the patch generated as an artifact of this
|
||||
job to your repo, commit, and push.
|
||||
2. Run 'python Builds/levelization/levelization.py' in your repo,
|
||||
2. Run './Builds/levelization/levelization.sh' in your repo,
|
||||
commit, and push.
|
||||
|
||||
See Builds/levelization/README.md for more info.
|
||||
|
||||
@@ -16,14 +16,8 @@ jobs:
|
||||
generator: ./hook/generate_extern.sh
|
||||
- target: hook/sfcodes.h
|
||||
generator: bash ./hook/generate_sfcodes.sh
|
||||
- target: hook/genesis/headers/sfcodes.h
|
||||
generator: bash ./hook/generate_sfcodes.sh
|
||||
- target: hook/tts.h
|
||||
generator: ./hook/generate_tts.sh
|
||||
- target: hook/ls_flags.h
|
||||
generator: ./hook/generate_lsflags.sh
|
||||
- target: hook/tx_flags.h
|
||||
generator: ./hook/generate_txflags.sh
|
||||
runs-on: ubuntu-24.04
|
||||
env:
|
||||
CLANG_VERSION: 18
|
||||
|
||||
7
.github/workflows/xahau-ga-macos.yml
vendored
7
.github/workflows/xahau-ga-macos.yml
vendored
@@ -4,8 +4,7 @@ on:
|
||||
push:
|
||||
branches: ["dev", "candidate", "release"]
|
||||
pull_request:
|
||||
branches: ["**"]
|
||||
types: [opened, synchronize, reopened, labeled, unlabeled]
|
||||
branches: ["dev", "candidate", "release"]
|
||||
schedule:
|
||||
- cron: '0 0 * * *'
|
||||
|
||||
@@ -15,10 +14,6 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
test:
|
||||
if: >
|
||||
github.event_name != 'pull_request' ||
|
||||
contains(fromJson('["dev","candidate","release"]'), github.base_ref) ||
|
||||
contains(join(github.event.pull_request.labels.*.name, ','), 'ci-full-build')
|
||||
strategy:
|
||||
matrix:
|
||||
generator:
|
||||
|
||||
168
.github/workflows/xahau-ga-nix.yml
vendored
168
.github/workflows/xahau-ga-nix.yml
vendored
@@ -4,16 +4,9 @@ on:
|
||||
push:
|
||||
branches: ["dev", "candidate", "release"]
|
||||
pull_request:
|
||||
branches: ["**"]
|
||||
types: [opened, synchronize, reopened, labeled, unlabeled]
|
||||
branches: ["dev", "candidate", "release"]
|
||||
schedule:
|
||||
- cron: '0 0 * * *'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
full_matrix:
|
||||
description: "Force full matrix (6 configs)"
|
||||
required: false
|
||||
default: "false"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
@@ -21,10 +14,6 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
matrix-setup:
|
||||
if: >
|
||||
github.event_name != 'pull_request' ||
|
||||
contains(fromJson('["dev","candidate","release"]'), github.base_ref) ||
|
||||
contains(join(github.event.pull_request.labels.*.name, ','), 'ci-full-build')
|
||||
runs-on: [self-hosted, generic, 20.04]
|
||||
container: python:3-slim
|
||||
outputs:
|
||||
@@ -57,9 +46,8 @@ jobs:
|
||||
"cc": "gcc-11",
|
||||
"cxx": "g++-11",
|
||||
"compiler_version": 11,
|
||||
"stdlib": "default",
|
||||
"configuration": "Debug",
|
||||
"job_type": "build"
|
||||
"stdlib": "libstdcxx",
|
||||
"configuration": "Debug"
|
||||
},
|
||||
{
|
||||
"compiler_id": "gcc-13-libstdcxx",
|
||||
@@ -67,20 +55,8 @@ jobs:
|
||||
"cc": "gcc-13",
|
||||
"cxx": "g++-13",
|
||||
"compiler_version": 13,
|
||||
"stdlib": "default",
|
||||
"configuration": "Debug",
|
||||
"job_type": "build"
|
||||
},
|
||||
{
|
||||
"compiler_id": "gcc-13-libstdcxx",
|
||||
"compiler": "gcc",
|
||||
"cc": "gcc-13",
|
||||
"cxx": "g++-13",
|
||||
"gcov": "gcov-13",
|
||||
"compiler_version": 13,
|
||||
"stdlib": "default",
|
||||
"configuration": "Debug",
|
||||
"job_type": "coverage"
|
||||
"stdlib": "libstdcxx",
|
||||
"configuration": "Debug"
|
||||
},
|
||||
{
|
||||
"compiler_id": "clang-14-libstdcxx-gcc11",
|
||||
@@ -90,8 +66,7 @@ jobs:
|
||||
"compiler_version": 14,
|
||||
"stdlib": "libstdcxx",
|
||||
"clang_gcc_toolchain": 11,
|
||||
"configuration": "Debug",
|
||||
"job_type": "build"
|
||||
"configuration": "Debug"
|
||||
},
|
||||
{
|
||||
"compiler_id": "clang-16-libstdcxx-gcc13",
|
||||
@@ -101,8 +76,7 @@ jobs:
|
||||
"compiler_version": 16,
|
||||
"stdlib": "libstdcxx",
|
||||
"clang_gcc_toolchain": 13,
|
||||
"configuration": "Debug",
|
||||
"job_type": "build"
|
||||
"configuration": "Debug"
|
||||
},
|
||||
{
|
||||
"compiler_id": "clang-17-libcxx",
|
||||
@@ -111,8 +85,7 @@ jobs:
|
||||
"cxx": "clang++-17",
|
||||
"compiler_version": 17,
|
||||
"stdlib": "libcxx",
|
||||
"configuration": "Debug",
|
||||
"job_type": "build"
|
||||
"configuration": "Debug"
|
||||
},
|
||||
{
|
||||
# Clang 18 - testing if it's faster than Clang 17 with libc++
|
||||
@@ -123,16 +96,14 @@ jobs:
|
||||
"cxx": "clang++-18",
|
||||
"compiler_version": 18,
|
||||
"stdlib": "libcxx",
|
||||
"configuration": "Debug",
|
||||
"job_type": "build"
|
||||
"configuration": "Debug"
|
||||
}
|
||||
]
|
||||
|
||||
# Minimal matrix for PRs and feature branches
|
||||
minimal_matrix = [
|
||||
full_matrix[1], # gcc-13 (middle-ground gcc)
|
||||
full_matrix[2], # gcc-13 coverage
|
||||
full_matrix[3] # clang-14 (mature, stable clang)
|
||||
full_matrix[2] # clang-14 (mature, stable clang)
|
||||
]
|
||||
|
||||
# Determine which matrix to use based on the target branch
|
||||
@@ -140,7 +111,6 @@ jobs:
|
||||
base_ref = "${{ github.base_ref }}" # For PRs, this is the target branch
|
||||
event_name = "${{ github.event_name }}"
|
||||
pr_title = """${{ steps.escape.outputs.title }}"""
|
||||
pr_labels = """${{ join(github.event.pull_request.labels.*.name, ',') }}"""
|
||||
pr_head_sha = "${{ github.event.pull_request.head.sha }}"
|
||||
|
||||
# Get commit message - for PRs, fetch via API since head_commit.message is empty
|
||||
@@ -166,24 +136,11 @@ jobs:
|
||||
print(f"Base ref: {base_ref}")
|
||||
print(f"PR head SHA: {pr_head_sha}")
|
||||
print(f"PR title: {pr_title}")
|
||||
print(f"PR labels: {pr_labels}")
|
||||
print(f"Commit message: {commit_message}")
|
||||
|
||||
# Manual trigger input to force full matrix.
|
||||
manual_full = "${{ github.event.inputs.full_matrix || 'false' }}" == "true"
|
||||
|
||||
# Label/manual overrides, while preserving existing title/commit behavior.
|
||||
force_full = (
|
||||
manual_full
|
||||
or "[ci-nix-full-matrix]" in commit_message
|
||||
or "[ci-nix-full-matrix]" in pr_title
|
||||
or ("ci-full-build" in pr_labels and "ci-nix-full-matrix" in pr_labels)
|
||||
)
|
||||
force_min = (
|
||||
"ci-full-build" in pr_labels
|
||||
)
|
||||
# Check for override tags in commit message or PR title
|
||||
force_full = "[ci-nix-full-matrix]" in commit_message or "[ci-nix-full-matrix]" in pr_title
|
||||
print(f"Force full matrix: {force_full}")
|
||||
print(f"Force min matrix: {force_min}")
|
||||
|
||||
# Check if this is targeting a main branch
|
||||
# For PRs: check base_ref (target branch)
|
||||
@@ -191,11 +148,8 @@ jobs:
|
||||
main_branches = ["refs/heads/dev", "refs/heads/release", "refs/heads/candidate"]
|
||||
|
||||
if force_full:
|
||||
# Override: always use full matrix if forced by manual input or label.
|
||||
# Override: always use full matrix if tag is present
|
||||
use_full = True
|
||||
elif force_min:
|
||||
# Override: always use minimal matrix if ci-full-build label is present.
|
||||
use_full = False
|
||||
elif event_name == "pull_request":
|
||||
# For PRs, base_ref is just the branch name (e.g., "dev", not "refs/heads/dev")
|
||||
# Check if the PR targets release or candidate (more critical branches)
|
||||
@@ -207,21 +161,14 @@ jobs:
|
||||
# Select the appropriate matrix
|
||||
if use_full:
|
||||
if force_full:
|
||||
print(f"Using FULL matrix (7 configs) - forced by [ci-nix-full-matrix] tag")
|
||||
print(f"Using FULL matrix (6 configs) - forced by [ci-nix-full-matrix] tag")
|
||||
else:
|
||||
print(f"Using FULL matrix (7 configs) - targeting main branch")
|
||||
print(f"Using FULL matrix (6 configs) - targeting main branch")
|
||||
matrix = full_matrix
|
||||
else:
|
||||
print(f"Using MINIMAL matrix (3 configs) - feature branch/PR")
|
||||
print(f"Using MINIMAL matrix (2 configs) - feature branch/PR")
|
||||
matrix = minimal_matrix
|
||||
|
||||
# Add runs_on based on job_type
|
||||
for entry in matrix:
|
||||
if entry.get("job_type") == "coverage":
|
||||
entry["runs_on"] = '["self-hosted", "generic", 24.04]'
|
||||
else:
|
||||
entry["runs_on"] = '["self-hosted", "generic", 20.04]'
|
||||
|
||||
|
||||
# Output the matrix as JSON
|
||||
output = json.dumps({"include": matrix})
|
||||
with open(os.environ['GITHUB_OUTPUT'], 'a') as f:
|
||||
@@ -229,10 +176,7 @@ jobs:
|
||||
|
||||
build:
|
||||
needs: matrix-setup
|
||||
runs-on: ${{ fromJSON(matrix.runs_on) }}
|
||||
permissions:
|
||||
id-token: write
|
||||
contents: read
|
||||
runs-on: [self-hosted, generic, 20.04]
|
||||
container:
|
||||
image: ubuntu:24.04
|
||||
volumes:
|
||||
@@ -261,7 +205,7 @@ jobs:
|
||||
apt-get install -y software-properties-common
|
||||
add-apt-repository ppa:ubuntu-toolchain-r/test -y
|
||||
apt-get update
|
||||
apt-get install -y git python3 python-is-python3 pipx
|
||||
apt-get install -y python3 python-is-python3 pipx
|
||||
pipx ensurepath
|
||||
apt-get install -y cmake ninja-build ${{ matrix.cc }} ${{ matrix.cxx }} ccache
|
||||
apt-get install -y perl # for openssl build
|
||||
@@ -332,12 +276,6 @@ jobs:
|
||||
pipx install "conan>=2.0,<3"
|
||||
echo "$HOME/.local/bin" >> $GITHUB_PATH
|
||||
|
||||
# Install gcovr for coverage jobs
|
||||
if [ "${{ matrix.job_type }}" = "coverage" ]; then
|
||||
pipx install "gcovr>=7,<9"
|
||||
apt-get install -y curl lcov
|
||||
fi
|
||||
|
||||
- name: Check environment
|
||||
run: |
|
||||
echo "PATH:"
|
||||
@@ -347,13 +285,6 @@ jobs:
|
||||
which ${{ matrix.cc }} && ${{ matrix.cc }} --version || echo "${{ matrix.cc }} not found"
|
||||
which ${{ matrix.cxx }} && ${{ matrix.cxx }} --version || echo "${{ matrix.cxx }} not found"
|
||||
which ccache && ccache --version || echo "ccache not found"
|
||||
|
||||
# Check gcovr for coverage jobs
|
||||
if [ "${{ matrix.job_type }}" = "coverage" ]; then
|
||||
which gcov && gcov --version || echo "gcov not found"
|
||||
which gcovr && gcovr --version || echo "gcovr not found"
|
||||
fi
|
||||
|
||||
echo "---- Full Environment ----"
|
||||
env
|
||||
|
||||
@@ -381,7 +312,6 @@ jobs:
|
||||
gha_cache_enabled: 'false' # Disable caching for self hosted runner
|
||||
|
||||
- name: Build
|
||||
if: matrix.job_type == 'build'
|
||||
uses: ./.github/actions/xahau-ga-build
|
||||
with:
|
||||
generator: Ninja
|
||||
@@ -396,27 +326,7 @@ jobs:
|
||||
clang_gcc_toolchain: ${{ matrix.clang_gcc_toolchain || '' }}
|
||||
ccache_max_size: '100G'
|
||||
|
||||
- name: Build (Coverage)
|
||||
if: matrix.job_type == 'coverage'
|
||||
uses: ./.github/actions/xahau-ga-build
|
||||
with:
|
||||
generator: Ninja
|
||||
configuration: ${{ matrix.configuration }}
|
||||
build_dir: ${{ env.build_dir }}
|
||||
cc: ${{ matrix.cc }}
|
||||
cxx: ${{ matrix.cxx }}
|
||||
gcov: ${{ matrix.gcov }}
|
||||
compiler-id: ${{ matrix.compiler_id }}
|
||||
cache_version: ${{ env.CACHE_VERSION }}
|
||||
main_branch: ${{ env.MAIN_BRANCH_NAME }}
|
||||
stdlib: ${{ matrix.stdlib }}
|
||||
# Coverage builds are slower due to instrumentation; use fewer parallel jobs to avoid flakiness
|
||||
cmake-args: '-Dcoverage=ON -Dcoverage_format=xml -Dcoverage_test_parallelism=$(($(nproc)/2)) -DCODE_COVERAGE_VERBOSE=ON -DCMAKE_CXX_FLAGS="-O0" -DCMAKE_C_FLAGS="-O0"'
|
||||
cmake-target: 'coverage'
|
||||
ccache_max_size: '100G'
|
||||
|
||||
- name: Set artifact name
|
||||
if: matrix.job_type == 'build'
|
||||
id: set-artifact-name
|
||||
run: |
|
||||
ARTIFACT_NAME="build-output-nix-${{ github.run_id }}-${{ matrix.compiler }}-${{ matrix.configuration }}"
|
||||
@@ -429,7 +339,6 @@ jobs:
|
||||
ls -la ${{ env.build_dir }} || echo "Build directory not found or empty"
|
||||
|
||||
- name: Run tests
|
||||
if: matrix.job_type == 'build'
|
||||
run: |
|
||||
# Ensure the binary exists before trying to run
|
||||
if [ -f "${{ env.build_dir }}/rippled" ]; then
|
||||
@@ -438,42 +347,3 @@ jobs:
|
||||
echo "Error: rippled executable not found in ${{ env.build_dir }}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Coverage-specific steps
|
||||
- name: Move coverage report
|
||||
if: matrix.job_type == 'coverage'
|
||||
shell: bash
|
||||
run: |
|
||||
mv "${{ env.build_dir }}/coverage.xml" ./
|
||||
|
||||
- name: Archive coverage report
|
||||
if: matrix.job_type == 'coverage'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: coverage.xml
|
||||
path: coverage.xml
|
||||
retention-days: 30
|
||||
|
||||
- name: Upload coverage report
|
||||
if: matrix.job_type == 'coverage'
|
||||
uses: codecov/codecov-action@v5
|
||||
with:
|
||||
files: coverage.xml
|
||||
fail_ci_if_error: true
|
||||
disable_search: true
|
||||
verbose: true
|
||||
plugins: noop
|
||||
use_oidc: true
|
||||
|
||||
- name: Export server definitions
|
||||
if: matrix.job_type == 'build' && matrix.compiler_id == 'gcc-13-libstdcxx'
|
||||
run: |
|
||||
${{ env.build_dir }}/rippled --definitions | python3 -m json.tool > server_definitions.json
|
||||
|
||||
- name: Upload server definitions
|
||||
if: matrix.job_type == 'build' && matrix.compiler_id == 'gcc-13-libstdcxx'
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: server-definitions
|
||||
path: server_definitions.json
|
||||
archive: false
|
||||
|
||||
11
.gitignore
vendored
11
.gitignore
vendored
@@ -53,9 +53,6 @@ Builds/levelization/results/paths.txt
|
||||
Builds/levelization/results/includes/
|
||||
Builds/levelization/results/includedby/
|
||||
|
||||
# Python
|
||||
__pycache__
|
||||
|
||||
# Ignore tmp directory.
|
||||
tmp
|
||||
|
||||
@@ -79,7 +76,6 @@ docs/html_doc
|
||||
# Xcode
|
||||
.DS_Store
|
||||
*/build/*
|
||||
!/docs/build/
|
||||
*.pbxuser
|
||||
!default.pbxuser
|
||||
*.mode1v3
|
||||
@@ -127,12 +123,5 @@ bld.rippled/
|
||||
generated
|
||||
.vscode
|
||||
|
||||
# AI docs (local working documents)
|
||||
.ai-docs/
|
||||
|
||||
# Local formal-methods workspace; kept as a separate repository and optionally
|
||||
# symlinked here for navigation.
|
||||
formal/lean/xahau_consensus
|
||||
|
||||
# Suggested in-tree build directory
|
||||
/.build/
|
||||
|
||||
2
.mise.toml
Normal file
2
.mise.toml
Normal file
@@ -0,0 +1,2 @@
|
||||
[tools]
|
||||
clang-format = "18"
|
||||
4
.testnet/.gitignore
vendored
4
.testnet/.gitignore
vendored
@@ -1,4 +0,0 @@
|
||||
output/
|
||||
__pycache__/
|
||||
scenarios/odd-cases/
|
||||
scenarios/suite-experiments.yml
|
||||
@@ -1,29 +0,0 @@
|
||||
"""Scenario: ConsensusEntropy amendment crashes non-supporting node.
|
||||
|
||||
Votes ConsensusEntropy accept on all nodes except n4, then waits for n4
|
||||
to crash as the amendment activates without its support.
|
||||
|
||||
x-testnet run --scenario-script consensus_entropy_crash.py
|
||||
"""
|
||||
|
||||
from helpers import CONSENSUS_ENTROPY_FEATURE
|
||||
|
||||
|
||||
async def scenario(ctx, log):
|
||||
await ctx.wait_for_ledger_close()
|
||||
ctx.feature(CONSENSUS_ENTROPY_FEATURE, vetoed=False, exclude_nodes=[4])
|
||||
|
||||
log("Waiting for ConsensusEntropy to be voted for...")
|
||||
await ctx.wait_for_feature(
|
||||
CONSENSUS_ENTROPY_FEATURE,
|
||||
check=lambda s: not s.get("vetoed"),
|
||||
exclude_nodes=[4],
|
||||
timeout=60,
|
||||
)
|
||||
|
||||
log("Waiting for n4 to crash...")
|
||||
op = await ctx.wait_for_nodes_down(nodes=[4], timeout=600)
|
||||
|
||||
ctx.assert_log("unsupported amendments activated", since=op.started, nodes=[4])
|
||||
ctx.assert_exit_status(0, nodes=[4])
|
||||
log("PASS: n4 shut down due to unsupported amendment")
|
||||
@@ -1,52 +0,0 @@
|
||||
""":descr: entropy stays valid under transaction load"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from helpers import require_entropy, get_entropy_tx, assert_valid_entropy
|
||||
|
||||
variants = [
|
||||
{"label": "light", "min_txns": 5, "max_txns": 10},
|
||||
{"label": "heavy", "min_txns": 50, "max_txns": 60},
|
||||
{"label": "super_heavy", "min_txns": 90, "max_txns": 120},
|
||||
]
|
||||
|
||||
|
||||
async def scenario(ctx, log, *, min_txns=5, max_txns=10, **_):
|
||||
await require_entropy(ctx, log)
|
||||
|
||||
gen = ctx.txn_generator(min_txns=min_txns, max_txns=max_txns)
|
||||
await gen.start()
|
||||
await gen.wait_until_ready()
|
||||
log(f"Transaction generator ready ({min_txns}-{max_txns} txns/ledger)")
|
||||
|
||||
# Wait for pipeline warmup + a few txn-bearing ledgers.
|
||||
await ctx.wait_for_ledgers(3, node_id=0, timeout=60)
|
||||
|
||||
start_seq = ctx.validated_ledger_index(0)
|
||||
await ctx.wait_for_ledgers(10, node_id=0, timeout=120)
|
||||
end_seq = ctx.validated_ledger_index(0)
|
||||
log(f"Inspecting ledgers {start_seq + 1} → {end_seq}")
|
||||
|
||||
digests = set()
|
||||
total_user_txns = 0
|
||||
|
||||
for seq in range(start_seq + 1, end_seq + 1):
|
||||
ce, user_txns = get_entropy_tx(ctx, seq)
|
||||
digest, count = assert_valid_entropy(ce, seq, seen_digests=digests)
|
||||
total_user_txns += len(user_txns)
|
||||
log(
|
||||
f" Ledger {seq}: EntropyCount={count} "
|
||||
f"user_txns={len(user_txns)} Digest={digest[:16]}..."
|
||||
)
|
||||
|
||||
await gen.stop()
|
||||
|
||||
log(
|
||||
f"Verified {end_seq - start_seq} ledgers: {total_user_txns} user txns, "
|
||||
f"all entropy valid and unique"
|
||||
)
|
||||
|
||||
if total_user_txns == 0:
|
||||
raise AssertionError("No user transactions were included in any ledger")
|
||||
|
||||
log("PASS")
|
||||
@@ -1,28 +0,0 @@
|
||||
""":descr: healthy non-standalone testnet without UNLReport mints Tier 1 fallback"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from helpers import require_entropy, get_entropy_tx, assert_consensus_fallback
|
||||
|
||||
|
||||
async def scenario(ctx, log):
|
||||
await require_entropy(ctx, log)
|
||||
|
||||
# Non-standalone nodes require a ledger-anchored UNLReport before assigning
|
||||
# validator_quorum / participant_aligned labels. Without it, the RNG pipeline
|
||||
# may still collect commits/reveals, but injection must remain Tier 1.
|
||||
await ctx.wait_for_ledgers(3, node_id=0, timeout=60)
|
||||
log("Pipeline warmed up without UNLReport")
|
||||
|
||||
start_seq = ctx.validated_ledger_index(0)
|
||||
await ctx.wait_for_ledgers(5, node_id=0, timeout=90)
|
||||
end_seq = ctx.validated_ledger_index(0)
|
||||
log(f"Inspecting ledgers {start_seq + 1} -> {end_seq}")
|
||||
|
||||
for seq in range(start_seq + 1, end_seq + 1):
|
||||
ce, _ = get_entropy_tx(ctx, seq)
|
||||
digest, count = assert_consensus_fallback(ce, seq)
|
||||
log(f" Ledger {seq}: EntropyCount={count} Digest={digest[:16]}...")
|
||||
|
||||
log(f"Verified {end_seq - start_seq} ledgers: all consensus_fallback")
|
||||
log("PASS")
|
||||
@@ -1,76 +0,0 @@
|
||||
""":descr: n0 ignores proposal-carried CE claims; sidecar fetch must recover them
|
||||
|
||||
This is the positive-control counterpart to the healthy steady-state fetch
|
||||
measurement. RuntimeConfig `rng_reveal_drop_pct=100` makes node 0 still harvest
|
||||
proposal-carried commits, but ignore proposal-carried reveals. That creates a
|
||||
clean "hash visible, reveal payload missing" case without relying on a
|
||||
particular relay topology.
|
||||
|
||||
The test proves two things on n0:
|
||||
1. fetch/acquisition ran; and
|
||||
2. acquired entropy sidecars added new reveal material (`pendingDelta`).
|
||||
|
||||
The second check is the load-bearing one: `entriesMerged` alone only proves that
|
||||
leaves were replayed through the merge loop, not that local consensus state was
|
||||
improved.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from helpers import require_entropy, get_entropy_tx, assert_valid_entropy
|
||||
|
||||
|
||||
async def scenario(ctx, log):
|
||||
await require_entropy(ctx, log)
|
||||
|
||||
cfg = ctx.rpc.runtime_config(0)
|
||||
log(f"n0 runtime_config: {cfg}")
|
||||
|
||||
start = ctx.mark("ce-fetch-recovers-start")
|
||||
await ctx.wait_for_ledgers(6, node_id=0, timeout=120)
|
||||
end = ctx.mark("ce-fetch-recovers-end")
|
||||
|
||||
end_seq = ctx.validated_ledger_index(0)
|
||||
start_seq = end_seq - 4
|
||||
log(f"Inspecting ledgers {start_seq} -> {end_seq}")
|
||||
|
||||
digests = set()
|
||||
for seq in range(start_seq, end_seq + 1):
|
||||
ce, _ = get_entropy_tx(ctx, seq)
|
||||
digest, count = assert_valid_entropy(ce, seq, seen_digests=digests)
|
||||
if count != 5:
|
||||
raise AssertionError(
|
||||
f"Ledger {seq}: expected full-count EntropyCount=5 after "
|
||||
f"fetch recovery, got {count}"
|
||||
)
|
||||
log(f" Ledger {seq}: EntropyCount={count} Digest={digest[:16]}...")
|
||||
|
||||
drops = ctx.assert_log(
|
||||
r"RNG: TESTING dropping reveal claim",
|
||||
since=start,
|
||||
until=end,
|
||||
nodes=[0],
|
||||
min_count=1,
|
||||
)
|
||||
log(f"n0 dropped proposal-carried CE reveal claims: {drops.count}")
|
||||
|
||||
triggers = ctx.assert_log(
|
||||
r"SIDECARFETCH: triggering network fetch.*kind=entropySet",
|
||||
since=start,
|
||||
until=end,
|
||||
nodes=[0],
|
||||
min_count=1,
|
||||
)
|
||||
log(f"n0 entropySet network-fetch triggers: {triggers.count}")
|
||||
|
||||
yielded = ctx.assert_log(
|
||||
r"SIDECARFETCH: merged acquired set.*setKind=entropySet.*"
|
||||
r"pendingDelta=[1-9]",
|
||||
since=start,
|
||||
until=end,
|
||||
nodes=[0],
|
||||
min_count=1,
|
||||
)
|
||||
log(f"n0 acquired entropySet sidecars with positive reveal yield: {yielded.count}")
|
||||
|
||||
log("PASS -- sidecar fetch recovered CE material hidden from proposals")
|
||||
@@ -1,162 +0,0 @@
|
||||
""":descr: 5/6 validator_quorum, 4/6 participant_aligned (tier 2), recovery
|
||||
|
||||
Requires node_count: 6 (see suite.yml) — the smallest NON-degenerate Tier 2
|
||||
size. At n=6: tier2 floor = 4, validator quorum = 5, validation quorum = 5. So
|
||||
6/6, 5/6 present -> validator_quorum (EntropyTier=3)
|
||||
4/6 present -> participant_aligned (EntropyTier=2, count 4) <-- the band
|
||||
3/6 present -> consensus_fallback (EntropyTier=1)
|
||||
n=5 has NO tier-2 band (tier2 == quorum == 4), which is why the existing
|
||||
degradation smoke at 5 nodes only ever sees tier 3 / fallback.
|
||||
|
||||
KEY: the 4/6 window is BELOW the 80% validation quorum (5). The 4 survivors
|
||||
keep CLOSING ledgers that carry tier-2 entropy, but those ledgers do NOT
|
||||
validate until the network recovers — exactly the transition window Tier 2
|
||||
serves. So validated_ledger_index() stalls; we instead inspect a surviving
|
||||
node's CLOSED ledger (its LCL) directly, and cross-check the injection from the
|
||||
cohort's logs.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from helpers import (
|
||||
require_entropy,
|
||||
get_entropy_tx,
|
||||
assert_participant_aligned,
|
||||
assert_validator_quorum,
|
||||
)
|
||||
|
||||
|
||||
def _closed_entropy(result):
|
||||
"""(seq, ConsensusEntropy tx) from a ctx.ledger('closed', transactions=True)
|
||||
result, or (None, None) if the fetch returned no usable ledger.
|
||||
|
||||
Enforces the per-ledger invariant that an entropy-enabled closed ledger
|
||||
carries EXACTLY ONE ConsensusEntropy pseudo-tx (mirroring get_entropy_tx):
|
||||
a duplicate or missing injection raises here with a clear error instead of
|
||||
being silently skipped and resurfacing later as a generic 'no tier-2 ledger'.
|
||||
"""
|
||||
if not result or not isinstance(result.get("ledger"), dict):
|
||||
return None, None
|
||||
led = result["ledger"]
|
||||
try:
|
||||
seq = int(led.get("ledger_index"))
|
||||
except (TypeError, ValueError):
|
||||
return None, None
|
||||
ce = [
|
||||
t
|
||||
for t in led.get("transactions", [])
|
||||
if isinstance(t, dict) and t.get("TransactionType") == "ConsensusEntropy"
|
||||
]
|
||||
if len(ce) != 1:
|
||||
raise AssertionError(
|
||||
f"Closed ledger {seq}: expected 1 ConsensusEntropy txn, got {len(ce)}"
|
||||
)
|
||||
return seq, ce[0]
|
||||
|
||||
|
||||
async def scenario(ctx, log):
|
||||
await require_entropy(ctx, log)
|
||||
|
||||
# Baseline: healthy 6/6 produces validator_quorum entropy.
|
||||
await ctx.wait_for_ledgers(1, node_id=0, timeout=30)
|
||||
|
||||
# --- 5/6: settles back to validator_quorum (5 present >= quorum 5) ---
|
||||
val_before_drop = ctx.validated_ledger_index(0)
|
||||
ctx.stop_node(5)
|
||||
await ctx.wait_for_nodes_down(nodes=[5], timeout=30)
|
||||
# Settle a few ledgers past the membership change. The ledger right at a
|
||||
# validator drop can carry a transient consensus_fallback (tier 1, count 0,
|
||||
# deterministic and by design) before the commit/reveal pipeline re-primes,
|
||||
# so we do NOT assume any single post-drop ledger is already tier 3.
|
||||
await ctx.wait_for_ledgers(4, node_id=0, timeout=90)
|
||||
|
||||
# 5/6 is at/above the 80% quorum (5), so steady state is validator_quorum.
|
||||
# Scan the post-drop validated ledgers (all carry the 5-node cohort, so a
|
||||
# tier-3 here has count == 5) and require at least one clean validator_quorum
|
||||
# — EntropyTier=3, count >= quorum, non-zero digest — tolerating the
|
||||
# transition fallback instead of depending on where the tip happened to land.
|
||||
val_5of6 = ctx.validated_ledger_index(0)
|
||||
t3_seq = None
|
||||
for seq in range(val_5of6, val_before_drop, -1):
|
||||
ce, _ = get_entropy_tx(ctx, seq)
|
||||
tier = ce.get("EntropyTier")
|
||||
log(f" 5/6 ledger {seq}: tier={tier} count={ce.get('EntropyCount')}")
|
||||
if tier == 3:
|
||||
assert_validator_quorum(ce, seq, min_count=5)
|
||||
t3_seq = seq
|
||||
break
|
||||
if t3_seq is None:
|
||||
raise AssertionError(
|
||||
f"5/6: no validator_quorum (tier 3) entropy in post-drop validated "
|
||||
f"ledgers {val_before_drop + 1}..{val_5of6}"
|
||||
)
|
||||
log(f"5/6: validator_quorum at validated seq {t3_seq}")
|
||||
|
||||
#@@start test-participant-aligned-window
|
||||
# --- 4/6: participant_aligned (Tier 2) degraded window ---
|
||||
ctx.stop_node(4)
|
||||
await ctx.wait_for_nodes_down(nodes=[4], timeout=30)
|
||||
|
||||
# ~12s window: confirm tier-2 INJECTION from the cohort's logs, and that the
|
||||
# round is NOT the below-quorum fallback path (which is what distinguishes
|
||||
# the tier-2 band from the tier-1 fallback regime).
|
||||
op = await ctx.sleep(12, name="tier2_window")
|
||||
selected_t2 = ctx.search_logs(
|
||||
r"RNG: entropy selected seq=\d+ tier=2 count=4",
|
||||
within=op.window,
|
||||
nodes=[0, 1, 2, 3],
|
||||
)
|
||||
log(f"4/6: 'entropy selected tier=2 count=4' logs: {selected_t2.count}")
|
||||
if selected_t2.count == 0:
|
||||
raise AssertionError(
|
||||
"4/6 window injected no participant_aligned (tier 2) entropy: no "
|
||||
"'RNG: entropy selected ... tier=2 count=4' on the surviving cohort"
|
||||
)
|
||||
ctx.assert_not_log(
|
||||
r"STALLDIAG: rng-commit-timeout-below-quorum",
|
||||
within=op.window,
|
||||
nodes=[0, 1, 2, 3],
|
||||
)
|
||||
|
||||
# Verify the on-ledger EntropyTier=2 DIRECTLY: validation is stalled (4 < 5),
|
||||
# so sample the surviving cohort's CLOSED ledger (its LCL — built but not yet
|
||||
# validated). At least one must be participant_aligned with EntropyCount=4.
|
||||
tier2_on_ledger = 0
|
||||
last_seq = None
|
||||
for _ in range(5):
|
||||
seq, ce = _closed_entropy(
|
||||
ctx.ledger("closed", transactions=True, node_id=0)
|
||||
)
|
||||
if ce is not None and seq is not None and seq != last_seq:
|
||||
last_seq = seq
|
||||
tier = ce.get("EntropyTier")
|
||||
count = ce.get("EntropyCount", -1)
|
||||
log(f" closed ledger {seq}: tier={tier} count={count}")
|
||||
if tier == 2:
|
||||
assert_participant_aligned(ce, seq, expected_count=4)
|
||||
tier2_on_ledger += 1
|
||||
await ctx.sleep(3)
|
||||
|
||||
if tier2_on_ledger == 0:
|
||||
raise AssertionError(
|
||||
"no closed participant_aligned (tier 2) ledger observed during the "
|
||||
"4/6 window (tier 2 was injected per logs, but not seen on a closed "
|
||||
"ledger)"
|
||||
)
|
||||
log(f"4/6: {tier2_on_ledger} participant_aligned closed ledger(s) verified")
|
||||
#@@end test-participant-aligned-window
|
||||
|
||||
# --- Recovery: liveness — validation resumes once quorum is restored ---
|
||||
ctx.start_node(4)
|
||||
ctx.start_node(5)
|
||||
await ctx.wait_for_ledgers(1, node_id=0, timeout=120)
|
||||
|
||||
val_recovered = ctx.validated_ledger_index(0)
|
||||
if not val_recovered or val_recovered <= val_5of6:
|
||||
raise AssertionError(
|
||||
f"Validated ledger did not advance after recovery "
|
||||
f"({val_5of6} -> {val_recovered})"
|
||||
)
|
||||
log(f"Recovered: validated seq {val_5of6} -> {val_recovered}")
|
||||
|
||||
log("PASS")
|
||||
@@ -1,164 +0,0 @@
|
||||
""":descr: 4/5 liveness, 3/5 fail-closed sub-quorum window, recovery"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from helpers import (
|
||||
require_entropy,
|
||||
get_entropy_tx,
|
||||
entropy_fields,
|
||||
assert_consensus_fallback,
|
||||
)
|
||||
|
||||
|
||||
def _closed_entropy(result):
|
||||
"""Return (seq, ConsensusEntropy tx) from a closed-ledger RPC result.
|
||||
|
||||
The 3/5 window is below validation quorum, so validated-ledger history is
|
||||
expected to stall. Sampling a surviving node's closed ledger catches any
|
||||
local LCL that advanced despite the sub-quorum condition.
|
||||
"""
|
||||
if not result or not isinstance(result.get("ledger"), dict):
|
||||
return None, None
|
||||
ledger = result["ledger"]
|
||||
try:
|
||||
seq = int(ledger.get("ledger_index"))
|
||||
except (TypeError, ValueError):
|
||||
return None, None
|
||||
ce = [
|
||||
tx
|
||||
for tx in ledger.get("transactions", [])
|
||||
if isinstance(tx, dict) and tx.get("TransactionType") == "ConsensusEntropy"
|
||||
]
|
||||
if len(ce) != 1:
|
||||
raise AssertionError(
|
||||
f"Closed ledger {seq}: expected 1 ConsensusEntropy txn, got {len(ce)}"
|
||||
)
|
||||
return seq, ce[0]
|
||||
|
||||
|
||||
async def scenario(ctx, log):
|
||||
await require_entropy(ctx, log)
|
||||
|
||||
# Baseline: wait 1 ledger to confirm network is healthy.
|
||||
await ctx.wait_for_ledgers(1, node_id=0, timeout=30)
|
||||
|
||||
# --- 4/5 liveness ---
|
||||
ctx.stop_node(4)
|
||||
await ctx.wait_for_nodes_down(nodes=[4], timeout=30)
|
||||
await ctx.wait_for_ledgers(1, node_id=0, timeout=30)
|
||||
log("4/5: liveness OK")
|
||||
|
||||
# Snapshot validated seq before dropping to 3/5.
|
||||
val_before = ctx.validated_ledger_index(0)
|
||||
|
||||
# --- 3/5 degraded window ---
|
||||
ctx.stop_node(3)
|
||||
await ctx.wait_for_nodes_down(nodes=[3], timeout=30)
|
||||
|
||||
# 10s ≈ 3 rounds at 3s cadence.
|
||||
await ctx.sleep(10)
|
||||
|
||||
val_after = ctx.validated_ledger_index(0)
|
||||
log(f"3/5: validated ledger {val_before} → {val_after}")
|
||||
|
||||
if val_after and val_before and val_after > val_before:
|
||||
raise AssertionError(
|
||||
f"3/5 sub-quorum window unexpectedly validated ledgers "
|
||||
f"({val_before} -> {val_after})"
|
||||
)
|
||||
|
||||
# If the surviving cohort exposes an advanced closed ledger despite being
|
||||
# below validation quorum, it must fail closed to consensus_fallback. This
|
||||
# keeps the entropy assertion live without pretending validated history
|
||||
# should advance at 3/5.
|
||||
degraded_fallback = 0
|
||||
last_closed = None
|
||||
for _ in range(5):
|
||||
seq, ce = _closed_entropy(ctx.ledger("closed", transactions=True, node_id=0))
|
||||
if seq and val_before and seq > val_before and seq != last_closed:
|
||||
last_closed = seq
|
||||
digest, count = assert_consensus_fallback(ce, seq)
|
||||
degraded_fallback += 1
|
||||
log(
|
||||
f" 3/5 closed ledger {seq}: EntropyCount={count} "
|
||||
f"Digest={digest[:16]}... FALLBACK"
|
||||
)
|
||||
await ctx.sleep(2)
|
||||
|
||||
log(f"3/5 closed-ledger fallback samples: {degraded_fallback}")
|
||||
|
||||
# Log checks tied to current transition mechanics:
|
||||
# - commit-set SHAMap publication is the observable output of entering the
|
||||
# commit sidecar phase
|
||||
# - ConvergingCommit transition is the gateway out of seq=0-only behavior
|
||||
# - rng-commit-timeout-below-quorum is the degraded-window fallback path
|
||||
ctx.log_level("LedgerConsensus", "trace")
|
||||
ctx.log_level("ConsensusExtensions", "trace")
|
||||
op = await ctx.sleep(6, name="stall_window")
|
||||
|
||||
ctx.assert_not_log(
|
||||
r"RNG: transitioned to ConvergingCommit", within=op.window, nodes=[0, 1, 2]
|
||||
)
|
||||
ctx.assert_not_log(
|
||||
r"RNG: built commitSet SHAMap", within=op.window, nodes=[0, 1, 2]
|
||||
)
|
||||
|
||||
gate_blocked = ctx.search_logs(
|
||||
r"STALLDIAG: establish gate blocked reason=(pause|no-tx-consensus)",
|
||||
within=op.window,
|
||||
nodes=[0, 1, 2],
|
||||
)
|
||||
log(f"3/5: establish gate-blocked logs in 6s: {gate_blocked.count}")
|
||||
|
||||
below_quorum = ctx.search_logs(
|
||||
r"STALLDIAG: rng-commit-timeout-below-quorum",
|
||||
within=op.window,
|
||||
nodes=[0, 1, 2],
|
||||
)
|
||||
log(f"3/5: RNG commit timeout below quorum logs in 6s: {below_quorum.count}")
|
||||
|
||||
# --- Recovery: restart nodes, verify ledger advancement ---
|
||||
ctx.start_node(3)
|
||||
ctx.start_node(4)
|
||||
await ctx.wait_for_ledgers(1, node_id=0, timeout=120)
|
||||
|
||||
val_recovered = ctx.validated_ledger_index(0)
|
||||
pre_recovery = max(v for v in [val_before, val_after] if v is not None)
|
||||
log(f"Recovered: validated seq {pre_recovery} → {val_recovered}")
|
||||
|
||||
if not val_recovered or val_recovered <= pre_recovery:
|
||||
raise AssertionError(
|
||||
f"Validated ledger did not advance after recovery "
|
||||
f"({pre_recovery} → {val_recovered})"
|
||||
)
|
||||
|
||||
# Inspect post-recovery ledgers separately from the degraded window above.
|
||||
# Once the network is back at quorum, validator-tier entropy is expected
|
||||
# again (transitional fallback ledgers are fine) and must be quorum-met.
|
||||
fallback_count = 0
|
||||
validator_count = 0
|
||||
for seq in range(pre_recovery + 1, val_recovered + 1):
|
||||
ce, _ = get_entropy_tx(ctx, seq)
|
||||
digest, entropy_count, is_fallback = entropy_fields(ce)
|
||||
|
||||
if is_fallback:
|
||||
fallback_count += 1
|
||||
else:
|
||||
validator_count += 1
|
||||
if entropy_count < 4:
|
||||
raise AssertionError(
|
||||
f"Ledger {seq}: validator entropy with sub-quorum "
|
||||
f"EntropyCount={entropy_count} (need >= 4)"
|
||||
)
|
||||
|
||||
log(
|
||||
f" Ledger {seq}: EntropyCount={entropy_count} "
|
||||
f"{'FALLBACK' if is_fallback else 'VALIDATOR'}"
|
||||
)
|
||||
|
||||
log(
|
||||
f"Entropy summary: {fallback_count} fallback, "
|
||||
f"{validator_count} validator"
|
||||
)
|
||||
|
||||
log("PASS")
|
||||
@@ -1,44 +0,0 @@
|
||||
""":descr: drop 2 nodes (3/5 stall), restart both, verify recovery"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from helpers import require_entropy
|
||||
|
||||
|
||||
async def scenario(ctx, log):
|
||||
await require_entropy(ctx, log)
|
||||
|
||||
await ctx.wait_for_ledgers(1, node_id=0, timeout=60)
|
||||
log("Baseline OK")
|
||||
|
||||
# Drop 2 nodes → validation stall.
|
||||
ctx.stop_node(3)
|
||||
ctx.stop_node(4)
|
||||
await ctx.wait_for_nodes_down(nodes=[3, 4], timeout=30)
|
||||
|
||||
info = ctx.rpc.server_info(node_id=0)
|
||||
val_before = info.get("info", {}).get("validated_ledger", {}).get("seq", 0)
|
||||
log(f"Stalled at validated seq {val_before}")
|
||||
|
||||
# Let it sit for a few rounds in degraded state.
|
||||
await ctx.sleep(6)
|
||||
|
||||
# Bring both nodes back.
|
||||
ctx.start_node(3)
|
||||
ctx.start_node(4)
|
||||
log("Restarted n3 and n4, waiting for recovery...")
|
||||
|
||||
# Recovery: wait for ANY validated ledger advance on n0.
|
||||
await ctx.wait_for_ledger_close(node_id=0, timeout=60)
|
||||
|
||||
info = ctx.rpc.server_info(node_id=0)
|
||||
val_after = info.get("info", {}).get("validated_ledger", {}).get("seq", 0)
|
||||
log(f"Recovered: validated seq {val_before} → {val_after}")
|
||||
|
||||
if val_after <= val_before:
|
||||
raise AssertionError(
|
||||
f"Validated ledger did not advance after recovery "
|
||||
f"({val_before} → {val_after})"
|
||||
)
|
||||
|
||||
log("PASS")
|
||||
@@ -1,27 +0,0 @@
|
||||
""":descr: all 5 nodes healthy, every ledger has valid unique quorum-met entropy"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from helpers import require_entropy, get_entropy_tx, assert_valid_entropy
|
||||
|
||||
|
||||
async def scenario(ctx, log):
|
||||
await require_entropy(ctx, log)
|
||||
|
||||
# Wait for the RNG pipeline to warm up past initial proposal/sidecar gossip.
|
||||
await ctx.wait_for_ledgers(3, node_id=0, timeout=60)
|
||||
log("Pipeline warmed up")
|
||||
|
||||
start_seq = ctx.validated_ledger_index(0)
|
||||
await ctx.wait_for_ledgers(10, node_id=0, timeout=120)
|
||||
end_seq = ctx.validated_ledger_index(0)
|
||||
log(f"Inspecting ledgers {start_seq + 1} → {end_seq}")
|
||||
|
||||
digests = set()
|
||||
for seq in range(start_seq + 1, end_seq + 1):
|
||||
ce, _ = get_entropy_tx(ctx, seq)
|
||||
digest, count = assert_valid_entropy(ce, seq, seen_digests=digests)
|
||||
log(f" Ledger {seq}: EntropyCount={count} Digest={digest[:16]}...")
|
||||
|
||||
log(f"Verified {end_seq - start_seq} ledgers: all quorum entropy, all unique")
|
||||
log("PASS")
|
||||
@@ -1,104 +0,0 @@
|
||||
defaults:
|
||||
network:
|
||||
node_count: 5
|
||||
launcher: tmux
|
||||
find_ports: true
|
||||
slave_delay: 0.2
|
||||
features:
|
||||
- ConsensusEntropy
|
||||
- Export
|
||||
track_features:
|
||||
- ConsensusEntropy
|
||||
- Export
|
||||
unl_report: true
|
||||
log_levels:
|
||||
TxQ: info
|
||||
Protocol: debug
|
||||
Peer: debug
|
||||
LedgerConsensus: debug
|
||||
ConsensusExtensions: debug
|
||||
NetworkOPs: info
|
||||
env:
|
||||
XAHAU_RESOURCE_PER_PORT: "1"
|
||||
rc:
|
||||
- rng_poll_ms=333
|
||||
|
||||
tests:
|
||||
# --- CE + Export (80% quorum, SHAMap convergence) ---
|
||||
- name: steady_state_export_ce
|
||||
script: .testnet/scenarios/export/steady_state_export.py
|
||||
|
||||
- name: retriable_export_ce
|
||||
script: .testnet/scenarios/export/retriable_export.py
|
||||
|
||||
- name: export_degradation_ce
|
||||
script: .testnet/scenarios/export/export_degradation.py
|
||||
network:
|
||||
rc:
|
||||
- rng_poll_ms=333
|
||||
- n3:no_export_sig=true
|
||||
- n4:no_export_sig=true
|
||||
|
||||
- name: export_without_unl_report
|
||||
script: .testnet/scenarios/export/export_without_unl_report.py
|
||||
network:
|
||||
features:
|
||||
- Export
|
||||
track_features:
|
||||
- Export
|
||||
unl_report: false
|
||||
|
||||
- name: export_no_veto_missing_observation
|
||||
script: .testnet/scenarios/export/export_no_veto_missing_observation.py
|
||||
network:
|
||||
rc:
|
||||
- rng_poll_ms=333
|
||||
- n4:no_export_sig_hash=true
|
||||
|
||||
# CE + Export: 1 node suppressed, 4/5 = 80% quorum, should succeed
|
||||
- name: export_ce_one_node_down
|
||||
script: .testnet/scenarios/export/export_quorum.py
|
||||
params:
|
||||
expect_success: true
|
||||
network:
|
||||
rc:
|
||||
- rng_poll_ms=333
|
||||
- n4:no_export_sig=true
|
||||
|
||||
# --- Export only, no CE (80% active-view quorum) ---
|
||||
- name: export_only_all_up
|
||||
script: .testnet/scenarios/export/export_quorum.py
|
||||
params:
|
||||
expect_success: true
|
||||
network:
|
||||
features:
|
||||
- Export
|
||||
track_features:
|
||||
- Export
|
||||
|
||||
- name: export_only_one_node_down
|
||||
script: .testnet/scenarios/export/export_quorum.py
|
||||
params:
|
||||
expect_success: true
|
||||
network:
|
||||
features:
|
||||
- Export
|
||||
track_features:
|
||||
- Export
|
||||
rc:
|
||||
- rng_poll_ms=333
|
||||
- n4:no_export_sig=true
|
||||
|
||||
- name: export_only_two_nodes_down
|
||||
script: .testnet/scenarios/export/export_quorum.py
|
||||
params:
|
||||
expect_success: false
|
||||
network:
|
||||
features:
|
||||
- Export
|
||||
track_features:
|
||||
- Export
|
||||
rc:
|
||||
- rng_poll_ms=333
|
||||
- n3:no_export_sig=true
|
||||
- n4:no_export_sig=true
|
||||
@@ -1,123 +0,0 @@
|
||||
""":descr: Submit ttEXPORT with 2 nodes suppressing export sigs, verify it
|
||||
retries via terRETRY_EXPORT until LLS expiry (insufficient signatures).
|
||||
|
||||
Nodes 3 and 4 have runtime_config no_export_sig=true, so only 3/5 nodes
|
||||
provide export signatures. With 80% quorum = ceil(5*0.8) = 4 required,
|
||||
the export cannot reach quorum and should expire via tecEXPORT_EXPIRED.
|
||||
|
||||
Flow:
|
||||
1. Fund alice and bob
|
||||
2. alice submits ttEXPORT with tight LLS
|
||||
3. Export retries (only 3/5 sigs available, need 4)
|
||||
4. Verify export expires with tecEXPORT_EXPIRED
|
||||
5. Verify subsequent payment still works (sequence not permanently blocked)
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from export_helpers import require_export, assert_shadow_ticket
|
||||
|
||||
|
||||
async def scenario(ctx, log):
|
||||
await require_export(ctx, log)
|
||||
|
||||
# --- Setup ---
|
||||
await ctx.fund_accounts({"alice": 10000, "bob": 1000})
|
||||
log("Accounts funded")
|
||||
|
||||
alice = ctx.account("alice")
|
||||
bob = ctx.account("bob")
|
||||
current_seq = ctx.validated_ledger_index(0)
|
||||
|
||||
log(f"Current ledger: {current_seq}")
|
||||
log("Nodes 3,4 have runtime_config no_export_sig=true (3/5 sigs, need 4)")
|
||||
|
||||
#@@start test-export-below-quorum-expiry
|
||||
# --- Submit ttEXPORT (should retry then expire -- only 3/5 sigs) ---
|
||||
export_start = ctx.mark("export-degradation-submit-start")
|
||||
result = await ctx.submit_and_wait(
|
||||
{
|
||||
"TransactionType": "Export",
|
||||
"LastLedgerSequence": current_seq + 8,
|
||||
"Fee": "1000000",
|
||||
"ExportedTxn": {
|
||||
"TransactionType": "Payment",
|
||||
"Account": alice.address,
|
||||
"Destination": bob.address,
|
||||
"Amount": "1000000",
|
||||
"Fee": "10",
|
||||
"Sequence": 0,
|
||||
"TicketSequence": 1,
|
||||
"FirstLedgerSequence": current_seq + 1,
|
||||
"LastLedgerSequence": current_seq + 6,
|
||||
"Flags": 2147483648,
|
||||
"SigningPubKey": "",
|
||||
},
|
||||
},
|
||||
alice.wallet,
|
||||
timeout=60,
|
||||
)
|
||||
export_end = ctx.mark("export-degradation-submit-end")
|
||||
|
||||
final_seq = ctx.validated_ledger_index(0)
|
||||
engine_result = result.get("engine_result", "")
|
||||
log(f"Export completed at ledger {final_seq}, result: {engine_result}")
|
||||
|
||||
# With only 3/5 sigs and 80% quorum (4 required), export MUST fail
|
||||
if engine_result == "tesSUCCESS":
|
||||
raise AssertionError(
|
||||
"Export should NOT have succeeded with only 3/5 sigs "
|
||||
"(need 4 for 80% quorum) -- check runtime_config no_export_sig"
|
||||
)
|
||||
|
||||
# Should be tecEXPORT_EXPIRED (LLS reached without quorum). Be exact here:
|
||||
# any other non-success means the retry/expiry boundary regressed.
|
||||
if engine_result != "tecEXPORT_EXPIRED":
|
||||
raise AssertionError(
|
||||
f"Expected tecEXPORT_EXPIRED below quorum, got {engine_result}"
|
||||
)
|
||||
|
||||
log(f"Export failed as expected ({engine_result})")
|
||||
|
||||
retry_logs = ctx.assert_log(
|
||||
r"Export: insufficient signatures .*result=terRETRY_EXPORT",
|
||||
since=export_start,
|
||||
until=export_end,
|
||||
)
|
||||
log(f"Export insufficient-signature retries: {retry_logs.count}")
|
||||
|
||||
expired_logs = ctx.assert_log(
|
||||
r"Export: last ledger expired .*result=tecEXPORT_EXPIRED",
|
||||
since=export_start,
|
||||
until=export_end,
|
||||
)
|
||||
log(f"Export LLS expiry logs: {expired_logs.count}")
|
||||
|
||||
# No shadow ticket should exist (export never reached quorum)
|
||||
assert_shadow_ticket(ctx, alice.address, log, expect_exists=False)
|
||||
#@@end test-export-below-quorum-expiry
|
||||
|
||||
# --- Verify subsequent payment works regardless ---
|
||||
log("Submitting payment from alice to bob...")
|
||||
pay_result = await ctx.submit_and_wait(
|
||||
{
|
||||
"TransactionType": "Payment",
|
||||
"Destination": bob.address,
|
||||
"Amount": "1000000",
|
||||
"Fee": "12",
|
||||
},
|
||||
alice.wallet,
|
||||
timeout=30,
|
||||
)
|
||||
|
||||
pay_engine = pay_result.get("engine_result", "")
|
||||
log(f"Payment result: {pay_engine}")
|
||||
|
||||
if pay_engine != "tesSUCCESS":
|
||||
raise AssertionError(
|
||||
f"Payment failed after expired export: {pay_engine} "
|
||||
f"-- sequence may be blocked"
|
||||
)
|
||||
|
||||
log("Payment succeeded -- account not permanently blocked")
|
||||
log("PASS")
|
||||
@@ -1,158 +0,0 @@
|
||||
""":descr: Drop n4->n0 proposals after setup and assert n0 uses sidecar fetch.
|
||||
|
||||
The x-testnet default topology is a full mesh, so a one-edge proposal drop does
|
||||
not prove n0 missed every copy of n4's proposal-carried material: n1/n2/n3 may
|
||||
relay around the cut. This scenario is therefore a fetch-path exercise and
|
||||
export-convergence test, not a strict proof that fetch recovered a contributor
|
||||
that proposal relay could not deliver. For positive CE recovery, see
|
||||
entropy_fetch_recovers_dropped_claims.
|
||||
|
||||
This is the resilience counterpart to export_degradation:
|
||||
- export_degradation: n3/n4 do NOT sign (no_export_sig) -> only 3/5 sigs exist
|
||||
-> export EXPIRES (tecEXPORT_EXPIRED). The sigs genuinely don't exist.
|
||||
- this test: n4 DOES sign, but its proposals to n0 are 100% dropped after
|
||||
account setup. n0 stays above quorum from direct proposals and obtains n4's
|
||||
contribution through the sidecar fetch/acquisition path. With fetch working,
|
||||
n0 reconstructs the agreed set and the export SUCCEEDS.
|
||||
|
||||
So this is a regression test for sidecar acquisition on lossy proposal links:
|
||||
the fetch path must run on n0, and export must still converge. It is deliberately
|
||||
weaker than a topology-isolated proof that n0 missed a specific contributor.
|
||||
|
||||
Flow:
|
||||
1. Fund alice and bob
|
||||
2. Enable runtime_config drop for n4->n0 proposals
|
||||
3. alice submits ttEXPORT (all 5 nodes sign; n0 loses direct n4 proposals)
|
||||
4. n0 fetches agreed sidecars (assert SIDECARFETCH triggered + merged on n0)
|
||||
5. Export succeeds (tesSUCCESS) and a shadow ticket latch is created
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
|
||||
from export_helpers import require_export, assert_shadow_ticket
|
||||
|
||||
|
||||
def _peer_key_for_node(ctx, node_id: int) -> str:
|
||||
network_file = ctx.base_dir / "network.json"
|
||||
with network_file.open() as f:
|
||||
network = json.load(f)
|
||||
|
||||
for node in network["nodes"]:
|
||||
if node["id"] == node_id:
|
||||
return f"peer:127.0.0.1:{node['port_peer']}"
|
||||
|
||||
raise AssertionError(f"node {node_id} missing from {network_file}")
|
||||
|
||||
|
||||
def _drop_proposals_from_n4_to_n0(ctx, log) -> None:
|
||||
n0_peer_key = _peer_key_for_node(ctx, 0)
|
||||
params = {
|
||||
"set": {
|
||||
n0_peer_key: {
|
||||
"send_drop_pct": 100.0,
|
||||
"message_types": ["proposal"],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result = ctx.rpc.runtime_config(4, params)
|
||||
if not result or result.get("error"):
|
||||
raise AssertionError(f"Failed to configure n4->n0 proposal drop: {result}")
|
||||
|
||||
applied = ctx.rpc.runtime_config(4)
|
||||
log(f"Applied n4 runtime_config drop to {n0_peer_key}: {applied}")
|
||||
|
||||
|
||||
async def scenario(ctx, log):
|
||||
await require_export(ctx, log)
|
||||
|
||||
# --- Setup ---
|
||||
await ctx.fund_accounts({"alice": 10000, "bob": 1000})
|
||||
log("Accounts funded")
|
||||
|
||||
alice = ctx.account("alice")
|
||||
bob = ctx.account("bob")
|
||||
current_seq = ctx.validated_ledger_index(0)
|
||||
log(f"Current ledger: {current_seq}")
|
||||
|
||||
#@@start test-export-sidecar-fetch-under-proposal-drop
|
||||
_drop_proposals_from_n4_to_n0(ctx, log)
|
||||
log(
|
||||
"n4->n0 proposals are now 100% dropped (msg=proposal): in the full "
|
||||
"mesh this exercises sidecar acquisition without proving all relayed "
|
||||
"copies of n4 material were suppressed"
|
||||
)
|
||||
|
||||
# --- Submit ttEXPORT (all nodes sign; n0 only misses n4 inline) ---
|
||||
fetch_start = ctx.mark("export-fetch-drop-start")
|
||||
result = await ctx.submit_and_wait(
|
||||
{
|
||||
"TransactionType": "Export",
|
||||
"LastLedgerSequence": current_seq + 5,
|
||||
"Fee": "1000000",
|
||||
"ExportedTxn": {
|
||||
"TransactionType": "Payment",
|
||||
"Account": alice.address,
|
||||
"Destination": bob.address,
|
||||
"Amount": "1000000",
|
||||
"Fee": "10",
|
||||
"Sequence": 0,
|
||||
"TicketSequence": 1,
|
||||
"FirstLedgerSequence": current_seq + 1,
|
||||
"LastLedgerSequence": current_seq + 5,
|
||||
"Flags": 2147483648,
|
||||
"SigningPubKey": "",
|
||||
},
|
||||
},
|
||||
alice.wallet,
|
||||
timeout=90,
|
||||
)
|
||||
fetch_end = ctx.mark("export-fetch-drop-end")
|
||||
|
||||
engine_result = result.get("engine_result", "")
|
||||
final_seq = ctx.validated_ledger_index(0)
|
||||
log(f"Export completed at ledger {final_seq}, result: {engine_result}")
|
||||
|
||||
# The export signatures exist (all 5 nodes sign). With acquisition working,
|
||||
# n0 can reconstruct the agreed set even while direct n4->n0 proposals are
|
||||
# dropped.
|
||||
if engine_result != "tesSUCCESS":
|
||||
raise AssertionError(
|
||||
f"Expected tesSUCCESS via sidecar fetch, got {engine_result} -- the "
|
||||
"fetch path failed to deliver n4 sidecar contributions to n0 "
|
||||
"(or the proposal drop starved consensus on n0)"
|
||||
)
|
||||
log("Export succeeded despite dropped direct n4->n0 proposals")
|
||||
|
||||
# Prove the SIDECAR FETCH path actually ran on n0. In a full mesh,
|
||||
# entriesMerged proves the acquired set was replayed through the merge path;
|
||||
# it does not prove local state gained a previously unseen contributor.
|
||||
triggered = ctx.assert_log(
|
||||
r"SIDECARFETCH: triggering network fetch",
|
||||
since=fetch_start,
|
||||
until=fetch_end,
|
||||
nodes=[0],
|
||||
min_count=1,
|
||||
)
|
||||
log(f"n0 SIDECARFETCH network-fetch triggers: {triggered.count}")
|
||||
|
||||
merged = ctx.assert_log(
|
||||
r"SIDECARFETCH: merged acquired set.*entriesMerged=[1-9]",
|
||||
since=fetch_start,
|
||||
until=fetch_end,
|
||||
nodes=[0],
|
||||
min_count=1,
|
||||
)
|
||||
log(f"n0 SIDECARFETCH merged-with-entries: {merged.count}")
|
||||
|
||||
# Export completed -> a shadow-ticket callback latch exists for alice
|
||||
# (contrast: export_degradation asserts expect_exists=False on expiry).
|
||||
assert_shadow_ticket(ctx, alice.address, log, expect_exists=True)
|
||||
#@@end test-export-sidecar-fetch-under-proposal-drop
|
||||
|
||||
log(
|
||||
"PASS -- proposal drop exercised node 0 sidecar acquisition and the "
|
||||
"export still converged"
|
||||
)
|
||||
@@ -1,244 +0,0 @@
|
||||
"""Shared helpers for Export scenario tests."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from xahaud_scripts.testnet.config import _unl_report_index, feature_name_to_hash
|
||||
|
||||
|
||||
async def require_export(
|
||||
ctx, log, *, require_unl_report=True, require_runtime_config=True
|
||||
):
|
||||
"""Wait for first ledger and assert Export is enabled.
|
||||
|
||||
Network-mode Export success requires a parent-ledger UNLReport-backed
|
||||
active validator view. Most export scenarios seed that report in genesis;
|
||||
assert it here so a success-path test cannot accidentally pass setup
|
||||
without the condition Export::doApply requires. The no-UNLReport retry
|
||||
scenario opts out deliberately.
|
||||
|
||||
The tracked export suite also uses XAHAUD_RUNTIME_TEST_CONFIG for polling
|
||||
and fault-injection knobs. Default binaries reject the runtime_config RPC,
|
||||
so check it up front rather than silently running without those knobs.
|
||||
"""
|
||||
await ctx.wait_for_ledger_close(timeout=120)
|
||||
|
||||
if require_runtime_config:
|
||||
result = ctx.rpc.runtime_config(0)
|
||||
if not result or result.get("error"):
|
||||
raise AssertionError(
|
||||
"Export suite requires a binary built with "
|
||||
"xahaud_runtime_test_config=ON; runtime_config RPC returned "
|
||||
f"{result}"
|
||||
)
|
||||
log("RuntimeConfig RPC active")
|
||||
|
||||
feature = ctx.feature_check(feature_name_to_hash("Export"), node_id=0)
|
||||
if not feature or not feature.get("enabled", False):
|
||||
raise AssertionError(f"Export not enabled: {feature}")
|
||||
log("Export enabled")
|
||||
|
||||
if require_unl_report:
|
||||
result = ctx.rpc.ledger_entry(0, _unl_report_index())
|
||||
node = (result or {}).get("node", {})
|
||||
active = node.get("ActiveValidators", [])
|
||||
if node.get("LedgerEntryType") != "UNLReport" or not active:
|
||||
raise AssertionError(
|
||||
"Export success scenario requires a ledger UNLReport with "
|
||||
f"ActiveValidators, got: {result}"
|
||||
)
|
||||
log(f"UNLReport active validators: {len(active)}")
|
||||
|
||||
|
||||
def find_export_txns(ctx, seq):
|
||||
"""Find Export transactions in a ledger.
|
||||
|
||||
Returns list of Export transaction dicts.
|
||||
"""
|
||||
result = ctx.ledger(seq, transactions=True)
|
||||
if not result:
|
||||
return []
|
||||
|
||||
txns = result.get("ledger", {}).get("transactions", [])
|
||||
return [tx for tx in txns if tx.get("TransactionType") == "Export"]
|
||||
|
||||
|
||||
def find_export_signature_witness(ctx, seq, witness_hash):
|
||||
"""Find the same-ledger ExportSignatures witness by transaction hash."""
|
||||
result = ctx.ledger(seq, transactions=True)
|
||||
txns = (result or {}).get("ledger", {}).get("transactions", [])
|
||||
for tx in txns:
|
||||
if not isinstance(tx, dict):
|
||||
continue
|
||||
if tx.get("hash") != witness_hash:
|
||||
continue
|
||||
if tx.get("TransactionType") != "ExportSignatures":
|
||||
raise AssertionError(
|
||||
f"ExportSignatureHash {witness_hash} resolved to "
|
||||
f"{tx.get('TransactionType')}, not ExportSignatures"
|
||||
)
|
||||
return tx
|
||||
raise AssertionError(
|
||||
f"ExportSignatures witness {witness_hash} not found in ledger {seq}"
|
||||
)
|
||||
|
||||
|
||||
def dst_param(address):
|
||||
"""Encode an address as a HookParameter entry for the DST param."""
|
||||
from xrpl.core.addresscodec import decode_classic_address
|
||||
|
||||
dst_hex = decode_classic_address(address).hex().upper()
|
||||
return {
|
||||
"HookParameter": {
|
||||
"HookParameterName": "445354", # "DST"
|
||||
"HookParameterValue": dst_hex,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def assert_hook_accepted(
|
||||
meta, log, *, expected_emits=1, expected_exports=None
|
||||
):
|
||||
"""Assert hook executed with ACCEPT and expected emission counts.
|
||||
|
||||
Checks sfHookExecutions in transaction metadata.
|
||||
Returns the hook execution entry for further inspection.
|
||||
"""
|
||||
hook_execs = meta.get("HookExecutions", [])
|
||||
if not hook_execs:
|
||||
raise AssertionError("No HookExecutions in metadata")
|
||||
|
||||
exec_entry = hook_execs[0].get("HookExecution", {})
|
||||
hook_result = exec_entry.get("HookResult", -1)
|
||||
emit_count = exec_entry.get("HookEmitCount", -1)
|
||||
export_count = exec_entry.get("HookExportCount")
|
||||
return_code = exec_entry.get("HookReturnCode", "")
|
||||
|
||||
log(
|
||||
f" HookResult={hook_result} EmitCount={emit_count} "
|
||||
f"ExportCount={export_count} ReturnCode={return_code}"
|
||||
)
|
||||
|
||||
# HookResult 3 = ExitType::ACCEPT
|
||||
if hook_result != 3:
|
||||
raise AssertionError(
|
||||
f"Hook did not ACCEPT: HookResult={hook_result} "
|
||||
f"ReturnCode={return_code}"
|
||||
)
|
||||
|
||||
if emit_count != expected_emits:
|
||||
raise AssertionError(
|
||||
f"Expected {expected_emits} emits, got {emit_count}"
|
||||
)
|
||||
|
||||
if expected_exports is not None and export_count != expected_exports:
|
||||
raise AssertionError(
|
||||
f"Expected {expected_exports} exports, got {export_count}"
|
||||
)
|
||||
|
||||
# ReturnCode 0 = success; non-zero = ASSERT line number in hook
|
||||
if return_code and str(return_code) != "0":
|
||||
raise AssertionError(
|
||||
f"Hook returned error code {return_code} "
|
||||
f"(likely ASSERT failure at that line)"
|
||||
)
|
||||
|
||||
return exec_entry
|
||||
|
||||
|
||||
def _signer_entries(witness):
|
||||
entries = []
|
||||
for entry in witness.get("Signers", []):
|
||||
signer = entry.get("Signer", entry)
|
||||
entries.append(signer)
|
||||
return entries
|
||||
|
||||
|
||||
def _account_sort_key(address):
|
||||
from xrpl.core.addresscodec import decode_classic_address
|
||||
|
||||
return decode_classic_address(address)
|
||||
|
||||
|
||||
def assert_export_result(meta, log, *, ctx=None, require_signers=True):
|
||||
"""Assert ExportResult is present and well-formed in metadata.
|
||||
|
||||
Returns the ExportResult dict. When signers are required, the result is
|
||||
annotated with _Witness and _WitnessSigners from the same-ledger
|
||||
ttEXPORT_SIGNATURES pseudo transaction.
|
||||
"""
|
||||
export_result = meta.get("ExportResult", {})
|
||||
if not export_result:
|
||||
raise AssertionError("ExportResult not found in metadata")
|
||||
|
||||
# Must have LedgerSequence and TransactionHash
|
||||
if "LedgerSequence" not in export_result:
|
||||
raise AssertionError("ExportResult missing LedgerSequence")
|
||||
if "TransactionHash" not in export_result:
|
||||
raise AssertionError("ExportResult missing TransactionHash")
|
||||
if "ExportSignatureHash" not in export_result:
|
||||
raise AssertionError("ExportResult missing ExportSignatureHash")
|
||||
|
||||
log(f" ExportResult: seq={export_result['LedgerSequence']} "
|
||||
f"hash={export_result['TransactionHash'][:16]}... "
|
||||
f"witness={export_result['ExportSignatureHash'][:16]}...")
|
||||
|
||||
if "ExportedTxn" in export_result:
|
||||
raise AssertionError(
|
||||
"ExportResult should reference ExportSignatureHash, not embed "
|
||||
"ExportedTxn"
|
||||
)
|
||||
|
||||
if require_signers:
|
||||
if ctx is None:
|
||||
raise AssertionError(
|
||||
"assert_export_result(require_signers=True) needs ctx to "
|
||||
"dereference ExportSignatureHash"
|
||||
)
|
||||
witness = find_export_signature_witness(
|
||||
ctx,
|
||||
export_result["LedgerSequence"],
|
||||
export_result["ExportSignatureHash"],
|
||||
)
|
||||
if witness.get("TransactionHash") != export_result["TransactionHash"]:
|
||||
raise AssertionError(
|
||||
"ExportSignatures witness TransactionHash does not match "
|
||||
"ExportResult.TransactionHash"
|
||||
)
|
||||
if witness.get("LedgerSequence") != export_result["LedgerSequence"]:
|
||||
raise AssertionError(
|
||||
"ExportSignatures witness LedgerSequence does not match "
|
||||
"ExportResult.LedgerSequence"
|
||||
)
|
||||
signers = _signer_entries(witness)
|
||||
if not signers:
|
||||
raise AssertionError("ExportSignatures witness has no Signers")
|
||||
accounts = [s.get("Account") for s in signers]
|
||||
if accounts != sorted(accounts, key=_account_sort_key):
|
||||
raise AssertionError("ExportSignatures Signers are not Account-sorted")
|
||||
log(f" Witness signers: {len(signers)} validator(s)")
|
||||
export_result["_Witness"] = witness
|
||||
export_result["_WitnessSigners"] = signers
|
||||
|
||||
return export_result
|
||||
|
||||
|
||||
def assert_shadow_ticket(ctx, account_address, log, *, expect_exists=True):
|
||||
"""Assert shadow ticket exists (or doesn't) for the account."""
|
||||
obj_result = ctx.rpc.request(
|
||||
0, "account_objects", {"account": account_address}
|
||||
)
|
||||
all_objects = (obj_result or {}).get("account_objects", [])
|
||||
shadow_tickets = [
|
||||
obj for obj in all_objects
|
||||
if obj.get("LedgerEntryType") == "ShadowTicket"
|
||||
]
|
||||
log(f" Shadow tickets: {len(shadow_tickets)}")
|
||||
|
||||
if expect_exists and not shadow_tickets:
|
||||
raise AssertionError("Expected shadow ticket but none found")
|
||||
if not expect_exists and shadow_tickets:
|
||||
raise AssertionError(
|
||||
f"Expected no shadow tickets but found {len(shadow_tickets)}"
|
||||
)
|
||||
|
||||
return shadow_tickets
|
||||
@@ -1,87 +0,0 @@
|
||||
""":descr: Export succeeds when quorum sidecar material exists but one active
|
||||
validator withholds exportSigSetHash observation.
|
||||
|
||||
Node 4 has runtime_config no_export_sig_hash=true. It still attaches export
|
||||
signatures, but it does not publish its exportSigSetHash in proposals. The
|
||||
remaining 4/5 active validators can still align on the same export sidecar
|
||||
hash, so the round must not retry/expire just because fullObservation is false.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from export_helpers import (
|
||||
require_export,
|
||||
assert_export_result,
|
||||
assert_shadow_ticket,
|
||||
)
|
||||
|
||||
|
||||
async def scenario(ctx, log):
|
||||
await require_export(ctx, log)
|
||||
|
||||
await ctx.fund_accounts({"alice": 10000, "bob": 1000})
|
||||
log("Accounts funded")
|
||||
|
||||
alice = ctx.account("alice")
|
||||
bob = ctx.account("bob")
|
||||
current_seq = ctx.validated_ledger_index(0)
|
||||
|
||||
log(f"Current ledger: {current_seq}")
|
||||
log("Node 4 withholds exportSigSetHash but still attaches export signatures")
|
||||
|
||||
export_start = ctx.mark("export-no-veto-submit-start")
|
||||
result = await ctx.submit_and_wait(
|
||||
{
|
||||
"TransactionType": "Export",
|
||||
"LastLedgerSequence": current_seq + 10,
|
||||
"Fee": "1000000",
|
||||
"ExportedTxn": {
|
||||
"TransactionType": "Payment",
|
||||
"Account": alice.address,
|
||||
"Destination": bob.address,
|
||||
"Amount": "1000000",
|
||||
"Fee": "10",
|
||||
"Sequence": 0,
|
||||
"TicketSequence": 1,
|
||||
"FirstLedgerSequence": current_seq + 1,
|
||||
"LastLedgerSequence": current_seq + 8,
|
||||
"Flags": 2147483648,
|
||||
"SigningPubKey": "",
|
||||
},
|
||||
},
|
||||
alice.wallet,
|
||||
timeout=60,
|
||||
)
|
||||
export_end = ctx.mark("export-no-veto-submit-end")
|
||||
|
||||
final_seq = ctx.validated_ledger_index(0)
|
||||
engine_result = result.get("engine_result", "")
|
||||
meta = result.get("meta", {})
|
||||
|
||||
log(f"Export completed at ledger {final_seq}, result: {engine_result}")
|
||||
if engine_result != "tesSUCCESS":
|
||||
raise AssertionError(f"Expected tesSUCCESS, got {engine_result}")
|
||||
|
||||
export_result = assert_export_result(meta, log, ctx=ctx, require_signers=True)
|
||||
signers = export_result.get("_WitnessSigners", [])
|
||||
if len(signers) < 4:
|
||||
raise AssertionError(f"Expected at least 4 signers, got {len(signers)}")
|
||||
log(f"Export signer count: {len(signers)}")
|
||||
|
||||
no_veto_logs = ctx.assert_log(
|
||||
r"Export: missing exportSigSetHash observation ignored",
|
||||
since=export_start,
|
||||
until=export_end,
|
||||
)
|
||||
log(f"Export no-veto missing-observation logs: {no_veto_logs.count}")
|
||||
|
||||
withhold_logs = ctx.assert_log(
|
||||
r"Export: withholding exportSigSetHash",
|
||||
since=export_start,
|
||||
until=export_end,
|
||||
)
|
||||
log(f"Export sidecar hash withholding logs: {withhold_logs.count}")
|
||||
|
||||
assert_shadow_ticket(ctx, alice.address, log, expect_exists=True)
|
||||
|
||||
log("PASS")
|
||||
@@ -1,117 +0,0 @@
|
||||
""":descr: Test Export quorum behavior. When enough active validators sign,
|
||||
the export should succeed whether or not CE is enabled. When fewer than the
|
||||
active-view quorum sign, the export should expire.
|
||||
|
||||
Parameterized via `expect_success` kwarg from suite.yml.
|
||||
|
||||
Flow:
|
||||
1. Fund alice and bob
|
||||
2. alice submits ttEXPORT
|
||||
3. Verify result matches expectation (tesSUCCESS or tecEXPORT_EXPIRED)
|
||||
4. Verify ExportResult + shadow ticket on success, absence on failure
|
||||
5. Verify subsequent payment works regardless
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from export_helpers import (
|
||||
require_export,
|
||||
assert_export_result,
|
||||
assert_shadow_ticket,
|
||||
)
|
||||
|
||||
|
||||
async def scenario(ctx, log, expect_success=True):
|
||||
await require_export(ctx, log)
|
||||
|
||||
# --- Setup ---
|
||||
await ctx.fund_accounts({"alice": 10000, "bob": 1000})
|
||||
log("Accounts funded")
|
||||
|
||||
alice = ctx.account("alice")
|
||||
bob = ctx.account("bob")
|
||||
current_seq = ctx.validated_ledger_index(0)
|
||||
|
||||
log(f"Current ledger: {current_seq}")
|
||||
outcome = "success" if expect_success else "failure (below quorum)"
|
||||
log(f"Expecting export {outcome}")
|
||||
|
||||
# --- Submit ttEXPORT ---
|
||||
result = await ctx.submit_and_wait(
|
||||
{
|
||||
"TransactionType": "Export",
|
||||
"LastLedgerSequence": current_seq + 10,
|
||||
"Fee": "1000000",
|
||||
"ExportedTxn": {
|
||||
"TransactionType": "Payment",
|
||||
"Account": alice.address,
|
||||
"Destination": bob.address,
|
||||
"Amount": "1000000",
|
||||
"Fee": "10",
|
||||
"Sequence": 0,
|
||||
"TicketSequence": 1,
|
||||
"FirstLedgerSequence": current_seq + 1,
|
||||
"LastLedgerSequence": current_seq + 8,
|
||||
"Flags": 2147483648,
|
||||
"SigningPubKey": "",
|
||||
},
|
||||
},
|
||||
alice.wallet,
|
||||
timeout=60,
|
||||
)
|
||||
|
||||
final_seq = ctx.validated_ledger_index(0)
|
||||
engine_result = result.get("engine_result", "")
|
||||
meta = result.get("meta", {})
|
||||
|
||||
log(f"Export at ledger {final_seq}, result: {engine_result}")
|
||||
|
||||
if expect_success:
|
||||
if engine_result != "tesSUCCESS":
|
||||
raise AssertionError(
|
||||
f"Expected tesSUCCESS, got {engine_result}"
|
||||
)
|
||||
|
||||
# Assert ExportResult is well-formed with signers
|
||||
assert_export_result(meta, log, ctx=ctx, require_signers=True)
|
||||
|
||||
# Assert shadow ticket was created
|
||||
assert_shadow_ticket(ctx, alice.address, log, expect_exists=True)
|
||||
|
||||
log("Export succeeded as expected (active-view quorum reached)")
|
||||
else:
|
||||
if engine_result == "tesSUCCESS":
|
||||
raise AssertionError(
|
||||
"Export should NOT have succeeded below active-view quorum"
|
||||
)
|
||||
if engine_result != "tecEXPORT_EXPIRED":
|
||||
raise AssertionError(
|
||||
"Expected tecEXPORT_EXPIRED below active-view quorum, "
|
||||
f"got {engine_result}"
|
||||
)
|
||||
log(f"Export failed as expected ({engine_result})")
|
||||
|
||||
# No shadow ticket should exist
|
||||
assert_shadow_ticket(ctx, alice.address, log, expect_exists=False)
|
||||
|
||||
# --- Verify subsequent payment works ---
|
||||
log("Submitting payment from alice to bob...")
|
||||
pay_result = await ctx.submit_and_wait(
|
||||
{
|
||||
"TransactionType": "Payment",
|
||||
"Destination": bob.address,
|
||||
"Amount": "1000000",
|
||||
"Fee": "12",
|
||||
},
|
||||
alice.wallet,
|
||||
timeout=30,
|
||||
)
|
||||
|
||||
pay_engine = pay_result.get("engine_result", "")
|
||||
log(f"Payment result: {pay_engine}")
|
||||
|
||||
if pay_engine != "tesSUCCESS":
|
||||
raise AssertionError(f"Payment failed: {pay_engine}")
|
||||
|
||||
log("Payment succeeded -- account not blocked")
|
||||
log("PASS")
|
||||
@@ -1,92 +0,0 @@
|
||||
""":descr: Export retries/expires without a ledger-anchored UNLReport view.
|
||||
|
||||
All validators may sign, but network-mode Export must not assemble quorum
|
||||
material from a node-local trusted-config view. Without UNLReport, the export
|
||||
should retry until LastLedgerSequence and expire without creating a shadow
|
||||
ticket.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from export_helpers import require_export, assert_shadow_ticket
|
||||
|
||||
|
||||
async def scenario(ctx, log):
|
||||
await require_export(ctx, log, require_unl_report=False)
|
||||
|
||||
await ctx.fund_accounts({"alice": 10000, "bob": 1000})
|
||||
log("Accounts funded")
|
||||
|
||||
alice = ctx.account("alice")
|
||||
bob = ctx.account("bob")
|
||||
current_seq = ctx.validated_ledger_index(0)
|
||||
|
||||
log(f"Current ledger: {current_seq}")
|
||||
log("UNLReport intentionally absent; export must not use local config view")
|
||||
|
||||
export_start = ctx.mark("export-without-unlreport-submit-start")
|
||||
result = await ctx.submit_and_wait(
|
||||
{
|
||||
"TransactionType": "Export",
|
||||
"LastLedgerSequence": current_seq + 8,
|
||||
"Fee": "1000000",
|
||||
"ExportedTxn": {
|
||||
"TransactionType": "Payment",
|
||||
"Account": alice.address,
|
||||
"Destination": bob.address,
|
||||
"Amount": "1000000",
|
||||
"Fee": "10",
|
||||
"Sequence": 0,
|
||||
"TicketSequence": 1,
|
||||
"FirstLedgerSequence": current_seq + 1,
|
||||
"LastLedgerSequence": current_seq + 6,
|
||||
"Flags": 2147483648,
|
||||
"SigningPubKey": "",
|
||||
},
|
||||
},
|
||||
alice.wallet,
|
||||
timeout=60,
|
||||
)
|
||||
export_end = ctx.mark("export-without-unlreport-submit-end")
|
||||
|
||||
final_seq = ctx.validated_ledger_index(0)
|
||||
engine_result = result.get("engine_result", "")
|
||||
log(f"Export completed at ledger {final_seq}, result: {engine_result}")
|
||||
|
||||
if engine_result == "tesSUCCESS":
|
||||
raise AssertionError(
|
||||
"Export should not succeed without a ledger-anchored UNLReport view"
|
||||
)
|
||||
|
||||
# Be exact: without a UNLReport view the export should retry until LLS and
|
||||
# expire, not fail by some unrelated terminal code.
|
||||
if engine_result != "tecEXPORT_EXPIRED":
|
||||
raise AssertionError(
|
||||
"Expected tecEXPORT_EXPIRED without UNLReport view, "
|
||||
f"got {engine_result}"
|
||||
)
|
||||
|
||||
warning_logs = ctx.assert_log(
|
||||
r"Export: retrying without ledger-anchored validator view",
|
||||
since=export_start,
|
||||
until=export_end,
|
||||
)
|
||||
log(f"Export no-UNLReport retry warnings: {warning_logs.count}")
|
||||
|
||||
retry_logs = ctx.assert_log(
|
||||
r"Export: insufficient signatures .*result=terRETRY_EXPORT",
|
||||
since=export_start,
|
||||
until=export_end,
|
||||
)
|
||||
log(f"Export retry logs: {retry_logs.count}")
|
||||
|
||||
expired_logs = ctx.assert_log(
|
||||
r"Export: last ledger expired .*result=tecEXPORT_EXPIRED",
|
||||
since=export_start,
|
||||
until=export_end,
|
||||
)
|
||||
log(f"Export expiry logs: {expired_logs.count}")
|
||||
|
||||
assert_shadow_ticket(ctx, alice.address, log, expect_exists=False)
|
||||
|
||||
log("PASS")
|
||||
@@ -1,94 +0,0 @@
|
||||
""":descr: Submit ttEXPORT directly (no hook), verify it succeeds with
|
||||
ExportResult in metadata. Then submit a payment from the same account
|
||||
to verify sequence handling doesn't block subsequent transactions.
|
||||
|
||||
Flow:
|
||||
1. Fund alice and bob
|
||||
2. alice submits ttEXPORT with inner payment -> tesSUCCESS (provisional)
|
||||
3. Validators attach sigs via proposals -> quorum -> ExportResult in metadata
|
||||
4. alice submits a Payment to bob -> should succeed (sequence not blocked)
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from export_helpers import require_export, assert_export_result, assert_shadow_ticket
|
||||
|
||||
|
||||
async def scenario(ctx, log):
|
||||
await require_export(ctx, log)
|
||||
|
||||
# --- Setup ---
|
||||
await ctx.fund_accounts({"alice": 10000, "bob": 1000})
|
||||
log("Accounts funded")
|
||||
|
||||
alice = ctx.account("alice")
|
||||
bob = ctx.account("bob")
|
||||
current_seq = ctx.validated_ledger_index(0)
|
||||
|
||||
log(f"Current ledger: {current_seq}")
|
||||
|
||||
# --- 1. Submit ttEXPORT ---
|
||||
result = await ctx.submit_and_wait(
|
||||
{
|
||||
"TransactionType": "Export",
|
||||
"LastLedgerSequence": current_seq + 15,
|
||||
"Fee": "1000000",
|
||||
"ExportedTxn": {
|
||||
"TransactionType": "Payment",
|
||||
"Account": alice.address,
|
||||
"Destination": bob.address,
|
||||
"Amount": "1000000",
|
||||
"Fee": "10",
|
||||
"Sequence": 0,
|
||||
"TicketSequence": 1,
|
||||
"FirstLedgerSequence": current_seq + 1,
|
||||
"LastLedgerSequence": current_seq + 10,
|
||||
"Flags": 2147483648,
|
||||
"SigningPubKey": "",
|
||||
},
|
||||
},
|
||||
alice.wallet,
|
||||
timeout=60,
|
||||
)
|
||||
|
||||
export_seq = ctx.validated_ledger_index(0)
|
||||
engine_result = result.get("engine_result", "")
|
||||
log(f"Export completed at ledger {export_seq}, result: {engine_result}")
|
||||
|
||||
if engine_result != "tesSUCCESS":
|
||||
raise AssertionError(
|
||||
f"Expected tesSUCCESS for export, got {engine_result}"
|
||||
)
|
||||
|
||||
# Assert ExportResult is well-formed with signers
|
||||
meta = result.get("meta", {})
|
||||
assert_export_result(meta, log, ctx=ctx, require_signers=True)
|
||||
|
||||
# Assert shadow ticket was created
|
||||
assert_shadow_ticket(ctx, alice.address, log, expect_exists=True)
|
||||
|
||||
# --- 2. Submit Payment from same account ---
|
||||
log("Submitting payment from alice to bob...")
|
||||
pay_result = await ctx.submit_and_wait(
|
||||
{
|
||||
"TransactionType": "Payment",
|
||||
"Destination": bob.address,
|
||||
"Amount": "1000000",
|
||||
"Fee": "12",
|
||||
},
|
||||
alice.wallet,
|
||||
timeout=30,
|
||||
)
|
||||
|
||||
pay_engine = pay_result.get("engine_result", "")
|
||||
log(f"Payment result: {pay_engine}")
|
||||
|
||||
if pay_engine != "tesSUCCESS":
|
||||
raise AssertionError(f"Payment failed: {pay_engine}")
|
||||
|
||||
log(
|
||||
f"Both transactions succeeded: "
|
||||
f"Export at ledger {export_seq}, Payment at ledger {ctx.validated_ledger_index(0)}"
|
||||
)
|
||||
log("Sequence handling OK - export didn't block subsequent txns")
|
||||
log("PASS")
|
||||
@@ -1,212 +0,0 @@
|
||||
""":descr: install xport hook, trigger export, verify emitted ttEXPORT lifecycle
|
||||
|
||||
1. Fund alice (hook holder), bob (trigger), carol (export destination)
|
||||
2. Install xport hook on alice
|
||||
3. bob pays alice with DST=carol → hook calls xport() → emits ttEXPORT
|
||||
4. Emitted ttEXPORT enters open ledger, validators attach sigs via proposals
|
||||
5. Verify Export transaction appears in a subsequent ledger
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from export_helpers import (
|
||||
require_export,
|
||||
find_export_txns,
|
||||
dst_param,
|
||||
assert_hook_accepted,
|
||||
assert_export_result,
|
||||
assert_shadow_ticket,
|
||||
)
|
||||
|
||||
# C source for the xport hook — verbatim from src/test/app/Export_test_hooks.h
|
||||
# On Payment to the hook account, exports a 1 XAH payment to the DST param.
|
||||
XPORT_HOOK_C = r"""
|
||||
#include <stdint.h>
|
||||
extern int32_t _g(uint32_t id, uint32_t maxiter);
|
||||
extern int64_t accept(uint32_t read_ptr, uint32_t read_len, int64_t error_code);
|
||||
extern int64_t rollback(uint32_t read_ptr, uint32_t read_len, int64_t error_code);
|
||||
extern int64_t xport(uint32_t write_ptr, uint32_t write_len, uint32_t read_ptr, uint32_t read_len);
|
||||
extern int64_t xport_reserve(uint32_t count);
|
||||
extern int64_t hook_account(uint32_t write_ptr, uint32_t write_len);
|
||||
extern int64_t otxn_param(uint32_t write_ptr, uint32_t write_len, uint32_t name_ptr, uint32_t name_len);
|
||||
extern int64_t otxn_type(void);
|
||||
extern int64_t ledger_seq(void);
|
||||
|
||||
#define SBUF(x) (uint32_t)(x), sizeof(x)
|
||||
#define ASSERT(x) if (!(x)) rollback((uint32_t)#x, sizeof(#x), __LINE__)
|
||||
|
||||
#define ttPAYMENT 0
|
||||
#define tfCANONICAL 0x80000000UL
|
||||
#define amAMOUNT 1
|
||||
#define amFEE 8
|
||||
#define atACCOUNT 1
|
||||
#define atDESTINATION 3
|
||||
|
||||
#define ENCODE_TT(buf_out, tt) \
|
||||
buf_out[0] = 0x12U; buf_out[1] = (tt >> 8) & 0xFFU; buf_out[2] = tt & 0xFFU; buf_out += 3;
|
||||
|
||||
#define ENCODE_FLAGS(buf_out, flags) \
|
||||
buf_out[0] = 0x22U; buf_out[1] = (flags >> 24) & 0xFFU; buf_out[2] = (flags >> 16) & 0xFFU; \
|
||||
buf_out[3] = (flags >> 8) & 0xFFU; buf_out[4] = flags & 0xFFU; buf_out += 5;
|
||||
|
||||
#define ENCODE_SEQUENCE(buf_out, seq) \
|
||||
buf_out[0] = 0x24U; buf_out[1] = (seq >> 24) & 0xFFU; buf_out[2] = (seq >> 16) & 0xFFU; \
|
||||
buf_out[3] = (seq >> 8) & 0xFFU; buf_out[4] = seq & 0xFFU; buf_out += 5;
|
||||
|
||||
#define ENCODE_FLS(buf_out, fls) \
|
||||
buf_out[0] = 0x20U; buf_out[1] = 0x1AU; buf_out[2] = (fls >> 24) & 0xFFU; \
|
||||
buf_out[3] = (fls >> 16) & 0xFFU; buf_out[4] = (fls >> 8) & 0xFFU; \
|
||||
buf_out[5] = fls & 0xFFU; buf_out += 6;
|
||||
|
||||
#define ENCODE_LLS(buf_out, lls) \
|
||||
buf_out[0] = 0x20U; buf_out[1] = 0x1BU; buf_out[2] = (lls >> 24) & 0xFFU; \
|
||||
buf_out[3] = (lls >> 16) & 0xFFU; buf_out[4] = (lls >> 8) & 0xFFU; \
|
||||
buf_out[5] = lls & 0xFFU; buf_out += 6;
|
||||
|
||||
#define ENCODE_DROPS(buf_out, drops, amt_type) \
|
||||
buf_out[0] = 0x60U + amt_type; buf_out[1] = 0x40U + ((drops >> 56) & 0x3FU); \
|
||||
buf_out[2] = (drops >> 48) & 0xFFU; buf_out[3] = (drops >> 40) & 0xFFU; \
|
||||
buf_out[4] = (drops >> 32) & 0xFFU; buf_out[5] = (drops >> 24) & 0xFFU; \
|
||||
buf_out[6] = (drops >> 16) & 0xFFU; buf_out[7] = (drops >> 8) & 0xFFU; \
|
||||
buf_out[8] = drops & 0xFFU; buf_out += 9;
|
||||
|
||||
#define ENCODE_SIGNING_PUBKEY_EMPTY(buf_out) \
|
||||
buf_out[0] = 0x73U; buf_out[1] = 0x00U; buf_out += 2;
|
||||
|
||||
#define ENCODE_ACCOUNT(buf_out, acc, acc_type) \
|
||||
buf_out[0] = 0x80U + acc_type; buf_out[1] = 0x14U; \
|
||||
for (int i = 0; i < 20; ++i) buf_out[2+i] = acc[i]; buf_out += 22;
|
||||
|
||||
#define PREPARE_PAYMENT_SIMPLE_SIZE 270U
|
||||
|
||||
int64_t hook(uint32_t reserved) {
|
||||
_g(1, 1);
|
||||
|
||||
if (otxn_type() != ttPAYMENT)
|
||||
return accept(0, 0, 0);
|
||||
|
||||
ASSERT(xport_reserve(1) == 1);
|
||||
|
||||
uint8_t dst[20];
|
||||
int64_t dst_len = otxn_param(SBUF(dst), "DST", 3);
|
||||
ASSERT(dst_len == 20);
|
||||
|
||||
uint8_t acc[20];
|
||||
ASSERT(hook_account(SBUF(acc)) == 20);
|
||||
|
||||
uint32_t cls = (uint32_t)ledger_seq();
|
||||
|
||||
uint8_t tx[PREPARE_PAYMENT_SIMPLE_SIZE];
|
||||
uint8_t* buf = tx;
|
||||
|
||||
ENCODE_TT(buf, ttPAYMENT);
|
||||
ENCODE_FLAGS(buf, tfCANONICAL);
|
||||
ENCODE_SEQUENCE(buf, 0);
|
||||
ENCODE_FLS(buf, cls + 1);
|
||||
ENCODE_LLS(buf, cls + 5);
|
||||
// sfTicketSequence = UINT32 field 41 = 0x20 0x29
|
||||
buf[0] = 0x20U; buf[1] = 0x29U;
|
||||
buf[2] = 0; buf[3] = 0; buf[4] = 0; buf[5] = 1;
|
||||
buf += 6;
|
||||
|
||||
uint64_t drops = 1000000;
|
||||
ENCODE_DROPS(buf, drops, amAMOUNT);
|
||||
ENCODE_DROPS(buf, 10, amFEE);
|
||||
|
||||
ENCODE_SIGNING_PUBKEY_EMPTY(buf);
|
||||
ENCODE_ACCOUNT(buf, acc, atACCOUNT);
|
||||
ENCODE_ACCOUNT(buf, dst, atDESTINATION);
|
||||
|
||||
uint8_t hash[32];
|
||||
int64_t xport_result = xport(SBUF(hash), (uint32_t)tx, buf - tx);
|
||||
ASSERT(xport_result == 32);
|
||||
|
||||
return accept(0, 0, 0);
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
async def scenario(ctx, log):
|
||||
# Wait for network to start and amendments to activate
|
||||
await require_export(ctx, log)
|
||||
|
||||
# --- Setup ---
|
||||
await ctx.fund_accounts({"alice": 10000, "bob": 10000, "carol": 1000})
|
||||
log("Accounts funded")
|
||||
|
||||
alice = ctx.account("alice")
|
||||
carol = ctx.account("carol")
|
||||
|
||||
# Compile and install xport hook on alice
|
||||
wasm = ctx.compile_hook(XPORT_HOOK_C, label="xport")
|
||||
await ctx.submit_and_wait(
|
||||
{
|
||||
"TransactionType": "SetHook",
|
||||
"Hooks": [
|
||||
{
|
||||
"Hook": {
|
||||
"CreateCode": wasm.hex().upper(),
|
||||
"HookOn": "0" * 64,
|
||||
"HookNamespace": "0" * 64,
|
||||
"HookApiVersion": 0,
|
||||
"Flags": 1, # hsfOVERRIDE
|
||||
}
|
||||
}
|
||||
],
|
||||
"Fee": "100000000",
|
||||
},
|
||||
alice.wallet,
|
||||
)
|
||||
log(
|
||||
f"Hook installed on alice ({alice.address[:12]}...) "
|
||||
f"ledger {ctx.validated_ledger_index(0)}"
|
||||
)
|
||||
|
||||
# --- Trigger ---
|
||||
# bob pays alice → hook calls xport() → emits ttEXPORT
|
||||
trigger_result = await ctx.submit_and_wait(
|
||||
{
|
||||
"TransactionType": "Payment",
|
||||
"Destination": alice.address,
|
||||
"Amount": "100000000",
|
||||
"Fee": "1000000",
|
||||
"HookParameters": [dst_param(carol.address)],
|
||||
},
|
||||
ctx.account("bob").wallet,
|
||||
)
|
||||
trigger_seq = ctx.validated_ledger_index(0)
|
||||
log(f"Export triggered at ledger {trigger_seq}")
|
||||
|
||||
# xport() schedules a ttEXPORT through the emitted directory, but hook
|
||||
# metadata reports it separately from ordinary HookEmissions.
|
||||
trigger_meta = trigger_result.get("meta", {})
|
||||
assert_hook_accepted(trigger_meta, log, expected_emits=0, expected_exports=1)
|
||||
|
||||
# --- Verify: check each ledger close for the Export transaction ---
|
||||
max_ledgers = 10
|
||||
for i in range(max_ledgers):
|
||||
await ctx.wait_for_ledgers(1, node_id=0, timeout=30)
|
||||
seq = ctx.validated_ledger_index(0)
|
||||
exports = find_export_txns(ctx, seq)
|
||||
if exports:
|
||||
export_tx = exports[0]
|
||||
meta = export_tx.get("meta", export_tx.get("metaData", {}))
|
||||
result = meta.get("TransactionResult", "")
|
||||
log(f"Ledger {seq}: Export txn found, result={result}")
|
||||
|
||||
if result != "tesSUCCESS":
|
||||
raise AssertionError(f"Export did not succeed: {result}")
|
||||
|
||||
# Assert ExportResult is well-formed with signers and inner tx
|
||||
assert_export_result(meta, log, ctx=ctx, require_signers=True)
|
||||
|
||||
# Assert shadow ticket was created
|
||||
assert_shadow_ticket(ctx, alice.address, log, expect_exists=True)
|
||||
|
||||
log("PASS")
|
||||
return
|
||||
log(f"Ledger {seq}: no Export txn yet")
|
||||
|
||||
raise AssertionError(
|
||||
f"No Export transaction found after {max_ledgers} ledger closes"
|
||||
)
|
||||
@@ -1,180 +0,0 @@
|
||||
"""Shared helpers for ConsensusEntropy scenario tests."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from xahaud_scripts.testnet.config import feature_name_to_hash
|
||||
|
||||
ZERO_DIGEST = "0" * 64
|
||||
CONSENSUS_ENTROPY_FEATURE = feature_name_to_hash("ConsensusEntropy")
|
||||
|
||||
|
||||
def feature_hash(name: str) -> str:
|
||||
"""Return the amendment hash accepted by feature RPC."""
|
||||
return feature_name_to_hash(name)
|
||||
|
||||
|
||||
def feature_status(ctx, name: str, node_id=0):
|
||||
"""Query a feature by amendment hash; feature RPC names are ambiguous."""
|
||||
return ctx.feature_check(feature_hash(name), node_id=node_id)
|
||||
|
||||
|
||||
def consensus_entropy_feature(ctx, node_id=0):
|
||||
"""Query ConsensusEntropy by amendment hash."""
|
||||
return feature_status(ctx, "ConsensusEntropy", node_id=node_id)
|
||||
|
||||
|
||||
async def require_entropy(ctx, log):
|
||||
"""Wait for first ledger and assert ConsensusEntropy is enabled."""
|
||||
await ctx.wait_for_ledger_close(timeout=120)
|
||||
feature = consensus_entropy_feature(ctx, node_id=0)
|
||||
if not feature or not feature.get("enabled", False):
|
||||
raise AssertionError(f"ConsensusEntropy not enabled: {feature}")
|
||||
log("ConsensusEntropy enabled")
|
||||
|
||||
|
||||
def get_entropy_tx(ctx, seq):
|
||||
"""Fetch ledger and return (ce_tx, user_txns) or raise."""
|
||||
result = ctx.ledger(seq, transactions=True)
|
||||
if not result:
|
||||
raise AssertionError(f"Ledger {seq}: fetch failed")
|
||||
|
||||
ledger = result.get("ledger")
|
||||
if not isinstance(ledger, dict):
|
||||
raise AssertionError(f"Ledger {seq}: fetch returned no ledger: {result}")
|
||||
|
||||
txns = ledger.get("transactions", [])
|
||||
ce = [tx for tx in txns if tx.get("TransactionType") == "ConsensusEntropy"]
|
||||
user = [tx for tx in txns if tx.get("TransactionType") != "ConsensusEntropy"]
|
||||
|
||||
if len(ce) != 1:
|
||||
raise AssertionError(
|
||||
f"Ledger {seq}: expected 1 ConsensusEntropy txn, got {len(ce)}"
|
||||
)
|
||||
|
||||
return ce[0], user
|
||||
|
||||
|
||||
def entropy_fields(ce_tx):
|
||||
"""Return (digest, entropy_count, is_fallback) from a ConsensusEntropy tx.
|
||||
|
||||
consensus_fallback rounds carry a deterministic non-zero consensus-bound
|
||||
digest with EntropyCount=0 and EntropyTier=1 (consensus_fallback).
|
||||
Validator entropy has EntropyTier=3 (validator_quorum).
|
||||
|
||||
WARNING: is_fallback is ``tier != 3``, so it lumps participant_aligned
|
||||
(Tier 2) in with fallback. It is only safe where no Tier 2 band exists
|
||||
(e.g. 5-node networks, where tier2 == quorum). For band-aware scenarios use
|
||||
the explicit assert_consensus_fallback / assert_participant_aligned /
|
||||
assert_validator_quorum helpers, which check EntropyTier directly.
|
||||
"""
|
||||
digest = ce_tx.get("Digest", "")
|
||||
entropy_count = ce_tx.get("EntropyCount", -1)
|
||||
tier = ce_tx.get("EntropyTier", None)
|
||||
if tier is not None:
|
||||
is_fallback = tier != 3
|
||||
else:
|
||||
is_fallback = entropy_count == 0
|
||||
return digest, entropy_count, is_fallback
|
||||
|
||||
|
||||
def assert_participant_aligned(ce_tx, seq, expected_count=None):
|
||||
"""Assert participant_aligned (Tier 2) entropy on a ConsensusEntropy tx.
|
||||
|
||||
Tier 2 is the sub-quorum band: the agreed reveal cohort is >= the
|
||||
participant floor but < the 80% validator quorum, so it carries
|
||||
EntropyTier=2 with a deterministic non-zero digest. NOTE entropy_fields()'s
|
||||
is_fallback lumps tier 2 in with fallback (is_fallback = tier != 3), so the
|
||||
tier must be checked EXPLICITLY here.
|
||||
"""
|
||||
digest = ce_tx.get("Digest", "")
|
||||
count = ce_tx.get("EntropyCount", -1)
|
||||
tier = ce_tx.get("EntropyTier", None)
|
||||
if tier != 2:
|
||||
raise AssertionError(
|
||||
f"Ledger {seq}: expected EntropyTier==2 (participant_aligned), "
|
||||
f"got {tier} (EntropyCount={count})"
|
||||
)
|
||||
if not digest or digest == ZERO_DIGEST:
|
||||
raise AssertionError(
|
||||
f"Ledger {seq}: participant_aligned digest must be non-zero, got "
|
||||
f"{digest[:16]}..."
|
||||
)
|
||||
if expected_count is not None and count != expected_count:
|
||||
raise AssertionError(
|
||||
f"Ledger {seq}: participant_aligned EntropyCount must be "
|
||||
f"{expected_count} (the surviving cohort), got {count}"
|
||||
)
|
||||
return digest, count
|
||||
|
||||
|
||||
def assert_validator_quorum(ce_tx, seq, min_count=None):
|
||||
"""Assert validator_quorum (Tier 3) entropy on a ConsensusEntropy tx:
|
||||
EntropyTier=3, a deterministic non-zero digest, and (optionally)
|
||||
EntropyCount >= min_count (the active quorum). The count can EXCEED the
|
||||
quorum (e.g. a still-full 6/6 ledger caught at a 6->5 transition), so check
|
||||
>=, not ==.
|
||||
"""
|
||||
digest = ce_tx.get("Digest", "")
|
||||
count = ce_tx.get("EntropyCount", -1)
|
||||
tier = ce_tx.get("EntropyTier", None)
|
||||
if tier != 3:
|
||||
raise AssertionError(
|
||||
f"Ledger {seq}: expected EntropyTier==3 (validator_quorum), got "
|
||||
f"{tier} (EntropyCount={count})"
|
||||
)
|
||||
if not digest or digest == ZERO_DIGEST:
|
||||
raise AssertionError(
|
||||
f"Ledger {seq}: validator_quorum digest must be non-zero, got "
|
||||
f"{digest[:16]}..."
|
||||
)
|
||||
if min_count is not None and count < min_count:
|
||||
raise AssertionError(
|
||||
f"Ledger {seq}: validator_quorum EntropyCount={count} < quorum "
|
||||
f"{min_count}"
|
||||
)
|
||||
return digest, count
|
||||
|
||||
|
||||
def assert_consensus_fallback(ce_tx, seq):
|
||||
"""Assert consensus_fallback (Tier 1) entropy on a ConsensusEntropy tx:
|
||||
EntropyTier=1, EntropyCount=0, and a deterministic NON-zero digest.
|
||||
"""
|
||||
digest = ce_tx.get("Digest", "")
|
||||
count = ce_tx.get("EntropyCount", -1)
|
||||
tier = ce_tx.get("EntropyTier", None)
|
||||
if tier != 1:
|
||||
raise AssertionError(
|
||||
f"Ledger {seq}: expected EntropyTier==1 (consensus_fallback), got "
|
||||
f"{tier} (EntropyCount={count})"
|
||||
)
|
||||
if count != 0:
|
||||
raise AssertionError(
|
||||
f"Ledger {seq}: consensus_fallback EntropyCount must be 0, got "
|
||||
f"{count}"
|
||||
)
|
||||
if not digest or digest == ZERO_DIGEST:
|
||||
raise AssertionError(
|
||||
f"Ledger {seq}: consensus_fallback digest must be non-zero, got "
|
||||
f"{digest[:16]}..."
|
||||
)
|
||||
return digest, count
|
||||
|
||||
|
||||
def assert_valid_entropy(ce_tx, seq, seen_digests=None):
|
||||
"""Assert quorum-met validator entropy. Optionally check uniqueness."""
|
||||
digest, entropy_count, is_fallback = entropy_fields(ce_tx)
|
||||
|
||||
if is_fallback or not digest or digest == ZERO_DIGEST:
|
||||
raise AssertionError(f"Ledger {seq}: fallback/empty Digest")
|
||||
|
||||
if entropy_count < 4:
|
||||
raise AssertionError(
|
||||
f"Ledger {seq}: EntropyCount={entropy_count} < 4 (sub-quorum)"
|
||||
)
|
||||
|
||||
if seen_digests is not None:
|
||||
if digest in seen_digests:
|
||||
raise AssertionError(f"Ledger {seq}: duplicate Digest {digest[:16]}...")
|
||||
seen_digests.add(digest)
|
||||
|
||||
return digest, entropy_count
|
||||
@@ -1,92 +0,0 @@
|
||||
defaults:
|
||||
network:
|
||||
node_count: 5
|
||||
launcher: tmux
|
||||
find_ports: true
|
||||
slave_delay: 0.2
|
||||
features:
|
||||
- ConsensusEntropy
|
||||
- Export
|
||||
track_features:
|
||||
- ConsensusEntropy
|
||||
- Export
|
||||
unl_report: true
|
||||
log_levels:
|
||||
TxQ: info
|
||||
Protocol: debug
|
||||
Peer: debug
|
||||
LedgerConsensus: debug
|
||||
ConsensusExtensions: debug
|
||||
NetworkOPs: info
|
||||
env:
|
||||
XAHAU_RESOURCE_PER_PORT: "1"
|
||||
rc:
|
||||
- rng_poll_ms=250
|
||||
tests:
|
||||
- name: latency_baseline_ce
|
||||
script: .testnet/scenarios/perf/ce_export_latency_probe.py
|
||||
params:
|
||||
warmup_ledgers: 3
|
||||
ledgers: 8
|
||||
submit_export: false
|
||||
|
||||
- name: latency_baseline_export
|
||||
script: .testnet/scenarios/perf/ce_export_latency_probe.py
|
||||
params:
|
||||
warmup_ledgers: 3
|
||||
ledgers: 8
|
||||
submit_export: true
|
||||
|
||||
- name: latency_proposal_delay_export
|
||||
script: .testnet/scenarios/perf/ce_export_latency_probe.py
|
||||
params:
|
||||
warmup_ledgers: 3
|
||||
ledgers: 8
|
||||
submit_export: true
|
||||
network:
|
||||
rc:
|
||||
- rng_poll_ms=250
|
||||
- delay=100,jitter=25,msg=proposal
|
||||
|
||||
- name: latency_directed_pair_delay_export
|
||||
script: .testnet/scenarios/perf/ce_export_latency_probe.py
|
||||
params:
|
||||
warmup_ledgers: 3
|
||||
ledgers: 8
|
||||
submit_export: true
|
||||
network:
|
||||
rc:
|
||||
- rng_poll_ms=250
|
||||
- n0->n2:delay=750,jitter=100,msg=proposal
|
||||
- n2->n0:delay=750,jitter=100,msg=proposal
|
||||
|
||||
- name: latency_slow_minority_export
|
||||
script: .testnet/scenarios/perf/ce_export_latency_probe.py
|
||||
params:
|
||||
warmup_ledgers: 3
|
||||
ledgers: 8
|
||||
submit_export: true
|
||||
export_timeout: 120
|
||||
network:
|
||||
rc:
|
||||
- rng_poll_ms=250
|
||||
- n3->n0:delay=500,jitter=100,msg=proposal
|
||||
- n3->n1:delay=500,jitter=100,msg=proposal
|
||||
- n3->n2:delay=500,jitter=100,msg=proposal
|
||||
- n4->n0:delay=500,jitter=100,msg=proposal
|
||||
- n4->n1:delay=500,jitter=100,msg=proposal
|
||||
- n4->n2:delay=500,jitter=100,msg=proposal
|
||||
- n0->n3:delay=500,jitter=100,msg=proposal
|
||||
- n1->n3:delay=500,jitter=100,msg=proposal
|
||||
- n2->n3:delay=500,jitter=100,msg=proposal
|
||||
- n0->n4:delay=500,jitter=100,msg=proposal
|
||||
- n1->n4:delay=500,jitter=100,msg=proposal
|
||||
- n2->n4:delay=500,jitter=100,msg=proposal
|
||||
|
||||
- name: latency_export_no_veto_with_delay
|
||||
script: .testnet/scenarios/export/export_no_veto_missing_observation.py
|
||||
network:
|
||||
rc:
|
||||
- rng_poll_ms=250
|
||||
- delay=300,jitter=100,msg=proposal
|
||||
- n4:no_export_sig_hash=true
|
||||
@@ -1,196 +0,0 @@
|
||||
""":descr: measure CE/export behavior while RuntimeConfig injects latency/drop.
|
||||
|
||||
The suite supplies runtime fault injection through network.rc. This scenario
|
||||
does not mutate RuntimeConfig itself; it observes what the launched network does
|
||||
under that condition and logs enough counters to compare variants.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from collections import Counter
|
||||
import json
|
||||
|
||||
from export.export_helpers import assert_export_result, require_export
|
||||
from helpers import consensus_entropy_feature, get_entropy_tx
|
||||
|
||||
|
||||
async def _require_runtime_config(ctx, log):
|
||||
result = ctx.rpc.runtime_config(0)
|
||||
if not result or result.get("error"):
|
||||
raise AssertionError(
|
||||
"Latency probe requires a binary built with "
|
||||
"xahaud_runtime_test_config=ON; runtime_config RPC returned "
|
||||
f"{result}"
|
||||
)
|
||||
log("RuntimeConfig RPC active")
|
||||
|
||||
|
||||
async def _require_consensus_entropy(ctx, log):
|
||||
feature = consensus_entropy_feature(ctx, node_id=0)
|
||||
if not feature or not feature.get("enabled", False):
|
||||
raise AssertionError(f"ConsensusEntropy not enabled: {feature}")
|
||||
log("ConsensusEntropy enabled")
|
||||
|
||||
|
||||
def _log_runtime_config(ctx, log):
|
||||
for node_id in range(ctx.node_count):
|
||||
cfg = ctx.rpc.runtime_config(node_id)
|
||||
if cfg is None:
|
||||
raise AssertionError(f"runtime_config RPC failed on node {node_id}")
|
||||
log(
|
||||
f"runtime_config n{node_id}: "
|
||||
f"{json.dumps(cfg, sort_keys=True, separators=(',', ':'))}"
|
||||
)
|
||||
|
||||
|
||||
async def _submit_direct_export(ctx, log, *, timeout):
|
||||
await ctx.fund_accounts({"alice": 10000, "bob": 1000})
|
||||
alice = ctx.account("alice")
|
||||
bob = ctx.account("bob")
|
||||
current_seq = ctx.validated_ledger_index(0)
|
||||
|
||||
if current_seq is None:
|
||||
raise AssertionError("validated ledger is not available before Export")
|
||||
|
||||
log(f"Submitting direct Export at validated ledger {current_seq}")
|
||||
started = ctx.mark("latency-export-submit-start")
|
||||
result = await ctx.submit_and_wait(
|
||||
{
|
||||
"TransactionType": "Export",
|
||||
"LastLedgerSequence": current_seq + 12,
|
||||
"Fee": "1000000",
|
||||
"ExportedTxn": {
|
||||
"TransactionType": "Payment",
|
||||
"Account": alice.address,
|
||||
"Destination": bob.address,
|
||||
"Amount": "1000000",
|
||||
"Fee": "10",
|
||||
"Sequence": 0,
|
||||
"TicketSequence": 1,
|
||||
"FirstLedgerSequence": current_seq + 1,
|
||||
"LastLedgerSequence": current_seq + 10,
|
||||
"Flags": 2147483648,
|
||||
"SigningPubKey": "",
|
||||
},
|
||||
},
|
||||
alice.wallet,
|
||||
timeout=timeout,
|
||||
)
|
||||
ended = ctx.mark("latency-export-submit-end")
|
||||
|
||||
elapsed = (ended.monotonic_ns - started.monotonic_ns) / 1_000_000_000
|
||||
engine_result = result.get("engine_result", "")
|
||||
log(f"Export result={engine_result} elapsed={elapsed:.3f}s")
|
||||
|
||||
if engine_result != "tesSUCCESS":
|
||||
raise AssertionError(f"Expected Export tesSUCCESS, got {engine_result}")
|
||||
|
||||
export_result = assert_export_result(result.get("meta", {}), log)
|
||||
signers = export_result.get("ExportedTxn", {}).get("Signers", [])
|
||||
log(f"Export signer count={len(signers)}")
|
||||
return started, ended
|
||||
|
||||
|
||||
def _summarize_logs(ctx, log, *, label, started, ended):
|
||||
patterns = {
|
||||
"rng_selected": r"RNG: entropy selected",
|
||||
"rng_fallback": r"tier=1",
|
||||
"rng_participant_aligned": r"tier=2",
|
||||
"rng_validator_quorum": r"tier=3",
|
||||
"export_retry": r"terRETRY_EXPORT",
|
||||
"export_quorum_timeout": r"Export: exportSigSet quorum alignment timeout",
|
||||
"export_missing_observation_ignored": (
|
||||
r"Export: missing exportSigSetHash observation ignored"
|
||||
),
|
||||
}
|
||||
for name, pattern in patterns.items():
|
||||
result = ctx.search_logs(pattern, since=started, until=ended, limit=500)
|
||||
log(f"log_count {label}.{name}={result.count}")
|
||||
|
||||
|
||||
async def scenario(
|
||||
ctx,
|
||||
log,
|
||||
*,
|
||||
warmup_ledgers=3,
|
||||
ledgers=8,
|
||||
submit_export=False,
|
||||
export_timeout=90,
|
||||
):
|
||||
await ctx.wait_for_ledger_close(timeout=120)
|
||||
await _require_runtime_config(ctx, log)
|
||||
_log_runtime_config(ctx, log)
|
||||
await _require_consensus_entropy(ctx, log)
|
||||
|
||||
if submit_export:
|
||||
# require_export also asserts the UNLReport precondition for successful
|
||||
# network-mode Export. Keep that explicit in perf runs so a missing
|
||||
# report does not masquerade as a latency failure.
|
||||
await require_export(ctx, log, require_runtime_config=False)
|
||||
|
||||
await ctx.wait_for_ledgers(warmup_ledgers, node_id=0, timeout=120)
|
||||
warm_seq = ctx.validated_ledger_index(0)
|
||||
log(f"Warmup complete at validated ledger {warm_seq}")
|
||||
|
||||
export_window = None
|
||||
if submit_export:
|
||||
export_window = await _submit_direct_export(
|
||||
ctx, log, timeout=export_timeout
|
||||
)
|
||||
|
||||
started = ctx.mark("latency-probe-start")
|
||||
start_seq = ctx.validated_ledger_index(0)
|
||||
await ctx.wait_for_ledgers(ledgers, node_id=0, timeout=max(120, ledgers * 30))
|
||||
ended = ctx.mark("latency-probe-end")
|
||||
end_seq = ctx.validated_ledger_index(0)
|
||||
|
||||
if start_seq is None or end_seq is None:
|
||||
raise AssertionError("validated ledger index unavailable during probe")
|
||||
|
||||
elapsed = (ended.monotonic_ns - started.monotonic_ns) / 1_000_000_000
|
||||
closed = max(0, end_seq - start_seq)
|
||||
cadence = elapsed / closed if closed else 0.0
|
||||
log(
|
||||
f"Observed validated ledgers {start_seq + 1}..{end_seq} "
|
||||
f"closed={closed} elapsed={elapsed:.3f}s cadence={cadence:.3f}s/ledger"
|
||||
)
|
||||
|
||||
tiers: Counter[int] = Counter()
|
||||
counts: Counter[int] = Counter()
|
||||
missing_entropy = 0
|
||||
for seq in range(start_seq + 1, end_seq + 1):
|
||||
try:
|
||||
ce, user_txns = get_entropy_tx(ctx, seq)
|
||||
except AssertionError as exc:
|
||||
missing_entropy += 1
|
||||
log(f" Ledger {seq}: no ConsensusEntropy tx ({exc})")
|
||||
continue
|
||||
|
||||
tier = ce.get("EntropyTier", -1)
|
||||
count = ce.get("EntropyCount", -1)
|
||||
tiers[tier] += 1
|
||||
counts[count] += 1
|
||||
log(
|
||||
f" Ledger {seq}: tier={tier} count={count} "
|
||||
f"user_txns={len(user_txns)} digest={ce.get('Digest', '')[:16]}..."
|
||||
)
|
||||
|
||||
log(
|
||||
"SUMMARY "
|
||||
f"closed={closed} elapsed_s={elapsed:.3f} cadence_s={cadence:.3f} "
|
||||
f"tiers={dict(sorted(tiers.items()))} "
|
||||
f"counts={dict(sorted(counts.items()))} "
|
||||
f"missing_entropy={missing_entropy}"
|
||||
)
|
||||
|
||||
_summarize_logs(ctx, log, label="probe", started=started, ended=ended)
|
||||
if export_window is not None:
|
||||
_summarize_logs(
|
||||
ctx,
|
||||
log,
|
||||
label="export",
|
||||
started=export_window[0],
|
||||
ended=export_window[1],
|
||||
)
|
||||
|
||||
log("PASS")
|
||||
@@ -1,48 +0,0 @@
|
||||
# Opt-in suite for the sidecar SHAMap reconciliation path.
|
||||
#
|
||||
# These scenarios assert fetch/acquire/merge behavior and require a binary built
|
||||
# with:
|
||||
#
|
||||
# -Dxahaud_sidecar_reconciliation=ON
|
||||
#
|
||||
# The normal feature suites default to proposal-carried CE/export material and
|
||||
# do not run these tests while reconciliation is disabled by default.
|
||||
|
||||
defaults:
|
||||
network:
|
||||
node_count: 5
|
||||
launcher: tmux
|
||||
find_ports: true
|
||||
slave_delay: 0.2
|
||||
features:
|
||||
- ConsensusEntropy
|
||||
- Export
|
||||
track_features:
|
||||
- ConsensusEntropy
|
||||
- Export
|
||||
unl_report: true
|
||||
log_levels:
|
||||
TxQ: info
|
||||
Protocol: debug
|
||||
Peer: debug
|
||||
LedgerConsensus: debug
|
||||
ConsensusExtensions: debug
|
||||
NetworkOPs: info
|
||||
env:
|
||||
XAHAU_RESOURCE_PER_PORT: "1"
|
||||
rc:
|
||||
- rng_poll_ms=333
|
||||
|
||||
tests:
|
||||
- name: entropy_fetch_recovers_dropped_claims
|
||||
script: .testnet/scenarios/entropy/fetch_recovers_dropped_claims.py
|
||||
network:
|
||||
rc:
|
||||
- rng_poll_ms=333
|
||||
- n0:rngrevealdrop=100
|
||||
|
||||
- name: export_sidecar_fetch_under_proposal_drop_ce
|
||||
script: .testnet/scenarios/export/export_fetch_under_proposal_drop.py
|
||||
network:
|
||||
rc:
|
||||
- rng_poll_ms=333
|
||||
@@ -1,62 +0,0 @@
|
||||
defaults:
|
||||
network:
|
||||
node_count: 5
|
||||
launcher: tmux
|
||||
find_ports: true
|
||||
slave_delay: 0.2
|
||||
features:
|
||||
- ConsensusEntropy
|
||||
track_features:
|
||||
- ConsensusEntropy
|
||||
unl_report: true
|
||||
log_levels:
|
||||
TxQ: info
|
||||
Protocol: debug
|
||||
Peer: debug
|
||||
LedgerConsensus: debug
|
||||
ConsensusExtensions: debug
|
||||
NetworkOPs: info
|
||||
env:
|
||||
XAHAU_RESOURCE_PER_PORT: "1"
|
||||
rc:
|
||||
- rng_poll_ms=333
|
||||
|
||||
tests:
|
||||
- name: steady_state_entropy
|
||||
script: .testnet/scenarios/entropy/steady_state_entropy.py
|
||||
|
||||
- name: fallback_without_unl_report
|
||||
script: .testnet/scenarios/entropy/fallback_without_unl_report.py
|
||||
network:
|
||||
unl_report: false
|
||||
|
||||
- name: steady_state_entropy_fast_start
|
||||
script: .testnet/scenarios/entropy/steady_state_entropy.py
|
||||
network:
|
||||
env:
|
||||
XAHAUD_RUNTIME_TEST_CONFIG: '{"set":{"global":{"rng_poll_ms":333,"bootstrap_fast_start":true}}}'
|
||||
|
||||
- name: entropy_with_transactions
|
||||
script: .testnet/scenarios/entropy/entropy_with_transactions.py
|
||||
|
||||
- name: quorum_recovery_smoke
|
||||
script: .testnet/scenarios/entropy/quorum_recovery_smoke.py
|
||||
|
||||
- name: quorum_degradation_smoke
|
||||
script: .testnet/scenarios/entropy/quorum_degradation_smoke.py
|
||||
network:
|
||||
log_levels:
|
||||
LedgerConsensus: trace
|
||||
ConsensusExtensions: trace
|
||||
|
||||
# Tier 2 (participant_aligned) needs 6 nodes: n=5 has no band (tier2 ==
|
||||
# quorum). At 6, the 4/6 window is the participant_aligned band.
|
||||
- name: participant_aligned_smoke
|
||||
script: .testnet/scenarios/entropy/participant_aligned_smoke.py
|
||||
network:
|
||||
node_count: 6
|
||||
log_levels:
|
||||
LedgerConsensus: trace
|
||||
ConsensusExtensions: trace
|
||||
|
||||
# Export scenarios: see export-suite.yml
|
||||
75
BUILD.md
75
BUILD.md
@@ -10,7 +10,7 @@
|
||||
## Branches
|
||||
|
||||
For a stable release, choose the `master` branch or one of the [tagged
|
||||
releases](https://github.com/Xahau/xahaud/releases).
|
||||
releases](https://github.com/ripple/rippled/releases).
|
||||
|
||||
```
|
||||
git checkout master
|
||||
@@ -39,7 +39,13 @@ Building rippled generally requires git, Python, Conan, CMake, and a C++ compile
|
||||
- [Conan 2.x](https://conan.io/downloads)
|
||||
- [CMake 3.16](https://cmake.org/download/)
|
||||
|
||||
`xahaud` is written in the C++20 dialect and includes the `<concepts>` header.
|
||||
[^1]: It is possible to build with Conan 2.x,
|
||||
but the instructions are significantly different,
|
||||
which is why we are not recommending it yet.
|
||||
Notably, the `conan profile update` command is removed in 2.x.
|
||||
Profiles must be edited by hand.
|
||||
|
||||
`rippled` is written in the C++20 dialect and includes the `<concepts>` header.
|
||||
The [minimum compiler versions][2] required are:
|
||||
|
||||
| Compiler | Version |
|
||||
@@ -58,19 +64,17 @@ Here are [sample instructions for setting up a C++ development environment on Li
|
||||
|
||||
### Mac
|
||||
|
||||
Many xahaud engineers use macOS for development.
|
||||
Many rippled engineers use macOS for development.
|
||||
|
||||
Here are [sample instructions for setting up a C++ development environment on macOS](./docs/build/environment.md#macos).
|
||||
|
||||
### Windows
|
||||
|
||||
We don't recommend Windows for `xahaud` production at this time. As of
|
||||
November 2025, Ubuntu has the highest level of quality assurance, testing,
|
||||
and support.
|
||||
Windows is not recommended for production use at this time.
|
||||
|
||||
Windows developers should use Visual Studio 2019. `xahaud` isn't
|
||||
compatible with [Boost](https://www.boost.org/) 1.78 or 1.79, and Conan
|
||||
can't build earlier Boost versions.
|
||||
- Additionally, 32-bit Windows development is not supported.
|
||||
|
||||
[Boost]: https://www.boost.org/
|
||||
|
||||
## Steps
|
||||
|
||||
@@ -140,8 +144,8 @@ conan profile show default
|
||||
An easy way to do that is to run the shortcut "x64 Native Tools Command
|
||||
Prompt" for the version of Visual Studio that you have installed.
|
||||
|
||||
Windows developers must also build `xahaud` and its dependencies for the x64
|
||||
architecture.
|
||||
Windows developers must also build `rippled` and its dependencies for the x64
|
||||
architecture:
|
||||
|
||||
```
|
||||
# In ~/.conan2/profiles/default, ensure:
|
||||
@@ -149,7 +153,10 @@ Prompt" for the version of Visual Studio that you have installed.
|
||||
arch=x86_64
|
||||
```
|
||||
|
||||
### Multiple compilers
|
||||
3. (Optional) If you have multiple compilers installed on your platform,
|
||||
make sure that Conan and CMake select the one you want to use.
|
||||
This setting will set the correct variables (`CMAKE_<LANG>_COMPILER`)
|
||||
in the generated CMake toolchain file.
|
||||
|
||||
```
|
||||
# In ~/.conan2/profiles/default, add under [conf] section:
|
||||
@@ -166,17 +173,9 @@ Prompt" for the version of Visual Studio that you have installed.
|
||||
CXX=<path>
|
||||
```
|
||||
|
||||
It should choose the compiler for dependencies as well,
|
||||
but not all of them have a Conan recipe that respects this setting (yet).
|
||||
For the rest, you can set these environment variables.
|
||||
Replace `<path>` with paths to the desired compilers:
|
||||
|
||||
- `conan profile update env.CC=<path> default`
|
||||
- `conan profile update env.CXX=<path> default`
|
||||
|
||||
Export our [Conan recipe for Snappy](./external/snappy).
|
||||
It does not explicitly link the C++ standard library,
|
||||
which allows you to statically link it with GCC, if you want.
|
||||
4. Export our [Conan recipe for Snappy](./external/snappy).
|
||||
It doesn't explicitly link the C++ standard library,
|
||||
which allows you to statically link it with GCC, if you want.
|
||||
|
||||
```
|
||||
conan export external/snappy --version 1.1.10 --user xahaud --channel stable
|
||||
@@ -185,16 +184,6 @@ which allows you to statically link it with GCC, if you want.
|
||||
Export our [Conan recipe for RocksDB](./external/rocksdb).
|
||||
It does not override paths to dependencies when building with Visual Studio.
|
||||
|
||||
```
|
||||
# Conan 1.x
|
||||
conan export external/rocksdb rocksdb/6.29.5@
|
||||
# Conan 2.x
|
||||
conan export --version 6.29.5 external/rocksdb
|
||||
```
|
||||
|
||||
Export our [Conan recipe for SOCI](./external/soci).
|
||||
It patches their CMake to correctly import its dependencies.
|
||||
|
||||
```
|
||||
conan export external/soci --version 4.0.3 --user xahaud --channel stable
|
||||
```
|
||||
@@ -205,17 +194,6 @@ It patches their CMake to correctly import its dependencies.
|
||||
conan export external/wasmedge --version 0.11.2 --user xahaud --channel stable
|
||||
```
|
||||
|
||||
Export our [Conan recipe for NuDB](./external/nudb).
|
||||
It fixes some source files to add missing `#include`s.
|
||||
|
||||
|
||||
```
|
||||
# Conan 1.x
|
||||
conan export external/nudb nudb/2.0.8@
|
||||
# Conan 2.x
|
||||
conan export --version 2.0.8 external/nudb
|
||||
```
|
||||
|
||||
### Build and Test
|
||||
|
||||
1. Create a build directory and move into it.
|
||||
@@ -289,14 +267,13 @@ It fixes some source files to add missing `#include`s.
|
||||
cmake -DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake -Dxrpld=ON -Dtests=ON ..
|
||||
```
|
||||
|
||||
**Note:** You can pass build options for `xahaud` in this step.
|
||||
**Note:** You can pass build options for `rippled` in this step.
|
||||
|
||||
4. Build `xahaud`.
|
||||
5. Build `rippled`.
|
||||
|
||||
For a single-configuration generator, it will build whatever configuration
|
||||
you passed for `CMAKE_BUILD_TYPE`. For a multi-configuration generator,
|
||||
you must pass the option `--config` to select the build configuration.
|
||||
The output file is currently named 'rippled'.
|
||||
|
||||
Single-config generators:
|
||||
|
||||
@@ -311,7 +288,7 @@ It fixes some source files to add missing `#include`s.
|
||||
cmake --build . --config Debug
|
||||
```
|
||||
|
||||
5. Test xahaud.
|
||||
6. Test rippled.
|
||||
|
||||
Single-config generators:
|
||||
|
||||
@@ -326,7 +303,7 @@ It fixes some source files to add missing `#include`s.
|
||||
./Debug/rippled --unittest
|
||||
```
|
||||
|
||||
The location of `xahaud` in your build directory depends on your CMake
|
||||
The location of `rippled` in your build directory depends on your CMake
|
||||
generator. Pass `--help` to see the rest of the command line options.
|
||||
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ that `test` code should *never* be included in `ripple` code.)
|
||||
|
||||
## Validation
|
||||
|
||||
The [levelization.py](levelization.py) script takes no parameters,
|
||||
The [levelization.sh](levelization.sh) 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
|
||||
@@ -84,7 +84,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.py`,
|
||||
done anything else to improve levelization, run `levelization.sh`,
|
||||
and commit the updated results.
|
||||
|
||||
The `loops.txt` and `ordering.txt` files relate the modules
|
||||
@@ -108,7 +108,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.py`
|
||||
1. Run `levelization.sh`
|
||||
2. Grep the modules in `paths.txt`.
|
||||
* For example, if a cycle is found `A ~= B`, simply `grep -w
|
||||
A Builds/levelization/results/paths.txt | grep -w B`
|
||||
|
||||
@@ -1,283 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
Usage: levelization.py
|
||||
This script takes no parameters, and can be called from any directory in the file system.
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
from pathlib import Path
|
||||
|
||||
# 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):
|
||||
"""
|
||||
Create a sort key that mimics 'sort -d' (dictionary order).
|
||||
Dictionary order only considers blanks and alphanumeric characters.
|
||||
"""
|
||||
return "".join(c for c in s if c.isalnum() or c.isspace())
|
||||
|
||||
|
||||
def get_level(file_path):
|
||||
"""
|
||||
Extract the level from a file path (second and third directory components).
|
||||
Equivalent to bash: cut -d/ -f 2,3
|
||||
|
||||
Examples:
|
||||
src/ripple/app/main.cpp -> ripple.app
|
||||
src/test/app/Import_test.cpp -> test.app
|
||||
"""
|
||||
parts = file_path.split("/")
|
||||
|
||||
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]:
|
||||
# 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):
|
||||
"""
|
||||
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 <ripple/basics/base_uint.h> -> ripple.basics
|
||||
#include "ripple/app/main/Application.h" -> ripple.app
|
||||
"""
|
||||
match = INCLUDE_PATH_PATTERN.search(include_line)
|
||||
if not match:
|
||||
return None
|
||||
|
||||
include_path = match.group(1)
|
||||
parts = include_path.split("/")
|
||||
|
||||
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]:
|
||||
include_level = include_level.rsplit("/", 1)[0] + "/toplevel"
|
||||
|
||||
return include_level.replace("/", ".")
|
||||
|
||||
|
||||
def find_repository_directories(start_path, depth_limit=10):
|
||||
"""
|
||||
Find the repository root by looking for src or include folders.
|
||||
Walks up the directory tree from the start path.
|
||||
"""
|
||||
current = start_path.resolve()
|
||||
|
||||
for _ in range(depth_limit):
|
||||
src_path = current / "src"
|
||||
include_path = current / "include"
|
||||
has_src = src_path.exists()
|
||||
has_include = include_path.exists()
|
||||
|
||||
if has_src or has_include:
|
||||
dirs = []
|
||||
if has_src:
|
||||
dirs.append(src_path)
|
||||
if has_include:
|
||||
dirs.append(include_path)
|
||||
return current, dirs
|
||||
|
||||
parent = current.parent
|
||||
if parent == current:
|
||||
break
|
||||
current = parent
|
||||
|
||||
raise RuntimeError(
|
||||
"Could not find repository root. "
|
||||
"Expected to find a directory containing 'src' and/or 'include' folders."
|
||||
)
|
||||
|
||||
|
||||
def main():
|
||||
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.
|
||||
try:
|
||||
repo_root, scan_dirs = find_repository_directories(script_dir)
|
||||
print(f"Found repository root: {repo_root}")
|
||||
for scan_dir in scan_dirs:
|
||||
print(f" Scanning: {scan_dir.relative_to(repo_root)}")
|
||||
except RuntimeError as e:
|
||||
print(f"Error: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
# Find all #include directives.
|
||||
print("\nScanning for raw includes...")
|
||||
raw_includes = []
|
||||
rawincludes_file = results_dir / "rawincludes.txt"
|
||||
|
||||
with open(rawincludes_file, "w", buffering=8192) as raw_f:
|
||||
for dir_path in scan_dirs:
|
||||
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))
|
||||
with open(
|
||||
file_path, "r", encoding="utf-8", errors="ignore", buffering=8192
|
||||
) as f:
|
||||
for line in f:
|
||||
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.
|
||||
print("Build levelization paths")
|
||||
path_counts = 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.
|
||||
print("Sort and deduplicate paths")
|
||||
sorted_items = sorted(
|
||||
path_counts.items(),
|
||||
key=lambda x: (dictionary_sort_key(x[0][0]), dictionary_sort_key(x[0][1])),
|
||||
)
|
||||
|
||||
paths_file = results_dir / "paths.txt"
|
||||
with open(paths_file, "w") as f:
|
||||
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"
|
||||
includedby_dir = results_dir / "includedby"
|
||||
includes_dir.mkdir()
|
||||
includedby_dir.mkdir()
|
||||
|
||||
includes_data = defaultdict(list)
|
||||
includedby_data = defaultdict(list)
|
||||
|
||||
for (level, include_level), count in sorted_items:
|
||||
includes_data[level].append((include_level, count))
|
||||
includedby_data[include_level].append((level, count))
|
||||
|
||||
for level in sorted(includes_data.keys(), key=dictionary_sort_key):
|
||||
with open(includes_dir / level, "w") as f:
|
||||
for include_level, count in includes_data[level]:
|
||||
line = f"{include_level} {count}\n"
|
||||
print(line.rstrip())
|
||||
f.write(line)
|
||||
|
||||
for include_level in sorted(includedby_data.keys(), key=dictionary_sort_key):
|
||||
with open(includedby_dir / include_level, "w") as f:
|
||||
for level, count in includedby_data[include_level]:
|
||||
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"
|
||||
|
||||
# Pre-load all include files into memory for fast lookup.
|
||||
includes_cache = {}
|
||||
includes_lookup = {}
|
||||
|
||||
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:
|
||||
name, count = parts[0], int(parts[1])
|
||||
includes_cache[include_file.name].append((name, count))
|
||||
includes_lookup[include_file.name][name] = count
|
||||
|
||||
loops_found = set()
|
||||
|
||||
with open(loops_file, "w", buffering=8192) as loops_f, open(
|
||||
ordering_file, "w", buffering=8192
|
||||
) as ordering_f:
|
||||
for source in sorted(includes_cache.keys()):
|
||||
for include, include_freq in includes_cache[source]:
|
||||
if include not in includes_lookup:
|
||||
continue
|
||||
|
||||
source_freq = includes_lookup[include].get(source)
|
||||
|
||||
if source_freq is not None:
|
||||
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")
|
||||
|
||||
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
Builds/levelization/levelization.sh
Executable file
130
Builds/levelization/levelization.sh
Executable file
@@ -0,0 +1,130 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Usage: levelization.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 includedby
|
||||
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 dedup 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 includedby/${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
|
||||
@@ -10,6 +10,9 @@ Loop: test.jtx test.toplevel
|
||||
Loop: test.jtx test.unit_test
|
||||
test.unit_test == test.jtx
|
||||
|
||||
Loop: xrpl.hook xrpld.app
|
||||
xrpld.app > xrpl.hook
|
||||
|
||||
Loop: xrpl.protocol xrpld.app
|
||||
xrpld.app > xrpl.protocol
|
||||
|
||||
@@ -26,7 +29,7 @@ Loop: xrpld.app xrpld.nodestore
|
||||
xrpld.app > xrpld.nodestore
|
||||
|
||||
Loop: xrpld.app xrpld.overlay
|
||||
xrpld.overlay == xrpld.app
|
||||
xrpld.overlay ~= xrpld.app
|
||||
|
||||
Loop: xrpld.app xrpld.peerfinder
|
||||
xrpld.app > xrpld.peerfinder
|
||||
|
||||
@@ -12,7 +12,6 @@ libxrpl.server > xrpl.basics
|
||||
libxrpl.server > xrpl.json
|
||||
libxrpl.server > xrpl.protocol
|
||||
libxrpl.server > xrpl.server
|
||||
test.app > test.shamap
|
||||
test.app > test.toplevel
|
||||
test.app > test.unit_test
|
||||
test.app > xrpl.basics
|
||||
@@ -22,7 +21,6 @@ test.app > xrpld.ledger
|
||||
test.app > xrpld.nodestore
|
||||
test.app > xrpld.overlay
|
||||
test.app > xrpld.rpc
|
||||
test.app > xrpld.shamap
|
||||
test.app > xrpl.hook
|
||||
test.app > xrpl.json
|
||||
test.app > xrpl.protocol
|
||||
@@ -45,7 +43,6 @@ test.consensus > xrpld.app
|
||||
test.consensus > xrpld.consensus
|
||||
test.consensus > xrpld.core
|
||||
test.consensus > xrpld.ledger
|
||||
test.consensus > xrpl.json
|
||||
test.consensus > xrpl.protocol
|
||||
test.core > test.jtx
|
||||
test.core > test.toplevel
|
||||
@@ -87,7 +84,6 @@ test.nodestore > xrpl.basics
|
||||
test.nodestore > xrpld.core
|
||||
test.nodestore > xrpld.nodestore
|
||||
test.nodestore > xrpld.unity
|
||||
test.nodestore > xrpl.protocol
|
||||
test.overlay > test.jtx
|
||||
test.overlay > test.toplevel
|
||||
test.overlay > test.unit_test
|
||||
@@ -122,7 +118,6 @@ test.rpc > xrpld.core
|
||||
test.rpc > xrpld.net
|
||||
test.rpc > xrpld.overlay
|
||||
test.rpc > xrpld.rpc
|
||||
test.rpc > xrpld.shamap
|
||||
test.rpc > xrpl.hook
|
||||
test.rpc > xrpl.json
|
||||
test.rpc > xrpl.protocol
|
||||
@@ -160,7 +155,6 @@ xrpld.app > xrpl.basics
|
||||
xrpld.app > xrpld.conditions
|
||||
xrpld.app > xrpld.consensus
|
||||
xrpld.app > xrpld.perflog
|
||||
xrpld.app > xrpl.hook
|
||||
xrpld.app > xrpl.json
|
||||
xrpld.app > xrpl.resource
|
||||
xrpld.conditions > xrpl.basics
|
||||
|
||||
@@ -109,7 +109,7 @@ find_package(lz4 REQUIRED)
|
||||
find_package(LibArchive REQUIRED)
|
||||
find_package(SOCI REQUIRED)
|
||||
find_package(SQLite3 REQUIRED)
|
||||
|
||||
include(deps/WasmEdge)
|
||||
option(rocksdb "Enable RocksDB" ON)
|
||||
if(rocksdb)
|
||||
find_package(RocksDB REQUIRED)
|
||||
@@ -118,13 +118,9 @@ if(rocksdb)
|
||||
)
|
||||
target_link_libraries(ripple_libs INTERFACE RocksDB::rocksdb)
|
||||
endif()
|
||||
|
||||
find_package(nudb REQUIRED)
|
||||
find_package(date REQUIRED)
|
||||
find_package(xxHash REQUIRED)
|
||||
find_package(magic_enum REQUIRED)
|
||||
|
||||
include(deps/WasmEdge)
|
||||
if(TARGET nudb::core)
|
||||
set(nudb nudb::core)
|
||||
elseif(TARGET NuDB::nudb)
|
||||
@@ -136,10 +132,11 @@ target_link_libraries(ripple_libs INTERFACE ${nudb})
|
||||
|
||||
target_link_libraries(ripple_libs INTERFACE
|
||||
ed25519::ed25519
|
||||
LibArchive::LibArchive
|
||||
lz4::lz4
|
||||
OpenSSL::Crypto
|
||||
OpenSSL::SSL
|
||||
# Ripple::grpc_pbufs
|
||||
# Ripple::pbufs
|
||||
secp256k1::secp256k1
|
||||
soci::soci
|
||||
SQLite::SQLite3
|
||||
|
||||
@@ -57,12 +57,12 @@ Ensure that your code compiles according to the build instructions in the
|
||||
[`documentation`](https://docs.xahau.network/infrastructure/building-xahau).
|
||||
If you create new source files, they must go under `src/ripple`.
|
||||
You will need to add them to one of the
|
||||
[source lists](./Builds/CMake/RippledCore.cmake) in CMake.
|
||||
[source lists](./cmake/RippledCore.cmake) in CMake.
|
||||
|
||||
Please write tests for your code.
|
||||
If you create new test source files, they must go under `src/test`.
|
||||
You will need to add them to one of the
|
||||
[source lists](./Builds/CMake/RippledCore.cmake) in CMake.
|
||||
[source lists](./cmake/RippledCore.cmake) in CMake.
|
||||
If your test can be run offline, in under 60 seconds, then it can be an
|
||||
automatic test run by `rippled --unittest`.
|
||||
Otherwise, it must be a manual test.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
**Note:** Throughout this README, references to "we" or "our" pertain to the community and contributors involved in the Xahau network. It does not imply a legal entity or a specific collection of individuals.
|
||||
|
||||
[Xahau](https://xahau.network/) is a decentralized cryptographic ledger that builds upon the robust foundation of the XRP Ledger. It inherits the XRP Ledger's Byzantine Fault Tolerant consensus algorithm under the normal XRPL assumptions about configured validator-list overlap, timing, and fault bounds, and enhances it with additional features and functionalities. Developers and users familiar with the XRP Ledger will find that most documentation and tutorials available on [xrpl.org](https://xrpl.org) are relevant and applicable to Xahau, including those related to running validators and managing validator keys. For Xahau specific documentation you can visit our [documentation](https://xahau.network/)
|
||||
[Xahau](https://xahau.network/) is a decentralized cryptographic ledger that builds upon the robust foundation of the XRP Ledger. It inherits the XRP Ledger's Byzantine Fault Tolerant consensus algorithm and enhances it with additional features and functionalities. Developers and users familiar with the XRP Ledger will find that most documentation and tutorials available on [xrpl.org](https://xrpl.org) are relevant and applicable to Xahau, including those related to running validators and managing validator keys. For Xahau specific documentation you can visit our [documentation](https://xahau.network/)
|
||||
|
||||
## XAH
|
||||
XAH is the public, counterparty-free asset native to Xahau and functions primarily as network gas. Transactions submitted to the Xahau network must supply an appropriate amount of XAH, to be burnt by the network as a fee, in order to be successfully included in a validated ledger. In addition, XAH also acts as a bridge currency within the Xahau DEX. XAH is traded on the open-market and is available for anyone to access. Xahau was created in 2023 with a supply of 600 million units of XAH.
|
||||
@@ -12,7 +12,7 @@ The server software that powers Xahau is called `xahaud` and is available in thi
|
||||
|
||||
### Build from Source
|
||||
|
||||
* [Read the build instructions in our documentation](https://xahau.network/docs/infrastructure/build-xahaud/)
|
||||
* [Read the build instructions in our documentation](https://xahau.network/infrastructure/building-xahau)
|
||||
* If you encounter any issues, please [open an issue](https://github.com/xahau/xahaud/issues)
|
||||
|
||||
## Highlights of Xahau
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
set -o errexit
|
||||
|
||||
marker_base=f62f74da10c5936c64bd16cd509a8b68f1464e41
|
||||
marker_base=34be0ce4fef20c978df2923c29321ad6cc17facc
|
||||
marker_commit=${1:-${marker_base}}
|
||||
|
||||
if [ $(git merge-base ${marker_commit} ${marker_base}) != ${marker_base} ]; then
|
||||
|
||||
@@ -51,9 +51,10 @@ export CMAKE_STATIC_LINKER_FLAGS="-static-libstdc++"
|
||||
|
||||
git config --global --add safe.directory /io &&
|
||||
git checkout src/libxrpl/protocol/BuildInfo.cpp &&
|
||||
sed -i s/\"0.0.0\"/\"$(date +%Y).$(date +%-m).$(date +%-d)-$(git rev-parse --abbrev-ref HEAD)$(if [ -n "$4" ]; then echo "+$4"; fi)\"/g src/libxrpl/protocol/BuildInfo.cpp &&
|
||||
sed -i s/\"0.0.0\"/\"$(date +%Y).$(date +%-m).$(date +%-d)-$(git rev-parse --abbrev-ref HEAD)$(if [ -n "$4" ]; then echo "+$4"; fi)\"/g src/libxrpl/protocol/BuildInfo.cpp &&
|
||||
conan export external/snappy --version 1.1.10 --user xahaud --channel stable &&
|
||||
conan export external/soci --version 4.0.3 --user xahaud --channel stable &&
|
||||
conan export external/wasmedge --version 0.11.2 --user xahaud --channel stable &&
|
||||
cd release-build &&
|
||||
# Install dependencies - tool_requires in conanfile.py handles glibc 2.28 compatibility
|
||||
# for build tools (protoc, grpc plugins, b2) in HBB environment
|
||||
@@ -71,7 +72,6 @@ cmake .. -G Ninja \
|
||||
-Dxrpld=TRUE \
|
||||
-Dtests=TRUE &&
|
||||
ccache -z &&
|
||||
ccache -p &&
|
||||
ninja -j $3 && echo "=== Re-running final link with verbose output ===" && rm -f rippled && ninja -v rippled &&
|
||||
ccache -s &&
|
||||
strip -s rippled &&
|
||||
@@ -95,16 +95,8 @@ if [[ "$4" == "" ]]; then
|
||||
echo "Non GH, local building, no Action runner magic"
|
||||
else
|
||||
# GH Action, runner
|
||||
if [[ "$(git rev-parse --abbrev-ref HEAD)" == "release" ]]; then
|
||||
echo "building on the release branch... placing it in builds/candidate"
|
||||
mkdir /data/builds/candidate
|
||||
cp /io/release-build/xahaud /data/builds/candidate/$(date +%Y).$(date +%-m).$(date +%-d)-$(git rev-parse --abbrev-ref HEAD)+$4
|
||||
cp /io/release-build/release.info /data/builds/candidate/$(date +%Y).$(date +%-m).$(date +%-d)-$(git rev-parse --abbrev-ref HEAD)+$4.releaseinfo
|
||||
else
|
||||
echo "building non-release branch, placing it in builds root"
|
||||
cp /io/release-build/xahaud /data/builds/$(date +%Y).$(date +%-m).$(date +%-d)-$(git rev-parse --abbrev-ref HEAD)+$4
|
||||
cp /io/release-build/release.info /data/builds/$(date +%Y).$(date +%-m).$(date +%-d)-$(git rev-parse --abbrev-ref HEAD)+$4.releaseinfo
|
||||
fi
|
||||
cp /io/release-build/xahaud /data/builds/$(date +%Y).$(date +%-m).$(date +%-d)-$(git rev-parse --abbrev-ref HEAD)+$4
|
||||
cp /io/release-build/release.info /data/builds/$(date +%Y).$(date +%-m).$(date +%-d)-$(git rev-parse --abbrev-ref HEAD)+$4.releaseinfo
|
||||
echo "Published build to: http://build.xahau.tech/"
|
||||
echo $(date +%Y).$(date +%-m).$(date +%-d)-$(git rev-parse --abbrev-ref HEAD)+$4
|
||||
fi
|
||||
|
||||
@@ -12,16 +12,17 @@ echo "-- GITHUB_REPOSITORY: $1"
|
||||
echo "-- GITHUB_SHA: $2"
|
||||
echo "-- GITHUB_RUN_NUMBER: $4"
|
||||
|
||||
umask 0000
|
||||
umask 0000;
|
||||
|
||||
####
|
||||
|
||||
cd /io
|
||||
mkdir -p src/certs
|
||||
curl --silent -k https://raw.githubusercontent.com/RichardAH/rippled-release-builder/main/ca-bundle/certbundle.h -o src/certs/certbundle.h
|
||||
if [ "$(grep certbundle.h src/xrpld/net/detail/RegisterSSLCerts.cpp | wc -l)" -eq "0" ]; then
|
||||
cp src/xrpld/net/detail/RegisterSSLCerts.cpp src/xrpld/net/detail/RegisterSSLCerts.cpp.old
|
||||
perl -i -pe "s/^{/{
|
||||
cd /io;
|
||||
mkdir -p src/certs;
|
||||
curl --silent -k https://raw.githubusercontent.com/RichardAH/rippled-release-builder/main/ca-bundle/certbundle.h -o src/certs/certbundle.h;
|
||||
if [ "`grep certbundle.h src/xrpld/net/detail/RegisterSSLCerts.cpp | wc -l`" -eq "0" ]
|
||||
then
|
||||
cp src/xrpld/net/detail/RegisterSSLCerts.cpp src/xrpld/net/detail/RegisterSSLCerts.cpp.old
|
||||
perl -i -pe "s/^{/{
|
||||
#ifdef EMBEDDED_CA_BUNDLE
|
||||
BIO *cbio = BIO_new_mem_buf(ca_bundle.data(), ca_bundle.size());
|
||||
X509_STORE *cts = SSL_CTX_get_cert_store(ctx.native_handle());
|
||||
@@ -67,14 +68,15 @@ fi
|
||||
source /opt/rh/gcc-toolset-11/enable
|
||||
export PATH=/usr/local/bin:$PATH
|
||||
export CC='/usr/lib64/ccache/gcc' &&
|
||||
export CXX='/usr/lib64/ccache/g++' &&
|
||||
echo "-- Build Rippled --" &&
|
||||
pwd &&
|
||||
echo "MOVING TO [ build-core.sh ]"
|
||||
export CXX='/usr/lib64/ccache/g++' &&
|
||||
echo "-- Build Rippled --" &&
|
||||
pwd &&
|
||||
|
||||
printenv >.env.temp
|
||||
cat .env.temp | grep '=' | sed s/\\\(^[^=]\\+=\\\)/\\1\\\"/g | sed s/\$/\\\"/g >.env
|
||||
rm .env.temp
|
||||
echo "MOVING TO [ build-core.sh ]";
|
||||
|
||||
printenv > .env.temp;
|
||||
cat .env.temp | grep '=' | sed s/\\\(^[^=]\\+=\\\)/\\1\\\"/g|sed s/\$/\\\"/g > .env;
|
||||
rm .env.temp;
|
||||
|
||||
echo "Persisting ENV:"
|
||||
cat .env
|
||||
|
||||
@@ -394,7 +394,7 @@
|
||||
# true - enables compression
|
||||
# false - disables compression [default].
|
||||
#
|
||||
# The rippled server can save bandwidth by compressing its peer-to-peer communications,
|
||||
# The xahaud server can save bandwidth by compressing its peer-to-peer communications,
|
||||
# at a cost of greater CPU usage. If you enable link compression,
|
||||
# the server automatically compresses communications with peer servers
|
||||
# that also have link compression enabled.
|
||||
@@ -477,19 +477,6 @@
|
||||
#
|
||||
#
|
||||
#
|
||||
# [sntp_servers]
|
||||
#
|
||||
# IP address or domain of NTP servers to use for time synchronization.
|
||||
#
|
||||
# These NTP servers are suitable for xahaud servers located in the United
|
||||
# States:
|
||||
# time.windows.com
|
||||
# time.apple.com
|
||||
# time.nist.gov
|
||||
# pool.ntp.org
|
||||
#
|
||||
#
|
||||
#
|
||||
# [max_transactions]
|
||||
#
|
||||
# Configure the maximum number of transactions to have in the job queue
|
||||
@@ -954,12 +941,6 @@
|
||||
#
|
||||
# path Location to store the database
|
||||
#
|
||||
# Required keys for RWDB:
|
||||
#
|
||||
# online_delete Required. RWDB stores data in memory and will
|
||||
# grow unbounded without online_delete. See the
|
||||
# online_delete section below.
|
||||
#
|
||||
# Optional keys
|
||||
#
|
||||
# cache_size Size of cache for database records. Default is 16384.
|
||||
@@ -1450,7 +1431,7 @@
|
||||
#
|
||||
# ETL commands for Clio. We recommend setting secure_gateway
|
||||
# in this section to a comma-separated list of the addresses
|
||||
# of your Clio servers, in order to bypass rippled's rate limiting.
|
||||
# of your Clio servers, in order to bypass xahaud's rate limiting.
|
||||
#
|
||||
# This port is commented out but can be enabled by removing
|
||||
# the '#' from each corresponding line including the entry under [server]
|
||||
@@ -1524,13 +1505,10 @@ secure_gateway = 127.0.0.1
|
||||
# when the node has approximately two times the "online_delete" value of
|
||||
# ledgers. No external administrative command is required to initiate
|
||||
# deletion.
|
||||
[ledger_history]
|
||||
256
|
||||
|
||||
[node_db]
|
||||
type=NuDB
|
||||
path=/opt/xahaud/db/nudb
|
||||
online_delete=256
|
||||
online_delete=512
|
||||
advisory_delete=0
|
||||
|
||||
[database_path]
|
||||
@@ -1542,18 +1520,7 @@ advisory_delete=0
|
||||
[debug_logfile]
|
||||
/var/log/xahaud/debug.log
|
||||
|
||||
[sntp_servers]
|
||||
time.windows.com
|
||||
time.apple.com
|
||||
time.nist.gov
|
||||
pool.ntp.org
|
||||
|
||||
# Use the following [ips] section for the main network:
|
||||
[ips]
|
||||
bacab.alloy.ee 21337
|
||||
hubs.xahau.as16089.net 21337
|
||||
|
||||
# To use the Xahau Test Network
|
||||
# To use the Xahau test network
|
||||
# (see https://xahau.network/docs/infrastructure/installing-xahaud),
|
||||
# use the following [ips] section:
|
||||
# [ips]
|
||||
@@ -1579,10 +1546,3 @@ validators-xahau.txt
|
||||
# set to ssl_verify to 0.
|
||||
[ssl_verify]
|
||||
1
|
||||
|
||||
# Define which network xahaud is connecting to
|
||||
# 21337 for the Main Xahau Network
|
||||
# 21338 for the Test Xahau Network
|
||||
[network_id]
|
||||
21337
|
||||
# 21338
|
||||
|
||||
@@ -95,9 +95,6 @@
|
||||
# - replace both functions setup_target_for_coverage_gcovr_* with a single setup_target_for_coverage_gcovr
|
||||
# - add support for all gcovr output formats
|
||||
#
|
||||
# 2024-04-03, Bronek Kozicki
|
||||
# - add support for output formats: jacoco, clover, lcov
|
||||
#
|
||||
# USAGE:
|
||||
#
|
||||
# 1. Copy this file into your cmake modules path.
|
||||
@@ -259,10 +256,10 @@ endif()
|
||||
# BASE_DIRECTORY "../" # Base directory for report
|
||||
# # (defaults to PROJECT_SOURCE_DIR)
|
||||
# FORMAT "cobertura" # Output format, one of:
|
||||
# # xml cobertura sonarqube jacoco clover
|
||||
# # json-summary json-details coveralls csv
|
||||
# # txt html-single html-nested html-details
|
||||
# # lcov (xml is an alias to cobertura;
|
||||
# # xml cobertura sonarqube json-summary
|
||||
# # json-details coveralls csv txt
|
||||
# # html-single html-nested html-details
|
||||
# # (xml is an alias to cobertura;
|
||||
# # if no format is set, defaults to xml)
|
||||
# EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative
|
||||
# # to BASE_DIRECTORY, with CMake 3.4+)
|
||||
@@ -311,8 +308,6 @@ function(setup_target_for_coverage_gcovr)
|
||||
set(GCOVR_OUTPUT_FILE ${Coverage_NAME}.txt)
|
||||
elseif(Coverage_FORMAT STREQUAL "csv")
|
||||
set(GCOVR_OUTPUT_FILE ${Coverage_NAME}.csv)
|
||||
elseif(Coverage_FORMAT STREQUAL "lcov")
|
||||
set(GCOVR_OUTPUT_FILE ${Coverage_NAME}.lcov)
|
||||
else()
|
||||
set(GCOVR_OUTPUT_FILE ${Coverage_NAME}.xml)
|
||||
endif()
|
||||
@@ -325,14 +320,6 @@ function(setup_target_for_coverage_gcovr)
|
||||
set(Coverage_FORMAT cobertura) # overwrite xml
|
||||
elseif(Coverage_FORMAT STREQUAL "sonarqube")
|
||||
list(APPEND GCOVR_ADDITIONAL_ARGS --sonarqube "${GCOVR_OUTPUT_FILE}" )
|
||||
elseif(Coverage_FORMAT STREQUAL "jacoco")
|
||||
list(APPEND GCOVR_ADDITIONAL_ARGS --jacoco "${GCOVR_OUTPUT_FILE}" )
|
||||
list(APPEND GCOVR_ADDITIONAL_ARGS --jacoco-pretty )
|
||||
elseif(Coverage_FORMAT STREQUAL "clover")
|
||||
list(APPEND GCOVR_ADDITIONAL_ARGS --clover "${GCOVR_OUTPUT_FILE}" )
|
||||
list(APPEND GCOVR_ADDITIONAL_ARGS --clover-pretty )
|
||||
elseif(Coverage_FORMAT STREQUAL "lcov")
|
||||
list(APPEND GCOVR_ADDITIONAL_ARGS --lcov "${GCOVR_OUTPUT_FILE}" )
|
||||
elseif(Coverage_FORMAT STREQUAL "json-summary")
|
||||
list(APPEND GCOVR_ADDITIONAL_ARGS --json-summary "${GCOVR_OUTPUT_FILE}" )
|
||||
list(APPEND GCOVR_ADDITIONAL_ARGS --json-summary-pretty)
|
||||
@@ -393,7 +380,6 @@ function(setup_target_for_coverage_gcovr)
|
||||
${GCOVR_PATH}
|
||||
--gcov-executable ${GCOV_TOOL}
|
||||
--gcov-ignore-parse-errors=negative_hits.warn_once_per_file
|
||||
--gcov-ignore-parse-errors=suspicious_hits.warn_once_per_file
|
||||
-r ${BASEDIR}
|
||||
${GCOVR_ADDITIONAL_ARGS}
|
||||
${GCOVR_EXCLUDE_ARGS}
|
||||
|
||||
@@ -54,7 +54,6 @@ add_library(xrpl.imports.main INTERFACE)
|
||||
target_link_libraries(xrpl.imports.main
|
||||
INTERFACE
|
||||
LibArchive::LibArchive
|
||||
magic_enum::magic_enum
|
||||
OpenSSL::Crypto
|
||||
Ripple::boost
|
||||
wasmedge::wasmedge
|
||||
@@ -69,17 +68,6 @@ target_link_libraries(xrpl.imports.main
|
||||
$<$<BOOL:${voidstar}>:antithesis-sdk-cpp>
|
||||
)
|
||||
|
||||
# date-tz for enhanced logging (always linked, code is #ifdef guarded)
|
||||
if(TARGET date::date-tz)
|
||||
target_link_libraries(xrpl.imports.main INTERFACE date::date-tz)
|
||||
endif()
|
||||
|
||||
# BEAST_ENHANCED_LOGGING: enable for Debug builds OR when explicitly requested
|
||||
# Uses generator expression so it works with multi-config generators (Xcode, VS, Ninja Multi-Config)
|
||||
target_compile_definitions(xrpl.imports.main INTERFACE
|
||||
$<$<OR:$<CONFIG:Debug>,$<BOOL:${BEAST_ENHANCED_LOGGING}>>:BEAST_ENHANCED_LOGGING=1>
|
||||
)
|
||||
|
||||
include(add_module)
|
||||
include(target_link_modules)
|
||||
|
||||
@@ -90,6 +78,12 @@ target_link_libraries(xrpl.libxrpl.beast PUBLIC
|
||||
xrpl.libpb
|
||||
)
|
||||
|
||||
# Conditionally add enhanced logging source when BEAST_ENHANCED_LOGGING is enabled
|
||||
if(DEFINED BEAST_ENHANCED_LOGGING AND BEAST_ENHANCED_LOGGING)
|
||||
target_sources(xrpl.libxrpl.beast PRIVATE
|
||||
src/libxrpl/beast/utility/src/beast_EnhancedLogging.cpp)
|
||||
endif()
|
||||
|
||||
# Level 02
|
||||
add_module(xrpl basics)
|
||||
target_link_libraries(xrpl.libxrpl.basics PUBLIC xrpl.libxrpl.beast)
|
||||
@@ -165,14 +159,6 @@ if(xrpld)
|
||||
if(tests)
|
||||
target_compile_definitions(rippled PUBLIC ENABLE_TESTS)
|
||||
endif()
|
||||
if(xahaud_runtime_test_config)
|
||||
target_compile_definitions(rippled PUBLIC XAHAUD_ENABLE_RUNTIME_TEST_CONFIG=1)
|
||||
endif()
|
||||
if(xahaud_sidecar_reconciliation)
|
||||
target_compile_definitions(rippled PUBLIC XAHAUD_ENABLE_SIDECAR_RECONCILIATION=1)
|
||||
else()
|
||||
target_compile_definitions(rippled PUBLIC XAHAUD_ENABLE_SIDECAR_RECONCILIATION=0)
|
||||
endif()
|
||||
target_include_directories(rippled
|
||||
PRIVATE
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>
|
||||
@@ -181,9 +167,6 @@ if(xrpld)
|
||||
file(GLOB_RECURSE sources CONFIGURE_DEPENDS
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/xrpld/*.cpp"
|
||||
)
|
||||
if(NOT xahaud_sidecar_reconciliation)
|
||||
list(FILTER sources EXCLUDE REGEX "/src/xrpld/app/ledger/SidecarSetSF\\.cpp$")
|
||||
endif()
|
||||
target_sources(rippled PRIVATE ${sources})
|
||||
|
||||
if(tests)
|
||||
@@ -191,21 +174,6 @@ if(xrpld)
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/test/*.cpp"
|
||||
)
|
||||
target_sources(rippled PRIVATE ${sources})
|
||||
|
||||
set(HOOKS_TEST_DIR "" CACHE PATH "External hook Env-test directory")
|
||||
if(NOT HOOKS_TEST_DIR AND DEFINED ENV{HOOKS_TEST_DIR})
|
||||
set(HOOKS_TEST_DIR "$ENV{HOOKS_TEST_DIR}")
|
||||
endif()
|
||||
if(HOOKS_TEST_DIR)
|
||||
file(GLOB_RECURSE hook_test_sources CONFIGURE_DEPENDS
|
||||
"${HOOKS_TEST_DIR}/*_test.cpp"
|
||||
)
|
||||
if(hook_test_sources)
|
||||
message(STATUS "Including external hook Env tests from ${HOOKS_TEST_DIR}")
|
||||
target_sources(rippled PRIVATE ${hook_test_sources})
|
||||
target_include_directories(rippled PRIVATE "${HOOKS_TEST_DIR}")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
target_link_libraries(rippled
|
||||
|
||||
@@ -22,9 +22,6 @@ target_compile_definitions (opts
|
||||
$<$<BOOL:${beast_no_unit_test_inline}>:BEAST_NO_UNIT_TEST_INLINE=1>
|
||||
$<$<BOOL:${beast_disable_autolink}>:BEAST_DONT_AUTOLINK_TO_WIN32_LIBRARIES=1>
|
||||
$<$<BOOL:${single_io_service_thread}>:RIPPLE_SINGLE_IO_SERVICE_THREAD=1>
|
||||
# Enhanced logging is enabled for Debug builds, or explicitly via
|
||||
# -DBEAST_ENHANCED_LOGGING=ON for other build types.
|
||||
$<$<OR:$<CONFIG:Debug>,$<BOOL:${BEAST_ENHANCED_LOGGING}>>:BEAST_ENHANCED_LOGGING=1>
|
||||
$<$<BOOL:${voidstar}>:ENABLE_VOIDSTAR>)
|
||||
target_compile_options (opts
|
||||
INTERFACE
|
||||
|
||||
@@ -12,17 +12,6 @@ option(xrpld "Build xrpld" ON)
|
||||
|
||||
option(tests "Build tests" ON)
|
||||
|
||||
option(xahaud_runtime_test_config
|
||||
"Enable XAHAUD_RUNTIME_TEST_CONFIG env and runtime_config RPC fault-injection controls"
|
||||
OFF)
|
||||
# Conan 2 local opt-in:
|
||||
# [conf]
|
||||
# tools.cmake.cmaketoolchain:extra_variables={"xahaud_runtime_test_config":"ON"}
|
||||
|
||||
option(xahaud_sidecar_reconciliation
|
||||
"Enable consensus-extension sidecar SHAMap fetch/acquire/reconcile path"
|
||||
OFF)
|
||||
|
||||
option(unity "Creates a build using UNITY support in cmake. This is the default" ON)
|
||||
if(unity)
|
||||
if(NOT is_ci)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
find_package(Boost 1.86 REQUIRED
|
||||
find_package(Boost 1.83 REQUIRED
|
||||
COMPONENTS
|
||||
chrono
|
||||
container
|
||||
@@ -7,7 +7,6 @@ find_package(Boost 1.86 REQUIRED
|
||||
date_time
|
||||
filesystem
|
||||
json
|
||||
json
|
||||
program_options
|
||||
regex
|
||||
system
|
||||
@@ -32,6 +31,7 @@ target_link_libraries(ripple_boost
|
||||
Boost::date_time
|
||||
Boost::filesystem
|
||||
Boost::json
|
||||
Boost::iostreams
|
||||
Boost::program_options
|
||||
Boost::regex
|
||||
Boost::system
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
# those warnings.
|
||||
if (RIPPLED_SOURCE)
|
||||
execute_process( COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
${RIPPLED_SOURCE}/Builds/CMake/SociConfig.cmake.patched
|
||||
${RIPPLED_SOURCE}/cmake/SociConfig.cmake.patched
|
||||
cmake/SociConfig.cmake )
|
||||
endif ()
|
||||
|
||||
|
||||
11
conanfile.py
11
conanfile.py
@@ -29,7 +29,6 @@ class Xrpl(ConanFile):
|
||||
'date/3.0.3',
|
||||
'grpc/1.50.1',
|
||||
'libarchive/3.7.6',
|
||||
'magic_enum/0.9.5',
|
||||
'nudb/2.0.8',
|
||||
'openssl/3.6.0',
|
||||
'soci/4.0.3@xahaud/stable',
|
||||
@@ -51,9 +50,9 @@ class Xrpl(ConanFile):
|
||||
'static': True,
|
||||
'tests': False,
|
||||
'unity': False,
|
||||
'xrpld': False,
|
||||
'with_wasmedge': True,
|
||||
'tool_requires_b2': False,
|
||||
'xrpld': False,
|
||||
|
||||
'date/*:header_only': False,
|
||||
'grpc/*:shared': False,
|
||||
@@ -100,7 +99,6 @@ class Xrpl(ConanFile):
|
||||
self.version = match.group(1)
|
||||
|
||||
def build_requirements(self):
|
||||
# These provide build tools (protoc, grpc plugins) that run during build
|
||||
self.tool_requires('grpc/1.50.1')
|
||||
# Explicitly require b2 (e.g. for building from source for glibc compatibility)
|
||||
if self.options.tool_requires_b2:
|
||||
@@ -111,13 +109,14 @@ class Xrpl(ConanFile):
|
||||
self.options['boost/*'].visibility = 'global'
|
||||
|
||||
def requirements(self):
|
||||
# Force boost version for all dependencies to avoid conflicts
|
||||
self.requires('boost/1.86.0', override=True)
|
||||
self.requires('lz4/1.10.0', force=True)
|
||||
self.requires('protobuf/3.21.9', force=True)
|
||||
# Force sqlite3 version to avoid conflicts with soci
|
||||
self.requires('sqlite3/3.47.0', override=True)
|
||||
# Force our custom snappy build for all dependencies
|
||||
self.requires('snappy/1.1.10@xahaud/stable', override=True)
|
||||
# Force boost version for all dependencies to avoid conflicts
|
||||
self.requires('boost/1.86.0', override=True)
|
||||
self.requires('lz4/1.10.0', force=True)
|
||||
|
||||
if self.options.with_wasmedge:
|
||||
self.requires('wasmedge/0.11.2@xahaud/stable')
|
||||
|
||||
4
docs/build/environment.md
vendored
4
docs/build/environment.md
vendored
@@ -11,11 +11,11 @@ platforms: Linux, macOS, or Windows.
|
||||
Package ecosystems vary across Linux distributions,
|
||||
so there is no one set of instructions that will work for every Linux user.
|
||||
These instructions are written for Ubuntu 22.04.
|
||||
They are largely copied from the [script][1] used to configure a Docker
|
||||
They are largely copied from the [script][1] used to configure our Docker
|
||||
container for continuous integration.
|
||||
That script handles many more responsibilities.
|
||||
These instructions are just the bare minimum to build one configuration of
|
||||
xahaud.
|
||||
rippled.
|
||||
You can check that codebase for other Linux distributions and versions.
|
||||
If you cannot find yours there,
|
||||
then we hope that these instructions can at least guide you in the right
|
||||
|
||||
177
docs/build/install.md
vendored
177
docs/build/install.md
vendored
@@ -1,30 +1,159 @@
|
||||
Comprehensive instructions for installing and running xahaud are available on the [https://Xahau.Network](https://xahau.network/docs/infrastructure/installing-xahaud) documentation website.
|
||||
This document contains instructions for installing rippled.
|
||||
The APT package manager is common on Debian-based Linux distributions like
|
||||
Ubuntu,
|
||||
while the YUM package manager is common on Red Hat-based Linux distributions
|
||||
like CentOS.
|
||||
Installing from source is an option for all platforms,
|
||||
and the only supported option for installing custom builds.
|
||||
|
||||
## Create the Runtime Environment
|
||||
xahaud can be [built from source](../../BUILD.md) or installed using the binary files available from [https://build.xahau.tech](https://build.xahau.tech/). After obtaining a working xahaud binary, users will need to provide a suitable runtime environment. The following setup can be used for Linux or Docker environments.
|
||||
|
||||
1. Create or download two configuration files: the main xahaud.cfg configuration file and a second validators-xahau.txt file defining which validators or UNL list publishers are trusted. The default location for these files in this xahaud repository is `cfg/`.
|
||||
2. Provide a directory structure that is congruent with the contents of xahaud.cfg. This will include a location for logfiles, such as `/var/log/xahaud/`, as well as database files, `/opt/xahaud/db/`. Configuration files are, by default, sourced from `/etc/xahaud/`. It is possible to provide a symbolic link, if users wish to store configuration files elsewhere.
|
||||
3. If desired, created a xahaud user and group, and change ownership of the binary and directories. Servers used for validating nodes should use the most restrictive permissions possible for `xahaud.cfg`, as the validation token is stored therein.
|
||||
4. If desired, create a systemd service file: `/etc/systemd/system/xahaud.service`, enabling xahaud to run as a daemon. Alternately, run: `/path/to/binary/xahaud --conf=/path/to/xahaud.cfg`.
|
||||
## From source
|
||||
|
||||
From a source build, you can install rippled and libxrpl using CMake's
|
||||
`--install` mode:
|
||||
|
||||
## Example systemd Service File
|
||||
```
|
||||
[Unit]
|
||||
Description=Xahaud Daemon
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=/path/to/xahaud --silent --conf /path/to/xahaud.cfg
|
||||
Restart=on-failure
|
||||
User=xahaud
|
||||
Group=xahaud
|
||||
LimitNOFILE=65536
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
cmake --install . --prefix /opt/local
|
||||
```
|
||||
|
||||
After the systemd service file is installed, it must be loaded with: `systemctl daemon-reload`. xahaud can then be enabled: `systemctl enable --now xahaud`.
|
||||
The default [prefix][1] is typically `/usr/local` on Linux and macOS and
|
||||
`C:/Program Files/rippled` on Windows.
|
||||
|
||||
[1]: https://cmake.org/cmake/help/latest/variable/CMAKE_INSTALL_PREFIX.html
|
||||
|
||||
|
||||
## With the APT package manager
|
||||
|
||||
1. Update repositories:
|
||||
|
||||
sudo apt update -y
|
||||
|
||||
2. Install utilities:
|
||||
|
||||
sudo apt install -y apt-transport-https ca-certificates wget gnupg
|
||||
|
||||
3. Add Ripple's package-signing GPG key to your list of trusted keys:
|
||||
|
||||
sudo mkdir /usr/local/share/keyrings/
|
||||
wget -q -O - "https://repos.ripple.com/repos/api/gpg/key/public" | gpg --dearmor > ripple-key.gpg
|
||||
sudo mv ripple-key.gpg /usr/local/share/keyrings
|
||||
|
||||
|
||||
4. Check the fingerprint of the newly-added key:
|
||||
|
||||
gpg /usr/local/share/keyrings/ripple-key.gpg
|
||||
|
||||
The output should include an entry for Ripple such as the following:
|
||||
|
||||
gpg: WARNING: no command supplied. Trying to guess what you mean ...
|
||||
pub rsa3072 2019-02-14 [SC] [expires: 2026-02-17]
|
||||
C0010EC205B35A3310DC90DE395F97FFCCAFD9A2
|
||||
uid TechOps Team at Ripple <techops+rippled@ripple.com>
|
||||
sub rsa3072 2019-02-14 [E] [expires: 2026-02-17]
|
||||
|
||||
|
||||
In particular, make sure that the fingerprint matches. (In the above example, the fingerprint is on the third line, starting with `C001`.)
|
||||
|
||||
4. Add the appropriate Ripple repository for your operating system version:
|
||||
|
||||
echo "deb [signed-by=/usr/local/share/keyrings/ripple-key.gpg] https://repos.ripple.com/repos/rippled-deb focal stable" | \
|
||||
sudo tee -a /etc/apt/sources.list.d/ripple.list
|
||||
|
||||
The above example is appropriate for **Ubuntu 20.04 Focal Fossa**. For other operating systems, replace the word `focal` with one of the following:
|
||||
|
||||
- `jammy` for **Ubuntu 22.04 Jammy Jellyfish**
|
||||
- `bionic` for **Ubuntu 18.04 Bionic Beaver**
|
||||
- `bullseye` for **Debian 11 Bullseye**
|
||||
- `buster` for **Debian 10 Buster**
|
||||
|
||||
If you want access to development or pre-release versions of `rippled`, use one of the following instead of `stable`:
|
||||
|
||||
- `unstable` - Pre-release builds ([`release` branch](https://github.com/ripple/rippled/tree/release))
|
||||
- `nightly` - Experimental/development builds ([`develop` branch](https://github.com/ripple/rippled/tree/develop))
|
||||
|
||||
**Warning:** Unstable and nightly builds may be broken at any time. Do not use these builds for production servers.
|
||||
|
||||
5. Fetch the Ripple repository.
|
||||
|
||||
sudo apt -y update
|
||||
|
||||
6. Install the `rippled` software package:
|
||||
|
||||
sudo apt -y install rippled
|
||||
|
||||
7. Check the status of the `rippled` service:
|
||||
|
||||
systemctl status rippled.service
|
||||
|
||||
The `rippled` service should start automatically. If not, you can start it manually:
|
||||
|
||||
sudo systemctl start rippled.service
|
||||
|
||||
8. Optional: allow `rippled` to bind to privileged ports.
|
||||
|
||||
This allows you to serve incoming API requests on port 80 or 443. (If you want to do so, you must also update the config file's port settings.)
|
||||
|
||||
sudo setcap 'cap_net_bind_service=+ep' /opt/ripple/bin/rippled
|
||||
|
||||
|
||||
## With the YUM package manager
|
||||
|
||||
1. Install the Ripple RPM repository:
|
||||
|
||||
Choose the appropriate RPM repository for the stability of releases you want:
|
||||
|
||||
- `stable` for the latest production release (`master` branch)
|
||||
- `unstable` for pre-release builds (`release` branch)
|
||||
- `nightly` for experimental/development builds (`develop` branch)
|
||||
|
||||
*Stable*
|
||||
|
||||
cat << REPOFILE | sudo tee /etc/yum.repos.d/ripple.repo
|
||||
[ripple-stable]
|
||||
name=XRP Ledger Packages
|
||||
enabled=1
|
||||
gpgcheck=0
|
||||
repo_gpgcheck=1
|
||||
baseurl=https://repos.ripple.com/repos/rippled-rpm/stable/
|
||||
gpgkey=https://repos.ripple.com/repos/rippled-rpm/stable/repodata/repomd.xml.key
|
||||
REPOFILE
|
||||
|
||||
*Unstable*
|
||||
|
||||
cat << REPOFILE | sudo tee /etc/yum.repos.d/ripple.repo
|
||||
[ripple-unstable]
|
||||
name=XRP Ledger Packages
|
||||
enabled=1
|
||||
gpgcheck=0
|
||||
repo_gpgcheck=1
|
||||
baseurl=https://repos.ripple.com/repos/rippled-rpm/unstable/
|
||||
gpgkey=https://repos.ripple.com/repos/rippled-rpm/unstable/repodata/repomd.xml.key
|
||||
REPOFILE
|
||||
|
||||
*Nightly*
|
||||
|
||||
cat << REPOFILE | sudo tee /etc/yum.repos.d/ripple.repo
|
||||
[ripple-nightly]
|
||||
name=XRP Ledger Packages
|
||||
enabled=1
|
||||
gpgcheck=0
|
||||
repo_gpgcheck=1
|
||||
baseurl=https://repos.ripple.com/repos/rippled-rpm/nightly/
|
||||
gpgkey=https://repos.ripple.com/repos/rippled-rpm/nightly/repodata/repomd.xml.key
|
||||
REPOFILE
|
||||
|
||||
2. Fetch the latest repo updates:
|
||||
|
||||
sudo yum -y update
|
||||
|
||||
3. Install the new `rippled` package:
|
||||
|
||||
sudo yum install -y rippled
|
||||
|
||||
4. Configure the `rippled` service to start on boot:
|
||||
|
||||
sudo systemctl enable rippled.service
|
||||
|
||||
5. Start the `rippled` service:
|
||||
|
||||
sudo systemctl start rippled.service
|
||||
|
||||
@@ -47,8 +47,5 @@
|
||||
#define MEM_OVERLAP -43
|
||||
#define TOO_MANY_STATE_MODIFICATIONS -44
|
||||
#define TOO_MANY_NAMESPACES -45
|
||||
#define EXPORT_FAILURE -46
|
||||
#define TOO_MANY_EXPORTED_TXN -47
|
||||
#define TOO_LITTLE_ENTROPY -48
|
||||
#define HOOK_ERROR_CODES
|
||||
#endif //HOOK_ERROR_CODES
|
||||
|
||||
@@ -2,9 +2,6 @@
|
||||
// Generated using generate_extern.sh
|
||||
#include <stdint.h>
|
||||
#ifndef HOOK_EXTERN
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern int32_t __attribute__((noduplicate))
|
||||
_g(uint32_t guard_id, uint32_t maxiter);
|
||||
@@ -332,50 +329,5 @@ meta_slot(uint32_t slot_no);
|
||||
extern int64_t
|
||||
xpop_slot(uint32_t slot_no_tx, uint32_t slot_no_meta);
|
||||
|
||||
extern int64_t
|
||||
prepare(
|
||||
uint32_t write_ptr,
|
||||
uint32_t write_len,
|
||||
uint32_t read_ptr,
|
||||
uint32_t read_len);
|
||||
|
||||
extern int64_t
|
||||
xport_reserve(uint32_t count);
|
||||
|
||||
extern int64_t
|
||||
xport(
|
||||
uint32_t write_ptr,
|
||||
uint32_t write_len,
|
||||
uint32_t read_ptr,
|
||||
uint32_t read_len);
|
||||
|
||||
extern int64_t
|
||||
xport_cancel(uint32_t ticket_seq);
|
||||
|
||||
/*
|
||||
Consensus entropy APIs.
|
||||
|
||||
min_tier is a fail-closed floor:
|
||||
1 = consensus_fallback, 2 = participant_aligned, 3 = validator_quorum.
|
||||
min_count is the minimum validator/reveal count the caller accepts.
|
||||
|
||||
If the most recent finalized entropy object does not satisfy both floors,
|
||||
these APIs return TOO_LITTLE_ENTROPY. Open-ledger and simulate execution
|
||||
are provisional previews over the entropy currently visible to the node;
|
||||
final ordered ledger execution may see a different entropy object.
|
||||
*/
|
||||
extern int64_t
|
||||
dice(uint32_t sides, uint32_t min_tier, uint32_t min_count);
|
||||
|
||||
extern int64_t
|
||||
random(
|
||||
uint32_t write_ptr,
|
||||
uint32_t write_len,
|
||||
uint32_t min_tier,
|
||||
uint32_t min_count);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#define HOOK_EXTERN
|
||||
#endif // HOOK_EXTERN
|
||||
|
||||
@@ -9,7 +9,7 @@ ENUM_FILE="$SCRIPT_DIR/../include/xrpl/hook/Enum.h"
|
||||
echo '// For documentation please see: https://xrpl-hooks.readme.io/reference/'
|
||||
echo '// Generated using generate_error.sh'
|
||||
echo '#ifndef HOOK_ERROR_CODES'
|
||||
sed -n '/enum class hook_return_code/,/};/p' "$ENUM_FILE" |
|
||||
sed -n '/enum hook_return_code/,/};/p' "$ENUM_FILE" |
|
||||
awk '
|
||||
function ltrim(s) { sub(/^[[:space:]]+/, "", s); return s }
|
||||
function rtrim(s) { sub(/[[:space:]]+$/, "", s); return s }
|
||||
@@ -31,7 +31,7 @@ sed -n '/enum class hook_return_code/,/};/p' "$ENUM_FILE" |
|
||||
|
||||
{
|
||||
line = $0
|
||||
if (line ~ /enum[[:space:]]+class[[:space:]]+hook_return_code/)
|
||||
if (line ~ /enum[[:space:]]+hook_return_code/)
|
||||
next
|
||||
if (line ~ /^[[:space:]]*\{/)
|
||||
next
|
||||
|
||||
@@ -11,9 +11,6 @@ APPLY_HOOK="$SCRIPT_DIR/../include/xrpl/hook/hook_api.macro"
|
||||
echo '// Generated using generate_extern.sh'
|
||||
echo '#include <stdint.h>'
|
||||
echo '#ifndef HOOK_EXTERN'
|
||||
echo '#ifdef __cplusplus'
|
||||
echo 'extern "C" {'
|
||||
echo '#endif'
|
||||
echo
|
||||
awk '
|
||||
function trim(s) {
|
||||
@@ -41,21 +38,6 @@ APPLY_HOOK="$SCRIPT_DIR/../include/xrpl/hook/hook_api.macro"
|
||||
# Insert __attribute__((noduplicate)) before _g
|
||||
sub(/[[:space:]]+_g/, " __attribute__((noduplicate)) _g", line);
|
||||
}
|
||||
|
||||
if (line ~ /[[:space:]]+dice[[:space:]]*\(/) {
|
||||
print "/*";
|
||||
print " Consensus entropy APIs.";
|
||||
print "";
|
||||
print " min_tier is a fail-closed floor:";
|
||||
print " 1 = consensus_fallback, 2 = participant_aligned, 3 = validator_quorum.";
|
||||
print " min_count is the minimum validator/reveal count the caller accepts.";
|
||||
print "";
|
||||
print " If the most recent finalized entropy object does not satisfy both floors,";
|
||||
print " these APIs return TOO_LITTLE_ENTROPY. Open-ledger and simulate execution";
|
||||
print " are provisional previews over the entropy currently visible to the node;";
|
||||
print " final ordered ledger execution may see a different entropy object.";
|
||||
print "*/";
|
||||
}
|
||||
|
||||
# printf("\n");
|
||||
|
||||
@@ -64,9 +46,6 @@ APPLY_HOOK="$SCRIPT_DIR/../include/xrpl/hook/hook_api.macro"
|
||||
}
|
||||
' "$APPLY_HOOK"
|
||||
|
||||
echo '#ifdef __cplusplus'
|
||||
echo '}'
|
||||
echo '#endif'
|
||||
echo '#define HOOK_EXTERN'
|
||||
echo '#endif // HOOK_EXTERN'
|
||||
} | (
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -eu
|
||||
|
||||
SCRIPT_DIR=$(dirname "$0")
|
||||
SCRIPT_DIR=$(cd "$SCRIPT_DIR" && pwd)
|
||||
|
||||
RIPPLED_ROOT="$SCRIPT_DIR/../include/xrpl"
|
||||
LEDGER_FORMATS="$RIPPLED_ROOT/protocol/LedgerFormats.h"
|
||||
|
||||
echo '// Generated using generate_lsflags.sh'
|
||||
echo ''
|
||||
echo '#ifndef HOOKLSFLAGS_INCLUDED'
|
||||
echo '#define HOOKLSFLAGS_INCLUDED 1'
|
||||
echo ''
|
||||
awk '
|
||||
function ltrim(s) { sub(/^[[:space:]]+/, "", s); return s }
|
||||
function rtrim(s) { sub(/[[:space:]]+$/, "", s); return s }
|
||||
function trim(s) { return rtrim(ltrim(s)) }
|
||||
|
||||
function flush_group() {
|
||||
if (entry_count > 0 && group != "") {
|
||||
printf "enum %s {\n", group
|
||||
for (i = 1; i <= entry_count; i++) {
|
||||
printf " %s,\n", entries[i]
|
||||
}
|
||||
printf "};\n"
|
||||
}
|
||||
delete entries
|
||||
entry_count = 0
|
||||
}
|
||||
|
||||
/enum LedgerSpecificFlags \{/ { inside = 1; next }
|
||||
inside && /^\};/ { inside = 0; flush_group(); next }
|
||||
!inside { next }
|
||||
|
||||
# Group header comments: // ltFOO or // remarks
|
||||
/^[[:space:]]*\/\/[[:space:]]*(lt[A-Z_]+|remarks)[[:space:]]*$/ {
|
||||
flush_group()
|
||||
line = $0
|
||||
sub(/.*\/\/[[:space:]]*/, "", line)
|
||||
group = trim(line)
|
||||
next
|
||||
}
|
||||
|
||||
# Skip pure comment lines (not group headers)
|
||||
/^[[:space:]]*\/\// { next }
|
||||
|
||||
# Skip blank lines
|
||||
/^[[:space:]]*$/ { next }
|
||||
|
||||
# Accumulate flag lines (handle multi-line values)
|
||||
{
|
||||
line = $0
|
||||
# Strip inline comments
|
||||
sub(/\/\/.*/, "", line)
|
||||
line = trim(line)
|
||||
if (line == "") next
|
||||
|
||||
if (pending != "") {
|
||||
pending = pending " " line
|
||||
} else {
|
||||
pending = line
|
||||
}
|
||||
|
||||
# If line ends with comma, the entry is complete
|
||||
if (pending ~ /,$/) {
|
||||
# Remove trailing comma
|
||||
sub(/,$/, "", pending)
|
||||
entries[++entry_count] = pending
|
||||
pending = ""
|
||||
}
|
||||
}
|
||||
|
||||
BEGIN {
|
||||
inside = 0
|
||||
group = ""
|
||||
pending = ""
|
||||
entry_count = 0
|
||||
}
|
||||
' "$LEDGER_FORMATS"
|
||||
echo ''
|
||||
echo '#endif // HOOKLSFLAGS_INCLUDED'
|
||||
@@ -1,25 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -eu
|
||||
|
||||
SCRIPT_DIR=$(dirname "$0")
|
||||
SCRIPT_DIR=$(cd "$SCRIPT_DIR" && pwd)
|
||||
|
||||
RIPPLED_ROOT="$SCRIPT_DIR/../include/xrpl"
|
||||
TX_FLAGS="$RIPPLED_ROOT/protocol/TxFlags.h"
|
||||
|
||||
echo '// Generated using generate_txflags.sh'
|
||||
echo '#include "ls_flags.h"'
|
||||
echo '#include <stdint.h>'
|
||||
echo ''
|
||||
cat "$TX_FLAGS" |
|
||||
awk '
|
||||
/^[[:space:]]*enum / {
|
||||
if (count > 0) print ""
|
||||
inside = 1
|
||||
count++
|
||||
}
|
||||
inside {
|
||||
print
|
||||
if (/};/) inside = 0
|
||||
}
|
||||
'
|
||||
@@ -1,203 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# build_xahau_h.sh
|
||||
# Builds genesis hook WASMs and updates xahau.h with hex arrays
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Color codes for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Script directory and path constants
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
XAHAU_H="${SCRIPT_DIR}/../../include/xrpl/hook/xahau.h"
|
||||
TEMP_DIR="${SCRIPT_DIR}/.temp"
|
||||
|
||||
# Hook file mappings (space-separated: name:file)
|
||||
HOOK_FILES=(
|
||||
"GovernanceHook:govern.wasm"
|
||||
"RewardHook:reward.wasm"
|
||||
# "MintHook:mint.wasm"
|
||||
)
|
||||
|
||||
# Cleanup function
|
||||
cleanup() {
|
||||
local exit_code=$?
|
||||
if [ ${exit_code} -eq 0 ] && [ -d "${TEMP_DIR}" ]; then
|
||||
rm -rf "${TEMP_DIR}"
|
||||
elif [ ${exit_code} -ne 0 ]; then
|
||||
echo -e "${RED}Error: Script failed with exit code ${exit_code}${NC}" >&2
|
||||
if [ -d "${TEMP_DIR}" ]; then
|
||||
echo -e "${YELLOW}Temp files preserved at: ${TEMP_DIR}${NC}" >&2
|
||||
fi
|
||||
fi
|
||||
exit ${exit_code}
|
||||
}
|
||||
|
||||
trap cleanup EXIT INT TERM
|
||||
|
||||
# Tool verification
|
||||
echo -e "${BLUE}==> Checking required tools...${NC}"
|
||||
REQUIRED_TOOLS=("make" "xxd" "sed" "clang-format" "wasm-opt")
|
||||
for tool in "${REQUIRED_TOOLS[@]}"; do
|
||||
if ! command -v "${tool}" &> /dev/null; then
|
||||
echo -e "${RED}Error: Required tool '${tool}' not found${NC}" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo -e "${GREEN} ✓ ${tool}${NC}"
|
||||
done
|
||||
|
||||
# Verify wasm-opt version is exactly 100
|
||||
WASM_OPT_VERSION=$(wasm-opt --version | grep -oE '[0-9]+' | head -1)
|
||||
if [ "${WASM_OPT_VERSION}" != "100" ]; then
|
||||
echo -e "${RED}Error: wasm-opt version must be 100, but found ${WASM_OPT_VERSION}${NC}" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo -e "${GREEN} ✓ wasm-opt version 100${NC}"
|
||||
|
||||
# Verify xahau.h exists
|
||||
if [ ! -f "${XAHAU_H}" ]; then
|
||||
echo -e "${RED}Error: xahau.h not found at ${XAHAU_H}${NC}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create temp directory
|
||||
mkdir -p "${TEMP_DIR}"
|
||||
|
||||
# Build all WASM files
|
||||
echo -e "${BLUE}==> Building WASM files with 'make all'...${NC}"
|
||||
cd "${SCRIPT_DIR}"
|
||||
make all
|
||||
echo -e "${GREEN} Build completed successfully${NC}"
|
||||
|
||||
# Function to convert WASM to hex array
|
||||
wasm_to_hex_array() {
|
||||
local wasm_file="$1"
|
||||
local indent=" "
|
||||
|
||||
if [ ! -f "${wasm_file}" ]; then
|
||||
echo -e "${RED}Error: WASM file not found: ${wasm_file}${NC}" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Convert to hex with xxd, format with sed
|
||||
xxd -p -u -c 10 "${wasm_file}" | \
|
||||
sed 's/../0x&U,/g' | \
|
||||
sed "s/^/${indent}/g" | \
|
||||
sed '$ s/,$//'
|
||||
}
|
||||
|
||||
# Function to update hook array in xahau.h
|
||||
update_hook_array() {
|
||||
local hook_name="$1"
|
||||
local hex_array="$2"
|
||||
local temp_file="${TEMP_DIR}/xahau.h.tmp"
|
||||
|
||||
echo -e "${BLUE}==> Updating ${hook_name}...${NC}"
|
||||
|
||||
# Check if hook already exists
|
||||
if grep -q "static const std::vector<uint8_t> ${hook_name} = {" "${XAHAU_H}"; then
|
||||
echo -e "${YELLOW} Replacing existing ${hook_name}${NC}"
|
||||
|
||||
# Use awk to replace the array content
|
||||
awk -v hook="${hook_name}" -v hex="${hex_array}" '
|
||||
BEGIN { in_array=0 }
|
||||
{
|
||||
if ($0 ~ "static const std::vector<uint8_t> " hook " = {") {
|
||||
print $0
|
||||
print hex
|
||||
in_array=1
|
||||
next
|
||||
}
|
||||
if (in_array && $0 ~ /};/) {
|
||||
print "};"
|
||||
in_array=0
|
||||
next
|
||||
}
|
||||
if (!in_array) {
|
||||
print $0
|
||||
}
|
||||
}
|
||||
' "${XAHAU_H}" > "${temp_file}"
|
||||
|
||||
mv "${temp_file}" "${XAHAU_H}"
|
||||
else
|
||||
echo -e "${YELLOW} Adding new ${hook_name}${NC}"
|
||||
|
||||
# Find the position before #endif and add the new hook
|
||||
awk -v hook="${hook_name}" -v hex="${hex_array}" '
|
||||
{
|
||||
if ($0 ~ /#endif.*XAHAU_GENESIS_HOOKS/) {
|
||||
print ""
|
||||
print "static const std::vector<uint8_t> " hook " = {"
|
||||
print hex
|
||||
print "};"
|
||||
print ""
|
||||
print $0
|
||||
} else {
|
||||
print $0
|
||||
}
|
||||
}
|
||||
' "${XAHAU_H}" > "${temp_file}"
|
||||
|
||||
mv "${temp_file}" "${XAHAU_H}"
|
||||
fi
|
||||
|
||||
echo -e "${GREEN} ✓ ${hook_name} updated${NC}"
|
||||
}
|
||||
|
||||
# Process each hook
|
||||
for hook_entry in "${HOOK_FILES[@]}"; do
|
||||
hook_name="${hook_entry%%:*}"
|
||||
wasm_file="${SCRIPT_DIR}/${hook_entry##*:}"
|
||||
|
||||
echo -e "${BLUE}==> Converting ${wasm_file} to hex array...${NC}"
|
||||
hex_array=$(wasm_to_hex_array "${wasm_file}")
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo -e "${RED}Error: Failed to convert ${wasm_file}${NC}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${GREEN} Conversion successful ($(echo "${hex_array}" | wc -l) lines)${NC}"
|
||||
|
||||
update_hook_array "${hook_name}" "${hex_array}"
|
||||
done
|
||||
|
||||
# Format with clang-format
|
||||
echo -e "${BLUE}==> Formatting with clang-format...${NC}"
|
||||
cp "${XAHAU_H}" "${TEMP_DIR}/xahau.h.before_format"
|
||||
clang-format -i "${XAHAU_H}"
|
||||
echo -e "${GREEN} Formatting completed${NC}"
|
||||
|
||||
# Verification
|
||||
echo -e "${BLUE}==> Verifying changes...${NC}"
|
||||
for hook_entry in "${HOOK_FILES[@]}"; do
|
||||
hook_name="${hook_entry%%:*}"
|
||||
if grep -q "static const std::vector<uint8_t> ${hook_name} = {" "${XAHAU_H}"; then
|
||||
echo -e "${GREEN} ✓ ${hook_name} found in xahau.h${NC}"
|
||||
else
|
||||
echo -e "${RED} ✗ ${hook_name} NOT found in xahau.h${NC}" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
# Show summary
|
||||
echo ""
|
||||
echo -e "${GREEN}========================================${NC}"
|
||||
echo -e "${GREEN}Successfully updated xahau.h${NC}"
|
||||
echo -e "${GREEN}========================================${NC}"
|
||||
echo -e "Updated hooks:"
|
||||
for hook_entry in "${HOOK_FILES[@]}"; do
|
||||
hook_name="${hook_entry%%:*}"
|
||||
wasm_file="${SCRIPT_DIR}/${hook_entry##*:}"
|
||||
size=$(wc -c < "${wasm_file}" | tr -d ' ')
|
||||
echo -e " - ${hook_name}: ${size} bytes"
|
||||
done
|
||||
echo ""
|
||||
echo -e "File location: ${XAHAU_H}"
|
||||
echo ""
|
||||
@@ -1,46 +0,0 @@
|
||||
// For documentation please see: https://xrpl-hooks.readme.io/reference/
|
||||
// Generated using generate_error.sh
|
||||
#ifndef HOOK_ERROR_CODES
|
||||
#define SUCCESS 0
|
||||
#define OUT_OF_BOUNDS -1
|
||||
#define INTERNAL_ERROR -2
|
||||
#define TOO_BIG -3
|
||||
#define TOO_SMALL -4
|
||||
#define DOESNT_EXIST -5
|
||||
#define NO_FREE_SLOTS -6
|
||||
#define INVALID_ARGUMENT -7
|
||||
#define ALREADY_SET -8
|
||||
#define PREREQUISITE_NOT_MET -9
|
||||
#define FEE_TOO_LARGE -10
|
||||
#define EMISSION_FAILURE -11
|
||||
#define TOO_MANY_NONCES -12
|
||||
#define TOO_MANY_EMITTED_TXN -13
|
||||
#define NOT_IMPLEMENTED -14
|
||||
#define INVALID_ACCOUNT -15
|
||||
#define GUARD_VIOLATION -16
|
||||
#define INVALID_FIELD -17
|
||||
#define PARSE_ERROR -18
|
||||
#define RC_ROLLBACK -19
|
||||
#define RC_ACCEPT -20
|
||||
#define NO_SUCH_KEYLET -21
|
||||
#define NOT_AN_ARRAY -22
|
||||
#define NOT_AN_OBJECT -23
|
||||
#define INVALID_FLOAT -10024
|
||||
#define DIVISION_BY_ZERO -25
|
||||
#define MANTISSA_OVERSIZED -26
|
||||
#define MANTISSA_UNDERSIZED -27
|
||||
#define EXPONENT_OVERSIZED -28
|
||||
#define EXPONENT_UNDERSIZED -29
|
||||
#define OVERFLOW -30
|
||||
#define NOT_IOU_AMOUNT -31
|
||||
#define NOT_AN_AMOUNT -32
|
||||
#define CANT_RETURN_NEGATIVE -33
|
||||
#define NOT_AUTHORIZED -34
|
||||
#define PREVIOUS_FAILURE_PREVENTS_RETRY -35
|
||||
#define TOO_MANY_PARAMS -36
|
||||
#define INVALID_TXN -37
|
||||
#define RESERVE_INSUFFICIENT -38
|
||||
#define COMPLEX_NOT_SUPPORTED -39
|
||||
#define DOES_NOT_MATCH -40
|
||||
#define HOOK_ERROR_CODES
|
||||
#endif //HOOK_ERROR_CODES
|
||||
@@ -1,352 +0,0 @@
|
||||
// For documentation please see: https://xrpl-hooks.readme.io/reference/
|
||||
// Generated using generate_extern.sh
|
||||
#include <stdint.h>
|
||||
#ifndef HOOK_EXTERN
|
||||
|
||||
extern int32_t __attribute__((noduplicate))
|
||||
_g(uint32_t guard_id, uint32_t maxiter);
|
||||
|
||||
extern int64_t
|
||||
accept(uint32_t read_ptr, uint32_t read_len, int64_t error_code);
|
||||
|
||||
extern int64_t
|
||||
emit(
|
||||
uint32_t write_ptr,
|
||||
uint32_t write_len,
|
||||
uint32_t read_ptr,
|
||||
uint32_t read_len);
|
||||
|
||||
extern int64_t
|
||||
etxn_burden(void);
|
||||
|
||||
extern int64_t
|
||||
etxn_details(uint32_t write_ptr, uint32_t write_len);
|
||||
|
||||
extern int64_t
|
||||
etxn_fee_base(uint32_t read_ptr, uint32_t read_len);
|
||||
|
||||
extern int64_t
|
||||
etxn_generation(void);
|
||||
|
||||
extern int64_t
|
||||
etxn_nonce(uint32_t write_ptr, uint32_t write_len);
|
||||
|
||||
extern int64_t
|
||||
etxn_reserve(uint32_t count);
|
||||
|
||||
extern int64_t
|
||||
fee_base(void);
|
||||
|
||||
extern int64_t
|
||||
float_compare(int64_t float1, int64_t float2, uint32_t mode);
|
||||
|
||||
extern int64_t
|
||||
float_divide(int64_t float1, int64_t float2);
|
||||
|
||||
extern int64_t
|
||||
float_exponent(int64_t float1);
|
||||
|
||||
extern int64_t
|
||||
float_exponent_set(int64_t float1, int32_t exponent);
|
||||
|
||||
extern int64_t
|
||||
float_int(int64_t float1, uint32_t decimal_places, uint32_t abs);
|
||||
|
||||
extern int64_t
|
||||
float_invert(int64_t float1);
|
||||
|
||||
extern int64_t
|
||||
float_log(int64_t float1);
|
||||
|
||||
extern int64_t
|
||||
float_mantissa(int64_t float1);
|
||||
|
||||
extern int64_t
|
||||
float_mantissa_set(int64_t float1, int64_t mantissa);
|
||||
|
||||
extern int64_t
|
||||
float_mulratio(
|
||||
int64_t float1,
|
||||
uint32_t round_up,
|
||||
uint32_t numerator,
|
||||
uint32_t denominator);
|
||||
|
||||
extern int64_t
|
||||
float_multiply(int64_t float1, int64_t float2);
|
||||
|
||||
extern int64_t
|
||||
float_negate(int64_t float1);
|
||||
|
||||
extern int64_t
|
||||
float_one(void);
|
||||
|
||||
extern int64_t
|
||||
float_root(int64_t float1, uint32_t n);
|
||||
|
||||
extern int64_t
|
||||
float_set(int32_t exponent, int64_t mantissa);
|
||||
|
||||
extern int64_t
|
||||
float_sign(int64_t float1);
|
||||
|
||||
extern int64_t
|
||||
float_sign_set(int64_t float1, uint32_t negative);
|
||||
|
||||
extern int64_t
|
||||
float_sto(
|
||||
uint32_t write_ptr,
|
||||
uint32_t write_len,
|
||||
uint32_t cread_ptr,
|
||||
uint32_t cread_len,
|
||||
uint32_t iread_ptr,
|
||||
uint32_t iread_len,
|
||||
int64_t float1,
|
||||
uint32_t field_code);
|
||||
|
||||
extern int64_t
|
||||
float_sto_set(uint32_t read_ptr, uint32_t read_len);
|
||||
|
||||
extern int64_t
|
||||
float_sum(int64_t float1, int64_t float2);
|
||||
|
||||
extern int64_t
|
||||
hook_account(uint32_t write_ptr, uint32_t write_len);
|
||||
|
||||
extern int64_t
|
||||
hook_again(void);
|
||||
|
||||
extern int64_t
|
||||
hook_hash(uint32_t write_ptr, uint32_t write_len, int32_t hook_no);
|
||||
|
||||
extern int64_t
|
||||
hook_param(
|
||||
uint32_t write_ptr,
|
||||
uint32_t write_len,
|
||||
uint32_t read_ptr,
|
||||
uint32_t read_len);
|
||||
|
||||
extern int64_t
|
||||
otxn_param(
|
||||
uint32_t write_ptr,
|
||||
uint32_t write_len,
|
||||
uint32_t read_ptr,
|
||||
uint32_t read_len);
|
||||
|
||||
extern int64_t
|
||||
hook_param_set(
|
||||
uint32_t read_ptr,
|
||||
uint32_t read_len,
|
||||
uint32_t kread_ptr,
|
||||
uint32_t kread_len,
|
||||
uint32_t hread_ptr,
|
||||
uint32_t hread_len);
|
||||
|
||||
extern int64_t
|
||||
hook_pos(void);
|
||||
|
||||
extern int64_t
|
||||
hook_skip(uint32_t read_ptr, uint32_t read_len, uint32_t flags);
|
||||
|
||||
extern int64_t
|
||||
ledger_keylet(
|
||||
uint32_t write_ptr,
|
||||
uint32_t write_len,
|
||||
uint32_t lread_ptr,
|
||||
uint32_t lread_len,
|
||||
uint32_t hread_ptr,
|
||||
uint32_t hread_len);
|
||||
|
||||
extern int64_t
|
||||
ledger_last_hash(uint32_t write_ptr, uint32_t write_len);
|
||||
|
||||
extern int64_t
|
||||
ledger_last_time(void);
|
||||
|
||||
extern int64_t
|
||||
ledger_nonce(uint32_t write_ptr, uint32_t write_len);
|
||||
|
||||
extern int64_t
|
||||
ledger_seq(void);
|
||||
|
||||
extern int64_t
|
||||
meta_slot(uint32_t slot_no);
|
||||
|
||||
extern int64_t
|
||||
otxn_burden(void);
|
||||
|
||||
extern int64_t
|
||||
otxn_field(uint32_t write_ptr, uint32_t write_len, uint32_t field_id);
|
||||
|
||||
extern int64_t
|
||||
otxn_field_txt(uint32_t write_ptr, uint32_t write_len, uint32_t field_id);
|
||||
|
||||
extern int64_t
|
||||
otxn_generation(void);
|
||||
|
||||
extern int64_t
|
||||
otxn_id(uint32_t write_ptr, uint32_t write_len, uint32_t flags);
|
||||
|
||||
extern int64_t
|
||||
otxn_slot(uint32_t slot_no);
|
||||
|
||||
extern int64_t
|
||||
otxn_type(void);
|
||||
|
||||
extern int64_t
|
||||
rollback(uint32_t read_ptr, uint32_t read_len, int64_t error_code);
|
||||
|
||||
extern int64_t
|
||||
slot(uint32_t write_ptr, uint32_t write_len, uint32_t slot);
|
||||
|
||||
extern int64_t
|
||||
slot_clear(uint32_t slot);
|
||||
|
||||
extern int64_t
|
||||
slot_count(uint32_t slot);
|
||||
|
||||
extern int64_t
|
||||
slot_float(uint32_t slot_no);
|
||||
|
||||
extern int64_t
|
||||
slot_id(uint32_t write_ptr, uint32_t write_len, uint32_t slot);
|
||||
|
||||
extern int64_t
|
||||
slot_set(uint32_t read_ptr, uint32_t read_len, uint32_t slot);
|
||||
|
||||
extern int64_t
|
||||
slot_size(uint32_t slot);
|
||||
|
||||
extern int64_t
|
||||
slot_subarray(uint32_t parent_slot, uint32_t array_id, uint32_t new_slot);
|
||||
|
||||
extern int64_t
|
||||
slot_subfield(uint32_t parent_slot, uint32_t field_id, uint32_t new_slot);
|
||||
|
||||
extern int64_t
|
||||
slot_type(uint32_t slot_no, uint32_t flags);
|
||||
|
||||
extern int64_t
|
||||
state(
|
||||
uint32_t write_ptr,
|
||||
uint32_t write_len,
|
||||
uint32_t kread_ptr,
|
||||
uint32_t kread_len);
|
||||
|
||||
extern int64_t
|
||||
state_foreign(
|
||||
uint32_t write_ptr,
|
||||
uint32_t write_len,
|
||||
uint32_t kread_ptr,
|
||||
uint32_t kread_len,
|
||||
uint32_t nread_ptr,
|
||||
uint32_t nread_len,
|
||||
uint32_t aread_ptr,
|
||||
uint32_t aread_len);
|
||||
|
||||
extern int64_t
|
||||
state_foreign_set(
|
||||
uint32_t read_ptr,
|
||||
uint32_t read_len,
|
||||
uint32_t kread_ptr,
|
||||
uint32_t kread_len,
|
||||
uint32_t nread_ptr,
|
||||
uint32_t nread_len,
|
||||
uint32_t aread_ptr,
|
||||
uint32_t aread_len);
|
||||
|
||||
extern int64_t
|
||||
state_set(
|
||||
uint32_t read_ptr,
|
||||
uint32_t read_len,
|
||||
uint32_t kread_ptr,
|
||||
uint32_t kread_len);
|
||||
|
||||
extern int64_t
|
||||
sto_emplace(
|
||||
uint32_t write_ptr,
|
||||
uint32_t write_len,
|
||||
uint32_t sread_ptr,
|
||||
uint32_t sread_len,
|
||||
uint32_t fread_ptr,
|
||||
uint32_t fread_len,
|
||||
uint32_t field_id);
|
||||
|
||||
extern int64_t
|
||||
sto_erase(
|
||||
uint32_t write_ptr,
|
||||
uint32_t write_len,
|
||||
uint32_t read_ptr,
|
||||
uint32_t read_len,
|
||||
uint32_t field_id);
|
||||
|
||||
extern int64_t
|
||||
sto_subarray(uint32_t read_ptr, uint32_t read_len, uint32_t array_id);
|
||||
|
||||
extern int64_t
|
||||
sto_subfield(uint32_t read_ptr, uint32_t read_len, uint32_t field_id);
|
||||
|
||||
extern int64_t
|
||||
sto_validate(uint32_t tread_ptr, uint32_t tread_len);
|
||||
|
||||
extern int64_t
|
||||
trace(
|
||||
uint32_t mread_ptr,
|
||||
uint32_t mread_len,
|
||||
uint32_t dread_ptr,
|
||||
uint32_t dread_len,
|
||||
uint32_t as_hex);
|
||||
|
||||
extern int64_t
|
||||
trace_float(uint32_t read_ptr, uint32_t read_len, int64_t float1);
|
||||
|
||||
extern int64_t
|
||||
trace_num(uint32_t read_ptr, uint32_t read_len, int64_t number);
|
||||
|
||||
extern int64_t
|
||||
trace_slot(uint32_t read_ptr, uint32_t read_len, uint32_t slot);
|
||||
|
||||
extern int64_t
|
||||
util_accid(
|
||||
uint32_t write_ptr,
|
||||
uint32_t write_len,
|
||||
uint32_t read_ptr,
|
||||
uint32_t read_len);
|
||||
|
||||
extern int64_t
|
||||
util_keylet(
|
||||
uint32_t write_ptr,
|
||||
uint32_t write_len,
|
||||
uint32_t keylet_type,
|
||||
uint32_t a,
|
||||
uint32_t b,
|
||||
uint32_t c,
|
||||
uint32_t d,
|
||||
uint32_t e,
|
||||
uint32_t f);
|
||||
|
||||
extern int64_t
|
||||
util_raddr(
|
||||
uint32_t write_ptr,
|
||||
uint32_t write_len,
|
||||
uint32_t read_ptr,
|
||||
uint32_t read_len);
|
||||
|
||||
extern int64_t
|
||||
util_sha512h(
|
||||
uint32_t write_ptr,
|
||||
uint32_t write_len,
|
||||
uint32_t read_ptr,
|
||||
uint32_t read_len);
|
||||
|
||||
extern int64_t
|
||||
util_verify(
|
||||
uint32_t dread_ptr,
|
||||
uint32_t dread_len,
|
||||
uint32_t sread_ptr,
|
||||
uint32_t sread_len,
|
||||
uint32_t kread_ptr,
|
||||
uint32_t kread_len);
|
||||
|
||||
extern int64_t xpop_slot(uint32_t, uint32_t);
|
||||
#define HOOK_EXTERN
|
||||
#endif // HOOK_EXTERN
|
||||
@@ -1,50 +0,0 @@
|
||||
/**
|
||||
* Hook API include file
|
||||
*
|
||||
* Note to the reader:
|
||||
* This include defines two types of things: external functions and macros
|
||||
* Functions are used sparingly because a non-inlining compiler may produce
|
||||
* undesirable output.
|
||||
*
|
||||
* Find documentation here: https://xrpl-hooks.readme.io/reference/
|
||||
*/
|
||||
|
||||
#ifndef HOOKAPI_INCLUDED
|
||||
#define HOOKAPI_INCLUDED 1
|
||||
|
||||
#define KEYLET_HOOK 1
|
||||
#define KEYLET_HOOK_STATE 2
|
||||
#define KEYLET_ACCOUNT 3
|
||||
#define KEYLET_AMENDMENTS 4
|
||||
#define KEYLET_CHILD 5
|
||||
#define KEYLET_SKIP 6
|
||||
#define KEYLET_FEES 7
|
||||
#define KEYLET_NEGATIVE_UNL 8
|
||||
#define KEYLET_LINE 9
|
||||
#define KEYLET_OFFER 10
|
||||
#define KEYLET_QUALITY 11
|
||||
#define KEYLET_EMITTED_DIR 12
|
||||
#define KEYLET_TICKET 13
|
||||
#define KEYLET_SIGNERS 14
|
||||
#define KEYLET_CHECK 15
|
||||
#define KEYLET_DEPOSIT_PREAUTH 16
|
||||
#define KEYLET_UNCHECKED 17
|
||||
#define KEYLET_OWNER_DIR 18
|
||||
#define KEYLET_PAGE 19
|
||||
#define KEYLET_ESCROW 20
|
||||
#define KEYLET_PAYCHAN 21
|
||||
#define KEYLET_EMITTED 22
|
||||
#define KEYLET_NFT_OFFER 23
|
||||
#define KEYLET_HOOK_DEFINITION 24
|
||||
|
||||
#define COMPARE_EQUAL 1U
|
||||
#define COMPARE_LESS 2U
|
||||
#define COMPARE_GREATER 4U
|
||||
|
||||
#include "error.h"
|
||||
#include "extern.h"
|
||||
#include "sfcodes.h"
|
||||
#include "macro.h"
|
||||
#include "types.h"
|
||||
|
||||
#endif
|
||||
@@ -1,679 +0,0 @@
|
||||
/**
|
||||
* These are helper macros for writing hooks, all of them are optional as is including hookmacro.h at all
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "hookapi.h"
|
||||
#include "sfcodes.h"
|
||||
|
||||
#ifndef HOOKMACROS_INCLUDED
|
||||
#define HOOKMACROS_INCLUDED 1
|
||||
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define DEBUG 0
|
||||
#else
|
||||
#define DEBUG 1
|
||||
#endif
|
||||
|
||||
#define TRACEVAR(v) if (DEBUG) trace_num((uint32_t)(#v), (uint32_t)(sizeof(#v) - 1), (int64_t)v);
|
||||
#define TRACEHEX(v) if (DEBUG) trace((uint32_t)(#v), (uint32_t)(sizeof(#v) - 1), (uint32_t)(v), (uint32_t)(sizeof(v)), 1);
|
||||
#define TRACEXFL(v) if (DEBUG) trace_float((uint32_t)(#v), (uint32_t)(sizeof(#v) - 1), (int64_t)v);
|
||||
#define TRACESTR(v) if (DEBUG) trace((uint32_t)(#v), (uint32_t)(sizeof(#v) - 1), (uint32_t)(v), sizeof(v), 0);
|
||||
|
||||
// hook developers should use this guard macro, simply GUARD(<maximum iterations>)
|
||||
#define GUARD(maxiter) _g((1ULL << 31U) + __LINE__, (maxiter)+1)
|
||||
#define GUARDM(maxiter, n) _g(( (1ULL << 31U) + (__LINE__ << 16) + n), (maxiter)+1)
|
||||
|
||||
#define SBUF(str) (uint32_t)(str), sizeof(str)
|
||||
|
||||
#define REQUIRE(cond, str)\
|
||||
{\
|
||||
if (!(cond))\
|
||||
rollback(SBUF(str), __LINE__);\
|
||||
}
|
||||
|
||||
// make a report buffer as a c-string
|
||||
// provide a name for a buffer to declare (buf)
|
||||
// provide a static string
|
||||
// provide an integer to print after the string
|
||||
#define RBUF(buf, out_len, str, num)\
|
||||
unsigned char buf[sizeof(str) + 21];\
|
||||
int out_len = 0;\
|
||||
{\
|
||||
int i = 0;\
|
||||
for (; GUARDM(sizeof(str),1),i < sizeof(str); ++i)\
|
||||
(buf)[i] = str[i];\
|
||||
if ((buf)[sizeof(str)-1] == 0) i--;\
|
||||
if ((num) < 0) (buf)[i++] = '-';\
|
||||
uint64_t unsigned_num = (uint64_t)( (num) < 0 ? (num) * -1 : (num) );\
|
||||
uint64_t j = 10000000000000000000ULL;\
|
||||
int start = 1;\
|
||||
for (; GUARDM(20,2), unsigned_num > 0 && j > 0; j /= 10)\
|
||||
{\
|
||||
unsigned char digit = ( unsigned_num / j ) % 10;\
|
||||
if (digit == 0 && start)\
|
||||
continue;\
|
||||
start = 0;\
|
||||
(buf)[i++] = '0' + digit;\
|
||||
}\
|
||||
(buf)[i] = '\0';\
|
||||
out_len = i;\
|
||||
}
|
||||
|
||||
#define RBUF2(buff, out_len, str, num, str2, num2)\
|
||||
unsigned char buff[sizeof(str) + sizeof(str2) + 42];\
|
||||
int out_len = 0;\
|
||||
{\
|
||||
unsigned char* buf = buff;\
|
||||
int i = 0;\
|
||||
for (; GUARDM(sizeof(str),1),i < sizeof(str); ++i)\
|
||||
(buf)[i] = str[i];\
|
||||
if ((buf)[sizeof(str)-1] == 0) i--;\
|
||||
if ((num) < 0) (buf)[i++] = '-';\
|
||||
uint64_t unsigned_num = (uint64_t)( (num) < 0 ? (num) * -1 : (num) );\
|
||||
uint64_t j = 10000000000000000000ULL;\
|
||||
int start = 1;\
|
||||
for (; GUARDM(20,2), unsigned_num > 0 && j > 0; j /= 10)\
|
||||
{\
|
||||
unsigned char digit = ( unsigned_num / j ) % 10;\
|
||||
if (digit == 0 && start)\
|
||||
continue;\
|
||||
start = 0;\
|
||||
(buf)[i++] = '0' + digit;\
|
||||
}\
|
||||
buf += i;\
|
||||
out_len += i;\
|
||||
i = 0;\
|
||||
for (; GUARDM(sizeof(str2),3),i < sizeof(str2); ++i)\
|
||||
(buf)[i] = str2[i];\
|
||||
if ((buf)[sizeof(str2)-1] == 0) i--;\
|
||||
if ((num2) < 0) (buf)[i++] = '-';\
|
||||
unsigned_num = (uint64_t)( (num2) < 0 ? (num2) * -1 : (num2) );\
|
||||
j = 10000000000000000000ULL;\
|
||||
start = 1;\
|
||||
for (; GUARDM(20,4), unsigned_num > 0 && j > 0; j /= 10)\
|
||||
{\
|
||||
unsigned char digit = ( unsigned_num / j ) % 10;\
|
||||
if (digit == 0 && start)\
|
||||
continue;\
|
||||
start = 0;\
|
||||
(buf)[i++] = '0' + digit;\
|
||||
}\
|
||||
(buf)[i] = '\0';\
|
||||
out_len += i;\
|
||||
}
|
||||
|
||||
#define CLEARBUF(b)\
|
||||
{\
|
||||
for (int x = 0; GUARD(sizeof(b)), x < sizeof(b); ++x)\
|
||||
b[x] = 0;\
|
||||
}
|
||||
|
||||
// returns an in64_t, negative if error, non-negative if valid drops
|
||||
#define AMOUNT_TO_DROPS(amount_buffer)\
|
||||
(((amount_buffer)[0] >> 7) ? -2 : (\
|
||||
((((uint64_t)((amount_buffer)[0])) & 0xb00111111) << 56) +\
|
||||
(((uint64_t)((amount_buffer)[1])) << 48) +\
|
||||
(((uint64_t)((amount_buffer)[2])) << 40) +\
|
||||
(((uint64_t)((amount_buffer)[3])) << 32) +\
|
||||
(((uint64_t)((amount_buffer)[4])) << 24) +\
|
||||
(((uint64_t)((amount_buffer)[5])) << 16) +\
|
||||
(((uint64_t)((amount_buffer)[6])) << 8) +\
|
||||
(((uint64_t)((amount_buffer)[7])))))
|
||||
|
||||
#define SUB_OFFSET(x) ((int32_t)(x >> 32))
|
||||
#define SUB_LENGTH(x) ((int32_t)(x & 0xFFFFFFFFULL))
|
||||
|
||||
#define BUFFER_EQUAL_20(buf1, buf2)\
|
||||
(\
|
||||
*(((uint64_t*)(buf1)) + 0) == *(((uint64_t*)(buf2)) + 0) &&\
|
||||
*(((uint64_t*)(buf1)) + 1) == *(((uint64_t*)(buf2)) + 1) &&\
|
||||
*(((uint32_t*)(buf1)) + 4) == *(((uint32_t*)(buf2)) + 4))
|
||||
|
||||
#define BUFFER_EQUAL_32(buf1, buf2)\
|
||||
(\
|
||||
*(((uint64_t*)(buf1)) + 0) == *(((uint64_t*)(buf2)) + 0) &&\
|
||||
*(((uint64_t*)(buf1)) + 1) == *(((uint64_t*)(buf2)) + 1) &&\
|
||||
*(((uint64_t*)(buf1)) + 2) == *(((uint64_t*)(buf2)) + 2) &&\
|
||||
*(((uint64_t*)(buf1)) + 3) == *(((uint64_t*)(buf2)) + 3))
|
||||
|
||||
|
||||
// when using this macro buf1len may be dynamic but buf2len must be static
|
||||
// provide n >= 1 to indicate how many times the macro will be hit on the line of code
|
||||
// e.g. if it is in a loop that loops 10 times n = 10
|
||||
|
||||
#define BUFFER_EQUAL_GUARD(output, buf1, buf1len, buf2, buf2len, n)\
|
||||
{\
|
||||
output = ((buf1len) == (buf2len) ? 1 : 0);\
|
||||
for (int x = 0; GUARDM( (buf2len) * (n), 1 ), output && x < (buf2len);\
|
||||
++x)\
|
||||
output = *(((uint8_t*)(buf1)) + x) == *(((uint8_t*)(buf2)) + x);\
|
||||
}
|
||||
|
||||
#define BUFFER_SWAP(x,y)\
|
||||
{\
|
||||
uint8_t* z = x;\
|
||||
x = y;\
|
||||
y = z;\
|
||||
}
|
||||
|
||||
#define ACCOUNT_COMPARE(compare_result, buf1, buf2)\
|
||||
{\
|
||||
compare_result = 0;\
|
||||
for (int i = 0; GUARD(20), i < 20; ++i)\
|
||||
{\
|
||||
if (buf1[i] > buf2[i])\
|
||||
{\
|
||||
compare_result = 1;\
|
||||
break;\
|
||||
}\
|
||||
else if (buf1[i] < buf2[i])\
|
||||
{\
|
||||
compare_result = -1;\
|
||||
break;\
|
||||
}\
|
||||
}\
|
||||
}
|
||||
|
||||
#define BUFFER_EQUAL_STR_GUARD(output, buf1, buf1len, str, n)\
|
||||
BUFFER_EQUAL_GUARD(output, buf1, buf1len, str, (sizeof(str)-1), n)
|
||||
|
||||
#define BUFFER_EQUAL_STR(output, buf1, buf1len, str)\
|
||||
BUFFER_EQUAL_GUARD(output, buf1, buf1len, str, (sizeof(str)-1), 1)
|
||||
|
||||
#define BUFFER_EQUAL(output, buf1, buf2, compare_len)\
|
||||
BUFFER_EQUAL_GUARD(output, buf1, compare_len, buf2, compare_len, 1)
|
||||
|
||||
#define UINT16_TO_BUF(buf_raw, i)\
|
||||
{\
|
||||
unsigned char* buf = (unsigned char*)buf_raw;\
|
||||
buf[0] = (((uint64_t)i) >> 8) & 0xFFUL;\
|
||||
buf[1] = (((uint64_t)i) >> 0) & 0xFFUL;\
|
||||
}
|
||||
|
||||
#define UINT16_FROM_BUF(buf)\
|
||||
(((uint64_t)((buf)[0]) << 8) +\
|
||||
((uint64_t)((buf)[1]) << 0))
|
||||
|
||||
#define UINT32_TO_BUF(buf_raw, i)\
|
||||
{\
|
||||
unsigned char* buf = (unsigned char*)buf_raw;\
|
||||
buf[0] = (((uint64_t)i) >> 24) & 0xFFUL;\
|
||||
buf[1] = (((uint64_t)i) >> 16) & 0xFFUL;\
|
||||
buf[2] = (((uint64_t)i) >> 8) & 0xFFUL;\
|
||||
buf[3] = (((uint64_t)i) >> 0) & 0xFFUL;\
|
||||
}
|
||||
|
||||
|
||||
#define UINT32_FROM_BUF(buf)\
|
||||
(((uint64_t)((buf)[0]) << 24) +\
|
||||
((uint64_t)((buf)[1]) << 16) +\
|
||||
((uint64_t)((buf)[2]) << 8) +\
|
||||
((uint64_t)((buf)[3]) << 0))
|
||||
|
||||
#define UINT64_TO_BUF(buf_raw, i)\
|
||||
{\
|
||||
unsigned char* buf = (unsigned char*)buf_raw;\
|
||||
buf[0] = (((uint64_t)i) >> 56) & 0xFFUL;\
|
||||
buf[1] = (((uint64_t)i) >> 48) & 0xFFUL;\
|
||||
buf[2] = (((uint64_t)i) >> 40) & 0xFFUL;\
|
||||
buf[3] = (((uint64_t)i) >> 32) & 0xFFUL;\
|
||||
buf[4] = (((uint64_t)i) >> 24) & 0xFFUL;\
|
||||
buf[5] = (((uint64_t)i) >> 16) & 0xFFUL;\
|
||||
buf[6] = (((uint64_t)i) >> 8) & 0xFFUL;\
|
||||
buf[7] = (((uint64_t)i) >> 0) & 0xFFUL;\
|
||||
}
|
||||
|
||||
|
||||
#define UINT64_FROM_BUF(buf)\
|
||||
(((uint64_t)((buf)[0]) << 56) +\
|
||||
((uint64_t)((buf)[1]) << 48) +\
|
||||
((uint64_t)((buf)[2]) << 40) +\
|
||||
((uint64_t)((buf)[3]) << 32) +\
|
||||
((uint64_t)((buf)[4]) << 24) +\
|
||||
((uint64_t)((buf)[5]) << 16) +\
|
||||
((uint64_t)((buf)[6]) << 8) +\
|
||||
((uint64_t)((buf)[7]) << 0))
|
||||
|
||||
|
||||
#define INT64_FROM_BUF(buf)\
|
||||
((((uint64_t)((buf)[0] & 0x7FU) << 56) +\
|
||||
((uint64_t)((buf)[1]) << 48) +\
|
||||
((uint64_t)((buf)[2]) << 40) +\
|
||||
((uint64_t)((buf)[3]) << 32) +\
|
||||
((uint64_t)((buf)[4]) << 24) +\
|
||||
((uint64_t)((buf)[5]) << 16) +\
|
||||
((uint64_t)((buf)[6]) << 8) +\
|
||||
((uint64_t)((buf)[7]) << 0)) * (buf[0] & 0x80U ? -1 : 1))
|
||||
|
||||
#define INT64_TO_BUF(buf_raw, i)\
|
||||
{\
|
||||
unsigned char* buf = (unsigned char*)buf_raw;\
|
||||
buf[0] = (((uint64_t)i) >> 56) & 0x7FUL;\
|
||||
buf[1] = (((uint64_t)i) >> 48) & 0xFFUL;\
|
||||
buf[2] = (((uint64_t)i) >> 40) & 0xFFUL;\
|
||||
buf[3] = (((uint64_t)i) >> 32) & 0xFFUL;\
|
||||
buf[4] = (((uint64_t)i) >> 24) & 0xFFUL;\
|
||||
buf[5] = (((uint64_t)i) >> 16) & 0xFFUL;\
|
||||
buf[6] = (((uint64_t)i) >> 8) & 0xFFUL;\
|
||||
buf[7] = (((uint64_t)i) >> 0) & 0xFFUL;\
|
||||
if (i < 0) buf[0] |= 0x80U;\
|
||||
}
|
||||
|
||||
#define ttPAYMENT 0
|
||||
#define ttESCROW_CREATE 1
|
||||
#define ttESCROW_FINISH 2
|
||||
#define ttACCOUNT_SET 3
|
||||
#define ttESCROW_CANCEL 4
|
||||
#define ttREGULAR_KEY_SET 5
|
||||
#define ttOFFER_CREATE 7
|
||||
#define ttOFFER_CANCEL 8
|
||||
#define ttTICKET_CREATE 10
|
||||
#define ttSIGNER_LIST_SET 12
|
||||
#define ttPAYCHAN_CREATE 13
|
||||
#define ttPAYCHAN_FUND 14
|
||||
#define ttPAYCHAN_CLAIM 15
|
||||
#define ttCHECK_CREATE 16
|
||||
#define ttCHECK_CASH 17
|
||||
#define ttCHECK_CANCEL 18
|
||||
#define ttDEPOSIT_PREAUTH 19
|
||||
#define ttTRUST_SET 20
|
||||
#define ttACCOUNT_DELETE 21
|
||||
#define ttHOOK_SET 22
|
||||
#define ttNFTOKEN_MINT 25
|
||||
#define ttNFTOKEN_BURN 26
|
||||
#define ttNFTOKEN_CREATE_OFFER 27
|
||||
#define ttNFTOKEN_CANCEL_OFFER 28
|
||||
#define ttNFTOKEN_ACCEPT_OFFER 29
|
||||
#define ttURITOKEN_MINT 45
|
||||
#define ttURITOKEN_BURN 46
|
||||
#define ttURITOKEN_BUY 47
|
||||
#define ttURITOKEN_CREATE_SELL_OFFER 48
|
||||
#define ttURITOKEN_CANCEL_SELL_OFFER 49
|
||||
#define ttCLAIM_REWARD 98
|
||||
#define ttINVOKE 99
|
||||
#define ttAMENDMENT 100
|
||||
#define ttFEE 101
|
||||
#define ttUNL_MODIFY 102
|
||||
#define ttEMIT_FAILURE 103
|
||||
#define tfCANONICAL 0x80000000UL
|
||||
|
||||
#define atACCOUNT 1U
|
||||
#define atOWNER 2U
|
||||
#define atDESTINATION 3U
|
||||
#define atISSUER 4U
|
||||
#define atAUTHORIZE 5U
|
||||
#define atUNAUTHORIZE 6U
|
||||
#define atTARGET 7U
|
||||
#define atREGULARKEY 8U
|
||||
#define atPSEUDOCALLBACK 9U
|
||||
|
||||
#define amAMOUNT 1U
|
||||
#define amBALANCE 2U
|
||||
#define amLIMITAMOUNT 3U
|
||||
#define amTAKERPAYS 4U
|
||||
#define amTAKERGETS 5U
|
||||
#define amLOWLIMIT 6U
|
||||
#define amHIGHLIMIT 7U
|
||||
#define amFEE 8U
|
||||
#define amSENDMAX 9U
|
||||
#define amDELIVERMIN 10U
|
||||
#define amMINIMUMOFFER 16U
|
||||
#define amRIPPLEESCROW 17U
|
||||
#define amDELIVEREDAMOUNT 18U
|
||||
|
||||
/**
|
||||
* RH NOTE -- PAY ATTENTION
|
||||
*
|
||||
* ALL 'ENCODE' MACROS INCREMENT BUF_OUT
|
||||
* THIS IS TO MAKE CHAINING EASY
|
||||
* BUF_OUT IS A SACRIFICIAL POINTER
|
||||
*
|
||||
* 'ENCODE' MACROS WITH CONSTANTS HAVE
|
||||
* ALIASING TO ASSIST YOU WITH ORDER
|
||||
* _TYPECODE_FIELDCODE_ENCODE_MACRO
|
||||
* TO PRODUCE A SERIALIZED OBJECT
|
||||
* IN CANONICAL FORMAT YOU MUST ORDER
|
||||
* FIRST BY TYPE CODE THEN BY FIELD CODE
|
||||
*
|
||||
* ALL 'PREPARE' MACROS PRESERVE POINTERS
|
||||
*
|
||||
**/
|
||||
|
||||
|
||||
#define ENCODE_TL_SIZE 49
|
||||
#define ENCODE_TL(buf_out, tlamt, amount_type)\
|
||||
{\
|
||||
uint8_t uat = amount_type; \
|
||||
buf_out[0] = 0x60U +(uat & 0x0FU ); \
|
||||
for (int i = 1; GUARDM(48, 1), i < 49; ++i)\
|
||||
buf_out[i] = tlamt[i-1];\
|
||||
buf_out += ENCODE_TL_SIZE;\
|
||||
}
|
||||
#define _06_XX_ENCODE_TL(buf_out, drops, amount_type )\
|
||||
ENCODE_TL(buf_out, drops, amount_type );
|
||||
#define ENCODE_TL_AMOUNT(buf_out, drops )\
|
||||
ENCODE_TL(buf_out, drops, amAMOUNT );
|
||||
#define _06_01_ENCODE_TL_AMOUNT(buf_out, drops )\
|
||||
ENCODE_TL_AMOUNT(buf_out, drops );
|
||||
|
||||
|
||||
// Encode drops to serialization format
|
||||
// consumes 9 bytes
|
||||
#define ENCODE_DROPS_SIZE 9
|
||||
#define ENCODE_DROPS(buf_out, drops, amount_type ) \
|
||||
{\
|
||||
uint8_t uat = amount_type; \
|
||||
uint64_t udrops = drops; \
|
||||
buf_out[0] = 0x60U +(uat & 0x0FU ); \
|
||||
buf_out[1] = 0b01000000 + (( udrops >> 56 ) & 0b00111111 ); \
|
||||
buf_out[2] = (udrops >> 48) & 0xFFU; \
|
||||
buf_out[3] = (udrops >> 40) & 0xFFU; \
|
||||
buf_out[4] = (udrops >> 32) & 0xFFU; \
|
||||
buf_out[5] = (udrops >> 24) & 0xFFU; \
|
||||
buf_out[6] = (udrops >> 16) & 0xFFU; \
|
||||
buf_out[7] = (udrops >> 8) & 0xFFU; \
|
||||
buf_out[8] = (udrops >> 0) & 0xFFU; \
|
||||
buf_out += ENCODE_DROPS_SIZE; \
|
||||
}
|
||||
|
||||
#define _06_XX_ENCODE_DROPS(buf_out, drops, amount_type )\
|
||||
ENCODE_DROPS(buf_out, drops, amount_type );
|
||||
|
||||
#define ENCODE_DROPS_AMOUNT(buf_out, drops )\
|
||||
ENCODE_DROPS(buf_out, drops, amAMOUNT );
|
||||
#define _06_01_ENCODE_DROPS_AMOUNT(buf_out, drops )\
|
||||
ENCODE_DROPS_AMOUNT(buf_out, drops );
|
||||
|
||||
#define ENCODE_DROPS_FEE(buf_out, drops )\
|
||||
ENCODE_DROPS(buf_out, drops, amFEE );
|
||||
#define _06_08_ENCODE_DROPS_FEE(buf_out, drops )\
|
||||
ENCODE_DROPS_FEE(buf_out, drops );
|
||||
|
||||
#define ENCODE_TT_SIZE 3
|
||||
#define ENCODE_TT(buf_out, tt )\
|
||||
{\
|
||||
uint8_t utt = tt;\
|
||||
buf_out[0] = 0x12U;\
|
||||
buf_out[1] =(utt >> 8 ) & 0xFFU;\
|
||||
buf_out[2] =(utt >> 0 ) & 0xFFU;\
|
||||
buf_out += ENCODE_TT_SIZE; \
|
||||
}
|
||||
#define _01_02_ENCODE_TT(buf_out, tt)\
|
||||
ENCODE_TT(buf_out, tt);
|
||||
|
||||
|
||||
#define ENCODE_ACCOUNT_SIZE 22
|
||||
#define ENCODE_ACCOUNT(buf_out, account_id, account_type)\
|
||||
{\
|
||||
uint8_t uat = account_type;\
|
||||
buf_out[0] = 0x80U + uat;\
|
||||
buf_out[1] = 0x14U;\
|
||||
*(uint64_t*)(buf_out + 2) = *(uint64_t*)(account_id + 0);\
|
||||
*(uint64_t*)(buf_out + 10) = *(uint64_t*)(account_id + 8);\
|
||||
*(uint32_t*)(buf_out + 18) = *(uint32_t*)(account_id + 16);\
|
||||
buf_out += ENCODE_ACCOUNT_SIZE;\
|
||||
}
|
||||
#define _08_XX_ENCODE_ACCOUNT(buf_out, account_id, account_type)\
|
||||
ENCODE_ACCOUNT(buf_out, account_id, account_type);
|
||||
|
||||
#define ENCODE_ACCOUNT_SRC_SIZE 22
|
||||
#define ENCODE_ACCOUNT_SRC(buf_out, account_id)\
|
||||
ENCODE_ACCOUNT(buf_out, account_id, atACCOUNT);
|
||||
#define _08_01_ENCODE_ACCOUNT_SRC(buf_out, account_id)\
|
||||
ENCODE_ACCOUNT_SRC(buf_out, account_id);
|
||||
|
||||
#define ENCODE_ACCOUNT_DST_SIZE 22
|
||||
#define ENCODE_ACCOUNT_DST(buf_out, account_id)\
|
||||
ENCODE_ACCOUNT(buf_out, account_id, atDESTINATION);
|
||||
#define _08_03_ENCODE_ACCOUNT_DST(buf_out, account_id)\
|
||||
ENCODE_ACCOUNT_DST(buf_out, account_id);
|
||||
|
||||
#define ENCODE_ACCOUNT_OWNER_SIZE 22
|
||||
#define ENCODE_ACCOUNT_OWNER(buf_out, account_id) \
|
||||
ENCODE_ACCOUNT(buf_out, account_id, atOWNER);
|
||||
#define _08_02_ENCODE_ACCOUNT_OWNER(buf_out, account_id) \
|
||||
ENCODE_ACCOUNT_OWNER(buf_out, account_id);
|
||||
|
||||
#define ENCODE_UINT32_COMMON_SIZE 5U
|
||||
#define ENCODE_UINT32_COMMON(buf_out, i, field)\
|
||||
{\
|
||||
uint32_t ui = i; \
|
||||
uint8_t uf = field; \
|
||||
buf_out[0] = 0x20U +(uf & 0x0FU); \
|
||||
buf_out[1] =(ui >> 24 ) & 0xFFU; \
|
||||
buf_out[2] =(ui >> 16 ) & 0xFFU; \
|
||||
buf_out[3] =(ui >> 8 ) & 0xFFU; \
|
||||
buf_out[4] =(ui >> 0 ) & 0xFFU; \
|
||||
buf_out += ENCODE_UINT32_COMMON_SIZE; \
|
||||
}
|
||||
#define _02_XX_ENCODE_UINT32_COMMON(buf_out, i, field)\
|
||||
ENCODE_UINT32_COMMON(buf_out, i, field)\
|
||||
|
||||
#define ENCODE_UINT32_UNCOMMON_SIZE 6U
|
||||
#define ENCODE_UINT32_UNCOMMON(buf_out, i, field)\
|
||||
{\
|
||||
uint32_t ui = i; \
|
||||
uint8_t uf = field; \
|
||||
buf_out[0] = 0x20U; \
|
||||
buf_out[1] = uf; \
|
||||
buf_out[2] =(ui >> 24 ) & 0xFFU; \
|
||||
buf_out[3] =(ui >> 16 ) & 0xFFU; \
|
||||
buf_out[4] =(ui >> 8 ) & 0xFFU; \
|
||||
buf_out[5] =(ui >> 0 ) & 0xFFU; \
|
||||
buf_out += ENCODE_UINT32_UNCOMMON_SIZE; \
|
||||
}
|
||||
#define _02_XX_ENCODE_UINT32_UNCOMMON(buf_out, i, field)\
|
||||
ENCODE_UINT32_UNCOMMON(buf_out, i, field)\
|
||||
|
||||
#define ENCODE_LLS_SIZE 6U
|
||||
#define ENCODE_LLS(buf_out, lls )\
|
||||
ENCODE_UINT32_UNCOMMON(buf_out, lls, 0x1B );
|
||||
#define _02_27_ENCODE_LLS(buf_out, lls )\
|
||||
ENCODE_LLS(buf_out, lls );
|
||||
|
||||
#define ENCODE_FLS_SIZE 6U
|
||||
#define ENCODE_FLS(buf_out, fls )\
|
||||
ENCODE_UINT32_UNCOMMON(buf_out, fls, 0x1A );
|
||||
#define _02_26_ENCODE_FLS(buf_out, fls )\
|
||||
ENCODE_FLS(buf_out, fls );
|
||||
|
||||
#define ENCODE_TAG_SRC_SIZE 5
|
||||
#define ENCODE_TAG_SRC(buf_out, tag )\
|
||||
ENCODE_UINT32_COMMON(buf_out, tag, 0x3U );
|
||||
#define _02_03_ENCODE_TAG_SRC(buf_out, tag )\
|
||||
ENCODE_TAG_SRC(buf_out, tag );
|
||||
|
||||
#define ENCODE_TAG_DST_SIZE 5
|
||||
#define ENCODE_TAG_DST(buf_out, tag )\
|
||||
ENCODE_UINT32_COMMON(buf_out, tag, 0xEU );
|
||||
#define _02_14_ENCODE_TAG_DST(buf_out, tag )\
|
||||
ENCODE_TAG_DST(buf_out, tag );
|
||||
|
||||
#define ENCODE_SEQUENCE_SIZE 5
|
||||
#define ENCODE_SEQUENCE(buf_out, sequence )\
|
||||
ENCODE_UINT32_COMMON(buf_out, sequence, 0x4U );
|
||||
#define _02_04_ENCODE_SEQUENCE(buf_out, sequence )\
|
||||
ENCODE_SEQUENCE(buf_out, sequence );
|
||||
|
||||
#define ENCODE_FLAGS_SIZE 5
|
||||
#define ENCODE_FLAGS(buf_out, tag )\
|
||||
ENCODE_UINT32_COMMON(buf_out, tag, 0x2U );
|
||||
#define _02_02_ENCODE_FLAGS(buf_out, tag )\
|
||||
ENCODE_FLAGS(buf_out, tag );
|
||||
|
||||
#define ENCODE_SIGNING_PUBKEY_SIZE 35
|
||||
#define ENCODE_SIGNING_PUBKEY(buf_out, pkey )\
|
||||
{\
|
||||
buf_out[0] = 0x73U;\
|
||||
buf_out[1] = 0x21U;\
|
||||
*(uint64_t*)(buf_out + 2) = *(uint64_t*)(pkey + 0);\
|
||||
*(uint64_t*)(buf_out + 10) = *(uint64_t*)(pkey + 8);\
|
||||
*(uint64_t*)(buf_out + 18) = *(uint64_t*)(pkey + 16);\
|
||||
*(uint64_t*)(buf_out + 26) = *(uint64_t*)(pkey + 24);\
|
||||
buf[34] = pkey[32];\
|
||||
buf_out += ENCODE_SIGNING_PUBKEY_SIZE;\
|
||||
}
|
||||
|
||||
#define _07_03_ENCODE_SIGNING_PUBKEY(buf_out, pkey )\
|
||||
ENCODE_SIGNING_PUBKEY(buf_out, pkey );
|
||||
|
||||
#define ENCODE_SIGNING_PUBKEY_NULL_SIZE 2
|
||||
#define ENCODE_SIGNING_PUBKEY_NULL(buf_out )\
|
||||
{\
|
||||
*buf_out++ = 0x73U;\
|
||||
*buf_out++ = 0x00U;\
|
||||
}
|
||||
|
||||
#define _07_03_ENCODE_SIGNING_PUBKEY_NULL(buf_out )\
|
||||
ENCODE_SIGNING_PUBKEY_NULL(buf_out );
|
||||
|
||||
|
||||
#define _0E_0E_ENCODE_HOOKOBJ(buf_out, hhash)\
|
||||
{\
|
||||
uint8_t* hook0 = (hhash);\
|
||||
*buf_out++ = 0xEEU; /* hook obj start */ \
|
||||
if (hook0 == 0) /* noop */\
|
||||
{\
|
||||
/* do nothing */ \
|
||||
}\
|
||||
else\
|
||||
{\
|
||||
*buf_out++ = 0x22U; /* flags = override */\
|
||||
*buf_out++ = 0x00U;\
|
||||
*buf_out++ = 0x00U;\
|
||||
*buf_out++ = 0x00U;\
|
||||
*buf_out++ = 0x01U;\
|
||||
if (hook0 == 0xFFFFFFFFUL) /* delete operation */ \
|
||||
{\
|
||||
*buf_out++ = 0x7BU; /* empty createcode */ \
|
||||
*buf_out++ = 0x00U;\
|
||||
}\
|
||||
else\
|
||||
{\
|
||||
*buf_out++ = 0x50U; /* HookHash */\
|
||||
*buf_out++ = 0x1FU;\
|
||||
uint64_t* d = (uint64_t*)buf_out;\
|
||||
uint64_t* s = (uint64_t*)hook0;\
|
||||
*d++ = *s++;\
|
||||
*d++ = *s++;\
|
||||
*d++ = *s++;\
|
||||
*d++ = *s++;\
|
||||
buf_out+=32;\
|
||||
}\
|
||||
}\
|
||||
*buf_out++ = 0xE1U;\
|
||||
}
|
||||
|
||||
#define PREPARE_HOOKSET(buf_out_master, maxlen, h, sizeout)\
|
||||
{\
|
||||
uint8_t* buf_out = (buf_out_master); \
|
||||
uint8_t acc[20]; \
|
||||
uint32_t cls = (uint32_t)ledger_seq(); \
|
||||
hook_account(SBUF(acc)); \
|
||||
_01_02_ENCODE_TT (buf_out, ttHOOK_SET ); \
|
||||
_02_02_ENCODE_FLAGS (buf_out, tfCANONICAL ); \
|
||||
_02_04_ENCODE_SEQUENCE (buf_out, 0 ); \
|
||||
_02_26_ENCODE_FLS (buf_out, cls + 1 ); \
|
||||
_02_27_ENCODE_LLS (buf_out, cls + 5 ); \
|
||||
uint8_t* fee_ptr = buf_out; \
|
||||
_06_08_ENCODE_DROPS_FEE (buf_out, 0 ); \
|
||||
_07_03_ENCODE_SIGNING_PUBKEY_NULL (buf_out ); \
|
||||
_08_01_ENCODE_ACCOUNT_SRC (buf_out, acc ); \
|
||||
uint32_t remaining_size = (maxlen) - (buf_out - (buf_out_master)); \
|
||||
int64_t edlen = etxn_details((uint32_t)buf_out, remaining_size); \
|
||||
buf_out += edlen; \
|
||||
*buf_out++ = 0xFBU; /* hook array start */ \
|
||||
_0E_0E_ENCODE_HOOKOBJ (buf_out, h[0]); \
|
||||
_0E_0E_ENCODE_HOOKOBJ (buf_out, h[1]); \
|
||||
_0E_0E_ENCODE_HOOKOBJ (buf_out, h[2]); \
|
||||
_0E_0E_ENCODE_HOOKOBJ (buf_out, h[3]); \
|
||||
_0E_0E_ENCODE_HOOKOBJ (buf_out, h[4]); \
|
||||
_0E_0E_ENCODE_HOOKOBJ (buf_out, h[5]); \
|
||||
_0E_0E_ENCODE_HOOKOBJ (buf_out, h[6]); \
|
||||
_0E_0E_ENCODE_HOOKOBJ (buf_out, h[7]); \
|
||||
_0E_0E_ENCODE_HOOKOBJ (buf_out, h[8]); \
|
||||
_0E_0E_ENCODE_HOOKOBJ (buf_out, h[9]); \
|
||||
*buf_out++ = 0xF1U; /* hook array end */ \
|
||||
sizeout = (buf_out - (buf_out_master)); \
|
||||
int64_t fee = etxn_fee_base(buf_out_master, sizeout); \
|
||||
_06_08_ENCODE_DROPS_FEE (fee_ptr, fee ); \
|
||||
}
|
||||
|
||||
#ifdef HAS_CALLBACK
|
||||
#define PREPARE_PAYMENT_SIMPLE_SIZE 270U
|
||||
#else
|
||||
#define PREPARE_PAYMENT_SIMPLE_SIZE 248U
|
||||
#endif
|
||||
|
||||
#define PREPARE_PAYMENT_SIMPLE( \
|
||||
buf_out_master, drops_amount_raw, to_address, dest_tag_raw, src_tag_raw) \
|
||||
{ \
|
||||
uint8_t* buf_out = buf_out_master; \
|
||||
uint8_t acc[20]; \
|
||||
uint64_t drops_amount = (drops_amount_raw); \
|
||||
uint32_t dest_tag = (dest_tag_raw); \
|
||||
uint32_t src_tag = (src_tag_raw); \
|
||||
uint32_t cls = (uint32_t)ledger_seq(); \
|
||||
hook_account(SBUF(acc)); \
|
||||
_01_02_ENCODE_TT(buf_out, ttPAYMENT); /* uint16 | size 3 */ \
|
||||
_02_02_ENCODE_FLAGS(buf_out, tfCANONICAL); /* uint32 | size 5 */ \
|
||||
_02_03_ENCODE_TAG_SRC(buf_out, src_tag); /* uint32 | size 5 */ \
|
||||
_02_04_ENCODE_SEQUENCE(buf_out, 0); /* uint32 | size 5 */ \
|
||||
_02_14_ENCODE_TAG_DST(buf_out, dest_tag); /* uint32 | size 5 */ \
|
||||
_02_26_ENCODE_FLS(buf_out, cls + 1); /* uint32 | size 6 */ \
|
||||
_02_27_ENCODE_LLS(buf_out, cls + 5); /* uint32 | size 6 */ \
|
||||
_06_01_ENCODE_DROPS_AMOUNT( \
|
||||
buf_out, drops_amount); /* amount | size 9 */ \
|
||||
uint8_t* fee_ptr = buf_out; \
|
||||
_06_08_ENCODE_DROPS_FEE(buf_out, 0); /* amount | size 9 */ \
|
||||
_07_03_ENCODE_SIGNING_PUBKEY_NULL(buf_out); /* pk | size 35 */ \
|
||||
_08_01_ENCODE_ACCOUNT_SRC(buf_out, acc); /* account | size 22 */ \
|
||||
_08_03_ENCODE_ACCOUNT_DST( \
|
||||
buf_out, to_address); /* account | size 22 */ \
|
||||
int64_t edlen = etxn_details( \
|
||||
(uint32_t)buf_out, \
|
||||
PREPARE_PAYMENT_SIMPLE_SIZE); /* emitdet | size 1?? */ \
|
||||
int64_t fee = \
|
||||
etxn_fee_base(buf_out_master, PREPARE_PAYMENT_SIMPLE_SIZE); \
|
||||
_06_08_ENCODE_DROPS_FEE(fee_ptr, fee); \
|
||||
}
|
||||
|
||||
#ifdef HAS_CALLBACK
|
||||
#define PREPARE_PAYMENT_SIMPLE_TRUSTLINE_SIZE 309
|
||||
#else
|
||||
#define PREPARE_PAYMENT_SIMPLE_TRUSTLINE_SIZE 287
|
||||
#endif
|
||||
#define PREPARE_PAYMENT_SIMPLE_TRUSTLINE( \
|
||||
buf_out_master, tlamt, to_address, dest_tag_raw, src_tag_raw) \
|
||||
{ \
|
||||
uint8_t* buf_out = buf_out_master; \
|
||||
uint8_t acc[20]; \
|
||||
uint32_t dest_tag = (dest_tag_raw); \
|
||||
uint32_t src_tag = (src_tag_raw); \
|
||||
uint32_t cls = (uint32_t)ledger_seq(); \
|
||||
hook_account(SBUF(acc)); \
|
||||
_01_02_ENCODE_TT(buf_out, ttPAYMENT); /* uint16 | size 3 */ \
|
||||
_02_02_ENCODE_FLAGS(buf_out, tfCANONICAL); /* uint32 | size 5 */ \
|
||||
_02_03_ENCODE_TAG_SRC(buf_out, src_tag); /* uint32 | size 5 */ \
|
||||
_02_04_ENCODE_SEQUENCE(buf_out, 0); /* uint32 | size 5 */ \
|
||||
_02_14_ENCODE_TAG_DST(buf_out, dest_tag); /* uint32 | size 5 */ \
|
||||
_02_26_ENCODE_FLS(buf_out, cls + 1); /* uint32 | size 6 */ \
|
||||
_02_27_ENCODE_LLS(buf_out, cls + 5); /* uint32 | size 6 */ \
|
||||
_06_01_ENCODE_TL_AMOUNT(buf_out, tlamt); /* amount | size 48 */ \
|
||||
uint8_t* fee_ptr = buf_out; \
|
||||
_06_08_ENCODE_DROPS_FEE(buf_out, 0); /* amount | size 9 */ \
|
||||
_07_03_ENCODE_SIGNING_PUBKEY_NULL(buf_out); /* pk | size 35 */ \
|
||||
_08_01_ENCODE_ACCOUNT_SRC(buf_out, acc); /* account | size 22 */ \
|
||||
_08_03_ENCODE_ACCOUNT_DST( \
|
||||
buf_out, to_address); /* account | size 22 */ \
|
||||
etxn_details( \
|
||||
(uint32_t)buf_out, \
|
||||
PREPARE_PAYMENT_SIMPLE_TRUSTLINE_SIZE); /* emitdet | size 1?? */ \
|
||||
int64_t fee = etxn_fee_base( \
|
||||
buf_out_master, PREPARE_PAYMENT_SIMPLE_TRUSTLINE_SIZE); \
|
||||
_06_08_ENCODE_DROPS_FEE(fee_ptr, fee); \
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,335 +0,0 @@
|
||||
// For documentation please see: https://xrpl-hooks.readme.io/reference/
|
||||
// Generated using generate_sfcodes.sh
|
||||
#define sfCloseResolution ((16U << 16U) + 1U)
|
||||
#define sfMethod ((16U << 16U) + 2U)
|
||||
#define sfTransactionResult ((16U << 16U) + 3U)
|
||||
#define sfScale ((16U << 16U) + 4U)
|
||||
#define sfAssetScale ((16U << 16U) + 5U)
|
||||
#define sfTickSize ((16U << 16U) + 16U)
|
||||
#define sfUNLModifyDisabling ((16U << 16U) + 17U)
|
||||
#define sfHookResult ((16U << 16U) + 18U)
|
||||
#define sfWasLockingChainSend ((16U << 16U) + 19U)
|
||||
#define sfSidecarType ((16U << 16U) + 20U)
|
||||
#define sfEntropyTier ((16U << 16U) + 21U)
|
||||
#define sfLedgerEntryType ((1U << 16U) + 1U)
|
||||
#define sfTransactionType ((1U << 16U) + 2U)
|
||||
#define sfSignerWeight ((1U << 16U) + 3U)
|
||||
#define sfTransferFee ((1U << 16U) + 4U)
|
||||
#define sfTradingFee ((1U << 16U) + 5U)
|
||||
#define sfDiscountedFee ((1U << 16U) + 6U)
|
||||
#define sfVersion ((1U << 16U) + 16U)
|
||||
#define sfHookStateChangeCount ((1U << 16U) + 17U)
|
||||
#define sfHookEmitCount ((1U << 16U) + 18U)
|
||||
#define sfHookExecutionIndex ((1U << 16U) + 19U)
|
||||
#define sfHookApiVersion ((1U << 16U) + 20U)
|
||||
#define sfHookStateScale ((1U << 16U) + 21U)
|
||||
#define sfLedgerFixType ((1U << 16U) + 22U)
|
||||
#define sfHookExportCount ((1U << 16U) + 98U)
|
||||
#define sfEntropyCount ((1U << 16U) + 99U)
|
||||
#define sfNetworkID ((2U << 16U) + 1U)
|
||||
#define sfFlags ((2U << 16U) + 2U)
|
||||
#define sfSourceTag ((2U << 16U) + 3U)
|
||||
#define sfSequence ((2U << 16U) + 4U)
|
||||
#define sfPreviousTxnLgrSeq ((2U << 16U) + 5U)
|
||||
#define sfLedgerSequence ((2U << 16U) + 6U)
|
||||
#define sfCloseTime ((2U << 16U) + 7U)
|
||||
#define sfParentCloseTime ((2U << 16U) + 8U)
|
||||
#define sfSigningTime ((2U << 16U) + 9U)
|
||||
#define sfExpiration ((2U << 16U) + 10U)
|
||||
#define sfTransferRate ((2U << 16U) + 11U)
|
||||
#define sfWalletSize ((2U << 16U) + 12U)
|
||||
#define sfOwnerCount ((2U << 16U) + 13U)
|
||||
#define sfDestinationTag ((2U << 16U) + 14U)
|
||||
#define sfLastUpdateTime ((2U << 16U) + 15U)
|
||||
#define sfHighQualityIn ((2U << 16U) + 16U)
|
||||
#define sfHighQualityOut ((2U << 16U) + 17U)
|
||||
#define sfLowQualityIn ((2U << 16U) + 18U)
|
||||
#define sfLowQualityOut ((2U << 16U) + 19U)
|
||||
#define sfQualityIn ((2U << 16U) + 20U)
|
||||
#define sfQualityOut ((2U << 16U) + 21U)
|
||||
#define sfStampEscrow ((2U << 16U) + 22U)
|
||||
#define sfBondAmount ((2U << 16U) + 23U)
|
||||
#define sfLoadFee ((2U << 16U) + 24U)
|
||||
#define sfOfferSequence ((2U << 16U) + 25U)
|
||||
#define sfFirstLedgerSequence ((2U << 16U) + 26U)
|
||||
#define sfLastLedgerSequence ((2U << 16U) + 27U)
|
||||
#define sfTransactionIndex ((2U << 16U) + 28U)
|
||||
#define sfOperationLimit ((2U << 16U) + 29U)
|
||||
#define sfReferenceFeeUnits ((2U << 16U) + 30U)
|
||||
#define sfReserveBase ((2U << 16U) + 31U)
|
||||
#define sfReserveIncrement ((2U << 16U) + 32U)
|
||||
#define sfSetFlag ((2U << 16U) + 33U)
|
||||
#define sfClearFlag ((2U << 16U) + 34U)
|
||||
#define sfSignerQuorum ((2U << 16U) + 35U)
|
||||
#define sfCancelAfter ((2U << 16U) + 36U)
|
||||
#define sfFinishAfter ((2U << 16U) + 37U)
|
||||
#define sfSignerListID ((2U << 16U) + 38U)
|
||||
#define sfSettleDelay ((2U << 16U) + 39U)
|
||||
#define sfTicketCount ((2U << 16U) + 40U)
|
||||
#define sfTicketSequence ((2U << 16U) + 41U)
|
||||
#define sfNFTokenTaxon ((2U << 16U) + 42U)
|
||||
#define sfMintedNFTokens ((2U << 16U) + 43U)
|
||||
#define sfBurnedNFTokens ((2U << 16U) + 44U)
|
||||
#define sfHookStateCount ((2U << 16U) + 45U)
|
||||
#define sfEmitGeneration ((2U << 16U) + 46U)
|
||||
#define sfVoteWeight ((2U << 16U) + 48U)
|
||||
#define sfLockCount ((2U << 16U) + 49U)
|
||||
#define sfFirstNFTokenSequence ((2U << 16U) + 50U)
|
||||
#define sfOracleDocumentID ((2U << 16U) + 51U)
|
||||
#define sfStartTime ((2U << 16U) + 93U)
|
||||
#define sfRepeatCount ((2U << 16U) + 94U)
|
||||
#define sfDelaySeconds ((2U << 16U) + 95U)
|
||||
#define sfXahauActivationLgrSeq ((2U << 16U) + 96U)
|
||||
#define sfImportSequence ((2U << 16U) + 97U)
|
||||
#define sfRewardTime ((2U << 16U) + 98U)
|
||||
#define sfRewardLgrFirst ((2U << 16U) + 99U)
|
||||
#define sfRewardLgrLast ((2U << 16U) + 100U)
|
||||
#define sfCancelTicketSequence ((2U << 16U) + 101U)
|
||||
#define sfIndexNext ((3U << 16U) + 1U)
|
||||
#define sfIndexPrevious ((3U << 16U) + 2U)
|
||||
#define sfBookNode ((3U << 16U) + 3U)
|
||||
#define sfOwnerNode ((3U << 16U) + 4U)
|
||||
#define sfBaseFee ((3U << 16U) + 5U)
|
||||
#define sfExchangeRate ((3U << 16U) + 6U)
|
||||
#define sfLowNode ((3U << 16U) + 7U)
|
||||
#define sfHighNode ((3U << 16U) + 8U)
|
||||
#define sfDestinationNode ((3U << 16U) + 9U)
|
||||
#define sfCookie ((3U << 16U) + 10U)
|
||||
#define sfServerVersion ((3U << 16U) + 11U)
|
||||
#define sfNFTokenOfferNode ((3U << 16U) + 12U)
|
||||
#define sfEmitBurden ((3U << 16U) + 13U)
|
||||
#define sfHookInstructionCount ((3U << 16U) + 17U)
|
||||
#define sfHookReturnCode ((3U << 16U) + 18U)
|
||||
#define sfReferenceCount ((3U << 16U) + 19U)
|
||||
#define sfXChainClaimID ((3U << 16U) + 20U)
|
||||
#define sfXChainAccountCreateCount ((3U << 16U) + 21U)
|
||||
#define sfXChainAccountClaimCount ((3U << 16U) + 22U)
|
||||
#define sfAssetPrice ((3U << 16U) + 23U)
|
||||
#define sfMaximumAmount ((3U << 16U) + 24U)
|
||||
#define sfOutstandingAmount ((3U << 16U) + 25U)
|
||||
#define sfMPTAmount ((3U << 16U) + 26U)
|
||||
#define sfIssuerNode ((3U << 16U) + 27U)
|
||||
#define sfSubjectNode ((3U << 16U) + 28U)
|
||||
#define sfTouchCount ((3U << 16U) + 97U)
|
||||
#define sfAccountIndex ((3U << 16U) + 98U)
|
||||
#define sfAccountCount ((3U << 16U) + 99U)
|
||||
#define sfRewardAccumulator ((3U << 16U) + 100U)
|
||||
#define sfEmailHash ((4U << 16U) + 1U)
|
||||
#define sfTakerPaysCurrency ((17U << 16U) + 1U)
|
||||
#define sfTakerPaysIssuer ((17U << 16U) + 2U)
|
||||
#define sfTakerGetsCurrency ((17U << 16U) + 3U)
|
||||
#define sfTakerGetsIssuer ((17U << 16U) + 4U)
|
||||
#define sfMPTokenIssuanceID ((21U << 16U) + 1U)
|
||||
#define sfLedgerHash ((5U << 16U) + 1U)
|
||||
#define sfParentHash ((5U << 16U) + 2U)
|
||||
#define sfTransactionHash ((5U << 16U) + 3U)
|
||||
#define sfAccountHash ((5U << 16U) + 4U)
|
||||
#define sfPreviousTxnID ((5U << 16U) + 5U)
|
||||
#define sfLedgerIndex ((5U << 16U) + 6U)
|
||||
#define sfWalletLocator ((5U << 16U) + 7U)
|
||||
#define sfRootIndex ((5U << 16U) + 8U)
|
||||
#define sfAccountTxnID ((5U << 16U) + 9U)
|
||||
#define sfNFTokenID ((5U << 16U) + 10U)
|
||||
#define sfEmitParentTxnID ((5U << 16U) + 11U)
|
||||
#define sfEmitNonce ((5U << 16U) + 12U)
|
||||
#define sfEmitHookHash ((5U << 16U) + 13U)
|
||||
#define sfObjectID ((5U << 16U) + 14U)
|
||||
#define sfAMMID ((5U << 16U) + 15U)
|
||||
#define sfBookDirectory ((5U << 16U) + 16U)
|
||||
#define sfInvoiceID ((5U << 16U) + 17U)
|
||||
#define sfNickname ((5U << 16U) + 18U)
|
||||
#define sfAmendment ((5U << 16U) + 19U)
|
||||
#define sfHookOn ((5U << 16U) + 20U)
|
||||
#define sfDigest ((5U << 16U) + 21U)
|
||||
#define sfChannel ((5U << 16U) + 22U)
|
||||
#define sfConsensusHash ((5U << 16U) + 23U)
|
||||
#define sfCheckID ((5U << 16U) + 24U)
|
||||
#define sfValidatedHash ((5U << 16U) + 25U)
|
||||
#define sfPreviousPageMin ((5U << 16U) + 26U)
|
||||
#define sfNextPageMin ((5U << 16U) + 27U)
|
||||
#define sfNFTokenBuyOffer ((5U << 16U) + 28U)
|
||||
#define sfNFTokenSellOffer ((5U << 16U) + 29U)
|
||||
#define sfHookStateKey ((5U << 16U) + 30U)
|
||||
#define sfHookHash ((5U << 16U) + 31U)
|
||||
#define sfHookNamespace ((5U << 16U) + 32U)
|
||||
#define sfHookSetTxnID ((5U << 16U) + 33U)
|
||||
#define sfOfferID ((5U << 16U) + 34U)
|
||||
#define sfEscrowID ((5U << 16U) + 35U)
|
||||
#define sfURITokenID ((5U << 16U) + 36U)
|
||||
#define sfDomainID ((5U << 16U) + 37U)
|
||||
#define sfExportSignatureHash ((5U << 16U) + 38U)
|
||||
#define sfHookOnOutgoing ((5U << 16U) + 93U)
|
||||
#define sfHookOnIncoming ((5U << 16U) + 94U)
|
||||
#define sfCron ((5U << 16U) + 95U)
|
||||
#define sfHookCanEmit ((5U << 16U) + 96U)
|
||||
#define sfEmittedTxnID ((5U << 16U) + 97U)
|
||||
#define sfGovernanceMarks ((5U << 16U) + 98U)
|
||||
#define sfGovernanceFlags ((5U << 16U) + 99U)
|
||||
#define sfNumber ((9U << 16U) + 1U)
|
||||
#define sfAmount ((6U << 16U) + 1U)
|
||||
#define sfBalance ((6U << 16U) + 2U)
|
||||
#define sfLimitAmount ((6U << 16U) + 3U)
|
||||
#define sfTakerPays ((6U << 16U) + 4U)
|
||||
#define sfTakerGets ((6U << 16U) + 5U)
|
||||
#define sfLowLimit ((6U << 16U) + 6U)
|
||||
#define sfHighLimit ((6U << 16U) + 7U)
|
||||
#define sfFee ((6U << 16U) + 8U)
|
||||
#define sfSendMax ((6U << 16U) + 9U)
|
||||
#define sfDeliverMin ((6U << 16U) + 10U)
|
||||
#define sfAmount2 ((6U << 16U) + 11U)
|
||||
#define sfBidMin ((6U << 16U) + 12U)
|
||||
#define sfBidMax ((6U << 16U) + 13U)
|
||||
#define sfMinimumOffer ((6U << 16U) + 16U)
|
||||
#define sfRippleEscrow ((6U << 16U) + 17U)
|
||||
#define sfDeliveredAmount ((6U << 16U) + 18U)
|
||||
#define sfNFTokenBrokerFee ((6U << 16U) + 19U)
|
||||
#define sfHookCallbackFee ((6U << 16U) + 20U)
|
||||
#define sfLockedBalance ((6U << 16U) + 21U)
|
||||
#define sfBaseFeeDrops ((6U << 16U) + 22U)
|
||||
#define sfReserveBaseDrops ((6U << 16U) + 23U)
|
||||
#define sfReserveIncrementDrops ((6U << 16U) + 24U)
|
||||
#define sfLPTokenOut ((6U << 16U) + 25U)
|
||||
#define sfLPTokenIn ((6U << 16U) + 26U)
|
||||
#define sfEPrice ((6U << 16U) + 27U)
|
||||
#define sfPrice ((6U << 16U) + 28U)
|
||||
#define sfSignatureReward ((6U << 16U) + 29U)
|
||||
#define sfMinAccountCreateAmount ((6U << 16U) + 30U)
|
||||
#define sfLPTokenBalance ((6U << 16U) + 31U)
|
||||
#define sfTrustLineRewardAccumulator ((6U << 16U) + 99U)
|
||||
#define sfPublicKey ((7U << 16U) + 1U)
|
||||
#define sfMessageKey ((7U << 16U) + 2U)
|
||||
#define sfSigningPubKey ((7U << 16U) + 3U)
|
||||
#define sfTxnSignature ((7U << 16U) + 4U)
|
||||
#define sfURI ((7U << 16U) + 5U)
|
||||
#define sfSignature ((7U << 16U) + 6U)
|
||||
#define sfDomain ((7U << 16U) + 7U)
|
||||
#define sfFundCode ((7U << 16U) + 8U)
|
||||
#define sfRemoveCode ((7U << 16U) + 9U)
|
||||
#define sfExpireCode ((7U << 16U) + 10U)
|
||||
#define sfCreateCode ((7U << 16U) + 11U)
|
||||
#define sfMemoType ((7U << 16U) + 12U)
|
||||
#define sfMemoData ((7U << 16U) + 13U)
|
||||
#define sfMemoFormat ((7U << 16U) + 14U)
|
||||
#define sfFulfillment ((7U << 16U) + 16U)
|
||||
#define sfCondition ((7U << 16U) + 17U)
|
||||
#define sfMasterSignature ((7U << 16U) + 18U)
|
||||
#define sfUNLModifyValidator ((7U << 16U) + 19U)
|
||||
#define sfValidatorToDisable ((7U << 16U) + 20U)
|
||||
#define sfValidatorToReEnable ((7U << 16U) + 21U)
|
||||
#define sfHookStateData ((7U << 16U) + 22U)
|
||||
#define sfHookReturnString ((7U << 16U) + 23U)
|
||||
#define sfHookParameterName ((7U << 16U) + 24U)
|
||||
#define sfHookParameterValue ((7U << 16U) + 25U)
|
||||
#define sfBlob ((7U << 16U) + 26U)
|
||||
#define sfDIDDocument ((7U << 16U) + 27U)
|
||||
#define sfData ((7U << 16U) + 28U)
|
||||
#define sfAssetClass ((7U << 16U) + 29U)
|
||||
#define sfProvider ((7U << 16U) + 30U)
|
||||
#define sfMPTokenMetadata ((7U << 16U) + 31U)
|
||||
#define sfCredentialType ((7U << 16U) + 32U)
|
||||
#define sfHookName ((7U << 16U) + 97U)
|
||||
#define sfRemarkValue ((7U << 16U) + 98U)
|
||||
#define sfRemarkName ((7U << 16U) + 99U)
|
||||
#define sfAccount ((8U << 16U) + 1U)
|
||||
#define sfOwner ((8U << 16U) + 2U)
|
||||
#define sfDestination ((8U << 16U) + 3U)
|
||||
#define sfIssuer ((8U << 16U) + 4U)
|
||||
#define sfAuthorize ((8U << 16U) + 5U)
|
||||
#define sfUnauthorize ((8U << 16U) + 6U)
|
||||
#define sfRegularKey ((8U << 16U) + 8U)
|
||||
#define sfNFTokenMinter ((8U << 16U) + 9U)
|
||||
#define sfEmitCallback ((8U << 16U) + 10U)
|
||||
#define sfHolder ((8U << 16U) + 11U)
|
||||
#define sfHookAccount ((8U << 16U) + 16U)
|
||||
#define sfOtherChainSource ((8U << 16U) + 18U)
|
||||
#define sfOtherChainDestination ((8U << 16U) + 19U)
|
||||
#define sfAttestationSignerAccount ((8U << 16U) + 20U)
|
||||
#define sfAttestationRewardAccount ((8U << 16U) + 21U)
|
||||
#define sfLockingChainDoor ((8U << 16U) + 22U)
|
||||
#define sfIssuingChainDoor ((8U << 16U) + 23U)
|
||||
#define sfSubject ((8U << 16U) + 24U)
|
||||
#define sfInform ((8U << 16U) + 99U)
|
||||
#define sfIndexes ((19U << 16U) + 1U)
|
||||
#define sfHashes ((19U << 16U) + 2U)
|
||||
#define sfAmendments ((19U << 16U) + 3U)
|
||||
#define sfNFTokenOffers ((19U << 16U) + 4U)
|
||||
#define sfHookNamespaces ((19U << 16U) + 5U)
|
||||
#define sfCredentialIDs ((19U << 16U) + 6U)
|
||||
#define sfURITokenIDs ((19U << 16U) + 99U)
|
||||
#define sfPaths ((18U << 16U) + 1U)
|
||||
#define sfBaseAsset ((26U << 16U) + 1U)
|
||||
#define sfQuoteAsset ((26U << 16U) + 2U)
|
||||
#define sfLockingChainIssue ((24U << 16U) + 1U)
|
||||
#define sfIssuingChainIssue ((24U << 16U) + 2U)
|
||||
#define sfAsset ((24U << 16U) + 3U)
|
||||
#define sfAsset2 ((24U << 16U) + 4U)
|
||||
#define sfClaimCurrency ((24U << 16U) + 5U)
|
||||
#define sfXChainBridge ((25U << 16U) + 1U)
|
||||
#define sfTransactionMetaData ((14U << 16U) + 2U)
|
||||
#define sfCreatedNode ((14U << 16U) + 3U)
|
||||
#define sfDeletedNode ((14U << 16U) + 4U)
|
||||
#define sfModifiedNode ((14U << 16U) + 5U)
|
||||
#define sfPreviousFields ((14U << 16U) + 6U)
|
||||
#define sfFinalFields ((14U << 16U) + 7U)
|
||||
#define sfNewFields ((14U << 16U) + 8U)
|
||||
#define sfTemplateEntry ((14U << 16U) + 9U)
|
||||
#define sfMemo ((14U << 16U) + 10U)
|
||||
#define sfSignerEntry ((14U << 16U) + 11U)
|
||||
#define sfNFToken ((14U << 16U) + 12U)
|
||||
#define sfEmitDetails ((14U << 16U) + 13U)
|
||||
#define sfHook ((14U << 16U) + 14U)
|
||||
#define sfSigner ((14U << 16U) + 16U)
|
||||
#define sfMajority ((14U << 16U) + 18U)
|
||||
#define sfDisabledValidator ((14U << 16U) + 19U)
|
||||
#define sfEmittedTxn ((14U << 16U) + 20U)
|
||||
#define sfHookExecution ((14U << 16U) + 21U)
|
||||
#define sfHookParameter ((14U << 16U) + 23U)
|
||||
#define sfHookGrant ((14U << 16U) + 24U)
|
||||
#define sfVoteEntry ((14U << 16U) + 25U)
|
||||
#define sfAuctionSlot ((14U << 16U) + 26U)
|
||||
#define sfAuthAccount ((14U << 16U) + 27U)
|
||||
#define sfXChainClaimProofSig ((14U << 16U) + 28U)
|
||||
#define sfXChainCreateAccountProofSig ((14U << 16U) + 29U)
|
||||
#define sfXChainClaimAttestationCollectionElement ((14U << 16U) + 30U)
|
||||
#define sfXChainCreateAccountAttestationCollectionElement ((14U << 16U) + 31U)
|
||||
#define sfPriceData ((14U << 16U) + 32U)
|
||||
#define sfCredential ((14U << 16U) + 33U)
|
||||
#define sfExportedTxn ((14U << 16U) + 90U)
|
||||
#define sfAmountEntry ((14U << 16U) + 91U)
|
||||
#define sfMintURIToken ((14U << 16U) + 92U)
|
||||
#define sfHookEmission ((14U << 16U) + 93U)
|
||||
#define sfImportVLKey ((14U << 16U) + 94U)
|
||||
#define sfActiveValidator ((14U << 16U) + 95U)
|
||||
#define sfGenesisMint ((14U << 16U) + 96U)
|
||||
#define sfRemark ((14U << 16U) + 97U)
|
||||
#define sfHighReward ((14U << 16U) + 98U)
|
||||
#define sfLowReward ((14U << 16U) + 99U)
|
||||
#define sfExportResult ((14U << 16U) + 100U)
|
||||
#define sfSigners ((15U << 16U) + 3U)
|
||||
#define sfSignerEntries ((15U << 16U) + 4U)
|
||||
#define sfTemplate ((15U << 16U) + 5U)
|
||||
#define sfNecessary ((15U << 16U) + 6U)
|
||||
#define sfSufficient ((15U << 16U) + 7U)
|
||||
#define sfAffectedNodes ((15U << 16U) + 8U)
|
||||
#define sfMemos ((15U << 16U) + 9U)
|
||||
#define sfNFTokens ((15U << 16U) + 10U)
|
||||
#define sfHooks ((15U << 16U) + 11U)
|
||||
#define sfVoteSlots ((15U << 16U) + 12U)
|
||||
#define sfMajorities ((15U << 16U) + 16U)
|
||||
#define sfDisabledValidators ((15U << 16U) + 17U)
|
||||
#define sfHookExecutions ((15U << 16U) + 18U)
|
||||
#define sfHookParameters ((15U << 16U) + 19U)
|
||||
#define sfHookGrants ((15U << 16U) + 20U)
|
||||
#define sfXChainClaimAttestations ((15U << 16U) + 21U)
|
||||
#define sfXChainCreateAccountAttestations ((15U << 16U) + 22U)
|
||||
#define sfPriceDataSeries ((15U << 16U) + 24U)
|
||||
#define sfAuthAccounts ((15U << 16U) + 25U)
|
||||
#define sfAuthorizeCredentials ((15U << 16U) + 26U)
|
||||
#define sfUnauthorizeCredentials ((15U << 16U) + 27U)
|
||||
#define sfAcceptedCredentials ((15U << 16U) + 28U)
|
||||
#define sfAmounts ((15U << 16U) + 92U)
|
||||
#define sfHookEmissions ((15U << 16U) + 93U)
|
||||
#define sfImportVLKeys ((15U << 16U) + 94U)
|
||||
#define sfActiveValidators ((15U << 16U) + 95U)
|
||||
#define sfGenesisMints ((15U << 16U) + 96U)
|
||||
#define sfRemarks ((15U << 16U) + 97U)
|
||||
@@ -1,239 +0,0 @@
|
||||
#include <stdint.h>
|
||||
|
||||
// 8 byte-int = 1 bytes
|
||||
#define SFL_CLOSERESOLUTION 1
|
||||
#define SFL_METHOD 1
|
||||
#define SFL_TRANSACTIONRESULT 1
|
||||
#define SFL_TICKSIZE 1
|
||||
#define SFL_UNLMODIFYDISABLING 1
|
||||
#define SFL_HOOKRESULT 1
|
||||
// 16 byte-int = 2 bytes
|
||||
#define SFL_LEDGERENTRYTYPE 2
|
||||
#define SFL_TRANSACTIONTYPE 2
|
||||
#define SFL_SIGNERWEIGHT 2
|
||||
#define SFL_TRANSFERFEE 2
|
||||
#define SFL_VERSION 2
|
||||
#define SFL_HOOKSTATECHANGECOUNT 2
|
||||
#define SFL_HOOKEMITCOUNT 2
|
||||
#define SFL_HOOKEXECUTIONINDEX 2
|
||||
#define SFL_HOOKAPIVERSION 2
|
||||
// 32 byte-int = 4 bytes
|
||||
#define SFL_NETWORKID 4
|
||||
#define SFL_FLAGS 4
|
||||
#define SFL_SOURCETAG 4
|
||||
#define SFL_SEQUENCE 4
|
||||
#define SFL_PREVIOUSTXNLGRSEQ 4
|
||||
#define SFL_LEDGERSEQUENCE 4
|
||||
#define SFL_CLOSETIME 4
|
||||
#define SFL_PARENTCLOSETIME 4
|
||||
#define SFL_SIGNINGTIME 4
|
||||
#define SFL_EXPIRATION 4
|
||||
#define SFL_TRANSFERRATE 4
|
||||
#define SFL_WALLETSIZE 4
|
||||
#define SFL_OWNERCOUNT 4
|
||||
#define SFL_DESTINATIONTAG 4
|
||||
#define SFL_HIGHQUALITYIN 4
|
||||
#define SFL_HIGHQUALITYOUT 4
|
||||
#define SFL_LOWQUALITYIN 4
|
||||
#define SFL_LOWQUALITYOUT 4
|
||||
#define SFL_QUALITYIN 4
|
||||
#define SFL_QUALITYOUT 4
|
||||
#define SFL_STAMPESCROW 4
|
||||
#define SFL_BONDAMOUNT 4
|
||||
#define SFL_LOADFEE 4
|
||||
#define SFL_OFFERSEQUENCE 4
|
||||
#define SFL_FIRSTLEDGERSEQUENCE 4
|
||||
#define SFL_LASTLEDGERSEQUENCE 4
|
||||
#define SFL_TRANSACTIONINDEX 4
|
||||
#define SFL_OPERATIONLIMIT 4
|
||||
#define SFL_REFERENCEFEEUNITS 4
|
||||
#define SFL_RESERVEBASE 4
|
||||
#define SFL_RESERVEINCREMENT 4
|
||||
#define SFL_SETFLAG 4
|
||||
#define SFL_CLEARFLAG 4
|
||||
#define SFL_SIGNERQUORUM 4
|
||||
#define SFL_CANCELAFTER 4
|
||||
#define SFL_FINISHAFTER 4
|
||||
#define SFL_SIGNERLISTID 4
|
||||
#define SFL_SETTLEDELAY 4
|
||||
#define SFL_TICKETCOUNT 4
|
||||
#define SFL_TICKETSEQUENCE 4
|
||||
#define SFL_NFTOKENTAXON 4
|
||||
#define SFL_MINTEDNFTOKENS 4
|
||||
#define SFL_BURNEDNFTOKENS 4
|
||||
#define SFL_HOOKSTATECOUNT 4
|
||||
#define SFL_EMITGENERATION 4
|
||||
#define SFL_LOCKCOUNT 4
|
||||
#define SFL_REWARDTIME 4
|
||||
#define SFL_REWARDLGRFIRST 4
|
||||
#define SFL_REWARDLGRLAST 4
|
||||
#define SFL_FIRSTNFTOKENSEQUENCE 4
|
||||
// 64 byte-int = 8 bytes
|
||||
#define SFL_INDEX_NEXT 8
|
||||
#define SFL_INDEX_PREVIOUS 8
|
||||
#define SFL_BOOK_NODE 8
|
||||
#define SFL_OWNER_NODE 8
|
||||
#define SFL_BASE_FEE 8
|
||||
#define SFL_EXCHANGE_RATE 8
|
||||
#define SFL_LOW_NODE 8
|
||||
#define SFL_HIGH_NODE 8
|
||||
#define SFL_DESTINATION_NODE 8
|
||||
#define SFL_COOKIE 8
|
||||
#define SFL_SERVER_VERSION 8
|
||||
#define SFL_EMIT_BURDEN 8
|
||||
#define SFL_NFTOKEN_OFFER_NODE 8
|
||||
#define SFL_HOOK_INSTRUCTION_COUNT 8
|
||||
#define SFL_HOOK_RETURN_CODE 8
|
||||
#define SFL_REFERENCE_COUNT 8
|
||||
#define SFL_REWARD_ACCUMULATOR 8
|
||||
// 128 byte-int = 4 bytes
|
||||
#define SFL_EMAIL_HASH 128
|
||||
// 160 byte-int = 4 bytes
|
||||
#define SFL_TAKER_PAYS_CURRENCY 160
|
||||
#define SFL_TAKER_PAYS_ISSUER 160
|
||||
#define SFL_TAKER_GETS_CURRENCY 160
|
||||
#define SFL_TAKER_GETS_ISSUER 160
|
||||
// 256 byte-int = ??? bytes
|
||||
#define SFL_LEDGER_HASH 256
|
||||
#define SFL_PARENT_HASH 256
|
||||
#define SFL_TRANSACTION_HASH 256
|
||||
#define SFL_ACCOUNT_HASH 256
|
||||
#define SFL_HOOK_ON 256
|
||||
#define SFL_PREVIOUS_TXN_ID 256
|
||||
#define SFL_LEDGER_INDEX 256
|
||||
#define SFL_WALLET_LOCATOR 256
|
||||
#define SFL_ROOT_INDEX 256
|
||||
#define SFL_ACCOUNT_TXN_ID 256
|
||||
#define SFL_NFTOKEN_ID 256
|
||||
#define SFL_EMIT_PARENT_TXN_ID 256
|
||||
#define SFL_EMIT_NONCE 256
|
||||
#define SFL_EMIT_HOOK_HASH 256
|
||||
// 256 byte-int = ??? bytes
|
||||
#define SFL_BOOK_DIRECTORY 256
|
||||
#define SFL_INVOICE_ID 256
|
||||
#define SFL_NICKNAME 256
|
||||
#define SFL_AMENDMENT 256
|
||||
#define SFL_DIGEST 256
|
||||
#define SFL_CHANNEL 256
|
||||
#define SFL_CONSENSUS_HASH 256
|
||||
#define SFL_CHECK_ID 256
|
||||
#define SFL_VALIDATED_HASH 256
|
||||
#define SFL_PREVIOUS_PAGE_MIN 256
|
||||
#define SFL_NEXT_PAGE_MIN 256
|
||||
#define SFL_NFTOKEN_BUY_OFFER 256
|
||||
#define SFL_NFTOKEN_SELL_OFFER 256
|
||||
#define SFL_HOOK_STATE_KEY 256
|
||||
#define SFL_HOOK_HASH 256
|
||||
#define SFL_HOOK_NAMESPACE 256
|
||||
#define SFL_HOOK_SET_TXN_ID 256
|
||||
#define SFL_OFFER_ID 256
|
||||
#define SFL_ESCROW_ID 256
|
||||
#define SFL_URITOKEN_ID 256
|
||||
// 20 bytes
|
||||
#define SFL_AMOUNT 20
|
||||
#define SFL_BALANCE 20
|
||||
#define SFL_LIMIT_AMOUNT 20
|
||||
#define SFL_TAKER_PAYS 20
|
||||
#define SFL_TAKER_GETS 20
|
||||
#define SFL_LOW_LIMIT 20
|
||||
#define SFL_HIGH_LIMIT 20
|
||||
#define SFL_FEE 20
|
||||
#define SFL_SEND_MAX 20
|
||||
#define SFL_DELIVER_MIN 20
|
||||
#define SFL_LOCKED_BALANCE 20
|
||||
// Unimplemented
|
||||
#define SFL_AMOUNT_MINIMUM_OFFER 8
|
||||
#define SFL_AMOUNT_RIPPLE_ESCROW 8
|
||||
#define SFL_AMOUNT_DELIVERED_AMOUNT 8
|
||||
#define SFL_AMOUNT_NFTOKEN_BROKER_FEE 8
|
||||
#define SFL_AMOUNT_HOOK_CALLBACK_FEE 8
|
||||
#define SFL_AMOUNT_BASE_FEE_DROPS 8
|
||||
#define SFL_AMOUNT_RESERVE_BASE_DROPS 8
|
||||
#define SFL_AMOUNT_RESERVE_INCREMENT_DROPS 8
|
||||
// Unimplemented
|
||||
#define SFL_VL_PUBLIC_KEY 64
|
||||
#define SFL_VL_MESSAGE_KEY 64
|
||||
#define SFL_VL_SIGNING_PUB_KEY 64
|
||||
// Unimplemented
|
||||
#define SFL_VL_TXN_SIGNATURE 96
|
||||
// Unimplemented
|
||||
#define SFL_VL_URI 256
|
||||
// Unimplemented
|
||||
#define SFL_VL_SIGNATURE 96
|
||||
// Unimplemented
|
||||
#define SFL_VL_DOMAIN 256
|
||||
#define SFL_VL_FUND_CODE 256
|
||||
#define SFL_VL_REMOVE_CODE 256
|
||||
#define SFL_VL_EXPIRE_CODE 256
|
||||
#define SFL_VL_CREATE_CODE 256
|
||||
#define SFL_VL_MEMO_TYPE 256
|
||||
#define SFL_VL_MEMO_DATA 256
|
||||
#define SFL_VL_MEMO_FORMAT 256
|
||||
#define SFL_VL_FULFILLMENT 256
|
||||
#define SFL_VL_CONDITION 256
|
||||
// Unimplemented
|
||||
#define SFL_VL_MASTER_SIGNATURE 96
|
||||
// Unimplemented
|
||||
#define SFL_VL_UNL_MODIFY_VALIDATOR 256
|
||||
#define SFL_VL_VALIDATOR_TO_DISABLE 256
|
||||
#define SFL_VL_VALIDATOR_TO_RE_ENABLE 256
|
||||
#define SFL_VL_HOOK_STATE_DATA 256
|
||||
#define SFL_VL_HOOK_RETURN_STRING 256
|
||||
#define SFL_VL_HOOK_PARAMETER_NAME 256
|
||||
#define SFL_VL_HOOK_PARAMETER_VALUE 256
|
||||
#define SFL_VL_BLOB 256
|
||||
// 20 bytes
|
||||
#define SFL_ACCOUNT 20
|
||||
#define SFL_OWNER 20
|
||||
#define SFL_DESTINATION 20
|
||||
#define SFL_ISSUER 20
|
||||
#define SFL_AUTHORIZE 20
|
||||
#define SFL_UNAUTHORIZE 20
|
||||
#define SFL_REGULAR_KEY 20
|
||||
#define SFL_NFTOKEN_MINTER 20
|
||||
#define SFL_EMIT_CALLBACK 20
|
||||
#define SFL_HOOK_ACCOUNT 20
|
||||
#define SFL_NFTOKEN_MINTER 20
|
||||
// Unimplemented
|
||||
#define SFL_PATHS 1
|
||||
// Unimplemented
|
||||
#define SFL_VECTOR256_INDEXES 32
|
||||
#define SFL_VECTOR256_HASHES 32
|
||||
#define SFL_VECTOR256_AMENDMENTS 32
|
||||
#define SFL_VECTOR256_NFTOKEN_OFFERS 32
|
||||
#define SFL_VECTOR256_HOOK_NAMESPACES 32
|
||||
// Unimplemented
|
||||
#define SFL_TRANSACTION_META_DATA 1
|
||||
#define SFL_CREATED_NODE 1
|
||||
#define SFL_DELETED_NODE 1
|
||||
#define SFL_MODIFIED_NODE 1
|
||||
#define SFL_PREVIOUS_FIELDS 1
|
||||
#define SFL_FINAL_FIELDS 1
|
||||
#define SFL_NEW_FIELDS 1
|
||||
#define SFL_TEMPLATE_ENTRY 1
|
||||
#define SFL_MEMO 1
|
||||
#define SFL_SIGNER_ENTRY 1
|
||||
#define SFL_NFTOKEN 1
|
||||
#define SFL_EMIT_DETAILS 1
|
||||
#define SFL_HOOK 1
|
||||
#define SFL_SIGNER 1
|
||||
#define SFL_MAJORITY 1
|
||||
#define SFL_DISABLED_VALIDATOR 1
|
||||
#define SFL_EMITTED_TXN 1
|
||||
#define SFL_HOOK_EXECUTION 1
|
||||
#define SFL_HOOK_DEFINITION 1
|
||||
#define SFL_HOOK_PARAMETER 1
|
||||
#define SFL_HOOK_GRANT 1
|
||||
#define SFL_SIGNERS 1
|
||||
#define SFL_SIGNER_ENTRIES 1
|
||||
#define SFL_TEMPLATE 1
|
||||
#define SFL_NECESSARY 1
|
||||
#define SFL_SUFFICIENT 1
|
||||
#define SFL_AFFECTED_NODES 1
|
||||
#define SFL_MEMOS 1
|
||||
#define SFL_NFTOKENS 1
|
||||
#define SFL_HOOKS 1
|
||||
#define SFL_MAJORITIES 1
|
||||
#define SFL_DISABLED_VALIDATORS 1
|
||||
#define SFL_HOOK_EXECUTIONS 1
|
||||
#define SFL_HOOK_EXECUTION 1
|
||||
@@ -1,9 +1,9 @@
|
||||
all: reward govern mint
|
||||
accept:
|
||||
wasmcc accept.c -o accept.wasm -Oz -Wl,--allow-undefined -I./headers
|
||||
wasmcc accept.c -o accept.wasm -Oz -Wl,--allow-undefined -I../
|
||||
hook-cleaner accept.wasm
|
||||
reward:
|
||||
wasmcc reward.c -o reward.wasm -Oz -Wl,--allow-undefined -I./headers
|
||||
wasmcc reward.c -o reward.wasm -Oz -Wl,--allow-undefined -I../
|
||||
wasm-opt reward.wasm -o reward.wasm \
|
||||
--shrink-level=100000000 \
|
||||
--coalesce-locals-learning \
|
||||
@@ -58,7 +58,7 @@ reward:
|
||||
hook-cleaner reward.wasm
|
||||
guard_checker reward.wasm
|
||||
govern:
|
||||
wasmcc govern.c -o govern.wasm -Oz -Wl,--allow-undefined -I./headers
|
||||
wasmcc govern.c -o govern.wasm -Oz -Wl,--allow-undefined -I../
|
||||
wasm-opt govern.wasm -o govern.wasm \
|
||||
--shrink-level=100000000 \
|
||||
--coalesce-locals-learning \
|
||||
@@ -113,7 +113,7 @@ govern:
|
||||
hook-cleaner govern.wasm
|
||||
guard_checker govern.wasm
|
||||
mint:
|
||||
wasmcc mint.c -o mint.wasm -Oz -Wl,--allow-undefined -I./headers
|
||||
wasmcc mint.c -o mint.wasm -Oz -Wl,--allow-undefined -I../
|
||||
wasm-opt mint.wasm -o mint.wasm \
|
||||
--shrink-level=100000000 \
|
||||
--coalesce-locals-learning \
|
||||
@@ -142,5 +142,5 @@ mint:
|
||||
hook-cleaner mint.wasm
|
||||
guard_checker mint.wasm
|
||||
nftoken:
|
||||
wasmcc nftoken.c -o nftoken.wasm -Oz -Wl,--allow-undefined -I./headers
|
||||
wasmcc nftoken.c -o nftoken.wasm -Oz -Wl,--allow-undefined -I../
|
||||
hook-cleaner nftoken.wasm
|
||||
|
||||
@@ -49,7 +49,4 @@
|
||||
#include "macro.h"
|
||||
#include "tts.h"
|
||||
|
||||
#include "ls_flags.h"
|
||||
#include "tx_flags.h"
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
// Generated using generate_lsflags.sh
|
||||
|
||||
#ifndef HOOKLSFLAGS_INCLUDED
|
||||
#define HOOKLSFLAGS_INCLUDED 1
|
||||
|
||||
enum ltACCOUNT_ROOT {
|
||||
lsfPasswordSpent = 0x00010000,
|
||||
lsfRequireDestTag = 0x00020000,
|
||||
lsfRequireAuth = 0x00040000,
|
||||
lsfDisallowXRP = 0x00080000,
|
||||
lsfDisableMaster = 0x00100000,
|
||||
lsfNoFreeze = 0x00200000,
|
||||
lsfGlobalFreeze = 0x00400000,
|
||||
lsfDefaultRipple = 0x00800000,
|
||||
lsfDepositAuth = 0x01000000,
|
||||
lsfTshCollect = 0x02000000,
|
||||
lsfDisallowIncomingNFTokenOffer = 0x04000000,
|
||||
lsfDisallowIncomingCheck = 0x08000000,
|
||||
lsfDisallowIncomingPayChan = 0x10000000,
|
||||
lsfDisallowIncomingTrustline = 0x20000000,
|
||||
lsfURITokenIssuer = 0x40000000,
|
||||
lsfDisallowIncomingRemit = 0x80000000,
|
||||
lsfAllowTrustLineClawback = 0x00001000,
|
||||
};
|
||||
enum ltOFFER {
|
||||
lsfPassive = 0x00010000,
|
||||
lsfSell = 0x00020000,
|
||||
};
|
||||
enum ltRIPPLE_STATE {
|
||||
lsfLowReserve = 0x00010000,
|
||||
lsfHighReserve = 0x00020000,
|
||||
lsfLowAuth = 0x00040000,
|
||||
lsfHighAuth = 0x00080000,
|
||||
lsfLowNoRipple = 0x00100000,
|
||||
lsfHighNoRipple = 0x00200000,
|
||||
lsfLowFreeze = 0x00400000,
|
||||
lsfHighFreeze = 0x00800000,
|
||||
lsfLowDeepFreeze = 0x02000000,
|
||||
lsfHighDeepFreeze = 0x04000000,
|
||||
lsfAMMNode = 0x01000000,
|
||||
};
|
||||
enum ltSIGNER_LIST {
|
||||
lsfOneOwnerCount = 0x00010000,
|
||||
};
|
||||
enum ltDIR_NODE {
|
||||
lsfNFTokenBuyOffers = 0x00000001,
|
||||
lsfNFTokenSellOffers = 0x00000002,
|
||||
lsfEmittedDir = 0x00000004,
|
||||
};
|
||||
enum ltNFTOKEN_OFFER {
|
||||
lsfSellNFToken = 0x00000001,
|
||||
};
|
||||
enum ltURI_TOKEN {
|
||||
lsfBurnable = 0x00000001,
|
||||
};
|
||||
enum remarks {
|
||||
lsfImmutable = 1,
|
||||
};
|
||||
enum ltMPTOKEN_ISSUANCE {
|
||||
lsfMPTLocked = 0x00000001,
|
||||
lsfMPTCanLock = 0x00000002,
|
||||
lsfMPTRequireAuth = 0x00000004,
|
||||
lsfMPTCanEscrow = 0x00000008,
|
||||
lsfMPTCanTrade = 0x00000010,
|
||||
lsfMPTCanTransfer = 0x00000020,
|
||||
lsfMPTCanClawback = 0x00000040,
|
||||
};
|
||||
enum ltMPTOKEN {
|
||||
lsfMPTAuthorized = 0x00000002,
|
||||
};
|
||||
enum ltCREDENTIAL {
|
||||
lsfAccepted = 0x00010000,
|
||||
};
|
||||
|
||||
#endif // HOOKLSFLAGS_INCLUDED
|
||||
@@ -9,8 +9,6 @@
|
||||
#define sfUNLModifyDisabling ((16U << 16U) + 17U)
|
||||
#define sfHookResult ((16U << 16U) + 18U)
|
||||
#define sfWasLockingChainSend ((16U << 16U) + 19U)
|
||||
#define sfSidecarType ((16U << 16U) + 20U)
|
||||
#define sfEntropyTier ((16U << 16U) + 21U)
|
||||
#define sfLedgerEntryType ((1U << 16U) + 1U)
|
||||
#define sfTransactionType ((1U << 16U) + 2U)
|
||||
#define sfSignerWeight ((1U << 16U) + 3U)
|
||||
@@ -24,8 +22,6 @@
|
||||
#define sfHookApiVersion ((1U << 16U) + 20U)
|
||||
#define sfHookStateScale ((1U << 16U) + 21U)
|
||||
#define sfLedgerFixType ((1U << 16U) + 22U)
|
||||
#define sfHookExportCount ((1U << 16U) + 98U)
|
||||
#define sfEntropyCount ((1U << 16U) + 99U)
|
||||
#define sfNetworkID ((2U << 16U) + 1U)
|
||||
#define sfFlags ((2U << 16U) + 2U)
|
||||
#define sfSourceTag ((2U << 16U) + 3U)
|
||||
@@ -84,7 +80,6 @@
|
||||
#define sfRewardTime ((2U << 16U) + 98U)
|
||||
#define sfRewardLgrFirst ((2U << 16U) + 99U)
|
||||
#define sfRewardLgrLast ((2U << 16U) + 100U)
|
||||
#define sfCancelTicketSequence ((2U << 16U) + 101U)
|
||||
#define sfIndexNext ((3U << 16U) + 1U)
|
||||
#define sfIndexPrevious ((3U << 16U) + 2U)
|
||||
#define sfBookNode ((3U << 16U) + 3U)
|
||||
@@ -157,14 +152,11 @@
|
||||
#define sfEscrowID ((5U << 16U) + 35U)
|
||||
#define sfURITokenID ((5U << 16U) + 36U)
|
||||
#define sfDomainID ((5U << 16U) + 37U)
|
||||
#define sfExportSignatureHash ((5U << 16U) + 38U)
|
||||
#define sfHookOnOutgoing ((5U << 16U) + 93U)
|
||||
#define sfHookOnIncoming ((5U << 16U) + 94U)
|
||||
#define sfCron ((5U << 16U) + 95U)
|
||||
#define sfHookCanEmit ((5U << 16U) + 96U)
|
||||
#define sfEmittedTxnID ((5U << 16U) + 97U)
|
||||
#define sfGovernanceMarks ((5U << 16U) + 98U)
|
||||
#define sfGovernanceFlags ((5U << 16U) + 99U)
|
||||
#define sfGovernanceMarks ((5U << 16U) + 98U)
|
||||
#define sfEmittedTxnID ((5U << 16U) + 97U)
|
||||
#define sfHookCanEmit ((5U << 16U) + 96U)
|
||||
#define sfCron ((5U << 16U) + 95U)
|
||||
#define sfNumber ((9U << 16U) + 1U)
|
||||
#define sfAmount ((6U << 16U) + 1U)
|
||||
#define sfBalance ((6U << 16U) + 2U)
|
||||
@@ -195,7 +187,6 @@
|
||||
#define sfSignatureReward ((6U << 16U) + 29U)
|
||||
#define sfMinAccountCreateAmount ((6U << 16U) + 30U)
|
||||
#define sfLPTokenBalance ((6U << 16U) + 31U)
|
||||
#define sfTrustLineRewardAccumulator ((6U << 16U) + 99U)
|
||||
#define sfPublicKey ((7U << 16U) + 1U)
|
||||
#define sfMessageKey ((7U << 16U) + 2U)
|
||||
#define sfSigningPubKey ((7U << 16U) + 3U)
|
||||
@@ -227,7 +218,6 @@
|
||||
#define sfProvider ((7U << 16U) + 30U)
|
||||
#define sfMPTokenMetadata ((7U << 16U) + 31U)
|
||||
#define sfCredentialType ((7U << 16U) + 32U)
|
||||
#define sfHookName ((7U << 16U) + 97U)
|
||||
#define sfRemarkValue ((7U << 16U) + 98U)
|
||||
#define sfRemarkName ((7U << 16U) + 99U)
|
||||
#define sfAccount ((8U << 16U) + 1U)
|
||||
@@ -263,7 +253,6 @@
|
||||
#define sfIssuingChainIssue ((24U << 16U) + 2U)
|
||||
#define sfAsset ((24U << 16U) + 3U)
|
||||
#define sfAsset2 ((24U << 16U) + 4U)
|
||||
#define sfClaimCurrency ((24U << 16U) + 5U)
|
||||
#define sfXChainBridge ((25U << 16U) + 1U)
|
||||
#define sfTransactionMetaData ((14U << 16U) + 2U)
|
||||
#define sfCreatedNode ((14U << 16U) + 3U)
|
||||
@@ -283,6 +272,7 @@
|
||||
#define sfDisabledValidator ((14U << 16U) + 19U)
|
||||
#define sfEmittedTxn ((14U << 16U) + 20U)
|
||||
#define sfHookExecution ((14U << 16U) + 21U)
|
||||
#define sfHookDefinition ((14U << 16U) + 22U)
|
||||
#define sfHookParameter ((14U << 16U) + 23U)
|
||||
#define sfHookGrant ((14U << 16U) + 24U)
|
||||
#define sfVoteEntry ((14U << 16U) + 25U)
|
||||
@@ -294,7 +284,6 @@
|
||||
#define sfXChainCreateAccountAttestationCollectionElement ((14U << 16U) + 31U)
|
||||
#define sfPriceData ((14U << 16U) + 32U)
|
||||
#define sfCredential ((14U << 16U) + 33U)
|
||||
#define sfExportedTxn ((14U << 16U) + 90U)
|
||||
#define sfAmountEntry ((14U << 16U) + 91U)
|
||||
#define sfMintURIToken ((14U << 16U) + 92U)
|
||||
#define sfHookEmission ((14U << 16U) + 93U)
|
||||
@@ -302,9 +291,6 @@
|
||||
#define sfActiveValidator ((14U << 16U) + 95U)
|
||||
#define sfGenesisMint ((14U << 16U) + 96U)
|
||||
#define sfRemark ((14U << 16U) + 97U)
|
||||
#define sfHighReward ((14U << 16U) + 98U)
|
||||
#define sfLowReward ((14U << 16U) + 99U)
|
||||
#define sfExportResult ((14U << 16U) + 100U)
|
||||
#define sfSigners ((15U << 16U) + 3U)
|
||||
#define sfSignerEntries ((15U << 16U) + 4U)
|
||||
#define sfTemplate ((15U << 16U) + 5U)
|
||||
@@ -327,9 +313,9 @@
|
||||
#define sfAuthorizeCredentials ((15U << 16U) + 26U)
|
||||
#define sfUnauthorizeCredentials ((15U << 16U) + 27U)
|
||||
#define sfAcceptedCredentials ((15U << 16U) + 28U)
|
||||
#define sfAmounts ((15U << 16U) + 92U)
|
||||
#define sfHookEmissions ((15U << 16U) + 93U)
|
||||
#define sfImportVLKeys ((15U << 16U) + 94U)
|
||||
#define sfActiveValidators ((15U << 16U) + 95U)
|
||||
#define sfGenesisMints ((15U << 16U) + 96U)
|
||||
#define sfRemarks ((15U << 16U) + 97U)
|
||||
#define sfGenesisMints ((15U << 16U) + 96U)
|
||||
#define sfActiveValidators ((15U << 16U) + 95U)
|
||||
#define sfImportVLKeys ((15U << 16U) + 94U)
|
||||
#define sfHookEmissions ((15U << 16U) + 93U)
|
||||
#define sfAmounts ((15U << 16U) + 92U)
|
||||
|
||||
@@ -61,7 +61,6 @@
|
||||
#define ttNFTOKEN_MODIFY 70
|
||||
#define ttPERMISSIONED_DOMAIN_SET 71
|
||||
#define ttPERMISSIONED_DOMAIN_DELETE 72
|
||||
#define ttEXPORT 91
|
||||
#define ttCRON 92
|
||||
#define ttCRON_SET 93
|
||||
#define ttREMARKS_SET 94
|
||||
@@ -75,5 +74,3 @@
|
||||
#define ttUNL_MODIFY 102
|
||||
#define ttEMIT_FAILURE 103
|
||||
#define ttUNL_REPORT 104
|
||||
#define ttCONSENSUS_ENTROPY 105
|
||||
#define ttEXPORT_SIGNATURES 106
|
||||
|
||||
122
hook/tx_flags.h
122
hook/tx_flags.h
@@ -1,122 +0,0 @@
|
||||
// Generated using generate_txflags.sh
|
||||
#include "ls_flags.h"
|
||||
#include <stdint.h>
|
||||
|
||||
enum UniversalFlags : uint32_t {
|
||||
tfFullyCanonicalSig = 0x80000000,
|
||||
};
|
||||
|
||||
enum AccountSetFlags : uint32_t {
|
||||
tfRequireDestTag = 0x00010000,
|
||||
tfOptionalDestTag = 0x00020000,
|
||||
tfRequireAuth = 0x00040000,
|
||||
tfOptionalAuth = 0x00080000,
|
||||
tfDisallowXRP = 0x00100000,
|
||||
tfAllowXRP = 0x00200000,
|
||||
};
|
||||
|
||||
enum AccountFlags : uint32_t {
|
||||
asfRequireDest = 1,
|
||||
asfRequireAuth = 2,
|
||||
asfDisallowXRP = 3,
|
||||
asfDisableMaster = 4,
|
||||
asfAccountTxnID = 5,
|
||||
asfNoFreeze = 6,
|
||||
asfGlobalFreeze = 7,
|
||||
asfDefaultRipple = 8,
|
||||
asfDepositAuth = 9,
|
||||
asfAuthorizedNFTokenMinter = 10,
|
||||
asfTshCollect = 11,
|
||||
asfDisallowIncomingNFTokenOffer = 12,
|
||||
asfDisallowIncomingCheck = 13,
|
||||
asfDisallowIncomingPayChan = 14,
|
||||
asfDisallowIncomingTrustline = 15,
|
||||
asfDisallowIncomingRemit = 16,
|
||||
asfAllowTrustLineClawback = 17,
|
||||
};
|
||||
|
||||
enum OfferCreateFlags : uint32_t {
|
||||
tfPassive = 0x00010000,
|
||||
tfImmediateOrCancel = 0x00020000,
|
||||
tfFillOrKill = 0x00040000,
|
||||
tfSell = 0x00080000,
|
||||
};
|
||||
|
||||
enum PaymentFlags : uint32_t {
|
||||
tfNoRippleDirect = 0x00010000,
|
||||
tfPartialPayment = 0x00020000,
|
||||
tfLimitQuality = 0x00040000,
|
||||
};
|
||||
|
||||
enum TrustSetFlags : uint32_t {
|
||||
tfSetfAuth = 0x00010000,
|
||||
tfSetNoRipple = 0x00020000,
|
||||
tfClearNoRipple = 0x00040000,
|
||||
tfSetFreeze = 0x00100000,
|
||||
tfClearFreeze = 0x00200000,
|
||||
tfSetDeepFreeze = 0x00400000,
|
||||
tfClearDeepFreeze = 0x00800000
|
||||
};
|
||||
|
||||
enum EnableAmendmentFlags : uint32_t {
|
||||
tfGotMajority = 0x00010000,
|
||||
tfLostMajority = 0x00020000,
|
||||
tfTestSuite = 0x80000000,
|
||||
};
|
||||
|
||||
enum PaymentChannelClaimFlags : uint32_t {
|
||||
tfRenew = 0x00010000,
|
||||
tfClose = 0x00020000,
|
||||
};
|
||||
|
||||
enum NFTokenMintFlags : uint32_t {
|
||||
tfBurnable = 0x00000001,
|
||||
tfOnlyXRP = 0x00000002,
|
||||
tfTrustLine = 0x00000004,
|
||||
tfTransferable = 0x00000008,
|
||||
tfMutable = 0x00000010,
|
||||
tfStrongTSH = 0x00008000,
|
||||
};
|
||||
|
||||
enum MPTokenIssuanceCreateFlags : uint32_t {
|
||||
tfMPTCanLock = lsfMPTCanLock,
|
||||
tfMPTRequireAuth = lsfMPTRequireAuth,
|
||||
tfMPTCanEscrow = lsfMPTCanEscrow,
|
||||
tfMPTCanTrade = lsfMPTCanTrade,
|
||||
tfMPTCanTransfer = lsfMPTCanTransfer,
|
||||
tfMPTCanClawback = lsfMPTCanClawback,
|
||||
};
|
||||
|
||||
enum MPTokenAuthorizeFlags : uint32_t {
|
||||
tfMPTUnauthorize = 0x00000001,
|
||||
};
|
||||
|
||||
enum MPTokenIssuanceSetFlags : uint32_t {
|
||||
tfMPTLock = 0x00000001,
|
||||
tfMPTUnlock = 0x00000002,
|
||||
};
|
||||
|
||||
enum NFTokenCreateOfferFlags : uint32_t {
|
||||
tfSellNFToken = 0x00000001,
|
||||
};
|
||||
|
||||
enum ClaimRewardFlags : uint32_t {
|
||||
tfOptOut = 0x00000001,
|
||||
};
|
||||
|
||||
enum CronSetFlags : uint32_t {
|
||||
tfCronUnset = 0x00000001,
|
||||
};
|
||||
|
||||
enum AMMClawbackFlags : uint32_t {
|
||||
tfClawTwoAssets = 0x00000001,
|
||||
};
|
||||
|
||||
enum BridgeModifyFlags : uint32_t {
|
||||
tfClearAccountCreateAmount = 0x00010000,
|
||||
};
|
||||
|
||||
enum ConsensusEntropyFlags : uint32_t {
|
||||
tfEntropyCommit = 0x00000001, // entry is a commitment in commitSet
|
||||
tfEntropyReveal = 0x00000002, // entry is a reveal in entropySet
|
||||
};
|
||||
@@ -138,14 +138,14 @@ public:
|
||||
template <typename U>
|
||||
requires std::convertible_to<U, T>
|
||||
constexpr Expected(U&& r)
|
||||
: Base(boost::outcome_v2::in_place_type_t<T>{}, std::forward<U>(r))
|
||||
: Base(boost::outcome_v2::success(T(std::forward<U>(r))))
|
||||
{
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
requires std::convertible_to<U, E> && (!std::is_reference_v<U>)
|
||||
constexpr Expected(Unexpected<U> e)
|
||||
: Base(boost::outcome_v2::in_place_type_t<E>{}, std::move(e.value()))
|
||||
: Base(boost::outcome_v2::failure(E(std::move(e.value()))))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -14,11 +14,7 @@
|
||||
// Override uint256, Feature and Rules for guard checker build
|
||||
#define uint256 std::string
|
||||
#define featureHooksUpdate1 "1"
|
||||
#define featureHooksUpdate2 "1"
|
||||
#define featureExport "1"
|
||||
#define featureConsensusEntropy "1"
|
||||
#define fix20250131 "1"
|
||||
#define fixGuardDepth32 "1"
|
||||
namespace hook_api {
|
||||
struct Rules
|
||||
{
|
||||
@@ -322,7 +318,7 @@ namespace compare_mode {
|
||||
enum compare_mode : uint32_t { EQUAL = 1, LESS = 2, GREATER = 4 };
|
||||
}
|
||||
|
||||
enum class hook_return_code : int64_t {
|
||||
enum hook_return_code : int64_t {
|
||||
SUCCESS =
|
||||
0, // return codes > 0 are reserved for hook apis to return "success"
|
||||
OUT_OF_BOUNDS =
|
||||
@@ -386,13 +382,10 @@ enum class hook_return_code : int64_t {
|
||||
MEM_OVERLAP = -43, // one or more specified buffers are the same memory
|
||||
TOO_MANY_STATE_MODIFICATIONS = -44, // more than 5000 modified state
|
||||
// entires in the combined hook chains
|
||||
TOO_MANY_NAMESPACES = -45,
|
||||
EXPORT_FAILURE = -46,
|
||||
TOO_MANY_EXPORTED_TXN = -47,
|
||||
TOO_LITTLE_ENTROPY = -48,
|
||||
TOO_MANY_NAMESPACES = -45
|
||||
};
|
||||
|
||||
enum class ExitType : uint8_t {
|
||||
enum ExitType : uint8_t {
|
||||
UNSET = 0,
|
||||
WASM_ERROR = 1,
|
||||
ROLLBACK = 2,
|
||||
@@ -403,7 +396,6 @@ const uint16_t max_state_modifications = 256;
|
||||
const uint8_t max_slots = 255;
|
||||
const uint8_t max_nonce = 255;
|
||||
const uint8_t max_emit = 255;
|
||||
const uint8_t max_export = 2;
|
||||
const uint8_t max_params = 16;
|
||||
const double fee_base_multiplier = 1.1f;
|
||||
|
||||
@@ -444,9 +436,12 @@ getImportWhitelist(Rules const& rules)
|
||||
return whitelist;
|
||||
}
|
||||
|
||||
#undef HOOK_API_DEFINITION
|
||||
#undef I32
|
||||
#undef I64
|
||||
|
||||
enum GuardRulesVersion : uint64_t {
|
||||
GuardRuleFix20250131 = 0x00000001,
|
||||
GuardRuleDepth32 = 0x00000002,
|
||||
};
|
||||
|
||||
inline uint64_t
|
||||
@@ -455,8 +450,6 @@ getGuardRulesVersion(Rules const& rules)
|
||||
uint64_t version = 0;
|
||||
if (rules.enabled(fix20250131))
|
||||
version |= GuardRuleFix20250131;
|
||||
if (rules.enabled(fixGuardDepth32))
|
||||
version |= GuardRuleDepth32;
|
||||
return version;
|
||||
}
|
||||
|
||||
|
||||
@@ -204,13 +204,9 @@ struct WasmBlkInf
|
||||
}
|
||||
// compute worst case execution time
|
||||
inline uint64_t
|
||||
compute_wce(
|
||||
const WasmBlkInf* blk,
|
||||
int level,
|
||||
int max_level,
|
||||
bool* recursion_limit_reached)
|
||||
compute_wce(const WasmBlkInf* blk, int level, bool* recursion_limit_reached)
|
||||
{
|
||||
if (level > max_level)
|
||||
if (level > 16)
|
||||
{
|
||||
*recursion_limit_reached = true;
|
||||
return 0;
|
||||
@@ -237,8 +233,8 @@ compute_wce(
|
||||
|
||||
if (blk->children.size() > 0)
|
||||
for (auto const& child : blk->children)
|
||||
worst_case_execution += compute_wce(
|
||||
child, level + 1, max_level, recursion_limit_reached);
|
||||
worst_case_execution +=
|
||||
compute_wce(child, level + 1, recursion_limit_reached);
|
||||
|
||||
if (parent == 0 ||
|
||||
parent->iteration_bound ==
|
||||
@@ -792,17 +788,12 @@ check_guard(
|
||||
}
|
||||
|
||||
bool recursion_limit_reached = false;
|
||||
int max_level = 16;
|
||||
if (rulesVersion & hook_api::GuardRuleDepth32)
|
||||
max_level = 32;
|
||||
uint64_t wce =
|
||||
compute_wce(&(*root), 0, max_level, &recursion_limit_reached);
|
||||
uint64_t wce = compute_wce(&(*root), 0, &recursion_limit_reached);
|
||||
if (recursion_limit_reached)
|
||||
{
|
||||
GUARDLOG(hook::log::NESTING_LIMIT)
|
||||
<< "GuardCheck "
|
||||
<< "Maximum allowable depth of blocks reached (" << max_level
|
||||
<< " levels). Flatten "
|
||||
<< "Maximum allowable depth of blocks reached (16 levels). Flatten "
|
||||
"your loops and conditions!.\n";
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -3,297 +3,10 @@
|
||||
|
||||
#include <xrpld/app/misc/Transaction.h>
|
||||
#include <xrpl/hook/Enum.h>
|
||||
#include <cfenv>
|
||||
|
||||
namespace hook {
|
||||
|
||||
using HookReturnCode = hook_api::hook_return_code;
|
||||
|
||||
namespace hook_float {
|
||||
using enum hook_api::hook_return_code;
|
||||
|
||||
// power of 10 LUT for fast integer math
|
||||
static int64_t power_of_ten[19] = {
|
||||
1LL,
|
||||
10LL,
|
||||
100LL,
|
||||
1000LL,
|
||||
10000LL,
|
||||
100000LL,
|
||||
1000000LL,
|
||||
10000000LL,
|
||||
100000000LL,
|
||||
1000000000LL,
|
||||
10000000000LL,
|
||||
100000000000LL,
|
||||
1000000000000LL,
|
||||
10000000000000LL,
|
||||
100000000000000LL,
|
||||
1000000000000000LL, // 15
|
||||
10000000000000000LL,
|
||||
100000000000000000LL,
|
||||
1000000000000000000LL,
|
||||
};
|
||||
|
||||
using namespace hook_api;
|
||||
static int64_t const minMantissa = 1000000000000000ull;
|
||||
static int64_t const maxMantissa = 9999999999999999ull;
|
||||
static int32_t const minExponent = -96;
|
||||
static int32_t const maxExponent = 80;
|
||||
|
||||
inline Expected<int32_t, HookReturnCode>
|
||||
get_exponent(int64_t float1)
|
||||
{
|
||||
using enum hook_api::hook_return_code;
|
||||
if (float1 < 0)
|
||||
return Unexpected(INVALID_FLOAT);
|
||||
if (float1 == 0)
|
||||
return 0u;
|
||||
uint64_t float_in = (uint64_t)float1;
|
||||
float_in >>= 54U;
|
||||
float_in &= 0xFFU;
|
||||
return static_cast<int32_t>(float_in) - 97;
|
||||
}
|
||||
|
||||
inline Expected<uint64_t, HookReturnCode>
|
||||
get_mantissa(int64_t float1)
|
||||
{
|
||||
using enum hook_api::hook_return_code;
|
||||
if (float1 < 0)
|
||||
return Unexpected(INVALID_FLOAT);
|
||||
if (float1 == 0)
|
||||
return 0ULL;
|
||||
float1 -= ((((uint64_t)float1) >> 54U) << 54U);
|
||||
return float1;
|
||||
}
|
||||
|
||||
inline bool
|
||||
is_negative(int64_t float1)
|
||||
{
|
||||
return ((float1 >> 62U) & 1ULL) == 0;
|
||||
}
|
||||
|
||||
inline int64_t
|
||||
invert_sign(int64_t float1)
|
||||
{
|
||||
int64_t r = (int64_t)(((uint64_t)float1) ^ (1ULL << 62U));
|
||||
return r;
|
||||
}
|
||||
|
||||
inline int64_t
|
||||
set_sign(int64_t float1, bool set_negative)
|
||||
{
|
||||
bool neg = is_negative(float1);
|
||||
if ((neg && set_negative) || (!neg && !set_negative))
|
||||
return float1;
|
||||
|
||||
return invert_sign(float1);
|
||||
}
|
||||
|
||||
inline Expected<uint64_t, HookReturnCode>
|
||||
set_mantissa(int64_t float1, uint64_t mantissa)
|
||||
{
|
||||
using enum hook_api::hook_return_code;
|
||||
if (mantissa > maxMantissa)
|
||||
return Unexpected(MANTISSA_OVERSIZED);
|
||||
if (mantissa < minMantissa)
|
||||
return Unexpected(MANTISSA_UNDERSIZED);
|
||||
return float1 - get_mantissa(float1).value() + mantissa;
|
||||
}
|
||||
|
||||
inline Expected<uint64_t, HookReturnCode>
|
||||
set_exponent(int64_t float1, int32_t exponent)
|
||||
{
|
||||
using enum hook_api::hook_return_code;
|
||||
if (exponent > maxExponent)
|
||||
return Unexpected(EXPONENT_OVERSIZED);
|
||||
if (exponent < minExponent)
|
||||
return Unexpected(EXPONENT_UNDERSIZED);
|
||||
|
||||
uint64_t exp = (exponent + 97);
|
||||
exp <<= 54U;
|
||||
float1 &= ~(0xFFLL << 54);
|
||||
float1 += (int64_t)exp;
|
||||
return float1;
|
||||
}
|
||||
|
||||
inline Expected<uint64_t, HookReturnCode>
|
||||
make_float(ripple::IOUAmount& amt)
|
||||
{
|
||||
using enum hook_api::hook_return_code;
|
||||
int64_t man_out = amt.mantissa();
|
||||
int64_t float_out = 0;
|
||||
bool neg = man_out < 0;
|
||||
if (neg)
|
||||
man_out *= -1;
|
||||
|
||||
float_out = set_sign(float_out, neg);
|
||||
auto const mantissa = set_mantissa(float_out, (uint64_t)man_out);
|
||||
if (!mantissa)
|
||||
// TODO: This change requires the amendment.
|
||||
// return Unexpected(mantissa.error());
|
||||
float_out = (int64_t)mantissa.error();
|
||||
else
|
||||
float_out = mantissa.value();
|
||||
auto const exponent = set_exponent(float_out, amt.exponent());
|
||||
if (!exponent)
|
||||
return Unexpected(exponent.error());
|
||||
float_out = exponent.value();
|
||||
return float_out;
|
||||
}
|
||||
|
||||
inline Expected<uint64_t, HookReturnCode>
|
||||
make_float(uint64_t mantissa, int32_t exponent, bool neg)
|
||||
{
|
||||
using enum hook_api::hook_return_code;
|
||||
if (mantissa == 0)
|
||||
return 0ULL;
|
||||
if (mantissa > maxMantissa)
|
||||
return Unexpected(MANTISSA_OVERSIZED);
|
||||
if (mantissa < minMantissa)
|
||||
return Unexpected(MANTISSA_UNDERSIZED);
|
||||
if (exponent > maxExponent)
|
||||
return Unexpected(EXPONENT_OVERSIZED);
|
||||
if (exponent < minExponent)
|
||||
return Unexpected(EXPONENT_UNDERSIZED);
|
||||
int64_t out = 0;
|
||||
|
||||
auto const m = set_mantissa(out, mantissa);
|
||||
if (!m)
|
||||
return Unexpected(m.error()); // LCOV_EXCL_LINE
|
||||
out = m.value();
|
||||
|
||||
auto const e = set_exponent(out, exponent);
|
||||
if (!e)
|
||||
return Unexpected(e.error()); // LCOV_EXCL_LINE
|
||||
out = e.value();
|
||||
|
||||
out = set_sign(out, neg);
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function normalizes the mantissa and exponent passed, if it can.
|
||||
* It returns the XFL and mutates the supplied manitssa and exponent.
|
||||
* If a negative mantissa is provided then the returned XFL has the negative
|
||||
* flag set. If there is an overflow error return XFL_OVERFLOW. On underflow
|
||||
* returns canonical 0
|
||||
*/
|
||||
template <typename T>
|
||||
inline Expected<uint64_t, HookReturnCode>
|
||||
normalize_xfl(T& man, int32_t& exp, bool neg = false)
|
||||
{
|
||||
if (man == 0)
|
||||
return 0ULL;
|
||||
|
||||
if (man == std::numeric_limits<int64_t>::min())
|
||||
man++;
|
||||
|
||||
constexpr bool sman = std::is_same<T, int64_t>::value;
|
||||
static_assert(sman || std::is_same<T, uint64_t>());
|
||||
|
||||
if constexpr (sman)
|
||||
{
|
||||
if (man < 0)
|
||||
{
|
||||
man *= -1LL;
|
||||
neg = true;
|
||||
}
|
||||
}
|
||||
|
||||
// mantissa order
|
||||
std::feclearexcept(FE_ALL_EXCEPT);
|
||||
int32_t mo = log10(man);
|
||||
// defensively ensure log10 produces a sane result; we'll borrow the
|
||||
// overflow error code if it didn't
|
||||
if (std::fetestexcept(FE_INVALID))
|
||||
return Unexpected(XFL_OVERFLOW); // LCOV_EXCL_LINE
|
||||
|
||||
int32_t adjust = 15 - mo;
|
||||
|
||||
if (adjust > 0)
|
||||
{
|
||||
// defensive check
|
||||
if (adjust > 18)
|
||||
return 0ULL; // LCOV_EXCL_LINE
|
||||
man *= power_of_ten[adjust];
|
||||
exp -= adjust;
|
||||
}
|
||||
else if (adjust < 0)
|
||||
{
|
||||
// defensive check
|
||||
if (-adjust > 18)
|
||||
return Unexpected(XFL_OVERFLOW); // LCOV_EXCL_LINE
|
||||
man /= power_of_ten[-adjust];
|
||||
exp -= adjust;
|
||||
}
|
||||
|
||||
if (man == 0)
|
||||
{
|
||||
exp = 0;
|
||||
return 0ULL;
|
||||
}
|
||||
|
||||
// even after adjustment the mantissa can be outside the range by one place
|
||||
// improving the math above would probably alleviate the need for these
|
||||
// branches
|
||||
if (man < minMantissa)
|
||||
{
|
||||
if (man == minMantissa - 1LL)
|
||||
man += 1LL;
|
||||
else
|
||||
{
|
||||
man *= 10LL;
|
||||
exp--;
|
||||
}
|
||||
}
|
||||
|
||||
if (man > maxMantissa)
|
||||
{
|
||||
if (man == maxMantissa + 1LL)
|
||||
man -= 1LL;
|
||||
else
|
||||
{
|
||||
man /= 10LL;
|
||||
exp++;
|
||||
}
|
||||
}
|
||||
|
||||
if (exp < minExponent)
|
||||
{
|
||||
man = 0;
|
||||
exp = 0;
|
||||
return 0ULL;
|
||||
}
|
||||
|
||||
if (man == 0)
|
||||
{
|
||||
exp = 0;
|
||||
return 0ULL;
|
||||
}
|
||||
|
||||
if (exp > maxExponent)
|
||||
return Unexpected(XFL_OVERFLOW);
|
||||
|
||||
auto const ret = make_float((uint64_t)man, exp, neg);
|
||||
if constexpr (sman)
|
||||
{
|
||||
if (neg)
|
||||
man *= -1LL;
|
||||
}
|
||||
|
||||
if (!ret)
|
||||
return Unexpected(ret.error());
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const int64_t float_one_internal =
|
||||
make_float(1000000000000000ull, -15, false).value();
|
||||
|
||||
} // namespace hook_float
|
||||
|
||||
using namespace ripple;
|
||||
using HookReturnCode = hook_api::hook_return_code;
|
||||
|
||||
using Bytes = std::vector<std::uint8_t>;
|
||||
|
||||
@@ -345,9 +58,6 @@ public:
|
||||
// sto_erase(): same as sto_emplace with field_object = nullopt
|
||||
|
||||
/// etxn APIs
|
||||
Expected<Bytes, HookReturnCode>
|
||||
prepare(Slice const& txBlob) const;
|
||||
|
||||
Expected<std::shared_ptr<Transaction>, HookReturnCode>
|
||||
emit(Slice const& txBlob) const;
|
||||
|
||||
@@ -369,16 +79,6 @@ public:
|
||||
Expected<uint256, HookReturnCode>
|
||||
etxn_nonce() const;
|
||||
|
||||
/// xport APIs
|
||||
Expected<uint64_t, HookReturnCode>
|
||||
xport_reserve(uint64_t count) const;
|
||||
|
||||
Expected<uint256, HookReturnCode>
|
||||
xport(Slice const& txBlob) const;
|
||||
|
||||
Expected<uint64_t, HookReturnCode>
|
||||
xport_cancel(uint32_t ticketSeq) const;
|
||||
|
||||
/// float APIs
|
||||
Expected<uint64_t, HookReturnCode>
|
||||
float_set(int32_t exponent, int64_t mantissa) const;
|
||||
@@ -467,7 +167,7 @@ public:
|
||||
Expected<ripple::uint256, HookReturnCode>
|
||||
hook_hash(int32_t hook_no) const;
|
||||
|
||||
Expected<uint64_t, HookReturnCode>
|
||||
Expected<int64_t, HookReturnCode>
|
||||
hook_again() const;
|
||||
|
||||
Expected<Blob, HookReturnCode>
|
||||
@@ -617,7 +317,7 @@ private:
|
||||
bool modified) const;
|
||||
|
||||
// these are only used by get_stobject_length below
|
||||
enum class STOParseErrorCode {
|
||||
enum parse_error {
|
||||
pe_unexpected_end = -1,
|
||||
pe_unknown_type_early = -2, // detected early
|
||||
pe_unknown_type_late = -3, // end of function
|
||||
@@ -626,8 +326,8 @@ private:
|
||||
};
|
||||
|
||||
inline Expected<
|
||||
uint32_t,
|
||||
STOParseErrorCode>
|
||||
int32_t,
|
||||
parse_error>
|
||||
get_stobject_length(
|
||||
unsigned char* start, // in - begin iterator
|
||||
unsigned char* maxptr, // in - end iterator
|
||||
@@ -89,69 +89,58 @@
|
||||
|
||||
#define WASM_VAL_TYPE(T, b) CAT2(TYP_, T)
|
||||
|
||||
#define UNSIGNED_TYPE(T) std::make_unsigned_t<T>
|
||||
|
||||
#define DECLARE_HOOK_FUNCTION(R, F, ...) \
|
||||
std::variant<UNSIGNED_TYPE(R), hook_api::hook_return_code> F( \
|
||||
hook::HookContext& hookCtx, \
|
||||
WasmEdge_CallingFrameContext const& frameCtx __VA_OPT__( \
|
||||
COMMA __VA_ARGS__)); \
|
||||
extern WasmEdge_Result WasmFunction##F( \
|
||||
void* data_ptr, \
|
||||
const WasmEdge_CallingFrameContext* frameCtx, \
|
||||
const WasmEdge_Value* in, \
|
||||
WasmEdge_Value* out); \
|
||||
extern WasmEdge_ValType WasmFunctionParams##F[]; \
|
||||
extern WasmEdge_ValType WasmFunctionResult##F[]; \
|
||||
extern WasmEdge_FunctionTypeContext* WasmFunctionType##F; \
|
||||
#define DECLARE_HOOK_FUNCTION(R, F, ...) \
|
||||
R F(hook::HookContext& hookCtx, \
|
||||
WasmEdge_CallingFrameContext const& frameCtx __VA_OPT__( \
|
||||
COMMA __VA_ARGS__)); \
|
||||
extern WasmEdge_Result WasmFunction##F( \
|
||||
void* data_ptr, \
|
||||
const WasmEdge_CallingFrameContext* frameCtx, \
|
||||
const WasmEdge_Value* in, \
|
||||
WasmEdge_Value* out); \
|
||||
extern WasmEdge_ValType WasmFunctionParams##F[]; \
|
||||
extern WasmEdge_ValType WasmFunctionResult##F[]; \
|
||||
extern WasmEdge_FunctionTypeContext* WasmFunctionType##F; \
|
||||
extern WasmEdge_String WasmFunctionName##F;
|
||||
|
||||
#define DEFINE_HOOK_FUNCTION(R, F, ...) \
|
||||
WasmEdge_Result hook_api::WasmFunction##F( \
|
||||
void* data_ptr, \
|
||||
const WasmEdge_CallingFrameContext* frameCtx, \
|
||||
const WasmEdge_Value* in, \
|
||||
WasmEdge_Value* out) \
|
||||
{ \
|
||||
__VA_OPT__(int _stack = 0;) \
|
||||
__VA_OPT__(FOR_VARS(VAR_ASSIGN, 2, __VA_ARGS__);) \
|
||||
hook::HookContext* hookCtx = \
|
||||
reinterpret_cast<hook::HookContext*>(data_ptr); \
|
||||
auto const& return_code = hook_api::F( \
|
||||
*hookCtx, \
|
||||
*const_cast<WasmEdge_CallingFrameContext*>(frameCtx) \
|
||||
__VA_OPT__(COMMA STRIP_TYPES(__VA_ARGS__))); \
|
||||
if (std::holds_alternative<hook_api::hook_return_code>(return_code) && \
|
||||
(std::get<hook_api::hook_return_code>(return_code) == \
|
||||
RC_ROLLBACK || \
|
||||
std::get<hook_api::hook_return_code>(return_code) == RC_ACCEPT)) \
|
||||
return WasmEdge_Result_Terminate; \
|
||||
out[0] = RET_ASSIGN( \
|
||||
R, \
|
||||
std::holds_alternative<UNSIGNED_TYPE(R)>(return_code) \
|
||||
? std::get<UNSIGNED_TYPE(R)>(return_code) \
|
||||
: R(std::get<hook_api::hook_return_code>(return_code))); \
|
||||
return WasmEdge_Result_Success; \
|
||||
}; \
|
||||
WasmEdge_ValType hook_api::WasmFunctionParams##F[] = { \
|
||||
__VA_OPT__(FOR_VARS(WASM_VAL_TYPE, 0, __VA_ARGS__))}; \
|
||||
WasmEdge_ValType hook_api::WasmFunctionResult##F[1] = { \
|
||||
WASM_VAL_TYPE(R, dummy)}; \
|
||||
WasmEdge_FunctionTypeContext* hook_api::WasmFunctionType##F = \
|
||||
WasmEdge_FunctionTypeCreate( \
|
||||
WasmFunctionParams##F, \
|
||||
VA_NARGS(NULL __VA_OPT__(, __VA_ARGS__)), \
|
||||
WasmFunctionResult##F, \
|
||||
1); \
|
||||
WasmEdge_String hook_api::WasmFunctionName##F = \
|
||||
WasmEdge_StringCreateByCString(#F); \
|
||||
std::variant<UNSIGNED_TYPE(R), hook_api::hook_return_code> hook_api::F( \
|
||||
hook::HookContext& hookCtx, \
|
||||
WasmEdge_CallingFrameContext const& frameCtx __VA_OPT__( \
|
||||
#define DEFINE_HOOK_FUNCTION(R, F, ...) \
|
||||
WasmEdge_Result hook_api::WasmFunction##F( \
|
||||
void* data_ptr, \
|
||||
const WasmEdge_CallingFrameContext* frameCtx, \
|
||||
const WasmEdge_Value* in, \
|
||||
WasmEdge_Value* out) \
|
||||
{ \
|
||||
__VA_OPT__(int _stack = 0;) \
|
||||
__VA_OPT__(FOR_VARS(VAR_ASSIGN, 2, __VA_ARGS__);) \
|
||||
hook::HookContext* hookCtx = \
|
||||
reinterpret_cast<hook::HookContext*>(data_ptr); \
|
||||
R return_code = hook_api::F( \
|
||||
*hookCtx, \
|
||||
*const_cast<WasmEdge_CallingFrameContext*>(frameCtx) \
|
||||
__VA_OPT__(COMMA STRIP_TYPES(__VA_ARGS__))); \
|
||||
if (return_code == RC_ROLLBACK || return_code == RC_ACCEPT) \
|
||||
return WasmEdge_Result_Terminate; \
|
||||
out[0] = RET_ASSIGN(R, return_code); \
|
||||
return WasmEdge_Result_Success; \
|
||||
}; \
|
||||
WasmEdge_ValType hook_api::WasmFunctionParams##F[] = { \
|
||||
__VA_OPT__(FOR_VARS(WASM_VAL_TYPE, 0, __VA_ARGS__))}; \
|
||||
WasmEdge_ValType hook_api::WasmFunctionResult##F[1] = { \
|
||||
WASM_VAL_TYPE(R, dummy)}; \
|
||||
WasmEdge_FunctionTypeContext* hook_api::WasmFunctionType##F = \
|
||||
WasmEdge_FunctionTypeCreate( \
|
||||
WasmFunctionParams##F, \
|
||||
VA_NARGS(NULL __VA_OPT__(, __VA_ARGS__)), \
|
||||
WasmFunctionResult##F, \
|
||||
1); \
|
||||
WasmEdge_String hook_api::WasmFunctionName##F = \
|
||||
WasmEdge_StringCreateByCString(#F); \
|
||||
R hook_api::F( \
|
||||
hook::HookContext& hookCtx, \
|
||||
WasmEdge_CallingFrameContext const& frameCtx __VA_OPT__( \
|
||||
COMMA __VA_ARGS__))
|
||||
|
||||
#define HOOK_SETUP() \
|
||||
using enum hook_api::hook_return_code; \
|
||||
try \
|
||||
{ \
|
||||
[[maybe_unused]] ApplyContext& applyCtx = hookCtx.applyCtx; \
|
||||
@@ -214,7 +203,7 @@
|
||||
host_memory_ptr, \
|
||||
guest_memory_length) \
|
||||
{ \
|
||||
uint64_t bytes_written = 0; \
|
||||
int64_t bytes_written = 0; \
|
||||
WRITE_WASM_MEMORY( \
|
||||
bytes_written, \
|
||||
guest_dst_ptr, \
|
||||
@@ -283,7 +272,7 @@
|
||||
data_ptr < (data_ptr_in)) \
|
||||
return INTERNAL_ERROR; \
|
||||
if (data_len == 0) \
|
||||
return 0ULL; \
|
||||
return 0; \
|
||||
if ((write_ptr_in) == 0) \
|
||||
return data_as_int64(data_ptr, data_len); \
|
||||
if (data_len > (write_len_in)) \
|
||||
|
||||
@@ -367,33 +367,3 @@ HOOK_API_DEFINITION(
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, xpop_slot, (uint32_t, uint32_t),
|
||||
featureHooksUpdate1)
|
||||
|
||||
// int64_t prepare(uint32_t write_ptr, uint32_t write_len, uint32_t read_ptr, uint32_t read_len);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, prepare, (uint32_t, uint32_t, uint32_t, uint32_t),
|
||||
featureHooksUpdate2)
|
||||
|
||||
// int64_t xport_reserve(uint32_t count);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, xport_reserve, (uint32_t),
|
||||
featureExport)
|
||||
|
||||
// int64_t xport(uint32_t write_ptr, uint32_t write_len, uint32_t read_ptr, uint32_t read_len);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, xport, (uint32_t, uint32_t, uint32_t, uint32_t),
|
||||
featureExport)
|
||||
|
||||
// int64_t xport_cancel(uint32_t ticket_seq);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, xport_cancel, (uint32_t),
|
||||
featureExport)
|
||||
|
||||
// int64_t dice(uint32_t sides, uint32_t min_tier, uint32_t min_count);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, dice, (uint32_t, uint32_t, uint32_t),
|
||||
featureConsensusEntropy)
|
||||
|
||||
// int64_t random(uint32_t write_ptr, uint32_t write_len, uint32_t min_tier, uint32_t min_count);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, random, (uint32_t, uint32_t, uint32_t, uint32_t),
|
||||
featureConsensusEntropy)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,2 +0,0 @@
|
||||
---
|
||||
DisableFormat: true
|
||||
@@ -153,11 +153,7 @@ message TMStatusChange
|
||||
message TMProposeSet
|
||||
{
|
||||
required uint32 proposeSeq = 1;
|
||||
// Proposed transaction-set identity. Legacy/plain proposals carry the
|
||||
// tx-set hash directly; ConsensusExtensions proposals carry a serialized
|
||||
// ExtendedPosition whose first field is that tx-set hash, followed by
|
||||
// signed RNG/Export sidecar fields.
|
||||
required bytes currentTxHash = 2;
|
||||
required bytes currentTxHash = 2; // the hash of the ledger we are proposing
|
||||
required bytes nodePubKey = 3;
|
||||
required uint32 closeTime = 4;
|
||||
required bytes signature = 5; // signature of above fields
|
||||
@@ -170,14 +166,6 @@ message TMProposeSet
|
||||
|
||||
// Number of hops traveled
|
||||
optional uint32 hops = 12 [deprecated=true];
|
||||
|
||||
// Export signatures for pending exports seen in the proposal set. The
|
||||
// proposal's ExtendedPosition includes a digest of this repeated field, so
|
||||
// these side-channel blobs are covered by the proposal signature.
|
||||
// Each entry is: txnHash (32 bytes) + validator pubkey (33 bytes)
|
||||
// + multisign signature (variable length). Validators attach these
|
||||
// so export quorum can be reached within the same consensus round.
|
||||
repeated bytes exportSignatures = 13;
|
||||
}
|
||||
|
||||
enum TxSetStatus
|
||||
@@ -396,3 +384,4 @@ message TMHaveTransactions
|
||||
{
|
||||
repeated bytes hashes = 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
#ifndef RIPPLE_PROTOCOL_ENTROPY_TIER_H_INCLUDED
|
||||
#define RIPPLE_PROTOCOL_ENTROPY_TIER_H_INCLUDED
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
/// Which gate the ledger's entropy passed. Stored in sfEntropyTier (UINT8)
|
||||
/// on the ttCONSENSUS_ENTROPY pseudo-transaction and the ConsensusEntropy
|
||||
/// ledger entry.
|
||||
///
|
||||
/// EntropyCount says how many validators contributed; EntropyTier says which
|
||||
/// gate the result passed. Values are strength-ordered so consumers can gate
|
||||
/// with a numeric comparison (tier >= required).
|
||||
///
|
||||
/// RESIDUAL BIAS — applies to EVERY tier, including participant_aligned and
|
||||
/// validator_quorum, not just the fallback. This is a commit/reveal scheme: a
|
||||
/// validator can withhold its reveal until after observing peers' reveals,
|
||||
/// choosing between two outcomes (its contribution in vs. out) — up to one bit
|
||||
/// of influence per withholder, and colluding withholders near a threshold can
|
||||
/// instead force a downgrade to a lower tier. These tiers bound and *label*
|
||||
/// manipulation (it is observable and limited); they are NOT bias-resistant
|
||||
/// against a colluding validator minority. Applications that need that
|
||||
/// guarantee (e.g. high-value lotteries) must layer additional mechanisms on
|
||||
/// top (VRF / threshold-BLS style constructions).
|
||||
enum EntropyTier : std::uint8_t {
|
||||
/// No usable entropy (reserved; a fresh ConsensusEntropy entry should
|
||||
/// always carry one of the tiers below).
|
||||
entropyTierNone = 0,
|
||||
|
||||
/// Consensus-bound deterministic fallback: derived from already-agreed
|
||||
/// round inputs (parent ledger hash, base tx set hash, sequence) under
|
||||
/// HashPrefix::entropyFallback when no agreed reveal set reaches either
|
||||
/// participant_aligned or validator_quorum. Unpredictable in practice but
|
||||
/// user-influenceable via transaction submission — never suitable for
|
||||
/// value-bearing outcomes.
|
||||
entropyTierConsensusFallback = 1,
|
||||
|
||||
/// Participant-aligned sub-quorum entropy: the agreed reveal set aligned at
|
||||
/// the tier-2 participant threshold — below the 80% validator quorum but at
|
||||
/// or above the equivocation-intersection floor over the original
|
||||
/// (pre-nUNL)
|
||||
/// view. Weaker than validator_quorum; opt-in for hooks via min_tier.
|
||||
entropyTierParticipantAligned = 2,
|
||||
|
||||
/// Validator commit/reveal entropy whose sidecar set passed the
|
||||
/// active-validator-view quorum alignment gate.
|
||||
entropyTierValidatorQuorum = 3,
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
@@ -1,53 +0,0 @@
|
||||
#ifndef RIPPLE_PROTOCOL_EXPORT_LIMITS_H_INCLUDED
|
||||
#define RIPPLE_PROTOCOL_EXPORT_LIMITS_H_INCLUDED
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
// Export system caps.
|
||||
//
|
||||
// These limits bound the DoS surface of the export signature system:
|
||||
// - Each pending export requires every validator to sign it every round
|
||||
// (sign-once, attach once via TMProposeSet)
|
||||
// - Inbound signature processing involves crypto verification per sig
|
||||
// - The open-ledger cap (maxPendingExports) is the root constraint;
|
||||
// signing throughput and inbound processing are transitively bounded by it
|
||||
struct ExportLimits
|
||||
{
|
||||
// Maximum exports a single hook execution may produce. Hook API ABI
|
||||
// constant hook_api::max_export must stay equal.
|
||||
static constexpr std::uint8_t maxExportsPerHook = 2;
|
||||
|
||||
// Maximum pending export transactions in an open/apply ledger.
|
||||
// Hook-emitted export backlog drains into the open ledger at this cap.
|
||||
// This transitively caps:
|
||||
// - signatures per TMProposeSet message (1 per pending export)
|
||||
// - inbound proposal signature processing (clamped to this)
|
||||
// - validator signing work per round
|
||||
static constexpr std::uint8_t maxPendingExports = 8;
|
||||
|
||||
// Maximum number of ledgers a pending export may retry before its
|
||||
// mandatory LastLedgerSequence expires. This bounds validator signing work
|
||||
// for both hook-emitted and user-submitted exports.
|
||||
static constexpr std::uint32_t maxRetryLedgers = 5;
|
||||
|
||||
// Maximum byte length of a single export-signature wire blob:
|
||||
// txHash(32) + validator pubkey(33) + multisign signature(<= 72).
|
||||
// A fully-canonical secp256k1 signature is at most 72 bytes (ed25519 is
|
||||
// 64), so 137 is the true upper bound for a well-formed entry. The proposal
|
||||
// ingress path hashes these blobs BEFORE the proposal signature is
|
||||
// verified, so bounding the per-blob size caps pre-auth hashing/copy work
|
||||
// (DoS).
|
||||
static constexpr std::size_t maxExportSignatureBytes = 32 + 33 + 72;
|
||||
|
||||
// Export-signature sidecar leaves wrap one export-signature blob in an
|
||||
// STObject envelope. Keep this comfortably above the canonical encoding
|
||||
// while bounding fetched, peer-supplied leaf bytes before parse/hash work.
|
||||
static constexpr std::size_t maxExportSignatureSidecarBytes = 256;
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
@@ -33,39 +33,35 @@
|
||||
*
|
||||
* Steps required to add new features to the code:
|
||||
*
|
||||
* 1) Add the appropriate XRPL_FEATURE or XRPL_FIX macro definition for the
|
||||
* feature to features.macro with the feature's name, `Supported::no`, and
|
||||
* `VoteBehavior::DefaultNo`.
|
||||
*
|
||||
* 2) Use the generated variable name as the parameter to `view.rules.enabled()`
|
||||
* to control flow into new code that this feature limits. (featureName or
|
||||
* fixName)
|
||||
*
|
||||
* 3) If the feature development is COMPLETE, and the feature is ready to be
|
||||
* SUPPORTED, change the macro parameter in features.macro to Supported::yes.
|
||||
*
|
||||
* 4) In general, any newly supported amendments (`Supported::yes`) should have
|
||||
* a `VoteBehavior::DefaultNo` indefinitely so that external governance can
|
||||
* make the decision on when to activate it. High priority bug fixes can be
|
||||
* an exception to this rule. In such cases, ensure the fix has been
|
||||
* clearly communicated to the community using appropriate channels,
|
||||
* then change the macro parameter in features.macro to
|
||||
* `VoteBehavior::DefaultYes`. The communication process is beyond
|
||||
* the scope of these instructions.
|
||||
*
|
||||
* 1) In this file, increment `numFeatures` and add a uint256 declaration
|
||||
* for the feature at the bottom
|
||||
* 2) Add a uint256 definition for the feature to the corresponding source
|
||||
* file (Feature.cpp). Use `registerFeature` to create the feature with
|
||||
* the feature's name, `Supported::no`, and `VoteBehavior::DefaultNo`. This
|
||||
* should be the only place the feature's name appears in code as a string.
|
||||
* 3) Use the uint256 as the parameter to `view.rules.enabled()` to
|
||||
* control flow into new code that this feature limits.
|
||||
* 4) If the feature development is COMPLETE, and the feature is ready to be
|
||||
* SUPPORTED, change the `registerFeature` parameter to Supported::yes.
|
||||
* 5) When the feature is ready to be ENABLED, change the `registerFeature`
|
||||
* parameter to `VoteBehavior::DefaultYes`.
|
||||
* In general, any newly supported amendments (`Supported::yes`) should have
|
||||
* a `VoteBehavior::DefaultNo` for at least one full release cycle. High
|
||||
* priority bug fixes can be an exception to this rule of thumb.
|
||||
*
|
||||
* When a feature has been enabled for several years, the conditional code
|
||||
* may be removed, and the feature "retired". To retire a feature:
|
||||
*
|
||||
* 1) MOVE the macro definition in features.macro to the "retired features"
|
||||
* section at the end of the file, and change the macro to XRPL_RETIRE.
|
||||
*
|
||||
* 1) Remove the uint256 declaration from this file.
|
||||
* 2) MOVE the uint256 definition in Feature.cpp to the "retired features"
|
||||
* section at the end of the file.
|
||||
* 3) CHANGE the name of the variable to start with "retired".
|
||||
* 4) CHANGE the parameters of the `registerFeature` call to `Supported::yes`
|
||||
* and `VoteBehavior::DefaultNo`.
|
||||
* The feature must remain registered and supported indefinitely because it
|
||||
* may exist in the Amendments object on ledger. There is no need to vote
|
||||
* for it because there's nothing to vote for. If the feature definition is
|
||||
* removed completely from the code, any instances running that code will get
|
||||
* amendment blocked. Removing the feature from the ledger is beyond the scope
|
||||
* of these instructions.
|
||||
* still exists in the ledger, but there is no need to vote for it because
|
||||
* there's nothing to vote for. If it is removed completely from the code, any
|
||||
* instances running that code will get amendment blocked. Removing the
|
||||
* feature from the ledger is beyond the scope of these instructions.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -80,32 +76,11 @@ allAmendments();
|
||||
|
||||
namespace detail {
|
||||
|
||||
#pragma push_macro("XRPL_FEATURE")
|
||||
#undef XRPL_FEATURE
|
||||
#pragma push_macro("XRPL_FIX")
|
||||
#undef XRPL_FIX
|
||||
#pragma push_macro("XRPL_RETIRE")
|
||||
#undef XRPL_RETIRE
|
||||
|
||||
#define XRPL_FEATURE(name, supported, vote) +1
|
||||
#define XRPL_FIX(name, supported, vote) +1
|
||||
#define XRPL_RETIRE(name) +1
|
||||
|
||||
// This value SHOULD be equal to the number of amendments registered in
|
||||
// Feature.cpp. Because it's only used to reserve storage, and determine how
|
||||
// large to make the FeatureBitset, it MAY be larger. It MUST NOT be less than
|
||||
// the actual number of amendments. A LogicError on startup will verify this.
|
||||
static constexpr std::size_t numFeatures =
|
||||
(0 +
|
||||
#include <xrpl/protocol/detail/features.macro>
|
||||
);
|
||||
|
||||
#undef XRPL_RETIRE
|
||||
#pragma pop_macro("XRPL_RETIRE")
|
||||
#undef XRPL_FIX
|
||||
#pragma pop_macro("XRPL_FIX")
|
||||
#undef XRPL_FEATURE
|
||||
#pragma pop_macro("XRPL_FEATURE")
|
||||
static constexpr std::size_t numFeatures = 111;
|
||||
|
||||
/** Amendments that this server supports and the default voting behavior.
|
||||
Whether they are enabled depends on the Rules defined in the validated
|
||||
@@ -345,17 +320,12 @@ foreachFeature(FeatureBitset bs, F&& f)
|
||||
#undef XRPL_FEATURE
|
||||
#pragma push_macro("XRPL_FIX")
|
||||
#undef XRPL_FIX
|
||||
#pragma push_macro("XRPL_RETIRE")
|
||||
#undef XRPL_RETIRE
|
||||
|
||||
#define XRPL_FEATURE(name, supported, vote) extern uint256 const feature##name;
|
||||
#define XRPL_FIX(name, supported, vote) extern uint256 const fix##name;
|
||||
#define XRPL_RETIRE(name)
|
||||
|
||||
#include <xrpl/protocol/detail/features.macro>
|
||||
|
||||
#undef XRPL_RETIRE
|
||||
#pragma pop_macro("XRPL_RETIRE")
|
||||
#undef XRPL_FIX
|
||||
#pragma pop_macro("XRPL_FIX")
|
||||
#undef XRPL_FEATURE
|
||||
|
||||
@@ -96,21 +96,6 @@ enum class HashPrefix : std::uint32_t {
|
||||
|
||||
/** Credentials signature */
|
||||
credential = detail::make_hash_prefix('C', 'R', 'D'),
|
||||
|
||||
/** consensus extension sidecar object */
|
||||
sidecar = detail::make_hash_prefix('S', 'C', 'R'),
|
||||
|
||||
/** consensus diagnostic observed participant set */
|
||||
observedParticipants = detail::make_hash_prefix('O', 'B', 'P'),
|
||||
|
||||
/** consensus-bound fallback entropy digest (Tier 1: derived from
|
||||
already-agreed round inputs when no agreed reveal set reaches an
|
||||
accepted validator-participant tier; never to be confused with
|
||||
validator entropy) */
|
||||
entropyFallback = detail::make_hash_prefix('E', 'F', 'B'),
|
||||
|
||||
/** consensus entropy transaction-ordering salt */
|
||||
entropyTxnOrder = detail::make_hash_prefix('E', 'T', 'O'),
|
||||
};
|
||||
|
||||
template <class Hasher>
|
||||
|
||||
@@ -97,12 +97,6 @@ public:
|
||||
|
||||
static IOUAmount
|
||||
minPositiveAmount();
|
||||
|
||||
friend std::ostream&
|
||||
operator<<(std::ostream& os, IOUAmount const& x)
|
||||
{
|
||||
return os << to_string(x);
|
||||
}
|
||||
};
|
||||
|
||||
inline IOUAmount::IOUAmount(beast::Zero)
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
#ifndef RIPPLE_PROTOCOL_IMPORT_H_INCLUDED
|
||||
#define RIPPLE_PROTOCOL_IMPORT_H_INCLUDED
|
||||
|
||||
// #include <ripple/basics/Log.h>
|
||||
#include <xrpld/app/misc/Manifest.h>
|
||||
#include <xrpl/basics/Log.h>
|
||||
#include <xrpl/basics/StringUtilities.h>
|
||||
#include <xrpl/basics/base64.h>
|
||||
#include <xrpl/json/json_reader.h>
|
||||
@@ -454,15 +454,6 @@ getVLInfo(Json::Value const& xpop, beast::Journal const& j)
|
||||
<< "Import: unl blob was not valid json (after base64 decoding)";
|
||||
return {};
|
||||
}
|
||||
auto const isNonNegativeUInt = [](Json::Value const& value) {
|
||||
return value.isUInt() || (value.isInt() && value.asInt() >= 0);
|
||||
};
|
||||
if (!list.isMember(jss::sequence) ||
|
||||
!isNonNegativeUInt(list[jss::sequence]))
|
||||
{
|
||||
JLOG(j.warn()) << "Import: unl blob sequence was missing or negative";
|
||||
return {};
|
||||
}
|
||||
auto const sequence = list[jss::sequence].asUInt();
|
||||
auto const m = deserializeManifest(base64_decode(
|
||||
xpop[jss::validation][jss::unl][jss::manifest].asString()));
|
||||
|
||||
@@ -62,9 +62,6 @@ emittedDir() noexcept;
|
||||
Keylet
|
||||
emittedTxn(uint256 const& id) noexcept;
|
||||
|
||||
Keylet
|
||||
shadowTicket(AccountID const& account, std::uint32_t ticketSeq) noexcept;
|
||||
|
||||
Keylet
|
||||
hookDefinition(uint256 const& hash) noexcept;
|
||||
|
||||
@@ -121,10 +118,6 @@ negativeUNL() noexcept;
|
||||
Keylet const&
|
||||
UNLReport() noexcept;
|
||||
|
||||
/** The (fixed) index of the object containing consensus-derived entropy. */
|
||||
Keylet const&
|
||||
consensusEntropy() noexcept;
|
||||
|
||||
/** The beginning of an order book */
|
||||
struct book_t
|
||||
{
|
||||
|
||||
@@ -147,9 +147,8 @@ enum LedgerSpecificFlags {
|
||||
0x40000000, // True, has minted tokens in the past
|
||||
lsfDisallowIncomingRemit = // True, no remits allowed to this account
|
||||
0x80000000,
|
||||
// 0x0004000 is available
|
||||
lsfAllowTrustLineClawback =
|
||||
0x00001000, // True, enable clawback
|
||||
lsfAllowTrustLineClawback =
|
||||
0x00001000, // True, enable clawback
|
||||
|
||||
// ltOFFER
|
||||
lsfPassive = 0x00010000,
|
||||
@@ -164,10 +163,10 @@ enum LedgerSpecificFlags {
|
||||
lsfHighNoRipple = 0x00200000,
|
||||
lsfLowFreeze = 0x00400000, // True, low side has set freeze flag
|
||||
lsfHighFreeze = 0x00800000, // True, high side has set freeze flag
|
||||
lsfAMMNode = 0x01000000, // True, trust line to AMM. Used by client
|
||||
// apps to identify payments via AMM.
|
||||
lsfLowDeepFreeze = 0x02000000, // True, low side has set deep freeze flag
|
||||
lsfHighDeepFreeze = 0x04000000, // True, high side has set deep freeze flag
|
||||
lsfAMMNode = 0x01000000, // True, trust line to AMM. Used by client
|
||||
// apps to identify payments via AMM.
|
||||
|
||||
// ltSIGNER_LIST
|
||||
lsfOneOwnerCount = 0x00010000, // True, uses only one OwnerCount
|
||||
|
||||
@@ -43,19 +43,6 @@ std::size_t constexpr txMinSizeBytes = 10;
|
||||
/** Largest legal byte size of a transaction. */
|
||||
std::size_t constexpr txMaxSizeBytes = megabytes(1);
|
||||
|
||||
/** Largest network ID whose transactions retain the legacy canonical form.
|
||||
|
||||
Transactions on these networks must omit sfNetworkID. Transactions on
|
||||
networks with larger IDs must include sfNetworkID matching the network.
|
||||
*/
|
||||
std::uint32_t constexpr maxNetworkIDWithoutTxField = 1024;
|
||||
|
||||
constexpr bool
|
||||
requiresTxNetworkID(std::uint32_t networkID)
|
||||
{
|
||||
return networkID > maxNetworkIDWithoutTxField;
|
||||
}
|
||||
|
||||
/** The maximum number of unfunded offers to delete at once */
|
||||
std::size_t constexpr unfundedOfferRemoveLimit = 1000;
|
||||
|
||||
|
||||
@@ -28,9 +28,6 @@
|
||||
|
||||
namespace ripple {
|
||||
|
||||
bool
|
||||
isFeatureEnabled(uint256 const& feature);
|
||||
|
||||
class DigestAwareReadView;
|
||||
|
||||
/** Rules controlling protocol behavior. */
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
#ifndef RIPPLE_PROTOCOL_SIDECAR_TYPE_H_INCLUDED
|
||||
#define RIPPLE_PROTOCOL_SIDECAR_TYPE_H_INCLUDED
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
/// Discriminator for sidecar set entries (SHAMap leaves used for
|
||||
/// consensus extension data: RNG commit/reveal, export signatures).
|
||||
///
|
||||
/// Stored in sfSidecarType (UINT8) on each STObject entry.
|
||||
/// Makes sidecar sets self-describing — no content-sniffing needed.
|
||||
enum SidecarType : std::uint8_t {
|
||||
sidecarRngCommit = 1,
|
||||
sidecarRngReveal = 2,
|
||||
sidecarExportSig = 3,
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
@@ -68,10 +68,7 @@ enum TELcodes : TERUnderlyingType {
|
||||
telNON_LOCAL_EMITTED_TXN,
|
||||
telIMPORT_VL_KEY_NOT_RECOGNISED,
|
||||
telCAN_NOT_QUEUE_IMPORT,
|
||||
// Keep test-only sentinels before appended branch-local TEL codes so their
|
||||
// numeric values do not move.
|
||||
telENV_RPC_FAILED,
|
||||
telSHADOW_TICKET_REQUIRED,
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -140,7 +137,6 @@ enum TEMcodes : TERUnderlyingType {
|
||||
temXCHAIN_BRIDGE_NONDOOR_OWNER,
|
||||
temXCHAIN_BRIDGE_BAD_MIN_ACCOUNT_CREATE_AMOUNT,
|
||||
temXCHAIN_BRIDGE_BAD_REWARD_AMOUNT,
|
||||
temXCHAIN_TOO_MANY_ATTESTATIONS, // RESERVED - not used
|
||||
|
||||
temHOOK_DATA_TOO_LARGE,
|
||||
temEMPTY_DID,
|
||||
@@ -237,10 +233,8 @@ enum TERcodes : TERUnderlyingType {
|
||||
terQUEUED, // Transaction is being held in TxQ until fee drops
|
||||
terPRE_TICKET, // Ticket is not yet in ledger but might be on its way
|
||||
terNO_AMM, // AMM doesn't exist for the asset pair
|
||||
terNO_HOOK, // Transaction requires a non-existent hook definition
|
||||
terNO_HOOK // Transaction requires a non-existent hook definition
|
||||
// (referenced by sfHookHash)
|
||||
terRETRY_EXPORT // Export does not yet have enough validator signatures.
|
||||
// Retained in retriable set for next ledger.
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -368,7 +362,6 @@ enum TECcodes : TERUnderlyingType {
|
||||
tecARRAY_TOO_LARGE = 197,
|
||||
tecLOCKED = 198,
|
||||
tecBAD_CREDENTIALS = 199,
|
||||
tecEXPORT_EXPIRED = 200,
|
||||
tecLAST_POSSIBLE_ENTRY = 255,
|
||||
};
|
||||
|
||||
|
||||
@@ -125,14 +125,14 @@ enum TrustSetFlags : uint32_t {
|
||||
tfSetFreeze = 0x00100000,
|
||||
tfClearFreeze = 0x00200000,
|
||||
tfSetDeepFreeze = 0x00400000,
|
||||
tfClearDeepFreeze = 0x00800000
|
||||
tfClearDeepFreeze = 0x00800000,
|
||||
};
|
||||
constexpr std::uint32_t tfTrustSetMask =
|
||||
~(tfUniversal | tfSetfAuth | tfSetNoRipple | tfClearNoRipple | tfSetFreeze |
|
||||
tfClearFreeze | tfSetDeepFreeze | tfClearDeepFreeze);
|
||||
|
||||
// EnableAmendment flags:
|
||||
enum EnableAmendmentFlags : uint32_t {
|
||||
enum EnableAmendmentFlags : std::uint32_t {
|
||||
tfGotMajority = 0x00010000,
|
||||
tfLostMajority = 0x00020000,
|
||||
tfTestSuite = 0x80000000,
|
||||
@@ -274,13 +274,6 @@ enum BridgeModifyFlags : uint32_t {
|
||||
tfClearAccountCreateAmount = 0x00010000,
|
||||
};
|
||||
constexpr std::uint32_t tfBridgeModifyMask = ~(tfUniversal | tfClearAccountCreateAmount);
|
||||
|
||||
// ConsensusEntropy flags (used on ttCONSENSUS_ENTROPY SHAMap entries):
|
||||
enum ConsensusEntropyFlags : uint32_t {
|
||||
tfEntropyCommit = 0x00000001, // entry is a commitment in commitSet
|
||||
tfEntropyReveal = 0x00000002, // entry is a reveal in entropySet
|
||||
};
|
||||
// flag=0 (no tfEntropyCommit/tfEntropyReveal) = final injected pseudo-tx
|
||||
// clang-format on
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
@@ -140,12 +140,6 @@ public:
|
||||
mHookEmissions = hookEmissions;
|
||||
}
|
||||
|
||||
void
|
||||
setExportResult(STObject const& exportResult)
|
||||
{
|
||||
mExportResult = exportResult;
|
||||
}
|
||||
|
||||
bool
|
||||
hasHookExecutions() const
|
||||
{
|
||||
@@ -158,12 +152,6 @@ public:
|
||||
return static_cast<bool>(mHookEmissions);
|
||||
}
|
||||
|
||||
bool
|
||||
hasExportResult() const
|
||||
{
|
||||
return static_cast<bool>(mExportResult);
|
||||
}
|
||||
|
||||
STAmount
|
||||
getDeliveredAmount() const
|
||||
{
|
||||
@@ -188,7 +176,6 @@ private:
|
||||
std::optional<STAmount> mDelivered;
|
||||
std::optional<STArray> mHookExecutions;
|
||||
std::optional<STArray> mHookEmissions;
|
||||
std::optional<STObject> mExportResult;
|
||||
|
||||
STArray mNodes;
|
||||
};
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user