Compare commits

...

2 Commits

Author SHA1 Message Date
tequ
26c86681b5 release builder gcc13 2026-09-24 01:27:05 +09:00
Niq Dudfield
2e32b5c6bb feat(server_definitions): distinguish config-forced from ledger-enabled amendments (#765) 2026-09-23 15:33:43 +10:00
6 changed files with 215 additions and 50 deletions

View File

@@ -55,10 +55,8 @@ sed -i s/\"0.0.0\"/\"$(date +%Y).$(date +%-m).$(date +%-d)-$(git rev-parse --abb
conan export external/snappy --version 1.1.10 --user xahaud --channel stable &&
conan export external/soci --version 4.0.3 --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
# The tool_requires('b2/5.3.2') in conanfile.py should force b2 to build from source
# with the correct toolchain, avoiding the GLIBCXX_3.4.29 issue
# Install dependencies. The Conan profile tags package_ids with the glibc
# baseline, so tools like b2/protoc are built locally instead of downloaded.
echo "=== Installing dependencies ===" &&
conan install .. --output-folder . --build missing --settings build_type=$BUILD_TYPE \
-o with_wasmedge=False -o tool_requires_b2=True &&
@@ -78,8 +76,10 @@ strip -s rippled &&
mv rippled xahaud &&
echo "=== Full ldd output ===" &&
ldd xahaud &&
echo "=== Running libcheck ===" &&
libcheck xahaud &&
echo "=== Checking GLIBC requirement (must be <= 2.28) ===" &&
GLIBC_MAX=$(objdump -T xahaud | grep -o 'GLIBC_[0-9.]*' | sort -uV | tail -1) &&
echo "Max required: $GLIBC_MAX" &&
[ "$(printf '%s\n' GLIBC_2.28 "$GLIBC_MAX" | sort -V | tail -1)" = "GLIBC_2.28" ] &&
echo "Build host: `hostname`" > release.info &&
echo "Build date: `date`" >> release.info &&
echo "Build md5: `md5sum xahaud`" >> release.info &&
@@ -88,9 +88,11 @@ git remote -v >> release.info &&
echo "Git status:" >> release.info &&
git status -v >> release.info &&
echo "Git log [last 20]:" >> release.info &&
git log -n 20 >> release.info;
git log -n 20 >> release.info || BUILD_FAILED=1
if [[ "$4" == "" ]]; then
if [[ -n "${BUILD_FAILED:-}" ]]; then
echo "ERR build failed, not publishing"
elif [[ "$4" == "" ]]; then
# Non GH, local building
echo "Non GH, local building, no Action runner magic"
else
@@ -109,7 +111,7 @@ else
echo $(date +%Y).$(date +%-m).$(date +%-d)-$(git rev-parse --abbrev-ref HEAD)+$4
fi
cd ..;
cd /io;
mv src/xrpld/net/detail/RegisterSSLCerts.cpp.old src/xrpld/net/detail/RegisterSSLCerts.cpp;
mv cmake/deps/WasmEdge.old cmake/deps/WasmEdge.cmake;
@@ -117,3 +119,5 @@ rm src/certs/certbundle.h;
git checkout src/libxrpl/protocol/BuildInfo.cpp;
echo "END INSIDE CONTAINER - CORE"
[[ -z "${BUILD_FAILED:-}" ]] || exit 1

View File

@@ -64,7 +64,7 @@ if [ "$(grep certbundle.h src/xrpld/net/detail/RegisterSSLCerts.cpp | wc -l)" -e
sed -i "s/#include <xrpld\/net\/RegisterSSLCerts.h>/\0\n#include <certs\/certbundle.h>/g" src/xrpld/net/detail/RegisterSSLCerts.cpp
fi
# Environment setup moved to Dockerfile in release-builder.sh
source /opt/rh/gcc-toolset-11/enable
source /opt/rh/gcc-toolset-13/enable
export PATH=/usr/local/bin:$PATH
export CC='/usr/lib64/ccache/gcc' &&
export CXX='/usr/lib64/ccache/g++' &&

View File

@@ -292,7 +292,9 @@ JSS(duration_us); // out: NetworkOPs
JSS(effective); // out: ValidatorList
// in: UNL
JSS(elapsed_seconds);
JSS(enabled); // out: AmendmentTable
JSS(enabled); // out: AmendmentTable (on-ledger);
// ServerDefinitions (this server)
JSS(ledger_enabled); // out: ServerDefinitions (on-ledger)
JSS(engine_result); // out: NetworkOPs, TransactionSign, Submit
JSS(engine_result_code); // out: NetworkOPs, TransactionSign, Submit
JSS(engine_result_message); // out: NetworkOPs, TransactionSign, Submit

View File

@@ -12,10 +12,12 @@ echo "Cleaning previously built binary"
rm -f release-build/xahaud
BUILD_CORES=$(echo "scale=0 ; $(nproc) / 1.337" | bc)
OUT_DIR="/data/builds"
if [[ "$GITHUB_REPOSITORY" == "" ]]; then
#Default
BUILD_CORES=${BUILD_CORES:-8}
OUT_DIR="./data/builds"
fi
# Ensure still works outside of GH Actions by setting these to /dev/null
@@ -51,7 +53,7 @@ CACHE_VOLUME_NAME="xahau-release-builder-cache"
if false; then
echo "Static container, execute in static container to have max. cache"
docker start $CONTAINER_NAME
docker exec -i $CONTAINER_NAME /hbb_exe/activate-exec bash -c "source /opt/rh/gcc-toolset-11/enable && bash -x /io/build-core.sh '$GITHUB_REPOSITORY' '$GITHUB_SHA' '$BUILD_CORES' '$GITHUB_RUN_NUMBER'"
docker exec -i $CONTAINER_NAME bash -c "source /opt/rh/gcc-toolset-13/enable && bash -x /io/build-core.sh '$GITHUB_REPOSITORY' '$GITHUB_SHA' '$BUILD_CORES' '$GITHUB_RUN_NUMBER'"
docker stop $CONTAINER_NAME
else
echo "No static container, build on temp container"
@@ -63,24 +65,32 @@ else
# Create inline Dockerfile with environment setup for build-full.sh
DOCKERFILE_CONTENT=$(
cat <<'DOCKERFILE_EOF'
FROM ghcr.io/phusion/holy-build-box:4.0.1-amd64
FROM --platform=linux/amd64 almalinux:8
ARG BUILD_CORES=8
# Enable repositories and install dependencies
RUN /hbb_exe/activate-exec bash -c "dnf install -y epel-release && \
dnf config-manager --set-enabled powertools || dnf config-manager --set-enabled crb && \
# AlmaLinux 8 keeps the glibc 2.28 baseline (same as holy-build-box 4).
# The devel repo (disabled by default, like in holy-build-box) provides ncurses-static.
# - gcc-toolset-13: compiler for xahaud itself and its Conan dependencies
# - gcc-toolset-11: used only for the pre-built LLD/WasmEdge below (known-good);
# their static libs are linked into the gcc-13 build with -static-libstdc++
RUN dnf install -y dnf-plugins-core epel-release && \
dnf config-manager --set-enabled powertools && \
printf "%s\n" "[devel]" "name=AlmaLinux 8 - Devel" \
"baseurl=https://repo.almalinux.org/almalinux/8/devel/\$basearch/os/" \
"gpgcheck=1" "gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux" "enabled=0" \
> /etc/yum.repos.d/almalinux-devel.repo && \
dnf install -y --enablerepo=devel \
wget git \
gcc-toolset-11-gcc-c++ gcc-toolset-11-binutils gcc-toolset-11-libatomic-devel \
wget git unzip xz perl hostname make \
gcc-toolset-11-gcc-c++ gcc-toolset-11-binutils \
gcc-toolset-13-gcc-c++ gcc-toolset-13-binutils gcc-toolset-13-libatomic-devel \
lz4 lz4-devel \
ncurses-static ncurses-devel \
snappy snappy-devel \
zlib zlib-devel zlib-static \
libasan \
python3 python3-pip \
sqlite-devel \
python3.11 python3.11-pip \
ccache \
ninja-build \
mold \
patch \
glibc-devel glibc-static \
@@ -90,16 +100,15 @@ RUN /hbb_exe/activate-exec bash -c "dnf install -y epel-release && \
texinfo \
libtool \
llvm14-static llvm14-devel && \
dnf clean all"
dnf clean all
# Install Conan 2 and CMake
RUN /hbb_exe/activate-exec pip3 install "conan>=2.0,<3.0" && \
/hbb_exe/activate-exec wget -q https://github.com/Kitware/CMake/releases/download/v3.25.3/cmake-3.25.3-linux-x86_64.tar.gz -O cmake.tar.gz && \
mkdir cmake && \
tar -xzf cmake.tar.gz --strip-components=1 -C cmake && \
RUN python3.11 -m pip install "conan>=2.0,<3.0" "ninja>=1.13,<1.14" && \
wget -q https://github.com/Kitware/CMake/releases/download/v3.25.3/cmake-3.25.3-linux-x86_64.tar.gz -O cmake.tar.gz && \
tar -xzf cmake.tar.gz --strip-components=1 -C /usr/local && \
rm cmake.tar.gz
# Dual Boost configuration in HBB environment:
# Dual Boost configuration:
# - Manual Boost in /usr/local (minimal: for WasmEdge which is pre-built in Docker)
# - Conan Boost (full: for the application and all dependencies via toolchain)
#
@@ -109,7 +118,8 @@ RUN /hbb_exe/activate-exec pip3 install "conan>=2.0,<3.0" && \
# - link=static: Creates static Boost libraries (.a files) instead of shared (.so files)
# - runtime-link=shared: Links Boost libraries against shared libc (glibc)
# WasmEdge only needs boost::filesystem and boost::system
RUN /hbb_exe/activate-exec bash -c "echo 'Boost cache bust: v5-minimal' && \
RUN echo 'Boost cache bust: v5-minimal' && \
source /opt/rh/gcc-toolset-11/enable && \
rm -rf /usr/local/lib/libboost* /usr/local/include/boost && \
cd /tmp && \
wget -q https://archives.boost.io/release/1.86.0/source/boost_1_86_0.tar.gz -O boost.tar.gz && \
@@ -121,7 +131,7 @@ RUN /hbb_exe/activate-exec bash -c "echo 'Boost cache bust: v5-minimal' && \
link=static runtime-link=shared -j${BUILD_CORES} \
--with-filesystem --with-system && \
cd /tmp && \
rm -rf boost boost.tar.gz"
rm -rf boost boost.tar.gz
ENV CMAKE_EXE_LINKER_FLAGS="-static-libstdc++"
@@ -132,7 +142,7 @@ ENV CC='ccache gcc'
ENV CXX='ccache g++'
# Install LLD
RUN /hbb_exe/activate-exec bash -c "source /opt/rh/gcc-toolset-11/enable && \
RUN source /opt/rh/gcc-toolset-11/enable && \
cd /tmp && \
wget -q https://github.com/llvm/llvm-project/releases/download/llvmorg-14.0.3/lld-14.0.3.src.tar.xz && \
wget -q https://github.com/llvm/llvm-project/releases/download/llvmorg-14.0.3/libunwind-14.0.3.src.tar.xz && \
@@ -145,11 +155,11 @@ RUN /hbb_exe/activate-exec bash -c "source /opt/rh/gcc-toolset-11/enable && \
-DLLVM_LIBRARY_DIR=/usr/lib64/llvm14/lib/ \
-DCMAKE_INSTALL_PREFIX=/usr/lib64/llvm14/ \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_EXE_LINKER_FLAGS=\"\$CMAKE_EXE_LINKER_FLAGS\" && \
-DCMAKE_EXE_LINKER_FLAGS="$CMAKE_EXE_LINKER_FLAGS" && \
make -j${BUILD_CORES} install && \
ln -s /usr/lib64/llvm14/lib/include/lld /usr/include/lld && \
cp /usr/lib64/llvm14/lib/liblld*.a /usr/local/lib/ && \
cd /tmp && rm -rf lld-* libunwind-*"
cd /tmp && rm -rf lld-* libunwind-*
# Build and install WasmEdge (static version)
# Note: Conan only provides WasmEdge with shared library linking.
@@ -163,7 +173,7 @@ RUN cd /tmp && \
cd WasmEdge-0.11.2 && \
( mkdir -p build; echo "" ) && \
cd build && \
/hbb_exe/activate-exec bash -c "source /opt/rh/gcc-toolset-11/enable && \
source /opt/rh/gcc-toolset-11/enable && \
ln -sf /opt/rh/gcc-toolset-11/root/usr/bin/ar /usr/bin/ar && \
ln -sf /opt/rh/gcc-toolset-11/root/usr/bin/ranlib /usr/bin/ranlib && \
echo '=== Binutils version check ===' && \
@@ -181,9 +191,9 @@ RUN cd /tmp && \
-DWASMEDGE_BUILD_PLUGINS=OFF \
-DWASMEDGE_LINK_TOOLS_STATIC=ON \
-DBoost_NO_BOOST_CMAKE=ON \
-DCMAKE_EXE_LINKER_FLAGS=\"\$CMAKE_EXE_LINKER_FLAGS\" \
-DCMAKE_EXE_LINKER_FLAGS="$CMAKE_EXE_LINKER_FLAGS" \
&& \
make -j${BUILD_CORES} install" && \
make -j${BUILD_CORES} install && \
cp -r include/api/wasmedge /usr/include/ && \
cd /tmp && rm -rf WasmEdge* 0.11.2.zip
@@ -192,7 +202,7 @@ ENV PATH=/usr/local/bin:$PATH
# Configure ccache and Conan 2
# NOTE: Using echo commands instead of heredocs because heredocs in Docker RUN commands are finnicky
RUN /hbb_exe/activate-exec bash -c "ccache -M 100G && \
RUN ccache -M 100G && \
ccache -o cache_dir=/cache/ccache && \
ccache -o compiler_check=content && \
ccache -o direct_mode=true && \
@@ -207,14 +217,23 @@ RUN /hbb_exe/activate-exec bash -c "ccache -M 100G && \
echo 'compiler=gcc' >> ~/.conan2/profiles/default && \
echo 'compiler.cppstd=20' >> ~/.conan2/profiles/default && \
echo 'compiler.libcxx=libstdc++11' >> ~/.conan2/profiles/default && \
echo 'compiler.version=11' >> ~/.conan2/profiles/default && \
echo 'compiler.version=13' >> ~/.conan2/profiles/default && \
echo 'os=Linux' >> ~/.conan2/profiles/default && \
echo '' >> ~/.conan2/profiles/default && \
echo '[conf]' >> ~/.conan2/profiles/default && \
echo '# Force building from source for packages with binary compatibility issues' >> ~/.conan2/profiles/default && \
echo '*:tools.system.package_manager:mode=build' >> ~/.conan2/profiles/default && \
ln -s ../../bin/ccache /usr/lib64/ccache/g++ && \
ln -s ../../bin/ccache /usr/lib64/ccache/c++"
echo '# Tag every package_id with the glibc baseline so ConanCenter binaries (built on a' >> ~/.conan2/profiles/default && \
echo '# newer glibc, e.g. protoc/b2) never match; everything is built locally and cached' >> ~/.conan2/profiles/default && \
echo 'user.xahaud:glibc=2.28' >> ~/.conan2/profiles/default && \
echo 'tools.info.package_id:confs=["user.xahaud:glibc"]' >> ~/.conan2/profiles/default && \
echo "" >> ~/.conan2/profiles/default && \
echo "# ninja is provided by pip (manylinux wheel); building it in Conan hits a gcc-13 LTO ICE" >> ~/.conan2/profiles/default && \
echo "[platform_tool_requires]" >> ~/.conan2/profiles/default && \
echo "ninja/1.13.2" >> ~/.conan2/profiles/default && \
ln -sf ../../bin/ccache /usr/lib64/ccache/gcc && \
ln -sf ../../bin/ccache /usr/lib64/ccache/g++ && \
ln -sf ../../bin/ccache /usr/lib64/ccache/c++
DOCKERFILE_EOF
)
@@ -227,15 +246,15 @@ DOCKERFILE_EOF
if [[ "$GITHUB_REPOSITORY" == "" ]]; then
# Non GH, local building
echo "Non-GH runner, local building, temp container"
docker run -i --user 0:$(id -g) --rm -v /data/builds:/data/builds -v $(pwd):/io -v "$CACHE_VOLUME_NAME":/cache --network host "$IMAGE_NAME" /hbb_exe/activate-exec bash -c "source /opt/rh/gcc-toolset-11/enable && bash -x /io/build-full.sh '$GITHUB_REPOSITORY' '$GITHUB_SHA' '$BUILD_CORES' '$GITHUB_RUN_NUMBER'"
docker run -i --user 0:$(id -g) --rm -v $OUT_DIR:/data/builds -v $(pwd):/io -v "$CACHE_VOLUME_NAME":/cache --network host "$IMAGE_NAME" bash -c "source /opt/rh/gcc-toolset-13/enable && bash -x /io/build-full.sh '$GITHUB_REPOSITORY' '$GITHUB_SHA' '$BUILD_CORES' '$GITHUB_RUN_NUMBER'"
else
# GH Action, runner
echo "GH Action, runner, clean & re-create create persistent container"
docker rm -f $CONTAINER_NAME
echo "echo 'Stopping container: $CONTAINER_NAME'" >>"$JOB_CLEANUP_SCRIPT"
echo "docker stop --time=15 \"$CONTAINER_NAME\" || echo 'Failed to stop container or container not running'" >>"$JOB_CLEANUP_SCRIPT"
docker run -di --user 0:$(id -g) --name $CONTAINER_NAME -v /data/builds:/data/builds -v $(pwd):/io -v "$CACHE_VOLUME_NAME":/cache --network host "$IMAGE_NAME" /hbb_exe/activate-exec bash
docker exec -i $CONTAINER_NAME /hbb_exe/activate-exec bash -c "source /opt/rh/gcc-toolset-11/enable && bash -x /io/build-full.sh '$GITHUB_REPOSITORY' '$GITHUB_SHA' '$BUILD_CORES' '$GITHUB_RUN_NUMBER'"
docker run -di --user 0:$(id -g) --name $CONTAINER_NAME -v $OUT_DIR:/data/builds -v $(pwd):/io -v "$CACHE_VOLUME_NAME":/cache --network host "$IMAGE_NAME" bash
docker exec -i $CONTAINER_NAME bash -c "source /opt/rh/gcc-toolset-13/enable && bash -x /io/build-full.sh '$GITHUB_REPOSITORY' '$GITHUB_SHA' '$BUILD_CORES' '$GITHUB_RUN_NUMBER'"
docker stop $CONTAINER_NAME
fi
fi

View File

@@ -163,7 +163,7 @@ public:
void
testNoParams(FeatureBitset features)
{
testcase("No Params, None Enabled");
testcase("Default Env: config-forced, none on-ledger");
using namespace test::jtx;
Env env{*this};
@@ -178,8 +178,6 @@ public:
{
if (!BEAST_EXPECT(feature.isMember(jss::name)))
return;
// default config - so all should be disabled, and
// supported. Some may be vetoed.
bool expectVeto =
(votes.at(feature[jss::name].asString()) ==
VoteBehavior::DefaultNo);
@@ -188,8 +186,12 @@ public:
VoteBehavior::Obsolete);
BEAST_EXPECTS(
feature.isMember(jss::enabled) &&
!feature[jss::enabled].asBool(),
feature[jss::enabled].asBool(),
feature[jss::name].asString() + " enabled");
BEAST_EXPECTS(
feature.isMember(jss::ledger_enabled) &&
!feature[jss::ledger_enabled].asBool(),
feature[jss::name].asString() + " ledger_enabled");
BEAST_EXPECTS(
feature.isMember(jss::vetoed) &&
feature[jss::vetoed].isBool() == !expectObsolete &&
@@ -208,7 +210,7 @@ public:
void
testSomeEnabled(FeatureBitset features)
{
testcase("No Params, Some Enabled");
testcase("Two config-forced, none on-ledger");
using namespace test::jtx;
Env env{
@@ -228,7 +230,10 @@ public:
(void)id.parseHex(it.key().asString().c_str());
if (!BEAST_EXPECT((*it).isMember(jss::name)))
return;
bool expectEnabled = env.app().getAmendmentTable().isEnabled(id);
bool const expectOnLedger =
env.app().getAmendmentTable().isEnabled(id);
bool const expectForced =
id == featureDepositAuth || id == featureDepositPreauth;
bool expectSupported =
env.app().getAmendmentTable().isSupported(id);
bool expectVeto =
@@ -239,9 +244,14 @@ public:
VoteBehavior::Obsolete);
BEAST_EXPECTS(
(*it).isMember(jss::enabled) &&
(*it)[jss::enabled].asBool() == expectEnabled,
(*it)[jss::enabled].asBool() ==
(expectOnLedger || expectForced),
(*it)[jss::name].asString() + " enabled");
if (expectEnabled)
BEAST_EXPECTS(
(*it).isMember(jss::ledger_enabled) &&
(*it)[jss::ledger_enabled].asBool() == expectOnLedger,
(*it)[jss::name].asString() + " ledger_enabled");
if (expectOnLedger)
BEAST_EXPECTS(
!(*it).isMember(jss::vetoed),
(*it)[jss::name].asString() + " vetoed");
@@ -360,12 +370,122 @@ public:
}
}
void
testConfigForced(FeatureBitset features)
{
testcase("Config-forced features ([features] stanza)");
using namespace test::jtx;
auto const forced = featurePriceOracle;
auto const forcedHex = to_string(forced);
Env env{*this, FeatureBitset(forced)};
auto jrr = env.rpc("server_definitions")[jss::result];
if (!BEAST_EXPECT(jrr.isMember(jss::features)))
return;
bool sawForced = false;
for (auto it = jrr[jss::features].begin();
it != jrr[jss::features].end();
++it)
{
auto const& f = *it;
auto const name = f[jss::name].asString();
if (!BEAST_EXPECTS(
f.isMember(jss::enabled) && f.isMember(jss::ledger_enabled),
name + " enabled/ledger_enabled"))
return;
BEAST_EXPECTS(
!f[jss::ledger_enabled].asBool(), name + " ledger_enabled");
if (it.key().asString() == forcedHex)
{
sawForced = true;
BEAST_EXPECTS(f[jss::enabled].asBool(), name + " enabled");
}
else
{
BEAST_EXPECTS(!f[jss::enabled].asBool(), name + " enabled");
}
}
BEAST_EXPECT(sawForced);
}
void
testOnLedger(FeatureBitset features)
{
testcase("On-ledger plus one config-forced");
using namespace test::jtx;
// Veto XahauGenesis: FRESH would otherwise enable it via pseudo-tx.
auto const forced = featurePriceOracle;
auto const forcedHex = to_string(forced);
Env env{
*this,
envconfig([](std::unique_ptr<Config> cfg) {
cfg->START_UP = Config::FRESH;
cfg->section(SECTION_VETO_AMENDMENTS)
.append(to_string(featureXahauGenesis) + " XahauGenesis");
return cfg;
}),
FeatureBitset(forced)};
auto jrr = env.rpc("server_definitions")[jss::result];
if (!BEAST_EXPECT(jrr.isMember(jss::features)))
return;
bool sawOnLedger = false;
bool sawForced = false;
for (auto it = jrr[jss::features].begin();
it != jrr[jss::features].end();
++it)
{
uint256 id;
(void)id.parseHex(it.key().asString().c_str());
auto const& f = *it;
auto const name = f[jss::name].asString();
if (!BEAST_EXPECTS(
f.isMember(jss::enabled) && f.isMember(jss::ledger_enabled),
name + " enabled/ledger_enabled"))
return;
bool const onLedger = env.app().getAmendmentTable().isEnabled(id);
bool const isForced = it.key().asString() == forcedHex;
BEAST_EXPECTS(
f[jss::ledger_enabled].asBool() == onLedger,
name + " ledger_enabled");
BEAST_EXPECTS(
f[jss::enabled].asBool() == (onLedger || isForced),
name + " enabled");
if (onLedger)
sawOnLedger = true;
if (isForced)
{
sawForced = true;
BEAST_EXPECTS(!onLedger, name + " forced not on-ledger");
}
}
BEAST_EXPECT(sawOnLedger);
BEAST_EXPECT(sawForced);
}
void
testServerFeatures(FeatureBitset features)
{
testNoParams(features);
testSomeEnabled(features);
testWithMajorities(features);
testConfigForced(features);
testOnLedger(features);
}
void

View File

@@ -22,6 +22,7 @@
#include <xrpld/app/main/Application.h>
#include <xrpld/app/misc/AmendmentTable.h>
#include <xrpld/app/misc/NetworkOPs.h>
#include <xrpld/core/Config.h>
#include <xrpld/rpc/detail/TransactionSign.h>
#include <xrpl/json/json_value.h>
#include <xrpl/json/json_writer.h>
@@ -545,6 +546,25 @@ doServerDefinitions(RPC::JsonContext& context)
features[to_string(h)][jss::majority] =
t.time_since_epoch().count();
// getJson's enabled is on-ledger; [features] also apply here.
for (auto const& name : features.getMemberNames())
{
Json::Value& entry = features[name];
entry[jss::ledger_enabled] = entry[jss::enabled].asBool();
}
for (auto const& h : context.app.config().features)
{
Json::Value& entry = features[to_string(h)];
if (!entry.isMember(jss::name))
{
if (auto const fname = featureToName(h); !fname.empty())
entry[jss::name] = fname;
}
if (!entry.isMember(jss::ledger_enabled))
entry[jss::ledger_enabled] = false;
entry[jss::enabled] = true;
}
lastFeatures = features;
{
const std::string out = Json::FastWriter().write(features);