diff --git a/src/ripple/app/hook/Enum.h b/src/ripple/app/hook/Enum.h index f28ca9c2c..a3ba418dd 100644 --- a/src/ripple/app/hook/Enum.h +++ b/src/ripple/app/hook/Enum.h @@ -20,6 +20,12 @@ enum HookSetFlags : uint8_t { hsfNSDELETE = 0b00000010U, // delete namespace hsfCOLLECT = 0b00000100U, // allow collect calls on this hook }; + +enum HookEmissionFlags : uint16_t { + hefSTRONG = 0x1, + hefCALLBACK = 0x2, + hefDOAAW = 0x4, +}; } // namespace ripple namespace hook { diff --git a/src/ripple/app/hook/applyHook.h b/src/ripple/app/hook/applyHook.h index ade62b792..c81514fe4 100644 --- a/src/ripple/app/hook/applyHook.h +++ b/src/ripple/app/hook/applyHook.h @@ -45,43 +45,6 @@ public: }; using namespace ripple; -static const std::map TSHAllowances = { - {ttPAYMENT, tshROLLBACK}, - {ttESCROW_CREATE, tshROLLBACK}, - {ttESCROW_FINISH, tshROLLBACK}, - {ttACCOUNT_SET, tshNONE}, - {ttESCROW_CANCEL, tshCOLLECT}, - {ttREGULAR_KEY_SET, tshROLLBACK}, - {ttOFFER_CREATE, tshCOLLECT}, - {ttOFFER_CANCEL, tshNONE}, - {ttTICKET_CREATE, tshNONE}, - {ttSIGNER_LIST_SET, tshROLLBACK}, - {ttPAYCHAN_CREATE, tshROLLBACK}, - {ttPAYCHAN_FUND, tshCOLLECT}, - {ttPAYCHAN_CLAIM, tshCOLLECT}, - {ttCHECK_CREATE, tshROLLBACK}, - {ttCHECK_CASH, tshROLLBACK}, - {ttCHECK_CANCEL, tshCOLLECT}, - {ttDEPOSIT_PREAUTH, tshROLLBACK}, - {ttTRUST_SET, tshCOLLECT}, - {ttACCOUNT_DELETE, tshROLLBACK}, - {ttHOOK_SET, tshNONE}, - {ttNFTOKEN_MINT, tshROLLBACK}, - {ttNFTOKEN_BURN, tshCOLLECT}, - {ttNFTOKEN_CREATE_OFFER, tshROLLBACK}, - {ttNFTOKEN_CANCEL_OFFER, tshCOLLECT}, - {ttNFTOKEN_ACCEPT_OFFER, tshROLLBACK}, - {ttCLAIM_REWARD, tshROLLBACK}, - {ttINVOKE, tshROLLBACK}, - {ttURITOKEN_MINT, tshNONE}, - {ttURITOKEN_BURN, tshROLLBACK}, - {ttURITOKEN_BUY, tshROLLBACK}, - {ttURITOKEN_CREATE_SELL_OFFER, tshROLLBACK}, - {ttURITOKEN_CANCEL_SELL_OFFER, tshNONE}, - {ttIMPORT, tshROLLBACK}, - {ttGENESIS_MINT, tshCOLLECT}, -}; - std::vector> getTransactionalStakeHolders(STTx const& tx, ReadView const& rv); } // namespace hook diff --git a/src/ripple/app/hook/impl/applyHook.cpp b/src/ripple/app/hook/impl/applyHook.cpp index 67f97572f..d831f5f68 100644 --- a/src/ripple/app/hook/impl/applyHook.cpp +++ b/src/ripple/app/hook/impl/applyHook.cpp @@ -38,19 +38,10 @@ getTransactionalStakeHolders(STTx const& tx, ReadView const& rv) uint16_t tt = tx.getFieldU16(sfTransactionType); - uint8_t tsh = tshNONE; - if (auto const& found = hook::TSHAllowances.find(tt); - found != hook::TSHAllowances.end()) - tsh = found->second; - else - return {}; - std::map> tshEntries; int upto = 0; - bool canRollback = tsh & tshROLLBACK; - auto const ADD_TSH = [&otxnAcc, &tshEntries, &upto]( const AccountID& acc_r, bool rb) { if (acc_r != *otxnAcc) @@ -62,6 +53,9 @@ getTransactionalStakeHolders(STTx const& tx, ReadView const& rv) } }; + bool const tshSTRONG = true; // tshROLLBACK + bool const tshWEAK = false; // tshCOLLECT + auto const getNFTOffer = [](std::optional id, ReadView const& rv) -> std::shared_ptr { @@ -72,12 +66,13 @@ getTransactionalStakeHolders(STTx const& tx, ReadView const& rv) }; bool const fixV1 = rv.rules().enabled(fixXahauV1); + bool const fixV2 = rv.rules().enabled(fixXahauV2); switch (tt) { case ttIMPORT: { if (tx.isFieldPresent(sfIssuer)) - ADD_TSH(tx.getAccountID(sfIssuer), canRollback); + ADD_TSH(tx.getAccountID(sfIssuer), fixV2 ? tshWEAK : tshSTRONG); break; } @@ -107,11 +102,11 @@ getTransactionalStakeHolders(STTx const& tx, ReadView const& rv) { // the owner burns their token, and the issuer is a weak TSH if (*otxnAcc == owner && rv.exists(keylet::account(issuer))) - ADD_TSH(issuer, false); + ADD_TSH(issuer, tshWEAK); // the issuer burns the owner's token, and the owner is a weak // TSH else if (rv.exists(keylet::account(owner))) - ADD_TSH(owner, false); + ADD_TSH(owner, tshWEAK); break; } @@ -121,13 +116,13 @@ getTransactionalStakeHolders(STTx const& tx, ReadView const& rv) if (*otxnAcc == owner) { // the owner burns their token, and the issuer is a weak TSH - ADD_TSH(issuer, true); + ADD_TSH(issuer, tshSTRONG); } else { // the issuer burns the owner's token, and the owner is a // weak TSH - ADD_TSH(owner, true); + ADD_TSH(owner, tshSTRONG); } } @@ -148,17 +143,46 @@ getTransactionalStakeHolders(STTx const& tx, ReadView const& rv) if (owner != tx.getAccountID(sfAccount)) { // current owner is a strong TSH - ADD_TSH(owner, canRollback); + ADD_TSH(owner, tshSTRONG); } // issuer is also a strong TSH if the burnable flag is set auto const issuer = ut->getAccountID(sfIssuer); if (issuer != owner) - ADD_TSH(issuer, ut->getFlags() & lsfBurnable); + ADD_TSH( + issuer, + (ut->getFlags() & lsfBurnable) ? tshSTRONG : tshWEAK); break; } + case ttURITOKEN_MINT: { + // destination is a strong tsh + if (fixV2 && tx.isFieldPresent(sfDestination)) + ADD_TSH(tx.getAccountID(sfDestination), tshSTRONG); + break; + } + + case ttURITOKEN_CANCEL_SELL_OFFER: { + if (!fixV2) + break; + + Keylet const id{ltURI_TOKEN, tx.getFieldH256(sfURITokenID)}; + if (!rv.exists(id)) + return {}; + + auto const ut = rv.read(id); + if (!ut || ut->getFieldU16(sfLedgerEntryType) != ltURI_TOKEN) + return {}; + + if (ut->isFieldPresent(sfDestination)) + { + auto const dest = ut->getAccountID(sfDestination); + ADD_TSH(dest, tshWEAK); + } + break; + } + case ttURITOKEN_CREATE_SELL_OFFER: { Keylet const id{ltURI_TOKEN, tx.getFieldH256(sfURITokenID)}; if (!rv.exists(id)) @@ -173,11 +197,13 @@ getTransactionalStakeHolders(STTx const& tx, ReadView const& rv) // issuer is a strong TSH if the burnable flag is set if (issuer != owner) - ADD_TSH(issuer, ut->getFlags() & lsfBurnable); + ADD_TSH( + issuer, + (ut->getFlags() & lsfBurnable) ? tshSTRONG : tshWEAK); // destination is a strong tsh if (tx.isFieldPresent(sfDestination)) - ADD_TSH(tx.getAccountID(sfDestination), canRollback); + ADD_TSH(tx.getAccountID(sfDestination), tshSTRONG); break; } @@ -186,7 +212,7 @@ getTransactionalStakeHolders(STTx const& tx, ReadView const& rv) case ttNFTOKEN_MINT: case ttCLAIM_REWARD: { if (tx.isFieldPresent(sfIssuer)) - ADD_TSH(tx.getAccountID(sfIssuer), canRollback); + ADD_TSH(tx.getAccountID(sfIssuer), tshSTRONG); break; }; @@ -209,7 +235,7 @@ getTransactionalStakeHolders(STTx const& tx, ReadView const& rv) ADD_TSH(issuer, issuerCanRollback); if (hasOwner) - ADD_TSH(owner, canRollback); + ADD_TSH(owner, tshWEAK); break; } @@ -228,16 +254,16 @@ getTransactionalStakeHolders(STTx const& tx, ReadView const& rv) if (bo) { - ADD_TSH(bo->getAccountID(sfOwner), canRollback); + ADD_TSH(bo->getAccountID(sfOwner), tshSTRONG); if (bo->isFieldPresent(sfDestination)) - ADD_TSH(bo->getAccountID(sfDestination), canRollback); + ADD_TSH(bo->getAccountID(sfDestination), tshWEAK); } if (so) { - ADD_TSH(so->getAccountID(sfOwner), canRollback); + ADD_TSH(so->getAccountID(sfOwner), tshSTRONG); if (so->isFieldPresent(sfDestination)) - ADD_TSH(so->getAccountID(sfDestination), canRollback); + ADD_TSH(so->getAccountID(sfDestination), tshWEAK); } break; @@ -253,24 +279,21 @@ getTransactionalStakeHolders(STTx const& tx, ReadView const& rv) auto const offer = getNFTOffer(offerID, rv); if (offer) { - ADD_TSH(offer->getAccountID(sfOwner), canRollback); + ADD_TSH(offer->getAccountID(sfOwner), tshSTRONG); if (offer->isFieldPresent(sfDestination)) - ADD_TSH( - offer->getAccountID(sfDestination), canRollback); + ADD_TSH(offer->getAccountID(sfDestination), tshWEAK); // issuer can't stop people canceling their offers, but can // get weak executions uint256 nid = offer->getFieldH256(sfNFTokenID); auto const issuer = nft::getIssuer(nid); - ADD_TSH(issuer, false); + ADD_TSH(issuer, tshWEAK); } } break; } // self transactions - case ttURITOKEN_MINT: - case ttURITOKEN_CANCEL_SELL_OFFER: case ttACCOUNT_SET: case ttOFFER_CANCEL: case ttTICKET_CREATE: @@ -283,14 +306,14 @@ getTransactionalStakeHolders(STTx const& tx, ReadView const& rv) case ttREGULAR_KEY_SET: { if (!tx.isFieldPresent(sfRegularKey)) return {}; - ADD_TSH(tx.getAccountID(sfRegularKey), canRollback); + ADD_TSH(tx.getAccountID(sfRegularKey), tshSTRONG); break; } case ttDEPOSIT_PREAUTH: { if (!tx.isFieldPresent(sfAuthorize)) return {}; - ADD_TSH(tx.getAccountID(sfAuthorize), canRollback); + ADD_TSH(tx.getAccountID(sfAuthorize), tshSTRONG); break; } @@ -302,7 +325,7 @@ getTransactionalStakeHolders(STTx const& tx, ReadView const& rv) case ttPAYCHAN_CREATE: case ttINVOKE: { if (destAcc) - ADD_TSH(*destAcc, canRollback); + ADD_TSH(*destAcc, tshSTRONG); break; } @@ -313,7 +336,7 @@ getTransactionalStakeHolders(STTx const& tx, ReadView const& rv) auto const& lim = tx.getFieldAmount(sfLimitAmount); AccountID const& issuer = lim.getIssuer(); - ADD_TSH(issuer, canRollback); + ADD_TSH(issuer, tshWEAK); break; } @@ -348,11 +371,11 @@ getTransactionalStakeHolders(STTx const& tx, ReadView const& rv) // the source account is a strong transacitonal stakeholder for // fin and can - ADD_TSH(src, true); + ADD_TSH(src, tshSTRONG); // the dest acc is a strong tsh for fin and weak for can if (src != dst) - ADD_TSH(dst, tt == ttESCROW_FINISH); + ADD_TSH(dst, tt == ttESCROW_FINISH ? tshSTRONG : tshWEAK); break; } @@ -368,8 +391,10 @@ getTransactionalStakeHolders(STTx const& tx, ReadView const& rv) if (!escrow) return {}; - ADD_TSH(escrow->getAccountID(sfAccount), true); - ADD_TSH(escrow->getAccountID(sfDestination), canRollback); + ADD_TSH(escrow->getAccountID(sfAccount), tshSTRONG); + ADD_TSH( + escrow->getAccountID(sfDestination), + tt == ttESCROW_FINISH ? tshSTRONG : tshWEAK); break; } } @@ -383,8 +408,8 @@ getTransactionalStakeHolders(STTx const& tx, ReadView const& rv) if (!chan) return {}; - ADD_TSH(chan->getAccountID(sfAccount), true); - ADD_TSH(chan->getAccountID(sfDestination), canRollback); + ADD_TSH(chan->getAccountID(sfAccount), tshSTRONG); + ADD_TSH(chan->getAccountID(sfDestination), tshWEAK); break; } @@ -397,8 +422,8 @@ getTransactionalStakeHolders(STTx const& tx, ReadView const& rv) if (!check) return {}; - ADD_TSH(check->getAccountID(sfAccount), true); - ADD_TSH(check->getAccountID(sfDestination), canRollback); + ADD_TSH(check->getAccountID(sfAccount), tshSTRONG); + ADD_TSH(check->getAccountID(sfDestination), tshWEAK); break; } @@ -408,7 +433,7 @@ getTransactionalStakeHolders(STTx const& tx, ReadView const& rv) STArray const& signerEntries = tx.getFieldArray(sfSignerEntries); for (auto const& entryObj : signerEntries) if (entryObj.isFieldPresent(sfAccount)) - ADD_TSH(entryObj.getAccountID(sfAccount), canRollback); + ADD_TSH(entryObj.getAccountID(sfAccount), tshSTRONG); break; } @@ -420,7 +445,7 @@ getTransactionalStakeHolders(STTx const& tx, ReadView const& rv) { if (mint.isFieldPresent(sfDestination)) { - ADD_TSH(mint.getAccountID(sfDestination), canRollback); + ADD_TSH(mint.getAccountID(sfDestination), tshWEAK); } } } @@ -1832,7 +1857,7 @@ hook::finalizeHookResult( uint16_t exec_index = avi.nextHookExecutionIndex(); // apply emitted transactions to the ledger (by adding them to the emitted // directory) if we are allowed to - std::vector emission_txnid; + std::map emission_txnid; if (doEmit) { @@ -1853,7 +1878,12 @@ hook::finalizeHookResult( if (!sleEmitted) { - emission_txnid.push_back(id); + auto const& emitDetails = const_cast(*ptr) + .getField(sfEmitDetails) + .downcast(); + + emission_txnid.emplace( + id, emitDetails.getFieldH256(sfEmitNonce)); sleEmitted = std::make_shared(emittedId); // RH TODO: add a new constructor to STObject to avoid this @@ -1885,6 +1915,7 @@ hook::finalizeHookResult( } } + bool const fixV2 = applyCtx.view().rules().enabled(fixXahauV2); // add a metadata entry for this hook execution result { STObject meta{sfHookExecution}; @@ -1911,6 +1942,19 @@ hook::finalizeHookResult( meta.setFieldU16(sfHookExecutionIndex, exec_index); meta.setFieldU16(sfHookStateChangeCount, hookResult.changedStateCount); meta.setFieldH256(sfHookHash, hookResult.hookHash); + + // add informational flags in fix2 + if (fixV2) + { + uint32_t flags = 0; + if (hookResult.isStrong) + flags |= hefSTRONG; + if (hookResult.isCallback) + flags |= hefCALLBACK; + if (hookResult.executeAgainAsWeak) + flags |= hefDOAAW; + meta.setFieldU32(sfFlags, flags); + } avi.addHookExecutionMetaData(std::move(meta)); } @@ -1918,12 +1962,14 @@ hook::finalizeHookResult( if (applyCtx.view().rules().enabled(featureHooksUpdate1) && !emission_txnid.empty()) { - for (auto const& etxnid : emission_txnid) + for (auto const& [etxnid, enonce] : emission_txnid) { STObject meta{sfHookEmission}; meta.setFieldH256(sfHookHash, hookResult.hookHash); meta.setAccountID(sfHookAccount, hookResult.account); meta.setFieldH256(sfEmittedTxnID, etxnid); + if (fixV2) + meta.setFieldH256(sfEmitNonce, enonce); avi.addHookEmissionMetaData(std::move(meta)); } } diff --git a/src/ripple/protocol/impl/InnerObjectFormats.cpp b/src/ripple/protocol/impl/InnerObjectFormats.cpp index d98ad2056..aee747c2e 100644 --- a/src/ripple/protocol/impl/InnerObjectFormats.cpp +++ b/src/ripple/protocol/impl/InnerObjectFormats.cpp @@ -72,13 +72,15 @@ InnerObjectFormats::InnerObjectFormats() {sfHookInstructionCount, soeREQUIRED}, {sfHookExecutionIndex, soeREQUIRED}, {sfHookStateChangeCount, soeREQUIRED}, - {sfHookEmitCount, soeREQUIRED}}); + {sfHookEmitCount, soeREQUIRED}, + {sfFlags, soeOPTIONAL}}); add(sfHookEmission.jsonName.c_str(), sfHookEmission.getCode(), {{sfHookHash, soeREQUIRED}, {sfHookAccount, soeREQUIRED}, - {sfEmittedTxnID, soeREQUIRED}}); + {sfEmittedTxnID, soeREQUIRED}, + {sfEmitNonce, soeOPTIONAL}}); add(sfHookDefinition.jsonName.c_str(), sfHookDefinition.getCode(), diff --git a/src/test/app/Import_test.cpp b/src/test/app/Import_test.cpp index 708f241df..3c73ade2c 100644 --- a/src/test/app/Import_test.cpp +++ b/src/test/app/Import_test.cpp @@ -4996,6 +4996,7 @@ class Import_test : public beast::unit_test::suite *this, network::makeNetworkVLConfig(21337, keys)}; auto const feeDrops = env.current()->fees().base; + bool const fixV2 = env.current()->rules().enabled(fixXahauV2); // confirm total coins header auto const initCoins = env.current()->info().drops; @@ -5015,6 +5016,10 @@ class Import_test : public beast::unit_test::suite env.fund(XRP(10000), alice, issuer); env.close(); + // fixXahauV2 - tshWEAK + env(fset(issuer, asfTshCollect)); + env.close(); + std::string const createCodeHex = "0061736D01000000011C0460057F7F7F7F7F017E60037F7F7E017E60027F7F" "017F60017F017E02250303656E76057472616365000003656E7608726F6C6C" @@ -5029,8 +5034,8 @@ class Import_test : public beast::unit_test::suite std::string ns_str = "CAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECA" "FE"; - Json::Value jv = - ripple::test::jtx::hook(issuer, {{hso(createCodeHex)}}, 0); + Json::Value jv = ripple::test::jtx::hook( + issuer, {{hso(createCodeHex)}}, hsfOVERRIDE | hsfCOLLECT); jv[jss::Hooks][0U][jss::Hook][jss::HookNamespace] = ns_str; jv[jss::Hooks][0U][jss::Hook][jss::HookOn] = "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDFFFFFFFFFFFFFFFFFFBFFF" @@ -5041,32 +5046,37 @@ class Import_test : public beast::unit_test::suite auto const preAlice = env.balance(alice); auto const preCoins = env.current()->info().drops; + auto const result = fixV2 ? ter(tesSUCCESS) : ter(tecHOOK_REJECTED); env(import::import( alice, import::loadXpop(ImportTCAccountSet::w_seed)), import::issuer(issuer), fee(1'000'000), - ter(tecHOOK_REJECTED)); + result); env.close(); - // confirm fee was burned but no mint + // fixXahauV2 + auto const mintXAH = fixV2 ? XRP(1000) : XRP(0); + // confirm fee was burned mint / no mint auto const postAlice = env.balance(alice); - BEAST_EXPECT(postAlice == preAlice - XRP(1)); + BEAST_EXPECT(postAlice == preAlice - XRP(1) + mintXAH); // confirm total coins header auto const postCoins = env.current()->info().drops; - BEAST_EXPECT(postCoins == preCoins - XRP(1)); + BEAST_EXPECT(postCoins == preCoins - XRP(1) + mintXAH); - // resubmit import without issuer - no trigger hook + // resubmit import without issuer + auto const result2 = + fixV2 ? ter(tefPAST_IMPORT_SEQ) : ter(tesSUCCESS); env(import::import( alice, import::loadXpop(ImportTCAccountSet::w_seed)), fee(feeDrops * 10), - ter(tesSUCCESS)); + result2); env.close(); - // total burn = (burn drops + burn fee drops) - fee drops - auto const totalBurn = XRP(1000) - (feeDrops * 10); + // total burn + auto const totalBurn = fixV2 ? XRP(0) : XRP(1000) - (feeDrops * 10); - // confirm fee was minted + // confirm fee was minted / not minted auto const postAlice2 = env.balance(alice); BEAST_EXPECT(postAlice2 == postAlice + totalBurn); @@ -5921,6 +5931,7 @@ public: { using namespace test::jtx; FeatureBitset const all{supported_amendments()}; + testWithFeats(all - fixXahauV2); testWithFeats(all); } diff --git a/src/test/app/SetHookTSH_test.cpp b/src/test/app/SetHookTSH_test.cpp index b33c2fc64..1024164da 100644 --- a/src/test/app/SetHookTSH_test.cpp +++ b/src/test/app/SetHookTSH_test.cpp @@ -48,91 +48,368 @@ private: jv[jss::Flags] = hsfOVERRIDE | hsfCOLLECT; } + const std::vector CallbackHook = { + 0x00U, 0x61U, 0x73U, 0x6DU, 0x01U, 0x00U, 0x00U, 0x00U, 0x01U, 0x35U, + 0x08U, 0x60U, 0x03U, 0x7FU, 0x7FU, 0x7EU, 0x01U, 0x7EU, 0x60U, 0x05U, + 0x7FU, 0x7FU, 0x7FU, 0x7FU, 0x7FU, 0x01U, 0x7EU, 0x60U, 0x02U, 0x7FU, + 0x7FU, 0x01U, 0x7EU, 0x60U, 0x04U, 0x7FU, 0x7FU, 0x7FU, 0x7FU, 0x01U, + 0x7EU, 0x60U, 0x01U, 0x7FU, 0x01U, 0x7EU, 0x60U, 0x00U, 0x01U, 0x7EU, + 0x60U, 0x03U, 0x7FU, 0x7FU, 0x7FU, 0x01U, 0x7EU, 0x60U, 0x02U, 0x7FU, + 0x7FU, 0x01U, 0x7FU, 0x02U, 0xAEU, 0x01U, 0x0BU, 0x03U, 0x65U, 0x6EU, + 0x76U, 0x06U, 0x61U, 0x63U, 0x63U, 0x65U, 0x70U, 0x74U, 0x00U, 0x00U, + 0x03U, 0x65U, 0x6EU, 0x76U, 0x05U, 0x74U, 0x72U, 0x61U, 0x63U, 0x65U, + 0x00U, 0x01U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x0CU, 0x68U, 0x6FU, 0x6FU, + 0x6BU, 0x5FU, 0x61U, 0x63U, 0x63U, 0x6FU, 0x75U, 0x6EU, 0x74U, 0x00U, + 0x02U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x0AU, 0x75U, 0x74U, 0x69U, 0x6CU, + 0x5FU, 0x61U, 0x63U, 0x63U, 0x69U, 0x64U, 0x00U, 0x03U, 0x03U, 0x65U, + 0x6EU, 0x76U, 0x0CU, 0x65U, 0x74U, 0x78U, 0x6EU, 0x5FU, 0x72U, 0x65U, + 0x73U, 0x65U, 0x72U, 0x76U, 0x65U, 0x00U, 0x04U, 0x03U, 0x65U, 0x6EU, + 0x76U, 0x0AU, 0x6CU, 0x65U, 0x64U, 0x67U, 0x65U, 0x72U, 0x5FU, 0x73U, + 0x65U, 0x71U, 0x00U, 0x05U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x0AU, 0x6FU, + 0x74U, 0x78U, 0x6EU, 0x5FU, 0x66U, 0x69U, 0x65U, 0x6CU, 0x64U, 0x00U, + 0x06U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x0CU, 0x65U, 0x74U, 0x78U, 0x6EU, + 0x5FU, 0x64U, 0x65U, 0x74U, 0x61U, 0x69U, 0x6CU, 0x73U, 0x00U, 0x02U, + 0x03U, 0x65U, 0x6EU, 0x76U, 0x0DU, 0x65U, 0x74U, 0x78U, 0x6EU, 0x5FU, + 0x66U, 0x65U, 0x65U, 0x5FU, 0x62U, 0x61U, 0x73U, 0x65U, 0x00U, 0x02U, + 0x03U, 0x65U, 0x6EU, 0x76U, 0x04U, 0x65U, 0x6DU, 0x69U, 0x74U, 0x00U, + 0x03U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x02U, 0x5FU, 0x67U, 0x00U, 0x07U, + 0x03U, 0x03U, 0x02U, 0x04U, 0x04U, 0x05U, 0x03U, 0x01U, 0x00U, 0x02U, + 0x06U, 0x31U, 0x08U, 0x7FU, 0x01U, 0x41U, 0xE0U, 0x8BU, 0x04U, 0x0BU, + 0x7FU, 0x00U, 0x41U, 0xA0U, 0x09U, 0x0BU, 0x7FU, 0x00U, 0x41U, 0x80U, + 0x08U, 0x0BU, 0x7FU, 0x00U, 0x41U, 0xD1U, 0x0BU, 0x0BU, 0x7FU, 0x00U, + 0x41U, 0x80U, 0x08U, 0x0BU, 0x7FU, 0x00U, 0x41U, 0xE0U, 0x8BU, 0x04U, + 0x0BU, 0x7FU, 0x00U, 0x41U, 0x00U, 0x0BU, 0x7FU, 0x00U, 0x41U, 0x01U, + 0x0BU, 0x07U, 0x0FU, 0x02U, 0x04U, 0x63U, 0x62U, 0x61U, 0x6BU, 0x00U, + 0x0BU, 0x04U, 0x68U, 0x6FU, 0x6FU, 0x6BU, 0x00U, 0x0CU, 0x0AU, 0xA6U, + 0x8EU, 0x00U, 0x02U, 0x8BU, 0x82U, 0x00U, 0x02U, 0x03U, 0x7EU, 0x04U, + 0x7FU, 0x02U, 0x7EU, 0x23U, 0x00U, 0x21U, 0x04U, 0x20U, 0x04U, 0x41U, + 0x10U, 0x6BU, 0x21U, 0x04U, 0x20U, 0x04U, 0x24U, 0x00U, 0x20U, 0x04U, + 0x20U, 0x00U, 0x36U, 0x02U, 0x0CU, 0x20U, 0x04U, 0x41U, 0x08U, 0x6AU, + 0x21U, 0x06U, 0x20U, 0x06U, 0x21U, 0x00U, 0x20U, 0x04U, 0x20U, 0x00U, + 0x36U, 0x02U, 0x04U, 0x20U, 0x04U, 0x28U, 0x02U, 0x0CU, 0x21U, 0x00U, + 0x20U, 0x00U, 0xADU, 0x21U, 0x01U, 0x20U, 0x01U, 0x42U, 0x18U, 0x88U, + 0x21U, 0x01U, 0x20U, 0x01U, 0x42U, 0xFFU, 0x01U, 0x83U, 0x21U, 0x01U, + 0x20U, 0x01U, 0xA7U, 0x21U, 0x00U, 0x20U, 0x04U, 0x28U, 0x02U, 0x04U, + 0x21U, 0x05U, 0x20U, 0x05U, 0x20U, 0x00U, 0x3AU, 0x00U, 0x00U, 0x20U, + 0x04U, 0x28U, 0x02U, 0x0CU, 0x21U, 0x00U, 0x20U, 0x00U, 0xADU, 0x21U, + 0x01U, 0x20U, 0x01U, 0x42U, 0x10U, 0x88U, 0x21U, 0x01U, 0x20U, 0x01U, + 0x42U, 0xFFU, 0x01U, 0x83U, 0x21U, 0x01U, 0x20U, 0x01U, 0xA7U, 0x21U, + 0x00U, 0x20U, 0x04U, 0x28U, 0x02U, 0x04U, 0x21U, 0x05U, 0x20U, 0x05U, + 0x20U, 0x00U, 0x3AU, 0x00U, 0x01U, 0x20U, 0x04U, 0x28U, 0x02U, 0x0CU, + 0x21U, 0x00U, 0x20U, 0x00U, 0xADU, 0x21U, 0x01U, 0x20U, 0x01U, 0x42U, + 0x08U, 0x88U, 0x21U, 0x01U, 0x20U, 0x01U, 0x42U, 0xFFU, 0x01U, 0x83U, + 0x21U, 0x01U, 0x20U, 0x01U, 0xA7U, 0x21U, 0x00U, 0x20U, 0x04U, 0x28U, + 0x02U, 0x04U, 0x21U, 0x05U, 0x20U, 0x05U, 0x20U, 0x00U, 0x3AU, 0x00U, + 0x02U, 0x20U, 0x04U, 0x28U, 0x02U, 0x0CU, 0x21U, 0x00U, 0x20U, 0x00U, + 0xADU, 0x21U, 0x01U, 0x20U, 0x01U, 0x42U, 0x00U, 0x88U, 0x21U, 0x01U, + 0x20U, 0x01U, 0x42U, 0xFFU, 0x01U, 0x83U, 0x21U, 0x01U, 0x20U, 0x01U, + 0xA7U, 0x21U, 0x00U, 0x20U, 0x04U, 0x28U, 0x02U, 0x04U, 0x21U, 0x05U, + 0x20U, 0x05U, 0x20U, 0x00U, 0x3AU, 0x00U, 0x03U, 0x20U, 0x06U, 0x21U, + 0x00U, 0x20U, 0x00U, 0x41U, 0x04U, 0x42U, 0x32U, 0x10U, 0x00U, 0x21U, + 0x02U, 0x20U, 0x02U, 0x1AU, 0x20U, 0x04U, 0x41U, 0x10U, 0x6AU, 0x21U, + 0x00U, 0x20U, 0x00U, 0x24U, 0x00U, 0x42U, 0x00U, 0x21U, 0x03U, 0x42U, + 0x00U, 0x0BU, 0x0BU, 0x94U, 0x8CU, 0x00U, 0x02U, 0x09U, 0x7EU, 0x05U, + 0x7FU, 0x02U, 0x40U, 0x02U, 0x40U, 0x23U, 0x00U, 0x21U, 0x0BU, 0x20U, + 0x0BU, 0x41U, 0x80U, 0x01U, 0x6BU, 0x21U, 0x0BU, 0x20U, 0x0BU, 0x24U, + 0x00U, 0x20U, 0x0BU, 0x20U, 0x00U, 0x36U, 0x02U, 0x7CU, 0x41U, 0xFBU, + 0x08U, 0x41U, 0x15U, 0x41U, 0xE7U, 0x08U, 0x41U, 0x14U, 0x41U, 0x00U, + 0x10U, 0x01U, 0x21U, 0x02U, 0x20U, 0x02U, 0x1AU, 0x41U, 0x9DU, 0x0AU, + 0x41U, 0x14U, 0x10U, 0x02U, 0x21U, 0x03U, 0x20U, 0x03U, 0x1AU, 0x41U, + 0xB3U, 0x0AU, 0x41U, 0x14U, 0x41U, 0x84U, 0x08U, 0x41U, 0x23U, 0x10U, + 0x03U, 0x21U, 0x01U, 0x20U, 0x0BU, 0x20U, 0x01U, 0x37U, 0x03U, 0x58U, + 0x41U, 0x01U, 0x10U, 0x04U, 0x21U, 0x04U, 0x20U, 0x04U, 0x1AU, 0x10U, + 0x05U, 0x21U, 0x01U, 0x20U, 0x01U, 0xA7U, 0x21U, 0x00U, 0x20U, 0x00U, + 0x41U, 0x01U, 0x6AU, 0x21U, 0x00U, 0x20U, 0x0BU, 0x20U, 0x00U, 0x36U, + 0x02U, 0x54U, 0x20U, 0x0BU, 0x28U, 0x02U, 0x54U, 0x21U, 0x00U, 0x20U, + 0x00U, 0x41U, 0xFFU, 0x01U, 0x71U, 0x21U, 0x00U, 0x20U, 0x00U, 0x41U, + 0x18U, 0x74U, 0x21U, 0x00U, 0x20U, 0x0BU, 0x28U, 0x02U, 0x54U, 0x21U, + 0x0AU, 0x20U, 0x0AU, 0x41U, 0x80U, 0xFEU, 0x03U, 0x71U, 0x21U, 0x0AU, + 0x20U, 0x0AU, 0x41U, 0x08U, 0x74U, 0x21U, 0x0AU, 0x20U, 0x00U, 0x20U, + 0x0AU, 0x72U, 0x21U, 0x00U, 0x20U, 0x0BU, 0x28U, 0x02U, 0x54U, 0x21U, + 0x0AU, 0x20U, 0x0AU, 0x41U, 0x80U, 0x80U, 0xFCU, 0x07U, 0x71U, 0x21U, + 0x0AU, 0x20U, 0x0AU, 0x41U, 0x08U, 0x76U, 0x21U, 0x0AU, 0x20U, 0x00U, + 0x20U, 0x0AU, 0x72U, 0x21U, 0x00U, 0x20U, 0x0BU, 0x28U, 0x02U, 0x54U, + 0x21U, 0x0AU, 0x20U, 0x0AU, 0x41U, 0x80U, 0x80U, 0x80U, 0x78U, 0x71U, + 0x21U, 0x0AU, 0x20U, 0x0AU, 0x41U, 0x18U, 0x76U, 0x21U, 0x0AU, 0x20U, + 0x00U, 0x20U, 0x0AU, 0x72U, 0x21U, 0x00U, 0x41U, 0x00U, 0x20U, 0x00U, + 0x36U, 0x02U, 0xB4U, 0x09U, 0x20U, 0x0BU, 0x28U, 0x02U, 0x54U, 0x21U, + 0x00U, 0x20U, 0x00U, 0x41U, 0x04U, 0x6AU, 0x21U, 0x00U, 0x20U, 0x0BU, + 0x20U, 0x00U, 0x36U, 0x02U, 0x50U, 0x20U, 0x0BU, 0x28U, 0x02U, 0x50U, + 0x21U, 0x00U, 0x20U, 0x00U, 0x41U, 0xFFU, 0x01U, 0x71U, 0x21U, 0x00U, + 0x20U, 0x00U, 0x41U, 0x18U, 0x74U, 0x21U, 0x00U, 0x20U, 0x0BU, 0x28U, + 0x02U, 0x50U, 0x21U, 0x0AU, 0x20U, 0x0AU, 0x41U, 0x80U, 0xFEU, 0x03U, + 0x71U, 0x21U, 0x0AU, 0x20U, 0x0AU, 0x41U, 0x08U, 0x74U, 0x21U, 0x0AU, + 0x20U, 0x00U, 0x20U, 0x0AU, 0x72U, 0x21U, 0x00U, 0x20U, 0x0BU, 0x28U, + 0x02U, 0x50U, 0x21U, 0x0AU, 0x20U, 0x0AU, 0x41U, 0x80U, 0x80U, 0xFCU, + 0x07U, 0x71U, 0x21U, 0x0AU, 0x20U, 0x0AU, 0x41U, 0x08U, 0x76U, 0x21U, + 0x0AU, 0x20U, 0x00U, 0x20U, 0x0AU, 0x72U, 0x21U, 0x00U, 0x20U, 0x0BU, + 0x28U, 0x02U, 0x50U, 0x21U, 0x0AU, 0x20U, 0x0AU, 0x41U, 0x80U, 0x80U, + 0x80U, 0x78U, 0x71U, 0x21U, 0x0AU, 0x20U, 0x0AU, 0x41U, 0x18U, 0x76U, + 0x21U, 0x0AU, 0x20U, 0x00U, 0x20U, 0x0AU, 0x72U, 0x21U, 0x00U, 0x41U, + 0x00U, 0x20U, 0x00U, 0x36U, 0x02U, 0xBAU, 0x09U, 0x20U, 0x0BU, 0x42U, + 0xC0U, 0x84U, 0x3DU, 0x37U, 0x03U, 0x48U, 0x20U, 0x0BU, 0x41U, 0xBFU, + 0x09U, 0x36U, 0x02U, 0x44U, 0x20U, 0x0BU, 0x29U, 0x03U, 0x48U, 0x21U, + 0x01U, 0x20U, 0x01U, 0x42U, 0x38U, 0x88U, 0x21U, 0x01U, 0x20U, 0x01U, + 0x42U, 0x3FU, 0x83U, 0x21U, 0x01U, 0x20U, 0x01U, 0x42U, 0xC0U, 0x00U, + 0x7CU, 0x21U, 0x01U, 0x20U, 0x01U, 0xA7U, 0x21U, 0x00U, 0x20U, 0x0BU, + 0x28U, 0x02U, 0x44U, 0x21U, 0x0AU, 0x20U, 0x0AU, 0x41U, 0x01U, 0x6AU, + 0x21U, 0x0CU, 0x20U, 0x0BU, 0x20U, 0x0CU, 0x36U, 0x02U, 0x44U, 0x20U, + 0x0AU, 0x20U, 0x00U, 0x3AU, 0x00U, 0x00U, 0x20U, 0x0BU, 0x29U, 0x03U, + 0x48U, 0x21U, 0x01U, 0x20U, 0x01U, 0x42U, 0x30U, 0x88U, 0x21U, 0x01U, + 0x20U, 0x01U, 0x42U, 0xFFU, 0x01U, 0x83U, 0x21U, 0x01U, 0x20U, 0x01U, + 0xA7U, 0x21U, 0x00U, 0x20U, 0x0BU, 0x28U, 0x02U, 0x44U, 0x21U, 0x0AU, + 0x20U, 0x0AU, 0x41U, 0x01U, 0x6AU, 0x21U, 0x0CU, 0x20U, 0x0BU, 0x20U, + 0x0CU, 0x36U, 0x02U, 0x44U, 0x20U, 0x0AU, 0x20U, 0x00U, 0x3AU, 0x00U, + 0x00U, 0x20U, 0x0BU, 0x29U, 0x03U, 0x48U, 0x21U, 0x01U, 0x20U, 0x01U, + 0x42U, 0x28U, 0x88U, 0x21U, 0x01U, 0x20U, 0x01U, 0x42U, 0xFFU, 0x01U, + 0x83U, 0x21U, 0x01U, 0x20U, 0x01U, 0xA7U, 0x21U, 0x00U, 0x20U, 0x0BU, + 0x28U, 0x02U, 0x44U, 0x21U, 0x0AU, 0x20U, 0x0AU, 0x41U, 0x01U, 0x6AU, + 0x21U, 0x0CU, 0x20U, 0x0BU, 0x20U, 0x0CU, 0x36U, 0x02U, 0x44U, 0x20U, + 0x0AU, 0x20U, 0x00U, 0x3AU, 0x00U, 0x00U, 0x20U, 0x0BU, 0x29U, 0x03U, + 0x48U, 0x21U, 0x01U, 0x20U, 0x01U, 0x42U, 0x20U, 0x88U, 0x21U, 0x01U, + 0x20U, 0x01U, 0x42U, 0xFFU, 0x01U, 0x83U, 0x21U, 0x01U, 0x20U, 0x01U, + 0xA7U, 0x21U, 0x00U, 0x20U, 0x0BU, 0x28U, 0x02U, 0x44U, 0x21U, 0x0AU, + 0x20U, 0x0AU, 0x41U, 0x01U, 0x6AU, 0x21U, 0x0CU, 0x20U, 0x0BU, 0x20U, + 0x0CU, 0x36U, 0x02U, 0x44U, 0x20U, 0x0AU, 0x20U, 0x00U, 0x3AU, 0x00U, + 0x00U, 0x20U, 0x0BU, 0x29U, 0x03U, 0x48U, 0x21U, 0x01U, 0x20U, 0x01U, + 0x42U, 0x18U, 0x88U, 0x21U, 0x01U, 0x20U, 0x01U, 0x42U, 0xFFU, 0x01U, + 0x83U, 0x21U, 0x01U, 0x20U, 0x01U, 0xA7U, 0x21U, 0x00U, 0x20U, 0x0BU, + 0x28U, 0x02U, 0x44U, 0x21U, 0x0AU, 0x20U, 0x0AU, 0x41U, 0x01U, 0x6AU, + 0x21U, 0x0CU, 0x20U, 0x0BU, 0x20U, 0x0CU, 0x36U, 0x02U, 0x44U, 0x20U, + 0x0AU, 0x20U, 0x00U, 0x3AU, 0x00U, 0x00U, 0x20U, 0x0BU, 0x29U, 0x03U, + 0x48U, 0x21U, 0x01U, 0x20U, 0x01U, 0x42U, 0x10U, 0x88U, 0x21U, 0x01U, + 0x20U, 0x01U, 0x42U, 0xFFU, 0x01U, 0x83U, 0x21U, 0x01U, 0x20U, 0x01U, + 0xA7U, 0x21U, 0x00U, 0x20U, 0x0BU, 0x28U, 0x02U, 0x44U, 0x21U, 0x0AU, + 0x20U, 0x0AU, 0x41U, 0x01U, 0x6AU, 0x21U, 0x0CU, 0x20U, 0x0BU, 0x20U, + 0x0CU, 0x36U, 0x02U, 0x44U, 0x20U, 0x0AU, 0x20U, 0x00U, 0x3AU, 0x00U, + 0x00U, 0x20U, 0x0BU, 0x29U, 0x03U, 0x48U, 0x21U, 0x01U, 0x20U, 0x01U, + 0x42U, 0x08U, 0x88U, 0x21U, 0x01U, 0x20U, 0x01U, 0x42U, 0xFFU, 0x01U, + 0x83U, 0x21U, 0x01U, 0x20U, 0x01U, 0xA7U, 0x21U, 0x00U, 0x20U, 0x0BU, + 0x28U, 0x02U, 0x44U, 0x21U, 0x0AU, 0x20U, 0x0AU, 0x41U, 0x01U, 0x6AU, + 0x21U, 0x0CU, 0x20U, 0x0BU, 0x20U, 0x0CU, 0x36U, 0x02U, 0x44U, 0x20U, + 0x0AU, 0x20U, 0x00U, 0x3AU, 0x00U, 0x00U, 0x20U, 0x0BU, 0x29U, 0x03U, + 0x48U, 0x21U, 0x01U, 0x20U, 0x01U, 0x42U, 0x00U, 0x88U, 0x21U, 0x01U, + 0x20U, 0x01U, 0x42U, 0xFFU, 0x01U, 0x83U, 0x21U, 0x01U, 0x20U, 0x01U, + 0xA7U, 0x21U, 0x00U, 0x20U, 0x0BU, 0x28U, 0x02U, 0x44U, 0x21U, 0x0AU, + 0x20U, 0x0AU, 0x41U, 0x01U, 0x6AU, 0x21U, 0x0CU, 0x20U, 0x0BU, 0x20U, + 0x0CU, 0x36U, 0x02U, 0x44U, 0x20U, 0x0AU, 0x20U, 0x00U, 0x3AU, 0x00U, + 0x00U, 0x41U, 0xAEU, 0x09U, 0x41U, 0x04U, 0x41U, 0x83U, 0x80U, 0x08U, + 0x10U, 0x06U, 0x21U, 0x01U, 0x20U, 0x01U, 0x42U, 0x04U, 0x51U, 0x21U, + 0x00U, 0x20U, 0x00U, 0x41U, 0x01U, 0x71U, 0x21U, 0x00U, 0x20U, 0x00U, + 0x45U, 0x21U, 0x00U, 0x20U, 0x00U, 0x45U, 0x21U, 0x00U, 0x0BU, 0x20U, + 0x00U, 0x04U, 0x40U, 0x02U, 0x40U, 0x41U, 0x00U, 0x41U, 0x2EU, 0x3AU, + 0x00U, 0xADU, 0x09U, 0x01U, 0x0BU, 0x05U, 0x01U, 0x0BU, 0x0BU, 0x02U, + 0x7EU, 0x02U, 0x40U, 0x02U, 0x40U, 0x41U, 0xC7U, 0x0AU, 0x41U, 0x8AU, + 0x01U, 0x10U, 0x07U, 0x21U, 0x05U, 0x20U, 0x05U, 0x1AU, 0x41U, 0xA0U, + 0x09U, 0x41U, 0xB1U, 0x02U, 0x10U, 0x08U, 0x21U, 0x01U, 0x20U, 0x0BU, + 0x20U, 0x01U, 0x37U, 0x03U, 0x38U, 0x20U, 0x0BU, 0x41U, 0xF0U, 0x09U, + 0x36U, 0x02U, 0x34U, 0x20U, 0x0BU, 0x29U, 0x03U, 0x38U, 0x21U, 0x01U, + 0x20U, 0x01U, 0x42U, 0x38U, 0x87U, 0x21U, 0x01U, 0x20U, 0x01U, 0x42U, + 0x3FU, 0x83U, 0x21U, 0x01U, 0x20U, 0x01U, 0x42U, 0xC0U, 0x00U, 0x7CU, + 0x21U, 0x01U, 0x20U, 0x01U, 0xA7U, 0x21U, 0x00U, 0x20U, 0x0BU, 0x28U, + 0x02U, 0x34U, 0x21U, 0x0AU, 0x20U, 0x0AU, 0x41U, 0x01U, 0x6AU, 0x21U, + 0x0CU, 0x20U, 0x0BU, 0x20U, 0x0CU, 0x36U, 0x02U, 0x34U, 0x20U, 0x0AU, + 0x20U, 0x00U, 0x3AU, 0x00U, 0x00U, 0x20U, 0x0BU, 0x29U, 0x03U, 0x38U, + 0x21U, 0x01U, 0x20U, 0x01U, 0x42U, 0x30U, 0x87U, 0x21U, 0x01U, 0x20U, + 0x01U, 0x42U, 0xFFU, 0x01U, 0x83U, 0x21U, 0x01U, 0x20U, 0x01U, 0xA7U, + 0x21U, 0x00U, 0x20U, 0x0BU, 0x28U, 0x02U, 0x34U, 0x21U, 0x0AU, 0x20U, + 0x0AU, 0x41U, 0x01U, 0x6AU, 0x21U, 0x0CU, 0x20U, 0x0BU, 0x20U, 0x0CU, + 0x36U, 0x02U, 0x34U, 0x20U, 0x0AU, 0x20U, 0x00U, 0x3AU, 0x00U, 0x00U, + 0x20U, 0x0BU, 0x29U, 0x03U, 0x38U, 0x21U, 0x01U, 0x20U, 0x01U, 0x42U, + 0x28U, 0x87U, 0x21U, 0x01U, 0x20U, 0x01U, 0x42U, 0xFFU, 0x01U, 0x83U, + 0x21U, 0x01U, 0x20U, 0x01U, 0xA7U, 0x21U, 0x00U, 0x20U, 0x0BU, 0x28U, + 0x02U, 0x34U, 0x21U, 0x0AU, 0x20U, 0x0AU, 0x41U, 0x01U, 0x6AU, 0x21U, + 0x0CU, 0x20U, 0x0BU, 0x20U, 0x0CU, 0x36U, 0x02U, 0x34U, 0x20U, 0x0AU, + 0x20U, 0x00U, 0x3AU, 0x00U, 0x00U, 0x20U, 0x0BU, 0x29U, 0x03U, 0x38U, + 0x21U, 0x01U, 0x20U, 0x01U, 0x42U, 0x20U, 0x87U, 0x21U, 0x01U, 0x20U, + 0x01U, 0x42U, 0xFFU, 0x01U, 0x83U, 0x21U, 0x01U, 0x20U, 0x01U, 0xA7U, + 0x21U, 0x00U, 0x20U, 0x0BU, 0x28U, 0x02U, 0x34U, 0x21U, 0x0AU, 0x20U, + 0x0AU, 0x41U, 0x01U, 0x6AU, 0x21U, 0x0CU, 0x20U, 0x0BU, 0x20U, 0x0CU, + 0x36U, 0x02U, 0x34U, 0x20U, 0x0AU, 0x20U, 0x00U, 0x3AU, 0x00U, 0x00U, + 0x20U, 0x0BU, 0x29U, 0x03U, 0x38U, 0x21U, 0x01U, 0x20U, 0x01U, 0x42U, + 0x18U, 0x87U, 0x21U, 0x01U, 0x20U, 0x01U, 0x42U, 0xFFU, 0x01U, 0x83U, + 0x21U, 0x01U, 0x20U, 0x01U, 0xA7U, 0x21U, 0x00U, 0x20U, 0x0BU, 0x28U, + 0x02U, 0x34U, 0x21U, 0x0AU, 0x20U, 0x0AU, 0x41U, 0x01U, 0x6AU, 0x21U, + 0x0CU, 0x20U, 0x0BU, 0x20U, 0x0CU, 0x36U, 0x02U, 0x34U, 0x20U, 0x0AU, + 0x20U, 0x00U, 0x3AU, 0x00U, 0x00U, 0x20U, 0x0BU, 0x29U, 0x03U, 0x38U, + 0x21U, 0x01U, 0x20U, 0x01U, 0x42U, 0x10U, 0x87U, 0x21U, 0x01U, 0x20U, + 0x01U, 0x42U, 0xFFU, 0x01U, 0x83U, 0x21U, 0x01U, 0x20U, 0x01U, 0xA7U, + 0x21U, 0x00U, 0x20U, 0x0BU, 0x28U, 0x02U, 0x34U, 0x21U, 0x0AU, 0x20U, + 0x0AU, 0x41U, 0x01U, 0x6AU, 0x21U, 0x0CU, 0x20U, 0x0BU, 0x20U, 0x0CU, + 0x36U, 0x02U, 0x34U, 0x20U, 0x0AU, 0x20U, 0x00U, 0x3AU, 0x00U, 0x00U, + 0x20U, 0x0BU, 0x29U, 0x03U, 0x38U, 0x21U, 0x01U, 0x20U, 0x01U, 0x42U, + 0x08U, 0x87U, 0x21U, 0x01U, 0x20U, 0x01U, 0x42U, 0xFFU, 0x01U, 0x83U, + 0x21U, 0x01U, 0x20U, 0x01U, 0xA7U, 0x21U, 0x00U, 0x20U, 0x0BU, 0x28U, + 0x02U, 0x34U, 0x21U, 0x0AU, 0x20U, 0x0AU, 0x41U, 0x01U, 0x6AU, 0x21U, + 0x0CU, 0x20U, 0x0BU, 0x20U, 0x0CU, 0x36U, 0x02U, 0x34U, 0x20U, 0x0AU, + 0x20U, 0x00U, 0x3AU, 0x00U, 0x00U, 0x20U, 0x0BU, 0x29U, 0x03U, 0x38U, + 0x21U, 0x01U, 0x20U, 0x01U, 0x42U, 0x00U, 0x87U, 0x21U, 0x01U, 0x20U, + 0x01U, 0x42U, 0xFFU, 0x01U, 0x83U, 0x21U, 0x01U, 0x20U, 0x01U, 0xA7U, + 0x21U, 0x00U, 0x20U, 0x0BU, 0x28U, 0x02U, 0x34U, 0x21U, 0x0AU, 0x20U, + 0x0AU, 0x41U, 0x01U, 0x6AU, 0x21U, 0x0CU, 0x20U, 0x0BU, 0x20U, 0x0CU, + 0x36U, 0x02U, 0x34U, 0x20U, 0x0AU, 0x20U, 0x00U, 0x3AU, 0x00U, 0x00U, + 0x41U, 0x80U, 0x08U, 0x41U, 0x03U, 0x41U, 0xA0U, 0x09U, 0x41U, 0xB1U, + 0x02U, 0x41U, 0x01U, 0x10U, 0x01U, 0x21U, 0x06U, 0x20U, 0x06U, 0x1AU, + 0x20U, 0x0BU, 0x41U, 0x10U, 0x6AU, 0x21U, 0x00U, 0x20U, 0x00U, 0x41U, + 0x20U, 0x41U, 0xA0U, 0x09U, 0x41U, 0xB1U, 0x02U, 0x10U, 0x09U, 0x21U, + 0x01U, 0x20U, 0x0BU, 0x20U, 0x01U, 0x37U, 0x03U, 0x08U, 0x20U, 0x0BU, + 0x29U, 0x03U, 0x08U, 0x21U, 0x01U, 0x20U, 0x01U, 0x42U, 0x00U, 0x55U, + 0x21U, 0x00U, 0x20U, 0x00U, 0x41U, 0x01U, 0x71U, 0x21U, 0x00U, 0x20U, + 0x00U, 0x45U, 0x21U, 0x00U, 0x20U, 0x00U, 0x45U, 0x21U, 0x00U, 0x0BU, + 0x20U, 0x00U, 0x04U, 0x40U, 0x02U, 0x40U, 0x02U, 0x40U, 0x41U, 0xA7U, + 0x08U, 0x41U, 0x20U, 0x42U, 0xF5U, 0x00U, 0x10U, 0x00U, 0x21U, 0x07U, + 0x20U, 0x07U, 0x1AU, 0x0BU, 0x01U, 0x0BU, 0x05U, 0x01U, 0x0BU, 0x0BU, + 0x02U, 0x7EU, 0x02U, 0x7EU, 0x41U, 0xC7U, 0x08U, 0x41U, 0x20U, 0x42U, + 0xF7U, 0x00U, 0x10U, 0x00U, 0x21U, 0x08U, 0x20U, 0x08U, 0x1AU, 0x41U, + 0x01U, 0x41U, 0x01U, 0x10U, 0x0AU, 0x21U, 0x0DU, 0x20U, 0x0DU, 0x1AU, + 0x20U, 0x0BU, 0x41U, 0x80U, 0x01U, 0x6AU, 0x21U, 0x00U, 0x20U, 0x00U, + 0x24U, 0x00U, 0x42U, 0x00U, 0x21U, 0x09U, 0x42U, 0x00U, 0x0BU, 0x0BU, + 0x0BU, 0x0BU, 0x0BU, 0x88U, 0x02U, 0x04U, 0x00U, 0x41U, 0x80U, 0x08U, + 0x0BU, 0x90U, 0x01U, 0x74U, 0x78U, 0x6EU, 0x00U, 0x72U, 0x50U, 0x4DU, + 0x68U, 0x37U, 0x50U, 0x69U, 0x39U, 0x63U, 0x74U, 0x36U, 0x39U, 0x39U, + 0x69U, 0x5AU, 0x55U, 0x54U, 0x57U, 0x61U, 0x79U, 0x74U, 0x4AU, 0x55U, + 0x6FU, 0x48U, 0x63U, 0x4AU, 0x37U, 0x63U, 0x67U, 0x79U, 0x7AU, 0x69U, + 0x4BU, 0x00U, 0x63U, 0x61U, 0x6CU, 0x6CU, 0x62U, 0x61U, 0x63U, 0x6BU, + 0x2EU, 0x63U, 0x3AU, 0x20U, 0x54U, 0x78U, 0x20U, 0x65U, 0x6DU, 0x69U, + 0x74U, 0x74U, 0x65U, 0x64U, 0x20U, 0x73U, 0x75U, 0x63U, 0x63U, 0x65U, + 0x73U, 0x73U, 0x2EU, 0x00U, 0x63U, 0x61U, 0x6CU, 0x6CU, 0x62U, 0x61U, + 0x63U, 0x6BU, 0x2EU, 0x63U, 0x3AU, 0x20U, 0x54U, 0x78U, 0x20U, 0x65U, + 0x6DU, 0x69U, 0x74U, 0x74U, 0x65U, 0x64U, 0x20U, 0x66U, 0x61U, 0x69U, + 0x6CU, 0x75U, 0x72U, 0x65U, 0x2EU, 0x00U, 0x63U, 0x61U, 0x6CU, 0x6CU, + 0x62U, 0x61U, 0x63U, 0x6BU, 0x2EU, 0x63U, 0x3AU, 0x20U, 0x43U, 0x61U, + 0x6CU, 0x6CU, 0x65U, 0x64U, 0x2EU, 0x00U, 0x22U, 0x63U, 0x61U, 0x6CU, + 0x6CU, 0x62U, 0x61U, 0x63U, 0x6BU, 0x2EU, 0x63U, 0x3AU, 0x20U, 0x43U, + 0x61U, 0x6CU, 0x6CU, 0x65U, 0x64U, 0x2EU, 0x22U, 0x00U, 0x41U, 0xA0U, + 0x09U, 0x0BU, 0x5AU, 0x12U, 0x00U, 0x00U, 0x22U, 0x80U, 0x00U, 0x00U, + 0x00U, 0x24U, 0x00U, 0x00U, 0x00U, 0x00U, 0x99U, 0x99U, 0x99U, 0x99U, + 0x99U, 0x20U, 0x1AU, 0x00U, 0x00U, 0x00U, 0x00U, 0x20U, 0x1BU, 0x00U, + 0x00U, 0x00U, 0x00U, 0x61U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, + 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, + 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, + 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, + 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, + 0x99U, 0x99U, 0x68U, 0x40U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, + 0x00U, 0x73U, 0x21U, 0x00U, 0x41U, 0x9BU, 0x0AU, 0x0BU, 0x02U, 0x81U, + 0x14U, 0x00U, 0x41U, 0xB1U, 0x0AU, 0x0BU, 0x02U, 0x83U, 0x14U}; + const std::vector TshHook = { - 0x00U, 0x61U, 0x73U, 0x6dU, 0x01U, 0x00U, 0x00U, 0x00U, 0x01U, 0x1cU, - 0x04U, 0x60U, 0x05U, 0x7fU, 0x7fU, 0x7fU, 0x7fU, 0x7fU, 0x01U, 0x7eU, - 0x60U, 0x03U, 0x7fU, 0x7fU, 0x7eU, 0x01U, 0x7eU, 0x60U, 0x02U, 0x7fU, - 0x7fU, 0x01U, 0x7fU, 0x60U, 0x01U, 0x7fU, 0x01U, 0x7eU, 0x02U, 0x23U, - 0x03U, 0x03U, 0x65U, 0x6eU, 0x76U, 0x05U, 0x74U, 0x72U, 0x61U, 0x63U, - 0x65U, 0x00U, 0x00U, 0x03U, 0x65U, 0x6eU, 0x76U, 0x06U, 0x61U, 0x63U, - 0x63U, 0x65U, 0x70U, 0x74U, 0x00U, 0x01U, 0x03U, 0x65U, 0x6eU, 0x76U, - 0x02U, 0x5fU, 0x67U, 0x00U, 0x02U, 0x03U, 0x02U, 0x01U, 0x03U, 0x05U, - 0x03U, 0x01U, 0x00U, 0x02U, 0x06U, 0x2bU, 0x07U, 0x7fU, 0x01U, 0x41U, - 0xc0U, 0x8bU, 0x04U, 0x0bU, 0x7fU, 0x00U, 0x41U, 0x80U, 0x08U, 0x0bU, - 0x7fU, 0x00U, 0x41U, 0xb8U, 0x0bU, 0x0bU, 0x7fU, 0x00U, 0x41U, 0x80U, - 0x08U, 0x0bU, 0x7fU, 0x00U, 0x41U, 0xc0U, 0x8bU, 0x04U, 0x0bU, 0x7fU, - 0x00U, 0x41U, 0x00U, 0x0bU, 0x7fU, 0x00U, 0x41U, 0x01U, 0x0bU, 0x07U, - 0x08U, 0x01U, 0x04U, 0x68U, 0x6fU, 0x6fU, 0x6bU, 0x00U, 0x03U, 0x0aU, - 0xf3U, 0x81U, 0x00U, 0x01U, 0xefU, 0x81U, 0x00U, 0x01U, 0x01U, 0x7fU, - 0x23U, 0x00U, 0x41U, 0x10U, 0x6bU, 0x22U, 0x01U, 0x24U, 0x00U, 0x20U, - 0x01U, 0x20U, 0x00U, 0x36U, 0x02U, 0x0cU, 0x41U, 0x9aU, 0x0bU, 0x41U, - 0x0fU, 0x41U, 0xbdU, 0x09U, 0x41U, 0x0eU, 0x41U, 0x00U, 0x10U, 0x00U, - 0x1aU, 0x02U, 0x40U, 0x02U, 0x40U, 0x02U, 0x40U, 0x02U, 0x40U, 0x20U, - 0x01U, 0x28U, 0x02U, 0x0cU, 0x0eU, 0x03U, 0x00U, 0x01U, 0x02U, 0x03U, - 0x0bU, 0x41U, 0xd9U, 0x0aU, 0x41U, 0xc0U, 0x00U, 0x41U, 0xfeU, 0x08U, - 0x41U, 0x3fU, 0x41U, 0x00U, 0x10U, 0x00U, 0x1aU, 0x0cU, 0x02U, 0x0bU, - 0x41U, 0x9bU, 0x0aU, 0x41U, 0x3dU, 0x41U, 0xc2U, 0x08U, 0x41U, 0x3cU, - 0x41U, 0x00U, 0x10U, 0x00U, 0x1aU, 0x0cU, 0x01U, 0x0bU, 0x41U, 0xd7U, - 0x09U, 0x41U, 0xc3U, 0x00U, 0x41U, 0x80U, 0x08U, 0x41U, 0xc2U, 0x00U, - 0x41U, 0x00U, 0x10U, 0x00U, 0x1aU, 0x0bU, 0x41U, 0xaaU, 0x0bU, 0x41U, - 0x0dU, 0x41U, 0xcbU, 0x09U, 0x41U, 0x0cU, 0x41U, 0x00U, 0x10U, 0x00U, - 0x1aU, 0x20U, 0x01U, 0x20U, 0x01U, 0x41U, 0x08U, 0x6aU, 0x22U, 0x00U, - 0x36U, 0x02U, 0x04U, 0x20U, 0x01U, 0x28U, 0x02U, 0x04U, 0x20U, 0x01U, - 0x35U, 0x02U, 0x0cU, 0x42U, 0x18U, 0x88U, 0x42U, 0xffU, 0x01U, 0x83U, - 0x3cU, 0x00U, 0x00U, 0x20U, 0x01U, 0x28U, 0x02U, 0x04U, 0x20U, 0x01U, - 0x35U, 0x02U, 0x0cU, 0x42U, 0x10U, 0x88U, 0x42U, 0xffU, 0x01U, 0x83U, - 0x3cU, 0x00U, 0x01U, 0x20U, 0x01U, 0x28U, 0x02U, 0x04U, 0x20U, 0x01U, - 0x35U, 0x02U, 0x0cU, 0x42U, 0x08U, 0x88U, 0x42U, 0xffU, 0x01U, 0x83U, - 0x3cU, 0x00U, 0x02U, 0x20U, 0x01U, 0x28U, 0x02U, 0x04U, 0x20U, 0x01U, - 0x35U, 0x02U, 0x0cU, 0x42U, 0xffU, 0x01U, 0x83U, 0x3cU, 0x00U, 0x03U, - 0x20U, 0x00U, 0x41U, 0x04U, 0x42U, 0x18U, 0x10U, 0x01U, 0x1aU, 0x41U, - 0x01U, 0x41U, 0x01U, 0x10U, 0x02U, 0x1aU, 0x20U, 0x01U, 0x41U, 0x10U, - 0x6aU, 0x24U, 0x00U, 0x42U, 0x00U, 0x0bU, 0x0bU, 0xbfU, 0x03U, 0x01U, - 0x00U, 0x41U, 0x80U, 0x08U, 0x0bU, 0xb7U, 0x03U, 0x74U, 0x73U, 0x68U, - 0x2eU, 0x63U, 0x3aU, 0x20U, 0x57U, 0x65U, 0x61U, 0x6bU, 0x20U, 0x41U, - 0x67U, 0x61U, 0x69U, 0x6eU, 0x2eU, 0x20U, 0x45U, 0x78U, 0x65U, 0x63U, - 0x75U, 0x74U, 0x65U, 0x20U, 0x41U, 0x46U, 0x54U, 0x45U, 0x52U, 0x20U, - 0x74U, 0x72U, 0x61U, 0x6eU, 0x73U, 0x61U, 0x63U, 0x74U, 0x69U, 0x6fU, - 0x6eU, 0x20U, 0x69U, 0x73U, 0x20U, 0x61U, 0x70U, 0x70U, 0x6cU, 0x69U, - 0x65U, 0x64U, 0x20U, 0x74U, 0x6fU, 0x20U, 0x6cU, 0x65U, 0x64U, 0x67U, - 0x65U, 0x72U, 0x00U, 0x74U, 0x73U, 0x68U, 0x2eU, 0x63U, 0x3aU, 0x20U, - 0x57U, 0x65U, 0x61U, 0x6bU, 0x2eU, 0x20U, 0x45U, 0x78U, 0x65U, 0x63U, - 0x75U, 0x74U, 0x65U, 0x20U, 0x41U, 0x46U, 0x54U, 0x45U, 0x52U, 0x20U, - 0x74U, 0x72U, 0x61U, 0x6eU, 0x73U, 0x61U, 0x63U, 0x74U, 0x69U, 0x6fU, - 0x6eU, 0x20U, 0x69U, 0x73U, 0x20U, 0x61U, 0x70U, 0x70U, 0x6cU, 0x69U, - 0x65U, 0x64U, 0x20U, 0x74U, 0x6fU, 0x20U, 0x6cU, 0x65U, 0x64U, 0x67U, - 0x65U, 0x72U, 0x00U, 0x74U, 0x73U, 0x68U, 0x2eU, 0x63U, 0x3aU, 0x20U, - 0x53U, 0x74U, 0x72U, 0x6fU, 0x6eU, 0x67U, 0x2eU, 0x20U, 0x45U, 0x78U, - 0x65U, 0x63U, 0x75U, 0x74U, 0x65U, 0x20U, 0x42U, 0x45U, 0x46U, 0x4fU, - 0x52U, 0x45U, 0x20U, 0x74U, 0x72U, 0x61U, 0x6eU, 0x73U, 0x61U, 0x63U, - 0x74U, 0x69U, 0x6fU, 0x6eU, 0x20U, 0x69U, 0x73U, 0x20U, 0x61U, 0x70U, - 0x70U, 0x6cU, 0x69U, 0x65U, 0x64U, 0x20U, 0x74U, 0x6fU, 0x20U, 0x6cU, - 0x65U, 0x64U, 0x67U, 0x65U, 0x72U, 0x00U, 0x74U, 0x73U, 0x68U, 0x2eU, - 0x63U, 0x3aU, 0x20U, 0x53U, 0x74U, 0x61U, 0x72U, 0x74U, 0x2eU, 0x00U, - 0x74U, 0x73U, 0x68U, 0x2eU, 0x63U, 0x3aU, 0x20U, 0x45U, 0x6eU, 0x64U, - 0x2eU, 0x00U, 0x22U, 0x74U, 0x73U, 0x68U, 0x2eU, 0x63U, 0x3aU, 0x20U, - 0x57U, 0x65U, 0x61U, 0x6bU, 0x20U, 0x41U, 0x67U, 0x61U, 0x69U, 0x6eU, - 0x2eU, 0x20U, 0x45U, 0x78U, 0x65U, 0x63U, 0x75U, 0x74U, 0x65U, 0x20U, - 0x41U, 0x46U, 0x54U, 0x45U, 0x52U, 0x20U, 0x74U, 0x72U, 0x61U, 0x6eU, - 0x73U, 0x61U, 0x63U, 0x74U, 0x69U, 0x6fU, 0x6eU, 0x20U, 0x69U, 0x73U, - 0x20U, 0x61U, 0x70U, 0x70U, 0x6cU, 0x69U, 0x65U, 0x64U, 0x20U, 0x74U, - 0x6fU, 0x20U, 0x6cU, 0x65U, 0x64U, 0x67U, 0x65U, 0x72U, 0x22U, 0x00U, - 0x22U, 0x74U, 0x73U, 0x68U, 0x2eU, 0x63U, 0x3aU, 0x20U, 0x57U, 0x65U, - 0x61U, 0x6bU, 0x2eU, 0x20U, 0x45U, 0x78U, 0x65U, 0x63U, 0x75U, 0x74U, - 0x65U, 0x20U, 0x41U, 0x46U, 0x54U, 0x45U, 0x52U, 0x20U, 0x74U, 0x72U, - 0x61U, 0x6eU, 0x73U, 0x61U, 0x63U, 0x74U, 0x69U, 0x6fU, 0x6eU, 0x20U, - 0x69U, 0x73U, 0x20U, 0x61U, 0x70U, 0x70U, 0x6cU, 0x69U, 0x65U, 0x64U, - 0x20U, 0x74U, 0x6fU, 0x20U, 0x6cU, 0x65U, 0x64U, 0x67U, 0x65U, 0x72U, - 0x22U, 0x00U, 0x22U, 0x74U, 0x73U, 0x68U, 0x2eU, 0x63U, 0x3aU, 0x20U, - 0x53U, 0x74U, 0x72U, 0x6fU, 0x6eU, 0x67U, 0x2eU, 0x20U, 0x45U, 0x78U, - 0x65U, 0x63U, 0x75U, 0x74U, 0x65U, 0x20U, 0x42U, 0x45U, 0x46U, 0x4fU, - 0x52U, 0x45U, 0x20U, 0x74U, 0x72U, 0x61U, 0x6eU, 0x73U, 0x61U, 0x63U, - 0x74U, 0x69U, 0x6fU, 0x6eU, 0x20U, 0x69U, 0x73U, 0x20U, 0x61U, 0x70U, - 0x70U, 0x6cU, 0x69U, 0x65U, 0x64U, 0x20U, 0x74U, 0x6fU, 0x20U, 0x6cU, - 0x65U, 0x64U, 0x67U, 0x65U, 0x72U, 0x22U, 0x00U, 0x22U, 0x74U, 0x73U, - 0x68U, 0x2eU, 0x63U, 0x3aU, 0x20U, 0x53U, 0x74U, 0x61U, 0x72U, 0x74U, - 0x2eU, 0x22U, 0x00U, 0x22U, 0x74U, 0x73U, 0x68U, 0x2eU, 0x63U, 0x3aU, - 0x20U, 0x45U, 0x6eU, 0x64U, 0x2eU, 0x22U}; + 0x00U, 0x61U, 0x73U, 0x6DU, 0x01U, 0x00U, 0x00U, 0x00U, 0x01U, 0x28U, + 0x06U, 0x60U, 0x05U, 0x7FU, 0x7FU, 0x7FU, 0x7FU, 0x7FU, 0x01U, 0x7EU, + 0x60U, 0x04U, 0x7FU, 0x7FU, 0x7FU, 0x7FU, 0x01U, 0x7EU, 0x60U, 0x00U, + 0x01U, 0x7EU, 0x60U, 0x03U, 0x7FU, 0x7FU, 0x7EU, 0x01U, 0x7EU, 0x60U, + 0x02U, 0x7FU, 0x7FU, 0x01U, 0x7FU, 0x60U, 0x01U, 0x7FU, 0x01U, 0x7EU, + 0x02U, 0x45U, 0x05U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x05U, 0x74U, 0x72U, + 0x61U, 0x63U, 0x65U, 0x00U, 0x00U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x0AU, + 0x6FU, 0x74U, 0x78U, 0x6EU, 0x5FU, 0x70U, 0x61U, 0x72U, 0x61U, 0x6DU, + 0x00U, 0x01U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x0AU, 0x68U, 0x6FU, 0x6FU, + 0x6BU, 0x5FU, 0x61U, 0x67U, 0x61U, 0x69U, 0x6EU, 0x00U, 0x02U, 0x03U, + 0x65U, 0x6EU, 0x76U, 0x06U, 0x61U, 0x63U, 0x63U, 0x65U, 0x70U, 0x74U, + 0x00U, 0x03U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x02U, 0x5FU, 0x67U, 0x00U, + 0x04U, 0x03U, 0x02U, 0x01U, 0x05U, 0x05U, 0x03U, 0x01U, 0x00U, 0x02U, + 0x06U, 0x2BU, 0x07U, 0x7FU, 0x01U, 0x41U, 0xC0U, 0x8BU, 0x04U, 0x0BU, + 0x7FU, 0x00U, 0x41U, 0x80U, 0x08U, 0x0BU, 0x7FU, 0x00U, 0x41U, 0xBCU, + 0x0BU, 0x0BU, 0x7FU, 0x00U, 0x41U, 0x80U, 0x08U, 0x0BU, 0x7FU, 0x00U, + 0x41U, 0xC0U, 0x8BU, 0x04U, 0x0BU, 0x7FU, 0x00U, 0x41U, 0x00U, 0x0BU, + 0x7FU, 0x00U, 0x41U, 0x01U, 0x0BU, 0x07U, 0x08U, 0x01U, 0x04U, 0x68U, + 0x6FU, 0x6FU, 0x6BU, 0x00U, 0x05U, 0x0AU, 0x8EU, 0x84U, 0x00U, 0x01U, + 0x8AU, 0x84U, 0x00U, 0x02U, 0x09U, 0x7EU, 0x05U, 0x7FU, 0x02U, 0x40U, + 0x02U, 0x40U, 0x23U, 0x00U, 0x21U, 0x0AU, 0x20U, 0x0AU, 0x41U, 0x10U, + 0x6BU, 0x21U, 0x0AU, 0x20U, 0x0AU, 0x24U, 0x00U, 0x20U, 0x0AU, 0x20U, + 0x00U, 0x36U, 0x02U, 0x0CU, 0x41U, 0x9EU, 0x0BU, 0x41U, 0x0FU, 0x41U, + 0xC1U, 0x09U, 0x41U, 0x0EU, 0x41U, 0x00U, 0x10U, 0x00U, 0x21U, 0x02U, + 0x20U, 0x02U, 0x1AU, 0x20U, 0x0AU, 0x41U, 0x0BU, 0x6AU, 0x21U, 0x00U, + 0x20U, 0x00U, 0x41U, 0x01U, 0x41U, 0xBDU, 0x09U, 0x41U, 0x03U, 0x10U, + 0x01U, 0x21U, 0x01U, 0x20U, 0x01U, 0x42U, 0x01U, 0x51U, 0x21U, 0x00U, + 0x20U, 0x00U, 0x41U, 0x01U, 0x71U, 0x21U, 0x00U, 0x20U, 0x00U, 0x45U, + 0x21U, 0x00U, 0x20U, 0x00U, 0x45U, 0x21U, 0x00U, 0x0BU, 0x20U, 0x00U, + 0x04U, 0x40U, 0x02U, 0x40U, 0x02U, 0x40U, 0x10U, 0x02U, 0x21U, 0x03U, + 0x20U, 0x03U, 0x1AU, 0x0BU, 0x01U, 0x0BU, 0x05U, 0x01U, 0x0BU, 0x0BU, + 0x02U, 0x7EU, 0x02U, 0x40U, 0x20U, 0x0AU, 0x28U, 0x02U, 0x0CU, 0x21U, + 0x00U, 0x02U, 0x40U, 0x02U, 0x40U, 0x02U, 0x40U, 0x02U, 0x40U, 0x02U, + 0x40U, 0x20U, 0x00U, 0x0EU, 0x03U, 0x02U, 0x01U, 0x00U, 0x04U, 0x0BU, + 0x02U, 0x40U, 0x02U, 0x40U, 0x02U, 0x40U, 0x41U, 0xDBU, 0x09U, 0x41U, + 0xC3U, 0x00U, 0x41U, 0x80U, 0x08U, 0x41U, 0xC2U, 0x00U, 0x41U, 0x00U, + 0x10U, 0x00U, 0x21U, 0x04U, 0x20U, 0x04U, 0x1AU, 0x0BU, 0x0CU, 0x06U, + 0x0BU, 0x00U, 0x0BU, 0x00U, 0x0BU, 0x02U, 0x40U, 0x02U, 0x40U, 0x02U, + 0x40U, 0x41U, 0x9FU, 0x0AU, 0x41U, 0x3DU, 0x41U, 0xC2U, 0x08U, 0x41U, + 0x3CU, 0x41U, 0x00U, 0x10U, 0x00U, 0x21U, 0x05U, 0x20U, 0x05U, 0x1AU, + 0x0BU, 0x0CU, 0x05U, 0x0BU, 0x00U, 0x0BU, 0x00U, 0x0BU, 0x02U, 0x40U, + 0x02U, 0x40U, 0x02U, 0x40U, 0x41U, 0xDDU, 0x0AU, 0x41U, 0xC0U, 0x00U, + 0x41U, 0xFEU, 0x08U, 0x41U, 0x3FU, 0x41U, 0x00U, 0x10U, 0x00U, 0x21U, + 0x06U, 0x20U, 0x06U, 0x1AU, 0x0BU, 0x01U, 0x0BU, 0x0BU, 0x0BU, 0x0BU, + 0x0BU, 0x02U, 0x7EU, 0x02U, 0x7EU, 0x41U, 0xAEU, 0x0BU, 0x41U, 0x0DU, + 0x41U, 0xCFU, 0x09U, 0x41U, 0x0CU, 0x41U, 0x00U, 0x10U, 0x00U, 0x21U, + 0x07U, 0x20U, 0x07U, 0x1AU, 0x20U, 0x0AU, 0x41U, 0x07U, 0x6AU, 0x21U, + 0x0CU, 0x20U, 0x0CU, 0x21U, 0x00U, 0x20U, 0x0AU, 0x20U, 0x00U, 0x36U, + 0x02U, 0x00U, 0x20U, 0x0AU, 0x28U, 0x02U, 0x0CU, 0x21U, 0x00U, 0x20U, + 0x00U, 0xADU, 0x21U, 0x01U, 0x20U, 0x01U, 0x42U, 0x18U, 0x88U, 0x21U, + 0x01U, 0x20U, 0x01U, 0x42U, 0xFFU, 0x01U, 0x83U, 0x21U, 0x01U, 0x20U, + 0x01U, 0xA7U, 0x21U, 0x00U, 0x20U, 0x0AU, 0x28U, 0x02U, 0x00U, 0x21U, + 0x0BU, 0x20U, 0x0BU, 0x20U, 0x00U, 0x3AU, 0x00U, 0x00U, 0x20U, 0x0AU, + 0x28U, 0x02U, 0x0CU, 0x21U, 0x00U, 0x20U, 0x00U, 0xADU, 0x21U, 0x01U, + 0x20U, 0x01U, 0x42U, 0x10U, 0x88U, 0x21U, 0x01U, 0x20U, 0x01U, 0x42U, + 0xFFU, 0x01U, 0x83U, 0x21U, 0x01U, 0x20U, 0x01U, 0xA7U, 0x21U, 0x00U, + 0x20U, 0x0AU, 0x28U, 0x02U, 0x00U, 0x21U, 0x0BU, 0x20U, 0x0BU, 0x20U, + 0x00U, 0x3AU, 0x00U, 0x01U, 0x20U, 0x0AU, 0x28U, 0x02U, 0x0CU, 0x21U, + 0x00U, 0x20U, 0x00U, 0xADU, 0x21U, 0x01U, 0x20U, 0x01U, 0x42U, 0x08U, + 0x88U, 0x21U, 0x01U, 0x20U, 0x01U, 0x42U, 0xFFU, 0x01U, 0x83U, 0x21U, + 0x01U, 0x20U, 0x01U, 0xA7U, 0x21U, 0x00U, 0x20U, 0x0AU, 0x28U, 0x02U, + 0x00U, 0x21U, 0x0BU, 0x20U, 0x0BU, 0x20U, 0x00U, 0x3AU, 0x00U, 0x02U, + 0x20U, 0x0AU, 0x28U, 0x02U, 0x0CU, 0x21U, 0x00U, 0x20U, 0x00U, 0xADU, + 0x21U, 0x01U, 0x20U, 0x01U, 0x42U, 0x00U, 0x88U, 0x21U, 0x01U, 0x20U, + 0x01U, 0x42U, 0xFFU, 0x01U, 0x83U, 0x21U, 0x01U, 0x20U, 0x01U, 0xA7U, + 0x21U, 0x00U, 0x20U, 0x0AU, 0x28U, 0x02U, 0x00U, 0x21U, 0x0BU, 0x20U, + 0x0BU, 0x20U, 0x00U, 0x3AU, 0x00U, 0x03U, 0x20U, 0x0CU, 0x21U, 0x00U, + 0x20U, 0x00U, 0x41U, 0x04U, 0x42U, 0x1CU, 0x10U, 0x03U, 0x21U, 0x08U, + 0x20U, 0x08U, 0x1AU, 0x41U, 0x01U, 0x41U, 0x01U, 0x10U, 0x04U, 0x21U, + 0x0DU, 0x20U, 0x0DU, 0x1AU, 0x20U, 0x0AU, 0x41U, 0x10U, 0x6AU, 0x21U, + 0x00U, 0x20U, 0x00U, 0x24U, 0x00U, 0x42U, 0x00U, 0x21U, 0x09U, 0x42U, + 0x00U, 0x0BU, 0x0BU, 0x0BU, 0x0BU, 0x0BU, 0xC3U, 0x03U, 0x01U, 0x00U, + 0x41U, 0x80U, 0x08U, 0x0BU, 0xBBU, 0x03U, 0x74U, 0x73U, 0x68U, 0x2EU, + 0x63U, 0x3AU, 0x20U, 0x57U, 0x65U, 0x61U, 0x6BU, 0x20U, 0x41U, 0x67U, + 0x61U, 0x69U, 0x6EU, 0x2EU, 0x20U, 0x45U, 0x78U, 0x65U, 0x63U, 0x75U, + 0x74U, 0x65U, 0x20U, 0x41U, 0x46U, 0x54U, 0x45U, 0x52U, 0x20U, 0x74U, + 0x72U, 0x61U, 0x6EU, 0x73U, 0x61U, 0x63U, 0x74U, 0x69U, 0x6FU, 0x6EU, + 0x20U, 0x69U, 0x73U, 0x20U, 0x61U, 0x70U, 0x70U, 0x6CU, 0x69U, 0x65U, + 0x64U, 0x20U, 0x74U, 0x6FU, 0x20U, 0x6CU, 0x65U, 0x64U, 0x67U, 0x65U, + 0x72U, 0x00U, 0x74U, 0x73U, 0x68U, 0x2EU, 0x63U, 0x3AU, 0x20U, 0x57U, + 0x65U, 0x61U, 0x6BU, 0x2EU, 0x20U, 0x45U, 0x78U, 0x65U, 0x63U, 0x75U, + 0x74U, 0x65U, 0x20U, 0x41U, 0x46U, 0x54U, 0x45U, 0x52U, 0x20U, 0x74U, + 0x72U, 0x61U, 0x6EU, 0x73U, 0x61U, 0x63U, 0x74U, 0x69U, 0x6FU, 0x6EU, + 0x20U, 0x69U, 0x73U, 0x20U, 0x61U, 0x70U, 0x70U, 0x6CU, 0x69U, 0x65U, + 0x64U, 0x20U, 0x74U, 0x6FU, 0x20U, 0x6CU, 0x65U, 0x64U, 0x67U, 0x65U, + 0x72U, 0x00U, 0x74U, 0x73U, 0x68U, 0x2EU, 0x63U, 0x3AU, 0x20U, 0x53U, + 0x74U, 0x72U, 0x6FU, 0x6EU, 0x67U, 0x2EU, 0x20U, 0x45U, 0x78U, 0x65U, + 0x63U, 0x75U, 0x74U, 0x65U, 0x20U, 0x42U, 0x45U, 0x46U, 0x4FU, 0x52U, + 0x45U, 0x20U, 0x74U, 0x72U, 0x61U, 0x6EU, 0x73U, 0x61U, 0x63U, 0x74U, + 0x69U, 0x6FU, 0x6EU, 0x20U, 0x69U, 0x73U, 0x20U, 0x61U, 0x70U, 0x70U, + 0x6CU, 0x69U, 0x65U, 0x64U, 0x20U, 0x74U, 0x6FU, 0x20U, 0x6CU, 0x65U, + 0x64U, 0x67U, 0x65U, 0x72U, 0x00U, 0x41U, 0x41U, 0x57U, 0x00U, 0x74U, + 0x73U, 0x68U, 0x2EU, 0x63U, 0x3AU, 0x20U, 0x53U, 0x74U, 0x61U, 0x72U, + 0x74U, 0x2EU, 0x00U, 0x74U, 0x73U, 0x68U, 0x2EU, 0x63U, 0x3AU, 0x20U, + 0x45U, 0x6EU, 0x64U, 0x2EU, 0x00U, 0x22U, 0x74U, 0x73U, 0x68U, 0x2EU, + 0x63U, 0x3AU, 0x20U, 0x57U, 0x65U, 0x61U, 0x6BU, 0x20U, 0x41U, 0x67U, + 0x61U, 0x69U, 0x6EU, 0x2EU, 0x20U, 0x45U, 0x78U, 0x65U, 0x63U, 0x75U, + 0x74U, 0x65U, 0x20U, 0x41U, 0x46U, 0x54U, 0x45U, 0x52U, 0x20U, 0x74U, + 0x72U, 0x61U, 0x6EU, 0x73U, 0x61U, 0x63U, 0x74U, 0x69U, 0x6FU, 0x6EU, + 0x20U, 0x69U, 0x73U, 0x20U, 0x61U, 0x70U, 0x70U, 0x6CU, 0x69U, 0x65U, + 0x64U, 0x20U, 0x74U, 0x6FU, 0x20U, 0x6CU, 0x65U, 0x64U, 0x67U, 0x65U, + 0x72U, 0x22U, 0x00U, 0x22U, 0x74U, 0x73U, 0x68U, 0x2EU, 0x63U, 0x3AU, + 0x20U, 0x57U, 0x65U, 0x61U, 0x6BU, 0x2EU, 0x20U, 0x45U, 0x78U, 0x65U, + 0x63U, 0x75U, 0x74U, 0x65U, 0x20U, 0x41U, 0x46U, 0x54U, 0x45U, 0x52U, + 0x20U, 0x74U, 0x72U, 0x61U, 0x6EU, 0x73U, 0x61U, 0x63U, 0x74U, 0x69U, + 0x6FU, 0x6EU, 0x20U, 0x69U, 0x73U, 0x20U, 0x61U, 0x70U, 0x70U, 0x6CU, + 0x69U, 0x65U, 0x64U, 0x20U, 0x74U, 0x6FU, 0x20U, 0x6CU, 0x65U, 0x64U, + 0x67U, 0x65U, 0x72U, 0x22U, 0x00U, 0x22U, 0x74U, 0x73U, 0x68U, 0x2EU, + 0x63U, 0x3AU, 0x20U, 0x53U, 0x74U, 0x72U, 0x6FU, 0x6EU, 0x67U, 0x2EU, + 0x20U, 0x45U, 0x78U, 0x65U, 0x63U, 0x75U, 0x74U, 0x65U, 0x20U, 0x42U, + 0x45U, 0x46U, 0x4FU, 0x52U, 0x45U, 0x20U, 0x74U, 0x72U, 0x61U, 0x6EU, + 0x73U, 0x61U, 0x63U, 0x74U, 0x69U, 0x6FU, 0x6EU, 0x20U, 0x69U, 0x73U, + 0x20U, 0x61U, 0x70U, 0x70U, 0x6CU, 0x69U, 0x65U, 0x64U, 0x20U, 0x74U, + 0x6FU, 0x20U, 0x6CU, 0x65U, 0x64U, 0x67U, 0x65U, 0x72U, 0x22U, 0x00U, + 0x22U, 0x74U, 0x73U, 0x68U, 0x2EU, 0x63U, 0x3AU, 0x20U, 0x53U, 0x74U, + 0x61U, 0x72U, 0x74U, 0x2EU, 0x22U, 0x00U, 0x22U, 0x74U, 0x73U, 0x68U, + 0x2EU, 0x63U, 0x3AU, 0x20U, 0x45U, 0x6EU, 0x64U, 0x2EU, 0x22U}; void addWeakTSH(jtx::Env& env, jtx::Account const& account) @@ -151,7 +428,21 @@ private: using namespace test::jtx; auto const tshFlag = testStrong ? overrideFlag : collectFlag; env(hook(account, {{hso(TshHook, tshFlag)}}, 0), - fee(XRP(1)), + fee(XRP(2)), + ter(tesSUCCESS)); + env.close(); + } + + void + setCallbackHook( + jtx::Env& env, + jtx::Account const& account, + bool const& testStrong) + { + using namespace test::jtx; + auto const tshFlag = testStrong ? overrideFlag : collectFlag; + env(hook(account, {{hso(CallbackHook, tshFlag)}}, 0), + fee(XRP(2)), ter(tesSUCCESS)); env.close(); } @@ -219,6 +510,22 @@ private: } } + void + validateTSHFlags(jtx::Env& env, Json::Value meta, uint32_t const& expected) + { + auto const executions = meta[sfHookExecutions.jsonName]; + auto const execution = executions[0u][sfHookExecution.jsonName]; + bool const fixV2 = env.current()->rules().enabled(fixXahauV2); + if (fixV2) + { + BEAST_EXPECT(execution[sfFlags.jsonName] == expected); + } + else + { + BEAST_REQUIRE(!execution[sfFlags.jsonName]); + } + } + void testTSHStrongWeak( jtx::Env& env, @@ -1776,7 +2083,7 @@ private: {{hso(TshHook, overrideFlag), hso(genesis::MintTestHook, overrideFlag)}}, 0), - fee(XRP(1)), + fee(XRP(2)), ter(tesSUCCESS)); env.close(); @@ -1960,7 +2267,11 @@ private: env.close(); // verify tsh hook triggered - testTSHStrongWeak(env, tshSTRONG, __LINE__); + bool const fixV2 = env.current()->rules().enabled(fixXahauV2); + auto const expected = + (fixV2 ? (testStrong ? tshNONE : tshWEAK) + : (testStrong ? tshSTRONG : tshSTRONG)); + testTSHStrongWeak(env, expected, __LINE__); } } @@ -2159,9 +2470,14 @@ private: auto const USD = gw["USD"]; env.fund(XRP(1000), account, cross, gw); env.close(); + env.trust(USD(100000), account); + env.trust(USD(100000), cross); + env.close(); + env(pay(gw, cross, USD(10000))); + env.close(); // gw create offer - env(offer(gw, USD(1000), XRP(1000))); + env(offer(cross, XRP(1000), USD(1000))); env.close(); // set tsh collect @@ -2178,7 +2494,8 @@ private: env.close(); // verify tsh hook triggered - testTSHStrongWeak(env, tshNONE, __LINE__); + auto const expected = testStrong ? tshNONE : tshWEAK; + testTSHStrongWeak(env, expected, __LINE__); } } @@ -3024,16 +3341,16 @@ private: // | otxn | tfBurnable | tsh | mint | burn | buy | sell | cancel // | O | false | O | N/A | S | N/A | S | S // | O | false | I | N/A | N | N/A | W | N/A - // | O | false | B | N/A | N/A | N/A | N | N/A - // | O | true | B | N/A | N/A | N/A | N | N/A + // | O | false | B | N/A | N/A | N/A | N | N + // | O | true | B | N/A | N/A | N/A | N | N // | O | true | O | N/A | S | N/A | S | S // | O | true | I | N/A | N | N/A | S | N/A // | I | false | O | N/A | N/A | N/A | N/A | N/A // | I | false | I | S | N/A | N/A | N/A | N/A - // | I | false | B | N | N/A | N/A | N/A | N/A + // | I | false | B | S | N/A | N/A | N/A | N/A // | I | true | O | N/A | N | N/A | N/A | N/A // | I | true | I | S | S | N/A | N/A | N/A - // | I | true | B | N | N/A | N/A | N/A | N/A + // | I | true | B | S | N/A | N/A | N/A | N/A // | B | true | O | N/A | N/A | S | N/A | N/A // | B | true | B | N/A | N/A | S | N/A | N/A // | B | false | I | N/A | N/A | W | N/A | N/A @@ -3089,7 +3406,7 @@ private: // otxn: issuer // flag: not burnable // tsh buyer - // w/s: none + // w/s: strong for (bool const testStrong : {true, false}) { test::jtx::Env env{ @@ -3122,7 +3439,11 @@ private: env.close(); // verify tsh hook triggered - testTSHStrongWeak(env, tshNONE, __LINE__); + bool const fixV2 = env.current()->rules().enabled(fixXahauV2); + auto const expected = + (fixV2 ? (testStrong ? tshSTRONG : tshSTRONG) + : (testStrong ? tshNONE : tshNONE)); + testTSHStrongWeak(env, expected, __LINE__); } // otxn: issuer @@ -3168,7 +3489,7 @@ private: // otxn: issuer // flag: burnable // tsh buyer - // w/s: none + // w/s: strong for (bool const testStrong : {true, false}) { test::jtx::Env env{ @@ -3202,7 +3523,11 @@ private: env.close(); // verify tsh hook triggered - testTSHStrongWeak(env, tshNONE, __LINE__); + bool const fixV2 = env.current()->rules().enabled(fixXahauV2); + auto const expected = + (fixV2 ? (testStrong ? tshSTRONG : tshSTRONG) + : (testStrong ? tshNONE : tshNONE)); + testTSHStrongWeak(env, expected, __LINE__); } } @@ -4351,133 +4676,11 @@ private: env.fund(XRP(1000), account, dest); env.close(); - auto setHook = [](test::jtx::Account const& account) { - std::string const createCodeHex = - "0061736D0100000001350860057F7F7F7F7F017E60017F017E60047F7F7F7F" - "017E60037F7F7E017E60027F7F017E60037F7F7F017E60027F7F017F600001" - "7E02CD010D03656E76057472616365000003656E760C6574786E5F72657365" - "727665000103656E760A7574696C5F6163636964000203656E760974726163" - "655F6E756D000303656E760C686F6F6B5F6163636F756E74000403656E760A" - "6F74786E5F6669656C64000503656E7608726F6C6C6261636B000303656E76" - "025F67000603656E7606616363657074000303656E760A6C65646765725F73" - "6571000703656E760C6574786E5F64657461696C73000403656E760D657478" - "6E5F6665655F62617365000403656E7604656D697400020303020101050301" - "0002062B077F0141C08C040B7F004180080B7F0041B40C0B7F004180080B7F" - "0041C08C040B7F0041000B7F0041010B070F02046362616B000D04686F6F6B" - "000E0AE1930002AC800001017F230041106B220124002001200036020C41F6" - "0B411A41B70A4119410010001A200141106A240042000BAE930002017F017C" - "230041B0056B22012400200120003602AC0541E40B411141840A4110410010" - "001A410110011A200120014190056A411441940A4123100237038805418C08" - "410320012903880510031A200141F0046A411410041A2001200141D0046A41" - "144181802010053E02CC0441E409411120013402CC0410031A20012802CC04" - "411448044041910C4123420110061A0B200141003602C804200141013602C8" - "04200141003602C4040340418180B48178411510071A4100210020012802C8" - "04047F20012802C4044114480520000B4101710440200120012802C4042001" - "41F0046A6A2D000020012802C404200141D0046A6A2D0000463602C8042001" - "20012802C40441016A3602C4040C010B0B20012802C804450440419B08411D" - "420210081A0B200120014190046A413041818018100537038804200142C084" - "3D370380040240200129038804420852044041D00A41CE0041D40841CD0041" - "0010001A0C010B419F0B41C40041A10941C300410010001A200120012D0090" - "04410776047E427E052001310097042001310090044291A2C480B001834238" - "862001310091044230867C2001310092044228867C2001310093044220867C" - "2001310094044218867C2001310095044210867C2001310096044208867C7C" - "0B3703F803419008410A20012903F80310031A20012903F80342A08D065504" - "402001027E20012903F803B94400000040E17A843FA2220299440000000000" - "00E0436304402002B00C010B428080808080808080807F0B370380040B0B41" - "F609410D20012903800410031A2001200141E0016A3602DC01200120012903" - "80043703B801200141003602B401200141003602B001200110093E02AC0120" - "0141C0016A411410041A200141003A00AB0120012802DC0141123A00002001" - "2802DC0120012D00AB014108763A000120012802DC0120012D00AB013A0002" - "200120012802DC0141036A3602DC0120014180808080783602A40120014102" - "3A00A30120012802DC0120012D00A301410F7141206A3A000020012802DC01" - "20012802A4014118763A000120012802DC0120012802A4014110763A000220" - "012802DC0120012802A4014108763A000320012802DC0120012802A4013A00" - "04200120012802DC0141056A3602DC01200120012802B00136029C01200141" - "033A009B0120012802DC0120012D009B01410F7141206A3A000020012802DC" - "01200128029C014118763A000120012802DC01200128029C014110763A0002" - "20012802DC01200128029C014108763A000320012802DC01200128029C013A" - "0004200120012802DC0141056A3602DC012001410036029401200141043A00" - "930120012802DC0120012D009301410F7141206A3A000020012802DC012001" - "280294014118763A000120012802DC012001280294014110763A0002200128" - "02DC012001280294014108763A000320012802DC012001280294013A000420" - "0120012802DC0141056A3602DC01200120012802B40136028C012001410E3A" - "008B0120012802DC0120012D008B01410F7141206A3A000020012802DC0120" - "0128028C014118763A000120012802DC01200128028C014110763A00022001" - "2802DC01200128028C014108763A000320012802DC01200128028C013A0004" - "200120012802DC0141056A3602DC01200120012802AC0141016A3602840120" - "01411A3A00830120012802DC0141203A000020012802DC0120012D0083013A" - "000120012802DC012001280284014118763A000220012802DC012001280284" - "014110763A000320012802DC012001280284014108763A000420012802DC01" - "2001280284013A0005200120012802DC0141066A3602DC01200120012802AC" - "0141056A36027C2001411B3A007B20012802DC0141203A000020012802DC01" - "20012D007B3A000120012802DC01200128027C4118763A000220012802DC01" - "200128027C4110763A000320012802DC01200128027C4108763A0004200128" - "02DC01200128027C3A0005200120012802DC0141066A3602DC01200141013A" - "007A200120012903B80137037020012802DC0120012D007A410F7141E0006A" - "3A000020012802DC012001290370423888423F8342407D3C000120012802DC" - "01200129037042308842FF01833C000220012802DC01200129037042288842" - "FF01833C000320012802DC01200129037042208842FF01833C000420012802" - "DC01200129037042188842FF01833C000520012802DC012001290370421088" - "42FF01833C000620012802DC01200129037042088842FF01833C0007200128" - "02DC01200129037042FF01833C0008200120012802DC0141096A3602DC0120" - "0120012802DC0136026C200141083A006B2001420037036020012802DC0120" - "012D006B410F7141E0006A3A000020012802DC012001290360423888423F83" - "42407D3C000120012802DC01200129036042308842FF01833C000220012802" - "DC01200129036042288842FF01833C000320012802DC012001290360422088" - "42FF01833C000420012802DC01200129036042188842FF01833C0005200128" - "02DC01200129036042108842FF01833C000620012802DC0120012903604208" - "8842FF01833C000720012802DC01200129036042FF01833C00082001200128" - "02DC0141096A3602DC0120012802DC0141F3003A000020012802DC0141213A" - "000120012802DC01420037030220012802DC01420037030A20012802DC0142" - "0037031220012802DC014200370319200120012802DC0141236A3602DC0120" - "0141013A005F20012802DC0120012D005F4180016A3A000020012802DC0141" - "143A000120012802DC0120012903C00137030220012802DC0120012903C801" - "37030A20012802DC0120012802D001360212200120012802DC0141166A3602" - "DC01200141033A005E20012802DC0120012D005E4180016A3A000020012802" - "DC0141143A000120012802DC0120012903900537030220012802DC01200129" - "03980537030A20012802DC0120012802A005360212200120012802DC014116" - "6A3602DC01200120012802DC01418E02100A3703502001200141E0016A418E" - "02100B370348200141083A004720012001290348370338200128026C20012D" - "0047410F7141E0006A3A0000200128026C2001290338423888423F8342407D" - "3C0001200128026C200129033842308842FF01833C0002200128026C200129" - "033842288842FF01833C0003200128026C200129033842208842FF01833C00" - "04200128026C200129033842188842FF01833C0005200128026C2001290338" - "42108842FF01833C0006200128026C200129033842088842FF01833C000720" - "0128026C200129033842FF01833C00082001200128026C41096A36026C2001" - "200141106A4120200141E0016A418E02100C370308418008410B2001290308" - "10031A41B808411C420010081A200141B0056A240042000B0BBB0401004180" - "080BB304656D69745F726573756C7400726574006F74786E5F64726F707300" - "436172626F6E3A20496E636F6D696E67207472616E73616374696F6E004361" - "72626F6E3A20456D6974746564207472616E73616374696F6E00436172626F" - "6E3A204E6F6E2D787270207472616E73616374696F6E206465746563746564" - "2C2073656E64696E672064656661756C7420313030302064726F707320746F" - "207266436172626F6E00436172626F6E3A20585250207472616E7361637469" - "6F6E2064657465637465642C20636F6D707574696E6720312520746F207365" - "6E6420746F207266436172626F6E006163636F756E745F6669656C645F6C65" - "6E0064726F70735F746F5F73656E6400436172626F6E3A2073746172746564" - "0072504D68375069396374363939695A5554576179744A556F48634A376367" - "797A694B00436172626F6E3A2063616C6C6261636B2063616C6C65642E0022" - "436172626F6E3A204E6F6E2D787270207472616E73616374696F6E20646574" - "65637465642C2073656E64696E672064656661756C7420313030302064726F" - "707320746F207266436172626F6E220022436172626F6E3A20585250207472" - "616E73616374696F6E2064657465637465642C20636F6D707574696E672031" - "2520746F2073656E6420746F207266436172626F6E220022436172626F6E3A" - "2073746172746564220022436172626F6E3A2063616C6C6261636B2063616C" - "6C65642E2200436172626F6E3A2073664163636F756E74206669656C64206D" - "697373696E67212121"; - Json::Value jhv = hso(createCodeHex); - jhv[jss::HookOn] = - "fffffffffffffffffffffffffffffffffffffff7ffffffffffffffffffbfff" - "ff"; - Json::Value jv = ripple::test::jtx::hook(account, {{jhv}}, 0); - return jv; - }; - - env(setHook(account), HSFEE); - env.close(); + // set emit hook + setCallbackHook(env, account, true); // ttINVOKE - env(invoke::invoke(account), fee(XRP(1)), ter(tesSUCCESS)); + env(invoke::invoke(account), fee(XRP(2)), ter(tesSUCCESS)); env.close(); Blob txBlob; @@ -4546,6 +4749,188 @@ private: BEAST_EXPECT(postDest1 == postDest + postValue1); } + void + testEmittedFlags(FeatureBitset features) + { + testcase("emitted flags"); + + using namespace test::jtx; + using namespace std::literals; + + // weak + { + test::jtx::Env env{ + *this, + network::makeNetworkConfig(21337, "10", "1000000", "200000"), + features}; + + auto const account = Account("alice"); + auto const issuer = Account{"gw"}; + auto const USD = issuer["USD"]; + env.fund(XRP(1000), account, issuer); + env.close(); + + addWeakTSH(env, issuer); + + // set tsh hook + setTSHHook(env, issuer, false); + + // trust set + env(trust(account, USD(1000)), fee(XRP(1)), ter(tesSUCCESS)); + env.close(); + + // verify tsh hook triggered + Json::Value params; + params[jss::transaction] = + env.tx()->getJson(JsonOptions::none)[jss::hash]; + auto const jrr = env.rpc("json", "tx", to_string(params)); + auto const meta = jrr[jss::result][jss::meta]; + validateTSHFlags(env, meta, 0); + } + + // strong + { + test::jtx::Env env{ + *this, + network::makeNetworkConfig(21337, "10", "1000000", "200000"), + features}; + + auto const account = Account("alice"); + auto const issuer = Account{"gw"}; + auto const USD = issuer["USD"]; + env.fund(XRP(1000), account, issuer); + env.close(); + + // set tsh hook + setTSHHook(env, account, true); + + // trust set + env(trust(account, USD(1000)), fee(XRP(1)), ter(tesSUCCESS)); + env.close(); + + // verify tsh hook triggered + Json::Value params; + params[jss::transaction] = + env.tx()->getJson(JsonOptions::none)[jss::hash]; + auto const jrr = env.rpc("json", "tx", to_string(params)); + auto const meta = jrr[jss::result][jss::meta]; + validateTSHFlags(env, meta, 1); + } + + // callback + { + test::jtx::Env env{ + *this, + network::makeNetworkConfig(21337, "10", "1000000", "200000"), + features}; + + auto const account = Account("alice"); + env.fund(XRP(1000), account); + env.close(); + + // set tsh hook + setCallbackHook(env, account, true); + + // invoke + env(invoke::invoke(account), fee(XRP(2)), ter(tesSUCCESS)); + env.close(); + + // get the emitted txn id + Json::Value params; + params[jss::transaction] = + env.tx()->getJson(JsonOptions::none)[jss::hash]; + auto const jrr = env.rpc("json", "tx", to_string(params)); + auto const meta = jrr[jss::result][jss::meta]; + auto const emissions = meta[sfHookEmissions.jsonName]; + auto const emission = emissions[0u][sfHookEmission.jsonName]; + auto const txId = emission[sfEmittedTxnID.jsonName]; + env.close(); + + // verify tsh hook triggered + Json::Value params1; + params1[jss::transaction] = txId; + auto const jrr1 = env.rpc("json", "tx", to_string(params1)); + auto const meta1 = jrr1[jss::result][jss::meta]; + validateTSHFlags(env, meta1, 2); + } + + // weak callback + { + test::jtx::Env env{ + *this, + network::makeNetworkConfig(21337, "10", "1000000", "200000"), + features}; + + auto const account = Account("alice"); + auto const issuer = Account{"gw"}; + auto const USD = issuer["USD"]; + env.fund(XRP(1000), account, issuer); + env.close(); + + addWeakTSH(env, issuer); + + // set tsh hook + setCallbackHook(env, issuer, false); + + // trust set + env(trust(account, USD(1000)), fee(XRP(1)), ter(tesSUCCESS)); + env.close(); + + // get the emitted txn id + Json::Value params; + params[jss::transaction] = + env.tx()->getJson(JsonOptions::none)[jss::hash]; + auto const jrr = env.rpc("json", "tx", to_string(params)); + auto const meta = jrr[jss::result][jss::meta]; + auto const emissions = meta[sfHookEmissions.jsonName]; + auto const emission = emissions[0u][sfHookEmission.jsonName]; + auto const txId = emission[sfEmittedTxnID.jsonName]; + env.close(); + + // verify tsh hook triggered + Json::Value params1; + params1[jss::transaction] = txId; + auto const jrr1 = env.rpc("json", "tx", to_string(params1)); + auto const meta1 = jrr1[jss::result][jss::meta]; + validateTSHFlags(env, meta1, 2); + } + + // again as weak + { + test::jtx::Env env{ + *this, + network::makeNetworkConfig(21337, "10", "1000000", "200000"), + features}; + + auto const account = Account("alice"); + env.fund(XRP(1000), account); + env.close(); + + // set tsh hook + setTSHHook(env, account, true); + + // invoke + auto tx = invoke::invoke(account); + tx[jss::HookParameters] = Json::Value{Json::arrayValue}; + tx[jss::HookParameters][0U] = Json::Value{}; + tx[jss::HookParameters][0U][jss::HookParameter] = Json::Value{}; + tx[jss::HookParameters][0U][jss::HookParameter] + [jss::HookParameterName] = "414157"; + tx[jss::HookParameters][0U][jss::HookParameter] + [jss::HookParameterValue] = "01"; + env(tx, fee(XRP(2)), ter(tesSUCCESS)); + env.close(); + + // verify tsh hook triggered + Json::Value params; + params[jss::transaction] = + env.tx()->getJson(JsonOptions::none)[jss::hash]; + auto const jrr = env.rpc("json", "tx", to_string(params)); + auto const meta = jrr[jss::result][jss::meta]; + validateTSHFlags(env, meta, 5); + } + } + void testTSH(FeatureBitset features) { @@ -4586,6 +4971,7 @@ private: testEmittedTxn(FeatureBitset features) { testEmittedTxnReliability(features); + testEmittedFlags(features); } public: @@ -4594,7 +4980,8 @@ public: { using namespace test::jtx; auto const sa = supported_amendments(); - testTSH(sa - fixXahauV1); + testTSH(sa - fixXahauV1 - fixXahauV2); + testTSH(sa - fixXahauV2); testTSH(sa); testEmittedTxn(sa - fixXahauV2); testEmittedTxn(sa); diff --git a/src/test/app/SetHook_test.cpp b/src/test/app/SetHook_test.cpp index f75c7c876..11dcb02eb 100644 --- a/src/test/app/SetHook_test.cpp +++ b/src/test/app/SetHook_test.cpp @@ -90,72 +90,65 @@ public: #define HSFEE fee(100'000'000) #define M(m) memo(m, "", "") void - testHooksOwnerDir() + testHooksOwnerDir(FeatureBitset features) { testcase("Test owner directory"); using namespace jtx; - for (bool const withXahauV1 : {true, false}) + Env env{*this, features}; + + auto const alice = Account{"alice"}; + auto const gw = Account{"gateway"}; + auto const USD = gw["USD"]; + env.fund(XRP(10000), alice, gw); + env.close(); + env.trust(USD(100000), alice); + env.close(); + env(pay(gw, alice, USD(10000))); + + for (int i = 1; i < 34; ++i) { - auto const amend = withXahauV1 - ? supported_amendments() - : supported_amendments() - fixXahauV1; - - Env env{*this, amend}; - - auto const alice = Account{"alice"}; - auto const gw = Account{"gateway"}; - auto const USD = gw["USD"]; - env.fund(XRP(10000), alice, gw); - env.close(); - env.trust(USD(100000), alice); - env.close(); - env(pay(gw, alice, USD(10000))); - - for (int i = 1; i < 34; ++i) - { - std::string const uri(i, '?'); - env(uritoken::mint(alice, uri)); - } - env.close(); - - env(ripple::test::jtx::hook( - alice, {{hso(accept_wasm, overrideFlag)}}, 0), - HSFEE, - ter(tesSUCCESS)); - env.close(); - - env(ripple::test::jtx::hook( - alice, {{hso(accept_wasm, overrideFlag)}}, 0), - HSFEE, - ter(tesSUCCESS)); - env.close(); - - // delete 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::Flags] = 1; - iv[jss::CreateCode] = ""; - jv[jss::Hooks][0U][jss::Hook] = iv; - - auto const txResult = - withXahauV1 ? ter(tesSUCCESS) : ter(tefBAD_LEDGER); - env(jv, HSFEE, txResult); - env.close(); + std::string const uri(i, '?'); + env(uritoken::mint(alice, uri)); } + env.close(); + + env(ripple::test::jtx::hook( + alice, {{hso(accept_wasm, overrideFlag)}}, 0), + HSFEE, + ter(tesSUCCESS)); + env.close(); + + env(ripple::test::jtx::hook( + alice, {{hso(accept_wasm, overrideFlag)}}, 0), + HSFEE, + ter(tesSUCCESS)); + env.close(); + + // delete 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::Flags] = 1; + iv[jss::CreateCode] = ""; + jv[jss::Hooks][0U][jss::Hook] = iv; + + bool const fixV1 = env.current()->rules().enabled(fixXahauV1); + auto const txResult = fixV1 ? ter(tesSUCCESS) : ter(tefBAD_LEDGER); + env(jv, HSFEE, txResult); + env.close(); } void - testHooksDisabled() + testHooksDisabled(FeatureBitset features) { testcase("Check for disabled amendment"); using namespace jtx; - Env env{*this, supported_amendments() - featureHooks}; + Env env{*this, features - featureHooks}; auto const alice = Account{"alice"}; env.fund(XRP(10000), alice); @@ -169,11 +162,11 @@ public: } void - testTxStructure() + testTxStructure(FeatureBitset features) { testcase("Checks malformed transactions"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const alice = Account{"alice"}; env.fund(XRP(10000), alice); @@ -230,11 +223,11 @@ public: } void - testGrants() + testGrants(FeatureBitset features) { testcase("Checks malformed grants on install operation"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const alice = Account{"alice"}; env.fund(XRP(10000), alice); @@ -288,11 +281,11 @@ public: } void - testParams() + testParams(FeatureBitset features) { testcase("Checks malformed params on install operation"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const alice = Account{"alice"}; env.fund(XRP(10000), alice); @@ -410,11 +403,11 @@ public: } void - testInstall() + testInstall(FeatureBitset features) { testcase("Checks malformed install operation"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const alice = Account{"alice"}; env.fund(XRP(10000), alice); @@ -503,11 +496,11 @@ public: } void - testDelete() + testDelete(FeatureBitset features) { testcase("Checks malformed delete operation"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const alice = Account{"alice"}; env.fund(XRP(10000), alice); @@ -690,11 +683,11 @@ public: } void - testNSDelete() + testNSDelete(FeatureBitset features) { testcase("Checks malformed nsdelete operation"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const alice = Account{"alice"}; env.fund(XRP(10000), alice); @@ -809,11 +802,11 @@ public: } void - testCreate() + testCreate(FeatureBitset features) { testcase("Checks malformed create operation"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const bob = Account{"bob"}; env.fund(XRP(10000), bob); @@ -1051,11 +1044,11 @@ public: } void - testUpdate() + testUpdate(FeatureBitset features) { testcase("Checks malformed update operation"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const alice = Account{"alice"}; env.fund(XRP(10000), alice); @@ -1621,12 +1614,12 @@ public: } void - testWithTickets() + testWithTickets(FeatureBitset features) { testcase("with tickets"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const alice = Account{"alice"}; env.fund(XRP(10000), alice); @@ -1706,11 +1699,11 @@ public: } void - testWasm() + testWasm(FeatureBitset features) { testcase("Checks malformed hook binaries"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const alice = Account{"alice"}; env.fund(XRP(10000), alice); @@ -1727,11 +1720,11 @@ public: } void - test_accept() + test_accept(FeatureBitset features) { testcase("Test accept() hookapi"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const alice = Account{"alice"}; auto const bob = Account{"bob"}; @@ -1748,11 +1741,11 @@ public: } void - test_rollback() + test_rollback(FeatureBitset features) { testcase("Test rollback() hookapi"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const bob = Account{"bob"}; auto const alice = Account{"alice"}; @@ -1772,11 +1765,11 @@ public: } void - testGuards() + testGuards(FeatureBitset features) { testcase("Test guards"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const alice = Account{"alice"}; auto const bob = Account{"bob"}; @@ -1983,16 +1976,12 @@ public: } void - test_emit() + test_emit(FeatureBitset features) { testcase("Test float_emit"); using namespace jtx; Env env{ - *this, - envconfig(), - supported_amendments(), - nullptr, - beast::severities::kWarning + *this, envconfig(), features, nullptr, beast::severities::kWarning // beast::severities::kTrace }; @@ -2341,6 +2330,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 @@ -2349,6 +2340,13 @@ public: 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); @@ -2392,6 +2390,8 @@ public: } BEAST_REQUIRE(emithash); + BEAST_EXPECT( + emithash == hookEmissions[0u].getFieldH256(sfEmittedTxnID)); } { @@ -2438,6 +2438,8 @@ public: 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; @@ -2461,6 +2463,8 @@ public: 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); } @@ -2477,13 +2481,13 @@ public: } void - test_etxn_details() + test_etxn_details(FeatureBitset features) { // mainly tested in test_emit testcase("Test etxn_details"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const alice = Account{"alice"}; auto const bob = Account{"bob"}; @@ -2535,13 +2539,13 @@ public: } void - test_etxn_fee_base() + test_etxn_fee_base(FeatureBitset features) { // mainly tested in test_emit testcase("Test etxn_fee_base"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const alice = Account{"alice"}; auto const bob = Account{"bob"}; @@ -2592,13 +2596,13 @@ public: } void - test_etxn_nonce() + test_etxn_nonce(FeatureBitset features) { // mainly tested in test_emit testcase("Test etxn_nonce"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const alice = Account{"alice"}; auto const bob = Account{"bob"}; @@ -2656,13 +2660,13 @@ public: } void - test_etxn_reserve() + test_etxn_reserve(FeatureBitset features) { // mainly tested in test_emit testcase("Test etxn_reserve"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const alice = Account{"alice"}; auto const bob = Account{"bob"}; @@ -2706,12 +2710,12 @@ public: } void - test_fee_base() + test_fee_base(FeatureBitset features) { testcase("Test fee_base"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const alice = Account{"alice"}; auto const bob = Account{"bob"}; @@ -2747,11 +2751,11 @@ public: } void - test_float_compare() + test_float_compare(FeatureBitset features) { testcase("Test float_compare"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const alice = Account{"alice"}; auto const bob = Account{"bob"}; @@ -2880,11 +2884,11 @@ public: } void - test_float_divide() + test_float_divide(FeatureBitset features) { testcase("Test float_divide"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const alice = Account{"alice"}; auto const bob = Account{"bob"}; @@ -3079,11 +3083,11 @@ public: } void - test_float_int() + test_float_int(FeatureBitset features) { testcase("Test float_int"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const alice = Account{"alice"}; auto const bob = Account{"bob"}; @@ -3208,11 +3212,11 @@ public: } void - test_float_invert() + test_float_invert(FeatureBitset features) { testcase("Test float_invert"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const alice = Account{"alice"}; auto const bob = Account{"bob"}; @@ -3296,11 +3300,11 @@ public: } void - test_float_log() + test_float_log(FeatureBitset features) { testcase("Test float_log"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const alice = Account{"alice"}; auto const bob = Account{"bob"}; @@ -3379,11 +3383,11 @@ public: } void - test_float_mantissa() + test_float_mantissa(FeatureBitset features) { testcase("Test float_mantissa"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const alice = Account{"alice"}; auto const bob = Account{"bob"}; @@ -3508,11 +3512,11 @@ public: } void - test_float_mulratio() + test_float_mulratio(FeatureBitset features) { testcase("Test float_mulratio"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const alice = Account{"alice"}; auto const bob = Account{"bob"}; @@ -3663,11 +3667,11 @@ public: } void - test_float_multiply() + test_float_multiply(FeatureBitset features) { testcase("Test float_multiply"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const alice = Account{"alice"}; auto const bob = Account{"bob"}; @@ -3962,11 +3966,11 @@ public: } void - test_float_negate() + test_float_negate(FeatureBitset features) { testcase("Test float_negate"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const alice = Account{"alice"}; auto const bob = Account{"bob"}; @@ -4033,11 +4037,11 @@ public: } void - test_float_one() + test_float_one(FeatureBitset features) { testcase("Test float_one"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const alice = Account{"alice"}; auto const bob = Account{"bob"}; @@ -4074,11 +4078,11 @@ public: } void - test_float_root() + test_float_root(FeatureBitset features) { testcase("Test float_root"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const alice = Account{"alice"}; auto const bob = Account{"bob"}; @@ -4152,11 +4156,11 @@ public: } void - test_float_set() + test_float_set(FeatureBitset features) { testcase("Test float_set"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const alice = Account{"alice"}; auto const bob = Account{"bob"}; @@ -4225,11 +4229,11 @@ public: } void - test_float_sign() + test_float_sign(FeatureBitset features) { testcase("Test float_sign"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const alice = Account{"alice"}; auto const bob = Account{"bob"}; @@ -4338,11 +4342,11 @@ public: } void - test_float_sto() + test_float_sto(FeatureBitset features) { testcase("Test float_sto"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const alice = Account{"alice"}; auto const bob = Account{"bob"}; @@ -4543,11 +4547,11 @@ public: } void - test_float_sto_set() + test_float_sto_set(FeatureBitset features) { testcase("Test float_sto_set"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const alice = Account{"alice"}; auto const bob = Account{"bob"}; @@ -4685,11 +4689,11 @@ public: } void - test_float_sum() + test_float_sum(FeatureBitset features) { testcase("Test float_sum"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const alice = Account{"alice"}; auto const bob = Account{"bob"}; @@ -4865,13 +4869,13 @@ public: } void - test_hook_account() + test_hook_account(FeatureBitset features) { testcase("Test hook_account"); using namespace jtx; auto const test = [&](Account alice) -> void { - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const bob = Account{"bob"}; env.fund(XRP(10000), alice); @@ -4988,11 +4992,11 @@ public: } void - test_hook_again() + test_hook_again(FeatureBitset features) { testcase("Test hook_again"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; Account const alice{"alice"}; Account const bob{"bob"}; @@ -5049,6 +5053,13 @@ public: 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) + { + 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); @@ -5057,13 +5068,13 @@ public: } void - test_hook_hash() + test_hook_hash(FeatureBitset features) { testcase("Test hook_hash"); using namespace jtx; auto const test = [&](Account alice) -> void { - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const bob = Account{"bob"}; env.fund(XRP(10000), alice); @@ -5218,11 +5229,11 @@ public: } void - test_hook_param() + test_hook_param(FeatureBitset features) { testcase("Test hook_param"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; Account const alice{"alice"}; Account const bob{"bob"}; @@ -5345,11 +5356,11 @@ public: } void - test_hook_param_set() + test_hook_param_set(FeatureBitset features) { testcase("Test hook_param_set"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; Account const alice{"alice"}; Account const bob{"bob"}; @@ -5554,11 +5565,11 @@ public: } void - test_hook_pos() + test_hook_pos(FeatureBitset features) { testcase("Test hook_pos"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; Account const alice{"alice"}; Account const bob{"bob"}; @@ -5608,11 +5619,11 @@ public: } void - test_hook_skip() + test_hook_skip(FeatureBitset features) { testcase("Test hook_skip"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; Account const alice{"alice"}; Account const bob{"bob"}; @@ -5730,11 +5741,11 @@ public: } void - test_ledger_keylet() + test_ledger_keylet(FeatureBitset features) { testcase("Test ledger_keylet"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; Account const alice{"alice"}; Account const bob{"bob"}; @@ -5831,12 +5842,12 @@ public: } void - test_ledger_last_hash() + test_ledger_last_hash(FeatureBitset features) { testcase("Test ledger_last_hash"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const alice = Account{"alice"}; auto const bob = Account{"bob"}; @@ -5906,11 +5917,11 @@ public: } void - test_ledger_last_time() + test_ledger_last_time(FeatureBitset features) { testcase("Test ledger_last_time"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; Account const alice{"alice"}; Account const bob{"bob"}; @@ -5973,12 +5984,12 @@ public: } void - test_ledger_nonce() + test_ledger_nonce(FeatureBitset features) { testcase("Test ledger_nonce"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const alice = Account{"alice"}; auto const bob = Account{"bob"}; @@ -6072,11 +6083,11 @@ public: } void - test_ledger_seq() + test_ledger_seq(FeatureBitset features) { testcase("Test ledger_seq"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; Account const alice{"alice"}; Account const bob{"bob"}; @@ -6131,11 +6142,11 @@ public: } void - test_meta_slot() + test_meta_slot(FeatureBitset features) { testcase("Test meta_slot"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; Account const alice{"alice"}; Account const bob{"bob"}; @@ -6218,11 +6229,11 @@ public: } void - test_otxn_field() + test_otxn_field(FeatureBitset features) { testcase("Test otxn_field"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; Account const alice{"alice"}; Account const bob{"bob"}; @@ -6288,11 +6299,11 @@ public: } void - test_otxn_id() + test_otxn_id(FeatureBitset features) { testcase("Test otxn_id"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; Account const alice{"alice"}; Account const bob{"bob"}; @@ -6371,11 +6382,11 @@ public: } void - test_otxn_slot() + test_otxn_slot(FeatureBitset features) { testcase("Test otxn_slot"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; Account const alice{"alice"}; Account const bob{"bob"}; @@ -6453,11 +6464,11 @@ public: } void - test_otxn_type() + test_otxn_type(FeatureBitset features) { testcase("Test otxn_type"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; Account const alice{"alice"}; Account const bob{"bob"}; @@ -6524,11 +6535,11 @@ public: } void - test_otxn_param() + test_otxn_param(FeatureBitset features) { testcase("Test otxn_param"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; Account const alice{"alice"}; Account const bob{"bob"}; @@ -6647,11 +6658,11 @@ public: } void - test_slot() + test_slot(FeatureBitset features) { testcase("Test slot"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; Account const alice{"alice"}; Account const bob{"bob"}; @@ -6760,11 +6771,11 @@ public: } void - test_slot_clear() + test_slot_clear(FeatureBitset features) { testcase("Test slot_clear"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; Account const alice{"alice"}; Account const bob{"bob"}; @@ -6818,11 +6829,11 @@ public: } void - test_slot_count() + test_slot_count(FeatureBitset features) { testcase("Test slot_count"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; Account const alice{"alice"}; Account const bob{"bob"}; @@ -6883,11 +6894,11 @@ public: } void - test_slot_float() + test_slot_float(FeatureBitset features) { testcase("Test slot_float"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; Account const alice{"alice"}; Account const bob{"bob"}; @@ -6958,11 +6969,11 @@ public: } void - test_slot_set() + test_slot_set(FeatureBitset features) { testcase("Test slot_set"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; Account const alice{"alice"}; Account const bob{"bob"}; @@ -7068,11 +7079,11 @@ public: } void - test_slot_size() + test_slot_size(FeatureBitset features) { testcase("Test slot_size"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; Account const alice{"alice"}; Account const bob{"bob"}; @@ -7147,12 +7158,12 @@ public: } void - test_slot_subarray() + test_slot_subarray(FeatureBitset features) { testcase("Test slot_subarray"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const bob = Account{"bob"}; auto const alice = Account{"alice"}; @@ -7287,12 +7298,12 @@ public: } void - test_slot_subfield() + test_slot_subfield(FeatureBitset features) { testcase("Test slot_subfield"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const bob = Account{"bob"}; auto const alice = Account{"alice"}; @@ -7388,12 +7399,12 @@ public: } void - test_slot_type() + test_slot_type(FeatureBitset features) { testcase("Test slot_type"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const bob = Account{"bob"}; auto const alice = Account{"alice"}; @@ -7527,12 +7538,12 @@ public: } void - test_state() + test_state(FeatureBitset features) { testcase("Test state"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const bob = Account{"bob"}; auto const alice = Account{"alice"}; @@ -7668,12 +7679,12 @@ public: } void - test_state_foreign() + test_state_foreign(FeatureBitset features) { testcase("Test state_foreign"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const bob = Account{"bob"}; auto const alice = Account{"alice"}; @@ -7827,7 +7838,7 @@ public: } void - test_state_foreign_set_max() + test_state_foreign_set_max(FeatureBitset features) { testcase("Test state_foreign_set max"); using namespace jtx; @@ -7893,78 +7904,58 @@ public: 0x65U, 0x79U, 0x32U, 0x00U, 0x63U, 0x6fU, 0x6eU, 0x74U, 0x65U, 0x6eU, 0x74U, 0x32U}; - // fixXahauV1 + Env env{*this, features}; + + auto const bob = Account{"bob"}; + auto const alice = Account{"alice"}; + env.fund(XRP(10000000), alice); + env.fund(XRP(10000000), bob); + + // install the hook on alice + env(ripple::test::jtx::hook( + alice, {{hso(ns_maxHook, overrideFlag)}}, 0), + M("set state_foreign_set_max"), + HSFEE); + env.close(); + + // invoke the hook + for (uint32_t i = 0; i < 255; ++i) { - for (bool const withfixXahauV1 : {true, false}) - { - auto const amend = withfixXahauV1 - ? supported_amendments() - : supported_amendments() - fixXahauV1; - - Env env{*this, amend}; - - // Env env{*this, envconfig(), amend, nullptr, - // // beast::severities::kWarning - // beast::severities::kTrace - // }; - - auto const bob = Account{"bob"}; - auto const alice = Account{"alice"}; - env.fund(XRP(10000000), alice); - env.fund(XRP(10000000), bob); - - // install the hook on alice - env(ripple::test::jtx::hook( - alice, {{hso(ns_maxHook, overrideFlag)}}, 0), - M("set state_foreign_set_max"), - HSFEE); - env.close(); - - // invoke the hook - for (uint32_t i = 0; i < 255; ++i) - { - env(pay(bob, alice, XRP(1)), - M("test state_foreign_set_max"), - fee(XRP(1))); - } - - auto const txResult = - withfixXahauV1 ? ter(tecHOOK_REJECTED) : ter(tesSUCCESS); - env(pay(bob, alice, XRP(1)), - M("test state_foreign_set_max"), - fee(XRP(1)), - ter(txResult)); - env.close(); - - // verify hook result - std::string const hookResult = withfixXahauV1 - ? "800000000000002d" // TOO_MANY_NAMESPACES / -45 - : "9"; - - Json::Value params; - params[jss::transaction] = - env.tx()->getJson(JsonOptions::none)[jss::hash]; - auto const jrr = env.rpc("json", "tx", to_string(params)); - auto const meta = jrr[jss::result][jss::meta]; - auto const executions = meta[sfHookExecutions.jsonName]; - auto const execution = executions[0u][sfHookExecution.jsonName]; - BEAST_EXPECT( - execution[sfHookReturnCode.jsonName] == hookResult); - } + env(pay(bob, alice, XRP(1)), + M("test state_foreign_set_max"), + 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(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]; + auto const jrr = env.rpc("json", "tx", to_string(params)); + auto const meta = jrr[jss::result][jss::meta]; + auto const executions = meta[sfHookExecutions.jsonName]; + auto const execution = executions[0u][sfHookExecution.jsonName]; + BEAST_EXPECT(execution[sfHookReturnCode.jsonName] == hookResult); } void - test_state_foreign_set() + test_state_foreign_set(FeatureBitset features) { testcase("Test state_foreign_set"); using namespace jtx; - Env env{*this, supported_amendments()}; - // Env env{*this, envconfig(), supported_amendments(), nullptr, - // beast::severities::kWarning - // beast::severities::kTrace - // }; + Env env{*this, features}; auto const david = Account("david"); // grantee generic auto const cho = Account{"cho"}; // invoker @@ -8424,12 +8415,12 @@ public: } void - test_state_set() + test_state_set(FeatureBitset features) { testcase("Test state_set"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const bob = Account{"bob"}; auto const alice = Account{"alice"}; @@ -9134,12 +9125,12 @@ public: } void - test_sto_emplace() + test_sto_emplace(FeatureBitset features) { testcase("Test sto_emplace"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const bob = Account{"bob"}; auto const alice = Account{"alice"}; @@ -9328,12 +9319,12 @@ public: } void - test_sto_erase() + test_sto_erase(FeatureBitset features) { testcase("Test sto_erase"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const bob = Account{"bob"}; auto const alice = Account{"alice"}; @@ -9465,12 +9456,12 @@ public: } void - test_sto_subarray() + test_sto_subarray(FeatureBitset features) { testcase("Test sto_subarray"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const bob = Account{"bob"}; auto const alice = Account{"alice"}; @@ -9539,12 +9530,12 @@ public: } void - test_sto_subfield() + test_sto_subfield(FeatureBitset features) { testcase("Test sto_subfield"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const bob = Account{"bob"}; auto const alice = Account{"alice"}; @@ -9623,12 +9614,12 @@ public: } void - test_sto_validate() + test_sto_validate(FeatureBitset features) { testcase("Test sto_validate"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const bob = Account{"bob"}; auto const alice = Account{"alice"}; @@ -9706,12 +9697,12 @@ public: } void - test_trace() + test_trace(FeatureBitset features) { testcase("Test trace"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const alice = Account{"alice"}; auto const bob = Account{"bob"}; @@ -9756,12 +9747,12 @@ public: } void - test_trace_float() + test_trace_float(FeatureBitset features) { testcase("Test trace_float"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const alice = Account{"alice"}; auto const bob = Account{"bob"}; @@ -9800,12 +9791,12 @@ public: } void - test_trace_num() + test_trace_num(FeatureBitset features) { testcase("Test trace_num"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const alice = Account{"alice"}; auto const bob = Account{"bob"}; @@ -9844,10 +9835,10 @@ public: } void - test_util_accid() + test_util_accid(FeatureBitset features) { using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const alice = Account{"alice"}; auto const bob = Account{"bob"}; @@ -10112,12 +10103,12 @@ public: } void - test_util_keylet() + test_util_keylet(FeatureBitset features) { testcase("Test util_keylet"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const alice = Account{"alice"}; auto const bob = Account{"bob"}; @@ -10685,11 +10676,11 @@ public: } void - test_util_raddr() + test_util_raddr(FeatureBitset features) { testcase("Test util_raddr"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const alice = Account{"alice"}; auto const bob = Account{"bob"}; @@ -11138,11 +11129,11 @@ public: } void - test_util_sha512h() + test_util_sha512h(FeatureBitset features) { testcase("Test util_sha512h"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const alice = Account{"alice"}; auto const bob = Account{"bob"}; @@ -11511,11 +11502,11 @@ public: } void - test_util_verify() + test_util_verify(FeatureBitset features) { testcase("Test util_verify"); using namespace jtx; - Env env{*this, supported_amendments()}; + Env env{*this, features}; auto const alice = Account{"alice"}; auto const bob = Account{"bob"}; @@ -11624,114 +11615,124 @@ public: env(pay(bob, alice, XRP(1)), M("test util_verify"), fee(XRP(1))); } + void + testWithFeatures(FeatureBitset features) + { + testHooksOwnerDir(features); + testHooksDisabled(features); + testTxStructure(features); + testInferHookSetOperation(); + testParams(features); + testGrants(features); + + testDelete(features); + testInstall(features); + testCreate(features); + testWithTickets(features); + + testUpdate(features); + + testNSDelete(features); + + testWasm(features); + test_accept(features); + test_rollback(features); + + testGuards(features); + + test_emit(features); // + // test_etxn_burden(features); // tested above + // test_etxn_generation(features); // tested above + // test_otxn_burden(features); // tested above + // test_otxn_generation(features); // tested above + test_etxn_details(features); // + test_etxn_fee_base(features); // + test_etxn_nonce(features); // + test_etxn_reserve(features); // + test_fee_base(features); // + + test_otxn_field(features); // + + test_ledger_keylet(features); // + + test_float_compare(features); // + test_float_divide(features); // + test_float_int(features); // + test_float_invert(features); // + test_float_log(features); // + test_float_mantissa(features); // + test_float_mulratio(features); // + test_float_multiply(features); // + test_float_negate(features); // + test_float_one(features); // + test_float_root(features); // + test_float_set(features); // + test_float_sign(features); // + test_float_sto(features); // + test_float_sto_set(features); // + test_float_sum(features); // + + test_hook_account(features); // + test_hook_again(features); // + test_hook_hash(features); // + test_hook_param(features); // + test_hook_param_set(features); // + test_hook_pos(features); // + test_hook_skip(features); // + + test_ledger_last_hash(features); // + test_ledger_last_time(features); // + test_ledger_nonce(features); // + test_ledger_seq(features); // + + test_meta_slot(features); // + + test_otxn_id(features); // + test_otxn_slot(features); // + test_otxn_type(features); // + test_otxn_param(features); // + + test_slot(features); // + test_slot_clear(features); // + test_slot_count(features); // + test_slot_float(features); // + test_slot_set(features); // + test_slot_size(features); // + test_slot_subarray(features); // + test_slot_subfield(features); // + test_slot_type(features); // + + test_state(features); // + test_state_foreign(features); // + test_state_foreign_set(features); // + test_state_foreign_set_max(features); // + test_state_set(features); // + + test_sto_emplace(features); // + test_sto_erase(features); // + test_sto_subarray(features); // + test_sto_subfield(features); // + test_sto_validate(features); // + + test_trace(features); // + test_trace_float(features); // + test_trace_num(features); // + + test_util_accid(features); // + test_util_keylet(features); // + test_util_raddr(features); // + test_util_sha512h(features); // + test_util_verify(features); // + } + void run() override { - testHooksOwnerDir(); - testHooksDisabled(); - testTxStructure(); - testInferHookSetOperation(); - testParams(); - testGrants(); - - testDelete(); - testInstall(); - testCreate(); - testWithTickets(); - - testUpdate(); - - testNSDelete(); - - testWasm(); - test_accept(); - test_rollback(); - - testGuards(); - - test_emit(); // - // test_etxn_burden(); // tested above - // test_etxn_generation(); // tested above - // test_otxn_burden(); // tested above - // test_otxn_generation(); // tested above - test_etxn_details(); // - test_etxn_fee_base(); // - test_etxn_nonce(); // - test_etxn_reserve(); // - test_fee_base(); // - - test_otxn_field(); // - - test_ledger_keylet(); // - - test_float_compare(); // - test_float_divide(); // - test_float_int(); // - test_float_invert(); // - test_float_log(); // - test_float_mantissa(); // - test_float_mulratio(); // - test_float_multiply(); // - test_float_negate(); // - test_float_one(); // - test_float_root(); // - test_float_set(); // - test_float_sign(); // - test_float_sto(); // - test_float_sto_set(); // - test_float_sum(); // - - test_hook_account(); // - test_hook_again(); // - test_hook_hash(); // - test_hook_param(); // - test_hook_param_set(); // - test_hook_pos(); // - test_hook_skip(); // - - test_ledger_last_hash(); // - test_ledger_last_time(); // - test_ledger_nonce(); // - test_ledger_seq(); // - - test_meta_slot(); // - - test_otxn_id(); // - test_otxn_slot(); // - test_otxn_type(); // - test_otxn_param(); // - - test_slot(); // - test_slot_clear(); // - test_slot_count(); // - test_slot_float(); // - test_slot_set(); // - test_slot_size(); // - test_slot_subarray(); // - test_slot_subfield(); // - test_slot_type(); // - - test_state(); // - test_state_foreign(); // - test_state_foreign_set(); // - test_state_foreign_set_max(); // - test_state_set(); // - - test_sto_emplace(); // - test_sto_erase(); // - test_sto_subarray(); // - test_sto_subfield(); // - test_sto_validate(); // - - test_trace(); // - test_trace_float(); // - test_trace_num(); // - - test_util_accid(); // - test_util_keylet(); // - test_util_raddr(); // - test_util_sha512h(); // - test_util_verify(); // + using namespace test::jtx; + auto const sa = supported_amendments(); + testWithFeatures(sa); + testWithFeatures(sa - fixXahauV2); + testWithFeatures(sa - fixXahauV1 - fixXahauV2); } private: