From 12d8342c34d9500ef60cb56aee5873a0a4401178 Mon Sep 17 00:00:00 2001 From: Wietse Wind Date: Sat, 1 Feb 2025 08:57:25 +0100 Subject: [PATCH 1/4] Update artifact --- .github/workflows/levelization.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/levelization.yml b/.github/workflows/levelization.yml index c8284c5fb..1295bd393 100644 --- a/.github/workflows/levelization.yml +++ b/.github/workflows/levelization.yml @@ -18,8 +18,7 @@ jobs: git diff --exit-code | tee "levelization.patch" - name: Upload patch if: failure() && steps.assert.outcome == 'failure' - uses: actions/upload-artifact@v3 - continue-on-error: true + uses: actions/upload-artifact@v4 with: name: levelization.patch if-no-files-found: ignore From 412593d7bc178957875b9e71435b584bbadb5f36 Mon Sep 17 00:00:00 2001 From: Wietse Wind Date: Sat, 1 Feb 2025 08:57:48 +0100 Subject: [PATCH 2/4] Update artifact --- .github/workflows/clang-format.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/clang-format.yml b/.github/workflows/clang-format.yml index 0cc8dbe59..52432adda 100644 --- a/.github/workflows/clang-format.yml +++ b/.github/workflows/clang-format.yml @@ -30,7 +30,7 @@ jobs: git diff --exit-code | tee "clang-format.patch" - name: Upload patch if: failure() && steps.assert.outcome == 'failure' - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 continue-on-error: true with: name: clang-format.patch From fa71bda29c0ab1f5d8a0b76734ce886e325445a6 Mon Sep 17 00:00:00 2001 From: Wietse Wind Date: Sat, 1 Feb 2025 08:58:13 +0100 Subject: [PATCH 3/4] Artifact v4 continue on error --- .github/workflows/levelization.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/levelization.yml b/.github/workflows/levelization.yml index 1295bd393..f99c1ca56 100644 --- a/.github/workflows/levelization.yml +++ b/.github/workflows/levelization.yml @@ -19,6 +19,7 @@ jobs: - name: Upload patch if: failure() && steps.assert.outcome == 'failure' uses: actions/upload-artifact@v4 + continue-on-error: true with: name: levelization.patch if-no-files-found: ignore From 2fd465bb3fbfaa821cd80d9f1bf4c4bd9f45ac6f Mon Sep 17 00:00:00 2001 From: RichardAH Date: Mon, 3 Feb 2025 10:33:19 +1000 Subject: [PATCH 4/4] fix20250131 (#428) Co-authored-by: Denis Angell --- src/ripple/app/hook/Guard.h | 33 ++++++++++++++++-- src/ripple/app/hook/guard_checker.cpp | 2 +- src/ripple/app/tx/impl/Change.cpp | 3 +- src/ripple/app/tx/impl/Remit.cpp | 10 ++++++ src/ripple/app/tx/impl/SetHook.cpp | 3 +- src/ripple/protocol/Feature.h | 3 +- src/ripple/protocol/impl/Feature.cpp | 3 +- src/ripple/protocol/impl/TxMeta.cpp | 4 ++- src/test/app/SetHookTSH_test.cpp | 1 - src/test/app/SetHook_test.cpp | 50 +++++++++++++++++++++++++++ 10 files changed, 103 insertions(+), 9 deletions(-) diff --git a/src/ripple/app/hook/Guard.h b/src/ripple/app/hook/Guard.h index 893fe9282..f395af448 100644 --- a/src/ripple/app/hook/Guard.h +++ b/src/ripple/app/hook/Guard.h @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -271,7 +272,19 @@ check_guard( int guard_func_idx, int last_import_idx, GuardLog guardLog, - std::string guardLogAccStr) + std::string guardLogAccStr, + /* RH NOTE: + * rules version is a bit field, so rule update 1 is 0x01, update 2 is 0x02 + * and update 3 is 0x04 ideally at rule version 3 all bits so far are set + * (0b111) so the ruleVersion = 7, however if a specific rule update must be + * rolled back due to unforeseen behaviour then this may no longer be the + * case. using a bit field here leaves us flexible to rollback changes that + * might have unforeseen consequences, without also rolling back further + * changes that are fine. + */ + uint64_t rulesVersion = 0 + +) { #define MAX_GUARD_CALLS 1024 uint32_t guard_count = 0; @@ -621,11 +634,17 @@ check_guard( } else if (fc_type == 10) // memory.copy { + if (rulesVersion & 0x02U) + GUARD_ERROR("Memory.copy instruction is not allowed."); + REQUIRE(2); ADVANCE(2); } else if (fc_type == 11) // memory.fill { + if (rulesVersion & 0x02U) + GUARD_ERROR("Memory.fill instruction is not allowed."); + ADVANCE(1); } else if (fc_type <= 7) // numeric instructions @@ -807,6 +826,15 @@ validateGuards( std::vector const& wasm, GuardLog guardLog, std::string guardLogAccStr, + /* RH NOTE: + * rules version is a bit field, so rule update 1 is 0x01, update 2 is 0x02 + * and update 3 is 0x04 ideally at rule version 3 all bits so far are set + * (0b111) so the ruleVersion = 7, however if a specific rule update must be + * rolled back due to unforeseen behaviour then this may no longer be the + * case. using a bit field here leaves us flexible to rollback changes that + * might have unforeseen consequences, without also rolling back further + * changes that are fine. + */ uint64_t rulesVersion = 0) { uint64_t byteCount = wasm.size(); @@ -1477,7 +1505,8 @@ validateGuards( guard_import_number, last_import_number, guardLog, - guardLogAccStr); + guardLogAccStr, + rulesVersion); if (!valid) return {}; diff --git a/src/ripple/app/hook/guard_checker.cpp b/src/ripple/app/hook/guard_checker.cpp index 634dd8a93..f20d24617 100644 --- a/src/ripple/app/hook/guard_checker.cpp +++ b/src/ripple/app/hook/guard_checker.cpp @@ -79,7 +79,7 @@ main(int argc, char** argv) close(fd); - auto result = validateGuards(hook, std::cout, "", 1); + auto result = validateGuards(hook, std::cout, "", 3); if (!result) { diff --git a/src/ripple/app/tx/impl/Change.cpp b/src/ripple/app/tx/impl/Change.cpp index c91b79403..61134ca25 100644 --- a/src/ripple/app/tx/impl/Change.cpp +++ b/src/ripple/app/tx/impl/Change.cpp @@ -587,7 +587,8 @@ Change::activateXahauGenesis() wasmBytes, // wasm to verify loggerStream, "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", - ctx_.view().rules().enabled(featureHooksUpdate1) ? 1 : 0); + (ctx_.view().rules().enabled(featureHooksUpdate1) ? 1 : 0) + + (ctx_.view().rules().enabled(fix20250131) ? 2 : 0)); if (!result) { diff --git a/src/ripple/app/tx/impl/Remit.cpp b/src/ripple/app/tx/impl/Remit.cpp index 084513e02..33d8a4c6f 100644 --- a/src/ripple/app/tx/impl/Remit.cpp +++ b/src/ripple/app/tx/impl/Remit.cpp @@ -72,6 +72,16 @@ Remit::preflight(PreflightContext const& ctx) return temREDUNDANT; } + if (ctx.rules.enabled(fix20250131)) + { + if (!dstID || dstID == noAccount()) + { + JLOG(ctx.j.warn()) + << "Malformed transaction: Remit to invalid account."; + return temMALFORMED; + } + } + if (ctx.tx.isFieldPresent(sfInform)) { AccountID const infID = ctx.tx.getAccountID(sfInform); diff --git a/src/ripple/app/tx/impl/SetHook.cpp b/src/ripple/app/tx/impl/SetHook.cpp index aac02753c..67e89d993 100644 --- a/src/ripple/app/tx/impl/SetHook.cpp +++ b/src/ripple/app/tx/impl/SetHook.cpp @@ -479,7 +479,8 @@ SetHook::validateHookSetEntry(SetHookCtx& ctx, STObject const& hookSetObj) hook, // wasm to verify logger, hsacc, - ctx.rules.enabled(featureHooksUpdate1) ? 1 : 0); + (ctx.rules.enabled(featureHooksUpdate1) ? 1 : 0) + + (ctx.rules.enabled(fix20250131) ? 2 : 0)); if (ctx.j.trace()) { diff --git a/src/ripple/protocol/Feature.h b/src/ripple/protocol/Feature.h index f479ecba7..b242b2f7f 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 = 76; +static constexpr std::size_t numFeatures = 77; /** Amendments that this server supports and the default voting behavior. Whether they are enabled depends on the Rules defined in the validated @@ -364,6 +364,7 @@ extern uint256 const fix240911; extern uint256 const fixFloatDivide; extern uint256 const fixReduceImport; extern uint256 const fixXahauV3; +extern uint256 const fix20250131; } // namespace ripple diff --git a/src/ripple/protocol/impl/Feature.cpp b/src/ripple/protocol/impl/Feature.cpp index 12c7b66c8..73db671ed 100644 --- a/src/ripple/protocol/impl/Feature.cpp +++ b/src/ripple/protocol/impl/Feature.cpp @@ -469,7 +469,8 @@ REGISTER_FIX (fixPageCap, Supported::yes, VoteBehavior::De REGISTER_FIX (fix240911, Supported::yes, VoteBehavior::DefaultYes); REGISTER_FIX (fixFloatDivide, Supported::yes, VoteBehavior::DefaultYes); REGISTER_FIX (fixReduceImport, Supported::yes, VoteBehavior::DefaultYes); -REGISTER_FIX (fixXahauV3, Supported::yes, VoteBehavior::DefaultNo); +REGISTER_FIX (fixXahauV3, Supported::yes, VoteBehavior::DefaultYes); +REGISTER_FIX (fix20250131, Supported::yes, VoteBehavior::DefaultYes); // The following amendments are obsolete, but must remain supported // because they could potentially get enabled. diff --git a/src/ripple/protocol/impl/TxMeta.cpp b/src/ripple/protocol/impl/TxMeta.cpp index 4b48f5eb4..506c7f2a7 100644 --- a/src/ripple/protocol/impl/TxMeta.cpp +++ b/src/ripple/protocol/impl/TxMeta.cpp @@ -240,7 +240,9 @@ TxMeta::addRaw(Serializer& s, TER result, std::uint32_t index) { mResult = TERtoInt(result); mIndex = index; - assert((mResult == 0) || ((mResult > 100) && (mResult <= 255))); + assert( + (mResult == 0 || mResult == 1) || + ((mResult > 100) && (mResult <= 255))); mNodes.sort([](STObject const& o1, STObject const& o2) { return o1.getFieldH256(sfLedgerIndex) < o2.getFieldH256(sfLedgerIndex); diff --git a/src/test/app/SetHookTSH_test.cpp b/src/test/app/SetHookTSH_test.cpp index 30a561113..9b19c3936 100644 --- a/src/test/app/SetHookTSH_test.cpp +++ b/src/test/app/SetHookTSH_test.cpp @@ -5544,7 +5544,6 @@ struct SetHookTSH_test : public beast::unit_test::suite testTSH(sa - fixXahauV1 - fixXahauV2); testTSH(sa - fixXahauV2); testTSH(sa); - testEmittedTxn(sa - fixXahauV2); testEmittedTxn(sa); } }; diff --git a/src/test/app/SetHook_test.cpp b/src/test/app/SetHook_test.cpp index f0e97a859..7f42e9700 100644 --- a/src/test/app/SetHook_test.cpp +++ b/src/test/app/SetHook_test.cpp @@ -1138,6 +1138,54 @@ class SetHook_test : public beast::unit_test::suite : preHookCount + 66); } + void + testFillCopy(FeatureBitset features) + { + testcase("Test fill/copy"); + + // a hook containing memory.fill instruction + std::string hookFill = + "0061736d0100000001130360027f7f017f60037f7f7e017e60017f017e02" + "170203656e76025f67000003656e76066163636570740001030201020503" + "0100020621057f01418088040b7f004180080b7f004180080b7f00418088" + "040b7f004180080b07080104686f6f6b00020aa4800001a0800001017e23" + "01412a41e400fc0b004101410110001a41004100420010011a20010b"; + + // a hook containing memory.copy instruction + std::string hookCopy = + "0061736d0100000001130360027f7f017f60037f7f7e017e60017f017e02" + "170203656e76025f67000003656e76066163636570740001030201020503" + "0100020621057f01418088040b7f004180080b7f004180080b7f00418088" + "040b7f004180080b07080104686f6f6b00020aa5800001a1800001017e23" + "00230141e400fc0a00004101410110001a41004100420010011a20010b"; + + using namespace jtx; + + for (int withFix = 0; withFix < 2; ++withFix) + { + auto f = withFix ? features : features - fix20250131; + Env env{*this, f}; + + auto const alice = Account{"alice"}; + env.fund(XRP(10000), alice); + + auto const bob = Account{"bob"}; + env.fund(XRP(10000), bob); + + env(ripple::test::jtx::hook(alice, {{hso(hookFill)}}, 0), + M(withFix ? "hookFill - with fix" : "hookFill - zonder fix"), + HSFEE, + withFix ? ter(temMALFORMED) : ter(tesSUCCESS)); + + env(ripple::test::jtx::hook(bob, {{hso(hookCopy)}}, 0), + M(withFix ? "hookCopy - with fix" : "hookCopy - zonder fix"), + HSFEE, + withFix ? ter(temMALFORMED) : ter(tesSUCCESS)); + + env.close(); + } + } + void testCreate(FeatureBitset features) { @@ -11973,6 +12021,8 @@ class SetHook_test : public beast::unit_test::suite testNSDeletePartial(features); testPageCap(features); + testFillCopy(features); + testWasm(features); test_accept(features); test_rollback(features);