From b9dd8545959dd83950aafdef7d4e83e778e707a3 Mon Sep 17 00:00:00 2001 From: Nicholas Dudfield Date: Sat, 21 Feb 2026 17:46:46 +0700 Subject: [PATCH] refactor: unify featureExport + featureConsensusEntropy into featureExportRNG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Single amendment flag for both features. numFeatures 94 → 93. Exclude featureExportRNG from default test set to prevent ConsensusEntropy pseudo-tx injection from breaking existing tests. --- src/ripple/app/consensus/RCLConsensus.cpp | 6 +++--- src/ripple/app/hook/Enum.h | 3 +-- src/ripple/app/hook/hook_api.macro | 8 ++++---- src/ripple/app/hook/impl/applyHook.cpp | 2 +- .../app/misc/impl/ExportSignatureCollector.cpp | 2 +- src/ripple/app/misc/impl/TxQ.cpp | 2 +- src/ripple/app/tx/impl/Change.cpp | 4 ++-- src/ripple/app/tx/impl/Import.cpp | 4 ++-- src/ripple/app/tx/impl/SetHook.cpp | 2 +- src/ripple/protocol/Feature.h | 5 ++--- src/ripple/protocol/impl/Feature.cpp | 3 +-- src/test/app/ConsensusEntropy_test.cpp | 12 ++++++------ src/test/app/Export_test.cpp | 4 ++-- src/test/jtx/Env.h | 2 +- 14 files changed, 28 insertions(+), 31 deletions(-) diff --git a/src/ripple/app/consensus/RCLConsensus.cpp b/src/ripple/app/consensus/RCLConsensus.cpp index 0555e24a5..95de6d929 100644 --- a/src/ripple/app/consensus/RCLConsensus.cpp +++ b/src/ripple/app/consensus/RCLConsensus.cpp @@ -454,7 +454,7 @@ RCLConsensus::Adaptor::onClose( // all: no commitment, no reveal, no SHAMap entries. The surviving // proposers will close those rounds with fewer commits (possibly // falling back to ZERO entropy) until the rejoiner starts proposing. - if (proposing && prevLedger->rules().enabled(featureConsensusEntropy)) + if (proposing && prevLedger->rules().enabled(featureExportRNG)) { cacheUNLReport(); generateEntropySecret(); @@ -477,7 +477,7 @@ RCLConsensus::Adaptor::onClose( { JLOG(j_.debug()) << "RNG: onClose skipped (proposing=" << proposing << " amendment=" - << prevLedger->rules().enabled(featureConsensusEntropy) + << prevLedger->rules().enabled(featureExportRNG) << ")"; } @@ -610,7 +610,7 @@ RCLConsensus::Adaptor::doAccept( // Inject consensus entropy pseudo-transaction (if amendment enabled) // This must happen before buildLCL so the entropy tx is in the ledger - if (prevLedger.ledger_->rules().enabled(featureConsensusEntropy)) + if (prevLedger.ledger_->rules().enabled(featureExportRNG)) injectEntropyPseudoTx(retriableTxs, prevLedger.seq() + 1); else clearRngState(); diff --git a/src/ripple/app/hook/Enum.h b/src/ripple/app/hook/Enum.h index 9e32f4fe5..7285105b1 100644 --- a/src/ripple/app/hook/Enum.h +++ b/src/ripple/app/hook/Enum.h @@ -15,9 +15,8 @@ #define uint256 std::string #define featureHooksUpdate1 "1" #define featureHooksUpdate2 "1" -#define featureExport "1" +#define featureExportRNG "1" #define fix20250131 "1" -#define featureConsensusEntropy "1" namespace hook_api { struct Rules { diff --git a/src/ripple/app/hook/hook_api.macro b/src/ripple/app/hook/hook_api.macro index 1a1ab3e2c..28cfbf048 100644 --- a/src/ripple/app/hook/hook_api.macro +++ b/src/ripple/app/hook/hook_api.macro @@ -376,19 +376,19 @@ HOOK_API_DEFINITION( // int64_t xport_reserve(uint32_t count); HOOK_API_DEFINITION( int64_t, xport_reserve, (uint32_t), - featureExport) + featureExportRNG) // 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) + featureExportRNG) // int64_t dice(uint32_t sides); HOOK_API_DEFINITION( int64_t, dice, (uint32_t), - featureConsensusEntropy) + featureExportRNG) // int64_t random(uint32_t write_ptr, uint32_t write_len); HOOK_API_DEFINITION( int64_t, random, (uint32_t, uint32_t), - featureConsensusEntropy) + featureExportRNG) diff --git a/src/ripple/app/hook/impl/applyHook.cpp b/src/ripple/app/hook/impl/applyHook.cpp index 8fbb1d169..a384d26b5 100644 --- a/src/ripple/app/hook/impl/applyHook.cpp +++ b/src/ripple/app/hook/impl/applyHook.cpp @@ -1712,7 +1712,7 @@ hook::finalizeHookResult( meta.setFieldU16( sfHookEmitCount, emission_txnid.size()); // this will never wrap, hard limit - if (applyCtx.view().rules().enabled(featureExport)) + if (applyCtx.view().rules().enabled(featureExportRNG)) { meta.setFieldU16(sfHookExportCount, exported_txnid.size()); } diff --git a/src/ripple/app/misc/impl/ExportSignatureCollector.cpp b/src/ripple/app/misc/impl/ExportSignatureCollector.cpp index 066baf502..d70e28ef8 100644 --- a/src/ripple/app/misc/impl/ExportSignatureCollector.cpp +++ b/src/ripple/app/misc/impl/ExportSignatureCollector.cpp @@ -473,7 +473,7 @@ signPendingExports( { std::vector> result; - if (!view.rules().enabled(featureExport)) + if (!view.rules().enabled(featureExportRNG)) return result; JLOG(j.trace()) << "signPendingExports: started"; diff --git a/src/ripple/app/misc/impl/TxQ.cpp b/src/ripple/app/misc/impl/TxQ.cpp index dc667e13b..bd5815f60 100644 --- a/src/ripple/app/misc/impl/TxQ.cpp +++ b/src/ripple/app/misc/impl/TxQ.cpp @@ -1542,7 +1542,7 @@ TxQ::accept(Application& app, OpenView& view) } // Inject exported transactions/signatures, if any - if (view.rules().enabled(featureExport)) + if (view.rules().enabled(featureExportRNG)) { do { diff --git a/src/ripple/app/tx/impl/Change.cpp b/src/ripple/app/tx/impl/Change.cpp index f04435514..76846dee1 100644 --- a/src/ripple/app/tx/impl/Change.cpp +++ b/src/ripple/app/tx/impl/Change.cpp @@ -99,7 +99,7 @@ Change::preflight(PreflightContext const& ctx) } } - if (ctx.tx.getTxnType() == ttEXPORT && !ctx.rules.enabled(featureExport)) + if (ctx.tx.getTxnType() == ttEXPORT && !ctx.rules.enabled(featureExportRNG)) { JLOG(ctx.j.warn()) << "Change: Export not enabled"; return temDISABLED; @@ -107,7 +107,7 @@ Change::preflight(PreflightContext const& ctx) if (ctx.tx.getTxnType() == ttCONSENSUS_ENTROPY) { - if (!ctx.rules.enabled(featureConsensusEntropy)) + if (!ctx.rules.enabled(featureExportRNG)) { JLOG(ctx.j.warn()) << "Change: ConsensusEntropy is not enabled."; return temDISABLED; diff --git a/src/ripple/app/tx/impl/Import.cpp b/src/ripple/app/tx/impl/Import.cpp index 364e73b5c..bbad7f779 100644 --- a/src/ripple/app/tx/impl/Import.cpp +++ b/src/ripple/app/tx/impl/Import.cpp @@ -202,7 +202,7 @@ Import::preflight(PreflightContext const& ctx) return temMALFORMED; if (stpTrans->isFieldPresent(sfTicketSequence) && - !ctx.rules.enabled(featureExport)) + !ctx.rules.enabled(featureExportRNG)) { JLOG(ctx.j.warn()) << "Import: cannot use TicketSequence XPOP."; return temMALFORMED; @@ -897,7 +897,7 @@ Import::preclaim(PreclaimContext const& ctx) if (hasTicket) { - if (!ctx.view.rules().enabled(featureExport)) + if (!ctx.view.rules().enabled(featureExportRNG)) return tefINTERNAL; auto const acc = stpTrans->getAccountID(sfAccount); diff --git a/src/ripple/app/tx/impl/SetHook.cpp b/src/ripple/app/tx/impl/SetHook.cpp index fafddcc45..be6c7db8d 100644 --- a/src/ripple/app/tx/impl/SetHook.cpp +++ b/src/ripple/app/tx/impl/SetHook.cpp @@ -443,7 +443,7 @@ SetHook::validateHookSetEntry(SetHookCtx& ctx, STObject const& hookSetObj) auto version = hookSetObj.getFieldU16(sfHookApiVersion); // TODO: clarify API version history - version 1 was possibly // JSHooks? For now only version 0 is valid. Export APIs (xport, - // xport_reserve) are gated by featureExport amendment via + // xport_reserve) are gated by featureExportRNG amendment via // rulesVersion, not by sfHookApiVersion. if (version != 0) { diff --git a/src/ripple/protocol/Feature.h b/src/ripple/protocol/Feature.h index b481a0a12..5b30926fe 100644 --- a/src/ripple/protocol/Feature.h +++ b/src/ripple/protocol/Feature.h @@ -74,7 +74,7 @@ namespace detail { // Feature.cpp. Because it's only used to reserve storage, and determine how // large to make the FeatureBitset, it MAY be larger. It MUST NOT be less than // the actual number of amendments. A LogicError on startup will verify this. -static constexpr std::size_t numFeatures = 94; +static constexpr std::size_t numFeatures = 93; /** Amendments that this server supports and the default voting behavior. Whether they are enabled depends on the Rules defined in the validated @@ -378,10 +378,9 @@ extern uint256 const fixInvalidTxFlags; extern uint256 const featureExtendedHookState; extern uint256 const fixCronStacking; extern uint256 const fixHookAPI20251128; -extern uint256 const featureExport; +extern uint256 const featureExportRNG; extern uint256 const featureHookOnV2; extern uint256 const featureHooksUpdate2; -extern uint256 const featureConsensusEntropy; } // namespace ripple #endif diff --git a/src/ripple/protocol/impl/Feature.cpp b/src/ripple/protocol/impl/Feature.cpp index 61abe10ab..5d6f925fe 100644 --- a/src/ripple/protocol/impl/Feature.cpp +++ b/src/ripple/protocol/impl/Feature.cpp @@ -484,10 +484,9 @@ REGISTER_FIX (fixInvalidTxFlags, Supported::yes, VoteBehavior::De REGISTER_FEATURE(ExtendedHookState, Supported::yes, VoteBehavior::DefaultNo); REGISTER_FIX (fixCronStacking, Supported::yes, VoteBehavior::DefaultYes); REGISTER_FIX (fixHookAPI20251128, Supported::yes, VoteBehavior::DefaultYes); -REGISTER_FEATURE(Export, Supported::yes, VoteBehavior::DefaultNo); +REGISTER_FEATURE(ExportRNG, Supported::yes, VoteBehavior::DefaultNo); REGISTER_FEATURE(HookOnV2, Supported::yes, VoteBehavior::DefaultNo); REGISTER_FEATURE(HooksUpdate2, Supported::yes, VoteBehavior::DefaultNo); -REGISTER_FEATURE(ConsensusEntropy, Supported::yes, VoteBehavior::DefaultNo); // The following amendments are obsolete, but must remain supported // because they could potentially get enabled. diff --git a/src/test/app/ConsensusEntropy_test.cpp b/src/test/app/ConsensusEntropy_test.cpp index c048aba35..1c5985eba 100644 --- a/src/test/app/ConsensusEntropy_test.cpp +++ b/src/test/app/ConsensusEntropy_test.cpp @@ -60,7 +60,7 @@ class ConsensusEntropy_test : public beast::unit_test::suite Env env{ *this, envconfig(), - supported_amendments() | featureConsensusEntropy, + supported_amendments() | featureExportRNG, nullptr}; BEAST_EXPECT(!env.le(keylet::consensusEntropy())); @@ -89,7 +89,7 @@ class ConsensusEntropy_test : public beast::unit_test::suite Env env{ *this, envconfig(), - supported_amendments() | featureConsensusEntropy, + supported_amendments() | featureExportRNG, nullptr}; env.close(); @@ -134,7 +134,7 @@ class ConsensusEntropy_test : public beast::unit_test::suite Env env{ *this, envconfig(), - supported_amendments() | featureConsensusEntropy, + supported_amendments() | featureExportRNG, nullptr}; auto const alice = Account{"alice"}; @@ -211,7 +211,7 @@ class ConsensusEntropy_test : public beast::unit_test::suite Env env{ *this, envconfig(), - supported_amendments() | featureConsensusEntropy, + supported_amendments() | featureExportRNG, nullptr}; auto const alice = Account{"alice"}; @@ -289,7 +289,7 @@ class ConsensusEntropy_test : public beast::unit_test::suite Env env{ *this, envconfig(), - supported_amendments() | featureConsensusEntropy, + supported_amendments() | featureExportRNG, nullptr}; auto const alice = Account{"alice"}; @@ -369,7 +369,7 @@ class ConsensusEntropy_test : public beast::unit_test::suite Env env{ *this, envconfig(), - supported_amendments() | featureConsensusEntropy, + supported_amendments() | featureExportRNG, nullptr}; auto const alice = Account{"alice"}; diff --git a/src/test/app/Export_test.cpp b/src/test/app/Export_test.cpp index 687d62465..76d979d68 100644 --- a/src/test/app/Export_test.cpp +++ b/src/test/app/Export_test.cpp @@ -75,7 +75,7 @@ public: struct Export_test : public beast::unit_test::suite { // Hook that exports a payment using xport (for cross-chain export) - // xport APIs are gated by featureExport amendment, not sfHookApiVersion + // xport APIs are gated by featureExportRNG amendment, not sfHookApiVersion TestHook xport_wasm = export_test_wasm[R"[test.hook]( #include extern int32_t _g(uint32_t id, uint32_t maxiter); @@ -307,7 +307,7 @@ struct Export_test : public beast::unit_test::suite { using namespace test::jtx; FeatureBitset const all{supported_amendments()}; - FeatureBitset const allWithExport{all | featureExport}; + FeatureBitset const allWithExport{all | featureExportRNG}; testXportPaymentWithValidator(allWithExport); } }; diff --git a/src/test/jtx/Env.h b/src/test/jtx/Env.h index 335981541..61133f14f 100644 --- a/src/test/jtx/Env.h +++ b/src/test/jtx/Env.h @@ -86,7 +86,7 @@ supported_amendments() // TODO: ConsensusEntropy injects a pseudo-tx every ledger which // breaks existing test transaction count assumptions. Exclude from // default test set until dedicated tests are written. - return FeatureBitset(feats) - featureConsensusEntropy; + return FeatureBitset(feats) - featureExportRNG; //@@end rng-test-environment-gating }(); return ids;