From ea48e5cce1e3087008feb208cbfc30d460a34303 Mon Sep 17 00:00:00 2001 From: tequ Date: Tue, 20 Jan 2026 12:12:45 +0900 Subject: [PATCH] Add tests for Hooks fee --- src/test/app/SetHook_test.cpp | 648 ++++++---------------------------- 1 file changed, 106 insertions(+), 542 deletions(-) diff --git a/src/test/app/SetHook_test.cpp b/src/test/app/SetHook_test.cpp index 2b9c4ec4cf..16c06d7be3 100644 --- a/src/test/app/SetHook_test.cpp +++ b/src/test/app/SetHook_test.cpp @@ -294,7 +294,9 @@ public: iv[jss::CreateCode] = ""; jv[jss::Hooks][0U][jss::Hook] = iv; - env(jv, HSFEE, ter(tesSUCCESS)); + bool const fixV1 = env.current()->rules().enabled(fixXahauV1); + auto const txResult = fixV1 ? ter(tesSUCCESS) : ter(tefBAD_LEDGER); + env(jv, HSFEE, txResult); env.close(); } @@ -688,8 +690,6 @@ public: bool const hasHookCanEmit = env.current()->rules().enabled(featureHookCanEmit); - bool const hasNamedHooks = - env.current()->rules().enabled(featureNamedHooks); auto const alice = Account{"alice"}; env.fund(XRP(10000), alice); @@ -726,8 +726,7 @@ public: } // grants, parameters, hookon, hookonincoming, hookonoutgoing, - // hookcanemit, hookapiversion, hooknamespace, hookname keys must be - // absent + // hookcanemit, hookapiversion, hooknamespace keys must be absent for (auto const& [key, value] : JSSMap{ {jss::HookGrants, Json::arrayValue}, {jss::HookParameters, Json::arrayValue}, @@ -744,16 +743,11 @@ public: "000000000000000000000000000000000000000000000000000000000000" "0000"}, {jss::HookApiVersion, "0"}, - {jss::HookNamespace, to_string(uint256{beast::zero})}, - {jss::HookName, strHex(std::string{"DEADBEEF"})}, - }) + {jss::HookNamespace, to_string(uint256{beast::zero})}}) { if (!hasHookCanEmit && key == jss::HookCanEmit) continue; - if (!hasNamedHooks && key == jss::HookName) - continue; - Json::Value iv; iv[jss::CreateCode] = ""; iv[key] = value; @@ -761,7 +755,7 @@ public: env(jv, M("Hook DELETE operation cannot include: grants, params, " "hookon, HookOnIncoming, HookOnOutgoing, hookcanemit, " - "apiversion, namespace, hookname"), + "apiversion, namespace"), HSFEE, ter(temMALFORMED)); env.close(); @@ -900,8 +894,6 @@ public: bool const fixNS = env.current()->rules().enabled(fixNSDelete); bool const hasHookCanEmit = env.current()->rules().enabled(featureHookCanEmit); - bool const hasNamedHooks = - env.current()->rules().enabled(featureNamedHooks); auto const alice = Account{"alice"}; env.fund(XRP(10000), alice); @@ -934,15 +926,11 @@ public: "000000000000000000000000000000000000000000000000000000000000" "0000"}, {jss::HookApiVersion, "0"}, - {jss::HookName, strHex(std::string{"DEADBEEF"})}, }) { if (!hasHookCanEmit && key == jss::HookCanEmit) continue; - if (!hasNamedHooks && key == jss::HookName) - continue; - Json::Value iv; iv[key] = value; iv[jss::Flags] = hsfNSDELETE; @@ -951,16 +939,27 @@ public: env(jv, M("Hook NSDELETE operation cannot include: grants, params, " "hookon, hookonincoming, hookonoutgoing, hookcanemit, " - "apiversion, hookname"), + "apiversion"), HSFEE, ter(temMALFORMED)); env.close(); } - uint256 constexpr key{ - "000000000000000000000000000000000000000000000000000000006b657900"}; - uint256 constexpr ns{ - "cafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafe"}; + auto const key = uint256::fromVoid( + (std::array{ + 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, + 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, + 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, + 0x00U, 0x00U, 0x00U, 0x00U, 'k', 'e', 'y', 0x00U}) + .data()); + + auto const ns = uint256::fromVoid( + (std::array{ + 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, + 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, + 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, + 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU}) + .data()); auto const stateKeylet = keylet::hookState(Account("alice").id(), key, ns); @@ -1095,7 +1094,7 @@ public: ripple::test::jtx::hook(carol, {{hso(scaled_state_wasm)}}, 0); jv[jss::Hooks][0U][jss::Hook][jss::HookNamespace] = ns_str; jv[jss::Hooks][0U][jss::Hook][jss::HookOn] = - to_string(hook::UINT256_BIT[ttACCOUNT_SET]); + to_string(UINT256_BIT[ttACCOUNT_SET]); env(jv, M("Create scaled state hook"), HSFEE, ter(tesSUCCESS)); env.close(); @@ -1685,340 +1684,6 @@ public: } } - void - testHookName(FeatureBitset features) - { - testcase("Test hook name"); - using namespace jtx; - - auto const alice = Account{"alice"}; - auto const bob = Account{"bob"}; - auto const charlie = Account{"charlie"}; - auto const USD = alice["USD"]; - - Env env{*this, features}; - - env.fund(XRP(10000), alice, bob); - env.close(); - - // Invalid hook name (length=3,17, not utf-8) - for (auto const name : { - "414243", // ABC (length=3) - "4142434445464748494A4B4C4D4E4F5051", // ABCDEFGHIJKLMNOPQ - // (length=17) - "DEADBEEF", // not utf-8 - }) - { - auto jvh = hso(accept_wasm); - jvh[jss::HookName] = name; - env(ripple::test::jtx::hook(alice, {{jvh}}, 0), - M("Hook name must be between 8 and 32 hex characters and be a " - "valid UTF-8 string"), - HSFEE, - features[featureNamedHooks] ? ter(temMALFORMED) - : ter(temDISABLED)); - - auto jvi = invoke::invoke(alice); - jvi[jss::HookName] = name; - env(jvi, - M("Call named hook with the invalid hook name"), - HSFEE, - ter(temMALFORMED)); - } - - if (!features[featureNamedHooks]) - return; - - { - /// Create, Install, Update named Hook - Env env{*this, features}; - - env.fund(XRP(10000), alice, bob, charlie); - env.close(); - - // Create with hook name - auto jvh = hso(accept_wasm); - jvh[jss::HookName] = "41424344"; - env(ripple::test::jtx::hook(alice, {{jvh}}, 0), - M("Create named hook"), - HSFEE); - env.close(); - - // Check hook definition - { - auto const hookDef = - env.le(keylet::hookDefinition(accept_hash)); - BEAST_EXPECT(hookDef); - BEAST_EXPECT(!hookDef->isFieldPresent(sfHookName)); - } - // Check Hook - { - auto const hooks = env.le(keylet::hook(alice)); - BEAST_EXPECT(hooks && hooks->isFieldPresent(sfHooks)); - auto const& hooksArray = hooks->getFieldArray(sfHooks); - BEAST_EXPECT(hooksArray.size() == 1); - BEAST_EXPECT(hooksArray[0].isFieldPresent(sfHookName)); - BEAST_EXPECT( - strHex(hooksArray[0].getFieldVL(sfHookName)) == "41424344"); - } - - // install with hook name - jvh[jss::HookName] = "41424344"; - env(ripple::test::jtx::hook(bob, {{jvh}}, 0), - M("Install named hook"), - HSFEE); - env.close(); - // Check Hook - { - auto const hooks = env.le(keylet::hook(bob)); - BEAST_EXPECT(hooks && hooks->isFieldPresent(sfHooks)); - auto const& hooksArray = hooks->getFieldArray(sfHooks); - BEAST_EXPECT(hooksArray.size() == 1); - BEAST_EXPECT(hooksArray[0].isFieldPresent(sfHookName)); - BEAST_EXPECT( - strHex(hooksArray[0].getFieldVL(sfHookName)) == "41424344"); - } - - // install without hook name - jvh.removeMember(jss::HookName); - env(ripple::test::jtx::hook(charlie, {{jvh}}, 0), - M("Install non-named hook"), - HSFEE); - env.close(); - // Check Hook - { - auto const hooks = env.le(keylet::hook(charlie)); - BEAST_EXPECT(hooks && hooks->isFieldPresent(sfHooks)); - auto const& hooksArray = hooks->getFieldArray(sfHooks); - BEAST_EXPECT(hooksArray.size() == 1); - BEAST_EXPECT(!hooksArray[0].isFieldPresent(sfHookName)); - } - - // Update named hook to non-named hook - jvh[jss::HookName] = ""; - jvh[jss::Flags] = hsfOVERRIDE; - env(ripple::test::jtx::hook(alice, {{jvh}}, 0), - M("Update named hook to non-named hook"), - HSFEE); - env.close(); - // Check Hook - { - auto const hooks = env.le(keylet::hook(alice)); - BEAST_EXPECT(hooks && hooks->isFieldPresent(sfHooks)); - auto const& hooksArray = hooks->getFieldArray(sfHooks); - BEAST_EXPECT(hooksArray.size() == 1); - BEAST_EXPECT(!hooksArray[0].isFieldPresent(sfHookName)); - } - - // Update named hook to named hook - jvh[jss::HookName] = "4142434445"; - jvh[jss::Flags] = hsfOVERRIDE; - env(ripple::test::jtx::hook(bob, {{jvh}}, 0), - M("Update non-named hook to named hook"), - HSFEE); - env.close(); - // Check Hook - { - auto const hooks = env.le(keylet::hook(bob)); - BEAST_EXPECT(hooks && hooks->isFieldPresent(sfHooks)); - auto const& hooksArray = hooks->getFieldArray(sfHooks); - BEAST_EXPECT(hooksArray.size() == 1); - BEAST_EXPECT(hooksArray[0].isFieldPresent(sfHookName)); - BEAST_EXPECT( - strHex(hooksArray[0].getFieldVL(sfHookName)) == - "4142434445"); - } - - // Update non-named hook to named hook - jvh[jss::HookName] = "41424344"; - jvh[jss::Flags] = hsfOVERRIDE; - env(ripple::test::jtx::hook(charlie, {{jvh}}, 0), - M("Update non-named hook to named hook"), - HSFEE); - env.close(); - // Check Hook - { - auto const hooks = env.le(keylet::hook(charlie)); - BEAST_EXPECT(hooks && hooks->isFieldPresent(sfHooks)); - auto const& hooksArray = hooks->getFieldArray(sfHooks); - BEAST_EXPECT(hooksArray.size() == 1); - BEAST_EXPECT(hooksArray[0].isFieldPresent(sfHookName)); - BEAST_EXPECT( - strHex(hooksArray[0].getFieldVL(sfHookName)) == "41424344"); - } - } - - // Install named hook - auto jvh = hso(accept_wasm); - jvh[jss::HookName] = "41424344"; - jvh[jss::Flags] = hsfCOLLECT; - auto jvh2 = hso(accept2_wasm); - jvh2[jss::Flags] = hsfCOLLECT; - env(ripple::test::jtx::hook(alice, {{jvh, jvh2}}, 0), - M("Install named hook"), - HSFEE); - env.close(); - - // - // Test Strong - // - // Call named hook without specifying the hook name - { - auto jv = invoke::invoke(alice); - auto expectedFee = - calculateBaseFee(*env.current(), *env.jt(jv).stx); - BEAST_EXPECT(expectedFee == drops(19)); - env(jv, - M("Call named hook without specifying the hook name"), - HSFEE); - env.close(); - // execute only non-named hook - auto const hookExecutions = - env.meta()->getFieldArray(sfHookExecutions); - BEAST_EXPECT(hookExecutions.size() == 1); - BEAST_EXPECT( - hookExecutions[0].getFieldH256(sfHookHash) == accept2_hash); - } - - // Call named hook with the wrong hook name - { - auto jv = invoke::invoke(alice); - jv[jss::HookName] = "41424345"; - auto expectedFee = - calculateBaseFee(*env.current(), *env.jt(jv).stx); - BEAST_EXPECT(expectedFee == drops(19)); - env(jv, M("Call named hook with the wrong hook name"), HSFEE); - env.close(); - // execute only non-named hook - auto const hookExecutions = - env.meta()->getFieldArray(sfHookExecutions); - BEAST_EXPECT(hookExecutions.size() == 1); - BEAST_EXPECT( - hookExecutions[0].getFieldH256(sfHookHash) == accept2_hash); - } - - // Call named hook with the correct hook name - { - auto jv = invoke::invoke(alice); - jv[jss::HookName] = "41424344"; - auto expectedFee = - calculateBaseFee(*env.current(), *env.jt(jv).stx); - BEAST_EXPECT(expectedFee == drops(28)); - env(jv, M("Call named hook with the correct hook name"), HSFEE); - env.close(); - // execute both named and non-named hooks - auto const hookExecutions = - env.meta()->getFieldArray(sfHookExecutions); - BEAST_EXPECT(hookExecutions.size() == 2); - BEAST_EXPECT( - hookExecutions[0].getFieldH256(sfHookHash) == accept_hash); - BEAST_EXPECT( - hookExecutions[1].getFieldH256(sfHookHash) == accept2_hash); - } - - // - // Test Weak - // - env(fset(alice, asfTshCollect), fee(XRP(1))); - env.close(); - // Call named hook without specifying the hook name - { - auto jv = trust(bob, USD(1000)); - env(jv, - M("Call named hook without specifying the hook name"), - HSFEE); - env.close(); - // execute only non-named hook - auto const hookExecutions = - env.meta()->getFieldArray(sfHookExecutions); - BEAST_EXPECT(hookExecutions.size() == 1); - BEAST_EXPECT( - hookExecutions[0].getFieldH256(sfHookHash) == accept2_hash); - } - - // Call named hook with the wrong hook name - { - auto jv = trust(bob, USD(1000)); - jv[jss::HookName] = "41424345"; - env(jv, M("Call named hook with the wrong hook name"), HSFEE); - env.close(); - // execute only non-named hook - auto const hookExecutions = - env.meta()->getFieldArray(sfHookExecutions); - BEAST_EXPECT(hookExecutions.size() == 1); - BEAST_EXPECT( - hookExecutions[0].getFieldH256(sfHookHash) == accept2_hash); - } - - // Call named hook with the correct hook name - { - auto jv = invoke::invoke(alice); - jv[jss::HookName] = "41424344"; - env(jv, M("Call named hook with the correct hook name"), HSFEE); - env.close(); - // execute both named and non-named hooks - auto const hookExecutions = - env.meta()->getFieldArray(sfHookExecutions); - BEAST_EXPECT(hookExecutions.size() == 2); - BEAST_EXPECT( - hookExecutions[0].getFieldH256(sfHookHash) == accept_hash); - BEAST_EXPECT( - hookExecutions[1].getFieldH256(sfHookHash) == accept2_hash); - } - env(fclear(alice, asfTshCollect), fee(XRP(1))); - env.close(); - - // - // Callback Execution - // - jvh = hso(emit_invoke_wasm); - jvh[jss::HookName] = "41424344"; - jvh[jss::Flags] = hsfOVERRIDE; - env(ripple::test::jtx::hook(alice, {{jvh}}, 0), - M("Install named callback hook"), - HSFEE); - env.close(); - // Call named hook without specifying the hook name - { - auto jv = invoke::invoke(alice); - env(jv, - M("Call named hook without specifying the hook name"), - HSFEE); - env.close(); - // execute only non-named hook - BEAST_EXPECT(!env.meta()->isFieldPresent(sfHookEmissions)); - } - - // Call named hook with the wrong hook name - { - auto jv = invoke::invoke(alice); - jv[jss::HookName] = "41424345"; - env(jv, M("Call named hook with the wrong hook name"), HSFEE); - env.close(); - // execute only non-named hook - BEAST_EXPECT(!env.meta()->isFieldPresent(sfHookEmissions)); - } - - // Call named hook with the correct hook name - { - auto jv = invoke::invoke(alice); - jv[jss::HookName] = "41424344"; - env(jv, M("Call named hook with the correct hook name"), HSFEE); - env.close(); - // execute both named and non-named hooks - BEAST_EXPECT(env.meta()->isFieldPresent(sfHookEmissions)); - auto const hookEmissions = - env.meta()->getFieldArray(sfHookEmissions)[0]; - auto const etxn = hookEmissions.getFieldH256(sfEmittedTxnID); - env.close(); - auto const tx = env.closed()->txRead(etxn); - BEAST_EXPECT(tx.first && tx.second); - BEAST_EXPECT(!tx.first->isFieldPresent(sfHookName)); - // Callback transaction doesn't need to have hook name - BEAST_EXPECT(tx.second->isFieldPresent(sfHookExecutions)); - } - } - void testFillCopy(FeatureBitset features) { @@ -2076,8 +1741,6 @@ public: bool const hasHookCanEmit = env.current()->rules().enabled(featureHookCanEmit); - bool const hasNamedHooks = - env.current()->rules().enabled(featureNamedHooks); auto const bob = Account{"bob"}; env.fund(XRP(10000), bob); @@ -2126,8 +1789,6 @@ public: iv[jss::HookCanEmit] = "0000000000000000000000000000000000000000000000000000000000" "000000"; - if (hasNamedHooks) - iv[jss::HookName] = strHex(std::string{"DEADBEEF"}); jv[jss::Hooks][0U] = Json::Value{}; jv[jss::Hooks][0U][jss::Hook] = iv; @@ -2150,8 +1811,6 @@ public: iv[jss::HookCanEmit] = "0000000000000000000000000000000000000000000000000000000000" "000000"; - if (hasNamedHooks) - iv[jss::HookName] = strHex(std::string{"DEADBEEF"}); jv[jss::Hooks][0U] = Json::Value{}; jv[jss::Hooks][0U][jss::Hook] = iv; @@ -2175,8 +1834,6 @@ public: iv[jss::HookCanEmit] = "0000000000000000000000000000000000000000000000000000000000" "000000"; - if (hasNamedHooks) - iv[jss::HookName] = strHex(std::string{"DEADBEEF"}); jv[jss::Hooks][0U] = Json::Value{}; jv[jss::Hooks][0U][jss::Hook] = iv; @@ -2197,8 +1854,6 @@ public: iv[jss::HookCanEmit] = "0000000000000000000000000000000000000000000000000000000000" "000000"; - if (hasNamedHooks) - iv[jss::HookName] = strHex(std::string{"DEADBEEF"}); jv[jss::Hooks][0U] = Json::Value{}; jv[jss::Hooks][0U][jss::Hook] = iv; @@ -2347,8 +2002,6 @@ public: bool const hasHookCanEmit = env.current()->rules().enabled(featureHookCanEmit); - bool const hasNamedHooks = - env.current()->rules().enabled(featureNamedHooks); auto const alice = Account{"alice"}; env.fund(XRP(10000), alice); @@ -2375,8 +2028,6 @@ public: iv[jss::HookCanEmit] = "0000000000000000000000000000000000000000000000000000000000" "000000"; - if (hasNamedHooks) - iv[jss::HookName] = strHex(std::string{"DEADBEEF"}); iv[jss::HookParameters] = Json::Value{Json::arrayValue}; iv[jss::HookParameters][0U] = Json::Value{}; iv[jss::HookParameters][0U][jss::HookParameter] = Json::Value{}; @@ -2465,16 +2116,11 @@ public: "CAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFE" "CAFECAFE"}, {jss::HookParameters, params}, - {jss::HookGrants, grants}, - {jss::HookName, strHex(std::string{"DEADBEEF"})}, - }) + {jss::HookGrants, grants}}) { if (!hasHookCanEmit && key == jss::HookCanEmit) continue; - if (!hasNamedHooks && key == jss::HookName) - continue; - Json::Value iv; iv[key] = value; jv[jss::Hooks][0U] = Json::Value{}; @@ -2495,23 +2141,24 @@ public: // check all fields were updated to correct values BEAST_REQUIRE(hooks[0].isFieldPresent(sfHookOn)); - BEAST_EXPECT( - hooks[0].getFieldH256(sfHookOn) == hook::UINT256_BIT[0]); + BEAST_EXPECT(hooks[0].getFieldH256(sfHookOn) == UINT256_BIT[0]); if (hasHookCanEmit) { BEAST_REQUIRE(hooks[0].isFieldPresent(sfHookCanEmit)); BEAST_EXPECT( hooks[0].getFieldH256(sfHookCanEmit) == - ripple::uint256( - "000000000000000000000000000000000000000000" - "0000000000000000000001")); + ripple::uint256("000000000000000000000000000000000000000000" + "0000000000000000000001")); } - uint256 constexpr ns( - "cafecafecafecafecafecafecafecafecafecafecafecafecafecafecafeca" - "fe"); - + auto const ns = uint256::fromVoid( + (std::array{ + 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, + 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, + 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, + 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU}) + .data()); BEAST_REQUIRE(hooks[0].isFieldPresent(sfHookNamespace)); BEAST_EXPECT(hooks[0].getFieldH256(sfHookNamespace) == ns); @@ -2545,16 +2192,11 @@ public: {jss::HookCanEmit, "00000000000000000000000000000000000000000000000000000000" "00000000"}, - {jss::HookNamespace, to_string(uint256{beast::zero})}, - {jss::HookName, strHex(std::string{"DEADBEEF"})}, - }) + {jss::HookNamespace, to_string(uint256{beast::zero})}}) { if (key == jss::HookCanEmit && !hasHookCanEmit) continue; - if (!hasNamedHooks && key == jss::HookName) - continue; - Json::Value iv; iv[key] = value; jv[jss::Hooks][0U] = Json::Value{}; @@ -2803,16 +2445,11 @@ public: "CAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFE" "CAFECAFE"}, {jss::HookParameters, params}, - {jss::HookGrants, grants}, - {jss::HookName, strHex(std::string{"DEADBEEF"})}, - }) + {jss::HookGrants, grants}}) { if (key == jss::HookCanEmit && !hasHookCanEmit) continue; - if (!hasNamedHooks && key == jss::HookName) - continue; - Json::Value iv; iv[key] = value; jv[jss::Hooks][0U] = Json::Value{}; @@ -3032,7 +2669,7 @@ public: // hsoUPDATE { STObject hso{sfHook}; - hso.setFieldH256(sfHookOn, hook::UINT256_BIT[0]); + hso.setFieldH256(sfHookOn, UINT256_BIT[0]); BEAST_EXPECT(SetHook::inferOperation(hso) == hsoUPDATE); } @@ -3689,6 +3326,8 @@ public: env(invoke, M("test emit"), fee(XRP(1))); + bool const fixV2 = env.current()->rules().enabled(fixXahauV2); + std::optional emithash; { auto meta = env.meta(); // meta can close @@ -3698,7 +3337,9 @@ public: BEAST_REQUIRE(meta->isFieldPresent(sfHookExecutions)); auto const hookEmissions = meta->getFieldArray(sfHookEmissions); - BEAST_EXPECT(hookEmissions[0u].isFieldPresent(sfEmitNonce)); + BEAST_EXPECT( + hookEmissions[0u].isFieldPresent(sfEmitNonce) == fixV2 ? true + : false); BEAST_EXPECT( hookEmissions[0u].getAccountID(sfHookAccount) == alice.id()); @@ -3793,7 +3434,8 @@ public: BEAST_EXPECT(hookExecutions[0].getFieldU8(sfHookResult) == 3); BEAST_EXPECT( hookExecutions[0].getFieldU16(sfHookEmitCount) == 2); - BEAST_EXPECT(hookExecutions[0].getFieldU32(sfFlags) == 2); + if (fixV2) + BEAST_EXPECT(hookExecutions[0].getFieldU32(sfFlags) == 2); } env.close(); burden_expected *= 2U; @@ -3817,7 +3459,8 @@ public: BEAST_EXPECT( hookExecutions[0].getFieldU64(sfHookReturnCode) == 283); // emission failure on first emit - BEAST_EXPECT(hookExecutions[0].getFieldU32(sfFlags) == 2); + if (fixV2) + BEAST_EXPECT(hookExecutions[0].getFieldU32(sfFlags) == 2); } BEAST_EXPECT(txcount == 256); } @@ -4074,6 +3717,8 @@ public: env(invoke, M("test emit"), fee(XRP(1))); + bool const fixV2 = env.current()->rules().enabled(fixXahauV2); + std::optional emithash; { auto meta = env.meta(); // meta can close @@ -4083,7 +3728,9 @@ public: BEAST_REQUIRE(meta->isFieldPresent(sfHookExecutions)); auto const hookEmissions = meta->getFieldArray(sfHookEmissions); - BEAST_EXPECT(hookEmissions[0u].isFieldPresent(sfEmitNonce)); + BEAST_EXPECT( + hookEmissions[0u].isFieldPresent(sfEmitNonce) == fixV2 ? true + : false); BEAST_EXPECT( hookEmissions[0u].getAccountID(sfHookAccount) == alice.id()); @@ -4178,7 +3825,8 @@ public: BEAST_EXPECT(hookExecutions[0].getFieldU8(sfHookResult) == 3); BEAST_EXPECT( hookExecutions[0].getFieldU16(sfHookEmitCount) == 2); - BEAST_EXPECT(hookExecutions[0].getFieldU32(sfFlags) == 2); + if (fixV2) + BEAST_EXPECT(hookExecutions[0].getFieldU32(sfFlags) == 2); } env.close(); burden_expected *= 2U; @@ -4202,7 +3850,8 @@ public: BEAST_EXPECT( hookExecutions[0].getFieldU64(sfHookReturnCode) == 172); // emission failure on first emit - BEAST_EXPECT(hookExecutions[0].getFieldU32(sfFlags) == 2); + if (fixV2) + BEAST_EXPECT(hookExecutions[0].getFieldU32(sfFlags) == 2); } BEAST_EXPECT(txcount == 256); } @@ -4312,7 +3961,7 @@ public: M("set etxn_details"), HSFEE); env.close(); - EXPECT_HOOK_FEE(hook, 2436); + EXPECT_HOOK_FEE(hook, 88); // invoke the hook env(pay(bob, alice, XRP(1)), M("test etxn_details"), fee(XRP(1))); @@ -4482,7 +4131,7 @@ public: M("set etxn_nonce"), HSFEE); env.close(); - EXPECT_HOOK_FEE(hook, 11657); + EXPECT_HOOK_FEE(hook, 11644); // invoke the hook env(pay(bob, alice, XRP(1)), M("test etxn_nonce"), fee(XRP(1))); @@ -6939,8 +6588,12 @@ public: BEAST_REQUIRE(hookExecutions.size() == 2); // get the data in the return code of the execution - BEAST_EXPECT(hookExecutions[0].getFieldU32(sfFlags) == 5); - BEAST_EXPECT(hookExecutions[1].getFieldU32(sfFlags) == 0); + bool const fixV2 = env.current()->rules().enabled(fixXahauV2); + if (fixV2) + { + BEAST_EXPECT(hookExecutions[0].getFieldU32(sfFlags) == 5); + BEAST_EXPECT(hookExecutions[1].getFieldU32(sfFlags) == 0); + } BEAST_EXPECT(hookExecutions[0].getFieldU64(sfHookReturnCode) == 0); BEAST_EXPECT(hookExecutions[1].getFieldU64(sfHookReturnCode) == 1); @@ -8231,7 +7884,7 @@ public: HASH_WASM(hook); // before featureHooksUpdate1 - env(ripple::test::jtx::hook(alice, {{hso(hook_wasm, overrideFlag)}}, 0), + env(ripple::test::jtx::hook(alice, {{hso(hook, overrideFlag)}}, 0), M("set xpop_slot (disabled)"), HSFEE, ter(temMALFORMED)); @@ -10013,13 +9666,19 @@ public: fee(XRP(1))); } + // fixXahauV1 + bool const fixV1 = env.current()->rules().enabled(fixXahauV1); + auto const txResult = fixV1 ? ter(tecHOOK_REJECTED) : ter(tesSUCCESS); env(pay(bob, alice, XRP(1)), M("test state_foreign_set_max"), fee(XRP(1)), - ter(tecHOOK_REJECTED)); + ter(txResult)); env.close(); // verify hook result + // TOO_MANY_NAMESPACES / -45 + std::string const hookResult = fixV1 ? "800000000000002d" : "9"; + Json::Value params; params[jss::transaction] = env.tx()->getJson(JsonOptions::none)[jss::hash]; @@ -10027,9 +9686,7 @@ public: auto const meta = jrr[jss::result][jss::meta]; auto const executions = meta[sfHookExecutions.jsonName]; auto const execution = executions[0u][sfHookExecution.jsonName]; - // TOO_MANY_NAMESPACES / -45 - BEAST_EXPECT( - execution[sfHookReturnCode.jsonName] == "800000000000002d"); + BEAST_EXPECT(execution[sfHookReturnCode.jsonName] == hookResult); } void @@ -10775,19 +10432,17 @@ public: data1[0] == 0xCAU && data1[1] == 0xFEU && data1[2] == 0xBAU && data1[3] == 0xBEU); - std::array const key2{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1, 2, 3}; + uint8_t key2[32] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3}; - auto const state2 = env.le( - ripple::keylet::hookState( - aliceid, uint256(key2), beast::zero)); + auto const state2 = env.le(ripple::keylet::hookState( + aliceid, uint256::fromVoid(key2), beast::zero)); BEAST_REQUIRE(!!state2); auto const lekey2 = state2->getFieldH256(sfHookStateKey); - BEAST_EXPECT(lekey2 == uint256(key2)); + BEAST_EXPECT(lekey2 == uint256::fromVoid(key2)); uint8_t data2[128] = { 0x23U, 0x13U, 0x96U, 0x68U, 0x78U, 0xDCU, 0xABU, 0xC4U, 0x40U, @@ -11049,13 +10704,11 @@ public: for (uint32_t i = 0; i < sizeof(data1); ++i) BEAST_EXPECT(data1[i] == ledata1[i]); - auto const state2 = env.le( - ripple::keylet::hookState( - aliceid, - uint256( - "000000000000000000000000000000000000000000000000000000" - "0000010203"), - beast::zero)); + uint8_t key2[32] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3}; + + auto const state2 = env.le(ripple::keylet::hookState( + aliceid, uint256::fromVoid(key2), beast::zero)); BEAST_REQUIRE(!state2); } @@ -11128,12 +10781,12 @@ public: fee(XRP(1)), ter(tecHOOK_REJECTED)); - uint256 constexpr keyx( - "00000000000000000000000000000000000000000000000000000000000000" - "ff"); + uint8_t key[32] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFFU}; - auto const state = - env.le(ripple::keylet::hookState(aliceid, keyx, beast::zero)); + auto const state = env.le(ripple::keylet::hookState( + aliceid, uint256::fromVoid(key), beast::zero)); BEAST_EXPECT(state); @@ -11149,8 +10802,8 @@ public: // check the state is still present { - auto const state = env.le( - ripple::keylet::hookState(aliceid, keyx, beast::zero)); + auto const state = env.le(ripple::keylet::hookState( + aliceid, uint256::fromVoid(key), beast::zero)); BEAST_EXPECT(state); } @@ -11167,8 +10820,8 @@ public: // check the state is still present { - auto const state = env.le( - ripple::keylet::hookState(aliceid, keyx, beast::zero)); + auto const state = env.le(ripple::keylet::hookState( + aliceid, uint256::fromVoid(key), beast::zero)); BEAST_EXPECT(state); } @@ -11380,7 +11033,7 @@ public: ripple::test::jtx::hook(gary, {{hso(scaled_state_wasm)}}, 0); // jv[jss::Hooks][0U][jss::Hook][jss::HookNamespace] = ns_str; jv[jss::Hooks][0U][jss::Hook][jss::HookOn] = - to_string(hook::UINT256_BIT[ttACCOUNT_SET]); + to_string(UINT256_BIT[ttACCOUNT_SET]); env(jv, M("Create scaled state hook"), HSFEE, ter(tesSUCCESS)); env.close(); EXPECT_HOOK_FEE(scaled_state, 227); @@ -13469,7 +13122,7 @@ public: 0,0 ))); - ASSERT(INVALID_ARGUMENT == (e=util_keylet(buf, 34, KEYLET_AMM, + ASSERT(34 == (e=util_keylet(buf, 34, KEYLET_AMM, SBUF(asset1), SBUF(asset2), 0,0 ))); @@ -13545,7 +13198,7 @@ public: M("set util_keylet"), HSFEE); env.close(); - EXPECT_HOOK_FEE(hook, 1786); + EXPECT_HOOK_FEE(hook, 1546); // invoke the hook env(pay(bob, alice, XRP(1)), M("test util_keylet"), fee(XRP(1))); @@ -15068,7 +14721,6 @@ public: testPageCap(features); testHookOnV2(features); - testHookName(features); testFillCopy(features); @@ -15172,13 +14824,16 @@ public: using namespace test::jtx; static FeatureBitset const all{supported_amendments()}; - static std::array const feats{ + static std::array const feats{ all, - all - fixNSDelete, - all - fixNSDelete - fixPageCap, - all - fixNSDelete - fixPageCap - featureHookCanEmit, - all - fixNSDelete - fixPageCap - featureExtendedHookState, - all - featureNamedHooks, + all - fixXahauV2, + all - fixXahauV1 - fixXahauV2, + all - fixXahauV1 - fixXahauV2 - fixNSDelete, + all - fixXahauV1 - fixXahauV2 - fixNSDelete - fixPageCap, + all - fixXahauV1 - fixXahauV2 - fixNSDelete - fixPageCap - + featureHookCanEmit, + all - fixXahauV1 - fixXahauV2 - fixNSDelete - fixPageCap - + featureExtendedHookState, }; if (BEAST_EXPECT(instance < feats.size())) @@ -15191,7 +14846,6 @@ public: void run() override { - log << "Apparently equal!"; run(0); } @@ -15331,98 +14985,6 @@ private: )[test.hook]"]; HASH_WASM(accept2); - - // This hook is used to test Callback - TestHook emit_invoke_wasm = // WASM: 7 - wasm[ - R"[test.hook]( - #include - 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 emit (uint32_t write_ptr, uint32_t write_len, uint32_t read_ptr, uint32_t read_len); - extern int64_t hook_account(uint32_t write_ptr, uint32_t write_len); - extern int64_t etxn_reserve(uint32_t); - extern int64_t etxn_fee_base (uint32_t read_ptr, uint32_t read_len); - extern int64_t etxn_details (uint32_t write_ptr, uint32_t write_len); - extern int64_t ledger_seq (void); - - #define SBUF(x) (uint32_t)x,sizeof(x) - // clang-format off - uint8_t txn[229] = - { - /* size, upto, field name */ - /* 3, 0, tt = Invoke */ 0x12U, 0x00U, 0x63U, - /* 5, 3, flags */ 0x22U, 0x00U, 0x00U, 0x00U, 0x00U, - /* 5, 8, sequence */ 0x24U, 0x00U, 0x00U, 0x00U, 0x00U, - /* 6, 13, firstledgersequence */ 0x20U, 0x1AU, 0x00U, 0x00U, 0x00U, 0x00U, - /* 6, 19, lastledgersequence */ 0x20U, 0x1BU, 0x00U, 0x00U, 0x00U, 0x00U, - /* 9, 25, fee */ 0x68U, 0x40U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, - /* 35, 34, signingpubkey */ 0x73U, 0x21U, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - /* 22, 69, account */ 0x81U, 0x14U, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - /* 116, 91, emit details */ - /* 0, 229, */ - }; - // clang-format on - - // TX BUILDER - #define FLAGS_OUT (txn + 4U) - #define FLS_OUT (txn + 15U) - #define LLS_OUT (txn + 21U) - #define FEE_OUT (txn + 26U) - #define ACCOUNT_OUT (txn + 71U) - #define EMIT_OUT (txn + 91U) - - #define FLIP_ENDIAN_32(value) \ - (uint32_t)(((value & 0xFFU) << 24) | ((value & 0xFF00U) << 8) | \ - ((value & 0xFF0000U) >> 8) | ((value & 0xFF000000U) >> 24)) - - #define SET_UINT32(ptr, value) *((uint32_t *)(ptr)) = FLIP_ENDIAN_32(value); - - #define SET_NATIVE_AMOUNT(ptr, amount) \ - do { \ - uint8_t *b = (ptr); \ - *b++ = 0b01000000 + ((amount >> 56) & 0b00111111); \ - *b++ = (amount >> 48) & 0xFFU; \ - *b++ = (amount >> 40) & 0xFFU; \ - *b++ = (amount >> 32) & 0xFFU; \ - *b++ = (amount >> 24) & 0xFFU; \ - *b++ = (amount >> 16) & 0xFFU; \ - *b++ = (amount >> 8) & 0xFFU; \ - *b++ = (amount >> 0) & 0xFFU; \ - } while (0) - - #define PREPARE_TXN() \ - do { \ - etxn_reserve(1); \ - uint32_t fls = (uint32_t)ledger_seq() + 1; \ - SET_UINT32(FLS_OUT, fls); \ - SET_UINT32(LLS_OUT, fls + 4); \ - hook_account(ACCOUNT_OUT, 20); \ - etxn_details(EMIT_OUT, 138U); \ - int64_t fee = etxn_fee_base(SBUF(txn)); \ - SET_NATIVE_AMOUNT(FEE_OUT, fee); \ - } while (0) - - - int64_t cbak(uint32_t r) - { - _g(1,1); - return accept(0,0,0); - } - - int64_t hook(uint32_t reserved) - { - _g(1,1); - PREPARE_TXN(); - uint8_t emithash[32]; - int64_t emit_result = emit(SBUF(emithash), SBUF(txn)); - if (emit_result < 0) - return rollback(SBUF("Emit failed."), __LINE__); - return accept(SBUF("Emit succeeded."), __LINE__); - } - )[test.hook]"]; - - HASH_WASM(emit_invoke); }; #define SETHOOK_TEST(i, last) \ @@ -15439,7 +15001,8 @@ SETHOOK_TEST(1, false) SETHOOK_TEST(2, false) SETHOOK_TEST(3, false) SETHOOK_TEST(4, false) -SETHOOK_TEST(5, true) +SETHOOK_TEST(5, false) +SETHOOK_TEST(6, true) BEAST_DEFINE_TESTSUITE_PRIO(SetHook0, app, ripple, 2); BEAST_DEFINE_TESTSUITE_PRIO(SetHook1, app, ripple, 2); @@ -15447,6 +15010,7 @@ BEAST_DEFINE_TESTSUITE_PRIO(SetHook2, app, ripple, 2); BEAST_DEFINE_TESTSUITE_PRIO(SetHook3, app, ripple, 2); BEAST_DEFINE_TESTSUITE_PRIO(SetHook4, app, ripple, 2); BEAST_DEFINE_TESTSUITE_PRIO(SetHook5, app, ripple, 2); +BEAST_DEFINE_TESTSUITE_PRIO(SetHook6, app, ripple, 2); } // namespace test } // namespace ripple #undef M