diff --git a/src/test/app/SetJSHook_test.cpp b/src/test/app/SetJSHook_test.cpp index d2e6ccf53..f897518ea 100644 --- a/src/test/app/SetJSHook_test.cpp +++ b/src/test/app/SetJSHook_test.cpp @@ -1503,532 +1503,1504 @@ public: env.close(); } - void - test_emit(FeatureBitset features) - { - testcase("Test float_emit"); - using namespace jtx; - Env env{ - *this, envconfig(), features, nullptr, beast::severities::kWarning - // beast::severities::kTrace - }; + // void + // test_emit(FeatureBitset features) - auto const alice = Account{"alice"}; - auto const bob = Account{"bob"}; + void + test_otxn_field(FeatureBitset features) + { + testcase("Test otxn_field"); + using namespace jtx; + Env env{*this, features}; + + Account const alice{"alice"}; + Account const bob{"bob"}; env.fund(XRP(10000), alice); env.fund(XRP(10000), bob); - TestHook hook = wasm[R"[test.hook]( - #include - extern int32_t _g(uint32_t, uint32_t); - 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, uint32_t, uint32_t, uint32_t); - extern int64_t etxn_reserve(uint32_t); - extern int64_t otxn_param(uint32_t, uint32_t, uint32_t, uint32_t); - extern int64_t hook_account(uint32_t, uint32_t); - extern int64_t otxn_field ( - uint32_t write_ptr, - uint32_t write_len, - uint32_t field_id - ); - #define GUARD(maxiter) _g((1ULL << 31U) + __LINE__, (maxiter)+1) - #define OUT_OF_BOUNDS (-1) - #define ttPAYMENT 0 - #define tfCANONICAL 0x80000000UL - #define amAMOUNT 1U - #define amFEE 8U - #define atACCOUNT 1U - #define DOESNT_EXIST (-5) - #define atDESTINATION 3U - #define SBUF(x) (uint32_t)x,sizeof(x) + TestHook hook = jswasm[R"[test.hook]( + const INVALID_ARGUMENT = -7 + const sfAccount = 0x80001 - #define PREREQUISITE_NOT_MET -9 - #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 35 - #define ENCODE_SIGNING_PUBKEY_NULL(buf_out )\ - {\ - buf_out[0] = 0x73U;\ - buf_out[1] = 0x21U;\ - *(uint64_t*)(buf_out+2) = 0;\ - *(uint64_t*)(buf_out+10) = 0;\ - *(uint64_t*)(buf_out+18) = 0;\ - *(uint64_t*)(buf_out+25) = 0;\ - buf_out += ENCODE_SIGNING_PUBKEY_NULL_SIZE;\ - } - - #define _07_03_ENCODE_SIGNING_PUBKEY_NULL(buf_out )\ - ENCODE_SIGNING_PUBKEY_NULL(buf_out ); - - 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 PREPARE_PAYMENT_SIMPLE_SIZE 270U - #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 ); \ - } - - #define UINT16_FROM_BUF(buf)\ - (((uint64_t)((buf)[0]) << 8U) +\ - ((uint64_t)((buf)[1]) << 0U)) - - #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) &&\ - *(((uint64_t*)(buf1)) + 4) == *(((uint64_t*)(buf2)) + 4) &&\ - *(((uint64_t*)(buf1)) + 5) == *(((uint64_t*)(buf2)) + 5) &&\ - *(((uint64_t*)(buf1)) + 6) == *(((uint64_t*)(buf2)) + 6) &&\ - *(((uint64_t*)(buf1)) + 7) == *(((uint64_t*)(buf2)) + 7)) - - #define ASSERT(x)\ - if (!(x))\ - rollback((uint32_t)#x,sizeof(#x),__LINE__) - - #define sfDestination ((8U << 16U) + 3U) - - extern int64_t etxn_generation(void); - extern int64_t otxn_generation(void); - extern int64_t otxn_burden(void); - extern int64_t etxn_burden(void); - - int64_t cbak(uint32_t r) - { - // on callback we emit 2 more txns - uint8_t bob[20]; - ASSERT(otxn_field(SBUF(bob), sfDestination) == 20); - - ASSERT(otxn_generation() + 1 == etxn_generation()); - - ASSERT(etxn_burden() == PREREQUISITE_NOT_MET); - - ASSERT(etxn_reserve(2) == 2); - - ASSERT(otxn_burden() > 0); - ASSERT(etxn_burden() == otxn_burden() * 2); - - uint8_t tx[PREPARE_PAYMENT_SIMPLE_SIZE]; - PREPARE_PAYMENT_SIMPLE(tx, 1000, bob, 0, 0); - - uint8_t hash1[32]; - ASSERT(emit(SBUF(hash1), SBUF(tx)) == 32); - - ASSERT(etxn_details(tx + 132, 138) == 138); - uint8_t hash2[32]; - ASSERT(emit(SBUF(hash2), SBUF(tx)) == 32); - - ASSERT(!BUFFER_EQUAL_32(hash1, hash2)); - - return accept(0,0,0); - } - - int64_t hook(uint32_t r) - { - _g(1,1); - - etxn_reserve(1); - - // bounds checks - ASSERT(emit(1000000, 32, 0, 32) == OUT_OF_BOUNDS); - ASSERT(emit(0,1000000, 0, 32) == OUT_OF_BOUNDS); - ASSERT(emit(0,32, 1000000, 32) == OUT_OF_BOUNDS); - ASSERT(emit(0,32, 0, 1000000) == OUT_OF_BOUNDS); - - ASSERT(otxn_generation() == 0); - ASSERT(otxn_burden == 1); - - uint8_t bob[20]; - ASSERT(otxn_param(SBUF(bob), "bob", 3) == 20); - - uint8_t tx[PREPARE_PAYMENT_SIMPLE_SIZE]; - PREPARE_PAYMENT_SIMPLE(tx, 1000, bob, 0, 0); - - uint8_t hash[32]; - ASSERT(emit(SBUF(hash), SBUF(tx)) == 32); - - return accept(0,0,0); - } - )[test.hook]"]; - - env(ripple::test::jtx::hook(alice, {{hsov1(hook, 1, overrideFlag)}}, 0), - M("set emit"), - HSFEE); - env.close(); - - Json::Value invoke; - invoke[jss::TransactionType] = "Invoke"; - invoke[jss::Account] = alice.human(); - - Json::Value params{Json::arrayValue}; - params[0U][jss::HookParameter][jss::HookParameterName] = - strHex(std::string("bob")); - params[0U][jss::HookParameter][jss::HookParameterValue] = - strHex(bob.id()); - - invoke[jss::HookParameters] = params; - - 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 - - // ensure hook execution occured - BEAST_REQUIRE(meta); - BEAST_REQUIRE(meta->isFieldPresent(sfHookExecutions)); - - auto const hookEmissions = meta->getFieldArray(sfHookEmissions); - BEAST_EXPECT( - hookEmissions[0u].isFieldPresent(sfEmitNonce) == fixV2 ? true - : false); - BEAST_EXPECT( - hookEmissions[0u].getAccountID(sfHookAccount) == alice.id()); - - auto const hookExecutions = meta->getFieldArray(sfHookExecutions); - BEAST_REQUIRE(hookExecutions.size() == 1); - - // ensure there was one emitted txn - BEAST_EXPECT(hookExecutions[0].getFieldU16(sfHookEmitCount) == 1); - - BEAST_REQUIRE(meta->isFieldPresent(sfAffectedNodes)); - - BEAST_REQUIRE(meta->getFieldArray(sfAffectedNodes).size() == 3); - - for (auto const& node : meta->getFieldArray(sfAffectedNodes)) - { - SField const& metaType = node.getFName(); - uint16_t nodeType = node.getFieldU16(sfLedgerEntryType); - if (metaType == sfCreatedNode && nodeType == ltEMITTED_TXN) - { - BEAST_REQUIRE(node.isFieldPresent(sfNewFields)); - - auto const& nf = const_cast(node) - .getField(sfNewFields) - .downcast(); - - auto const& et = const_cast(nf) - .getField(sfEmittedTxn) - .downcast(); - - auto const& em = const_cast(et) - .getField(sfEmitDetails) - .downcast(); - - BEAST_EXPECT(em.getFieldU32(sfEmitGeneration) == 1); - BEAST_EXPECT(em.getFieldU64(sfEmitBurden) == 1); - - Blob txBlob = et.getSerializer().getData(); - auto const tx = std::make_unique( - Slice{txBlob.data(), txBlob.size()}); - emithash = tx->getTransactionID(); - - break; + const ASSERT = (x, code) => { + if (!x) { + rollback(x.toString(), code); } } - BEAST_REQUIRE(emithash); - BEAST_EXPECT( - emithash == hookEmissions[0u].getFieldH256(sfEmittedTxnID)); - } + const Hook = (arg) => { + ASSERT(otxn_field(sfAccount) == 20); + ASSERT(otxn_field(1) == INVALID_ARGUMENT); + + let acc2 = hook_account(); + ASSERT(acc2 == 20); - { - auto balbefore = env.balance(bob).value().xrp().drops(); + for (var i = 0; i < 20; ++i) + ASSERT(acc[i] == acc2[i]); - env.close(); - - auto const ledger = env.closed(); - - int txcount = 0; - for (auto& i : ledger->txs) - { - auto const& hash = i.first->getTransactionID(); - txcount++; - BEAST_EXPECT(hash == *emithash); + return accept("0", 0); } + )[test.hook]"]; - BEAST_EXPECT(txcount == 1); - - auto balafter = env.balance(bob).value().xrp().drops(); - - BEAST_EXPECT(balafter - balbefore == 1000); - - env.close(); - } - - uint64_t burden_expected = 2; - for (int j = 0; j < 7; ++j) - { - auto const ledger = env.closed(); - for (auto& i : ledger->txs) - { - auto const& em = const_cast(*(i.first)) - .getField(sfEmitDetails) - .downcast(); - BEAST_EXPECT(em.getFieldU64(sfEmitBurden) == burden_expected); - BEAST_EXPECT(em.getFieldU32(sfEmitGeneration) == j + 2); - BEAST_REQUIRE(i.second->isFieldPresent(sfHookExecutions)); - auto const hookExecutions = - i.second->getFieldArray(sfHookExecutions); - BEAST_EXPECT(hookExecutions.size() == 1); - BEAST_EXPECT( - hookExecutions[0].getFieldU64(sfHookReturnCode) == 0); - BEAST_EXPECT(hookExecutions[0].getFieldU8(sfHookResult) == 3); - BEAST_EXPECT( - hookExecutions[0].getFieldU16(sfHookEmitCount) == 2); - if (fixV2) - BEAST_EXPECT(hookExecutions[0].getFieldU32(sfFlags) == 2); - } - env.close(); - burden_expected *= 2U; - } - - { - auto const ledger = env.closed(); - int txcount = 0; - for (auto& i : ledger->txs) - { - txcount++; - auto const& em = const_cast(*(i.first)) - .getField(sfEmitDetails) - .downcast(); - BEAST_EXPECT(em.getFieldU64(sfEmitBurden) == 256); - BEAST_EXPECT(em.getFieldU32(sfEmitGeneration) == 9); - BEAST_REQUIRE(i.second->isFieldPresent(sfHookExecutions)); - auto const hookExecutions = - i.second->getFieldArray(sfHookExecutions); - BEAST_EXPECT(hookExecutions.size() == 1); - BEAST_EXPECT( - hookExecutions[0].getFieldU64(sfHookReturnCode) == - 283); // emission failure on first emit - if (fixV2) - BEAST_EXPECT(hookExecutions[0].getFieldU32(sfFlags) == 2); - } - BEAST_EXPECT(txcount == 256); - } - - // next close will lead to zero transactions + // install the hook on alice + env(ripple::test::jtx::hook(alice, {{hso(hook, overrideFlag)}}, 0), + M("set otxn_field"), + HSFEE); env.close(); + + // invoke the hook + env(pay(alice, bob, XRP(1)), M("test otxn_field"), fee(XRP(1))); + } + + void + test_hook_account(FeatureBitset features) + { + testcase("Test hook_account"); + using namespace jtx; + + auto const test = [&](Account alice) -> void { + Env env{*this, features}; + + // Env env{*this, envconfig(), features, nullptr, + // beast::severities::kTrace + // }; + + auto const bob = Account{"bob"}; + env.fund(XRP(10000), alice); + env.fund(XRP(10000), bob); + + TestHook hook = {0x43U, 0x11U, 0x0cU, 0x41U, 0x53U, 0x53U, 0x45U, 0x52U, 0x54U, 0x0aU, + 0x74U, 0x6fU, 0x48U, 0x65U, 0x78U, 0x08U, 0x48U, 0x6fU, 0x6fU, 0x6bU, + 0x28U, 0x77U, 0x61U, 0x73U, 0x6dU, 0x6aU, 0x73U, 0x2fU, 0x74U, 0x65U, + 0x73U, 0x74U, 0x2dU, 0x31U, 0x2dU, 0x67U, 0x65U, 0x6eU, 0x2eU, 0x6aU, + 0x73U, 0x02U, 0x78U, 0x08U, 0x63U, 0x6fU, 0x64U, 0x65U, 0x10U, 0x72U, + 0x6fU, 0x6cU, 0x6cU, 0x62U, 0x61U, 0x63U, 0x6bU, 0x06U, 0x61U, 0x72U, + 0x72U, 0x06U, 0x6dU, 0x61U, 0x70U, 0x16U, 0x74U, 0x6fU, 0x55U, 0x70U, + 0x70U, 0x65U, 0x72U, 0x43U, 0x61U, 0x73U, 0x65U, 0x06U, 0x6eU, 0x75U, + 0x6dU, 0x10U, 0x70U, 0x61U, 0x64U, 0x53U, 0x74U, 0x61U, 0x72U, 0x74U, + 0x06U, 0x61U, 0x72U, 0x67U, 0x08U, 0x61U, 0x63U, 0x63U, 0x32U, 0x18U, + 0x68U, 0x6fU, 0x6fU, 0x6bU, 0x5fU, 0x61U, 0x63U, 0x63U, 0x6fU, 0x75U, + 0x6eU, 0x74U, 0x0aU, 0x74U, 0x72U, 0x61U, 0x63U, 0x65U, 0x0cU, 0x61U, + 0x63U, 0x63U, 0x65U, 0x70U, 0x74U, 0x0cU, 0x00U, 0x06U, 0x00U, 0xa2U, + 0x01U, 0x00U, 0x01U, 0x00U, 0x01U, 0x00U, 0x03U, 0x4aU, 0x01U, 0xa4U, + 0x01U, 0x00U, 0x00U, 0x00U, 0x3fU, 0xe3U, 0x00U, 0x00U, 0x00U, 0x80U, + 0x3fU, 0xe4U, 0x00U, 0x00U, 0x00U, 0x80U, 0x3fU, 0xe5U, 0x00U, 0x00U, + 0x00U, 0x80U, 0x3eU, 0xe3U, 0x00U, 0x00U, 0x00U, 0x80U, 0x3eU, 0xe4U, + 0x00U, 0x00U, 0x00U, 0x80U, 0x3eU, 0xe5U, 0x00U, 0x00U, 0x00U, 0x80U, + 0xc2U, 0x00U, 0x4dU, 0xe3U, 0x00U, 0x00U, 0x00U, 0x3aU, 0xe3U, 0x00U, + 0x00U, 0x00U, 0xc2U, 0x01U, 0x4dU, 0xe4U, 0x00U, 0x00U, 0x00U, 0x3aU, + 0xe4U, 0x00U, 0x00U, 0x00U, 0xc2U, 0x02U, 0x4dU, 0xe5U, 0x00U, 0x00U, + 0x00U, 0x3aU, 0xe5U, 0x00U, 0x00U, 0x00U, 0xc7U, 0x28U, 0xccU, 0x03U, + 0x01U, 0x0aU, 0x5bU, 0x00U, 0x12U, 0x0cU, 0x00U, 0x0cU, 0x0eU, 0x00U, + 0x0cU, 0x0eU, 0x0cU, 0x02U, 0x06U, 0x00U, 0x00U, 0x02U, 0x00U, 0x02U, + 0x03U, 0x00U, 0x00U, 0x16U, 0x02U, 0xceU, 0x03U, 0x00U, 0x01U, 0x00U, + 0xd0U, 0x03U, 0x00U, 0x01U, 0x00U, 0xd3U, 0x97U, 0xecU, 0x12U, 0x38U, + 0xe9U, 0x00U, 0x00U, 0x00U, 0xd3U, 0x42U, 0x38U, 0x00U, 0x00U, 0x00U, + 0x24U, 0x00U, 0x00U, 0xd4U, 0xf2U, 0x0eU, 0x29U, 0xccU, 0x03U, 0x02U, + 0x03U, 0x03U, 0x17U, 0x59U, 0x0cU, 0x02U, 0x06U, 0x00U, 0x00U, 0x01U, + 0x00U, 0x01U, 0x03U, 0x00U, 0x01U, 0x1cU, 0x01U, 0xd4U, 0x03U, 0x00U, + 0x01U, 0x00U, 0xd3U, 0x42U, 0xebU, 0x00U, 0x00U, 0x00U, 0xc2U, 0x00U, + 0x24U, 0x01U, 0x00U, 0x42U, 0x5cU, 0x00U, 0x00U, 0x00U, 0xc3U, 0x24U, + 0x01U, 0x00U, 0x42U, 0xecU, 0x00U, 0x00U, 0x00U, 0x25U, 0x00U, 0x00U, + 0xccU, 0x03U, 0x08U, 0x04U, 0x03U, 0x08U, 0x35U, 0x30U, 0x0cU, 0x02U, + 0x06U, 0x00U, 0x00U, 0x01U, 0x00U, 0x01U, 0x04U, 0x00U, 0x01U, 0x16U, + 0x01U, 0xdaU, 0x03U, 0x00U, 0x01U, 0x00U, 0xd3U, 0x42U, 0x38U, 0x00U, + 0x00U, 0x00U, 0xbfU, 0x10U, 0x24U, 0x01U, 0x00U, 0x42U, 0xeeU, 0x00U, + 0x00U, 0x00U, 0xb9U, 0xc1U, 0x00U, 0x25U, 0x02U, 0x00U, 0xccU, 0x03U, + 0x0aU, 0x00U, 0x07U, 0x02U, 0x30U, 0x0cU, 0x02U, 0x06U, 0x00U, 0x00U, + 0x01U, 0x01U, 0x01U, 0x04U, 0x00U, 0x00U, 0x3aU, 0x02U, 0xdeU, 0x03U, + 0x00U, 0x01U, 0x00U, 0xe0U, 0x03U, 0x01U, 0x00U, 0x20U, 0x61U, 0x00U, + 0x00U, 0x38U, 0xf1U, 0x00U, 0x00U, 0x00U, 0xf0U, 0xcbU, 0x38U, 0xf2U, + 0x00U, 0x00U, 0x00U, 0x04U, 0xf0U, 0x00U, 0x00U, 0x00U, 0x62U, 0x00U, + 0x00U, 0x09U, 0xf3U, 0x0eU, 0x38U, 0xe3U, 0x00U, 0x00U, 0x00U, 0x62U, + 0x00U, 0x00U, 0xebU, 0xbfU, 0x14U, 0xaaU, 0xf1U, 0x0eU, 0x38U, 0xf3U, + 0x00U, 0x00U, 0x00U, 0x38U, 0xe4U, 0x00U, 0x00U, 0x00U, 0x62U, 0x00U, + 0x00U, 0xf1U, 0xb7U, 0x23U, 0x02U, 0x00U, 0xccU, 0x03U, 0x0fU, 0x04U, + 0x12U, 0x26U, 0x53U, 0x49U}; + + // TestHook hook = jswasm[ + // R"[test.hook]( + // const ASSERT = (x, code) => { + // if (!x) { + // rollback(x.toString(), code) + // } + // } + + // const toHex = (arr) => { + // return arr + // .map((num) => num.toString(16).padStart(2, '0')) + // .join('') + // .toUpperCase() + // } + + // const Hook = (arg) => { + // let acc2 = hook_account() + // trace('acc2', acc2, false) + // ASSERT(acc2.length == 20) + // return accept(toHex(acc2), 0) + // } + // )[test.hook]"]; + + // install the hook on alice + env(ripple::test::jtx::hook(alice, {{hsov1(hook, 1, overrideFlag)}}, 0), + M("set hook_account"), + HSFEE); + env.close(); + + // invoke the hook + env(pay(bob, alice, XRP(1)), M("test hook_account"), fee(XRP(1))); + + { + auto meta = env.meta(); + + // ensure hook execution occured + BEAST_REQUIRE(meta); + BEAST_REQUIRE(meta->isFieldPresent(sfHookExecutions)); + + // ensure there was only one hook execution + auto const hookExecutions = + meta->getFieldArray(sfHookExecutions); + BEAST_REQUIRE(hookExecutions.size() == 1); + + // get the data in the return string of the extention + auto const tmpRet = hookExecutions[0].getFieldVL(sfHookReturnString); + + // DA: TODO Fix `accept` and `rollback` and remove these lines + std::string tmpStr(tmpRet.begin(), tmpRet.end()); + auto const tmpBlob = strUnHex(tmpStr); + Blob const retStr = Blob(tmpBlob->begin(), tmpBlob->end()); + + // check that it matches the account id + BEAST_EXPECT(retStr.size() == 20); + auto const a = alice.id(); + BEAST_EXPECT(memcmp(retStr.data(), a.data(), 20) == 0); + } + + // install the same hook bob + env(ripple::test::jtx::hook(bob, {{hsov1(hook, 1, overrideFlag)}}, 0), + M("set hook_account 2"), + HSFEE); + env.close(); + + // invoke the hook + env(pay(bob, alice, XRP(1)), M("test hook_account 2"), fee(XRP(1))); + + // there should be two hook executions, the first should be bob's + // address the second should be alice's + { + auto meta = env.meta(); + + // ensure hook execution occured + BEAST_REQUIRE(meta); + BEAST_REQUIRE(meta->isFieldPresent(sfHookExecutions)); + + // ensure there were two hook executions + auto const hookExecutions = + meta->getFieldArray(sfHookExecutions); + BEAST_REQUIRE(hookExecutions.size() == 2); + + { + // get the data in the return string of the extention + auto const tmpRet = + hookExecutions[0].getFieldVL(sfHookReturnString); + + // DA: TODO Fix `accept` and `rollback` and remove these lines + std::string tmpStr(tmpRet.begin(), tmpRet.end()); + auto const tmpBlob = strUnHex(tmpStr); + Blob const retStr = Blob(tmpBlob->begin(), tmpBlob->end()); + + // check that it matches the account id + BEAST_EXPECT(retStr.size() == 20); + auto const b = bob.id(); + BEAST_EXPECT(memcmp(retStr.data(), b.data(), 20) == 0); + } + + { + // get the data in the return string of the extention + auto const tmpRet = + hookExecutions[1].getFieldVL(sfHookReturnString); + + // DA: TODO Fix `accept` and `rollback` and remove these lines + std::string tmpStr(tmpRet.begin(), tmpRet.end()); + auto const tmpBlob = strUnHex(tmpStr); + Blob const retStr = Blob(tmpBlob->begin(), tmpBlob->end()); + + // check that it matches the account id + BEAST_EXPECT(retStr.size() == 20); + auto const a = alice.id(); + BEAST_EXPECT(memcmp(retStr.data(), a.data(), 20) == 0); + } + } + }; + + test(Account{"alice"}); + test(Account{"cho"}); + } + + void + test_hook_again(FeatureBitset features) + { + testcase("Test hook_again"); + using namespace jtx; + Env env{*this, features}; + + Account const alice{"alice"}; + Account const bob{"bob"}; + env.fund(XRP(10000), alice); + env.fund(XRP(10000), bob); + + TestHook hook = { + 0x43U, 0x08U, 0x28U, 0x50U, 0x52U, 0x45U, 0x52U, 0x45U, 0x51U, + 0x55U, 0x49U, 0x53U, 0x49U, 0x54U, 0x45U, 0x5fU, 0x4eU, 0x4fU, + 0x54U, 0x5fU, 0x4dU, 0x45U, 0x54U, 0x16U, 0x41U, 0x4cU, 0x52U, + 0x45U, 0x41U, 0x44U, 0x59U, 0x5fU, 0x53U, 0x45U, 0x54U, 0x08U, + 0x48U, 0x6fU, 0x6fU, 0x6bU, 0x28U, 0x77U, 0x61U, 0x73U, 0x6dU, + 0x6aU, 0x73U, 0x2fU, 0x74U, 0x65U, 0x73U, 0x74U, 0x2dU, 0x32U, + 0x2dU, 0x67U, 0x65U, 0x6eU, 0x2eU, 0x6aU, 0x73U, 0x02U, 0x72U, + 0x14U, 0x68U, 0x6fU, 0x6fU, 0x6bU, 0x5fU, 0x61U, 0x67U, 0x61U, + 0x69U, 0x6eU, 0x10U, 0x72U, 0x6fU, 0x6cU, 0x6cU, 0x62U, 0x61U, + 0x63U, 0x6bU, 0x0cU, 0x61U, 0x63U, 0x63U, 0x65U, 0x70U, 0x74U, + 0x0cU, 0x00U, 0x06U, 0x00U, 0xa2U, 0x01U, 0x00U, 0x01U, 0x00U, + 0x01U, 0x00U, 0x01U, 0x40U, 0x01U, 0xa4U, 0x01U, 0x00U, 0x00U, + 0x00U, 0x3fU, 0xe3U, 0x00U, 0x00U, 0x00U, 0x80U, 0x3fU, 0xe4U, + 0x00U, 0x00U, 0x00U, 0x80U, 0x3fU, 0xe5U, 0x00U, 0x00U, 0x00U, + 0x80U, 0x3eU, 0xe3U, 0x00U, 0x00U, 0x00U, 0x80U, 0x3eU, 0xe4U, + 0x00U, 0x00U, 0x00U, 0x80U, 0x3eU, 0xe5U, 0x00U, 0x00U, 0x00U, + 0x80U, 0xbfU, 0xf7U, 0x3aU, 0xe3U, 0x00U, 0x00U, 0x00U, 0xbfU, + 0xf8U, 0x3aU, 0xe4U, 0x00U, 0x00U, 0x00U, 0xc2U, 0x00U, 0x4dU, + 0xe5U, 0x00U, 0x00U, 0x00U, 0x3aU, 0xe5U, 0x00U, 0x00U, 0x00U, + 0xc7U, 0x28U, 0xccU, 0x03U, 0x01U, 0x06U, 0x5bU, 0x5eU, 0x26U, + 0x00U, 0x07U, 0x1aU, 0x0cU, 0x02U, 0x06U, 0x00U, 0x00U, 0x01U, + 0x00U, 0x01U, 0x03U, 0x00U, 0x00U, 0x63U, 0x01U, 0xceU, 0x03U, + 0x00U, 0x01U, 0x00U, 0xd3U, 0xb7U, 0xa6U, 0xecU, 0x25U, 0x38U, + 0xe8U, 0x00U, 0x00U, 0x00U, 0xf0U, 0x38U, 0xe3U, 0x00U, 0x00U, + 0x00U, 0xabU, 0xecU, 0x0dU, 0x38U, 0xe9U, 0x00U, 0x00U, 0x00U, + 0xc3U, 0xc0U, 0xfdU, 0x00U, 0x23U, 0x02U, 0x00U, 0x38U, 0xeaU, + 0x00U, 0x00U, 0x00U, 0xc3U, 0xb8U, 0x23U, 0x02U, 0x00U, 0x38U, + 0xe8U, 0x00U, 0x00U, 0x00U, 0xf0U, 0xb8U, 0xabU, 0xecU, 0x0dU, + 0x38U, 0xe9U, 0x00U, 0x00U, 0x00U, 0xc3U, 0xc0U, 0xfeU, 0x00U, + 0x23U, 0x02U, 0x00U, 0x38U, 0xe8U, 0x00U, 0x00U, 0x00U, 0xf0U, + 0x38U, 0xe4U, 0x00U, 0x00U, 0x00U, 0xabU, 0xecU, 0x0dU, 0x38U, + 0xe9U, 0x00U, 0x00U, 0x00U, 0xc3U, 0xc0U, 0xffU, 0x00U, 0x23U, + 0x02U, 0x00U, 0x38U, 0xeaU, 0x00U, 0x00U, 0x00U, 0xc3U, 0xb7U, + 0x23U, 0x02U, 0x00U, 0xccU, 0x03U, 0x05U, 0x06U, 0x03U, 0x1cU, + 0x86U, 0x37U, 0x72U, 0x85U}; + + // TestHook hook = jswasm[R"[test.hook]( + // const PREREQUISITE_NOT_MET = -9 + // const ALREADY_SET = -8 + + // const Hook = (r) => { + // if (r > 0) { + // if (hook_again() != PREREQUISITE_NOT_MET) return rollback('', 253) + + // return accept('', 1) + // } + + // if (hook_again() != 1) return rollback('', 254) + + // if (hook_again() != ALREADY_SET) return rollback('', 255) + // return accept('', 0) + // } + // )[test.hook]"]; + + // install the hook on alice + env(ripple::test::jtx::hook(alice, {{hsov1(hook, 1, overrideFlag)}}, 0), + M("set hook_again"), + HSFEE); + env.close(); + + env(pay(bob, alice, XRP(1)), M("test hook_again"), fee(XRP(1))); + env.close(); + + auto meta = env.meta(); + + // ensure hook execution occured + BEAST_REQUIRE(meta); + BEAST_REQUIRE(meta->isFieldPresent(sfHookExecutions)); + + // ensure there were two executions + auto const hookExecutions = meta->getFieldArray(sfHookExecutions); + BEAST_REQUIRE(hookExecutions.size() == 2); + + // get the data in the return code of the execution + bool const fixV2 = env.current()->rules().enabled(fixXahauV2); + if (fixV2) { - auto const ledger = env.closed(); - int txcount = 0; - for ([[maybe_unused]] auto& i : ledger->txs) - txcount++; - BEAST_EXPECT(txcount == 0); + 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); + + // RH TODO: test hook_again on a weak execution not following a strong + // execution to make sure it fails + } + + void + test_hook_hash(FeatureBitset features) + { + testcase("Test hook_hash"); + using namespace jtx; + + auto const test = [&](Account alice) -> void { + Env env{*this, features}; + + auto const bob = Account{"bob"}; + env.fund(XRP(10000), alice); + env.fund(XRP(10000), bob); + + TestHook hook = { + 0x43U, 0x11U, 0x0cU, 0x41U, 0x53U, 0x53U, 0x45U, 0x52U, 0x54U, + 0x0aU, 0x74U, 0x6fU, 0x48U, 0x65U, 0x78U, 0x08U, 0x48U, 0x6fU, + 0x6fU, 0x6bU, 0x28U, 0x77U, 0x61U, 0x73U, 0x6dU, 0x6aU, 0x73U, + 0x2fU, 0x74U, 0x65U, 0x73U, 0x74U, 0x2dU, 0x33U, 0x2dU, 0x67U, + 0x65U, 0x6eU, 0x2eU, 0x6aU, 0x73U, 0x02U, 0x78U, 0x08U, 0x63U, + 0x6fU, 0x64U, 0x65U, 0x10U, 0x72U, 0x6fU, 0x6cU, 0x6cU, 0x62U, + 0x61U, 0x63U, 0x6bU, 0x06U, 0x61U, 0x72U, 0x72U, 0x06U, 0x6dU, + 0x61U, 0x70U, 0x16U, 0x74U, 0x6fU, 0x55U, 0x70U, 0x70U, 0x65U, + 0x72U, 0x43U, 0x61U, 0x73U, 0x65U, 0x06U, 0x6eU, 0x75U, 0x6dU, + 0x10U, 0x70U, 0x61U, 0x64U, 0x53U, 0x74U, 0x61U, 0x72U, 0x74U, + 0x06U, 0x61U, 0x72U, 0x67U, 0x08U, 0x68U, 0x61U, 0x73U, 0x68U, + 0x12U, 0x68U, 0x6fU, 0x6fU, 0x6bU, 0x5fU, 0x68U, 0x61U, 0x73U, + 0x68U, 0x0aU, 0x74U, 0x72U, 0x61U, 0x63U, 0x65U, 0x0cU, 0x61U, + 0x63U, 0x63U, 0x65U, 0x70U, 0x74U, 0x0cU, 0x00U, 0x06U, 0x00U, + 0xa2U, 0x01U, 0x00U, 0x01U, 0x00U, 0x01U, 0x00U, 0x03U, 0x4aU, + 0x01U, 0xa4U, 0x01U, 0x00U, 0x00U, 0x00U, 0x3fU, 0xe3U, 0x00U, + 0x00U, 0x00U, 0x80U, 0x3fU, 0xe4U, 0x00U, 0x00U, 0x00U, 0x80U, + 0x3fU, 0xe5U, 0x00U, 0x00U, 0x00U, 0x80U, 0x3eU, 0xe3U, 0x00U, + 0x00U, 0x00U, 0x80U, 0x3eU, 0xe4U, 0x00U, 0x00U, 0x00U, 0x80U, + 0x3eU, 0xe5U, 0x00U, 0x00U, 0x00U, 0x80U, 0xc2U, 0x00U, 0x4dU, + 0xe3U, 0x00U, 0x00U, 0x00U, 0x3aU, 0xe3U, 0x00U, 0x00U, 0x00U, + 0xc2U, 0x01U, 0x4dU, 0xe4U, 0x00U, 0x00U, 0x00U, 0x3aU, 0xe4U, + 0x00U, 0x00U, 0x00U, 0xc2U, 0x02U, 0x4dU, 0xe5U, 0x00U, 0x00U, + 0x00U, 0x3aU, 0xe5U, 0x00U, 0x00U, 0x00U, 0xc7U, 0x28U, 0xccU, + 0x03U, 0x01U, 0x0aU, 0x5bU, 0x00U, 0x12U, 0x0cU, 0x00U, 0x0cU, + 0x0eU, 0x00U, 0x0cU, 0x12U, 0x0cU, 0x02U, 0x06U, 0x00U, 0x00U, + 0x02U, 0x00U, 0x02U, 0x03U, 0x00U, 0x00U, 0x16U, 0x02U, 0xceU, + 0x03U, 0x00U, 0x01U, 0x00U, 0xd0U, 0x03U, 0x00U, 0x01U, 0x00U, + 0xd3U, 0x97U, 0xecU, 0x12U, 0x38U, 0xe9U, 0x00U, 0x00U, 0x00U, + 0xd3U, 0x42U, 0x38U, 0x00U, 0x00U, 0x00U, 0x24U, 0x00U, 0x00U, + 0xd4U, 0xf2U, 0x0eU, 0x29U, 0xccU, 0x03U, 0x02U, 0x03U, 0x03U, + 0x17U, 0x59U, 0x0cU, 0x02U, 0x06U, 0x00U, 0x00U, 0x01U, 0x00U, + 0x01U, 0x03U, 0x00U, 0x01U, 0x1cU, 0x01U, 0xd4U, 0x03U, 0x00U, + 0x01U, 0x00U, 0xd3U, 0x42U, 0xebU, 0x00U, 0x00U, 0x00U, 0xc2U, + 0x00U, 0x24U, 0x01U, 0x00U, 0x42U, 0x5cU, 0x00U, 0x00U, 0x00U, + 0xc3U, 0x24U, 0x01U, 0x00U, 0x42U, 0xecU, 0x00U, 0x00U, 0x00U, + 0x25U, 0x00U, 0x00U, 0xccU, 0x03U, 0x08U, 0x04U, 0x03U, 0x08U, + 0x35U, 0x30U, 0x0cU, 0x02U, 0x06U, 0x00U, 0x00U, 0x01U, 0x00U, + 0x01U, 0x04U, 0x00U, 0x01U, 0x16U, 0x01U, 0xdaU, 0x03U, 0x00U, + 0x01U, 0x00U, 0xd3U, 0x42U, 0x38U, 0x00U, 0x00U, 0x00U, 0xbfU, + 0x10U, 0x24U, 0x01U, 0x00U, 0x42U, 0xeeU, 0x00U, 0x00U, 0x00U, + 0xb9U, 0xc1U, 0x00U, 0x25U, 0x02U, 0x00U, 0xccU, 0x03U, 0x0aU, + 0x00U, 0x07U, 0x02U, 0x30U, 0x0cU, 0x02U, 0x06U, 0x00U, 0x00U, + 0x01U, 0x01U, 0x01U, 0x04U, 0x00U, 0x00U, 0x3cU, 0x02U, 0xdeU, + 0x03U, 0x00U, 0x01U, 0x00U, 0xe0U, 0x03U, 0x01U, 0x00U, 0x30U, + 0x61U, 0x00U, 0x00U, 0x38U, 0xf1U, 0x00U, 0x00U, 0x00U, 0xb6U, + 0xf1U, 0xcbU, 0x38U, 0xe3U, 0x00U, 0x00U, 0x00U, 0x62U, 0x00U, + 0x00U, 0xebU, 0xbfU, 0x20U, 0xaaU, 0xb7U, 0xf2U, 0x0eU, 0x38U, + 0xf2U, 0x00U, 0x00U, 0x00U, 0x04U, 0xf0U, 0x00U, 0x00U, 0x00U, + 0x62U, 0x00U, 0x00U, 0x09U, 0xf3U, 0x0eU, 0x38U, 0xf3U, 0x00U, + 0x00U, 0x00U, 0x38U, 0xe4U, 0x00U, 0x00U, 0x00U, 0x62U, 0x00U, + 0x00U, 0xf1U, 0xb7U, 0x23U, 0x02U, 0x00U, 0xccU, 0x03U, 0x0fU, + 0x04U, 0x12U, 0x2bU, 0x4eU, 0x55U}; + // TestHook hook = jswasm[R"[test.hook]( + // const ASSERT = (x, code) => { + // if (!x) { + // rollback(x.toString(), code) + // } + // } + + // const toHex = (arr) => { + // return arr + // .map((num) => num.toString(16).padStart(2, '0')) + // .join('') + // .toUpperCase() + // } + + // const Hook = (arg) => { + // const hash = hook_hash(-1) + // ASSERT(hash.length == 32, 0) + // trace('hash', hash, false) + + // // return the hash as the return string + // return accept(toHex(hash), 0) + // } + // )[test.hook]"]; + + // install the hook on alice + env(ripple::test::jtx::hook(alice, {{hsov1(hook, 1, overrideFlag)}}, 0), + M("set hook_hash"), + HSFEE); + env.close(); + + // invoke the hook + env(pay(bob, alice, XRP(1)), M("test hook_hash"), fee(XRP(1))); + + { + auto meta = env.meta(); + + // ensure hook execution occured + BEAST_REQUIRE(meta); + BEAST_REQUIRE(meta->isFieldPresent(sfHookExecutions)); + + // ensure there was only one hook execution + auto const hookExecutions = + meta->getFieldArray(sfHookExecutions); + BEAST_REQUIRE(hookExecutions.size() == 1); + + // get the data in the return string of the extention + auto const tmpRet = + hookExecutions[0].getFieldVL(sfHookReturnString); + + // DA: TODO Fix `accept` and `rollback` and remove these lines + std::string tmpStr(tmpRet.begin(), tmpRet.end()); + auto const tmpBlob = strUnHex(tmpStr); + Blob const retStr = Blob(tmpBlob->begin(), tmpBlob->end()); + + // check that it matches the hook hash + BEAST_EXPECT(retStr.size() == 32); + + auto const hash = hookExecutions[0].getFieldH256(sfHookHash); + BEAST_EXPECT(memcmp(hash.data(), retStr.data(), 32) == 0); + } + + TestHook hook2 = { + 0x43U, 0x11U, 0x0cU, 0x41U, 0x53U, 0x53U, 0x45U, 0x52U, 0x54U, + 0x0aU, 0x74U, 0x6fU, 0x48U, 0x65U, 0x78U, 0x08U, 0x48U, 0x6fU, + 0x6fU, 0x6bU, 0x28U, 0x77U, 0x61U, 0x73U, 0x6dU, 0x6aU, 0x73U, + 0x2fU, 0x74U, 0x65U, 0x73U, 0x74U, 0x2dU, 0x34U, 0x2dU, 0x67U, + 0x65U, 0x6eU, 0x2eU, 0x6aU, 0x73U, 0x02U, 0x78U, 0x08U, 0x63U, + 0x6fU, 0x64U, 0x65U, 0x10U, 0x72U, 0x6fU, 0x6cU, 0x6cU, 0x62U, + 0x61U, 0x63U, 0x6bU, 0x06U, 0x61U, 0x72U, 0x72U, 0x06U, 0x6dU, + 0x61U, 0x70U, 0x16U, 0x74U, 0x6fU, 0x55U, 0x70U, 0x70U, 0x65U, + 0x72U, 0x43U, 0x61U, 0x73U, 0x65U, 0x06U, 0x6eU, 0x75U, 0x6dU, + 0x10U, 0x70U, 0x61U, 0x64U, 0x53U, 0x74U, 0x61U, 0x72U, 0x74U, + 0x06U, 0x61U, 0x72U, 0x67U, 0x08U, 0x68U, 0x61U, 0x73U, 0x68U, + 0x12U, 0x68U, 0x6fU, 0x6fU, 0x6bU, 0x5fU, 0x68U, 0x61U, 0x73U, + 0x68U, 0x0aU, 0x74U, 0x72U, 0x61U, 0x63U, 0x65U, 0x0cU, 0x61U, + 0x63U, 0x63U, 0x65U, 0x70U, 0x74U, 0x0cU, 0x00U, 0x06U, 0x00U, + 0xa2U, 0x01U, 0x00U, 0x01U, 0x00U, 0x01U, 0x00U, 0x03U, 0x4aU, + 0x01U, 0xa4U, 0x01U, 0x00U, 0x00U, 0x00U, 0x3fU, 0xe3U, 0x00U, + 0x00U, 0x00U, 0x80U, 0x3fU, 0xe4U, 0x00U, 0x00U, 0x00U, 0x80U, + 0x3fU, 0xe5U, 0x00U, 0x00U, 0x00U, 0x80U, 0x3eU, 0xe3U, 0x00U, + 0x00U, 0x00U, 0x80U, 0x3eU, 0xe4U, 0x00U, 0x00U, 0x00U, 0x80U, + 0x3eU, 0xe5U, 0x00U, 0x00U, 0x00U, 0x80U, 0xc2U, 0x00U, 0x4dU, + 0xe3U, 0x00U, 0x00U, 0x00U, 0x3aU, 0xe3U, 0x00U, 0x00U, 0x00U, + 0xc2U, 0x01U, 0x4dU, 0xe4U, 0x00U, 0x00U, 0x00U, 0x3aU, 0xe4U, + 0x00U, 0x00U, 0x00U, 0xc2U, 0x02U, 0x4dU, 0xe5U, 0x00U, 0x00U, + 0x00U, 0x3aU, 0xe5U, 0x00U, 0x00U, 0x00U, 0xc7U, 0x28U, 0xccU, + 0x03U, 0x01U, 0x0aU, 0x5bU, 0x00U, 0x12U, 0x0cU, 0x00U, 0x0cU, + 0x0eU, 0x00U, 0x0cU, 0x12U, 0x0cU, 0x02U, 0x06U, 0x00U, 0x00U, + 0x02U, 0x00U, 0x02U, 0x03U, 0x00U, 0x00U, 0x16U, 0x02U, 0xceU, + 0x03U, 0x00U, 0x01U, 0x00U, 0xd0U, 0x03U, 0x00U, 0x01U, 0x00U, + 0xd3U, 0x97U, 0xecU, 0x12U, 0x38U, 0xe9U, 0x00U, 0x00U, 0x00U, + 0xd3U, 0x42U, 0x38U, 0x00U, 0x00U, 0x00U, 0x24U, 0x00U, 0x00U, + 0xd4U, 0xf2U, 0x0eU, 0x29U, 0xccU, 0x03U, 0x02U, 0x03U, 0x03U, + 0x17U, 0x59U, 0x0cU, 0x02U, 0x06U, 0x00U, 0x00U, 0x01U, 0x00U, + 0x01U, 0x03U, 0x00U, 0x01U, 0x1cU, 0x01U, 0xd4U, 0x03U, 0x00U, + 0x01U, 0x00U, 0xd3U, 0x42U, 0xebU, 0x00U, 0x00U, 0x00U, 0xc2U, + 0x00U, 0x24U, 0x01U, 0x00U, 0x42U, 0x5cU, 0x00U, 0x00U, 0x00U, + 0xc3U, 0x24U, 0x01U, 0x00U, 0x42U, 0xecU, 0x00U, 0x00U, 0x00U, + 0x25U, 0x00U, 0x00U, 0xccU, 0x03U, 0x08U, 0x04U, 0x03U, 0x08U, + 0x35U, 0x30U, 0x0cU, 0x02U, 0x06U, 0x00U, 0x00U, 0x01U, 0x00U, + 0x01U, 0x04U, 0x00U, 0x01U, 0x16U, 0x01U, 0xdaU, 0x03U, 0x00U, + 0x01U, 0x00U, 0xd3U, 0x42U, 0x38U, 0x00U, 0x00U, 0x00U, 0xbfU, + 0x10U, 0x24U, 0x01U, 0x00U, 0x42U, 0xeeU, 0x00U, 0x00U, 0x00U, + 0xb9U, 0xc1U, 0x00U, 0x25U, 0x02U, 0x00U, 0xccU, 0x03U, 0x0aU, + 0x00U, 0x07U, 0x02U, 0x30U, 0x0cU, 0x02U, 0x06U, 0x00U, 0x00U, + 0x01U, 0x01U, 0x01U, 0x04U, 0x00U, 0x00U, 0x3cU, 0x02U, 0xdeU, + 0x03U, 0x00U, 0x01U, 0x00U, 0xe0U, 0x03U, 0x01U, 0x00U, 0x30U, + 0x61U, 0x00U, 0x00U, 0x38U, 0xf1U, 0x00U, 0x00U, 0x00U, 0xb6U, + 0xf1U, 0xcbU, 0x38U, 0xe3U, 0x00U, 0x00U, 0x00U, 0x62U, 0x00U, + 0x00U, 0xebU, 0xbfU, 0x20U, 0xaaU, 0xb7U, 0xf2U, 0x0eU, 0x38U, + 0xf2U, 0x00U, 0x00U, 0x00U, 0x04U, 0xf0U, 0x00U, 0x00U, 0x00U, + 0x62U, 0x00U, 0x00U, 0x09U, 0xf3U, 0x0eU, 0x38U, 0xf3U, 0x00U, + 0x00U, 0x00U, 0x38U, 0xe4U, 0x00U, 0x00U, 0x00U, 0x62U, 0x00U, + 0x00U, 0xf1U, 0xb9U, 0x23U, 0x02U, 0x00U, 0xccU, 0x03U, 0x0fU, + 0x04U, 0x12U, 0x2bU, 0x4eU, 0x55U}; + // TestHook hook2 = jswasm[R"[test.hook]( + // const ASSERT = (x, code) => { + // if (!x) { + // rollback(x.toString(), code) + // } + // } + + // const toHex = (arr) => { + // return arr + // .map((num) => num.toString(16).padStart(2, '0')) + // .join('') + // .toUpperCase() + // } + + // const Hook = (arg) => { + // const hash = hook_hash(-1) + // ASSERT(hash.length == 32, 0) + // trace('hash', hash, false) + + // // return the hash as the return string + // return accept(toHex(hash), 2) + // } + // )[test.hook]"]; + + // install a slightly different hook on bob + env(ripple::test::jtx::hook(bob, {{hsov1(hook2, 1, overrideFlag)}}, 0), + M("set hook_hash 2"), + HSFEE); + env.close(); + + // invoke the hook + env(pay(bob, alice, XRP(1)), M("test hook_hash 2"), fee(XRP(1))); + + // there should be two hook executions, the first should have bob's + // hook hash the second should have alice's hook hash + { + auto meta = env.meta(); + + // ensure hook execution occured + BEAST_REQUIRE(meta); + BEAST_REQUIRE(meta->isFieldPresent(sfHookExecutions)); + + // ensure there was only one hook execution + auto const hookExecutions = + meta->getFieldArray(sfHookExecutions); + BEAST_REQUIRE(hookExecutions.size() == 2); + + // get the data in the return string of the extention + auto const tmpRet1 = + hookExecutions[0].getFieldVL(sfHookReturnString); + + // DA: TODO Fix `accept` and `rollback` and remove these lines + std::string tmpStr1(tmpRet1.begin(), tmpRet1.end()); + auto const tmpBlob1 = strUnHex(tmpStr1); + Blob const retStr1 = Blob(tmpBlob1->begin(), tmpBlob1->end()); + + // check that it matches the hook hash + BEAST_EXPECT(retStr1.size() == 32); + + auto const hash1 = hookExecutions[0].getFieldH256(sfHookHash); + BEAST_EXPECT(memcmp(hash1.data(), retStr1.data(), 32) == 0); + + // get the data in the return string of the extention + auto const tmpRet2 = + hookExecutions[1].getFieldVL(sfHookReturnString); + + // DA: TODO Fix `accept` and `rollback` and remove these lines + std::string tmpStr2(tmpRet2.begin(), tmpRet2.end()); + auto const tmpBlob2 = strUnHex(tmpStr2); + Blob const retStr2 = Blob(tmpBlob2->begin(), tmpBlob2->end()); + + // check that it matches the hook hash + BEAST_EXPECT(retStr2.size() == 32); + + auto const hash2 = hookExecutions[1].getFieldH256(sfHookHash); + BEAST_EXPECT(memcmp(hash2.data(), retStr2.data(), 32) == 0); + + // make sure they're not the same + BEAST_EXPECT(memcmp(hash1.data(), hash2.data(), 32) != 0); + + // compute the hashes + auto computedHash2 = ripple::sha512Half_s( + ripple::Slice(hook.data(), hook.size())); + + auto computedHash1 = ripple::sha512Half_s( + ripple::Slice(hook2.data(), hook2.size())); + + // ensure the computed hashes match + BEAST_EXPECT(computedHash1 == hash1); + BEAST_EXPECT(computedHash2 == hash2); + } + }; + + test(Account{"alice"}); + } + + void + test_hook_param(FeatureBitset features) + { + testcase("Test hook_param"); + using namespace jtx; + Env env{*this, features}; + + Account const alice{"alice"}; + Account const bob{"bob"}; + env.fund(XRP(10000), alice); + env.fund(XRP(10000), bob); + + TestHook hook = { + 0x43U, 0x33U, 0x0cU, 0x41U, 0x53U, 0x53U, 0x45U, 0x52U, 0x54U, + 0x18U, 0x44U, 0x4fU, 0x45U, 0x53U, 0x4eU, 0x54U, 0x5fU, 0x45U, + 0x58U, 0x49U, 0x53U, 0x54U, 0x0aU, 0x6eU, 0x61U, 0x6dU, 0x65U, + 0x73U, 0x08U, 0x48U, 0x6fU, 0x6fU, 0x6bU, 0x0cU, 0x70U, 0x61U, + 0x72U, 0x61U, 0x6dU, 0x30U, 0x0cU, 0x70U, 0x61U, 0x72U, 0x61U, + 0x6dU, 0x31U, 0x0cU, 0x70U, 0x61U, 0x72U, 0x61U, 0x6dU, 0x32U, + 0x0cU, 0x70U, 0x61U, 0x72U, 0x61U, 0x6dU, 0x33U, 0x0cU, 0x70U, + 0x61U, 0x72U, 0x61U, 0x6dU, 0x34U, 0x0cU, 0x70U, 0x61U, 0x72U, + 0x61U, 0x6dU, 0x35U, 0x0cU, 0x70U, 0x61U, 0x72U, 0x61U, 0x6dU, + 0x36U, 0x0cU, 0x70U, 0x61U, 0x72U, 0x61U, 0x6dU, 0x37U, 0x0cU, + 0x70U, 0x61U, 0x72U, 0x61U, 0x6dU, 0x38U, 0x0cU, 0x70U, 0x61U, + 0x72U, 0x61U, 0x6dU, 0x39U, 0x0eU, 0x70U, 0x61U, 0x72U, 0x61U, + 0x6dU, 0x31U, 0x30U, 0x0eU, 0x70U, 0x61U, 0x72U, 0x61U, 0x6dU, + 0x31U, 0x31U, 0x0eU, 0x70U, 0x61U, 0x72U, 0x61U, 0x6dU, 0x31U, + 0x32U, 0x0eU, 0x70U, 0x61U, 0x72U, 0x61U, 0x6dU, 0x31U, 0x33U, + 0x0eU, 0x70U, 0x61U, 0x72U, 0x61U, 0x6dU, 0x31U, 0x34U, 0x0eU, + 0x70U, 0x61U, 0x72U, 0x61U, 0x6dU, 0x31U, 0x35U, 0x0cU, 0x76U, + 0x61U, 0x6cU, 0x75U, 0x65U, 0x30U, 0x0cU, 0x76U, 0x61U, 0x6cU, + 0x75U, 0x65U, 0x31U, 0x0cU, 0x76U, 0x61U, 0x6cU, 0x75U, 0x65U, + 0x32U, 0x0cU, 0x76U, 0x61U, 0x6cU, 0x75U, 0x65U, 0x33U, 0x0cU, + 0x76U, 0x61U, 0x6cU, 0x75U, 0x65U, 0x34U, 0x0cU, 0x76U, 0x61U, + 0x6cU, 0x75U, 0x65U, 0x35U, 0x0cU, 0x76U, 0x61U, 0x6cU, 0x75U, + 0x65U, 0x36U, 0x0cU, 0x76U, 0x61U, 0x6cU, 0x75U, 0x65U, 0x37U, + 0x0cU, 0x76U, 0x61U, 0x6cU, 0x75U, 0x65U, 0x38U, 0x0cU, 0x76U, + 0x61U, 0x6cU, 0x75U, 0x65U, 0x39U, 0x0eU, 0x76U, 0x61U, 0x6cU, + 0x75U, 0x65U, 0x31U, 0x30U, 0x0eU, 0x76U, 0x61U, 0x6cU, 0x75U, + 0x65U, 0x31U, 0x31U, 0x0eU, 0x76U, 0x61U, 0x6cU, 0x75U, 0x65U, + 0x31U, 0x32U, 0x0eU, 0x76U, 0x61U, 0x6cU, 0x75U, 0x65U, 0x31U, + 0x33U, 0x0eU, 0x76U, 0x61U, 0x6cU, 0x75U, 0x65U, 0x31U, 0x34U, + 0x0eU, 0x76U, 0x61U, 0x6cU, 0x75U, 0x65U, 0x31U, 0x35U, 0x28U, + 0x77U, 0x61U, 0x73U, 0x6dU, 0x6aU, 0x73U, 0x2fU, 0x74U, 0x65U, + 0x73U, 0x74U, 0x2dU, 0x35U, 0x2dU, 0x67U, 0x65U, 0x6eU, 0x2eU, + 0x6aU, 0x73U, 0x02U, 0x78U, 0x08U, 0x63U, 0x6fU, 0x64U, 0x65U, + 0x10U, 0x72U, 0x6fU, 0x6cU, 0x6cU, 0x62U, 0x61U, 0x63U, 0x6bU, + 0x06U, 0x61U, 0x72U, 0x67U, 0x02U, 0x69U, 0x02U, 0x73U, 0x06U, + 0x62U, 0x75U, 0x66U, 0x14U, 0x68U, 0x6fU, 0x6fU, 0x6bU, 0x5fU, + 0x70U, 0x61U, 0x72U, 0x61U, 0x6dU, 0x02U, 0x76U, 0x02U, 0x61U, + 0x02U, 0x6cU, 0x02U, 0x75U, 0x02U, 0x65U, 0x0cU, 0x61U, 0x63U, + 0x63U, 0x65U, 0x70U, 0x74U, 0x0cU, 0x00U, 0x06U, 0x00U, 0xa2U, + 0x01U, 0x00U, 0x01U, 0x00U, 0x10U, 0x00U, 0x02U, 0x8dU, 0x02U, + 0x01U, 0xa4U, 0x01U, 0x00U, 0x00U, 0x00U, 0x3fU, 0xe3U, 0x00U, + 0x00U, 0x00U, 0x80U, 0x3fU, 0xe4U, 0x00U, 0x00U, 0x00U, 0x80U, + 0x3fU, 0xe5U, 0x00U, 0x00U, 0x00U, 0x80U, 0x3fU, 0x6cU, 0x00U, + 0x00U, 0x00U, 0x80U, 0x3fU, 0xe6U, 0x00U, 0x00U, 0x00U, 0x80U, + 0x3eU, 0xe3U, 0x00U, 0x00U, 0x00U, 0x80U, 0x3eU, 0xe4U, 0x00U, + 0x00U, 0x00U, 0x80U, 0x3eU, 0xe5U, 0x00U, 0x00U, 0x00U, 0x80U, + 0x3eU, 0x6cU, 0x00U, 0x00U, 0x00U, 0x80U, 0x3eU, 0xe6U, 0x00U, + 0x00U, 0x00U, 0x80U, 0xc2U, 0x00U, 0x4dU, 0xe3U, 0x00U, 0x00U, + 0x00U, 0x3aU, 0xe3U, 0x00U, 0x00U, 0x00U, 0xbfU, 0xfbU, 0x3aU, + 0xe4U, 0x00U, 0x00U, 0x00U, 0x04U, 0xe7U, 0x00U, 0x00U, 0x00U, + 0x04U, 0xe8U, 0x00U, 0x00U, 0x00U, 0x04U, 0xe9U, 0x00U, 0x00U, + 0x00U, 0x04U, 0xeaU, 0x00U, 0x00U, 0x00U, 0x04U, 0xebU, 0x00U, + 0x00U, 0x00U, 0x04U, 0xecU, 0x00U, 0x00U, 0x00U, 0x04U, 0xedU, + 0x00U, 0x00U, 0x00U, 0x04U, 0xeeU, 0x00U, 0x00U, 0x00U, 0x04U, + 0xefU, 0x00U, 0x00U, 0x00U, 0x04U, 0xf0U, 0x00U, 0x00U, 0x00U, + 0x04U, 0xf1U, 0x00U, 0x00U, 0x00U, 0x04U, 0xf2U, 0x00U, 0x00U, + 0x00U, 0x04U, 0xf3U, 0x00U, 0x00U, 0x00U, 0x04U, 0xf4U, 0x00U, + 0x00U, 0x00U, 0x04U, 0xf5U, 0x00U, 0x00U, 0x00U, 0x04U, 0xf6U, + 0x00U, 0x00U, 0x00U, 0x26U, 0x10U, 0x00U, 0x3aU, 0xe5U, 0x00U, + 0x00U, 0x00U, 0x04U, 0xf7U, 0x00U, 0x00U, 0x00U, 0x04U, 0xf8U, + 0x00U, 0x00U, 0x00U, 0x04U, 0xf9U, 0x00U, 0x00U, 0x00U, 0x04U, + 0xfaU, 0x00U, 0x00U, 0x00U, 0x04U, 0xfbU, 0x00U, 0x00U, 0x00U, + 0x04U, 0xfcU, 0x00U, 0x00U, 0x00U, 0x04U, 0xfdU, 0x00U, 0x00U, + 0x00U, 0x04U, 0xfeU, 0x00U, 0x00U, 0x00U, 0x04U, 0xffU, 0x00U, + 0x00U, 0x00U, 0x04U, 0x00U, 0x01U, 0x00U, 0x00U, 0x04U, 0x01U, + 0x01U, 0x00U, 0x00U, 0x04U, 0x02U, 0x01U, 0x00U, 0x00U, 0x04U, + 0x03U, 0x01U, 0x00U, 0x00U, 0x04U, 0x04U, 0x01U, 0x00U, 0x00U, + 0x04U, 0x05U, 0x01U, 0x00U, 0x00U, 0x04U, 0x06U, 0x01U, 0x00U, + 0x00U, 0x26U, 0x10U, 0x00U, 0x3aU, 0x6cU, 0x00U, 0x00U, 0x00U, + 0xc2U, 0x01U, 0x4dU, 0xe6U, 0x00U, 0x00U, 0x00U, 0x3aU, 0xe6U, + 0x00U, 0x00U, 0x00U, 0xc7U, 0x28U, 0x8eU, 0x04U, 0x01U, 0x2cU, + 0x97U, 0x00U, 0x1eU, 0x0cU, 0x40U, 0x27U, 0x1cU, 0x1cU, 0x1cU, + 0x1cU, 0x1cU, 0x1cU, 0x1cU, 0x1cU, 0x1cU, 0x1cU, 0x1cU, 0x1cU, + 0x1cU, 0x1cU, 0x1cU, 0x1cU, 0x12U, 0x1cU, 0x1cU, 0x1cU, 0x1cU, + 0x1cU, 0x1cU, 0x1cU, 0x1cU, 0x1cU, 0x1cU, 0x1cU, 0x1cU, 0x1cU, + 0x1cU, 0x1cU, 0x1cU, 0x1cU, 0x12U, 0x00U, 0x05U, 0x2aU, 0x0cU, + 0x02U, 0x06U, 0x00U, 0x00U, 0x02U, 0x00U, 0x02U, 0x03U, 0x00U, + 0x00U, 0x16U, 0x02U, 0x90U, 0x04U, 0x00U, 0x01U, 0x00U, 0x92U, + 0x04U, 0x00U, 0x01U, 0x00U, 0xd3U, 0x97U, 0xecU, 0x12U, 0x38U, + 0x0aU, 0x01U, 0x00U, 0x00U, 0xd3U, 0x42U, 0x38U, 0x00U, 0x00U, + 0x00U, 0x24U, 0x00U, 0x00U, 0xd4U, 0xf2U, 0x0eU, 0x29U, 0x8eU, + 0x04U, 0x02U, 0x03U, 0x03U, 0x17U, 0x59U, 0x0cU, 0x02U, 0x06U, + 0x00U, 0x00U, 0x01U, 0x03U, 0x01U, 0x05U, 0x00U, 0x00U, 0xccU, + 0x01U, 0x04U, 0x96U, 0x04U, 0x00U, 0x01U, 0x00U, 0x98U, 0x04U, + 0x00U, 0x00U, 0x00U, 0x9aU, 0x04U, 0x00U, 0x01U, 0x00U, 0x9cU, + 0x04U, 0x00U, 0x02U, 0x00U, 0x38U, 0xe3U, 0x00U, 0x00U, 0x00U, + 0x38U, 0x0fU, 0x01U, 0x00U, 0x00U, 0xc3U, 0xf1U, 0x38U, 0xe4U, + 0x00U, 0x00U, 0x00U, 0xaaU, 0xf1U, 0x0eU, 0xb7U, 0xcbU, 0xc7U, + 0xbfU, 0x10U, 0xa4U, 0x6aU, 0xa7U, 0x00U, 0x00U, 0x00U, 0xbdU, + 0xc7U, 0xbfU, 0x0aU, 0xa4U, 0xecU, 0x04U, 0xb7U, 0xeeU, 0x02U, + 0xb8U, 0x9eU, 0xccU, 0x38U, 0x0fU, 0x01U, 0x00U, 0x00U, 0x38U, + 0xe5U, 0x00U, 0x00U, 0x00U, 0xc7U, 0x47U, 0xf1U, 0xcdU, 0x38U, + 0xe3U, 0x00U, 0x00U, 0x00U, 0xc9U, 0xebU, 0xc8U, 0xaaU, 0xf1U, + 0x0eU, 0x38U, 0xe3U, 0x00U, 0x00U, 0x00U, 0xc9U, 0xb7U, 0x47U, + 0x04U, 0x10U, 0x01U, 0x00U, 0x00U, 0xaaU, 0x11U, 0xecU, 0x32U, + 0x0eU, 0xc9U, 0xb8U, 0x47U, 0x04U, 0x11U, 0x01U, 0x00U, 0x00U, + 0xaaU, 0x11U, 0xecU, 0x25U, 0x0eU, 0xc9U, 0xb9U, 0x47U, 0x04U, + 0x12U, 0x01U, 0x00U, 0x00U, 0xaaU, 0x11U, 0xecU, 0x18U, 0x0eU, + 0xc9U, 0xbaU, 0x47U, 0x04U, 0x13U, 0x01U, 0x00U, 0x00U, 0xaaU, + 0x11U, 0xecU, 0x0bU, 0x0eU, 0xc9U, 0xbbU, 0x47U, 0x04U, 0x14U, + 0x01U, 0x00U, 0x00U, 0xaaU, 0xf1U, 0x0eU, 0x38U, 0xe3U, 0x00U, + 0x00U, 0x00U, 0xc9U, 0xc9U, 0xebU, 0xb8U, 0x9fU, 0x47U, 0x38U, + 0x6cU, 0x00U, 0x00U, 0x00U, 0xc7U, 0x47U, 0xc9U, 0xebU, 0xb8U, + 0x9fU, 0x47U, 0xaaU, 0xf1U, 0x0eU, 0x38U, 0xe3U, 0x00U, 0x00U, + 0x00U, 0xc9U, 0xc9U, 0xebU, 0xb9U, 0x9fU, 0x47U, 0x38U, 0x6cU, + 0x00U, 0x00U, 0x00U, 0xc7U, 0x47U, 0xc9U, 0xebU, 0xb9U, 0x9fU, + 0x47U, 0xaaU, 0xf1U, 0x0eU, 0x94U, 0x00U, 0xefU, 0x56U, 0xffU, + 0x38U, 0x15U, 0x01U, 0x00U, 0x00U, 0xc3U, 0xb7U, 0x23U, 0x02U, + 0x00U, 0x8eU, 0x04U, 0x2fU, 0x10U, 0x03U, 0x68U, 0x3aU, 0x44U, + 0x49U, 0x3bU, 0x1cU, 0x44U, 0x44U, 0x44U, 0x44U, 0x30U, 0x0dU, + 0x85U, 0x85U, 0x1cU}; + // TestHook hook = jswasm[R"[test.hook]( + // const ASSERT = (x, code) => { + // if (!x) { + // rollback(x.toString(), code) + // } + // } + + // const DOESNT_EXIST = -5 + + // const names = [ + // 'param0', + // 'param1', + // 'param2', + // 'param3', + // 'param4', + // 'param5', + // 'param6', + // 'param7', + // 'param8', + // 'param9', + // 'param10', + // 'param11', + // 'param12', + // 'param13', + // 'param14', + // 'param15', + // ] + // const values = [ + // 'value0', + // 'value1', + // 'value2', + // 'value3', + // 'value4', + // 'value5', + // 'value6', + // 'value7', + // 'value8', + // 'value9', + // 'value10', + // 'value11', + // 'value12', + // 'value13', + // 'value14', + // 'value15', + // ] + + // const Hook = (arg) => { + // ASSERT(hook_param('') == DOESNT_EXIST) + + // for (var i = 0; i < 16; ++i) { + // var s = 6 + (i < 10 ? 0 : 1) + // var buf = hook_param(names[i]) + // ASSERT(buf.length == s) + + // ASSERT( + // buf[0] == 'v' && + // buf[1] == 'a' && + // buf[2] == 'l' && + // buf[3] == 'u' && + // buf[4] == 'e' + // ) + // ASSERT(buf[buf.length - 1] == values[i][buf.length - 1]) + // ASSERT(buf[buf.length - 2] == values[i][buf.length - 2]) + // } + // return accept('', 0) + // } + // )[test.hook]"]; + + Json::Value jv; + jv[jss::Account] = alice.human(); + jv[jss::TransactionType] = jss::SetHook; + jv[jss::Flags] = 0; + jv[jss::Hooks] = Json::Value{Json::arrayValue}; + + Json::Value iv; + iv[jss::CreateCode] = strHex(hook); + iv[jss::HookOn] = + "0000000000000000000000000000000000000000000000000000000000000000"; + iv[jss::HookApiVersion] = 1U; + iv[jss::HookNamespace] = to_string(uint256{beast::zero}); + Json::Value params{Json::arrayValue}; + for (uint32_t i = 0; i < 16; ++i) + { + Json::Value pv; + Json::Value piv; + piv[jss::HookParameterName] = strHex("param" + std::to_string(i)); + piv[jss::HookParameterValue] = strHex("value" + std::to_string(i)); + pv[jss::HookParameter] = piv; + params[i] = pv; + } + iv[jss::HookParameters] = params; + jv[jss::Hooks][0U][jss::Hook] = iv; + env(jv, M("set hook_param"), HSFEE, ter(tesSUCCESS)); + env.close(); + + // invoke + env(pay(bob, alice, XRP(1)), M("test hook_param"), fee(XRP(1))); + env.close(); + } + + void + test_hook_param_set(FeatureBitset features) + { + testcase("Test hook_param_set"); + using namespace jtx; + Env env{*this, features}; + // Env env{*this, envconfig(), features, nullptr, + // beast::severities::kTrace + // }; + + Account const alice{"alice"}; + Account const bob{"bob"}; + env.fund(XRP(10000), alice); + env.fund(XRP(10000), bob); + + TestHook checker_wasm = { + 0x43U, 0x22U, 0x0cU, 0x41U, 0x53U, 0x53U, 0x45U, 0x52U, 0x54U, + 0x18U, 0x44U, 0x4fU, 0x45U, 0x53U, 0x4eU, 0x54U, 0x5fU, 0x45U, + 0x58U, 0x49U, 0x53U, 0x54U, 0x0aU, 0x6eU, 0x61U, 0x6dU, 0x65U, + 0x73U, 0x0aU, 0x74U, 0x6fU, 0x48U, 0x65U, 0x78U, 0x08U, 0x48U, + 0x6fU, 0x6fU, 0x6bU, 0x0cU, 0x70U, 0x61U, 0x72U, 0x61U, 0x6dU, + 0x30U, 0x0cU, 0x70U, 0x61U, 0x72U, 0x61U, 0x6dU, 0x31U, 0x0cU, + 0x70U, 0x61U, 0x72U, 0x61U, 0x6dU, 0x32U, 0x0cU, 0x70U, 0x61U, + 0x72U, 0x61U, 0x6dU, 0x33U, 0x28U, 0x77U, 0x61U, 0x73U, 0x6dU, + 0x6aU, 0x73U, 0x2fU, 0x74U, 0x65U, 0x73U, 0x74U, 0x2dU, 0x36U, + 0x2dU, 0x67U, 0x65U, 0x6eU, 0x2eU, 0x6aU, 0x73U, 0x02U, 0x78U, + 0x08U, 0x63U, 0x6fU, 0x64U, 0x65U, 0x10U, 0x72U, 0x6fU, 0x6cU, + 0x6cU, 0x62U, 0x61U, 0x63U, 0x6bU, 0x06U, 0x73U, 0x74U, 0x72U, + 0x12U, 0x68U, 0x65U, 0x78U, 0x53U, 0x74U, 0x72U, 0x69U, 0x6eU, + 0x67U, 0x02U, 0x69U, 0x14U, 0x63U, 0x68U, 0x61U, 0x72U, 0x43U, + 0x6fU, 0x64U, 0x65U, 0x41U, 0x74U, 0x10U, 0x70U, 0x61U, 0x64U, + 0x53U, 0x74U, 0x61U, 0x72U, 0x74U, 0x16U, 0x74U, 0x6fU, 0x55U, + 0x70U, 0x70U, 0x65U, 0x72U, 0x43U, 0x61U, 0x73U, 0x65U, 0x06U, + 0x61U, 0x72U, 0x67U, 0x06U, 0x62U, 0x75U, 0x66U, 0x14U, 0x68U, + 0x6fU, 0x6fU, 0x6bU, 0x5fU, 0x70U, 0x61U, 0x72U, 0x61U, 0x6dU, + 0x0eU, 0x63U, 0x68U, 0x65U, 0x63U, 0x6bU, 0x65U, 0x72U, 0x0aU, + 0x68U, 0x65U, 0x6cU, 0x6cU, 0x6fU, 0x02U, 0x77U, 0x02U, 0x6fU, + 0x02U, 0x72U, 0x02U, 0x6cU, 0x02U, 0x64U, 0x02U, 0x76U, 0x02U, + 0x61U, 0x02U, 0x75U, 0x02U, 0x65U, 0x0cU, 0x61U, 0x63U, 0x63U, + 0x65U, 0x70U, 0x74U, 0x0cU, 0x00U, 0x06U, 0x00U, 0xa2U, 0x01U, + 0x00U, 0x01U, 0x00U, 0x04U, 0x00U, 0x03U, 0x7bU, 0x01U, 0xa4U, + 0x01U, 0x00U, 0x00U, 0x00U, 0x3fU, 0xe3U, 0x00U, 0x00U, 0x00U, + 0x80U, 0x3fU, 0xe4U, 0x00U, 0x00U, 0x00U, 0x80U, 0x3fU, 0xe5U, + 0x00U, 0x00U, 0x00U, 0x80U, 0x3fU, 0xe6U, 0x00U, 0x00U, 0x00U, + 0x40U, 0x3fU, 0xe7U, 0x00U, 0x00U, 0x00U, 0x80U, 0x3eU, 0xe3U, + 0x00U, 0x00U, 0x00U, 0x80U, 0x3eU, 0xe4U, 0x00U, 0x00U, 0x00U, + 0x80U, 0x3eU, 0xe5U, 0x00U, 0x00U, 0x00U, 0x80U, 0xc2U, 0x01U, + 0x40U, 0xe6U, 0x00U, 0x00U, 0x00U, 0x00U, 0x3eU, 0xe7U, 0x00U, + 0x00U, 0x00U, 0x80U, 0xc2U, 0x00U, 0x4dU, 0xe3U, 0x00U, 0x00U, + 0x00U, 0x3aU, 0xe3U, 0x00U, 0x00U, 0x00U, 0xbfU, 0xfbU, 0x3aU, + 0xe4U, 0x00U, 0x00U, 0x00U, 0x04U, 0xe8U, 0x00U, 0x00U, 0x00U, + 0x04U, 0xe9U, 0x00U, 0x00U, 0x00U, 0x04U, 0xeaU, 0x00U, 0x00U, + 0x00U, 0x04U, 0xebU, 0x00U, 0x00U, 0x00U, 0x26U, 0x04U, 0x00U, + 0x3aU, 0xe5U, 0x00U, 0x00U, 0x00U, 0xc2U, 0x02U, 0x4dU, 0xe7U, + 0x00U, 0x00U, 0x00U, 0x3aU, 0xe7U, 0x00U, 0x00U, 0x00U, 0xc7U, + 0x28U, 0xd8U, 0x03U, 0x01U, 0x09U, 0x97U, 0x00U, 0x20U, 0x0cU, + 0x40U, 0x27U, 0x00U, 0x1cU, 0x4eU, 0x0cU, 0x02U, 0x06U, 0x00U, + 0x00U, 0x02U, 0x00U, 0x02U, 0x03U, 0x00U, 0x00U, 0x16U, 0x02U, + 0xdaU, 0x03U, 0x00U, 0x01U, 0x00U, 0xdcU, 0x03U, 0x00U, 0x01U, + 0x00U, 0xd3U, 0x97U, 0xecU, 0x12U, 0x38U, 0xefU, 0x00U, 0x00U, + 0x00U, 0xd3U, 0x42U, 0x38U, 0x00U, 0x00U, 0x00U, 0x24U, 0x00U, + 0x00U, 0xd4U, 0xf2U, 0x0eU, 0x29U, 0xd8U, 0x03U, 0x02U, 0x03U, + 0x03U, 0x17U, 0x59U, 0x0cU, 0x43U, 0x06U, 0x00U, 0xccU, 0x03U, + 0x01U, 0x02U, 0x01U, 0x05U, 0x00U, 0x01U, 0x51U, 0x03U, 0xe0U, + 0x03U, 0x00U, 0x01U, 0x00U, 0xe2U, 0x03U, 0x01U, 0x00U, 0x20U, + 0xe4U, 0x03U, 0x02U, 0x01U, 0x20U, 0x61U, 0x00U, 0x00U, 0xc3U, + 0xcbU, 0x61U, 0x01U, 0x00U, 0xb7U, 0xccU, 0x62U, 0x01U, 0x00U, + 0xd3U, 0xebU, 0xa4U, 0xecU, 0x35U, 0x62U, 0x00U, 0x00U, 0xd3U, + 0x42U, 0xf3U, 0x00U, 0x00U, 0x00U, 0x62U, 0x01U, 0x00U, 0x24U, + 0x01U, 0x00U, 0x42U, 0x38U, 0x00U, 0x00U, 0x00U, 0xbfU, 0x10U, + 0x24U, 0x01U, 0x00U, 0x42U, 0xf4U, 0x00U, 0x00U, 0x00U, 0xb9U, + 0xc1U, 0x00U, 0x24U, 0x02U, 0x00U, 0x9eU, 0x11U, 0x63U, 0x00U, + 0x00U, 0x0eU, 0x62U, 0x01U, 0x00U, 0x92U, 0x63U, 0x01U, 0x00U, + 0x0eU, 0xeeU, 0xc5U, 0x62U, 0x00U, 0x00U, 0x42U, 0xf5U, 0x00U, + 0x00U, 0x00U, 0x25U, 0x00U, 0x00U, 0xd8U, 0x03U, 0x0cU, 0x05U, + 0x12U, 0x0dU, 0x44U, 0xd5U, 0x35U, 0x07U, 0x02U, 0x30U, 0x0cU, + 0x02U, 0x06U, 0x00U, 0x00U, 0x01U, 0x02U, 0x01U, 0x04U, 0x00U, + 0x01U, 0xb8U, 0x02U, 0x03U, 0xecU, 0x03U, 0x00U, 0x01U, 0x00U, + 0xeeU, 0x03U, 0x01U, 0x00U, 0x20U, 0xe4U, 0x03U, 0x02U, 0x01U, + 0x20U, 0x61U, 0x00U, 0x00U, 0x38U, 0xe3U, 0x00U, 0x00U, 0x00U, + 0x38U, 0xf8U, 0x00U, 0x00U, 0x00U, 0x38U, 0xe6U, 0x00U, 0x00U, + 0x00U, 0x04U, 0xf9U, 0x00U, 0x00U, 0x00U, 0xf1U, 0xf1U, 0x38U, + 0xe4U, 0x00U, 0x00U, 0x00U, 0xaaU, 0xf1U, 0x0eU, 0x38U, 0xf8U, + 0x00U, 0x00U, 0x00U, 0x38U, 0xe6U, 0x00U, 0x00U, 0x00U, 0x04U, + 0xfaU, 0x00U, 0x00U, 0x00U, 0xf1U, 0xf1U, 0xcbU, 0x38U, 0xe3U, + 0x00U, 0x00U, 0x00U, 0x62U, 0x00U, 0x00U, 0xebU, 0xbcU, 0xacU, + 0xf1U, 0x0eU, 0x38U, 0xe3U, 0x00U, 0x00U, 0x00U, 0x62U, 0x00U, + 0x00U, 0xb7U, 0x47U, 0x04U, 0xfbU, 0x00U, 0x00U, 0x00U, 0xaaU, + 0x11U, 0xecU, 0x3aU, 0x0eU, 0x62U, 0x00U, 0x00U, 0xb8U, 0x47U, + 0x04U, 0xfcU, 0x00U, 0x00U, 0x00U, 0xaaU, 0x11U, 0xecU, 0x2bU, + 0x0eU, 0x62U, 0x00U, 0x00U, 0xb9U, 0x47U, 0x04U, 0xfdU, 0x00U, + 0x00U, 0x00U, 0xaaU, 0x11U, 0xecU, 0x1cU, 0x0eU, 0x62U, 0x00U, + 0x00U, 0xbaU, 0x47U, 0x04U, 0xfeU, 0x00U, 0x00U, 0x00U, 0xaaU, + 0x11U, 0xecU, 0x0dU, 0x0eU, 0x62U, 0x00U, 0x00U, 0xbbU, 0x47U, + 0x04U, 0xffU, 0x00U, 0x00U, 0x00U, 0xaaU, 0xf1U, 0x0eU, 0x61U, + 0x01U, 0x00U, 0xb7U, 0xccU, 0x62U, 0x01U, 0x00U, 0xbbU, 0xa4U, + 0x6aU, 0x95U, 0x00U, 0x00U, 0x00U, 0x38U, 0xf8U, 0x00U, 0x00U, + 0x00U, 0x38U, 0xe6U, 0x00U, 0x00U, 0x00U, 0x38U, 0xe5U, 0x00U, + 0x00U, 0x00U, 0x62U, 0x01U, 0x00U, 0x47U, 0xf1U, 0xf1U, 0x11U, + 0x63U, 0x00U, 0x00U, 0x0eU, 0x38U, 0xe3U, 0x00U, 0x00U, 0x00U, + 0x62U, 0x00U, 0x00U, 0xebU, 0xbdU, 0xaaU, 0xf1U, 0x0eU, 0x38U, + 0xe3U, 0x00U, 0x00U, 0x00U, 0x62U, 0x00U, 0x00U, 0xb7U, 0x47U, + 0x04U, 0x00U, 0x01U, 0x00U, 0x00U, 0xaaU, 0x11U, 0xecU, 0x4aU, + 0x0eU, 0x62U, 0x00U, 0x00U, 0xb8U, 0x47U, 0x04U, 0x01U, 0x01U, + 0x00U, 0x00U, 0xaaU, 0x11U, 0xecU, 0x3bU, 0x0eU, 0x62U, 0x00U, + 0x00U, 0xb9U, 0x47U, 0x04U, 0xfeU, 0x00U, 0x00U, 0x00U, 0xaaU, + 0x11U, 0xecU, 0x2cU, 0x0eU, 0x62U, 0x00U, 0x00U, 0xbaU, 0x47U, + 0x04U, 0x02U, 0x01U, 0x00U, 0x00U, 0xaaU, 0x11U, 0xecU, 0x1dU, + 0x0eU, 0x62U, 0x00U, 0x00U, 0xbbU, 0x47U, 0x04U, 0x03U, 0x01U, + 0x00U, 0x00U, 0xaaU, 0x11U, 0xecU, 0x0eU, 0x0eU, 0x62U, 0x00U, + 0x00U, 0xbcU, 0x47U, 0xc1U, 0x00U, 0x62U, 0x01U, 0x00U, 0x9eU, + 0xaaU, 0xf1U, 0x0eU, 0x62U, 0x01U, 0x00U, 0x90U, 0x11U, 0x63U, + 0x01U, 0x00U, 0x0eU, 0xefU, 0x67U, 0xffU, 0x38U, 0x04U, 0x01U, + 0x00U, 0x00U, 0xc3U, 0xb7U, 0x23U, 0x02U, 0x00U, 0xd8U, 0x03U, + 0x14U, 0x17U, 0x12U, 0x9bU, 0x5dU, 0x44U, 0x1cU, 0x4eU, 0x4eU, + 0x4eU, 0x4eU, 0x3aU, 0x0fU, 0x4eU, 0x85U, 0x44U, 0x1cU, 0x4eU, + 0x4eU, 0x4eU, 0x4eU, 0x4eU, 0x3fU, 0x0dU, 0x40U, 0x07U, 0x02U, + 0x30U}; + // TestHook checker_wasm = jswasm[R"[test.hook]( + // const ASSERT = (x, code) => { + // if (!x) { + // rollback(x.toString(), code) + // } + // } + + // const DOESNT_EXIST = -5 + + // const names = ['param0', 'param1', 'param2', 'param3'] + + // function toHex(str) { + // let hexString = '' + // for (let i = 0; i < str.length; i++) { + // hexString += str.charCodeAt(i).toString(16).padStart(2, '0') + // } + // return hexString.toUpperCase() + // } + + // const Hook = (arg) => { + // ASSERT(hook_param(toHex('checker')) == DOESNT_EXIST) + + // // this entry should havebeen added by the setter + // let buf = hook_param(toHex('hello')) + // ASSERT(buf.length === 5) + // ASSERT( + // buf[0] == 'w' && + // buf[1] == 'o' && + // buf[2] == 'r' && + // buf[3] == 'l' && + // buf[4] == 'd' + // ) + + // // these pre-existing entries should be modified by the setter + // for (let i = 0; i < 4; ++i) { + // buf = hook_param(toHex(names[i])) + // ASSERT(buf.length == 6) + // ASSERT( + // buf[0] == 'v' && + // buf[1] == 'a' && + // buf[2] == 'l' && + // buf[3] == 'u' && + // buf[4] == 'e' && + // buf[5] == '0' + i + // ) + // } + + // return accept('', 0) + // } + // )[test.hook]"]; + + TestHook setter_wasm = { + 0x43U, 0x24U, 0x0cU, 0x41U, 0x53U, 0x53U, 0x45U, 0x52U, 0x54U, + 0x0aU, 0x74U, 0x6fU, 0x48U, 0x65U, 0x78U, 0x0aU, 0x6eU, 0x61U, + 0x6dU, 0x65U, 0x73U, 0x08U, 0x48U, 0x6fU, 0x6fU, 0x6bU, 0x0cU, + 0x70U, 0x61U, 0x72U, 0x61U, 0x6dU, 0x30U, 0x0cU, 0x70U, 0x61U, + 0x72U, 0x61U, 0x6dU, 0x31U, 0x0cU, 0x70U, 0x61U, 0x72U, 0x61U, + 0x6dU, 0x32U, 0x0cU, 0x70U, 0x61U, 0x72U, 0x61U, 0x6dU, 0x33U, + 0x0cU, 0x76U, 0x61U, 0x6cU, 0x75U, 0x65U, 0x30U, 0x0cU, 0x76U, + 0x61U, 0x6cU, 0x75U, 0x65U, 0x31U, 0x0cU, 0x76U, 0x61U, 0x6cU, + 0x75U, 0x65U, 0x32U, 0x0cU, 0x76U, 0x61U, 0x6cU, 0x75U, 0x65U, + 0x33U, 0x28U, 0x77U, 0x61U, 0x73U, 0x6dU, 0x6aU, 0x73U, 0x2fU, + 0x74U, 0x65U, 0x73U, 0x74U, 0x2dU, 0x37U, 0x2dU, 0x67U, 0x65U, + 0x6eU, 0x2eU, 0x6aU, 0x73U, 0x02U, 0x78U, 0x08U, 0x63U, 0x6fU, + 0x64U, 0x65U, 0x10U, 0x72U, 0x6fU, 0x6cU, 0x6cU, 0x62U, 0x61U, + 0x63U, 0x6bU, 0x06U, 0x73U, 0x74U, 0x72U, 0x12U, 0x68U, 0x65U, + 0x78U, 0x53U, 0x74U, 0x72U, 0x69U, 0x6eU, 0x67U, 0x02U, 0x69U, + 0x14U, 0x63U, 0x68U, 0x61U, 0x72U, 0x43U, 0x6fU, 0x64U, 0x65U, + 0x41U, 0x74U, 0x10U, 0x70U, 0x61U, 0x64U, 0x53U, 0x74U, 0x61U, + 0x72U, 0x74U, 0x16U, 0x74U, 0x6fU, 0x55U, 0x70U, 0x70U, 0x65U, + 0x72U, 0x43U, 0x61U, 0x73U, 0x65U, 0x06U, 0x61U, 0x72U, 0x67U, + 0x18U, 0x63U, 0x68U, 0x65U, 0x63U, 0x6bU, 0x65U, 0x72U, 0x5fU, + 0x68U, 0x61U, 0x73U, 0x68U, 0x06U, 0x62U, 0x75U, 0x66U, 0x14U, + 0x68U, 0x6fU, 0x6fU, 0x6bU, 0x5fU, 0x70U, 0x61U, 0x72U, 0x61U, + 0x6dU, 0x0eU, 0x63U, 0x68U, 0x65U, 0x63U, 0x6bU, 0x65U, 0x72U, + 0x1cU, 0x68U, 0x6fU, 0x6fU, 0x6bU, 0x5fU, 0x70U, 0x61U, 0x72U, + 0x61U, 0x6dU, 0x5fU, 0x73U, 0x65U, 0x74U, 0x0aU, 0x77U, 0x6fU, + 0x72U, 0x6cU, 0x64U, 0x0aU, 0x68U, 0x65U, 0x6cU, 0x6cU, 0x6fU, + 0x02U, 0x76U, 0x02U, 0x61U, 0x02U, 0x6cU, 0x02U, 0x75U, 0x02U, + 0x65U, 0x0cU, 0x61U, 0x63U, 0x63U, 0x65U, 0x70U, 0x74U, 0x0cU, + 0x00U, 0x06U, 0x00U, 0xa2U, 0x01U, 0x00U, 0x01U, 0x00U, 0x04U, + 0x00U, 0x03U, 0x90U, 0x01U, 0x01U, 0xa4U, 0x01U, 0x00U, 0x00U, + 0x00U, 0x3fU, 0xe3U, 0x00U, 0x00U, 0x00U, 0x80U, 0x3fU, 0xe4U, + 0x00U, 0x00U, 0x00U, 0x40U, 0x3fU, 0xe5U, 0x00U, 0x00U, 0x00U, + 0x80U, 0x3fU, 0x6cU, 0x00U, 0x00U, 0x00U, 0x80U, 0x3fU, 0xe6U, + 0x00U, 0x00U, 0x00U, 0x80U, 0x3eU, 0xe3U, 0x00U, 0x00U, 0x00U, + 0x80U, 0xc2U, 0x01U, 0x40U, 0xe4U, 0x00U, 0x00U, 0x00U, 0x00U, + 0x3eU, 0xe5U, 0x00U, 0x00U, 0x00U, 0x80U, 0x3eU, 0x6cU, 0x00U, + 0x00U, 0x00U, 0x80U, 0x3eU, 0xe6U, 0x00U, 0x00U, 0x00U, 0x80U, + 0xc2U, 0x00U, 0x4dU, 0xe3U, 0x00U, 0x00U, 0x00U, 0x3aU, 0xe3U, + 0x00U, 0x00U, 0x00U, 0x04U, 0xe7U, 0x00U, 0x00U, 0x00U, 0x04U, + 0xe8U, 0x00U, 0x00U, 0x00U, 0x04U, 0xe9U, 0x00U, 0x00U, 0x00U, + 0x04U, 0xeaU, 0x00U, 0x00U, 0x00U, 0x26U, 0x04U, 0x00U, 0x3aU, + 0xe5U, 0x00U, 0x00U, 0x00U, 0x04U, 0xebU, 0x00U, 0x00U, 0x00U, + 0x04U, 0xecU, 0x00U, 0x00U, 0x00U, 0x04U, 0xedU, 0x00U, 0x00U, + 0x00U, 0x04U, 0xeeU, 0x00U, 0x00U, 0x00U, 0x26U, 0x04U, 0x00U, + 0x3aU, 0x6cU, 0x00U, 0x00U, 0x00U, 0xc2U, 0x02U, 0x4dU, 0xe6U, + 0x00U, 0x00U, 0x00U, 0x3aU, 0xe6U, 0x00U, 0x00U, 0x00U, 0xc7U, + 0x28U, 0xdeU, 0x03U, 0x01U, 0x0bU, 0x97U, 0x00U, 0x20U, 0x0cU, + 0x00U, 0x0cU, 0x14U, 0x8fU, 0x00U, 0x1cU, 0x46U, 0x0cU, 0x02U, + 0x06U, 0x00U, 0x00U, 0x02U, 0x00U, 0x02U, 0x03U, 0x00U, 0x00U, + 0x16U, 0x02U, 0xe0U, 0x03U, 0x00U, 0x01U, 0x00U, 0xe2U, 0x03U, + 0x00U, 0x01U, 0x00U, 0xd3U, 0x97U, 0xecU, 0x12U, 0x38U, 0xf2U, + 0x00U, 0x00U, 0x00U, 0xd3U, 0x42U, 0x38U, 0x00U, 0x00U, 0x00U, + 0x24U, 0x00U, 0x00U, 0xd4U, 0xf2U, 0x0eU, 0x29U, 0xdeU, 0x03U, + 0x02U, 0x03U, 0x03U, 0x17U, 0x59U, 0x0cU, 0x43U, 0x06U, 0x00U, + 0xc8U, 0x03U, 0x01U, 0x02U, 0x01U, 0x05U, 0x00U, 0x01U, 0x51U, + 0x03U, 0xe6U, 0x03U, 0x00U, 0x01U, 0x00U, 0xe8U, 0x03U, 0x01U, + 0x00U, 0x20U, 0xeaU, 0x03U, 0x02U, 0x01U, 0x20U, 0x61U, 0x00U, + 0x00U, 0xc3U, 0xcbU, 0x61U, 0x01U, 0x00U, 0xb7U, 0xccU, 0x62U, + 0x01U, 0x00U, 0xd3U, 0xebU, 0xa4U, 0xecU, 0x35U, 0x62U, 0x00U, + 0x00U, 0xd3U, 0x42U, 0xf6U, 0x00U, 0x00U, 0x00U, 0x62U, 0x01U, + 0x00U, 0x24U, 0x01U, 0x00U, 0x42U, 0x38U, 0x00U, 0x00U, 0x00U, + 0xbfU, 0x10U, 0x24U, 0x01U, 0x00U, 0x42U, 0xf7U, 0x00U, 0x00U, + 0x00U, 0xb9U, 0xc1U, 0x00U, 0x24U, 0x02U, 0x00U, 0x9eU, 0x11U, + 0x63U, 0x00U, 0x00U, 0x0eU, 0x62U, 0x01U, 0x00U, 0x92U, 0x63U, + 0x01U, 0x00U, 0x0eU, 0xeeU, 0xc5U, 0x62U, 0x00U, 0x00U, 0x42U, + 0xf8U, 0x00U, 0x00U, 0x00U, 0x25U, 0x00U, 0x00U, 0xdeU, 0x03U, + 0x08U, 0x05U, 0x12U, 0x0dU, 0x44U, 0xd5U, 0x35U, 0x07U, 0x02U, + 0x30U, 0x0cU, 0x02U, 0x06U, 0x00U, 0x00U, 0x01U, 0x04U, 0x01U, + 0x06U, 0x00U, 0x01U, 0xd6U, 0x02U, 0x05U, 0xf2U, 0x03U, 0x00U, + 0x01U, 0x00U, 0xf4U, 0x03U, 0x01U, 0x00U, 0x30U, 0xeaU, 0x03U, + 0x02U, 0x01U, 0x20U, 0xeaU, 0x03U, 0x04U, 0x01U, 0x20U, 0xf6U, + 0x03U, 0x05U, 0x03U, 0x30U, 0x61U, 0x00U, 0x00U, 0x38U, 0xfcU, + 0x00U, 0x00U, 0x00U, 0x38U, 0xe4U, 0x00U, 0x00U, 0x00U, 0x04U, + 0xfdU, 0x00U, 0x00U, 0x00U, 0xf1U, 0xf1U, 0xcbU, 0x38U, 0xe3U, + 0x00U, 0x00U, 0x00U, 0x62U, 0x00U, 0x00U, 0xebU, 0xbfU, 0x20U, + 0xacU, 0xf1U, 0x0eU, 0x61U, 0x01U, 0x00U, 0xb7U, 0xccU, 0x62U, + 0x01U, 0x00U, 0xbbU, 0xa4U, 0xecU, 0x3dU, 0x38U, 0xe3U, 0x00U, + 0x00U, 0x00U, 0x38U, 0xfeU, 0x00U, 0x00U, 0x00U, 0x38U, 0xe4U, + 0x00U, 0x00U, 0x00U, 0x38U, 0x6cU, 0x00U, 0x00U, 0x00U, 0x62U, + 0x01U, 0x00U, 0x47U, 0xf1U, 0x38U, 0xe4U, 0x00U, 0x00U, 0x00U, + 0x38U, 0xe5U, 0x00U, 0x00U, 0x00U, 0x62U, 0x01U, 0x00U, 0x47U, + 0xf1U, 0x62U, 0x00U, 0x00U, 0xf3U, 0xebU, 0xbdU, 0xaaU, 0xf1U, + 0x0eU, 0x62U, 0x01U, 0x00U, 0x90U, 0x11U, 0x63U, 0x01U, 0x00U, + 0x0eU, 0xeeU, 0xbeU, 0x38U, 0xe3U, 0x00U, 0x00U, 0x00U, 0x38U, + 0xfeU, 0x00U, 0x00U, 0x00U, 0xc3U, 0x38U, 0xe4U, 0x00U, 0x00U, + 0x00U, 0x04U, 0xfdU, 0x00U, 0x00U, 0x00U, 0xf1U, 0x62U, 0x00U, + 0x00U, 0xf3U, 0xb7U, 0xaaU, 0xf1U, 0x0eU, 0x38U, 0xe3U, 0x00U, + 0x00U, 0x00U, 0x38U, 0xfeU, 0x00U, 0x00U, 0x00U, 0x38U, 0xe4U, + 0x00U, 0x00U, 0x00U, 0x04U, 0xffU, 0x00U, 0x00U, 0x00U, 0xf1U, + 0x38U, 0xe4U, 0x00U, 0x00U, 0x00U, 0x04U, 0x00U, 0x01U, 0x00U, + 0x00U, 0xf1U, 0x62U, 0x00U, 0x00U, 0xf3U, 0xbcU, 0xaaU, 0xf1U, + 0x0eU, 0x61U, 0x02U, 0x00U, 0xb7U, 0xcdU, 0x62U, 0x02U, 0x00U, + 0xbbU, 0xa4U, 0x6aU, 0x90U, 0x00U, 0x00U, 0x00U, 0x61U, 0x03U, + 0x00U, 0x38U, 0xfcU, 0x00U, 0x00U, 0x00U, 0x38U, 0xe4U, 0x00U, + 0x00U, 0x00U, 0x38U, 0xe5U, 0x00U, 0x00U, 0x00U, 0x62U, 0x02U, + 0x00U, 0x47U, 0xf1U, 0xf1U, 0xceU, 0x38U, 0xe3U, 0x00U, 0x00U, + 0x00U, 0x62U, 0x03U, 0x00U, 0xebU, 0xbdU, 0xaaU, 0xf1U, 0x0eU, + 0x38U, 0xe3U, 0x00U, 0x00U, 0x00U, 0x62U, 0x03U, 0x00U, 0xb7U, + 0x47U, 0x04U, 0x01U, 0x01U, 0x00U, 0x00U, 0xaaU, 0x11U, 0xecU, + 0x46U, 0x0eU, 0x62U, 0x03U, 0x00U, 0xb8U, 0x47U, 0x04U, 0x02U, + 0x01U, 0x00U, 0x00U, 0xaaU, 0x11U, 0xecU, 0x37U, 0x0eU, 0x62U, + 0x03U, 0x00U, 0xb9U, 0x47U, 0x04U, 0x03U, 0x01U, 0x00U, 0x00U, + 0xaaU, 0x11U, 0xecU, 0x28U, 0x0eU, 0x62U, 0x03U, 0x00U, 0xbaU, + 0x47U, 0x04U, 0x04U, 0x01U, 0x00U, 0x00U, 0xaaU, 0x11U, 0xecU, + 0x19U, 0x0eU, 0x62U, 0x03U, 0x00U, 0xbbU, 0x47U, 0x04U, 0x05U, + 0x01U, 0x00U, 0x00U, 0xaaU, 0x11U, 0xecU, 0x0aU, 0x0eU, 0x62U, + 0x03U, 0x00U, 0xbcU, 0x47U, 0xc1U, 0x00U, 0xaaU, 0xf1U, 0x0eU, + 0x62U, 0x02U, 0x00U, 0x90U, 0x11U, 0x63U, 0x02U, 0x00U, 0x0eU, + 0xefU, 0x6cU, 0xffU, 0x38U, 0x06U, 0x01U, 0x00U, 0x00U, 0xc3U, + 0xb7U, 0x23U, 0x02U, 0x00U, 0xdeU, 0x03U, 0x13U, 0x17U, 0x12U, + 0x5dU, 0x4aU, 0x3fU, 0x1cU, 0xd0U, 0x08U, 0x0dU, 0x3cU, 0x9bU, + 0xcdU, 0x5dU, 0x71U, 0x45U, 0x1cU, 0x4eU, 0x4eU, 0x4eU, 0x4eU, + 0x4eU, 0x2bU, 0x0dU, 0x40U, 0x07U, 0x02U, 0x30U}; + // TestHook setter_wasm = jswasm[R"[test.hook]( + // const ASSERT = (x, code) => { + // if (!x) { + // rollback(x.toString(), code) + // } + // } + + // function toHex(str) { + // let hexString = '' + // for (let i = 0; i < str.length; i++) { + // hexString += str.charCodeAt(i).toString(16).padStart(2, '0') + // } + // return hexString.toUpperCase() + // } + + // const names = ['param0', 'param1', 'param2', 'param3'] + // const values = ['value0', 'value1', 'value2', 'value3'] + + // const Hook = (arg) => { + // const checker_hash = hook_param(toHex('checker')) + // ASSERT(checker_hash.length === 32) + + // for (let i = 0; i < 4; ++i) { + // ASSERT( + // hook_param_set(toHex(values[i]), toHex(names[i]), checker_hash).length == + // 6 + // ) + // } + + // // "delete" the checker entry" for when the checker runs + // ASSERT(hook_param_set('', toHex('checker'), checker_hash) == 0) + + // // add a parameter that did not previously exist + // ASSERT(hook_param_set(toHex('world'), toHex('hello'), checker_hash) == 5) + + // // ensure this hook's parameters did not change + // for (let i = 0; i < 4; ++i) { + // const buf = hook_param(toHex(names[i])) + // ASSERT(buf.length == 6) + + // ASSERT( + // buf[0] == 'v' && + // buf[1] == 'a' && + // buf[2] == 'l' && + // buf[3] == 'u' && + // buf[4] == 'e' && + // buf[5] == '0' + // ) + // } + + // return accept('', 0) + // } + // )[test.hook]"]; + + HASH_WASM(checker); + + Json::Value jv; + jv[jss::Account] = alice.human(); + jv[jss::TransactionType] = jss::SetHook; + jv[jss::Flags] = 0; + jv[jss::Hooks] = Json::Value{Json::arrayValue}; + + Json::Value iv; + iv[jss::CreateCode] = strHex(setter_wasm); + iv[jss::HookOn] = + "0000000000000000000000000000000000000000000000000000000000000000"; + iv[jss::HookApiVersion] = 1U; + iv[jss::HookNamespace] = to_string(uint256{beast::zero}); + + Json::Value checkerpv; + { + Json::Value piv; + piv[jss::HookParameterName] = strHex(std::string("checker")); + piv[jss::HookParameterValue] = checker_hash_str; + checkerpv[jss::HookParameter] = piv; + } + + Json::Value params{Json::arrayValue}; + for (uint32_t i = 0; i < 4; ++i) + { + Json::Value pv; + Json::Value piv; + piv[jss::HookParameterName] = strHex("param" + std::to_string(i)); + piv[jss::HookParameterValue] = strHex(std::string("value0")); + pv[jss::HookParameter] = piv; + params[i] = pv; + } + params[4U] = checkerpv; + + iv[jss::HookParameters] = params; + jv[jss::Hooks][0U][jss::Hook] = iv; + + { + iv[jss::CreateCode] = strHex(checker_wasm); + Json::Value params{Json::arrayValue}; + params[0U] = checkerpv; + iv[jss::HookParameters] = params; + jv[jss::Hooks][3U][jss::Hook] = iv; + jv[jss::Hooks][1U][jss::Hook] = Json::objectValue; + jv[jss::Hooks][2U][jss::Hook] = Json::objectValue; + } + + env(jv, M("set hook_param_set"), HSFEE, ter(tesSUCCESS)); + env.close(); + + // invoke + env(pay(bob, alice, XRP(1)), M("test hook_param_set"), fee(XRP(1))); + env.close(); + } + + void + test_hook_pos(FeatureBitset features) + { + testcase("Test hook_pos"); + using namespace jtx; + Env env{*this, features}; + + Account const alice{"alice"}; + Account const bob{"bob"}; + env.fund(XRP(10000), alice); + env.fund(XRP(10000), bob); + + TestHook hook = { + 0x43U, 0x05U, 0x08U, 0x48U, 0x6fU, 0x6fU, 0x6bU, 0x28U, 0x77U, + 0x61U, 0x73U, 0x6dU, 0x6aU, 0x73U, 0x2fU, 0x74U, 0x65U, 0x73U, + 0x74U, 0x2dU, 0x38U, 0x2dU, 0x67U, 0x65U, 0x6eU, 0x2eU, 0x6aU, + 0x73U, 0x06U, 0x61U, 0x72U, 0x67U, 0x0cU, 0x61U, 0x63U, 0x63U, + 0x65U, 0x70U, 0x74U, 0x10U, 0x68U, 0x6fU, 0x6fU, 0x6bU, 0x5fU, + 0x70U, 0x6fU, 0x73U, 0x0cU, 0x00U, 0x06U, 0x00U, 0xa2U, 0x01U, + 0x00U, 0x01U, 0x00U, 0x01U, 0x00U, 0x01U, 0x1aU, 0x01U, 0xa4U, + 0x01U, 0x00U, 0x00U, 0x00U, 0x3fU, 0xe3U, 0x00U, 0x00U, 0x00U, + 0x80U, 0x3eU, 0xe3U, 0x00U, 0x00U, 0x00U, 0x80U, 0xc2U, 0x00U, + 0x4dU, 0xe3U, 0x00U, 0x00U, 0x00U, 0x3aU, 0xe3U, 0x00U, 0x00U, + 0x00U, 0xc7U, 0x28U, 0xc8U, 0x03U, 0x01U, 0x04U, 0x1fU, 0x00U, + 0x06U, 0x08U, 0x0cU, 0x02U, 0x06U, 0x00U, 0x00U, 0x01U, 0x00U, + 0x01U, 0x03U, 0x00U, 0x00U, 0x0fU, 0x01U, 0xcaU, 0x03U, 0x00U, + 0x01U, 0x00U, 0x38U, 0xe6U, 0x00U, 0x00U, 0x00U, 0xc3U, 0x38U, + 0xe7U, 0x00U, 0x00U, 0x00U, 0xf0U, 0x23U, 0x02U, 0x00U, 0xc8U, + 0x03U, 0x02U, 0x01U, 0x03U}; + // TestHook hook = jswasm[R"[test.hook]( + // const Hook = (arg) => { + // return accept('', hook_pos()) + // } + // )[test.hook]"]; + + // install the hook on alice in all four spots + env(ripple::test::jtx::hook( + alice, {{hsov1(hook, 1), hsov1(hook, 1), hsov1(hook, 1), hsov1(hook, 1)}}, 0), + M("set hook_pos"), + HSFEE, + ter(tesSUCCESS)); + env.close(); + + // invoke the hooks + env(pay(bob, alice, XRP(1)), M("test hook_pos"), fee(XRP(1))); + env.close(); + + auto meta = env.meta(); + + // ensure hook execution occured + BEAST_REQUIRE(meta); + BEAST_REQUIRE(meta->isFieldPresent(sfHookExecutions)); + + // ensure there was four hook executions + auto const hookExecutions = meta->getFieldArray(sfHookExecutions); + BEAST_REQUIRE(hookExecutions.size() == 4); + + // get the data in the return code of the execution + BEAST_EXPECT(hookExecutions[0].getFieldU64(sfHookReturnCode) == 0); + BEAST_EXPECT(hookExecutions[1].getFieldU64(sfHookReturnCode) == 1); + BEAST_EXPECT(hookExecutions[2].getFieldU64(sfHookReturnCode) == 2); + BEAST_EXPECT(hookExecutions[3].getFieldU64(sfHookReturnCode) == 3); + } + + void + test_hook_skip(FeatureBitset features) + { + testcase("Test hook_skip"); + using namespace jtx; + Env env{*this, features}; + + Account const alice{"alice"}; + Account const bob{"bob"}; + env.fund(XRP(10000), alice); + env.fund(XRP(10000), bob); + + TestHook skip_wasm = { + 0x43U, 0x11U, 0x0cU, 0x41U, 0x53U, 0x53U, 0x45U, 0x52U, 0x54U, + 0x18U, 0x44U, 0x4fU, 0x45U, 0x53U, 0x4eU, 0x54U, 0x5fU, 0x45U, + 0x58U, 0x49U, 0x53U, 0x54U, 0x20U, 0x49U, 0x4eU, 0x56U, 0x41U, + 0x4cU, 0x49U, 0x44U, 0x5fU, 0x41U, 0x52U, 0x47U, 0x55U, 0x4dU, + 0x45U, 0x4eU, 0x54U, 0x16U, 0x73U, 0x66U, 0x49U, 0x6eU, 0x76U, + 0x6fU, 0x69U, 0x63U, 0x65U, 0x49U, 0x44U, 0x08U, 0x48U, 0x6fU, + 0x6fU, 0x6bU, 0x28U, 0x77U, 0x61U, 0x73U, 0x6dU, 0x6aU, 0x73U, + 0x2fU, 0x74U, 0x65U, 0x73U, 0x74U, 0x2dU, 0x39U, 0x2dU, 0x67U, + 0x65U, 0x6eU, 0x2eU, 0x6aU, 0x73U, 0x02U, 0x78U, 0x08U, 0x63U, + 0x6fU, 0x64U, 0x65U, 0x10U, 0x72U, 0x6fU, 0x6cU, 0x6cU, 0x62U, + 0x61U, 0x63U, 0x6bU, 0x06U, 0x61U, 0x72U, 0x67U, 0x08U, 0x73U, + 0x6bU, 0x69U, 0x70U, 0x08U, 0x68U, 0x61U, 0x73U, 0x68U, 0x12U, + 0x68U, 0x6fU, 0x6fU, 0x6bU, 0x5fU, 0x73U, 0x6bU, 0x69U, 0x70U, + 0x14U, 0x6fU, 0x74U, 0x78U, 0x6eU, 0x5fU, 0x66U, 0x69U, 0x65U, + 0x6cU, 0x64U, 0x12U, 0x68U, 0x6fU, 0x6fU, 0x6bU, 0x5fU, 0x68U, + 0x61U, 0x73U, 0x68U, 0x10U, 0x68U, 0x6fU, 0x6fU, 0x6bU, 0x5fU, + 0x70U, 0x6fU, 0x73U, 0x0cU, 0x61U, 0x63U, 0x63U, 0x65U, 0x70U, + 0x74U, 0x0cU, 0x00U, 0x06U, 0x00U, 0xa2U, 0x01U, 0x00U, 0x01U, + 0x00U, 0x01U, 0x00U, 0x02U, 0x6eU, 0x01U, 0xa4U, 0x01U, 0x00U, + 0x00U, 0x00U, 0x3fU, 0xe3U, 0x00U, 0x00U, 0x00U, 0x80U, 0x3fU, + 0xe4U, 0x00U, 0x00U, 0x00U, 0x80U, 0x3fU, 0xe5U, 0x00U, 0x00U, + 0x00U, 0x80U, 0x3fU, 0xe6U, 0x00U, 0x00U, 0x00U, 0x80U, 0x3fU, + 0xe7U, 0x00U, 0x00U, 0x00U, 0x80U, 0x3eU, 0xe3U, 0x00U, 0x00U, + 0x00U, 0x80U, 0x3eU, 0xe4U, 0x00U, 0x00U, 0x00U, 0x80U, 0x3eU, + 0xe5U, 0x00U, 0x00U, 0x00U, 0x80U, 0x3eU, 0xe6U, 0x00U, 0x00U, + 0x00U, 0x80U, 0x3eU, 0xe7U, 0x00U, 0x00U, 0x00U, 0x80U, 0xc2U, + 0x00U, 0x4dU, 0xe3U, 0x00U, 0x00U, 0x00U, 0x3aU, 0xe3U, 0x00U, + 0x00U, 0x00U, 0xbfU, 0xfbU, 0x3aU, 0xe4U, 0x00U, 0x00U, 0x00U, + 0xbfU, 0xf9U, 0x3aU, 0xe5U, 0x00U, 0x00U, 0x00U, 0x01U, 0x11U, + 0x00U, 0x05U, 0x00U, 0x3aU, 0xe6U, 0x00U, 0x00U, 0x00U, 0xc2U, + 0x01U, 0x4dU, 0xe7U, 0x00U, 0x00U, 0x00U, 0x3aU, 0xe7U, 0x00U, + 0x00U, 0x00U, 0xc7U, 0x28U, 0xd0U, 0x03U, 0x01U, 0x0aU, 0x97U, + 0x00U, 0x1eU, 0x0cU, 0x40U, 0x26U, 0x26U, 0x00U, 0x0aU, 0x36U, + 0x0cU, 0x02U, 0x06U, 0x00U, 0x00U, 0x02U, 0x00U, 0x02U, 0x03U, + 0x00U, 0x00U, 0x16U, 0x02U, 0xd2U, 0x03U, 0x00U, 0x01U, 0x00U, + 0xd4U, 0x03U, 0x00U, 0x01U, 0x00U, 0xd3U, 0x97U, 0xecU, 0x12U, + 0x38U, 0xebU, 0x00U, 0x00U, 0x00U, 0xd3U, 0x42U, 0x38U, 0x00U, + 0x00U, 0x00U, 0x24U, 0x00U, 0x00U, 0xd4U, 0xf2U, 0x0eU, 0x29U, + 0xd0U, 0x03U, 0x02U, 0x03U, 0x03U, 0x17U, 0x59U, 0x0cU, 0x02U, + 0x06U, 0x00U, 0x00U, 0x01U, 0x02U, 0x01U, 0x04U, 0x00U, 0x00U, + 0xddU, 0x01U, 0x03U, 0xd8U, 0x03U, 0x00U, 0x01U, 0x00U, 0xdaU, + 0x03U, 0x01U, 0x00U, 0x30U, 0xdcU, 0x03U, 0x01U, 0x01U, 0x30U, + 0x61U, 0x01U, 0x00U, 0x61U, 0x00U, 0x00U, 0x38U, 0xe3U, 0x00U, + 0x00U, 0x00U, 0x38U, 0xefU, 0x00U, 0x00U, 0x00U, 0x26U, 0x00U, + 0x00U, 0xb7U, 0xf2U, 0x38U, 0xe4U, 0x00U, 0x00U, 0x00U, 0xacU, + 0xf1U, 0x0eU, 0x38U, 0xe3U, 0x00U, 0x00U, 0x00U, 0x38U, 0xefU, + 0x00U, 0x00U, 0x00U, 0x26U, 0x00U, 0x00U, 0xb8U, 0xf2U, 0x38U, + 0xe4U, 0x00U, 0x00U, 0x00U, 0xacU, 0xf1U, 0x0eU, 0x38U, 0xe3U, + 0x00U, 0x00U, 0x00U, 0x38U, 0xefU, 0x00U, 0x00U, 0x00U, 0x26U, + 0x00U, 0x00U, 0xb9U, 0xf2U, 0x38U, 0xe5U, 0x00U, 0x00U, 0x00U, + 0xacU, 0xf1U, 0x0eU, 0x38U, 0xf0U, 0x00U, 0x00U, 0x00U, 0x38U, + 0xe6U, 0x00U, 0x00U, 0x00U, 0xf1U, 0xcbU, 0x38U, 0xe3U, 0x00U, + 0x00U, 0x00U, 0x62U, 0x00U, 0x00U, 0xebU, 0xbfU, 0x20U, 0xacU, + 0xf1U, 0x0eU, 0x38U, 0xf1U, 0x00U, 0x00U, 0x00U, 0x38U, 0xf2U, + 0x00U, 0x00U, 0x00U, 0xf0U, 0xf1U, 0xccU, 0x38U, 0xe3U, 0x00U, + 0x00U, 0x00U, 0x62U, 0x01U, 0x00U, 0xebU, 0xbfU, 0x20U, 0xacU, + 0xf1U, 0x0eU, 0x38U, 0xe3U, 0x00U, 0x00U, 0x00U, 0x38U, 0xefU, + 0x00U, 0x00U, 0x00U, 0x62U, 0x01U, 0x00U, 0xb8U, 0xf2U, 0x38U, + 0xe4U, 0x00U, 0x00U, 0x00U, 0xacU, 0xf1U, 0x0eU, 0x38U, 0xe3U, + 0x00U, 0x00U, 0x00U, 0x38U, 0xefU, 0x00U, 0x00U, 0x00U, 0x62U, + 0x01U, 0x00U, 0xb7U, 0xf2U, 0xb8U, 0xacU, 0xf1U, 0x0eU, 0x38U, + 0xe3U, 0x00U, 0x00U, 0x00U, 0x38U, 0xefU, 0x00U, 0x00U, 0x00U, + 0x62U, 0x01U, 0x00U, 0xb8U, 0xf2U, 0xb8U, 0xacU, 0xf1U, 0x0eU, + 0x38U, 0xe3U, 0x00U, 0x00U, 0x00U, 0x38U, 0xefU, 0x00U, 0x00U, + 0x00U, 0x62U, 0x00U, 0x00U, 0xb7U, 0xf2U, 0xf1U, 0x0eU, 0x38U, + 0xf3U, 0x00U, 0x00U, 0x00U, 0xc3U, 0x38U, 0xf2U, 0x00U, 0x00U, + 0x00U, 0xf0U, 0x23U, 0x02U, 0x00U, 0xd0U, 0x03U, 0x0cU, 0x0eU, + 0x22U, 0x76U, 0x76U, 0x78U, 0x3fU, 0x4bU, 0x44U, 0x00U, 0x0eU, + 0x0aU, 0x76U, 0x62U, 0x64U, 0x59U}; + // TestHook skip_wasm = jswasm[R"[test.hook]( + // const ASSERT = (x, code) => { + // if (!x) { + // rollback(x.toString(), code) + // } + // } + + // const DOESNT_EXIST = -5 + // const INVALID_ARGUMENT = -7 + // const sfInvoiceID = 0x50011 + + // const Hook = (arg) => { + // // garbage check + // ASSERT(hook_skip([], 0) === DOESNT_EXIST) + // ASSERT(hook_skip([], 1) === DOESNT_EXIST) + // ASSERT(hook_skip([], 2) === INVALID_ARGUMENT) + + // // the hook to skip is passed in by invoice id + // const skip = otxn_field(sfInvoiceID) + // ASSERT(skip.length === 32) + + // // get this hook's hash + // const hash = hook_hash(hook_pos()) + // ASSERT(hash.length === 32) + + // // to test if the "remove" function works in the api we will add this hook hash itself and then + // // remove it again. Therefore if the hook is placed at positions 0 and 3, the one at 3 should still + // // run + // ASSERT(hook_skip(hash, 1) === DOESNT_EXIST) + // ASSERT(hook_skip(hash, 0) === 1) + // ASSERT(hook_skip(hash, 1) === 1) + + // // finally skip the hook hash indicated by invoice id + // ASSERT(hook_skip(skip, 0)) + + // return accept('', hook_pos()) + // } + // )[test.hook]"]; + + TestHook pos_wasm = { + 0x43U, 0x04U, 0x08U, 0x48U, 0x6fU, 0x6fU, 0x6bU, 0x2aU, 0x77U, + 0x61U, 0x73U, 0x6dU, 0x6aU, 0x73U, 0x2fU, 0x74U, 0x65U, 0x73U, + 0x74U, 0x2dU, 0x31U, 0x30U, 0x2dU, 0x67U, 0x65U, 0x6eU, 0x2eU, + 0x6aU, 0x73U, 0x06U, 0x61U, 0x72U, 0x67U, 0x0cU, 0x61U, 0x63U, + 0x63U, 0x65U, 0x70U, 0x74U, 0x0cU, 0x00U, 0x06U, 0x00U, 0xa2U, + 0x01U, 0x00U, 0x01U, 0x00U, 0x01U, 0x00U, 0x01U, 0x1aU, 0x01U, + 0xa4U, 0x01U, 0x00U, 0x00U, 0x00U, 0x3fU, 0xe3U, 0x00U, 0x00U, + 0x00U, 0x80U, 0x3eU, 0xe3U, 0x00U, 0x00U, 0x00U, 0x80U, 0xc2U, + 0x00U, 0x4dU, 0xe3U, 0x00U, 0x00U, 0x00U, 0x3aU, 0xe3U, 0x00U, + 0x00U, 0x00U, 0xc7U, 0x28U, 0xc8U, 0x03U, 0x01U, 0x04U, 0x1fU, + 0x00U, 0x06U, 0x08U, 0x0cU, 0x02U, 0x06U, 0x00U, 0x00U, 0x01U, + 0x00U, 0x01U, 0x03U, 0x00U, 0x00U, 0x0cU, 0x01U, 0xcaU, 0x03U, + 0x00U, 0x01U, 0x00U, 0x38U, 0xe6U, 0x00U, 0x00U, 0x00U, 0xc3U, + 0xc0U, 0xffU, 0x00U, 0x23U, 0x02U, 0x00U, 0xc8U, 0x03U, 0x02U, + 0x01U, 0x03U}; + // TestHook pos_wasm = jswasm[R"[test.hook]( + // const Hook = (arg) => { + // return accept('', 255) + // } + // )[test.hook]"]; + + HASH_WASM(pos); + + // install the hook on alice in one places + env(ripple::test::jtx::hook( + alice, + {{hsov1(skip_wasm, 1), + hsov1(pos_wasm, 1), + hsov1(pos_wasm, 1), + hsov1(skip_wasm, 1)}}, + 0), + M("set hook_skip"), + HSFEE, + ter(tesSUCCESS)); + env.close(); + + // invoke the hooks + { + Json::Value json = pay(bob, alice, XRP(1)); + json[jss::InvoiceID] = pos_hash_str; + env(json, fee(XRP(1)), M("test hook_skip"), ter(tesSUCCESS)); + env.close(); + } + + auto meta = env.meta(); + + // ensure hook execution occured + BEAST_REQUIRE(meta); + BEAST_REQUIRE(meta->isFieldPresent(sfHookExecutions)); + + // ensure there was four hook executions + auto const hookExecutions = meta->getFieldArray(sfHookExecutions); + BEAST_REQUIRE(hookExecutions.size() == 2); + + // get the data in the return code of the execution + BEAST_EXPECT(hookExecutions[0].getFieldU64(sfHookReturnCode) == 0); + BEAST_EXPECT(hookExecutions[1].getFieldU64(sfHookReturnCode) == 3); } void testWithFeatures(FeatureBitset features) { - testHooksOwnerDir(features); - testHooksDisabled(features); - testTxStructure(features); - // testInferHookSetOperation(); // Not Version Specific - // testParams(features); // Not Version Specific - // testGrants(features); // Not Version Specific + // testHooksOwnerDir(features); + // testHooksDisabled(features); + // testTxStructure(features); + // // testInferHookSetOperation(); // Not Version Specific + // // testParams(features); // Not Version Specific + // // testGrants(features); // Not Version Specific - testInstall(features); - testDelete(features); - testNSDelete(features); - testCreate(features); - testUpdate(features); - testWithTickets(features); + // testInstall(features); + // testDelete(features); + // testNSDelete(features); + // testCreate(features); + // testUpdate(features); + // testWithTickets(features); - // DA TODO: illegalfunc_wasm - // testWasm(features); - test_accept(features); - test_rollback(features); + // // DA TODO: illegalfunc_wasm + // // testWasm(features); + // test_accept(features); + // test_rollback(features); + + // DA HERE // testGuards(features); // Not Used in JSHooks @@ -2064,6 +3036,7 @@ public: // test_float_sto_set(features); // // test_float_sum(features); // + // DA: DONE // test_hook_account(features); // // test_hook_again(features); // // test_hook_hash(features); // @@ -2149,6 +3122,7 @@ private: TestHook illegalfunc_wasm = // WASM: 3 jswasm[ R"[test.hook]( + const Hook = (arg) => { console.log("HERE"); return accept(ret, 0); }