diff --git a/Builds/CMake/RippledCore.cmake b/Builds/CMake/RippledCore.cmake index 74ff58f601..65c063bf8a 100644 --- a/Builds/CMake/RippledCore.cmake +++ b/Builds/CMake/RippledCore.cmake @@ -488,6 +488,7 @@ target_sources (rippled PRIVATE src/ripple/app/tx/impl/apply.cpp src/ripple/app/tx/impl/applySteps.cpp src/ripple/app/hook/impl/applyHook.cpp + src/ripple/app/hook/impl/GasValidator.cpp src/ripple/app/tx/impl/details/NFTokenUtils.cpp #[===============================[ main sources: @@ -909,6 +910,7 @@ if (tests) src/test/jtx/impl/fee.cpp src/test/jtx/impl/flags.cpp src/test/jtx/impl/genesis.cpp + src/test/jtx/impl/hookgas.cpp src/test/jtx/impl/import.cpp src/test/jtx/impl/invoice_id.cpp src/test/jtx/impl/invoke.cpp diff --git a/hook/sfcodes.h b/hook/sfcodes.h index 8c7bc48f49..1477fdff3e 100644 --- a/hook/sfcodes.h +++ b/hook/sfcodes.h @@ -63,6 +63,10 @@ #define sfEmitGeneration ((2U << 16U) + 46U) #define sfLockCount ((2U << 16U) + 49U) #define sfFirstNFTokenSequence ((2U << 16U) + 50U) +#define sfHookCallbackGas ((2U << 16U) + 89U) +#define sfHookWeakGas ((2U << 16U) + 90U) +#define sfHookInstructionCost ((2U << 16U) + 91U) +#define sfHookGas ((2U << 16U) + 92U) #define sfStartTime ((2U << 16U) + 93U) #define sfRepeatCount ((2U << 16U) + 94U) #define sfDelaySeconds ((2U << 16U) + 95U) diff --git a/src/ripple/app/hook/Enum.h b/src/ripple/app/hook/Enum.h index 9728b10401..e026ef1309 100644 --- a/src/ripple/app/hook/Enum.h +++ b/src/ripple/app/hook/Enum.h @@ -358,6 +358,7 @@ enum ExitType : uint8_t { WASM_ERROR = 1, ROLLBACK = 2, ACCEPT = 3, + GAS_INSUFFICIENT = 4, }; const uint16_t max_state_modifications = 256; diff --git a/src/ripple/app/hook/GasValidator.h b/src/ripple/app/hook/GasValidator.h new file mode 100644 index 0000000000..172ea787a9 --- /dev/null +++ b/src/ripple/app/hook/GasValidator.h @@ -0,0 +1,61 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 XRPL-Labs + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_APP_HOOK_GASVALIDATOR_H_INCLUDED +#define RIPPLE_APP_HOOK_GASVALIDATOR_H_INCLUDED + +#include +#include +#include +#include +#include +#include +#include +#include + +// Forward declaration +using GuardLog = + std::optional>>; + +namespace hook { + +/** + * @brief Validate WASM host functions for Gas-type hooks + * + * Validates that a WASM binary only imports allowed host functions + * and does not import the _g (guard) function, which is only for + * Guard-type hooks. + * + * @param wasm The WASM binary to validate + * @param guardLog Logging function for validation errors + * @param guardLogAccStr Account string for logging + * @return bool if validation succeeds, + * @return true if contains cbak function + * @return false if otherwise + * @return error message if validation fails + */ +ripple::Expected +validateWasmHostFunctionsForGas( + std::vector const& wasm, + ripple::Rules const& rules, + beast::Journal const& j); + +} // namespace hook + +#endif // RIPPLE_APP_HOOK_GASVALIDATOR_H_INCLUDED diff --git a/src/ripple/app/hook/applyHook.h b/src/ripple/app/hook/applyHook.h index 2c1f250bbf..f271fd5f68 100644 --- a/src/ripple/app/hook/applyHook.h +++ b/src/ripple/app/hook/applyHook.h @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -462,7 +461,9 @@ apply( uint32_t wasmParam, uint8_t hookChainPosition, // result of apply() if this is weak exec - std::shared_ptr const& provisionalMeta); + std::shared_ptr const& provisionalMeta, + uint16_t hookApiVersion, + uint32_t hookGas); struct HookContext; @@ -501,6 +502,7 @@ struct HookResult std::string exitReason{""}; int64_t exitCode{-1}; uint64_t instructionCount{0}; + uint64_t instructionCost{0}; bool hasCallback = false; // true iff this hook wasm has a cbak function bool isCallback = false; // true iff this hook execution is a callback in action @@ -513,6 +515,8 @@ struct HookResult false; // hook_again allows strong pre-apply to nominate // additional weak post-apply execution std::shared_ptr provisionalMeta; + uint16_t hookApiVersion = 0; // 0 = Guard-type, 1 = Gas-type + uint32_t hookGas; // Gas limit for Gas-type hooks }; class HookExecutor; @@ -652,12 +656,18 @@ class HookExecutor WasmEdge_ConfigureContext* conf = NULL; WasmEdge_VMContext* ctx = NULL; - WasmEdgeVM() + WasmEdgeVM(uint16_t hookApiVersion) { conf = WasmEdge_ConfigureCreate(); if (!conf) return; WasmEdge_ConfigureStatisticsSetInstructionCounting(conf, true); + if (hookApiVersion == 1) + { + WasmEdge_ConfigureStatisticsSetCostMeasuring(conf, true); + uint32_t maxMemoryPage = 8; + WasmEdge_ConfigureSetMaxMemoryPage(conf, maxMemoryPage); + } ctx = WasmEdge_VMCreate(conf, NULL); } @@ -692,9 +702,9 @@ class HookExecutor * Validate that a web assembly blob can be loaded by wasmedge */ static std::optional - validateWasm(const void* wasm, size_t len) + validateWasm(const void* wasm, size_t len, uint16_t hookApiVersion) { - WasmEdgeVM vm; + WasmEdgeVM vm{hookApiVersion}; if (!vm.sane()) return "Could not create WASMEDGE instance"; @@ -737,7 +747,7 @@ class HookExecutor WasmEdge_LogOff(); - WasmEdgeVM vm; + WasmEdgeVM vm{hookCtx.result.hookApiVersion}; if (!vm.sane()) { @@ -758,6 +768,22 @@ class HookExecutor return; } + // Set Gas limit for Gas-type hooks (HookApiVersion == 1) + if (hookCtx.result.hookApiVersion == 1) + { + auto* statsCtx = WasmEdge_VMGetStatisticsContext(vm.ctx); + if (statsCtx) + { + // Convert HookGas to cost limit count (1 Gas = 1 cost) + uint32_t gasLimit = hookCtx.result.hookGas; + WasmEdge_StatisticsSetCostLimit(statsCtx, gasLimit); + + JLOG(j.trace()) + << "HookInfo[" << HC_ACC() << "]: Set Gas limit to " + << gasLimit << " cost limit for Gas-type Hook"; + } + } + WasmEdge_Value params[1] = {WasmEdge_ValueGenI32((int64_t)wasmParam)}; WasmEdge_Value returns[1]; @@ -771,17 +797,29 @@ class HookExecutor returns, 1); + auto* statsCtx = WasmEdge_VMGetStatisticsContext(vm.ctx); + hookCtx.result.instructionCount = + WasmEdge_StatisticsGetInstrCount(statsCtx); + hookCtx.result.instructionCost = + WasmEdge_StatisticsGetTotalCost(statsCtx); + if (auto err = getWasmError("WASM VM error", res); err) { - JLOG(j.warn()) << "HookError[" << HC_ACC() << "]: " << *err; - hookCtx.result.exitType = hook_api::ExitType::WASM_ERROR; + JLOG(j.trace()) << "HookError[" << HC_ACC() << "]: " << *err; + + // Check if error is due to Gas limit exceeded for Gas-type hooks + if (hookCtx.result.hookApiVersion == 1 && + err->find("cost limit exceeded") != std::string::npos) + { + JLOG(j.trace()) << "HookError[" << HC_ACC() + << "]: Gas limit exceeded. Limit was " + << hookCtx.result.hookGas; + } + + hookCtx.result.exitType = hook_api::ExitType::GAS_INSUFFICIENT; return; } - auto* statsCtx = WasmEdge_VMGetStatisticsContext(vm.ctx); - hookCtx.result.instructionCount = - WasmEdge_StatisticsGetInstrCount(statsCtx); - // RH NOTE: stack unwind will clean up WasmEdgeVM } diff --git a/src/ripple/app/hook/impl/GasValidator.cpp b/src/ripple/app/hook/impl/GasValidator.cpp new file mode 100644 index 0000000000..dadc2f4526 --- /dev/null +++ b/src/ripple/app/hook/impl/GasValidator.cpp @@ -0,0 +1,401 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 XRPL-Labs + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include +#include +#include +#include +#include +#include +#include + +namespace hook { + +Expected +validateExportSection( + WasmEdge_ASTModuleContext* astModule, + beast::Journal const& j) +{ + // Get export count + uint32_t exportCount = WasmEdge_ASTModuleListExportsLength(astModule); + if (exportCount == 0) + { + return Unexpected("WASM must export at least hook API functions"); + } + + // Get exports + const WasmEdge_ExportTypeContext* exports[256]; + uint32_t actualExportCount = std::min(exportCount, 256u); + actualExportCount = + WasmEdge_ASTModuleListExports(astModule, exports, actualExportCount); + + // Track if we found required hook() function + bool foundHook = false; + bool foundCbak = false; + + // Check each export + for (uint32_t i = 0; i < actualExportCount; i++) + { + // Only check function exports + WasmEdge_ExternalType const type = + WasmEdge_ExportTypeGetExternalType(exports[i]); + if (type != WasmEdge_ExternalType_Function) + continue; + + WasmEdge_String const name = + WasmEdge_ExportTypeGetExternalName(exports[i]); + std::string nameStr(name.Buf, name.Length); + + if (nameStr.starts_with("__")) + { + // skip runtime support functions + continue; + } + + // Only allow hook() and cbak() exports + if (nameStr != "hook" && nameStr != "cbak") + { + JLOG(j.trace()) << "HookSet(" << hook::log::EXPORT_MISSING + << "): Unauthorized export function '" << nameStr + << "'. Only 'hook' and 'cbak' are allowed"; + return Unexpected( + "Unauthorized export function '" + nameStr + + "'. Only 'hook' and 'cbak' are allowed"); + } + + if (nameStr == "hook") + foundHook = true; + if (nameStr == "cbak") + foundCbak = true; + + // Get function type to validate signature + WasmEdge_FunctionTypeContext const* functionType = + WasmEdge_ExportTypeGetFunctionType(astModule, exports[i]); + + // Validate parameter count (must be exactly 1) + uint32_t paramCount = + WasmEdge_FunctionTypeGetParametersLength(functionType); + if (paramCount != 1) + { + JLOG(j.trace()) + << "HookSet(" + << (nameStr == "hook" ? hook::log::EXPORT_HOOK_FUNC + : hook::log::EXPORT_CBAK_FUNC) + << "): Function '" << nameStr + << "' must have exactly 1 parameter, found " << paramCount; + return Unexpected( + "Function '" + nameStr + + "' must have exactly 1 parameter of type uint32_t"); + } + + // Validate parameter type (must be i32 / uint32_t) + WasmEdge_ValType parameters[1]; + WasmEdge_FunctionTypeGetParameters(functionType, parameters, 1); + if (parameters[0] != WasmEdge_ValType_I32) + { + JLOG(j.trace()) << "HookSet(" + << (nameStr == "hook" ? hook::log::EXPORT_HOOK_FUNC + : hook::log::EXPORT_CBAK_FUNC) + << "): Function '" << nameStr + << "' parameter must be uint32_t (i32), found type " + << parameters[0]; + return Unexpected( + "Function '" + nameStr + "' parameter must be uint32_t (i32)"); + } + + // Validate return type (must be i64 / uint64_t) + uint32_t returnCount = + WasmEdge_FunctionTypeGetReturnsLength(functionType); + if (returnCount != 1) + { + JLOG(j.trace()) + << "HookSet(" + << (nameStr == "hook" ? hook::log::EXPORT_HOOK_FUNC + : hook::log::EXPORT_CBAK_FUNC) + << "): Function '" << nameStr + << "' must return exactly 1 value, found " << returnCount; + return Unexpected( + "Function '" + nameStr + + "' must return exactly 1 value of type uint64_t"); + } + + WasmEdge_ValType returns[1]; + WasmEdge_FunctionTypeGetReturns(functionType, returns, 1); + if (returns[0] != WasmEdge_ValType_I64) + { + JLOG(j.trace()) + << "HookSet(" + << (nameStr == "hook" ? hook::log::EXPORT_HOOK_FUNC + : hook::log::EXPORT_CBAK_FUNC) + << "): Function '" << nameStr + << "' return type must be uint64_t (i64), found type " + << returns[0]; + return Unexpected( + "Function '" + nameStr + + "' return type must be uint64_t (i64)"); + } + } + + // Ensure hook() function was exported (required) + if (!foundHook) + { + JLOG(j.trace()) << "HookSet(" << hook::log::EXPORT_MISSING + << "): Required function 'hook' not found in exports"; + return Unexpected("Required function 'hook' not found in exports"); + } + + return foundCbak; +} + +Expected +validateImportSection( + WasmEdge_ASTModuleContext* astModule, + Rules const& rules, + beast::Journal const& j) +{ + // Get import count + uint32_t importCount = WasmEdge_ASTModuleListImportsLength(astModule); + + if (importCount == 0) + { + JLOG(j.trace()) << "HookSet(" << hook::log::IMPORTS_MISSING + << "): WASM must import at least hook API functions"; + return Unexpected("WASM must import at least hook API functions"); + } + + // Get imports (max 256) + const WasmEdge_ImportTypeContext* imports[256]; + uint32_t actualImportCount = std::min(importCount, 256u); + actualImportCount = + WasmEdge_ASTModuleListImports(astModule, imports, actualImportCount); + + std::optional error; + + // Check each import + for (uint32_t i = 0; i < actualImportCount; i++) + { + WasmEdge_String moduleName = + WasmEdge_ImportTypeGetModuleName(imports[i]); + WasmEdge_String externalName = + WasmEdge_ImportTypeGetExternalName(imports[i]); + WasmEdge_ExternalType extType = + WasmEdge_ImportTypeGetExternalType(imports[i]); + + // Only check function imports + if (extType != WasmEdge_ExternalType_Function) + continue; + + // Convert WasmEdge_String to std::string for comparison + std::string modName(moduleName.Buf, moduleName.Length); + std::string extName(externalName.Buf, externalName.Length); + + // Check module name is "env" + if (modName != "env") + { + JLOG(j.trace()) + << "HookSet(" << hook::log::IMPORT_MODULE_ENV + << "): Import module must be 'env', found: " << modName; + return Unexpected("Import module must be 'env', found: " + modName); + } + + // Check for forbidden _g function (guard function) + if (extName == "_g") + { + JLOG(j.trace()) + << "HookSet(" << hook::log::IMPORT_ILLEGAL + << "): Gas-type hooks cannot import _g (guard) function"; + return Unexpected( + "Gas-type hooks cannot import _g (guard) function"); + } + + // Determine which whitelist contains the function and get expected + // signature + std::vector const* expectedSig = nullptr; + auto baseIt = hook_api::import_whitelist.find(extName); + if (baseIt != hook_api::import_whitelist.end()) + { + expectedSig = &baseIt->second; + } + else if (rules.enabled(featureHooksUpdate1)) + { + auto extIt = hook_api::import_whitelist_1.find(extName); + if (extIt != hook_api::import_whitelist_1.end()) + { + expectedSig = &extIt->second; + } + } + + // Function not in any whitelist + if (!expectedSig) + { + JLOG(j.trace()) << "HookSet(" << hook::log::IMPORT_ILLEGAL + << "): Import not in whitelist: " << extName; + return Unexpected("Import not in whitelist: " + extName); + } + + // Get function type for signature validation + WasmEdge_FunctionTypeContext const* functionType = + WasmEdge_ImportTypeGetFunctionType(astModule, imports[i]); + + if (!functionType) + { + JLOG(j.trace()) << "HookSet(" << hook::log::FUNC_TYPELESS + << "): Import function '" << extName + << "' has no function type definition"; + return Unexpected( + "Import function '" + extName + + "' has no function type definition"); + } + + // Validate return type + // expectedSig[0] is the return type + uint32_t returnCount = + WasmEdge_FunctionTypeGetReturnsLength(functionType); + + if (returnCount != 1) + { + JLOG(j.trace()) + << "HookSet(" << hook::log::FUNC_RETURN_COUNT + << "): Import function '" << extName + << "' must return exactly 1 value, found " << returnCount; + return Unexpected( + "Import function '" + extName + + "' must return exactly 1 value"); + } + + WasmEdge_ValType actualReturnType; + WasmEdge_FunctionTypeGetReturns(functionType, &actualReturnType, 1); + + if (actualReturnType != (*expectedSig)[0]) + { + JLOG(j.trace()) << "HookSet(" << hook::log::FUNC_RETURN_INVALID + << "): Import function '" << extName + << "' has incorrect return type. Expected " + << static_cast((*expectedSig)[0]) << ", found " + << static_cast(actualReturnType); + return Unexpected( + "Import function '" + extName + "' has incorrect return type"); + } + + // Validate parameter count and types + // expectedSig[1..N] are the parameter types + uint32_t expectedParamCount = + expectedSig->size() > 0 ? expectedSig->size() - 1 : 0; + uint32_t actualParamCount = + WasmEdge_FunctionTypeGetParametersLength(functionType); + + if (actualParamCount != expectedParamCount) + { + JLOG(j.trace()) << "HookSet(" << hook::log::FUNC_PARAM_INVALID + << "): Import function '" << extName << "' has " + << actualParamCount << " parameters, expected " + << expectedParamCount; + return Unexpected( + "Import function '" + extName + + "' has incorrect parameter count"); + } + + // Validate each parameter type + if (actualParamCount > 0) + { + std::vector actualParams(actualParamCount); + WasmEdge_FunctionTypeGetParameters( + functionType, actualParams.data(), actualParamCount); + + for (uint32_t p = 0; p < actualParamCount; p++) + { + uint8_t expectedParamType = (*expectedSig)[1 + p]; + if (actualParams[p] != expectedParamType) + { + JLOG(j.trace()) + << "HookSet(" << hook::log::FUNC_PARAM_INVALID + << "): Import function '" << extName << "' parameter " + << p << " has incorrect type. Expected " + << static_cast(expectedParamType) << ", found " + << static_cast(actualParams[p]); + return Unexpected( + "Import function '" + extName + + "' has incorrect parameter types"); + } + } + } + } + + return {}; +} + +Expected +validateWasmHostFunctionsForGas( + std::vector const& wasm, + Rules const& rules, + beast::Journal const& j) +{ + // Create WasmEdge Loader + WasmEdge_LoaderContext* loader = WasmEdge_LoaderCreate(NULL); + if (!loader) + { + return Unexpected("Failed to create WasmEdge Loader"); + } + + // Parse WASM binary + WasmEdge_ASTModuleContext* astModule = NULL; + WasmEdge_Result res = WasmEdge_LoaderParseFromBuffer( + loader, &astModule, wasm.data(), wasm.size()); + + if (!WasmEdge_ResultOK(res)) + { + WasmEdge_LoaderDelete(loader); + const char* msg = WasmEdge_ResultGetMessage(res); + return Unexpected( + std::string("Failed to parse WASM: ") + + (msg ? msg : "unknown error")); + } + + bool foundCbak = false; + + // + // check export section + // + auto resultExport = validateExportSection(astModule, j); + if (!resultExport) + { + WasmEdge_ASTModuleDelete(astModule); + WasmEdge_LoaderDelete(loader); + return Unexpected(resultExport.error()); + } + foundCbak = resultExport.value(); + + // + // check import section + // + if (auto result = validateImportSection(astModule, rules, j); !result) + { + WasmEdge_ASTModuleDelete(astModule); + WasmEdge_LoaderDelete(loader); + return Unexpected(result.error()); + } + + // Cleanup + WasmEdge_ASTModuleDelete(astModule); + WasmEdge_LoaderDelete(loader); + + return foundCbak; +} + +} // namespace hook diff --git a/src/ripple/app/hook/impl/applyHook.cpp b/src/ripple/app/hook/impl/applyHook.cpp index f27b7d23b3..7db12ae06c 100644 --- a/src/ripple/app/hook/impl/applyHook.cpp +++ b/src/ripple/app/hook/impl/applyHook.cpp @@ -1232,7 +1232,9 @@ hook::apply( bool isStrong, uint32_t wasmParam, uint8_t hookChainPosition, - std::shared_ptr const& provisionalMeta) + std::shared_ptr const& provisionalMeta, + uint16_t hookApiVersion, + uint32_t hookGas) { HookContext hookCtx = { .applyCtx = applyCtx, @@ -1264,7 +1266,9 @@ hook::apply( .wasmParam = wasmParam, .hookChainPosition = hookChainPosition, .foreignStateSetDisabled = false, - .provisionalMeta = provisionalMeta}, + .provisionalMeta = provisionalMeta, + .hookApiVersion = hookApiVersion, + .hookGas = hookGas}, .emitFailure = isCallback && wasmParam & 1 ? std::optional( (*(applyCtx.view().peek(keylet::emittedTxn( @@ -2049,6 +2053,9 @@ hook::finalizeHookResult( ripple::Slice{ hookResult.exitReason.data(), hookResult.exitReason.size()}); meta.setFieldU64(sfHookInstructionCount, hookResult.instructionCount); + if (hookResult.hookApiVersion == 1) + meta.setFieldU32(sfHookInstructionCost, hookResult.instructionCost); + meta.setFieldU16( sfHookEmitCount, emission_txnid.size()); // this will never wrap, hard limit diff --git a/src/ripple/app/tx/impl/Change.cpp b/src/ripple/app/tx/impl/Change.cpp index 37a436feea..84fe432781 100644 --- a/src/ripple/app/tx/impl/Change.cpp +++ b/src/ripple/app/tx/impl/Change.cpp @@ -638,7 +638,7 @@ Change::activateXahauGenesis() std::optional result2 = hook::HookExecutor::validateWasm( - wasmBytes.data(), (size_t)wasmBytes.size()); + wasmBytes.data(), (size_t)wasmBytes.size(), 0); if (result2) { diff --git a/src/ripple/app/tx/impl/SetHook.cpp b/src/ripple/app/tx/impl/SetHook.cpp index 9ca8295571..910fcf7fc9 100644 --- a/src/ripple/app/tx/impl/SetHook.cpp +++ b/src/ripple/app/tx/impl/SetHook.cpp @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -435,7 +436,8 @@ SetHook::validateHookSetEntry(SetHookCtx& ctx, STObject const& hookSetObj) } auto version = hookSetObj.getFieldU16(sfHookApiVersion); - if (version != 0) + + if (!ctx.rules.enabled(featureHookGas) && version != 0) { // we currently only accept api version 0 JLOG(ctx.j.trace()) @@ -445,6 +447,92 @@ SetHook::validateHookSetEntry(SetHookCtx& ctx, STObject const& hookSetObj) return false; } + // allow only version=0 and version=1 + if (version != 0 && version != 1) + { + JLOG(ctx.j.trace()) + << "HookSet(" << ::hook::log::API_INVALID << ")[" + << HS_ACC() + << "]: Malformed transaction: SetHook " + "sfHook->sfHookApiVersion invalid. (Must be 0 or 1)."; + return false; + } + + // validate sfHookCallbackGas + auto hasHookCallbackGas = false; + if (hookSetObj.isFieldPresent(sfHookCallbackGas)) + { + if (version != 1) + { + JLOG(ctx.j.trace()) + << "HookSet(" << hook::log::HOOK_INVALID_FIELD << ")[" + << HS_ACC() + << "]: Malformed transaction: SetHook " + "sfHookCallbackGas is " + "not allowed in version " + << version << "."; + return false; + } + if (hookSetObj.getFieldU32(sfHookCallbackGas) == 0) + { + JLOG(ctx.j.trace()) + << "HookSet(" << hook::log::HOOK_INVALID_FIELD << ")[" + << HS_ACC() + << "]: Malformed transaction: SetHook " + "sfHookCallbackGas must be greater than 0."; + return false; + } + hasHookCallbackGas = true; + } + + // validate sfHookWeakGas + if (hookSetObj.isFieldPresent(sfHookWeakGas)) + { + if (version != 1) + { + JLOG(ctx.j.trace()) + << "HookSet(" << hook::log::HOOK_INVALID_FIELD << ")[" + << HS_ACC() + << "]: Malformed transaction: SetHook sfHookWeakGas is " + "not allowed in version " + << version << "."; + return false; + } + if (hookSetObj.getFieldU32(sfHookWeakGas) == 0) + { + JLOG(ctx.j.trace()) + << "HookSet(" << hook::log::HOOK_INVALID_FIELD << ")[" + << HS_ACC() + << "]: Malformed transaction: SetHook sfHookWeakGas " + "must be greater than 0."; + return false; + } + + if (!(flags & hsfCOLLECT)) + { + JLOG(ctx.j.trace()) + << "HookSet(" << hook::log::HOOK_INVALID_FIELD << ")[" + << HS_ACC() + << "]: Malformed transaction: SetHook with " + "sfHookWeakGas must be used with hsfCOLLECT " + "flag."; + return false; + } + } + else if (version == 1) + { + if (flags & hsfCOLLECT) + { + JLOG(ctx.j.trace()) + << "HookSet(" << hook::log::HOOK_INVALID_FIELD << ")[" + << HS_ACC() + << "]: Malformed transaction: SetHook with " + "sfHookWeakGas must be used with hsfCOLLECT " + "flag."; + return false; + } + } + // validate sfHookOn if (!hookSetObj.isFieldPresent(sfHookOn)) { @@ -469,6 +557,7 @@ SetHook::validateHookSetEntry(SetHookCtx& ctx, STObject const& hookSetObj) return {}; Blob hook = hookSetObj.getFieldVL(sfCreateCode); + auto version = hookSetObj.getFieldU16(sfHookApiVersion); // RH NOTE: validateGuards has a generic non-rippled specific // interface so it can be used in other projects (i.e. tooling). @@ -486,46 +575,97 @@ SetHook::validateHookSetEntry(SetHookCtx& ctx, STObject const& hookSetObj) hsacc = ss.str(); } - auto result = validateGuards( - hook, // wasm to verify - logger, - hsacc, - (ctx.rules.enabled(featureHooksUpdate1) ? 1 : 0) + - (ctx.rules.enabled(fix20250131) ? 2 : 0)); + uint64_t maxInstrCountHook = 0; + uint64_t maxInstrCountCbak = 0; - if (ctx.j.trace()) + if (version == 0) // Guard type { - // clunky but to get the stream to accept the output - // correctly we will split on new line and feed each line - // one by one into the trace stream beast::Journal should be - // updated to inherit from basic_ostream then this - // wouldn't be necessary. - - // is this a needless copy or does the compiler do copy - // elision here? - std::string s = loggerStream.str(); - - char* data = s.data(); - size_t len = s.size(); - - char* last = data; - size_t i = 0; - for (; i < len; ++i) + auto result = validateGuards( + hook, // wasm to verify + logger, + hsacc, + (ctx.rules.enabled(featureHooksUpdate1) ? 1 : 0) + + (ctx.rules.enabled(fix20250131) ? 2 : 0)); + + if (ctx.j.trace()) { - if (data[i] == '\n') + // clunky but to get the stream to accept the output + // correctly we will split on new line and feed each + // line one by one into the trace stream beast::Journal + // should be updated to inherit from basic_ostream + // then this wouldn't be necessary. + + // is this a needless copy or does the compiler do copy + // elision here? + std::string s = loggerStream.str(); + + char* data = s.data(); + size_t len = s.size(); + + char* last = data; + size_t i = 0; + for (; i < len; ++i) { - data[i] = '\0'; - ctx.j.trace() << last; - last = data + i; + if (data[i] == '\n') + { + data[i] = '\0'; + ctx.j.trace() << last; + last = data + i; + } } + + if (last < data + i) + ctx.j.trace() << last; } - if (last < data + i) - ctx.j.trace() << last; + if (!result) + { + JLOG(ctx.j.trace()) + << "HookSet(" << hook::log::WASM_BAD_MAGIC << ")[" + << HS_ACC() + << "]: Malformed transaction: SetHook " + "sfCreateCode failed validation."; + return false; + } + + std::tie(maxInstrCountHook, maxInstrCountCbak) = *result; } + else if (version == 1) // Gas type + { + // validate with GasValidator + auto validationResult = + hook::validateWasmHostFunctionsForGas( + hook, ctx.rules, ctx.j); - if (!result) - return false; + if (!validationResult) + { + JLOG(ctx.j.trace()) + << "HookSet(" << hook::log::IMPORT_ILLEGAL << ")[" + << HS_ACC() + << "]: Malformed transaction: Gas-type Hook " + "validation failed: " + << validationResult.error(); + return false; + } + + auto const hasCbak = validationResult.value(); + if ((!hasCbak && hasHookCallbackGas) || + (hasCbak && !hasHookCallbackGas)) + { + JLOG(ctx.j.trace()) + << "HookSet(" << hook::log::HOOK_INVALID_FIELD + << ")[" << HS_ACC() + << "]: Malformed transaction: Gas-type Hook must " + "contain either sfHookCallbackGas if it " + "contains cbak function"; + return false; + } + + // Gas type: maxInstrCount is not pre-calculated (use Gas + // limit at runtime) + maxInstrCountHook = 0; + maxInstrCountCbak = 0; + } JLOG(ctx.j.trace()) << "HookSet(" << hook::log::WASM_SMOKE_TEST << ")[" @@ -535,7 +675,7 @@ SetHook::validateHookSetEntry(SetHookCtx& ctx, STObject const& hookSetObj) std::optional result2 = hook::HookExecutor::validateWasm( - hook.data(), (size_t)hook.size()); + hook.data(), (size_t)hook.size(), version); if (result2) { @@ -547,7 +687,7 @@ SetHook::validateHookSetEntry(SetHookCtx& ctx, STObject const& hookSetObj) return false; } - return *result; + return std::make_pair(maxInstrCountHook, maxInstrCountCbak); } } @@ -736,6 +876,11 @@ SetHook::preflight(PreflightContext const& ctx) hookSetObj.isFieldPresent(sfHookCanEmit)) return temDISABLED; + if (!ctx.rules.enabled(featureHookGas) && + (hookSetObj.isFieldPresent(sfHookCallbackGas) || + hookSetObj.isFieldPresent(sfHookWeakGas))) + return temDISABLED; + for (auto const& hookSetElement : hookSetObj) { auto const& name = hookSetElement.getFName(); @@ -744,7 +889,8 @@ SetHook::preflight(PreflightContext const& ctx) name != sfHookNamespace && name != sfHookParameters && name != sfHookOn && name != sfHookGrants && name != sfHookApiVersion && name != sfFlags && - name != sfHookCanEmit) + name != sfHookCanEmit && name != sfHookCallbackGas && + name != sfHookWeakGas) { JLOG(ctx.j.trace()) << "HookSet(" << hook::log::HOOK_INVALID_FIELD << ")[" @@ -1183,6 +1329,34 @@ struct KeyletComparator } }; +TER +validateGasHook( + STObject const& hook, + std::shared_ptr const& defSLE) +{ + auto const version = defSLE->getFieldU16(sfHookApiVersion); + if (version == 1) + { + // Gas Hook + if (!defSLE->isFieldPresent(sfHookCallbackGas) && + hook.isFieldPresent(sfHookCallbackGas)) + return tecHOOK_INVALID; + + auto const flags = hook.getFlags(); + if (((flags & hsfCOLLECT) && !hook.isFieldPresent(sfHookWeakGas)) || + (!(flags & hsfCOLLECT) && hook.isFieldPresent(sfHookWeakGas))) + return tecHOOK_INVALID; + } + else + { + // Guard Hook + if (hook.isFieldPresent(sfHookCallbackGas) || + hook.isFieldPresent(sfHookWeakGas)) + return tecHOOK_INVALID; + } + return tesSUCCESS; +} + TER SetHook::setHook() { @@ -1272,6 +1446,14 @@ SetHook::setHook() std::optional newHookCanEmit; std::optional defHookCanEmit; + std::optional oldHookWeakGas; + std::optional newHookWeakGas; + std::optional defHookWeakGas; + + std::optional oldHookCallbackGas; + std::optional newHookCallbackGas; + std::optional defHookCallbackGas; + // when hsoCREATE is invoked it populates this variable in case the hook // definition already exists and the operation falls through into a // hsoINSTALL operation instead @@ -1340,6 +1522,23 @@ SetHook::setHook() oldHookCanEmit = oldHook->get().getFieldH256(sfHookCanEmit); else if (defHookCanEmit) oldHookCanEmit = *defHookCanEmit; + + if (oldDefSLE && oldDefSLE->isFieldPresent(sfHookWeakGas)) + defHookWeakGas = oldDefSLE->getFieldU32(sfHookWeakGas); + + if (oldHook && oldHook->get().isFieldPresent(sfHookWeakGas)) + oldHookWeakGas = oldHook->get().getFieldU32(sfHookWeakGas); + else if (defHookWeakGas) + oldHookWeakGas = *defHookWeakGas; + + if (oldDefSLE && oldDefSLE->isFieldPresent(sfHookCallbackGas)) + defHookCallbackGas = oldDefSLE->getFieldU32(sfHookCallbackGas); + + if (oldHook && oldHook->get().isFieldPresent(sfHookCallbackGas)) + oldHookCallbackGas = + oldHook->get().getFieldU32(sfHookCallbackGas); + else if (defHookCallbackGas) + oldHookCallbackGas = *defHookCallbackGas; } // in preparation for three way merge populate fields if they are @@ -1515,6 +1714,31 @@ SetHook::setHook() newHook.setFieldH256(sfHookCanEmit, *newHookCanEmit); } + if (newHookWeakGas) + { + if (defHookWeakGas.has_value() && + *defHookWeakGas == *newHookWeakGas) + { + if (newHook.isFieldPresent(sfHookWeakGas)) + newHook.makeFieldAbsent(sfHookWeakGas); + } + else + newHook.setFieldU32(sfHookWeakGas, *newHookWeakGas); + } + + if (newHookCallbackGas) + { + if (defHookCallbackGas.has_value() && + *defHookCallbackGas == *newHookCallbackGas) + { + if (newHook.isFieldPresent(sfHookCallbackGas)) + newHook.makeFieldAbsent(sfHookCallbackGas); + } + else + newHook.setFieldU32( + sfHookCallbackGas, *newHookCallbackGas); + } + // parameters if (hookSetObj->get().isFieldPresent(sfHookParameters) && hookSetObj->get().getFieldArray(sfHookParameters).empty()) @@ -1559,6 +1783,10 @@ SetHook::setHook() if (flags) newHook.setFieldU32(sfFlags, *flags); + TER result = validateGasHook(newHook, oldDefSLE); + if (!isTesSuccess(result)) + return result; + newHooks.push_back(std::move(newHook)); continue; } @@ -1680,10 +1908,24 @@ SetHook::setHook() newHookDef->setFieldH256( sfHookSetTxnID, ctx.tx.getTransactionID()); newHookDef->setFieldU64(sfReferenceCount, 1); - newHookDef->setFieldAmount( - sfFee, - XRPAmount{ - hook::computeExecutionFee(maxInstrCountHook)}); + + // Set HookCallbackGas if present in hookSetObj + if (hookSetObj->get().isFieldPresent(sfHookCallbackGas)) + newHookDef->setFieldU32( + sfHookCallbackGas, + hookSetObj->get().getFieldU32(sfHookCallbackGas)); + + // Set HookWeakGas if present in hookSetObj + if (hookSetObj->get().isFieldPresent(sfHookWeakGas)) + newHookDef->setFieldU32( + sfHookWeakGas, + hookSetObj->get().getFieldU32(sfHookWeakGas)); + + if (hookSetObj->get().getFieldU16(sfHookApiVersion) != 1) + newHookDef->setFieldAmount( + sfFee, + XRPAmount{ + hook::computeExecutionFee(maxInstrCountHook)}); if (maxInstrCountCbak > 0) newHookDef->setFieldAmount( sfHookCallbackFee, @@ -1705,6 +1947,38 @@ SetHook::setHook() slesToInsert.emplace(keylet, newHookDef); newHook.setFieldH256(sfHookHash, *createHookHash); + + // Set HookCallbackGas in Hook object only if different from + // Definition + if (hookSetObj->get().isFieldPresent(sfHookCallbackGas)) + { + uint32_t objGas = + hookSetObj->get().getFieldU32(sfHookCallbackGas); + if (!newHookDef->isFieldPresent(sfHookCallbackGas) || + newHookDef->getFieldU32(sfHookCallbackGas) != + objGas) + { + newHook.setFieldU32(sfHookCallbackGas, objGas); + } + } + + // Set HookWeakGas in Hook object only if different from + // Definition + if (hookSetObj->get().isFieldPresent(sfHookWeakGas)) + { + uint32_t objGas = + hookSetObj->get().getFieldU32(sfHookWeakGas); + if (!newHookDef->isFieldPresent(sfHookWeakGas) || + newHookDef->getFieldU32(sfHookWeakGas) != objGas) + { + newHook.setFieldU32(sfHookWeakGas, objGas); + } + } + + TER result = validateGasHook(newHook, newHookDef); + if (!isTesSuccess(result)) + return result; + newHooks.push_back(std::move(newHook)); continue; } @@ -1777,6 +2051,16 @@ SetHook::setHook() *defHookCanEmit == *newHookCanEmit)) newHook.setFieldH256(sfHookCanEmit, *newHookCanEmit); + if (newHookCallbackGas && + !(defHookCallbackGas.has_value() && + *defHookCallbackGas == *newHookCallbackGas)) + newHook.setFieldU32(sfHookCallbackGas, *newHookCallbackGas); + + if (newHookWeakGas && + !(defHookWeakGas.has_value() && + *defHookWeakGas == *newHookWeakGas)) + newHook.setFieldU32(sfHookWeakGas, *newHookWeakGas); + // parameters TER result = updateHookParameters( ctx, @@ -1800,6 +2084,10 @@ SetHook::setHook() if (flags) newHook.setFieldU32(sfFlags, newFlags); + result = validateGasHook(newHook, newDefSLE); + if (!isTesSuccess(result)) + return result; + newHooks.push_back(std::move(newHook)); slesToUpdate.emplace(*newDefKeylet, newDefSLE); diff --git a/src/ripple/app/tx/impl/Transactor.cpp b/src/ripple/app/tx/impl/Transactor.cpp index 80646172a0..a29f3e5b1c 100644 --- a/src/ripple/app/tx/impl/Transactor.cpp +++ b/src/ripple/app/tx/impl/Transactor.cpp @@ -100,6 +100,11 @@ preflight1(PreflightContext const& ctx) return temMALFORMED; } + if (ctx.tx.isFieldPresent(sfHookGas) && !ctx.rules.enabled(featureHookGas)) + { + return temMALFORMED; + } + auto const ret = preflight0(ctx); if (!isTesSuccess(ret)) return ret; @@ -205,6 +210,12 @@ Transactor::Transactor(ApplyContext& ctx) { } +XRPAmount +calculateHookGas(uint32_t gas) +{ + return XRPAmount{gas}; +} + // RH NOTE: this only computes one chain at a time, so if there is a receiving // side to a txn then it must seperately be computed by a second call here XRPAmount @@ -219,6 +230,7 @@ Transactor::calculateHookChainFee( return XRPAmount{0}; XRPAmount fee{0}; + uint32_t gasTypeHookCount = 0; // Gas type hook counter auto const& hooks = hookSLE->getFieldArray(sfHooks); @@ -255,18 +267,56 @@ Transactor::calculateHookChainFee( if (hook::canHook(tx.getTxnType(), hookOn) && (!collectCallsOnly || (flags & hook::hsfCOLLECT))) { - XRPAmount const toAdd{hookDef->getFieldAmount(sfFee).xrp().drops()}; + // get HookApiVersion + uint16_t apiVersion = hookDef->getFieldU16(sfHookApiVersion); - // this overflow should never happen, if somehow it does - // fee is set to the largest possible valid xrp value to force - // fail the transaction - if (fee + toAdd < fee) - fee = XRPAmount{INITIAL_XRP.drops()}; - else - fee += toAdd; + if (apiVersion == 0) // Guard type + { + // existing logic: read HookDefinition's sfFee + XRPAmount const toAdd{ + hookDef->getFieldAmount(sfFee).xrp().drops()}; + + // this overflow should never happen, if somehow it does + // fee is set to the largest possible valid xrp value to force + // fail the transaction + if (fee + toAdd < fee) + fee = XRPAmount{INITIAL_XRP.drops()}; + else + fee += toAdd; + } + else if (apiVersion == 1) // Gas type + { + if (!collectCallsOnly) + { + // Gas type: only count + gasTypeHookCount++; + } + else + { + auto const weakFee = hookObj.isFieldPresent(sfHookWeakGas) + ? hookObj.getFieldU32(sfHookWeakGas) + : hookDef->getFieldU32(sfHookWeakGas); + XRPAmount const toAdd = calculateHookGas(weakFee); + if (fee + toAdd < fee) + fee = XRPAmount{INITIAL_XRP.drops()}; + else + fee += toAdd; + } + } } } + // Additional cost for Gas type: baseFee * 100 /Hook = 10*100 drops/Hook + if (gasTypeHookCount > 0) + { + auto const baseGasFee = view.fees().base * 100; + XRPAmount const gasTypeFee{gasTypeHookCount * baseGasFee}; + if (fee + gasTypeFee < fee) + fee = XRPAmount{INITIAL_XRP.drops()}; // overflow + else + fee += gasTypeFee; + } + return fee; } @@ -329,6 +379,47 @@ Transactor::calculateBaseFee(ReadView const& view, STTx const& tx) hookExecutionFee += toAdd; } + if (const auto hookSLE = + view.read(keylet::hook(tx.getAccountID(sfAccount)))) + { + const auto& hooks = hookSLE->getFieldArray(sfHooks); + for (auto const& hookObj : hooks) + { + if (hookObj.isFieldPresent(sfHookHash)) + { + uint32_t callbackGas = 0; + + // Priority 1: Check HookObject + if (hookObj.isFieldPresent(sfHookCallbackGas)) + { + callbackGas = + hookObj.getFieldU32(sfHookCallbackGas); + } + // Priority 2: Check HookDefinition + else if ( + hookDef && + hookDef->isFieldPresent(sfHookCallbackGas)) + { + callbackGas = + hookDef->getFieldU32(sfHookCallbackGas); + } + // Priority 3: Default to 0 (implicit) + + if (callbackGas > 0) + { + XRPAmount const toAdd = + calculateHookGas(callbackGas); + if (hookExecutionFee + toAdd < hookExecutionFee) + hookExecutionFee = + XRPAmount{INITIAL_XRP.drops()}; + else + hookExecutionFee += toAdd; + } + break; + } + } + } + assert(emitDetails.isFieldPresent(sfEmitBurden)); burden = emitDetails.getFieldU64(sfEmitBurden); @@ -346,6 +437,10 @@ Transactor::calculateBaseFee(ReadView const& view, STTx const& tx) if (canRollback) hookExecutionFee += calculateHookChainFee(view, tx, keylet::hook(tshAcc)); + + if (view.rules().enabled(featureHookGas) && + tx.isFieldPresent(sfHookGas)) + hookExecutionFee += calculateHookGas(tx.getFieldU32(sfHookGas)); } XRPAmount accumulator = baseFee; @@ -1194,6 +1289,15 @@ Transactor::executeHookChain( std::map, std::vector>> hookParamOverrides{}; + // Initialize Gas pool for Gas-type hooks + uint32_t gasPool = 0; + if (ctx_.tx.isFieldPresent(sfHookGas)) + { + gasPool = ctx_.tx.getFieldU32(sfHookGas); + JLOG(j_.trace()) << "HookChain: Initialized Gas pool with " << gasPool + << " instructions"; + } + auto const& hooks = hookSLE->getFieldArray(sfHooks); uint8_t hook_no = 0; @@ -1260,7 +1364,30 @@ Transactor::executeHookChain( return tecINTERNAL; } - bool hasCallback = hookDef->isFieldPresent(sfHookCallbackFee); + bool hasCallback = hookDef->isFieldPresent(sfHookCallbackFee) || + hookDef->isFieldPresent(sfHookCallbackGas); + + // Extract HookApiVersion for Gas-type hooks + uint16_t hookApiVersion = hookDef->isFieldPresent(sfHookApiVersion) + ? hookDef->getFieldU16(sfHookApiVersion) + : 0; + + // Prepare Gas limit for this hook execution + uint32_t hookGas = 0; + if (hookApiVersion == 1) + { + if (!strong) // WeakTSH execution + { + hookGas = hookObj.isFieldPresent(sfHookWeakGas) + ? hookObj.getFieldU32(sfHookWeakGas) + : hookDef->getFieldU32(sfHookWeakGas); + } + else // Strong execution + { + // Pass remaining Gas pool to this hook + hookGas = gasPool; + } + } try { @@ -1280,12 +1407,35 @@ Transactor::executeHookChain( strong, (strong ? 0 : 1UL), // 0 = strong, 1 = weak hook_no - 1, - provisionalMeta)); + provisionalMeta, + hookApiVersion, + hookGas)); executedHookCount_++; hook::HookResult& hookResult = results.back(); + // Track Gas consumption for Gas-type hooks + if (hookApiVersion == 1) + { + uint64_t consumed = hookResult.instructionCost; + + JLOG(j_.trace()) << "HookChain: Hook consumed " << consumed + << " instructions. Pool before: " << gasPool; + + if (consumed >= gasPool) + { + JLOG(j_.trace()) << "HookError: Gas pool exhausted. " + << "Hook tried to consume " << consumed + << " but only " << gasPool << " remained."; + return tecHOOK_INSUFFICIENT_GAS; + } + + gasPool -= consumed; + + JLOG(j_.trace()) << "HookChain: Pool after: " << gasPool; + } + if (hookResult.exitType != hook_api::ExitType::ACCEPT) { if (results.back().exitType == hook_api::ExitType::WASM_ERROR) @@ -1365,7 +1515,8 @@ Transactor::doHookCallback( return; } - if (!hookDef->isFieldPresent(sfHookCallbackFee)) + if (!hookDef->isFieldPresent(sfHookCallbackFee) && + !hookDef->isFieldPresent(sfHookCallbackGas)) { JLOG(j_.trace()) << "HookInfo[" << callbackAccountID << "]: Callback specified by emitted txn " @@ -1422,6 +1573,24 @@ Transactor::doHookCallback( { hook::HookStateMap stateMap; + // Extract HookApiVersion for callback + uint16_t hookApiVersion = hookDef->getFieldU16(sfHookApiVersion); + + // Get callback gas with fallback priority: + // 1. HookObject's HookCallbackGas + // 2. HookDefinition's HookCallbackGas + // 3. Transaction's HookGas (for backward compatibility) + uint32_t hookGas = 0; + + if (hookObj.isFieldPresent(sfHookCallbackGas)) + { + hookGas = hookObj.getFieldU32(sfHookCallbackGas); + } + else if (hookDef->isFieldPresent(sfHookCallbackGas)) + { + hookGas = hookDef->getFieldU32(sfHookCallbackGas); + } + hook::HookResult callbackResult = hook::apply( hookDef->getFieldH256(sfHookSetTxnID), callbackHookHash, @@ -1441,7 +1610,9 @@ Transactor::doHookCallback( ? 1UL : 0UL, hook_no - 1, - provisionalMeta); + provisionalMeta, + hookApiVersion, + hookGas); executedHookCount_++; @@ -1717,6 +1888,14 @@ Transactor::doAgainAsWeak( return; } + // Extract HookApiVersion for aaw execution + uint16_t hookApiVersion = hookDef->getFieldU16(sfHookApiVersion); + + // Extract HookGas for Gas-type hooks + uint32_t hookGas = 0; + if (hookApiVersion == 1 && ctx_.tx.isFieldPresent(sfHookGas)) + hookGas = ctx_.tx.getFieldU32(sfHookGas); + try { hook::HookResult aawResult = hook::apply( @@ -1730,12 +1909,15 @@ Transactor::doAgainAsWeak( stateMap, ctx_, hookAccountID, - hookDef->isFieldPresent(sfHookCallbackFee), + hookDef->isFieldPresent(sfHookCallbackFee) || + hookDef->isFieldPresent(sfHookCallbackGas), false, false, 2UL, // param 2 = aaw hook_no - 1, - provisionalMeta); + provisionalMeta, + hookApiVersion, + hookGas); executedHookCount_++; diff --git a/src/ripple/protocol/Feature.h b/src/ripple/protocol/Feature.h index 2766859dc7..dd4b12903e 100644 --- a/src/ripple/protocol/Feature.h +++ b/src/ripple/protocol/Feature.h @@ -74,7 +74,7 @@ namespace detail { // Feature.cpp. Because it's only used to reserve storage, and determine how // large to make the FeatureBitset, it MAY be larger. It MUST NOT be less than // the actual number of amendments. A LogicError on startup will verify this. -static constexpr std::size_t numFeatures = 90; +static constexpr std::size_t numFeatures = 91; /** Amendments that this server supports and the default voting behavior. Whether they are enabled depends on the Rules defined in the validated @@ -378,6 +378,7 @@ extern uint256 const fixInvalidTxFlags; extern uint256 const featureExtendedHookState; extern uint256 const fixCronStacking; extern uint256 const fixHookAPI20251128; +extern uint256 const featureHookGas; } // namespace ripple #endif diff --git a/src/ripple/protocol/SField.h b/src/ripple/protocol/SField.h index f507b22326..25e551ea90 100644 --- a/src/ripple/protocol/SField.h +++ b/src/ripple/protocol/SField.h @@ -414,6 +414,10 @@ extern SF_UINT32 const sfXahauActivationLgrSeq; extern SF_UINT32 const sfDelaySeconds; extern SF_UINT32 const sfRepeatCount; extern SF_UINT32 const sfStartTime; +extern SF_UINT32 const sfHookGas; +extern SF_UINT32 const sfHookInstructionCost; +extern SF_UINT32 const sfHookCallbackGas; +extern SF_UINT32 const sfHookWeakGas; // 64-bit integers (common) extern SF_UINT64 const sfIndexNext; diff --git a/src/ripple/protocol/TER.h b/src/ripple/protocol/TER.h index 573e0b628f..fd1afe4abc 100644 --- a/src/ripple/protocol/TER.h +++ b/src/ripple/protocol/TER.h @@ -344,6 +344,8 @@ enum TECcodes : TERUnderlyingType { tecIMMUTABLE = 188, tecTOO_MANY_REMARKS = 189, tecHAS_HOOK_STATE = 190, + tecHOOK_INSUFFICIENT_GAS = 191, + tecHOOK_INVALID = 192, tecLAST_POSSIBLE_ENTRY = 255, }; diff --git a/src/ripple/protocol/impl/Feature.cpp b/src/ripple/protocol/impl/Feature.cpp index 24383f896c..5293e52d8f 100644 --- a/src/ripple/protocol/impl/Feature.cpp +++ b/src/ripple/protocol/impl/Feature.cpp @@ -484,6 +484,7 @@ REGISTER_FIX (fixInvalidTxFlags, Supported::yes, VoteBehavior::De REGISTER_FEATURE(ExtendedHookState, Supported::yes, VoteBehavior::DefaultNo); REGISTER_FIX (fixCronStacking, Supported::yes, VoteBehavior::DefaultYes); REGISTER_FIX (fixHookAPI20251128, Supported::yes, VoteBehavior::DefaultYes); +REGISTER_FEATURE(HookGas, Supported::yes, VoteBehavior::DefaultYes); // The following amendments are obsolete, but must remain supported // because they could potentially get enabled. diff --git a/src/ripple/protocol/impl/InnerObjectFormats.cpp b/src/ripple/protocol/impl/InnerObjectFormats.cpp index 4c2500ff21..3a66e6e44c 100644 --- a/src/ripple/protocol/impl/InnerObjectFormats.cpp +++ b/src/ripple/protocol/impl/InnerObjectFormats.cpp @@ -73,7 +73,10 @@ InnerObjectFormats::InnerObjectFormats() {sfHookExecutionIndex, soeREQUIRED}, {sfHookStateChangeCount, soeREQUIRED}, {sfHookEmitCount, soeREQUIRED}, - {sfFlags, soeOPTIONAL}}); + {sfFlags, soeOPTIONAL}, + {sfHookInstructionCost, soeOPTIONAL}, + {sfHookWeakGas, soeOPTIONAL}, + {sfHookCallbackGas, soeOPTIONAL}}); add(sfHookEmission.jsonName.c_str(), sfHookEmission.getCode(), @@ -91,7 +94,7 @@ InnerObjectFormats::InnerObjectFormats() {sfHookCanEmit, soeOPTIONAL}, {sfHookApiVersion, soeREQUIRED}, {sfFlags, soeREQUIRED}, - {sfFee, soeREQUIRED}}); + {sfFee, soeOPTIONAL}}); add(sfHook.jsonName.c_str(), sfHook.getCode(), @@ -103,6 +106,8 @@ InnerObjectFormats::InnerObjectFormats() {sfHookOn, soeOPTIONAL}, {sfHookCanEmit, soeOPTIONAL}, {sfHookApiVersion, soeOPTIONAL}, + {sfHookCallbackGas, soeOPTIONAL}, + {sfHookWeakGas, soeOPTIONAL}, {sfFlags, soeOPTIONAL}}); add(sfHookGrant.jsonName.c_str(), diff --git a/src/ripple/protocol/impl/LedgerFormats.cpp b/src/ripple/protocol/impl/LedgerFormats.cpp index 5f51976be3..91821a0d6f 100644 --- a/src/ripple/protocol/impl/LedgerFormats.cpp +++ b/src/ripple/protocol/impl/LedgerFormats.cpp @@ -232,12 +232,14 @@ LedgerFormats::LedgerFormats() {sfHookCanEmit, soeOPTIONAL}, {sfHookNamespace, soeREQUIRED}, {sfHookParameters, soeREQUIRED}, - {sfHookApiVersion, soeREQUIRED}, + {sfHookApiVersion, soeREQUIRED}, {sfCreateCode, soeREQUIRED}, {sfHookSetTxnID, soeREQUIRED}, {sfReferenceCount, soeREQUIRED}, - {sfFee, soeREQUIRED}, - {sfHookCallbackFee, soeOPTIONAL} + {sfFee, soeOPTIONAL}, + {sfHookCallbackFee, soeOPTIONAL}, + {sfHookCallbackGas, soeOPTIONAL}, + {sfHookWeakGas, soeOPTIONAL} }, commonFields); diff --git a/src/ripple/protocol/impl/SField.cpp b/src/ripple/protocol/impl/SField.cpp index c4f2ef85a5..b2a7216d6d 100644 --- a/src/ripple/protocol/impl/SField.cpp +++ b/src/ripple/protocol/impl/SField.cpp @@ -158,6 +158,11 @@ CONSTRUCT_TYPED_SFIELD(sfLockCount, "LockCount", UINT32, CONSTRUCT_TYPED_SFIELD(sfFirstNFTokenSequence, "FirstNFTokenSequence", UINT32, 50); +// 32-bit integers (hook) +CONSTRUCT_TYPED_SFIELD(sfHookCallbackGas, "HookCallbackGas", UINT32, 89); +CONSTRUCT_TYPED_SFIELD(sfHookWeakGas, "HookWeakGas", UINT32, 90); +CONSTRUCT_TYPED_SFIELD(sfHookInstructionCost, "HookInstructionCost", UINT32, 91); +CONSTRUCT_TYPED_SFIELD(sfHookGas, "HookGas", UINT32, 92); CONSTRUCT_TYPED_SFIELD(sfStartTime, "StartTime", UINT32, 93); CONSTRUCT_TYPED_SFIELD(sfRepeatCount, "RepeatCount", UINT32, 94); CONSTRUCT_TYPED_SFIELD(sfDelaySeconds, "DelaySeconds", UINT32, 95); diff --git a/src/ripple/protocol/impl/TER.cpp b/src/ripple/protocol/impl/TER.cpp index 08992c6a31..96a60822ec 100644 --- a/src/ripple/protocol/impl/TER.cpp +++ b/src/ripple/protocol/impl/TER.cpp @@ -95,6 +95,8 @@ transResults() MAKE_ERROR(tecIMMUTABLE, "The remark is marked immutable on the object, and therefore cannot be updated."), MAKE_ERROR(tecTOO_MANY_REMARKS, "The number of remarks on the object would exceed the limit of 32."), MAKE_ERROR(tecHAS_HOOK_STATE, "Delete all hook state before reducing scale"), + MAKE_ERROR(tecHOOK_INSUFFICIENT_GAS, "Insufficient hook gas to complete the transaction."), + MAKE_ERROR(tecHOOK_INVALID, "Invalid hook."), MAKE_ERROR(tefALREADY, "The exact transaction was already in this ledger."), MAKE_ERROR(tefBAD_ADD_AUTH, "Not authorized to add account."), diff --git a/src/ripple/protocol/impl/TxFormats.cpp b/src/ripple/protocol/impl/TxFormats.cpp index 789de36f2d..87162f55e8 100644 --- a/src/ripple/protocol/impl/TxFormats.cpp +++ b/src/ripple/protocol/impl/TxFormats.cpp @@ -44,6 +44,7 @@ TxFormats::TxFormats() {sfNetworkID, soeOPTIONAL}, {sfHookParameters, soeOPTIONAL}, {sfOperationLimit, soeOPTIONAL}, + {sfHookGas, soeOPTIONAL}, }; add(jss::AccountSet, diff --git a/src/test/app/SetHook_test.cpp b/src/test/app/SetHook_test.cpp index 0c7be29e81..b2065e79f8 100644 --- a/src/test/app/SetHook_test.cpp +++ b/src/test/app/SetHook_test.cpp @@ -17,6 +17,7 @@ */ //============================================================================== #include +#include #include #include #include @@ -27,6 +28,7 @@ #include #include #include +#include #include namespace ripple { @@ -81,7 +83,11 @@ class SetHook0_test : public beast::unit_test::suite // helper void static overrideFlag(Json::Value& jv) { - jv[jss::Flags] = hsfOVERRIDE; + jv[jss::Flags] = jv[jss::Flags].asUInt() | hsfOVERRIDE; + } + void static collectFlag(Json::Value& jv) + { + jv[jss::Flags] = jv[jss::Flags].asUInt() | hsfCOLLECT; } public: @@ -13378,189 +13384,213 @@ class SetHook0_test : public beast::unit_test::suite } void - testWithFeatures(FeatureBitset features) + testGasTypeHookHostFunctionValidation(FeatureBitset features) { - testHooksOwnerDir(features); - testHooksDisabled(features); - testTxStructure(features); - testInvalidTxFlags(features); - testInferHookSetOperation(); - testParams(features); - testGrants(features); - testHookCanEmit(features); - - testDelete(features); - testInstall(features); - testCreate(features); - testWithTickets(features); - - testUpdate(features); - - testNSDelete(features); - testNSDeletePartial(features); - testPageCap(features); - - testFillCopy(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_xpop_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); // + testcase("Direct test of validateWasmHostFunctionsForGas"); + using namespace jtx; - test_trace(features); // - test_trace_float(features); // - test_trace_num(features); // + Env env{*this, features}; + auto const& rules = env.current()->rules(); + auto const& j = env.journal; + + // Test 1: Valid gas hook (no _g) should return nullopt + { + // Gas Type Hook Host Function Validation Tests - WASM Definitions + + // Test 1: Valid Gas hook - no _g function (should succeed) + TestHook gas_valid_no_g_wasm = wasm[ + R"[test.hook.gas]( + (module + (type (;0;) (func (param i32 i32 i64) (result i64))) + (type (;1;) (func (param i32) (result i64))) + (import "env" "accept" (func (;0;) (type 0))) + (import "env" "trace_num" (func (;1;) (type 0))) + (func (;2;) (type 1) (param i32) (result i64) + i32.const 0 + i32.const 15 + i64.const 1 + call 1 + drop + i32.const 0 + i32.const 0 + i64.const 0 + call 0) + (memory (;0;) 2) + (export "memory" (memory 0)) + (export "hook" (func 2))) + )[test.hook.gas]"]; + + HASH_WASM(gas_valid_no_g); + + auto result = hook::validateWasmHostFunctionsForGas( + gas_valid_no_g_wasm, rules, j); + BEAST_EXPECT(result.has_value()); // No error + } + + // Test 2: Invalid gas hook (has _g) should return error + { + // Test 2: Invalid Gas hook - contains _g function (should fail) + TestHook gas_invalid_with_g_wasm = wasm[ + R"[test.hook.gas]( + (module + (type (;0;) (func (param i32 i32) (result i32))) + (type (;1;) (func (param i32 i32 i64) (result i64))) + (type (;2;) (func (param i32) (result i64))) + (import "env" "_g" (func (;0;) (type 0))) + (import "env" "accept" (func (;1;) (type 1))) + (func (;2;) (type 2) (param i32) (result i64) + i32.const 1 + i32.const 1 + call 0 + drop + i32.const 0 + i32.const 0 + i64.const 0 + call 1) + (memory (;0;) 2) + (export "memory" (memory 0)) + (export "hook" (func 2))) + )[test.hook.gas]"]; + + HASH_WASM(gas_invalid_with_g); + auto result = hook::validateWasmHostFunctionsForGas( + gas_invalid_with_g_wasm, rules, j); + BEAST_EXPECT(!result.has_value()); // Has error + if (!result.has_value()) + { + BEAST_EXPECT( + result.error().find( + "Gas-type hooks cannot import _g (guard) function") != + std::string::npos); + } + } - test_util_accid(features); // - test_util_keylet(features); // - test_util_raddr(features); // - test_util_sha512h(features); // - test_util_verify(features); // + // Test 3: Valid gas hook with multiple allowed host functions should + // return nullopt + { + // Test 3: Valid Gas hook - multiple allowed host functions + TestHook gas_valid_multi_hostfn_wasm = wasm[ + R"[test.hook.gas]( + (module + (type (;0;) (func (param i32 i32 i64) (result i64))) + (type (;1;) (func (result i64))) + (type (;2;) (func (param i32) (result i64))) + (import "env" "accept" (func (;0;) (type 0))) + (import "env" "trace_num" (func (;1;) (type 0))) + (import "env" "ledger_seq" (func (;2;) (type 1))) + (import "env" "fee_base" (func (;3;) (type 1))) + (func (;4;) (type 2) (param i32) (result i64) + (local i64 i64) + call 2 + local.set 1 + call 3 + local.set 2 + i32.const 0 + i32.const 10 + local.get 1 + call 1 + drop + i32.const 0 + i32.const 8 + local.get 2 + call 1 + drop + i32.const 0 + i32.const 0 + i64.const 0 + call 0) + (memory (;0;) 2) + (export "memory" (memory 0)) + (export "hook" (func 4))) + )[test.hook.gas]"]; + + HASH_WASM(gas_valid_multi_hostfn); + + auto result = hook::validateWasmHostFunctionsForGas( + gas_valid_multi_hostfn_wasm, rules, j); + BEAST_EXPECT(result.has_value()); // No error + BEAST_EXPECT(*result == false); // cbak function is not present + } + + // Test4: cbak function is present + { + TestHook gas_accept_with_cbak_wasm = wasm[ + R"[test.hook.gas]( + (module + (type (;0;) (func (param i32 i32 i64) (result i64))) + (type (;1;) (func (param i32) (result i64))) + (import "env" "accept" (func (;0;) (type 0))) + (func (;1;) (type 1) (param i32) (result i64) + i32.const 0 + i32.const 0 + i64.const 0 + call 0) + (memory (;0;) 2) + (export "memory" (memory 0)) + (export "hook" (func 1)) + (export "cbak" (func 1))) + )[test.hook.gas]"]; + + HASH_WASM(gas_accept_with_cbak); + auto result = hook::validateWasmHostFunctionsForGas( + gas_accept_with_cbak_wasm, rules, j); + BEAST_EXPECT(result.has_value()); // No error + BEAST_EXPECT(*result == true); // cbak function is present + } + // Note: Export and Import error tests are in separate functions } -public: void - run(std::uint32_t instance, bool last = false) + testGasTypeHookExportErrors(FeatureBitset features) { - using namespace test::jtx; - static FeatureBitset const all{supported_amendments()}; - - static std::array const feats{ - all, - all - fixXahauV2, - all - fixXahauV1 - fixXahauV2, - all - fixXahauV1 - fixXahauV2 - fixNSDelete, - all - fixXahauV1 - fixXahauV2 - fixNSDelete - fixPageCap, - all - fixXahauV1 - fixXahauV2 - fixNSDelete - fixPageCap - - featureHookCanEmit, - all - fixXahauV1 - fixXahauV2 - fixNSDelete - fixPageCap - - featureExtendedHookState, - }; - - if (BEAST_EXPECT(instance < feats.size())) - { - testWithFeatures(feats[instance]); - } - BEAST_EXPECT(!last || instance == feats.size() - 1); - } + testcase("Test Gas-type Hook export section validation"); + using namespace jtx; - void - run() override - { - run(0); - } + Env env{*this, features}; + auto const& rules = env.current()->rules(); + auto const& j = env.journal; -private: - TestHook accept_wasm = // WASM: 0 - wasm[ - R"[test.hook]( - #include - extern int32_t _g (uint32_t id, uint32_t maxiter); - extern int64_t accept (uint32_t read_ptr, uint32_t read_len, int64_t error_code); - int64_t hook(uint32_t reserved ) - { - _g(1,1); - return accept(0,0,0); - } - )[test.hook]"]; + // Test: No exports at all + TestHook test_gas_validation_no_exports_wasm = wasm[ + R"[test.hook.gas]( + (module + (type (;0;) (func (param i32 i32 i64) (result i64))) + (type (;1;) (func (param i32) (result i64))) + (import "env" "accept" (func (;0;) (type 0))) + (func (;1;) (type 1) (param i32) (result i64) + i32.const 0 + i32.const 0 + i64.const 0 + call 0) + (memory (;0;) 2)) + )[test.hook.gas]"]; - HASH_WASM(accept); + HASH_WASM(test_gas_validation_no_exports); - TestHook rollback_wasm = // WASM: 1 - wasm[ - R"[test.hook]( - #include - extern int32_t _g (uint32_t id, uint32_t maxiter); - extern int64_t rollback (uint32_t read_ptr, uint32_t read_len, int64_t error_code); - #define SBUF(x) (uint32_t)(x),sizeof(x) - int64_t hook(uint32_t reserved ) - { - _g(1,1); - return rollback(SBUF("Hook Rejected"),0); - } - )[test.hook]"]; + // Test 5: Export Section Error - Export function named + // "unauthorized_fn" + TestHook test_gas_validation_unauthorized_export_wasm = wasm[ + R"[test.hook.gas]( + (module + (type (;0;) (func (param i32 i32 i64) (result i64))) + (type (;1;) (func (param i32) (result i64))) + (import "env" "accept" (func (;0;) (type 0))) + (func (;1;) (type 1) (param i32) (result i64) + i32.const 0 + i32.const 0 + i64.const 0 + call 0) + (memory (;0;) 2) + (export "memory" (memory 0)) + (export "hook" (func 1)) + (export "unauthorized_fn" (func 1))) + )[test.hook.gas]"]; - HASH_WASM(rollback); + HASH_WASM(test_gas_validation_unauthorized_export); - TestHook noguard_wasm = // WASM: 2 - wasm[ - R"[test.hook]( + // Test 6: Export Section Error - Only export cbak, not hook + TestHook test_gas_validation_missing_hook_export_wasm = wasm[ + R"[test.hook.gas]( (module (type (;0;) (func (param i32 i32 i64) (result i64))) (type (;1;) (func (param i32) (result i64))) @@ -13572,64 +13602,1454 @@ class SetHook0_test : public beast::unit_test::suite call 0) (memory (;0;) 2) (export "memory" (memory 0)) - (export "hook" (func 1))) - )[test.hook]"]; + (export "cbak" (func 1))) + )[test.hook.gas]"]; - TestHook illegalfunc_wasm = // WASM: 3 - wasm[ - R"[test.hook]( + HASH_WASM(test_gas_validation_missing_hook_export); + + // Test 7: Export Section Error - hook() with signature () -> i64 + TestHook test_gas_validation_hook_no_params_wasm = wasm[ + R"[test.hook.gas]( (module - (type (;0;) (func (param i32 i32) (result i32))) - (type (;1;) (func (param i32 i32 i64) (result i64))) - (type (;2;) (func)) - (type (;3;) (func (param i32) (result i64))) - (import "env" "_g" (func (;0;) (type 0))) - (import "env" "accept" (func (;1;) (type 1))) - (func (;2;) (type 3) (param i32) (result i64) - i32.const 1 - i32.const 1 - call 0 - drop + (type (;0;) (func (param i32 i32 i64) (result i64))) + (type (;1;) (func (result i64))) + (import "env" "accept" (func (;0;) (type 0))) + (func (;1;) (type 1) (result i64) i32.const 0 i32.const 0 i64.const 0 - call 1) - (func (;3;) (type 2) - i32.const 1 - i32.const 1 - call 0 - drop) + call 0) (memory (;0;) 2) - (global (;0;) (mut i32) (i32.const 66560)) - (global (;1;) i32 (i32.const 1024)) - (global (;2;) i32 (i32.const 1024)) - (global (;3;) i32 (i32.const 66560)) - (global (;4;) i32 (i32.const 1024)) (export "memory" (memory 0)) - (export "hook" (func 2)) - (export "bad_func" (func 3))) - )[test.hook]"]; + (export "hook" (func 1))) + )[test.hook.gas]"]; - TestHook long_wasm = // WASM: 4 - wasm[ - R"[test.hook]( - #include - extern int32_t _g (uint32_t id, uint32_t maxiter); - extern int64_t accept (uint32_t read_ptr, uint32_t read_len, int64_t error_code); - #define SBUF(x) (uint32_t)(x), sizeof(x) - #define M_REPEAT_10(X) X X X X X X X X X X - #define M_REPEAT_100(X) M_REPEAT_10(M_REPEAT_10(X)) - #define M_REPEAT_1000(X) M_REPEAT_100(M_REPEAT_10(X)) - int64_t hook(uint32_t reserved ) - { - _g(1,1); - char ret[] = M_REPEAT_1000("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz01234567890123"); - return accept(SBUF(ret), 0); - } - )[test.hook]"]; + HASH_WASM(test_gas_validation_hook_no_params); - TestHook makestate_wasm = // WASM: 5 - wasm[ + // Test 8: Export Section Error - hook() with signature (i32, i32) -> + // i64 + TestHook test_gas_validation_hook_too_many_params_wasm = wasm[ + R"[test.hook.gas]( + (module + (type (;0;) (func (param i32 i32 i64) (result i64))) + (type (;1;) (func (param i32 i32) (result i64))) + (import "env" "accept" (func (;0;) (type 0))) + (func (;1;) (type 1) (param i32 i32) (result i64) + i32.const 0 + i32.const 0 + i64.const 0 + call 0) + (memory (;0;) 2) + (export "memory" (memory 0)) + (export "hook" (func 1))) + )[test.hook.gas]"]; + + HASH_WASM(test_gas_validation_hook_too_many_params); + + // Test 9: Export Section Error - hook() with signature (i64) -> i64 + TestHook test_gas_validation_hook_wrong_param_type_wasm = wasm[ + R"[test.hook.gas]( + (module + (type (;0;) (func (param i32 i32 i64) (result i64))) + (type (;1;) (func (param i64) (result i64))) + (import "env" "accept" (func (;0;) (type 0))) + (func (;1;) (type 1) (param i64) (result i64) + i32.const 0 + i32.const 0 + i64.const 0 + call 0) + (memory (;0;) 2) + (export "memory" (memory 0)) + (export "hook" (func 1))) + )[test.hook.gas]"]; + + HASH_WASM(test_gas_validation_hook_wrong_param_type); + + // Test 10: Export Section Error - hook() with signature (i32) (no + // return) + TestHook test_gas_validation_hook_no_return_wasm = wasm[ + R"[test.hook.gas]( + (module + (type (;0;) (func (param i32 i32 i64) (result i64))) + (type (;1;) (func (param i32))) + (import "env" "accept" (func (;0;) (type 0))) + (func (;1;) (type 1) (param i32) + i32.const 0 + i32.const 0 + i64.const 0 + call 0 + drop) + (memory (;0;) 2) + (export "memory" (memory 0)) + (export "hook" (func 1))) + )[test.hook.gas]"]; + + HASH_WASM(test_gas_validation_hook_no_return); + + // Test 11: Export Section Error - hook() with signature (i32) -> i32 + TestHook test_gas_validation_hook_wrong_return_type_wasm = wasm[ + R"[test.hook.gas]( + (module + (type (;0;) (func (param i32 i32 i64) (result i64))) + (type (;1;) (func (param i32) (result i32))) + (import "env" "accept" (func (;0;) (type 0))) + (func (;1;) (type 1) (param i32) (result i32) + i32.const 0 + i32.const 0 + i64.const 0 + call 0 + drop + i32.const 0) + (memory (;0;) 2) + (export "memory" (memory 0)) + (export "hook" (func 1))) + )[test.hook.gas]"]; + + HASH_WASM(test_gas_validation_hook_wrong_return_type); + + // Test 12: Export Section Error - cbak() with signature () -> i64 + TestHook test_gas_validation_cbak_wrong_params_wasm = wasm[ + R"[test.hook.gas]( + (module + (type (;0;) (func (param i32 i32 i64) (result i64))) + (type (;1;) (func (param i32) (result i64))) + (type (;2;) (func (result i64))) + (import "env" "accept" (func (;0;) (type 0))) + (func (;1;) (type 1) (param i32) (result i64) + i32.const 0 + i32.const 0 + i64.const 0 + call 0) + (func (;2;) (type 2) (result i64) + i32.const 0 + i32.const 0 + i64.const 0 + call 0) + (memory (;0;) 2) + (export "memory" (memory 0)) + (export "hook" (func 1)) + (export "cbak" (func 2))) + )[test.hook.gas]"]; + + HASH_WASM(test_gas_validation_cbak_wrong_params); + + // Test 13: Export Section Error - cbak() with signature (i64) -> i64 + TestHook test_gas_validation_cbak_wrong_param_type_wasm = wasm[ + R"[test.hook.gas]( + (module + (type (;0;) (func (param i32 i32 i64) (result i64))) + (type (;1;) (func (param i32) (result i64))) + (type (;2;) (func (param i64) (result i64))) + (import "env" "accept" (func (;0;) (type 0))) + (func (;1;) (type 1) (param i32) (result i64) + i32.const 0 + i32.const 0 + i64.const 0 + call 0) + (func (;2;) (type 2) (param i64) (result i64) + i32.const 0 + i32.const 0 + i64.const 0 + call 0) + (memory (;0;) 2) + (export "memory" (memory 0)) + (export "hook" (func 1)) + (export "cbak" (func 2))) + )[test.hook.gas]"]; + + HASH_WASM(test_gas_validation_cbak_wrong_param_type); + + // Test 14: Export Section Error - cbak() with signature (i32) -> i32 + TestHook test_gas_validation_cbak_wrong_return_type_wasm = wasm[ + R"[test.hook.gas]( + (module + (type (;0;) (func (param i32 i32 i64) (result i64))) + (type (;1;) (func (param i32) (result i64))) + (type (;2;) (func (param i32) (result i32))) + (import "env" "accept" (func (;0;) (type 0))) + (func (;1;) (type 1) (param i32) (result i64) + i32.const 0 + i32.const 0 + i64.const 0 + call 0) + (func (;2;) (type 2) (param i32) (result i32) + i32.const 0 + i32.const 0 + i64.const 0 + call 0 + drop + i32.const 0) + (memory (;0;) 2) + (export "memory" (memory 0)) + (export "hook" (func 1)) + (export "cbak" (func 2))) + )[test.hook.gas]"]; + + HASH_WASM(test_gas_validation_cbak_wrong_return_type); + + // Execute export section error tests + { + auto result = hook::validateWasmHostFunctionsForGas( + test_gas_validation_no_exports_wasm, rules, j); + BEAST_EXPECT(!result.has_value()); + if (!result.has_value()) + BEAST_EXPECT( + result.error().find( + "WASM must export at least hook API functions") != + std::string::npos); + } + + { + auto result = hook::validateWasmHostFunctionsForGas( + test_gas_validation_unauthorized_export_wasm, rules, j); + BEAST_EXPECT(!result.has_value()); + if (!result.has_value()) + BEAST_EXPECT( + result.error().find("Unauthorized export function") != + std::string::npos); + } + + { + auto result = hook::validateWasmHostFunctionsForGas( + test_gas_validation_missing_hook_export_wasm, rules, j); + BEAST_EXPECT(!result.has_value()); + if (!result.has_value()) + BEAST_EXPECT( + result.error().find("Required function 'hook' not found") != + std::string::npos); + } + + { + auto result = hook::validateWasmHostFunctionsForGas( + test_gas_validation_hook_no_params_wasm, rules, j); + BEAST_EXPECT(!result.has_value()); + if (!result.has_value()) + BEAST_EXPECT( + result.error().find("must have exactly 1 parameter") != + std::string::npos); + } + + { + auto result = hook::validateWasmHostFunctionsForGas( + test_gas_validation_hook_too_many_params_wasm, rules, j); + BEAST_EXPECT(!result.has_value()); + if (!result.has_value()) + BEAST_EXPECT( + result.error().find("must have exactly 1 parameter") != + std::string::npos); + } + + { + auto result = hook::validateWasmHostFunctionsForGas( + test_gas_validation_hook_wrong_param_type_wasm, rules, j); + BEAST_EXPECT(!result.has_value()); + if (!result.has_value()) + BEAST_EXPECT( + result.error().find("parameter must be uint32_t") != + std::string::npos); + } + + { + auto result = hook::validateWasmHostFunctionsForGas( + test_gas_validation_hook_no_return_wasm, rules, j); + BEAST_EXPECT(!result.has_value()); + if (!result.has_value()) + BEAST_EXPECT( + result.error().find("must return exactly 1 value") != + std::string::npos); + } + + { + auto result = hook::validateWasmHostFunctionsForGas( + test_gas_validation_hook_wrong_return_type_wasm, rules, j); + BEAST_EXPECT(!result.has_value()); + if (!result.has_value()) + BEAST_EXPECT( + result.error().find("return type must be uint64_t") != + std::string::npos); + } + + { + auto result = hook::validateWasmHostFunctionsForGas( + test_gas_validation_cbak_wrong_params_wasm, rules, j); + BEAST_EXPECT(!result.has_value()); + if (!result.has_value()) + BEAST_EXPECT( + result.error().find("must have exactly 1 parameter") != + std::string::npos); + } + + { + auto result = hook::validateWasmHostFunctionsForGas( + test_gas_validation_cbak_wrong_param_type_wasm, rules, j); + BEAST_EXPECT(!result.has_value()); + if (!result.has_value()) + BEAST_EXPECT( + result.error().find("parameter must be uint32_t") != + std::string::npos); + } + + { + auto result = hook::validateWasmHostFunctionsForGas( + test_gas_validation_cbak_wrong_return_type_wasm, rules, j); + BEAST_EXPECT(!result.has_value()); + if (!result.has_value()) + BEAST_EXPECT( + result.error().find("return type must be uint64_t") != + std::string::npos); + } + } + + void + testGasTypeHookImportErrors(FeatureBitset features) + { + testcase("Test Gas-type Hook import section validation"); + using namespace jtx; + + Env env{*this, features}; + auto const& rules = env.current()->rules(); + auto const& j = env.journal; + + // Test: No imports (should fail) + TestHook test_gas_validation_no_imports_wasm = wasm[ + R"[test.hook.gas]( + (module + (type (;0;) (func (param i32) (result i64))) + (func (;0;) (type 0) (param i32) (result i64) + i64.const 0) + (memory (;0;) 2) + (export "memory" (memory 0)) + (export "hook" (func 0))) + )[test.hook.gas]"]; + + HASH_WASM(test_gas_validation_no_imports); + + // Test: Import from wrong module (should fail) + TestHook test_gas_validation_wrong_import_module_wasm = wasm[ + R"[test.hook.gas]( + (module + (type (;0;) (func (param i32 i32 i64) (result i64))) + (type (;1;) (func (param i32) (result i64))) + (import "wasi_snapshot_preview1" "fd_write" (func (;0;) (type 0))) + (func (;1;) (type 1) (param i32) (result i64) + i32.const 0 + i32.const 0 + i64.const 0 + call 0) + (memory (;0;) 2) + (export "memory" (memory 0)) + (export "hook" (func 1))) + )[test.hook.gas]"]; + + HASH_WASM(test_gas_validation_wrong_import_module); + + // Test: Import not in whitelist (should fail) + TestHook test_gas_validation_import_not_whitelisted_wasm = wasm[ + R"[test.hook.gas]( + (module + (type (;0;) (func (param i32) (result i32))) + (type (;1;) (func (param i32) (result i64))) + (import "env" "malloc" (func (;0;) (type 0))) + (func (;1;) (type 1) (param i32) (result i64) + i64.const 0) + (memory (;0;) 2) + (export "memory" (memory 0)) + (export "hook" (func 1))) + )[test.hook.gas]"]; + + HASH_WASM(test_gas_validation_import_not_whitelisted); + + // Test: Import with no return value (should fail) + TestHook test_gas_validation_import_no_return_wasm = wasm[ + R"[test.hook.gas]( + (module + (type (;0;) (func (param i32 i32 i64))) + (type (;1;) (func (param i32) (result i64))) + (import "env" "accept" (func (;0;) (type 0))) + (func (;1;) (type 1) (param i32) (result i64) + i64.const 0) + (memory (;0;) 2) + (export "memory" (memory 0)) + (export "hook" (func 1))) + )[test.hook.gas]"]; + + HASH_WASM(test_gas_validation_import_no_return); + + // Test: Import with wrong return type (should fail) + TestHook test_gas_validation_import_wrong_return_type_wasm = wasm[ + R"[test.hook.gas]( + (module + (type (;0;) (func (param i32 i32 i64) (result i32))) + (type (;1;) (func (param i32) (result i64))) + (import "env" "accept" (func (;0;) (type 0))) + (func (;1;) (type 1) (param i32) (result i64) + i64.const 0) + (memory (;0;) 2) + (export "memory" (memory 0)) + (export "hook" (func 1))) + )[test.hook.gas]"]; + + HASH_WASM(test_gas_validation_import_wrong_return_type); + + // Test: Import with too few parameters (should fail) + TestHook test_gas_validation_import_too_few_params_wasm = wasm[ + R"[test.hook.gas]( + (module + (type (;0;) (func (param i32) (result i64))) + (type (;1;) (func (param i32) (result i64))) + (import "env" "accept" (func (;0;) (type 0))) + (func (;1;) (type 1) (param i32) (result i64) + i32.const 0 + call 0) + (memory (;0;) 2) + (export "memory" (memory 0)) + (export "hook" (func 1))) + )[test.hook.gas]"]; + + HASH_WASM(test_gas_validation_import_too_few_params); + + // Test: Import with too many parameters (should fail) + TestHook test_gas_validation_import_too_many_params_wasm = wasm[ + R"[test.hook.gas]( + (module + (type (;0;) (func (param i32 i32 i64 i32) (result i64))) + (type (;1;) (func (param i32) (result i64))) + (import "env" "accept" (func (;0;) (type 0))) + (func (;1;) (type 1) (param i32) (result i64) + i64.const 0) + (memory (;0;) 2) + (export "memory" (memory 0)) + (export "hook" (func 1))) + )[test.hook.gas]"]; + + HASH_WASM(test_gas_validation_import_too_many_params); + + // Test: Import with wrong parameter type (should fail) + TestHook test_gas_validation_import_wrong_param_type_wasm = wasm[ + R"[test.hook.gas]( + (module + (type (;0;) (func (param i64 i32 i64) (result i64))) + (type (;1;) (func (param i32) (result i64))) + (import "env" "accept" (func (;0;) (type 0))) + (func (;1;) (type 1) (param i32) (result i64) + i64.const 0) + (memory (;0;) 2) + (export "memory" (memory 0)) + (export "hook" (func 1))) + )[test.hook.gas]"]; + + HASH_WASM(test_gas_validation_import_wrong_param_type); + + // Test: Import with multiple wrong parameter types (should fail) + TestHook test_gas_validation_import_multiple_wrong_params_wasm = wasm[ + R"[test.hook.gas]( + (module + (type (;0;) (func (param i64 i64 i64 i64 i64 i64) (result i64))) + (type (;1;) (func (param i32) (result i64))) + (import "env" "util_verify" (func (;0;) (type 0))) + (func (;1;) (type 1) (param i32) (result i64) + i64.const 0) + (memory (;0;) 2) + (export "memory" (memory 0)) + (export "hook" (func 1))) + )[test.hook.gas]"]; + + HASH_WASM(test_gas_validation_import_multiple_wrong_params); + + // ======================================== + // Execute import error test cases + // ======================================== + { + auto result = hook::validateWasmHostFunctionsForGas( + test_gas_validation_no_imports_wasm, rules, j); + BEAST_EXPECT(!result.has_value()); + if (!result.has_value()) + BEAST_EXPECT( + result.error().find( + "WASM must import at least hook API functions") != + std::string::npos); + } + + { + auto result = hook::validateWasmHostFunctionsForGas( + test_gas_validation_wrong_import_module_wasm, rules, j); + BEAST_EXPECT(!result.has_value()); + if (!result.has_value()) + BEAST_EXPECT( + result.error().find("Import module must be 'env'") != + std::string::npos); + } + + { + auto result = hook::validateWasmHostFunctionsForGas( + test_gas_validation_import_not_whitelisted_wasm, rules, j); + BEAST_EXPECT(!result.has_value()); + if (!result.has_value()) + BEAST_EXPECT( + result.error().find("Import not in whitelist") != + std::string::npos); + } + + { + auto result = hook::validateWasmHostFunctionsForGas( + test_gas_validation_import_no_return_wasm, rules, j); + BEAST_EXPECT(!result.has_value()); + if (!result.has_value()) + BEAST_EXPECT( + result.error().find("must return exactly 1 value") != + std::string::npos); + } + + { + auto result = hook::validateWasmHostFunctionsForGas( + test_gas_validation_import_wrong_return_type_wasm, rules, j); + BEAST_EXPECT(!result.has_value()); + if (!result.has_value()) + BEAST_EXPECT( + result.error().find("has incorrect return type") != + std::string::npos); + } + + { + auto result = hook::validateWasmHostFunctionsForGas( + test_gas_validation_import_too_few_params_wasm, rules, j); + BEAST_EXPECT(!result.has_value()); + if (!result.has_value()) + BEAST_EXPECT( + result.error().find("has incorrect parameter count") != + std::string::npos); + } + + { + auto result = hook::validateWasmHostFunctionsForGas( + test_gas_validation_import_too_many_params_wasm, rules, j); + BEAST_EXPECT(!result.has_value()); + if (!result.has_value()) + BEAST_EXPECT( + result.error().find("has incorrect parameter count") != + std::string::npos); + } + + { + auto result = hook::validateWasmHostFunctionsForGas( + test_gas_validation_import_wrong_param_type_wasm, rules, j); + BEAST_EXPECT(!result.has_value()); + if (!result.has_value()) + BEAST_EXPECT( + result.error().find("has incorrect parameter types") != + std::string::npos); + } + + { + auto result = hook::validateWasmHostFunctionsForGas( + test_gas_validation_import_multiple_wrong_params_wasm, + rules, + j); + BEAST_EXPECT(!result.has_value()); + if (!result.has_value()) + BEAST_EXPECT( + result.error().find("has incorrect parameter types") != + std::string::npos); + } + } + + void + testGasTypeHookDisabled(FeatureBitset features) + { + testcase("Test Gas-type Hook disabled"); + using namespace jtx; + Env env{*this, features - featureHookGas}; + auto const alice = Account{"alice"}; + env.fund(XRP(10000), alice); + env.close(); + + // Install a Gas-type hook with Version 1 + Json::Value jvh = hso(gas_accept_wasm, overrideFlag); + jvh[jss::HookApiVersion] = 0; + + env(ripple::test::jtx::hook(alice, {{jvh}}, 0), + M("test gas type hook installation"), + HSFEE, + ter(temMALFORMED)); + + // Install a Gas-type hook with Version 1 + jvh[jss::HookApiVersion] = 1; + + env(ripple::test::jtx::hook(alice, {{jvh}}, 0), + M("test gas type hook installation"), + HSFEE, + ter(temMALFORMED)); + + // HookGas field + env(invoke::invoke(alice), + hookgas(1000000), + M("test gas type hook invocation"), + fee(XRP(1)), + ter(temMALFORMED)); + env.close(); + } + + void + testGasTypeHookInstallation(FeatureBitset features) + { + testcase("Test Gas-type Hook installation"); + using namespace jtx; + + Env env{*this, features}; + auto const alice = Account{"alice"}; + env.fund(XRP(10000), alice); + env.close(); + + { + // Invalid installation + // sfHookCallbackGas is present but cbak is not in the hook + Json::Value jvh = hso(gas_accept_wasm, overrideFlag); + jvh[jss::HookApiVersion] = 1; + jvh[sfHookCallbackGas.jsonName] = 1000000; + env(ripple::test::jtx::hook(alice, {{jvh}}, 0), + M("test gas type hook installation"), + HSFEE, + ter(temMALFORMED)); + } + { + // Invalid installation + // sfHookCallbackGas is not present but cbak is in the hook + Json::Value jvh = hso(gas_accept_with_cbak_wasm, overrideFlag); + jvh[jss::HookApiVersion] = 1; + env(ripple::test::jtx::hook(alice, {{jvh}}, 0), + M("test gas type hook installation"), + HSFEE, + ter(temMALFORMED)); + } + { + // Invalid installation + // sfHookWeakGas is present but collect flag is not set + Json::Value jvh = hso(gas_accept_wasm, overrideFlag); + jvh[jss::HookApiVersion] = 1; + jvh[sfHookWeakGas.jsonName] = 1000000; + env(ripple::test::jtx::hook(alice, {{jvh}}, 0), + M("test gas type hook installation"), + HSFEE, + ter(temMALFORMED)); + } + { + // Invalid installation + // sfHookWeakGas is not present but collect flag is set + Json::Value jvh = hso(gas_accept_wasm, collectFlag); + jvh[jss::HookApiVersion] = 1; + env(ripple::test::jtx::hook(alice, {{jvh}}, 0), + M("test gas type hook installation"), + HSFEE, + ter(temMALFORMED)); + } + + // Install a Gas-type hook using gas_accept_wasm + Json::Value jvh = hso(gas_accept_wasm, overrideFlag); + jvh[jss::HookApiVersion] = 1; + + env(ripple::test::jtx::hook(alice, {{jvh}}, 0), + M("test gas type hook installation"), + HSFEE); + env.close(); + + // no HookGas field for Gas-type hook + env(invoke::invoke(alice), + M("test gas type hook invocation"), + fee(XRP(1)), + ter(tecHOOK_INSUFFICIENT_GAS)); + env.close(); + + // insufficient fee for gas type hook + // baseFee + HookGas fee + gas type Hook call fee (baseFee*100) + auto const expectedGas = 1'000'000; + auto const baseFee = env.current()->fees().base; + auto const expectedFee = + baseFee + drops(expectedGas) + drops(baseFee * 100); + env(invoke::invoke(alice), + hookgas(expectedGas), + fee(expectedFee - drops(1)), + ter(telINSUF_FEE_P)); + env.close(); + + // HookGas field for Gas-type hook + env(invoke::invoke(alice), hookgas(expectedGas), fee(expectedFee)); + env.close(); + } + + void + testGasTypeHookRejects_gFunction(FeatureBitset features) + { + testcase("Test Gas-type Hook rejects _g function"); + using namespace jtx; + + Env env{*this, features}; + auto const alice = Account{"alice"}; + env.fund(XRP(10000), alice); + env.close(); + + // Attempt to install Gas-type hook with _g function (should fail) + Json::Value jv = hso(gas_with_g_wasm, overrideFlag); + jv[jss::HookApiVersion] = 1; + + env(ripple::test::jtx::hook(alice, {{jv}}, 0), + M("test gas type hook rejects _g function"), + HSFEE, + ter(temMALFORMED)); // Should fail because Gas-type + // hooks cannot use _g + env.close(); + } + + void + testGasTypeHookWeakGas(FeatureBitset features) + { + testcase("Test Gas-type Hook weak gas"); + using namespace jtx; + + auto const alice = Account{"alice"}; + auto const gw = Account{"gw"}; + auto const USD = gw["USD"]; + + for (auto const success : {true, false}) + { + Env env{*this, features}; + env.fund(XRP(10000), alice, gw); + env.close(); + + env(fset(gw, asfTshCollect)); + env.close(); + + auto const weakGas = success ? 1000000 : 1; + + Json::Value jv = hso(gas_accept_wasm, collectFlag); + jv[jss::HookApiVersion] = 1; + jv[sfHookWeakGas.jsonName] = weakGas; + + env(ripple::test::jtx::hook(gw, {{jv}}, 0), + M("test gas type hook weak gas installation"), + HSFEE); + env.close(); + + auto const balanceBefore = env.balance(gw); + + env(trust(alice, USD(1000000))); + env.close(); + + auto const balanceAfter = env.balance(gw); + BEAST_EXPECT(balanceBefore - balanceAfter == drops(weakGas)); + + auto const meta = env.meta(); + + BEAST_REQUIRE(meta); + BEAST_REQUIRE(meta->isFieldPresent(sfHookExecutions)); + BEAST_REQUIRE(meta->getFieldArray(sfHookExecutions).size() == 1); + + auto const& execution = meta->getFieldArray(sfHookExecutions)[0]; + BEAST_REQUIRE(execution.isFieldPresent(sfHookResult)); + BEAST_REQUIRE( + execution.getFieldU8(sfHookResult) == + (success ? hook_api::ExitType::ACCEPT + : hook_api::ExitType::GAS_INSUFFICIENT)); + BEAST_REQUIRE(execution.isFieldPresent(sfHookInstructionCost)); + BEAST_REQUIRE( + execution.getFieldU32(sfHookInstructionCost) == + (success ? 14 : 1)); + } + } + + void + testGasTypeHookCbakGas(FeatureBitset features) + { + testcase("Test Gas-type Hook cbak gas"); + using namespace jtx; + auto const alice = Account{"alice"}; + + TestHook hook_wasm = wasm[ + R"[test.hook.gas]( + #include + extern int64_t accept (uint32_t read_ptr, uint32_t read_len, int64_t error_code); + extern int64_t rollback (uint32_t read_ptr, uint32_t read_len, int64_t error_code); + extern int64_t emit (uint32_t write_ptr, uint32_t write_len, uint32_t read_ptr, uint32_t read_len); + extern int64_t hook_account(uint32_t write_ptr, uint32_t write_len); + extern int64_t etxn_reserve(uint32_t); + extern int64_t etxn_fee_base (uint32_t read_ptr, uint32_t read_len); + extern int64_t etxn_details (uint32_t write_ptr, uint32_t write_len); + extern int64_t ledger_seq (void); + + #define SBUF(x) (uint32_t)x,sizeof(x) + + // clang-format off + uint8_t txn[229] = + { + /* size, upto, field name */ + /* 3, 0, tt = AccountSet */ 0x12U, 0x00U, 0x03U, + /* 5, 3, flags */ 0x22U, 0x00U, 0x00U, 0x00U, 0x00U, + /* 5, 8, sequence */ 0x24U, 0x00U, 0x00U, 0x00U, 0x00U, + /* 6, 13, firstledgersequence */ 0x20U, 0x1AU, 0x00U, 0x00U, 0x00U, 0x00U, + /* 6, 19, lastledgersequence */ 0x20U, 0x1BU, 0x00U, 0x00U, 0x00U, 0x00U, + /* 9, 25, fee */ 0x68U, 0x40U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, + /* 35, 34, signingpubkey */ 0x73U, 0x21U, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + /* 22, 69, account */ 0x81U, 0x14U, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + /* 138, 91, emit details */ + /* 0, 229, */ + }; + // clang-format on + + // TX BUILDER + #define FLAGS_OUT (txn + 4U) + #define FLS_OUT (txn + 15U) + #define LLS_OUT (txn + 21U) + #define FEE_OUT (txn + 26U) + #define ACCOUNT_OUT (txn + 71U) + #define EMIT_OUT (txn + 91U) + + #define FLIP_ENDIAN_32(value) \ + (uint32_t)(((value & 0xFFU) << 24) | ((value & 0xFF00U) << 8) | \ + ((value & 0xFF0000U) >> 8) | ((value & 0xFF000000U) >> 24)) + + #define SET_UINT32(ptr, value) *((uint32_t *)(ptr)) = FLIP_ENDIAN_32(value); + + #define SET_NATIVE_AMOUNT(ptr, amount) \ + do { \ + uint8_t *b = (ptr); \ + *b++ = 0b01000000 + ((amount >> 56) & 0b00111111); \ + *b++ = (amount >> 48) & 0xFFU; \ + *b++ = (amount >> 40) & 0xFFU; \ + *b++ = (amount >> 32) & 0xFFU; \ + *b++ = (amount >> 24) & 0xFFU; \ + *b++ = (amount >> 16) & 0xFFU; \ + *b++ = (amount >> 8) & 0xFFU; \ + *b++ = (amount >> 0) & 0xFFU; \ + } while (0) + + #define PREPARE_TXN() \ + do { \ + etxn_reserve(1); \ + uint32_t fls = (uint32_t)ledger_seq() + 1; \ + SET_UINT32(FLS_OUT, fls); \ + SET_UINT32(LLS_OUT, fls + 4); \ + hook_account(ACCOUNT_OUT, 20); \ + etxn_details(EMIT_OUT, 138U); \ + int64_t fee = etxn_fee_base(SBUF(txn)); \ + SET_NATIVE_AMOUNT(FEE_OUT, fee); \ + } while (0) + + int64_t cbak(uint32_t reserved ) + { + for(int i = 0; i < 1000; i++) + ledger_seq(); + return accept(0,0,0); + } + int64_t hook(uint32_t reserved ) + { + PREPARE_TXN(); + uint8_t emithash[32]; + int64_t emit_result = emit(SBUF(emithash), SBUF(txn)); + if (emit_result > 0) + return accept(0,0,0); + else + return rollback(0,0,0); + } + )[test.hook.gas]"]; + + HASH_WASM(hook); + + for (auto const success : {true, false}) + { + Env env{*this, features}; + env.fund(XRP(10000), alice); + env.close(); + + auto const expectedGas = success ? 1000 : 1; + + Json::Value jv = hso(hook_wasm, overrideFlag); + jv[jss::HookApiVersion] = 1; + jv[sfHookCallbackGas.jsonName] = expectedGas; + + env(ripple::test::jtx::hook(alice, {{jv}}, 0), + M("test gas type hook cbak gas installation"), + HSFEE); + env.close(); + + env(invoke::invoke(alice), + hookgas(1000), + M("test gas type hook cbak gas invocation"), + fee(XRP(1))); + + auto meta = env.meta(); + BEAST_REQUIRE(meta); + BEAST_REQUIRE(meta->isFieldPresent(sfHookExecutions)); + + auto const& hookExecutions = meta->getFieldArray(sfHookExecutions); + BEAST_REQUIRE(hookExecutions.size() == 1); + + auto const& hookExecution = hookExecutions[0]; + BEAST_REQUIRE(hookExecution.isFieldPresent(sfHookResult)); + BEAST_REQUIRE( + hookExecution.getFieldU8(sfHookResult) == + hook_api::ExitType::ACCEPT); + + BEAST_REQUIRE(hookExecution.isFieldPresent(sfHookInstructionCost)); + BEAST_REQUIRE( + hookExecution.getFieldU32(sfHookInstructionCost) == 140); + + BEAST_REQUIRE(meta->isFieldPresent(sfHookEmissions)); + BEAST_REQUIRE(meta->getFieldArray(sfHookEmissions).size() == 1); + auto const& hookEmission = meta->getFieldArray(sfHookEmissions)[0]; + auto const& emittedTxnID = + hookEmission.getFieldH256(sfEmittedTxnID); + + // proceed ledger + env.close(); + + auto const& txPair = env.closed()->txRead(emittedTxnID); + auto const& tx = txPair.first; + meta = txPair.second; + BEAST_REQUIRE( + tx->getFieldAmount(sfFee).xrp() == + env.current()->fees().base + drops(expectedGas)); + + BEAST_REQUIRE(meta->isFieldPresent(sfHookExecutions)); + BEAST_REQUIRE(meta->getFieldArray(sfHookExecutions).size() == 1); + auto const& execution = meta->getFieldArray(sfHookExecutions)[0]; + BEAST_REQUIRE(execution.isFieldPresent(sfHookResult)); + BEAST_REQUIRE( + execution.getFieldU8(sfHookResult) == success + ? hook_api::ExitType::ACCEPT + : hook_api::ExitType::GAS_INSUFFICIENT); + } + } + + void + testGasExecutionSufficient(FeatureBitset features) + { + testcase("Test Gas execution with sufficient gas"); + using namespace jtx; + + Env env{*this, features}; + auto const alice = Account{"alice"}; + auto const bob = Account{"bob"}; + env.fund(XRP(100000), alice, bob); + env.close(); + + // Install Gas-type hook with sufficient gas + Json::Value jvh = hso(gas_long_wasm, overrideFlag); + jvh[jss::HookApiVersion] = 1; + + env(ripple::test::jtx::hook(alice, {{jvh}}, 0), HSFEE, ter(tesSUCCESS)); + env.close(); + + // Trigger the hook with a payment + env(pay(bob, alice, XRP(1)), + // insufficient gas for long execution + hookgas(100), + fee(XRP(10000)), + ter(tecHOOK_INSUFFICIENT_GAS)); + env.close(); + + // check exit type + auto meta = env.meta(); + BEAST_REQUIRE(meta); + BEAST_REQUIRE(meta->isFieldPresent(sfHookExecutions)); + + auto hookExecutions = meta->getFieldArray(sfHookExecutions); + BEAST_REQUIRE(hookExecutions.size() == 1); + + // validate HookInstructionCost + BEAST_REQUIRE(hookExecutions[0].isFieldPresent(sfHookInstructionCost)); + BEAST_REQUIRE( + hookExecutions[0].getFieldU32(sfHookInstructionCost) == 100); + // check exit type + BEAST_REQUIRE(hookExecutions[0].isFieldPresent(sfHookResult)); + BEAST_REQUIRE( + hookExecutions[0].getFieldU8(sfHookResult) == + hook_api::ExitType::GAS_INSUFFICIENT); + + // Trigger the hook with a payment + env(pay(bob, alice, XRP(1)), + // Sufficient gas for long execution + hookgas(10000000), + fee(XRP(10000)), + ter(tesSUCCESS)); + env.close(); + + meta = env.meta(); + BEAST_REQUIRE(meta); + BEAST_REQUIRE(meta->isFieldPresent(sfHookExecutions)); + + hookExecutions = meta->getFieldArray(sfHookExecutions); + BEAST_REQUIRE(hookExecutions.size() == 1); + + // validate HookInstructionCost + BEAST_REQUIRE(hookExecutions[0].isFieldPresent(sfHookInstructionCost)); + BEAST_REQUIRE( + hookExecutions[0].getFieldU32(sfHookInstructionCost) == 2014); + // check exit type + BEAST_REQUIRE(hookExecutions[0].isFieldPresent(sfHookResult)); + BEAST_REQUIRE( + hookExecutions[0].getFieldU8(sfHookResult) == + hook_api::ExitType::ACCEPT); + } + + void + testGasTypeHookMemoryValidation(FeatureBitset features) + { + testcase("Test Gas-type Hook memory.grow validation"); + using namespace jtx; + + Env env{*this, features}; + auto const alice = Account{"alice"}; + auto const bob = Account{"bob"}; + env.fund(XRP(100000), alice, bob); + env.close(); + + // Test 1: Install hook that grows memory to 8 pages (should succeed) + { + TestHook gas_memory_grow_to_8_wasm = wasm[ + R"[test.hook.gas]( + (module + (type (;0;) (func (param i32 i32 i64) (result i64))) + (type (;1;) (func (param i32) (result i64))) + (import "env" "accept" (func (;0;) (type 0))) + (import "env" "rollback" (func (;1;) (type 0))) + (func (;2;) (type 1) (param i32) (result i64) + ;; Grow memory from 1 page to 8 pages (7 page increase) + i32.const 7 + memory.grow + i32.const -1 + i32.eq + if (result i64) + ;; Should not happen + i32.const 0 + i32.const 0 + i64.const 1 + call 1 ;; rollback + else + ;; Success + i32.const 0 + i32.const 0 + i64.const 0 + call 0 ;; accept + end) + (memory (;0;) 1) + (export "memory" (memory 0)) + (export "hook" (func 2))) + )[test.hook.gas]"]; + + HASH_WASM(gas_memory_grow_to_8); + + Json::Value jvh = hso(gas_memory_grow_to_8_wasm, overrideFlag); + jvh[jss::HookApiVersion] = 1; + + env(ripple::test::jtx::hook(alice, {{jvh}}, 0), + M("install hook with memory.grow to 8 pages"), + HSFEE); + env.close(); + + // Trigger the hook with sufficient gas + env(pay(bob, alice, XRP(1)), + hookgas(1000000), + fee(XRP(10000)), + ter(tesSUCCESS)); + env.close(); + + // Verify hook executed successfully + auto meta = env.meta(); + BEAST_REQUIRE(meta); + BEAST_REQUIRE(meta->isFieldPresent(sfHookExecutions)); + + auto hookExecutions = meta->getFieldArray(sfHookExecutions); + BEAST_REQUIRE(hookExecutions.size() == 1); + + // Check that hook accepted (memory.grow succeeded) + BEAST_REQUIRE(hookExecutions[0].isFieldPresent(sfHookResult)); + BEAST_REQUIRE( + hookExecutions[0].getFieldU8(sfHookResult) == + hook_api::ExitType::ACCEPT); + } + + // Test 2: Install hook that tries to grow memory to 9 pages (should + // rollback) + { + TestHook gas_memory_grow_to_9_wasm = wasm[ + R"[test.hook.gas]( + (module + (type (;0;) (func (param i32 i32 i64) (result i64))) + (type (;1;) (func (param i32) (result i64))) + (import "env" "accept" (func (;0;) (type 0))) + (import "env" "rollback" (func (;1;) (type 0))) + (func (;2;) (type 1) (param i32) (result i64) + ;; Try to grow memory from 1 page to 9 pages (8 page increase) + ;; This should fail because maxMemoryPage=8 + i32.const 8 + memory.grow + i32.const -1 + i32.eq + if (result i64) + ;; Expected failure + i32.const 0 + i32.const 0 + i64.const 0 + call 1 ;; rollback + else + ;; Should not happen + i32.const 0 + i32.const 0 + i64.const 1 + call 0 ;; accept + end) + (memory (;0;) 1) + (export "memory" (memory 0)) + (export "hook" (func 2))) + )[test.hook.gas]"]; + + HASH_WASM(gas_memory_grow_to_9); + + Json::Value jvh = hso(gas_memory_grow_to_9_wasm, overrideFlag); + jvh[jss::HookApiVersion] = 1; + + env(ripple::test::jtx::hook(alice, {{jvh}}, 0), + M("install hook with memory.grow to 9 pages"), + HSFEE, + ter(tesSUCCESS)); + env.close(); + + // Trigger the hook - should rollback due to memory.grow failure + env(pay(bob, alice, XRP(1)), + hookgas(1000000), + fee(XRP(10000)), + ter(tecHOOK_REJECTED)); + env.close(); + + // Verify hook rolled back (memory.grow to 9 pages failed) + auto meta = env.meta(); + BEAST_REQUIRE(meta); + BEAST_REQUIRE(meta->isFieldPresent(sfHookExecutions)); + + auto hookExecutions = meta->getFieldArray(sfHookExecutions); + BEAST_REQUIRE(hookExecutions.size() == 1); + + // Check that hook rolled back (memory limit exceeded) + BEAST_REQUIRE(hookExecutions[0].isFieldPresent(sfHookResult)); + BEAST_REQUIRE( + hookExecutions[0].getFieldU8(sfHookResult) == + hook_api::ExitType::ROLLBACK); + } + } + + void + testMultipleGasHooksSharedPool(FeatureBitset features) + { + testcase("Test multiple Gas-type hooks share gas pool"); + using namespace jtx; + + Env env{*this, features}; + auto const alice = Account{"alice"}; + auto const bob = Account{"bob"}; + env.fund(XRP(100000), alice, bob); + env.close(); + + // Install multiple Gas-type hooks + // First hook + Json::Value hook1 = hso(gas_accept_wasm, overrideFlag); + hook1[jss::HookApiVersion] = 1; + + // Second hook + Json::Value hook2 = hso(gas_long_wasm, overrideFlag); + hook2[jss::HookApiVersion] = 1; + + env(ripple::test::jtx::hook(alice, {{hook1, hook2}}, 0), + M("test multiple gas hooks shared pool"), + HSFEE, + ter(tesSUCCESS)); + env.close(); + + // Trigger hooks with a payment + Json::Value jv = pay(bob, alice, XRP(1)); + env(jv, hookgas(10000000), fee(XRP(10000)), ter(tesSUCCESS)); + env.close(); + + auto meta = env.meta(); + BEAST_REQUIRE(meta); + BEAST_REQUIRE(meta->isFieldPresent(sfHookExecutions)); + + auto const hookExecutions = meta->getFieldArray(sfHookExecutions); + BEAST_REQUIRE(hookExecutions.size() == 2); + + // validate HookInstructionCost + BEAST_REQUIRE(hookExecutions[0].isFieldPresent(sfHookInstructionCost)); + BEAST_REQUIRE(hookExecutions[1].isFieldPresent(sfHookInstructionCost)); + BEAST_REQUIRE( + hookExecutions[0].getFieldU32(sfHookInstructionCost) == 14); + BEAST_REQUIRE( + hookExecutions[1].getFieldU32(sfHookInstructionCost) == 2014); + } + + void + testWithFeatures(FeatureBitset features) + { + testHooksOwnerDir(features); + testHooksDisabled(features); + testTxStructure(features); + testInvalidTxFlags(features); + testInferHookSetOperation(); + testParams(features); + testGrants(features); + testHookCanEmit(features); + + testDelete(features); + testInstall(features); + testCreate(features); + testWithTickets(features); + + testUpdate(features); + + testNSDelete(features); + testNSDeletePartial(features); + testPageCap(features); + + testFillCopy(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_xpop_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); // + + // Gas-type Hook tests + testGasTypeHookDisabled(features); + testGasTypeHookInstallation(features); + testGasTypeHookWeakGas(features); + testGasTypeHookCbakGas(features); + testGasTypeHookRejects_gFunction(features); + testGasExecutionSufficient(features); + testMultipleGasHooksSharedPool(features); + testGasTypeHookHostFunctionValidation(features); + testGasTypeHookExportErrors(features); + testGasTypeHookImportErrors(features); + testGasTypeHookMemoryValidation(features); + } + +public: + void + run(std::uint32_t instance, bool last = false) + { + using namespace test::jtx; + static FeatureBitset const all{supported_amendments()}; + + static std::array const feats{ + all, + all - fixXahauV2, + all - fixXahauV1 - fixXahauV2, + all - fixXahauV1 - fixXahauV2 - fixNSDelete, + all - fixXahauV1 - fixXahauV2 - fixNSDelete - fixPageCap, + all - fixXahauV1 - fixXahauV2 - fixNSDelete - fixPageCap - + featureHookCanEmit, + all - fixXahauV1 - fixXahauV2 - fixNSDelete - fixPageCap - + featureExtendedHookState, + }; + + if (BEAST_EXPECT(instance < feats.size())) + { + testWithFeatures(feats[instance]); + } + BEAST_EXPECT(!last || instance == feats.size() - 1); + } + + void + run() override + { + run(0); + } + +private: + TestHook accept_wasm = // WASM: 0 + wasm[ + R"[test.hook]( + #include + extern int32_t _g (uint32_t id, uint32_t maxiter); + extern int64_t accept (uint32_t read_ptr, uint32_t read_len, int64_t error_code); + int64_t hook(uint32_t reserved ) + { + _g(1,1); + return accept(0,0,0); + } + )[test.hook]"]; + + HASH_WASM(accept); + + TestHook rollback_wasm = // WASM: 1 + wasm[ + R"[test.hook]( + #include + extern int32_t _g (uint32_t id, uint32_t maxiter); + extern int64_t rollback (uint32_t read_ptr, uint32_t read_len, int64_t error_code); + #define SBUF(x) (uint32_t)(x),sizeof(x) + int64_t hook(uint32_t reserved ) + { + _g(1,1); + return rollback(SBUF("Hook Rejected"),0); + } + )[test.hook]"]; + + HASH_WASM(rollback); + + TestHook noguard_wasm = // WASM: 2 + wasm[ + R"[test.hook]( + (module + (type (;0;) (func (param i32 i32 i64) (result i64))) + (type (;1;) (func (param i32) (result i64))) + (import "env" "accept" (func (;0;) (type 0))) + (func (;1;) (type 1) (param i32) (result i64) + i32.const 0 + i32.const 0 + i64.const 0 + call 0) + (memory (;0;) 2) + (export "memory" (memory 0)) + (export "hook" (func 1))) + )[test.hook]"]; + + TestHook illegalfunc_wasm = // WASM: 3 + wasm[ + R"[test.hook]( + (module + (type (;0;) (func (param i32 i32) (result i32))) + (type (;1;) (func (param i32 i32 i64) (result i64))) + (type (;2;) (func)) + (type (;3;) (func (param i32) (result i64))) + (import "env" "_g" (func (;0;) (type 0))) + (import "env" "accept" (func (;1;) (type 1))) + (func (;2;) (type 3) (param i32) (result i64) + i32.const 1 + i32.const 1 + call 0 + drop + i32.const 0 + i32.const 0 + i64.const 0 + call 1) + (func (;3;) (type 2) + i32.const 1 + i32.const 1 + call 0 + drop) + (memory (;0;) 2) + (global (;0;) (mut i32) (i32.const 66560)) + (global (;1;) i32 (i32.const 1024)) + (global (;2;) i32 (i32.const 1024)) + (global (;3;) i32 (i32.const 66560)) + (global (;4;) i32 (i32.const 1024)) + (export "memory" (memory 0)) + (export "hook" (func 2)) + (export "bad_func" (func 3))) + )[test.hook]"]; + + TestHook long_wasm = // WASM: 4 + wasm[ + R"[test.hook]( + #include + extern int32_t _g (uint32_t id, uint32_t maxiter); + extern int64_t accept (uint32_t read_ptr, uint32_t read_len, int64_t error_code); + #define SBUF(x) (uint32_t)(x), sizeof(x) + #define M_REPEAT_10(X) X X X X X X X X X X + #define M_REPEAT_100(X) M_REPEAT_10(M_REPEAT_10(X)) + #define M_REPEAT_1000(X) M_REPEAT_100(M_REPEAT_10(X)) + int64_t hook(uint32_t reserved ) + { + _g(1,1); + char ret[] = M_REPEAT_1000("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz01234567890123"); + return accept(SBUF(ret), 0); + } + )[test.hook]"]; + + TestHook makestate_wasm = // WASM: 5 + wasm[ R"[test.hook]( #include extern int32_t _g (uint32_t id, uint32_t maxiter); @@ -13662,6 +15082,70 @@ class SetHook0_test : public beast::unit_test::suite )[test.hook]"]; HASH_WASM(accept2); + + TestHook gas_accept_wasm = // WASM: 7 + wasm[ + R"[test.hook.gas]( + #include + extern int64_t accept (uint32_t read_ptr, uint32_t read_len, int64_t error_code); + int64_t hook(uint32_t reserved ) + { + return accept(0,0,0); + } + )[test.hook.gas]"]; + + HASH_WASM(gas_accept); + + TestHook gas_accept_with_cbak_wasm = // WASM: 8 + wasm[ + R"[test.hook.gas]( + #include + extern int64_t accept (uint32_t read_ptr, uint32_t read_len, int64_t error_code); + int64_t cbak(uint32_t reserved ) + { + return accept(0,0,0); + } + int64_t hook(uint32_t reserved ) + { + return accept(0,0,0); + } + )[test.hook.gas]"]; + + HASH_WASM(gas_accept_with_cbak); + + TestHook gas_with_g_wasm = // WASM: 9 + wasm[ + R"[test.hook.gas]( + #include + extern int32_t _g (uint32_t id, uint32_t maxiter); + extern int64_t accept (uint32_t read_ptr, uint32_t read_len, int64_t error_code); + int64_t hook(uint32_t reserved ) + { + _g(1,1); + return accept(0,0,0); + } + )[test.hook.gas]"]; + + HASH_WASM(gas_with_g); + + TestHook gas_long_wasm = // WASM: 10 + wasm[ + R"[test.hook.gas]( + #include + extern int64_t accept (uint32_t read_ptr, uint32_t read_len, int64_t error_code); + extern int64_t float_one(); + #define SBUF(x) (uint32_t)(x), sizeof(x) + #define M_REPEAT_10(X) X X X X X X X X X X + #define M_REPEAT_100(X) M_REPEAT_10(M_REPEAT_10(X)) + #define M_REPEAT_1000(X) M_REPEAT_100(M_REPEAT_10(X)) + int64_t hook(uint32_t reserved ) + { + M_REPEAT_1000(float_one();); + return accept(0, 0, 0); + } + )[test.hook.gas]"]; + + HASH_WASM(gas_long); }; #define SETHOOK_TEST(i, last) \ diff --git a/src/test/app/SetHook_wasm.h b/src/test/app/SetHook_wasm.h index 73294c9fb0..68a7ab579c 100644 --- a/src/test/app/SetHook_wasm.h +++ b/src/test/app/SetHook_wasm.h @@ -16805,7 +16805,7 @@ std::map> wasm = { 0x64U, 0xE1U, 0xF1U, }}, - /* ==== WASM: 79 ==== */ + /* ==== WASM: 80 ==== */ {R"[test.hook]( #include extern int32_t _g (uint32_t id, uint32_t maxiter); @@ -16978,7 +16978,7 @@ std::map> wasm = { 0x54U, 0x5FU, 0x45U, 0x58U, 0x49U, 0x53U, 0x54U, 0x00U, }}, - /* ==== WASM: 80 ==== */ + /* ==== WASM: 81 ==== */ {R"[test.hook]( #include extern int32_t _g (uint32_t id, uint32_t maxiter); @@ -17126,7 +17126,7 @@ std::map> wasm = { 0x30U, 0x00U, 0x22U, 0x00U, 0x00U, 0x00U, 0x00U, }}, - /* ==== WASM: 81 ==== */ + /* ==== WASM: 82 ==== */ {R"[test.hook]( #include extern int32_t _g (uint32_t id, uint32_t maxiter); @@ -17223,7 +17223,7 @@ std::map> wasm = { 0x3DU, 0x20U, 0x30U, 0x00U, }}, - /* ==== WASM: 82 ==== */ + /* ==== WASM: 83 ==== */ {R"[test.hook]( #include extern int32_t _g (uint32_t id, uint32_t maxiter); @@ -17282,7 +17282,7 @@ std::map> wasm = { 0x4FU, 0x46U, 0x5FU, 0x42U, 0x4FU, 0x55U, 0x4EU, 0x44U, 0x53U, 0x00U, }}, - /* ==== WASM: 83 ==== */ + /* ==== WASM: 84 ==== */ {R"[test.hook]( #include extern int32_t _g (uint32_t id, uint32_t maxiter); @@ -17341,7 +17341,7 @@ std::map> wasm = { 0x4EU, 0x44U, 0x53U, 0x00U, }}, - /* ==== WASM: 84 ==== */ + /* ==== WASM: 85 ==== */ {R"[test.hook]( #include extern int32_t _g (uint32_t id, uint32_t maxiter); @@ -19170,7 +19170,7 @@ std::map> wasm = { 0x53U, 0x4DU, 0x41U, 0x4CU, 0x4CU, 0x00U, }}, - /* ==== WASM: 85 ==== */ + /* ==== WASM: 86 ==== */ {R"[test.hook]( #include extern int32_t _g (uint32_t id, uint32_t maxiter); @@ -20512,7 +20512,7 @@ std::map> wasm = { 0x20U, 0x30U, 0x2CU, 0x20U, 0x30U, 0x29U, 0x29U, 0x00U, }}, - /* ==== WASM: 86 ==== */ + /* ==== WASM: 87 ==== */ {R"[test.hook]( #include extern int32_t _g (uint32_t id, uint32_t maxiter); @@ -23445,7 +23445,7 @@ std::map> wasm = { 0x4FU, 0x4FU, 0x5FU, 0x53U, 0x4DU, 0x41U, 0x4CU, 0x4CU, 0x00U, }}, - /* ==== WASM: 87 ==== */ + /* ==== WASM: 88 ==== */ {R"[test.hook]( #include extern int32_t _g (uint32_t id, uint32_t maxiter); @@ -25410,7 +25410,7 @@ std::map> wasm = { 0x54U, 0x4FU, 0x4FU, 0x5FU, 0x53U, 0x4DU, 0x41U, 0x4CU, 0x4CU, 0x00U, }}, - /* ==== WASM: 88 ==== */ + /* ==== WASM: 89 ==== */ {R"[test.hook]( #include extern int32_t _g (uint32_t id, uint32_t maxiter); @@ -25695,7 +25695,7 @@ std::map> wasm = { 0x29U, 0x20U, 0x3DU, 0x3DU, 0x20U, 0x30U, 0x00U, }}, - /* ==== WASM: 89 ==== */ + /* ==== WASM: 90 ==== */ {R"[test.hook]( #include extern int32_t _g(uint32_t, uint32_t); @@ -26282,7 +26282,7 @@ std::map> wasm = { 0x4EU, 0x5FU, 0x46U, 0x41U, 0x49U, 0x4CU, 0x55U, 0x52U, 0x45U, 0x00U, }}, - /* ==== WASM: 90 ==== */ + /* ==== WASM: 91 ==== */ {R"[test.hook]( #include extern int32_t _g (uint32_t id, uint32_t maxiter); @@ -26311,7 +26311,7 @@ std::map> wasm = { 0x0BU, }}, - /* ==== WASM: 91 ==== */ + /* ==== WASM: 92 ==== */ {R"[test.hook]( #include extern int32_t _g (uint32_t id, uint32_t maxiter); @@ -26343,7 +26343,7 @@ std::map> wasm = { 0x20U, 0x52U, 0x65U, 0x6AU, 0x65U, 0x63U, 0x74U, 0x65U, 0x64U, 0x00U, }}, - /* ==== WASM: 92 ==== */ + /* ==== WASM: 93 ==== */ {R"[test.hook]( (module (type (;0;) (func (param i32 i32 i64) (result i64))) @@ -26370,7 +26370,7 @@ std::map> wasm = { 0x41U, 0x00U, 0x41U, 0x00U, 0x42U, 0x00U, 0x10U, 0x00U, 0x0BU, }}, - /* ==== WASM: 93 ==== */ + /* ==== WASM: 94 ==== */ {R"[test.hook]( (module (type (;0;) (func (param i32 i32) (result i32))) @@ -26423,7 +26423,7 @@ std::map> wasm = { 0x00U, 0x1AU, 0x0BU, }}, - /* ==== WASM: 94 ==== */ + /* ==== WASM: 95 ==== */ {R"[test.hook]( #include extern int32_t _g (uint32_t id, uint32_t maxiter); @@ -33066,7 +33066,7 @@ std::map> wasm = { 0x39U, 0x30U, 0x31U, 0x32U, 0x33U, 0x00U, }}, - /* ==== WASM: 95 ==== */ + /* ==== WASM: 96 ==== */ {R"[test.hook]( #include extern int32_t _g (uint32_t id, uint32_t maxiter); @@ -33112,7 +33112,7 @@ std::map> wasm = { 0x0BU, 0x06U, 0x76U, 0x61U, 0x6CU, 0x75U, 0x65U, 0x00U, }}, - /* ==== WASM: 96 ==== */ + /* ==== WASM: 97 ==== */ {R"[test.hook]( #include extern int32_t _g (uint32_t id, uint32_t maxiter); @@ -33141,6 +33141,1924 @@ std::map> wasm = { 0x0BU, }}, + /* ==== WASM: 98 ==== */ + {R"[test.hook.gas]( + (module + (type (;0;) (func (param i32 i32 i64) (result i64))) + (type (;1;) (func (param i32) (result i64))) + (import "env" "accept" (func (;0;) (type 0))) + (import "env" "trace_num" (func (;1;) (type 0))) + (func (;2;) (type 1) (param i32) (result i64) + i32.const 0 + i32.const 15 + i64.const 1 + call 1 + drop + i32.const 0 + i32.const 0 + i64.const 0 + call 0) + (memory (;0;) 2) + (export "memory" (memory 0)) + (export "hook" (func 2))) + )[test.hook.gas]", + { + 0x00U, 0x61U, 0x73U, 0x6DU, 0x01U, 0x00U, 0x00U, 0x00U, 0x01U, 0x0DU, + 0x02U, 0x60U, 0x03U, 0x7FU, 0x7FU, 0x7EU, 0x01U, 0x7EU, 0x60U, 0x01U, + 0x7FU, 0x01U, 0x7EU, 0x02U, 0x1EU, 0x02U, 0x03U, 0x65U, 0x6EU, 0x76U, + 0x06U, 0x61U, 0x63U, 0x63U, 0x65U, 0x70U, 0x74U, 0x00U, 0x00U, 0x03U, + 0x65U, 0x6EU, 0x76U, 0x09U, 0x74U, 0x72U, 0x61U, 0x63U, 0x65U, 0x5FU, + 0x6EU, 0x75U, 0x6DU, 0x00U, 0x00U, 0x03U, 0x02U, 0x01U, 0x01U, 0x05U, + 0x03U, 0x01U, 0x00U, 0x02U, 0x07U, 0x11U, 0x02U, 0x06U, 0x6DU, 0x65U, + 0x6DU, 0x6FU, 0x72U, 0x79U, 0x02U, 0x00U, 0x04U, 0x68U, 0x6FU, 0x6FU, + 0x6BU, 0x00U, 0x02U, 0x0AU, 0x15U, 0x01U, 0x13U, 0x00U, 0x41U, 0x00U, + 0x41U, 0x0FU, 0x42U, 0x01U, 0x10U, 0x01U, 0x1AU, 0x41U, 0x00U, 0x41U, + 0x00U, 0x42U, 0x00U, 0x10U, 0x00U, 0x0BU, + }}, + + /* ==== WASM: 99 ==== */ + {R"[test.hook.gas]( + (module + (type (;0;) (func (param i32 i32) (result i32))) + (type (;1;) (func (param i32 i32 i64) (result i64))) + (type (;2;) (func (param i32) (result i64))) + (import "env" "_g" (func (;0;) (type 0))) + (import "env" "accept" (func (;1;) (type 1))) + (func (;2;) (type 2) (param i32) (result i64) + i32.const 1 + i32.const 1 + call 0 + drop + i32.const 0 + i32.const 0 + i64.const 0 + call 1) + (memory (;0;) 2) + (export "memory" (memory 0)) + (export "hook" (func 2))) + )[test.hook.gas]", + { + 0x00U, 0x61U, 0x73U, 0x6DU, 0x01U, 0x00U, 0x00U, 0x00U, 0x01U, 0x13U, + 0x03U, 0x60U, 0x02U, 0x7FU, 0x7FU, 0x01U, 0x7FU, 0x60U, 0x03U, 0x7FU, + 0x7FU, 0x7EU, 0x01U, 0x7EU, 0x60U, 0x01U, 0x7FU, 0x01U, 0x7EU, 0x02U, + 0x17U, 0x02U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x02U, 0x5FU, 0x67U, 0x00U, + 0x00U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x06U, 0x61U, 0x63U, 0x63U, 0x65U, + 0x70U, 0x74U, 0x00U, 0x01U, 0x03U, 0x02U, 0x01U, 0x02U, 0x05U, 0x03U, + 0x01U, 0x00U, 0x02U, 0x07U, 0x11U, 0x02U, 0x06U, 0x6DU, 0x65U, 0x6DU, + 0x6FU, 0x72U, 0x79U, 0x02U, 0x00U, 0x04U, 0x68U, 0x6FU, 0x6FU, 0x6BU, + 0x00U, 0x02U, 0x0AU, 0x13U, 0x01U, 0x11U, 0x00U, 0x41U, 0x01U, 0x41U, + 0x01U, 0x10U, 0x00U, 0x1AU, 0x41U, 0x00U, 0x41U, 0x00U, 0x42U, 0x00U, + 0x10U, 0x01U, 0x0BU, + }}, + + /* ==== WASM: 100 ==== */ + {R"[test.hook.gas]( + (module + (type (;0;) (func (param i32 i32 i64) (result i64))) + (type (;1;) (func (result i64))) + (type (;2;) (func (param i32) (result i64))) + (import "env" "accept" (func (;0;) (type 0))) + (import "env" "trace_num" (func (;1;) (type 0))) + (import "env" "ledger_seq" (func (;2;) (type 1))) + (import "env" "fee_base" (func (;3;) (type 1))) + (func (;4;) (type 2) (param i32) (result i64) + (local i64 i64) + call 2 + local.set 1 + call 3 + local.set 2 + i32.const 0 + i32.const 10 + local.get 1 + call 1 + drop + i32.const 0 + i32.const 8 + local.get 2 + call 1 + drop + i32.const 0 + i32.const 0 + i64.const 0 + call 0) + (memory (;0;) 2) + (export "memory" (memory 0)) + (export "hook" (func 4))) + )[test.hook.gas]", + { + 0x00U, 0x61U, 0x73U, 0x6DU, 0x01U, 0x00U, 0x00U, 0x00U, 0x01U, 0x11U, + 0x03U, 0x60U, 0x03U, 0x7FU, 0x7FU, 0x7EU, 0x01U, 0x7EU, 0x60U, 0x00U, + 0x01U, 0x7EU, 0x60U, 0x01U, 0x7FU, 0x01U, 0x7EU, 0x02U, 0x3EU, 0x04U, + 0x03U, 0x65U, 0x6EU, 0x76U, 0x06U, 0x61U, 0x63U, 0x63U, 0x65U, 0x70U, + 0x74U, 0x00U, 0x00U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x09U, 0x74U, 0x72U, + 0x61U, 0x63U, 0x65U, 0x5FU, 0x6EU, 0x75U, 0x6DU, 0x00U, 0x00U, 0x03U, + 0x65U, 0x6EU, 0x76U, 0x0AU, 0x6CU, 0x65U, 0x64U, 0x67U, 0x65U, 0x72U, + 0x5FU, 0x73U, 0x65U, 0x71U, 0x00U, 0x01U, 0x03U, 0x65U, 0x6EU, 0x76U, + 0x08U, 0x66U, 0x65U, 0x65U, 0x5FU, 0x62U, 0x61U, 0x73U, 0x65U, 0x00U, + 0x01U, 0x03U, 0x02U, 0x01U, 0x02U, 0x05U, 0x03U, 0x01U, 0x00U, 0x02U, + 0x07U, 0x11U, 0x02U, 0x06U, 0x6DU, 0x65U, 0x6DU, 0x6FU, 0x72U, 0x79U, + 0x02U, 0x00U, 0x04U, 0x68U, 0x6FU, 0x6FU, 0x6BU, 0x00U, 0x04U, 0x0AU, + 0x28U, 0x01U, 0x26U, 0x01U, 0x02U, 0x7EU, 0x10U, 0x02U, 0x21U, 0x01U, + 0x10U, 0x03U, 0x21U, 0x02U, 0x41U, 0x00U, 0x41U, 0x0AU, 0x20U, 0x01U, + 0x10U, 0x01U, 0x1AU, 0x41U, 0x00U, 0x41U, 0x08U, 0x20U, 0x02U, 0x10U, + 0x01U, 0x1AU, 0x41U, 0x00U, 0x41U, 0x00U, 0x42U, 0x00U, 0x10U, 0x00U, + 0x0BU, + }}, + + /* ==== WASM: 101 ==== */ + {R"[test.hook.gas]( + (module + (type (;0;) (func (param i32 i32 i64) (result i64))) + (type (;1;) (func (param i32) (result i64))) + (import "env" "accept" (func (;0;) (type 0))) + (func (;1;) (type 1) (param i32) (result i64) + i32.const 0 + i32.const 0 + i64.const 0 + call 0) + (memory (;0;) 2) + (export "memory" (memory 0)) + (export "hook" (func 1)) + (export "cbak" (func 1))) + )[test.hook.gas]", + { + 0x00U, 0x61U, 0x73U, 0x6DU, 0x01U, 0x00U, 0x00U, 0x00U, 0x01U, 0x0DU, + 0x02U, 0x60U, 0x03U, 0x7FU, 0x7FU, 0x7EU, 0x01U, 0x7EU, 0x60U, 0x01U, + 0x7FU, 0x01U, 0x7EU, 0x02U, 0x0EU, 0x01U, 0x03U, 0x65U, 0x6EU, 0x76U, + 0x06U, 0x61U, 0x63U, 0x63U, 0x65U, 0x70U, 0x74U, 0x00U, 0x00U, 0x03U, + 0x02U, 0x01U, 0x01U, 0x05U, 0x03U, 0x01U, 0x00U, 0x02U, 0x07U, 0x18U, + 0x03U, 0x06U, 0x6DU, 0x65U, 0x6DU, 0x6FU, 0x72U, 0x79U, 0x02U, 0x00U, + 0x04U, 0x68U, 0x6FU, 0x6FU, 0x6BU, 0x00U, 0x01U, 0x04U, 0x63U, 0x62U, + 0x61U, 0x6BU, 0x00U, 0x01U, 0x0AU, 0x0CU, 0x01U, 0x0AU, 0x00U, 0x41U, + 0x00U, 0x41U, 0x00U, 0x42U, 0x00U, 0x10U, 0x00U, 0x0BU, + }}, + + /* ==== WASM: 102 ==== */ + {R"[test.hook.gas]( + (module + (type (;0;) (func (param i32 i32 i64) (result i64))) + (type (;1;) (func (param i32) (result i64))) + (import "env" "accept" (func (;0;) (type 0))) + (func (;1;) (type 1) (param i32) (result i64) + i32.const 0 + i32.const 0 + i64.const 0 + call 0) + (memory (;0;) 2)) + )[test.hook.gas]", + { + 0x00U, 0x61U, 0x73U, 0x6DU, 0x01U, 0x00U, 0x00U, 0x00U, 0x01U, + 0x0DU, 0x02U, 0x60U, 0x03U, 0x7FU, 0x7FU, 0x7EU, 0x01U, 0x7EU, + 0x60U, 0x01U, 0x7FU, 0x01U, 0x7EU, 0x02U, 0x0EU, 0x01U, 0x03U, + 0x65U, 0x6EU, 0x76U, 0x06U, 0x61U, 0x63U, 0x63U, 0x65U, 0x70U, + 0x74U, 0x00U, 0x00U, 0x03U, 0x02U, 0x01U, 0x01U, 0x05U, 0x03U, + 0x01U, 0x00U, 0x02U, 0x0AU, 0x0CU, 0x01U, 0x0AU, 0x00U, 0x41U, + 0x00U, 0x41U, 0x00U, 0x42U, 0x00U, 0x10U, 0x00U, 0x0BU, + }}, + + /* ==== WASM: 103 ==== */ + {R"[test.hook.gas]( + (module + (type (;0;) (func (param i32 i32 i64) (result i64))) + (type (;1;) (func (param i32) (result i64))) + (import "env" "accept" (func (;0;) (type 0))) + (func (;1;) (type 1) (param i32) (result i64) + i32.const 0 + i32.const 0 + i64.const 0 + call 0) + (memory (;0;) 2) + (export "memory" (memory 0)) + (export "hook" (func 1)) + (export "unauthorized_fn" (func 1))) + )[test.hook.gas]", + { + 0x00U, 0x61U, 0x73U, 0x6DU, 0x01U, 0x00U, 0x00U, 0x00U, 0x01U, 0x0DU, + 0x02U, 0x60U, 0x03U, 0x7FU, 0x7FU, 0x7EU, 0x01U, 0x7EU, 0x60U, 0x01U, + 0x7FU, 0x01U, 0x7EU, 0x02U, 0x0EU, 0x01U, 0x03U, 0x65U, 0x6EU, 0x76U, + 0x06U, 0x61U, 0x63U, 0x63U, 0x65U, 0x70U, 0x74U, 0x00U, 0x00U, 0x03U, + 0x02U, 0x01U, 0x01U, 0x05U, 0x03U, 0x01U, 0x00U, 0x02U, 0x07U, 0x23U, + 0x03U, 0x06U, 0x6DU, 0x65U, 0x6DU, 0x6FU, 0x72U, 0x79U, 0x02U, 0x00U, + 0x04U, 0x68U, 0x6FU, 0x6FU, 0x6BU, 0x00U, 0x01U, 0x0FU, 0x75U, 0x6EU, + 0x61U, 0x75U, 0x74U, 0x68U, 0x6FU, 0x72U, 0x69U, 0x7AU, 0x65U, 0x64U, + 0x5FU, 0x66U, 0x6EU, 0x00U, 0x01U, 0x0AU, 0x0CU, 0x01U, 0x0AU, 0x00U, + 0x41U, 0x00U, 0x41U, 0x00U, 0x42U, 0x00U, 0x10U, 0x00U, 0x0BU, + }}, + + /* ==== WASM: 104 ==== */ + {R"[test.hook.gas]( + (module + (type (;0;) (func (param i32 i32 i64) (result i64))) + (type (;1;) (func (param i32) (result i64))) + (import "env" "accept" (func (;0;) (type 0))) + (func (;1;) (type 1) (param i32) (result i64) + i32.const 0 + i32.const 0 + i64.const 0 + call 0) + (memory (;0;) 2) + (export "memory" (memory 0)) + (export "cbak" (func 1))) + )[test.hook.gas]", + { + 0x00U, 0x61U, 0x73U, 0x6DU, 0x01U, 0x00U, 0x00U, 0x00U, 0x01U, + 0x0DU, 0x02U, 0x60U, 0x03U, 0x7FU, 0x7FU, 0x7EU, 0x01U, 0x7EU, + 0x60U, 0x01U, 0x7FU, 0x01U, 0x7EU, 0x02U, 0x0EU, 0x01U, 0x03U, + 0x65U, 0x6EU, 0x76U, 0x06U, 0x61U, 0x63U, 0x63U, 0x65U, 0x70U, + 0x74U, 0x00U, 0x00U, 0x03U, 0x02U, 0x01U, 0x01U, 0x05U, 0x03U, + 0x01U, 0x00U, 0x02U, 0x07U, 0x11U, 0x02U, 0x06U, 0x6DU, 0x65U, + 0x6DU, 0x6FU, 0x72U, 0x79U, 0x02U, 0x00U, 0x04U, 0x63U, 0x62U, + 0x61U, 0x6BU, 0x00U, 0x01U, 0x0AU, 0x0CU, 0x01U, 0x0AU, 0x00U, + 0x41U, 0x00U, 0x41U, 0x00U, 0x42U, 0x00U, 0x10U, 0x00U, 0x0BU, + }}, + + /* ==== WASM: 105 ==== */ + {R"[test.hook.gas]( + (module + (type (;0;) (func (param i32 i32 i64) (result i64))) + (type (;1;) (func (result i64))) + (import "env" "accept" (func (;0;) (type 0))) + (func (;1;) (type 1) (result i64) + i32.const 0 + i32.const 0 + i64.const 0 + call 0) + (memory (;0;) 2) + (export "memory" (memory 0)) + (export "hook" (func 1))) + )[test.hook.gas]", + { + 0x00U, 0x61U, 0x73U, 0x6DU, 0x01U, 0x00U, 0x00U, 0x00U, 0x01U, 0x0CU, + 0x02U, 0x60U, 0x03U, 0x7FU, 0x7FU, 0x7EU, 0x01U, 0x7EU, 0x60U, 0x00U, + 0x01U, 0x7EU, 0x02U, 0x0EU, 0x01U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x06U, + 0x61U, 0x63U, 0x63U, 0x65U, 0x70U, 0x74U, 0x00U, 0x00U, 0x03U, 0x02U, + 0x01U, 0x01U, 0x05U, 0x03U, 0x01U, 0x00U, 0x02U, 0x07U, 0x11U, 0x02U, + 0x06U, 0x6DU, 0x65U, 0x6DU, 0x6FU, 0x72U, 0x79U, 0x02U, 0x00U, 0x04U, + 0x68U, 0x6FU, 0x6FU, 0x6BU, 0x00U, 0x01U, 0x0AU, 0x0CU, 0x01U, 0x0AU, + 0x00U, 0x41U, 0x00U, 0x41U, 0x00U, 0x42U, 0x00U, 0x10U, 0x00U, 0x0BU, + }}, + + /* ==== WASM: 106 ==== */ + {R"[test.hook.gas]( + (module + (type (;0;) (func (param i32 i32 i64) (result i64))) + (type (;1;) (func (param i32 i32) (result i64))) + (import "env" "accept" (func (;0;) (type 0))) + (func (;1;) (type 1) (param i32 i32) (result i64) + i32.const 0 + i32.const 0 + i64.const 0 + call 0) + (memory (;0;) 2) + (export "memory" (memory 0)) + (export "hook" (func 1))) + )[test.hook.gas]", + { + 0x00U, 0x61U, 0x73U, 0x6DU, 0x01U, 0x00U, 0x00U, 0x00U, 0x01U, 0x0EU, + 0x02U, 0x60U, 0x03U, 0x7FU, 0x7FU, 0x7EU, 0x01U, 0x7EU, 0x60U, 0x02U, + 0x7FU, 0x7FU, 0x01U, 0x7EU, 0x02U, 0x0EU, 0x01U, 0x03U, 0x65U, 0x6EU, + 0x76U, 0x06U, 0x61U, 0x63U, 0x63U, 0x65U, 0x70U, 0x74U, 0x00U, 0x00U, + 0x03U, 0x02U, 0x01U, 0x01U, 0x05U, 0x03U, 0x01U, 0x00U, 0x02U, 0x07U, + 0x11U, 0x02U, 0x06U, 0x6DU, 0x65U, 0x6DU, 0x6FU, 0x72U, 0x79U, 0x02U, + 0x00U, 0x04U, 0x68U, 0x6FU, 0x6FU, 0x6BU, 0x00U, 0x01U, 0x0AU, 0x0CU, + 0x01U, 0x0AU, 0x00U, 0x41U, 0x00U, 0x41U, 0x00U, 0x42U, 0x00U, 0x10U, + 0x00U, 0x0BU, + }}, + + /* ==== WASM: 107 ==== */ + {R"[test.hook.gas]( + (module + (type (;0;) (func (param i32 i32 i64) (result i64))) + (type (;1;) (func (param i64) (result i64))) + (import "env" "accept" (func (;0;) (type 0))) + (func (;1;) (type 1) (param i64) (result i64) + i32.const 0 + i32.const 0 + i64.const 0 + call 0) + (memory (;0;) 2) + (export "memory" (memory 0)) + (export "hook" (func 1))) + )[test.hook.gas]", + { + 0x00U, 0x61U, 0x73U, 0x6DU, 0x01U, 0x00U, 0x00U, 0x00U, 0x01U, + 0x0DU, 0x02U, 0x60U, 0x03U, 0x7FU, 0x7FU, 0x7EU, 0x01U, 0x7EU, + 0x60U, 0x01U, 0x7EU, 0x01U, 0x7EU, 0x02U, 0x0EU, 0x01U, 0x03U, + 0x65U, 0x6EU, 0x76U, 0x06U, 0x61U, 0x63U, 0x63U, 0x65U, 0x70U, + 0x74U, 0x00U, 0x00U, 0x03U, 0x02U, 0x01U, 0x01U, 0x05U, 0x03U, + 0x01U, 0x00U, 0x02U, 0x07U, 0x11U, 0x02U, 0x06U, 0x6DU, 0x65U, + 0x6DU, 0x6FU, 0x72U, 0x79U, 0x02U, 0x00U, 0x04U, 0x68U, 0x6FU, + 0x6FU, 0x6BU, 0x00U, 0x01U, 0x0AU, 0x0CU, 0x01U, 0x0AU, 0x00U, + 0x41U, 0x00U, 0x41U, 0x00U, 0x42U, 0x00U, 0x10U, 0x00U, 0x0BU, + }}, + + /* ==== WASM: 108 ==== */ + {R"[test.hook.gas]( + (module + (type (;0;) (func (param i32 i32 i64) (result i64))) + (type (;1;) (func (param i32))) + (import "env" "accept" (func (;0;) (type 0))) + (func (;1;) (type 1) (param i32) + i32.const 0 + i32.const 0 + i64.const 0 + call 0 + drop) + (memory (;0;) 2) + (export "memory" (memory 0)) + (export "hook" (func 1))) + )[test.hook.gas]", + { + 0x00U, 0x61U, 0x73U, 0x6DU, 0x01U, 0x00U, 0x00U, 0x00U, 0x01U, + 0x0CU, 0x02U, 0x60U, 0x03U, 0x7FU, 0x7FU, 0x7EU, 0x01U, 0x7EU, + 0x60U, 0x01U, 0x7FU, 0x00U, 0x02U, 0x0EU, 0x01U, 0x03U, 0x65U, + 0x6EU, 0x76U, 0x06U, 0x61U, 0x63U, 0x63U, 0x65U, 0x70U, 0x74U, + 0x00U, 0x00U, 0x03U, 0x02U, 0x01U, 0x01U, 0x05U, 0x03U, 0x01U, + 0x00U, 0x02U, 0x07U, 0x11U, 0x02U, 0x06U, 0x6DU, 0x65U, 0x6DU, + 0x6FU, 0x72U, 0x79U, 0x02U, 0x00U, 0x04U, 0x68U, 0x6FU, 0x6FU, + 0x6BU, 0x00U, 0x01U, 0x0AU, 0x0DU, 0x01U, 0x0BU, 0x00U, 0x41U, + 0x00U, 0x41U, 0x00U, 0x42U, 0x00U, 0x10U, 0x00U, 0x1AU, 0x0BU, + }}, + + /* ==== WASM: 109 ==== */ + {R"[test.hook.gas]( + (module + (type (;0;) (func (param i32 i32 i64) (result i64))) + (type (;1;) (func (param i32) (result i32))) + (import "env" "accept" (func (;0;) (type 0))) + (func (;1;) (type 1) (param i32) (result i32) + i32.const 0 + i32.const 0 + i64.const 0 + call 0 + drop + i32.const 0) + (memory (;0;) 2) + (export "memory" (memory 0)) + (export "hook" (func 1))) + )[test.hook.gas]", + { + 0x00U, 0x61U, 0x73U, 0x6DU, 0x01U, 0x00U, 0x00U, 0x00U, 0x01U, 0x0DU, + 0x02U, 0x60U, 0x03U, 0x7FU, 0x7FU, 0x7EU, 0x01U, 0x7EU, 0x60U, 0x01U, + 0x7FU, 0x01U, 0x7FU, 0x02U, 0x0EU, 0x01U, 0x03U, 0x65U, 0x6EU, 0x76U, + 0x06U, 0x61U, 0x63U, 0x63U, 0x65U, 0x70U, 0x74U, 0x00U, 0x00U, 0x03U, + 0x02U, 0x01U, 0x01U, 0x05U, 0x03U, 0x01U, 0x00U, 0x02U, 0x07U, 0x11U, + 0x02U, 0x06U, 0x6DU, 0x65U, 0x6DU, 0x6FU, 0x72U, 0x79U, 0x02U, 0x00U, + 0x04U, 0x68U, 0x6FU, 0x6FU, 0x6BU, 0x00U, 0x01U, 0x0AU, 0x0FU, 0x01U, + 0x0DU, 0x00U, 0x41U, 0x00U, 0x41U, 0x00U, 0x42U, 0x00U, 0x10U, 0x00U, + 0x1AU, 0x41U, 0x00U, 0x0BU, + }}, + + /* ==== WASM: 110 ==== */ + {R"[test.hook.gas]( + (module + (type (;0;) (func (param i32 i32 i64) (result i64))) + (type (;1;) (func (param i32) (result i64))) + (type (;2;) (func (result i64))) + (import "env" "accept" (func (;0;) (type 0))) + (func (;1;) (type 1) (param i32) (result i64) + i32.const 0 + i32.const 0 + i64.const 0 + call 0) + (func (;2;) (type 2) (result i64) + i32.const 0 + i32.const 0 + i64.const 0 + call 0) + (memory (;0;) 2) + (export "memory" (memory 0)) + (export "hook" (func 1)) + (export "cbak" (func 2))) + )[test.hook.gas]", + { + 0x00U, 0x61U, 0x73U, 0x6DU, 0x01U, 0x00U, 0x00U, 0x00U, 0x01U, 0x11U, + 0x03U, 0x60U, 0x03U, 0x7FU, 0x7FU, 0x7EU, 0x01U, 0x7EU, 0x60U, 0x01U, + 0x7FU, 0x01U, 0x7EU, 0x60U, 0x00U, 0x01U, 0x7EU, 0x02U, 0x0EU, 0x01U, + 0x03U, 0x65U, 0x6EU, 0x76U, 0x06U, 0x61U, 0x63U, 0x63U, 0x65U, 0x70U, + 0x74U, 0x00U, 0x00U, 0x03U, 0x03U, 0x02U, 0x01U, 0x02U, 0x05U, 0x03U, + 0x01U, 0x00U, 0x02U, 0x07U, 0x18U, 0x03U, 0x06U, 0x6DU, 0x65U, 0x6DU, + 0x6FU, 0x72U, 0x79U, 0x02U, 0x00U, 0x04U, 0x68U, 0x6FU, 0x6FU, 0x6BU, + 0x00U, 0x01U, 0x04U, 0x63U, 0x62U, 0x61U, 0x6BU, 0x00U, 0x02U, 0x0AU, + 0x17U, 0x02U, 0x0AU, 0x00U, 0x41U, 0x00U, 0x41U, 0x00U, 0x42U, 0x00U, + 0x10U, 0x00U, 0x0BU, 0x0AU, 0x00U, 0x41U, 0x00U, 0x41U, 0x00U, 0x42U, + 0x00U, 0x10U, 0x00U, 0x0BU, + }}, + + /* ==== WASM: 111 ==== */ + {R"[test.hook.gas]( + (module + (type (;0;) (func (param i32 i32 i64) (result i64))) + (type (;1;) (func (param i32) (result i64))) + (type (;2;) (func (param i64) (result i64))) + (import "env" "accept" (func (;0;) (type 0))) + (func (;1;) (type 1) (param i32) (result i64) + i32.const 0 + i32.const 0 + i64.const 0 + call 0) + (func (;2;) (type 2) (param i64) (result i64) + i32.const 0 + i32.const 0 + i64.const 0 + call 0) + (memory (;0;) 2) + (export "memory" (memory 0)) + (export "hook" (func 1)) + (export "cbak" (func 2))) + )[test.hook.gas]", + { + 0x00U, 0x61U, 0x73U, 0x6DU, 0x01U, 0x00U, 0x00U, 0x00U, 0x01U, 0x12U, + 0x03U, 0x60U, 0x03U, 0x7FU, 0x7FU, 0x7EU, 0x01U, 0x7EU, 0x60U, 0x01U, + 0x7FU, 0x01U, 0x7EU, 0x60U, 0x01U, 0x7EU, 0x01U, 0x7EU, 0x02U, 0x0EU, + 0x01U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x06U, 0x61U, 0x63U, 0x63U, 0x65U, + 0x70U, 0x74U, 0x00U, 0x00U, 0x03U, 0x03U, 0x02U, 0x01U, 0x02U, 0x05U, + 0x03U, 0x01U, 0x00U, 0x02U, 0x07U, 0x18U, 0x03U, 0x06U, 0x6DU, 0x65U, + 0x6DU, 0x6FU, 0x72U, 0x79U, 0x02U, 0x00U, 0x04U, 0x68U, 0x6FU, 0x6FU, + 0x6BU, 0x00U, 0x01U, 0x04U, 0x63U, 0x62U, 0x61U, 0x6BU, 0x00U, 0x02U, + 0x0AU, 0x17U, 0x02U, 0x0AU, 0x00U, 0x41U, 0x00U, 0x41U, 0x00U, 0x42U, + 0x00U, 0x10U, 0x00U, 0x0BU, 0x0AU, 0x00U, 0x41U, 0x00U, 0x41U, 0x00U, + 0x42U, 0x00U, 0x10U, 0x00U, 0x0BU, + }}, + + /* ==== WASM: 112 ==== */ + {R"[test.hook.gas]( + (module + (type (;0;) (func (param i32 i32 i64) (result i64))) + (type (;1;) (func (param i32) (result i64))) + (type (;2;) (func (param i32) (result i32))) + (import "env" "accept" (func (;0;) (type 0))) + (func (;1;) (type 1) (param i32) (result i64) + i32.const 0 + i32.const 0 + i64.const 0 + call 0) + (func (;2;) (type 2) (param i32) (result i32) + i32.const 0 + i32.const 0 + i64.const 0 + call 0 + drop + i32.const 0) + (memory (;0;) 2) + (export "memory" (memory 0)) + (export "hook" (func 1)) + (export "cbak" (func 2))) + )[test.hook.gas]", + { + 0x00U, 0x61U, 0x73U, 0x6DU, 0x01U, 0x00U, 0x00U, 0x00U, 0x01U, 0x12U, + 0x03U, 0x60U, 0x03U, 0x7FU, 0x7FU, 0x7EU, 0x01U, 0x7EU, 0x60U, 0x01U, + 0x7FU, 0x01U, 0x7EU, 0x60U, 0x01U, 0x7FU, 0x01U, 0x7FU, 0x02U, 0x0EU, + 0x01U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x06U, 0x61U, 0x63U, 0x63U, 0x65U, + 0x70U, 0x74U, 0x00U, 0x00U, 0x03U, 0x03U, 0x02U, 0x01U, 0x02U, 0x05U, + 0x03U, 0x01U, 0x00U, 0x02U, 0x07U, 0x18U, 0x03U, 0x06U, 0x6DU, 0x65U, + 0x6DU, 0x6FU, 0x72U, 0x79U, 0x02U, 0x00U, 0x04U, 0x68U, 0x6FU, 0x6FU, + 0x6BU, 0x00U, 0x01U, 0x04U, 0x63U, 0x62U, 0x61U, 0x6BU, 0x00U, 0x02U, + 0x0AU, 0x1AU, 0x02U, 0x0AU, 0x00U, 0x41U, 0x00U, 0x41U, 0x00U, 0x42U, + 0x00U, 0x10U, 0x00U, 0x0BU, 0x0DU, 0x00U, 0x41U, 0x00U, 0x41U, 0x00U, + 0x42U, 0x00U, 0x10U, 0x00U, 0x1AU, 0x41U, 0x00U, 0x0BU, + }}, + + /* ==== WASM: 113 ==== */ + {R"[test.hook.gas]( + (module + (type (;0;) (func (param i32) (result i64))) + (func (;0;) (type 0) (param i32) (result i64) + i64.const 0) + (memory (;0;) 2) + (export "memory" (memory 0)) + (export "hook" (func 0))) + )[test.hook.gas]", + { + 0x00U, 0x61U, 0x73U, 0x6DU, 0x01U, 0x00U, 0x00U, 0x00U, 0x01U, + 0x06U, 0x01U, 0x60U, 0x01U, 0x7FU, 0x01U, 0x7EU, 0x03U, 0x02U, + 0x01U, 0x00U, 0x05U, 0x03U, 0x01U, 0x00U, 0x02U, 0x07U, 0x11U, + 0x02U, 0x06U, 0x6DU, 0x65U, 0x6DU, 0x6FU, 0x72U, 0x79U, 0x02U, + 0x00U, 0x04U, 0x68U, 0x6FU, 0x6FU, 0x6BU, 0x00U, 0x00U, 0x0AU, + 0x06U, 0x01U, 0x04U, 0x00U, 0x42U, 0x00U, 0x0BU, + }}, + + /* ==== WASM: 114 ==== */ + {R"[test.hook.gas]( + (module + (type (;0;) (func (param i32 i32 i64) (result i64))) + (type (;1;) (func (param i32) (result i64))) + (import "wasi_snapshot_preview1" "fd_write" (func (;0;) (type 0))) + (func (;1;) (type 1) (param i32) (result i64) + i32.const 0 + i32.const 0 + i64.const 0 + call 0) + (memory (;0;) 2) + (export "memory" (memory 0)) + (export "hook" (func 1))) + )[test.hook.gas]", + { + 0x00U, 0x61U, 0x73U, 0x6DU, 0x01U, 0x00U, 0x00U, 0x00U, 0x01U, 0x0DU, + 0x02U, 0x60U, 0x03U, 0x7FU, 0x7FU, 0x7EU, 0x01U, 0x7EU, 0x60U, 0x01U, + 0x7FU, 0x01U, 0x7EU, 0x02U, 0x23U, 0x01U, 0x16U, 0x77U, 0x61U, 0x73U, + 0x69U, 0x5FU, 0x73U, 0x6EU, 0x61U, 0x70U, 0x73U, 0x68U, 0x6FU, 0x74U, + 0x5FU, 0x70U, 0x72U, 0x65U, 0x76U, 0x69U, 0x65U, 0x77U, 0x31U, 0x08U, + 0x66U, 0x64U, 0x5FU, 0x77U, 0x72U, 0x69U, 0x74U, 0x65U, 0x00U, 0x00U, + 0x03U, 0x02U, 0x01U, 0x01U, 0x05U, 0x03U, 0x01U, 0x00U, 0x02U, 0x07U, + 0x11U, 0x02U, 0x06U, 0x6DU, 0x65U, 0x6DU, 0x6FU, 0x72U, 0x79U, 0x02U, + 0x00U, 0x04U, 0x68U, 0x6FU, 0x6FU, 0x6BU, 0x00U, 0x01U, 0x0AU, 0x0CU, + 0x01U, 0x0AU, 0x00U, 0x41U, 0x00U, 0x41U, 0x00U, 0x42U, 0x00U, 0x10U, + 0x00U, 0x0BU, + }}, + + /* ==== WASM: 115 ==== */ + {R"[test.hook.gas]( + (module + (type (;0;) (func (param i32) (result i32))) + (type (;1;) (func (param i32) (result i64))) + (import "env" "malloc" (func (;0;) (type 0))) + (func (;1;) (type 1) (param i32) (result i64) + i64.const 0) + (memory (;0;) 2) + (export "memory" (memory 0)) + (export "hook" (func 1))) + )[test.hook.gas]", + { + 0x00U, 0x61U, 0x73U, 0x6DU, 0x01U, 0x00U, 0x00U, 0x00U, 0x01U, 0x0BU, + 0x02U, 0x60U, 0x01U, 0x7FU, 0x01U, 0x7FU, 0x60U, 0x01U, 0x7FU, 0x01U, + 0x7EU, 0x02U, 0x0EU, 0x01U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x06U, 0x6DU, + 0x61U, 0x6CU, 0x6CU, 0x6FU, 0x63U, 0x00U, 0x00U, 0x03U, 0x02U, 0x01U, + 0x01U, 0x05U, 0x03U, 0x01U, 0x00U, 0x02U, 0x07U, 0x11U, 0x02U, 0x06U, + 0x6DU, 0x65U, 0x6DU, 0x6FU, 0x72U, 0x79U, 0x02U, 0x00U, 0x04U, 0x68U, + 0x6FU, 0x6FU, 0x6BU, 0x00U, 0x01U, 0x0AU, 0x06U, 0x01U, 0x04U, 0x00U, + 0x42U, 0x00U, 0x0BU, + }}, + + /* ==== WASM: 116 ==== */ + {R"[test.hook.gas]( + (module + (type (;0;) (func (param i32 i32 i64))) + (type (;1;) (func (param i32) (result i64))) + (import "env" "accept" (func (;0;) (type 0))) + (func (;1;) (type 1) (param i32) (result i64) + i64.const 0) + (memory (;0;) 2) + (export "memory" (memory 0)) + (export "hook" (func 1))) + )[test.hook.gas]", + { + 0x00U, 0x61U, 0x73U, 0x6DU, 0x01U, 0x00U, 0x00U, 0x00U, 0x01U, 0x0CU, + 0x02U, 0x60U, 0x03U, 0x7FU, 0x7FU, 0x7EU, 0x00U, 0x60U, 0x01U, 0x7FU, + 0x01U, 0x7EU, 0x02U, 0x0EU, 0x01U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x06U, + 0x61U, 0x63U, 0x63U, 0x65U, 0x70U, 0x74U, 0x00U, 0x00U, 0x03U, 0x02U, + 0x01U, 0x01U, 0x05U, 0x03U, 0x01U, 0x00U, 0x02U, 0x07U, 0x11U, 0x02U, + 0x06U, 0x6DU, 0x65U, 0x6DU, 0x6FU, 0x72U, 0x79U, 0x02U, 0x00U, 0x04U, + 0x68U, 0x6FU, 0x6FU, 0x6BU, 0x00U, 0x01U, 0x0AU, 0x06U, 0x01U, 0x04U, + 0x00U, 0x42U, 0x00U, 0x0BU, + }}, + + /* ==== WASM: 117 ==== */ + {R"[test.hook.gas]( + (module + (type (;0;) (func (param i32 i32 i64) (result i32))) + (type (;1;) (func (param i32) (result i64))) + (import "env" "accept" (func (;0;) (type 0))) + (func (;1;) (type 1) (param i32) (result i64) + i64.const 0) + (memory (;0;) 2) + (export "memory" (memory 0)) + (export "hook" (func 1))) + )[test.hook.gas]", + { + 0x00U, 0x61U, 0x73U, 0x6DU, 0x01U, 0x00U, 0x00U, 0x00U, 0x01U, 0x0DU, + 0x02U, 0x60U, 0x03U, 0x7FU, 0x7FU, 0x7EU, 0x01U, 0x7FU, 0x60U, 0x01U, + 0x7FU, 0x01U, 0x7EU, 0x02U, 0x0EU, 0x01U, 0x03U, 0x65U, 0x6EU, 0x76U, + 0x06U, 0x61U, 0x63U, 0x63U, 0x65U, 0x70U, 0x74U, 0x00U, 0x00U, 0x03U, + 0x02U, 0x01U, 0x01U, 0x05U, 0x03U, 0x01U, 0x00U, 0x02U, 0x07U, 0x11U, + 0x02U, 0x06U, 0x6DU, 0x65U, 0x6DU, 0x6FU, 0x72U, 0x79U, 0x02U, 0x00U, + 0x04U, 0x68U, 0x6FU, 0x6FU, 0x6BU, 0x00U, 0x01U, 0x0AU, 0x06U, 0x01U, + 0x04U, 0x00U, 0x42U, 0x00U, 0x0BU, + }}, + + /* ==== WASM: 118 ==== */ + {R"[test.hook.gas]( + (module + (type (;0;) (func (param i32) (result i64))) + (type (;1;) (func (param i32) (result i64))) + (import "env" "accept" (func (;0;) (type 0))) + (func (;1;) (type 1) (param i32) (result i64) + i32.const 0 + call 0) + (memory (;0;) 2) + (export "memory" (memory 0)) + (export "hook" (func 1))) + )[test.hook.gas]", + { + 0x00U, 0x61U, 0x73U, 0x6DU, 0x01U, 0x00U, 0x00U, 0x00U, 0x01U, 0x0BU, + 0x02U, 0x60U, 0x01U, 0x7FU, 0x01U, 0x7EU, 0x60U, 0x01U, 0x7FU, 0x01U, + 0x7EU, 0x02U, 0x0EU, 0x01U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x06U, 0x61U, + 0x63U, 0x63U, 0x65U, 0x70U, 0x74U, 0x00U, 0x00U, 0x03U, 0x02U, 0x01U, + 0x01U, 0x05U, 0x03U, 0x01U, 0x00U, 0x02U, 0x07U, 0x11U, 0x02U, 0x06U, + 0x6DU, 0x65U, 0x6DU, 0x6FU, 0x72U, 0x79U, 0x02U, 0x00U, 0x04U, 0x68U, + 0x6FU, 0x6FU, 0x6BU, 0x00U, 0x01U, 0x0AU, 0x08U, 0x01U, 0x06U, 0x00U, + 0x41U, 0x00U, 0x10U, 0x00U, 0x0BU, + }}, + + /* ==== WASM: 119 ==== */ + {R"[test.hook.gas]( + (module + (type (;0;) (func (param i32 i32 i64 i32) (result i64))) + (type (;1;) (func (param i32) (result i64))) + (import "env" "accept" (func (;0;) (type 0))) + (func (;1;) (type 1) (param i32) (result i64) + i64.const 0) + (memory (;0;) 2) + (export "memory" (memory 0)) + (export "hook" (func 1))) + )[test.hook.gas]", + { + 0x00U, 0x61U, 0x73U, 0x6DU, 0x01U, 0x00U, 0x00U, 0x00U, 0x01U, 0x0EU, + 0x02U, 0x60U, 0x04U, 0x7FU, 0x7FU, 0x7EU, 0x7FU, 0x01U, 0x7EU, 0x60U, + 0x01U, 0x7FU, 0x01U, 0x7EU, 0x02U, 0x0EU, 0x01U, 0x03U, 0x65U, 0x6EU, + 0x76U, 0x06U, 0x61U, 0x63U, 0x63U, 0x65U, 0x70U, 0x74U, 0x00U, 0x00U, + 0x03U, 0x02U, 0x01U, 0x01U, 0x05U, 0x03U, 0x01U, 0x00U, 0x02U, 0x07U, + 0x11U, 0x02U, 0x06U, 0x6DU, 0x65U, 0x6DU, 0x6FU, 0x72U, 0x79U, 0x02U, + 0x00U, 0x04U, 0x68U, 0x6FU, 0x6FU, 0x6BU, 0x00U, 0x01U, 0x0AU, 0x06U, + 0x01U, 0x04U, 0x00U, 0x42U, 0x00U, 0x0BU, + }}, + + /* ==== WASM: 120 ==== */ + {R"[test.hook.gas]( + (module + (type (;0;) (func (param i64 i32 i64) (result i64))) + (type (;1;) (func (param i32) (result i64))) + (import "env" "accept" (func (;0;) (type 0))) + (func (;1;) (type 1) (param i32) (result i64) + i64.const 0) + (memory (;0;) 2) + (export "memory" (memory 0)) + (export "hook" (func 1))) + )[test.hook.gas]", + { + 0x00U, 0x61U, 0x73U, 0x6DU, 0x01U, 0x00U, 0x00U, 0x00U, 0x01U, 0x0DU, + 0x02U, 0x60U, 0x03U, 0x7EU, 0x7FU, 0x7EU, 0x01U, 0x7EU, 0x60U, 0x01U, + 0x7FU, 0x01U, 0x7EU, 0x02U, 0x0EU, 0x01U, 0x03U, 0x65U, 0x6EU, 0x76U, + 0x06U, 0x61U, 0x63U, 0x63U, 0x65U, 0x70U, 0x74U, 0x00U, 0x00U, 0x03U, + 0x02U, 0x01U, 0x01U, 0x05U, 0x03U, 0x01U, 0x00U, 0x02U, 0x07U, 0x11U, + 0x02U, 0x06U, 0x6DU, 0x65U, 0x6DU, 0x6FU, 0x72U, 0x79U, 0x02U, 0x00U, + 0x04U, 0x68U, 0x6FU, 0x6FU, 0x6BU, 0x00U, 0x01U, 0x0AU, 0x06U, 0x01U, + 0x04U, 0x00U, 0x42U, 0x00U, 0x0BU, + }}, + + /* ==== WASM: 121 ==== */ + {R"[test.hook.gas]( + (module + (type (;0;) (func (param i64 i64 i64 i64 i64 i64) (result i64))) + (type (;1;) (func (param i32) (result i64))) + (import "env" "util_verify" (func (;0;) (type 0))) + (func (;1;) (type 1) (param i32) (result i64) + i64.const 0) + (memory (;0;) 2) + (export "memory" (memory 0)) + (export "hook" (func 1))) + )[test.hook.gas]", + { + 0x00U, 0x61U, 0x73U, 0x6DU, 0x01U, 0x00U, 0x00U, 0x00U, 0x01U, 0x10U, + 0x02U, 0x60U, 0x06U, 0x7EU, 0x7EU, 0x7EU, 0x7EU, 0x7EU, 0x7EU, 0x01U, + 0x7EU, 0x60U, 0x01U, 0x7FU, 0x01U, 0x7EU, 0x02U, 0x13U, 0x01U, 0x03U, + 0x65U, 0x6EU, 0x76U, 0x0BU, 0x75U, 0x74U, 0x69U, 0x6CU, 0x5FU, 0x76U, + 0x65U, 0x72U, 0x69U, 0x66U, 0x79U, 0x00U, 0x00U, 0x03U, 0x02U, 0x01U, + 0x01U, 0x05U, 0x03U, 0x01U, 0x00U, 0x02U, 0x07U, 0x11U, 0x02U, 0x06U, + 0x6DU, 0x65U, 0x6DU, 0x6FU, 0x72U, 0x79U, 0x02U, 0x00U, 0x04U, 0x68U, + 0x6FU, 0x6FU, 0x6BU, 0x00U, 0x01U, 0x0AU, 0x06U, 0x01U, 0x04U, 0x00U, + 0x42U, 0x00U, 0x0BU, + }}, + + /* ==== WASM: 122 ==== */ + {R"[test.hook.gas]( + #include + extern int64_t accept (uint32_t read_ptr, uint32_t read_len, int64_t error_code); + extern int64_t rollback (uint32_t read_ptr, uint32_t read_len, int64_t error_code); + extern int64_t emit (uint32_t write_ptr, uint32_t write_len, uint32_t read_ptr, uint32_t read_len); + extern int64_t hook_account(uint32_t write_ptr, uint32_t write_len); + extern int64_t etxn_reserve(uint32_t); + extern int64_t etxn_fee_base (uint32_t read_ptr, uint32_t read_len); + extern int64_t etxn_details (uint32_t write_ptr, uint32_t write_len); + extern int64_t ledger_seq (void); + + #define SBUF(x) (uint32_t)x,sizeof(x) + + // clang-format off + uint8_t txn[229] = + { + /* size, upto, field name */ + /* 3, 0, tt = AccountSet */ 0x12U, 0x00U, 0x03U, + /* 5, 3, flags */ 0x22U, 0x00U, 0x00U, 0x00U, 0x00U, + /* 5, 8, sequence */ 0x24U, 0x00U, 0x00U, 0x00U, 0x00U, + /* 6, 13, firstledgersequence */ 0x20U, 0x1AU, 0x00U, 0x00U, 0x00U, 0x00U, + /* 6, 19, lastledgersequence */ 0x20U, 0x1BU, 0x00U, 0x00U, 0x00U, 0x00U, + /* 9, 25, fee */ 0x68U, 0x40U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, + /* 35, 34, signingpubkey */ 0x73U, 0x21U, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + /* 22, 69, account */ 0x81U, 0x14U, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + /* 138, 91, emit details */ + /* 0, 229, */ + }; + // clang-format on + + // TX BUILDER + #define FLAGS_OUT (txn + 4U) + #define FLS_OUT (txn + 15U) + #define LLS_OUT (txn + 21U) + #define FEE_OUT (txn + 26U) + #define ACCOUNT_OUT (txn + 71U) + #define EMIT_OUT (txn + 91U) + + #define FLIP_ENDIAN_32(value) \ + (uint32_t)(((value & 0xFFU) << 24) | ((value & 0xFF00U) << 8) | \ + ((value & 0xFF0000U) >> 8) | ((value & 0xFF000000U) >> 24)) + + #define SET_UINT32(ptr, value) *((uint32_t *)(ptr)) = FLIP_ENDIAN_32(value); + + #define SET_NATIVE_AMOUNT(ptr, amount) \ + do { \ + uint8_t *b = (ptr); \ + *b++ = 0b01000000 + ((amount >> 56) & 0b00111111); \ + *b++ = (amount >> 48) & 0xFFU; \ + *b++ = (amount >> 40) & 0xFFU; \ + *b++ = (amount >> 32) & 0xFFU; \ + *b++ = (amount >> 24) & 0xFFU; \ + *b++ = (amount >> 16) & 0xFFU; \ + *b++ = (amount >> 8) & 0xFFU; \ + *b++ = (amount >> 0) & 0xFFU; \ + } while (0) + + #define PREPARE_TXN() \ + do { \ + etxn_reserve(1); \ + uint32_t fls = (uint32_t)ledger_seq() + 1; \ + SET_UINT32(FLS_OUT, fls); \ + SET_UINT32(LLS_OUT, fls + 4); \ + hook_account(ACCOUNT_OUT, 20); \ + etxn_details(EMIT_OUT, 138U); \ + int64_t fee = etxn_fee_base(SBUF(txn)); \ + SET_NATIVE_AMOUNT(FEE_OUT, fee); \ + } while (0) + + int64_t cbak(uint32_t reserved ) + { + for(int i = 0; i < 1000; i++) + ledger_seq(); + return accept(0,0,0); + } + int64_t hook(uint32_t reserved ) + { + PREPARE_TXN(); + uint8_t emithash[32]; + int64_t emit_result = emit(SBUF(emithash), SBUF(txn)); + if (emit_result > 0) + return accept(0,0,0); + else + return rollback(0,0,0); + } + )[test.hook.gas]", + { + 0x00U, 0x61U, 0x73U, 0x6DU, 0x01U, 0x00U, 0x00U, 0x00U, 0x01U, 0x22U, + 0x06U, 0x60U, 0x00U, 0x01U, 0x7EU, 0x60U, 0x03U, 0x7FU, 0x7FU, 0x7EU, + 0x01U, 0x7EU, 0x60U, 0x01U, 0x7FU, 0x01U, 0x7EU, 0x60U, 0x02U, 0x7FU, + 0x7FU, 0x01U, 0x7EU, 0x60U, 0x04U, 0x7FU, 0x7FU, 0x7FU, 0x7FU, 0x01U, + 0x7EU, 0x60U, 0x00U, 0x00U, 0x02U, 0x86U, 0x01U, 0x08U, 0x03U, 0x65U, + 0x6EU, 0x76U, 0x0AU, 0x6CU, 0x65U, 0x64U, 0x67U, 0x65U, 0x72U, 0x5FU, + 0x73U, 0x65U, 0x71U, 0x00U, 0x00U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x06U, + 0x61U, 0x63U, 0x63U, 0x65U, 0x70U, 0x74U, 0x00U, 0x01U, 0x03U, 0x65U, + 0x6EU, 0x76U, 0x0CU, 0x65U, 0x74U, 0x78U, 0x6EU, 0x5FU, 0x72U, 0x65U, + 0x73U, 0x65U, 0x72U, 0x76U, 0x65U, 0x00U, 0x02U, 0x03U, 0x65U, 0x6EU, + 0x76U, 0x0CU, 0x68U, 0x6FU, 0x6FU, 0x6BU, 0x5FU, 0x61U, 0x63U, 0x63U, + 0x6FU, 0x75U, 0x6EU, 0x74U, 0x00U, 0x03U, 0x03U, 0x65U, 0x6EU, 0x76U, + 0x0CU, 0x65U, 0x74U, 0x78U, 0x6EU, 0x5FU, 0x64U, 0x65U, 0x74U, 0x61U, + 0x69U, 0x6CU, 0x73U, 0x00U, 0x03U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x0DU, + 0x65U, 0x74U, 0x78U, 0x6EU, 0x5FU, 0x66U, 0x65U, 0x65U, 0x5FU, 0x62U, + 0x61U, 0x73U, 0x65U, 0x00U, 0x03U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x04U, + 0x65U, 0x6DU, 0x69U, 0x74U, 0x00U, 0x04U, 0x03U, 0x65U, 0x6EU, 0x76U, + 0x08U, 0x72U, 0x6FU, 0x6CU, 0x6CU, 0x62U, 0x61U, 0x63U, 0x6BU, 0x00U, + 0x01U, 0x03U, 0x04U, 0x03U, 0x05U, 0x02U, 0x02U, 0x04U, 0x05U, 0x01U, + 0x70U, 0x01U, 0x01U, 0x01U, 0x05U, 0x03U, 0x01U, 0x00U, 0x02U, 0x06U, + 0x27U, 0x06U, 0x7FU, 0x01U, 0x41U, 0xF0U, 0x89U, 0x04U, 0x0BU, 0x7FU, + 0x00U, 0x41U, 0xE5U, 0x09U, 0x0BU, 0x7FU, 0x00U, 0x41U, 0x80U, 0x08U, + 0x0BU, 0x7FU, 0x00U, 0x41U, 0xF0U, 0x89U, 0x04U, 0x0BU, 0x7FU, 0x00U, + 0x41U, 0x80U, 0x08U, 0x0BU, 0x7FU, 0x00U, 0x41U, 0x80U, 0x08U, 0x0BU, + 0x07U, 0x6CU, 0x09U, 0x06U, 0x6DU, 0x65U, 0x6DU, 0x6FU, 0x72U, 0x79U, + 0x02U, 0x00U, 0x11U, 0x5FU, 0x5FU, 0x77U, 0x61U, 0x73U, 0x6DU, 0x5FU, + 0x63U, 0x61U, 0x6CU, 0x6CU, 0x5FU, 0x63U, 0x74U, 0x6FU, 0x72U, 0x73U, + 0x00U, 0x08U, 0x0AU, 0x5FU, 0x5FU, 0x64U, 0x61U, 0x74U, 0x61U, 0x5FU, + 0x65U, 0x6EU, 0x64U, 0x03U, 0x01U, 0x0DU, 0x5FU, 0x5FU, 0x67U, 0x6CU, + 0x6FU, 0x62U, 0x61U, 0x6CU, 0x5FU, 0x62U, 0x61U, 0x73U, 0x65U, 0x03U, + 0x02U, 0x0BU, 0x5FU, 0x5FU, 0x68U, 0x65U, 0x61U, 0x70U, 0x5FU, 0x62U, + 0x61U, 0x73U, 0x65U, 0x03U, 0x03U, 0x0CU, 0x5FU, 0x5FU, 0x64U, 0x73U, + 0x6FU, 0x5FU, 0x68U, 0x61U, 0x6EU, 0x64U, 0x6CU, 0x65U, 0x03U, 0x04U, + 0x04U, 0x63U, 0x62U, 0x61U, 0x6BU, 0x00U, 0x09U, 0x04U, 0x68U, 0x6FU, + 0x6FU, 0x6BU, 0x00U, 0x0AU, 0x03U, 0x74U, 0x78U, 0x6EU, 0x03U, 0x05U, + 0x0AU, 0xA2U, 0x03U, 0x03U, 0x02U, 0x00U, 0x0BU, 0x28U, 0x01U, 0x01U, + 0x7FU, 0x41U, 0xE8U, 0x07U, 0x21U, 0x01U, 0x03U, 0x40U, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x20U, 0x01U, 0x41U, 0x7FU, 0x6AU, + 0x22U, 0x01U, 0x0DU, 0x00U, 0x0BU, 0x41U, 0x00U, 0x41U, 0x00U, 0x42U, + 0x00U, 0x10U, 0x81U, 0x80U, 0x80U, 0x80U, 0x00U, 0x0BU, 0xF3U, 0x02U, + 0x02U, 0x03U, 0x7FU, 0x01U, 0x7EU, 0x23U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x41U, 0x20U, 0x6BU, 0x22U, 0x01U, 0x24U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x41U, 0x01U, 0x10U, 0x82U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x41U, 0x00U, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0xA7U, + 0x22U, 0x02U, 0x41U, 0x05U, 0x6AU, 0x22U, 0x03U, 0x41U, 0x18U, 0x74U, + 0x20U, 0x03U, 0x41U, 0x08U, 0x74U, 0x41U, 0x80U, 0x80U, 0xFCU, 0x07U, + 0x71U, 0x72U, 0x20U, 0x03U, 0x41U, 0x08U, 0x76U, 0x41U, 0x80U, 0xFEU, + 0x03U, 0x71U, 0x20U, 0x03U, 0x41U, 0x18U, 0x76U, 0x72U, 0x72U, 0x36U, + 0x02U, 0x95U, 0x88U, 0x80U, 0x80U, 0x00U, 0x41U, 0x00U, 0x20U, 0x02U, + 0x41U, 0x01U, 0x6AU, 0x22U, 0x03U, 0x41U, 0x18U, 0x74U, 0x20U, 0x03U, + 0x41U, 0x08U, 0x74U, 0x41U, 0x80U, 0x80U, 0xFCU, 0x07U, 0x71U, 0x72U, + 0x20U, 0x03U, 0x41U, 0x08U, 0x76U, 0x41U, 0x80U, 0xFEU, 0x03U, 0x71U, + 0x20U, 0x03U, 0x41U, 0x18U, 0x76U, 0x72U, 0x72U, 0x36U, 0x02U, 0x8FU, + 0x88U, 0x80U, 0x80U, 0x00U, 0x41U, 0xC7U, 0x88U, 0x80U, 0x80U, 0x00U, + 0x41U, 0x14U, 0x10U, 0x83U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x41U, + 0xDBU, 0x88U, 0x80U, 0x80U, 0x00U, 0x41U, 0x8AU, 0x01U, 0x10U, 0x84U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x41U, 0x00U, 0x41U, 0x80U, 0x88U, + 0x80U, 0x80U, 0x00U, 0x41U, 0xE5U, 0x01U, 0x10U, 0x85U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x22U, 0x04U, 0x3CU, 0x00U, 0xA1U, 0x88U, 0x80U, 0x80U, + 0x00U, 0x41U, 0x00U, 0x20U, 0x04U, 0x42U, 0x08U, 0x88U, 0x3CU, 0x00U, + 0xA0U, 0x88U, 0x80U, 0x80U, 0x00U, 0x41U, 0x00U, 0x20U, 0x04U, 0x42U, + 0x10U, 0x88U, 0x3CU, 0x00U, 0x9FU, 0x88U, 0x80U, 0x80U, 0x00U, 0x41U, + 0x00U, 0x20U, 0x04U, 0x42U, 0x18U, 0x88U, 0x3CU, 0x00U, 0x9EU, 0x88U, + 0x80U, 0x80U, 0x00U, 0x41U, 0x00U, 0x20U, 0x04U, 0x42U, 0x20U, 0x88U, + 0x3CU, 0x00U, 0x9DU, 0x88U, 0x80U, 0x80U, 0x00U, 0x41U, 0x00U, 0x20U, + 0x04U, 0x42U, 0x28U, 0x88U, 0x3CU, 0x00U, 0x9CU, 0x88U, 0x80U, 0x80U, + 0x00U, 0x41U, 0x00U, 0x20U, 0x04U, 0x42U, 0x30U, 0x88U, 0x3CU, 0x00U, + 0x9BU, 0x88U, 0x80U, 0x80U, 0x00U, 0x41U, 0x00U, 0x20U, 0x04U, 0x42U, + 0x38U, 0x88U, 0xA7U, 0x41U, 0x3FU, 0x71U, 0x41U, 0xC0U, 0x00U, 0x72U, + 0x3AU, 0x00U, 0x9AU, 0x88U, 0x80U, 0x80U, 0x00U, 0x02U, 0x40U, 0x02U, + 0x40U, 0x20U, 0x01U, 0x41U, 0x20U, 0x41U, 0x80U, 0x88U, 0x80U, 0x80U, + 0x00U, 0x41U, 0xE5U, 0x01U, 0x10U, 0x86U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x42U, 0x01U, 0x53U, 0x0DU, 0x00U, 0x41U, 0x00U, 0x41U, 0x00U, 0x42U, + 0x00U, 0x10U, 0x81U, 0x80U, 0x80U, 0x80U, 0x00U, 0x21U, 0x04U, 0x0CU, + 0x01U, 0x0BU, 0x41U, 0x00U, 0x41U, 0x00U, 0x42U, 0x00U, 0x10U, 0x87U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x21U, 0x04U, 0x0BU, 0x20U, 0x01U, 0x41U, + 0x20U, 0x6AU, 0x24U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x20U, 0x04U, + 0x0BU, 0x0BU, 0xEDU, 0x01U, 0x01U, 0x00U, 0x41U, 0x80U, 0x08U, 0x0BU, + 0xE5U, 0x01U, 0x12U, 0x00U, 0x03U, 0x22U, 0x00U, 0x00U, 0x00U, 0x00U, + 0x24U, 0x00U, 0x00U, 0x00U, 0x00U, 0x20U, 0x1AU, 0x00U, 0x00U, 0x00U, + 0x00U, 0x20U, 0x1BU, 0x00U, 0x00U, 0x00U, 0x00U, 0x68U, 0x40U, 0x00U, + 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x73U, 0x21U, 0x00U, 0x00U, + 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, + 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, + 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, + 0x00U, 0x81U, 0x14U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, + 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, + 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, + 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, + 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, + 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, + 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, + 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, + 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, + 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, + 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, + 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, + 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, + 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, + 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, + 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, + 0x00U, 0x00U, 0x84U, 0x01U, 0x04U, 0x6EU, 0x61U, 0x6DU, 0x65U, 0x01U, + 0x7DU, 0x0BU, 0x00U, 0x0AU, 0x6CU, 0x65U, 0x64U, 0x67U, 0x65U, 0x72U, + 0x5FU, 0x73U, 0x65U, 0x71U, 0x01U, 0x06U, 0x61U, 0x63U, 0x63U, 0x65U, + 0x70U, 0x74U, 0x02U, 0x0CU, 0x65U, 0x74U, 0x78U, 0x6EU, 0x5FU, 0x72U, + 0x65U, 0x73U, 0x65U, 0x72U, 0x76U, 0x65U, 0x03U, 0x0CU, 0x68U, 0x6FU, + 0x6FU, 0x6BU, 0x5FU, 0x61U, 0x63U, 0x63U, 0x6FU, 0x75U, 0x6EU, 0x74U, + 0x04U, 0x0CU, 0x65U, 0x74U, 0x78U, 0x6EU, 0x5FU, 0x64U, 0x65U, 0x74U, + 0x61U, 0x69U, 0x6CU, 0x73U, 0x05U, 0x0DU, 0x65U, 0x74U, 0x78U, 0x6EU, + 0x5FU, 0x66U, 0x65U, 0x65U, 0x5FU, 0x62U, 0x61U, 0x73U, 0x65U, 0x06U, + 0x04U, 0x65U, 0x6DU, 0x69U, 0x74U, 0x07U, 0x08U, 0x72U, 0x6FU, 0x6CU, + 0x6CU, 0x62U, 0x61U, 0x63U, 0x6BU, 0x08U, 0x11U, 0x5FU, 0x5FU, 0x77U, + 0x61U, 0x73U, 0x6DU, 0x5FU, 0x63U, 0x61U, 0x6CU, 0x6CU, 0x5FU, 0x63U, + 0x74U, 0x6FU, 0x72U, 0x73U, 0x09U, 0x04U, 0x63U, 0x62U, 0x61U, 0x6BU, + 0x0AU, 0x04U, 0x68U, 0x6FU, 0x6FU, 0x6BU, 0x00U, 0x75U, 0x09U, 0x70U, + 0x72U, 0x6FU, 0x64U, 0x75U, 0x63U, 0x65U, 0x72U, 0x73U, 0x01U, 0x0CU, + 0x70U, 0x72U, 0x6FU, 0x63U, 0x65U, 0x73U, 0x73U, 0x65U, 0x64U, 0x2DU, + 0x62U, 0x79U, 0x01U, 0x05U, 0x63U, 0x6CU, 0x61U, 0x6EU, 0x67U, 0x55U, + 0x39U, 0x2EU, 0x30U, 0x2EU, 0x30U, 0x20U, 0x28U, 0x68U, 0x74U, 0x74U, + 0x70U, 0x73U, 0x3AU, 0x2FU, 0x2FU, 0x67U, 0x69U, 0x74U, 0x68U, 0x75U, + 0x62U, 0x2EU, 0x63U, 0x6FU, 0x6DU, 0x2FU, 0x6CU, 0x6CU, 0x76U, 0x6DU, + 0x2FU, 0x6CU, 0x6CU, 0x76U, 0x6DU, 0x2DU, 0x70U, 0x72U, 0x6FU, 0x6AU, + 0x65U, 0x63U, 0x74U, 0x20U, 0x30U, 0x33U, 0x39U, 0x39U, 0x64U, 0x35U, + 0x61U, 0x39U, 0x36U, 0x38U, 0x32U, 0x62U, 0x33U, 0x63U, 0x65U, 0x66U, + 0x37U, 0x31U, 0x63U, 0x36U, 0x35U, 0x33U, 0x33U, 0x37U, 0x33U, 0x65U, + 0x33U, 0x38U, 0x38U, 0x39U, 0x30U, 0x63U, 0x36U, 0x33U, 0x63U, 0x34U, + 0x63U, 0x33U, 0x36U, 0x35U, 0x29U, + }}, + + /* ==== WASM: 123 ==== */ + {R"[test.hook.gas]( + (module + (type (;0;) (func (param i32 i32 i64) (result i64))) + (type (;1;) (func (param i32) (result i64))) + (import "env" "accept" (func (;0;) (type 0))) + (import "env" "rollback" (func (;1;) (type 0))) + (func (;2;) (type 1) (param i32) (result i64) + ;; Grow memory from 1 page to 8 pages (7 page increase) + i32.const 7 + memory.grow + i32.const -1 + i32.eq + if (result i64) + ;; Should not happen + i32.const 0 + i32.const 0 + i64.const 1 + call 1 ;; rollback + else + ;; Success + i32.const 0 + i32.const 0 + i64.const 0 + call 0 ;; accept + end) + (memory (;0;) 1) + (export "memory" (memory 0)) + (export "hook" (func 2))) + )[test.hook.gas]", + { + 0x00U, 0x61U, 0x73U, 0x6DU, 0x01U, 0x00U, 0x00U, 0x00U, 0x01U, 0x0DU, + 0x02U, 0x60U, 0x03U, 0x7FU, 0x7FU, 0x7EU, 0x01U, 0x7EU, 0x60U, 0x01U, + 0x7FU, 0x01U, 0x7EU, 0x02U, 0x1DU, 0x02U, 0x03U, 0x65U, 0x6EU, 0x76U, + 0x06U, 0x61U, 0x63U, 0x63U, 0x65U, 0x70U, 0x74U, 0x00U, 0x00U, 0x03U, + 0x65U, 0x6EU, 0x76U, 0x08U, 0x72U, 0x6FU, 0x6CU, 0x6CU, 0x62U, 0x61U, + 0x63U, 0x6BU, 0x00U, 0x00U, 0x03U, 0x02U, 0x01U, 0x01U, 0x05U, 0x03U, + 0x01U, 0x00U, 0x01U, 0x07U, 0x11U, 0x02U, 0x06U, 0x6DU, 0x65U, 0x6DU, + 0x6FU, 0x72U, 0x79U, 0x02U, 0x00U, 0x04U, 0x68U, 0x6FU, 0x6FU, 0x6BU, + 0x00U, 0x02U, 0x0AU, 0x1FU, 0x01U, 0x1DU, 0x00U, 0x41U, 0x07U, 0x40U, + 0x00U, 0x41U, 0x7FU, 0x46U, 0x04U, 0x7EU, 0x41U, 0x00U, 0x41U, 0x00U, + 0x42U, 0x01U, 0x10U, 0x01U, 0x05U, 0x41U, 0x00U, 0x41U, 0x00U, 0x42U, + 0x00U, 0x10U, 0x00U, 0x0BU, 0x0BU, + }}, + + /* ==== WASM: 124 ==== */ + {R"[test.hook.gas]( + (module + (type (;0;) (func (param i32 i32 i64) (result i64))) + (type (;1;) (func (param i32) (result i64))) + (import "env" "accept" (func (;0;) (type 0))) + (import "env" "rollback" (func (;1;) (type 0))) + (func (;2;) (type 1) (param i32) (result i64) + ;; Try to grow memory from 1 page to 9 pages (8 page increase) + ;; This should fail because maxMemoryPage=8 + i32.const 8 + memory.grow + i32.const -1 + i32.eq + if (result i64) + ;; Expected failure + i32.const 0 + i32.const 0 + i64.const 0 + call 1 ;; rollback + else + ;; Should not happen + i32.const 0 + i32.const 0 + i64.const 1 + call 0 ;; accept + end) + (memory (;0;) 1) + (export "memory" (memory 0)) + (export "hook" (func 2))) + )[test.hook.gas]", + { + 0x00U, 0x61U, 0x73U, 0x6DU, 0x01U, 0x00U, 0x00U, 0x00U, 0x01U, 0x0DU, + 0x02U, 0x60U, 0x03U, 0x7FU, 0x7FU, 0x7EU, 0x01U, 0x7EU, 0x60U, 0x01U, + 0x7FU, 0x01U, 0x7EU, 0x02U, 0x1DU, 0x02U, 0x03U, 0x65U, 0x6EU, 0x76U, + 0x06U, 0x61U, 0x63U, 0x63U, 0x65U, 0x70U, 0x74U, 0x00U, 0x00U, 0x03U, + 0x65U, 0x6EU, 0x76U, 0x08U, 0x72U, 0x6FU, 0x6CU, 0x6CU, 0x62U, 0x61U, + 0x63U, 0x6BU, 0x00U, 0x00U, 0x03U, 0x02U, 0x01U, 0x01U, 0x05U, 0x03U, + 0x01U, 0x00U, 0x01U, 0x07U, 0x11U, 0x02U, 0x06U, 0x6DU, 0x65U, 0x6DU, + 0x6FU, 0x72U, 0x79U, 0x02U, 0x00U, 0x04U, 0x68U, 0x6FU, 0x6FU, 0x6BU, + 0x00U, 0x02U, 0x0AU, 0x1FU, 0x01U, 0x1DU, 0x00U, 0x41U, 0x08U, 0x40U, + 0x00U, 0x41U, 0x7FU, 0x46U, 0x04U, 0x7EU, 0x41U, 0x00U, 0x41U, 0x00U, + 0x42U, 0x00U, 0x10U, 0x01U, 0x05U, 0x41U, 0x00U, 0x41U, 0x00U, 0x42U, + 0x01U, 0x10U, 0x00U, 0x0BU, 0x0BU, + }}, + + /* ==== WASM: 125 ==== */ + {R"[test.hook.gas]( + #include + extern int64_t accept (uint32_t read_ptr, uint32_t read_len, int64_t error_code); + int64_t hook(uint32_t reserved ) + { + return accept(0,0,0); + } + )[test.hook.gas]", + { + 0x00U, 0x61U, 0x73U, 0x6DU, 0x01U, 0x00U, 0x00U, 0x00U, 0x01U, 0x10U, + 0x03U, 0x60U, 0x03U, 0x7FU, 0x7FU, 0x7EU, 0x01U, 0x7EU, 0x60U, 0x00U, + 0x00U, 0x60U, 0x01U, 0x7FU, 0x01U, 0x7EU, 0x02U, 0x0EU, 0x01U, 0x03U, + 0x65U, 0x6EU, 0x76U, 0x06U, 0x61U, 0x63U, 0x63U, 0x65U, 0x70U, 0x74U, + 0x00U, 0x00U, 0x03U, 0x03U, 0x02U, 0x01U, 0x02U, 0x04U, 0x05U, 0x01U, + 0x70U, 0x01U, 0x01U, 0x01U, 0x05U, 0x03U, 0x01U, 0x00U, 0x02U, 0x06U, + 0x21U, 0x05U, 0x7FU, 0x01U, 0x41U, 0x80U, 0x88U, 0x04U, 0x0BU, 0x7FU, + 0x00U, 0x41U, 0x80U, 0x08U, 0x0BU, 0x7FU, 0x00U, 0x41U, 0x80U, 0x08U, + 0x0BU, 0x7FU, 0x00U, 0x41U, 0x80U, 0x88U, 0x04U, 0x0BU, 0x7FU, 0x00U, + 0x41U, 0x80U, 0x08U, 0x0BU, 0x07U, 0x5FU, 0x07U, 0x06U, 0x6DU, 0x65U, + 0x6DU, 0x6FU, 0x72U, 0x79U, 0x02U, 0x00U, 0x11U, 0x5FU, 0x5FU, 0x77U, + 0x61U, 0x73U, 0x6DU, 0x5FU, 0x63U, 0x61U, 0x6CU, 0x6CU, 0x5FU, 0x63U, + 0x74U, 0x6FU, 0x72U, 0x73U, 0x00U, 0x01U, 0x0AU, 0x5FU, 0x5FU, 0x64U, + 0x61U, 0x74U, 0x61U, 0x5FU, 0x65U, 0x6EU, 0x64U, 0x03U, 0x01U, 0x0DU, + 0x5FU, 0x5FU, 0x67U, 0x6CU, 0x6FU, 0x62U, 0x61U, 0x6CU, 0x5FU, 0x62U, + 0x61U, 0x73U, 0x65U, 0x03U, 0x02U, 0x0BU, 0x5FU, 0x5FU, 0x68U, 0x65U, + 0x61U, 0x70U, 0x5FU, 0x62U, 0x61U, 0x73U, 0x65U, 0x03U, 0x03U, 0x0CU, + 0x5FU, 0x5FU, 0x64U, 0x73U, 0x6FU, 0x5FU, 0x68U, 0x61U, 0x6EU, 0x64U, + 0x6CU, 0x65U, 0x03U, 0x04U, 0x04U, 0x68U, 0x6FU, 0x6FU, 0x6BU, 0x00U, + 0x02U, 0x0AU, 0x13U, 0x02U, 0x02U, 0x00U, 0x0BU, 0x0EU, 0x00U, 0x41U, + 0x00U, 0x41U, 0x00U, 0x42U, 0x00U, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x0BU, 0x00U, 0x29U, 0x04U, 0x6EU, 0x61U, 0x6DU, 0x65U, 0x01U, + 0x22U, 0x03U, 0x00U, 0x06U, 0x61U, 0x63U, 0x63U, 0x65U, 0x70U, 0x74U, + 0x01U, 0x11U, 0x5FU, 0x5FU, 0x77U, 0x61U, 0x73U, 0x6DU, 0x5FU, 0x63U, + 0x61U, 0x6CU, 0x6CU, 0x5FU, 0x63U, 0x74U, 0x6FU, 0x72U, 0x73U, 0x02U, + 0x04U, 0x68U, 0x6FU, 0x6FU, 0x6BU, 0x00U, 0x75U, 0x09U, 0x70U, 0x72U, + 0x6FU, 0x64U, 0x75U, 0x63U, 0x65U, 0x72U, 0x73U, 0x01U, 0x0CU, 0x70U, + 0x72U, 0x6FU, 0x63U, 0x65U, 0x73U, 0x73U, 0x65U, 0x64U, 0x2DU, 0x62U, + 0x79U, 0x01U, 0x05U, 0x63U, 0x6CU, 0x61U, 0x6EU, 0x67U, 0x55U, 0x39U, + 0x2EU, 0x30U, 0x2EU, 0x30U, 0x20U, 0x28U, 0x68U, 0x74U, 0x74U, 0x70U, + 0x73U, 0x3AU, 0x2FU, 0x2FU, 0x67U, 0x69U, 0x74U, 0x68U, 0x75U, 0x62U, + 0x2EU, 0x63U, 0x6FU, 0x6DU, 0x2FU, 0x6CU, 0x6CU, 0x76U, 0x6DU, 0x2FU, + 0x6CU, 0x6CU, 0x76U, 0x6DU, 0x2DU, 0x70U, 0x72U, 0x6FU, 0x6AU, 0x65U, + 0x63U, 0x74U, 0x20U, 0x30U, 0x33U, 0x39U, 0x39U, 0x64U, 0x35U, 0x61U, + 0x39U, 0x36U, 0x38U, 0x32U, 0x62U, 0x33U, 0x63U, 0x65U, 0x66U, 0x37U, + 0x31U, 0x63U, 0x36U, 0x35U, 0x33U, 0x33U, 0x37U, 0x33U, 0x65U, 0x33U, + 0x38U, 0x38U, 0x39U, 0x30U, 0x63U, 0x36U, 0x33U, 0x63U, 0x34U, 0x63U, + 0x33U, 0x36U, 0x35U, 0x29U, + }}, + + /* ==== WASM: 126 ==== */ + {R"[test.hook.gas]( + #include + extern int64_t accept (uint32_t read_ptr, uint32_t read_len, int64_t error_code); + int64_t cbak(uint32_t reserved ) + { + return accept(0,0,0); + } + int64_t hook(uint32_t reserved ) + { + return accept(0,0,0); + } + )[test.hook.gas]", + { + 0x00U, 0x61U, 0x73U, 0x6DU, 0x01U, 0x00U, 0x00U, 0x00U, 0x01U, 0x10U, + 0x03U, 0x60U, 0x03U, 0x7FU, 0x7FU, 0x7EU, 0x01U, 0x7EU, 0x60U, 0x00U, + 0x00U, 0x60U, 0x01U, 0x7FU, 0x01U, 0x7EU, 0x02U, 0x0EU, 0x01U, 0x03U, + 0x65U, 0x6EU, 0x76U, 0x06U, 0x61U, 0x63U, 0x63U, 0x65U, 0x70U, 0x74U, + 0x00U, 0x00U, 0x03U, 0x04U, 0x03U, 0x01U, 0x02U, 0x02U, 0x04U, 0x05U, + 0x01U, 0x70U, 0x01U, 0x01U, 0x01U, 0x05U, 0x03U, 0x01U, 0x00U, 0x02U, + 0x06U, 0x21U, 0x05U, 0x7FU, 0x01U, 0x41U, 0x80U, 0x88U, 0x04U, 0x0BU, + 0x7FU, 0x00U, 0x41U, 0x80U, 0x08U, 0x0BU, 0x7FU, 0x00U, 0x41U, 0x80U, + 0x08U, 0x0BU, 0x7FU, 0x00U, 0x41U, 0x80U, 0x88U, 0x04U, 0x0BU, 0x7FU, + 0x00U, 0x41U, 0x80U, 0x08U, 0x0BU, 0x07U, 0x66U, 0x08U, 0x06U, 0x6DU, + 0x65U, 0x6DU, 0x6FU, 0x72U, 0x79U, 0x02U, 0x00U, 0x11U, 0x5FU, 0x5FU, + 0x77U, 0x61U, 0x73U, 0x6DU, 0x5FU, 0x63U, 0x61U, 0x6CU, 0x6CU, 0x5FU, + 0x63U, 0x74U, 0x6FU, 0x72U, 0x73U, 0x00U, 0x01U, 0x0AU, 0x5FU, 0x5FU, + 0x64U, 0x61U, 0x74U, 0x61U, 0x5FU, 0x65U, 0x6EU, 0x64U, 0x03U, 0x01U, + 0x0DU, 0x5FU, 0x5FU, 0x67U, 0x6CU, 0x6FU, 0x62U, 0x61U, 0x6CU, 0x5FU, + 0x62U, 0x61U, 0x73U, 0x65U, 0x03U, 0x02U, 0x0BU, 0x5FU, 0x5FU, 0x68U, + 0x65U, 0x61U, 0x70U, 0x5FU, 0x62U, 0x61U, 0x73U, 0x65U, 0x03U, 0x03U, + 0x0CU, 0x5FU, 0x5FU, 0x64U, 0x73U, 0x6FU, 0x5FU, 0x68U, 0x61U, 0x6EU, + 0x64U, 0x6CU, 0x65U, 0x03U, 0x04U, 0x04U, 0x63U, 0x62U, 0x61U, 0x6BU, + 0x00U, 0x02U, 0x04U, 0x68U, 0x6FU, 0x6FU, 0x6BU, 0x00U, 0x03U, 0x0AU, + 0x22U, 0x03U, 0x02U, 0x00U, 0x0BU, 0x0EU, 0x00U, 0x41U, 0x00U, 0x41U, + 0x00U, 0x42U, 0x00U, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x0BU, + 0x0EU, 0x00U, 0x41U, 0x00U, 0x41U, 0x00U, 0x42U, 0x00U, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x0BU, 0x00U, 0x2FU, 0x04U, 0x6EU, 0x61U, + 0x6DU, 0x65U, 0x01U, 0x28U, 0x04U, 0x00U, 0x06U, 0x61U, 0x63U, 0x63U, + 0x65U, 0x70U, 0x74U, 0x01U, 0x11U, 0x5FU, 0x5FU, 0x77U, 0x61U, 0x73U, + 0x6DU, 0x5FU, 0x63U, 0x61U, 0x6CU, 0x6CU, 0x5FU, 0x63U, 0x74U, 0x6FU, + 0x72U, 0x73U, 0x02U, 0x04U, 0x63U, 0x62U, 0x61U, 0x6BU, 0x03U, 0x04U, + 0x68U, 0x6FU, 0x6FU, 0x6BU, 0x00U, 0x75U, 0x09U, 0x70U, 0x72U, 0x6FU, + 0x64U, 0x75U, 0x63U, 0x65U, 0x72U, 0x73U, 0x01U, 0x0CU, 0x70U, 0x72U, + 0x6FU, 0x63U, 0x65U, 0x73U, 0x73U, 0x65U, 0x64U, 0x2DU, 0x62U, 0x79U, + 0x01U, 0x05U, 0x63U, 0x6CU, 0x61U, 0x6EU, 0x67U, 0x55U, 0x39U, 0x2EU, + 0x30U, 0x2EU, 0x30U, 0x20U, 0x28U, 0x68U, 0x74U, 0x74U, 0x70U, 0x73U, + 0x3AU, 0x2FU, 0x2FU, 0x67U, 0x69U, 0x74U, 0x68U, 0x75U, 0x62U, 0x2EU, + 0x63U, 0x6FU, 0x6DU, 0x2FU, 0x6CU, 0x6CU, 0x76U, 0x6DU, 0x2FU, 0x6CU, + 0x6CU, 0x76U, 0x6DU, 0x2DU, 0x70U, 0x72U, 0x6FU, 0x6AU, 0x65U, 0x63U, + 0x74U, 0x20U, 0x30U, 0x33U, 0x39U, 0x39U, 0x64U, 0x35U, 0x61U, 0x39U, + 0x36U, 0x38U, 0x32U, 0x62U, 0x33U, 0x63U, 0x65U, 0x66U, 0x37U, 0x31U, + 0x63U, 0x36U, 0x35U, 0x33U, 0x33U, 0x37U, 0x33U, 0x65U, 0x33U, 0x38U, + 0x38U, 0x39U, 0x30U, 0x63U, 0x36U, 0x33U, 0x63U, 0x34U, 0x63U, 0x33U, + 0x36U, 0x35U, 0x29U, + }}, + + /* ==== WASM: 127 ==== */ + {R"[test.hook.gas]( + #include + extern int32_t _g (uint32_t id, uint32_t maxiter); + extern int64_t accept (uint32_t read_ptr, uint32_t read_len, int64_t error_code); + int64_t hook(uint32_t reserved ) + { + _g(1,1); + return accept(0,0,0); + } + )[test.hook.gas]", + { + 0x00U, 0x61U, 0x73U, 0x6DU, 0x01U, 0x00U, 0x00U, 0x00U, 0x01U, 0x16U, + 0x04U, 0x60U, 0x02U, 0x7FU, 0x7FU, 0x01U, 0x7FU, 0x60U, 0x03U, 0x7FU, + 0x7FU, 0x7EU, 0x01U, 0x7EU, 0x60U, 0x00U, 0x00U, 0x60U, 0x01U, 0x7FU, + 0x01U, 0x7EU, 0x02U, 0x17U, 0x02U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x02U, + 0x5FU, 0x67U, 0x00U, 0x00U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x06U, 0x61U, + 0x63U, 0x63U, 0x65U, 0x70U, 0x74U, 0x00U, 0x01U, 0x03U, 0x03U, 0x02U, + 0x02U, 0x03U, 0x04U, 0x05U, 0x01U, 0x70U, 0x01U, 0x01U, 0x01U, 0x05U, + 0x03U, 0x01U, 0x00U, 0x02U, 0x06U, 0x21U, 0x05U, 0x7FU, 0x01U, 0x41U, + 0x80U, 0x88U, 0x04U, 0x0BU, 0x7FU, 0x00U, 0x41U, 0x80U, 0x08U, 0x0BU, + 0x7FU, 0x00U, 0x41U, 0x80U, 0x08U, 0x0BU, 0x7FU, 0x00U, 0x41U, 0x80U, + 0x88U, 0x04U, 0x0BU, 0x7FU, 0x00U, 0x41U, 0x80U, 0x08U, 0x0BU, 0x07U, + 0x5FU, 0x07U, 0x06U, 0x6DU, 0x65U, 0x6DU, 0x6FU, 0x72U, 0x79U, 0x02U, + 0x00U, 0x11U, 0x5FU, 0x5FU, 0x77U, 0x61U, 0x73U, 0x6DU, 0x5FU, 0x63U, + 0x61U, 0x6CU, 0x6CU, 0x5FU, 0x63U, 0x74U, 0x6FU, 0x72U, 0x73U, 0x00U, + 0x02U, 0x0AU, 0x5FU, 0x5FU, 0x64U, 0x61U, 0x74U, 0x61U, 0x5FU, 0x65U, + 0x6EU, 0x64U, 0x03U, 0x01U, 0x0DU, 0x5FU, 0x5FU, 0x67U, 0x6CU, 0x6FU, + 0x62U, 0x61U, 0x6CU, 0x5FU, 0x62U, 0x61U, 0x73U, 0x65U, 0x03U, 0x02U, + 0x0BU, 0x5FU, 0x5FU, 0x68U, 0x65U, 0x61U, 0x70U, 0x5FU, 0x62U, 0x61U, + 0x73U, 0x65U, 0x03U, 0x03U, 0x0CU, 0x5FU, 0x5FU, 0x64U, 0x73U, 0x6FU, + 0x5FU, 0x68U, 0x61U, 0x6EU, 0x64U, 0x6CU, 0x65U, 0x03U, 0x04U, 0x04U, + 0x68U, 0x6FU, 0x6FU, 0x6BU, 0x00U, 0x03U, 0x0AU, 0x1EU, 0x02U, 0x02U, + 0x00U, 0x0BU, 0x19U, 0x00U, 0x41U, 0x01U, 0x41U, 0x01U, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x41U, 0x00U, 0x41U, 0x00U, 0x42U, + 0x00U, 0x10U, 0x81U, 0x80U, 0x80U, 0x80U, 0x00U, 0x0BU, 0x00U, 0x2DU, + 0x04U, 0x6EU, 0x61U, 0x6DU, 0x65U, 0x01U, 0x26U, 0x04U, 0x00U, 0x02U, + 0x5FU, 0x67U, 0x01U, 0x06U, 0x61U, 0x63U, 0x63U, 0x65U, 0x70U, 0x74U, + 0x02U, 0x11U, 0x5FU, 0x5FU, 0x77U, 0x61U, 0x73U, 0x6DU, 0x5FU, 0x63U, + 0x61U, 0x6CU, 0x6CU, 0x5FU, 0x63U, 0x74U, 0x6FU, 0x72U, 0x73U, 0x03U, + 0x04U, 0x68U, 0x6FU, 0x6FU, 0x6BU, 0x00U, 0x75U, 0x09U, 0x70U, 0x72U, + 0x6FU, 0x64U, 0x75U, 0x63U, 0x65U, 0x72U, 0x73U, 0x01U, 0x0CU, 0x70U, + 0x72U, 0x6FU, 0x63U, 0x65U, 0x73U, 0x73U, 0x65U, 0x64U, 0x2DU, 0x62U, + 0x79U, 0x01U, 0x05U, 0x63U, 0x6CU, 0x61U, 0x6EU, 0x67U, 0x55U, 0x39U, + 0x2EU, 0x30U, 0x2EU, 0x30U, 0x20U, 0x28U, 0x68U, 0x74U, 0x74U, 0x70U, + 0x73U, 0x3AU, 0x2FU, 0x2FU, 0x67U, 0x69U, 0x74U, 0x68U, 0x75U, 0x62U, + 0x2EU, 0x63U, 0x6FU, 0x6DU, 0x2FU, 0x6CU, 0x6CU, 0x76U, 0x6DU, 0x2FU, + 0x6CU, 0x6CU, 0x76U, 0x6DU, 0x2DU, 0x70U, 0x72U, 0x6FU, 0x6AU, 0x65U, + 0x63U, 0x74U, 0x20U, 0x30U, 0x33U, 0x39U, 0x39U, 0x64U, 0x35U, 0x61U, + 0x39U, 0x36U, 0x38U, 0x32U, 0x62U, 0x33U, 0x63U, 0x65U, 0x66U, 0x37U, + 0x31U, 0x63U, 0x36U, 0x35U, 0x33U, 0x33U, 0x37U, 0x33U, 0x65U, 0x33U, + 0x38U, 0x38U, 0x39U, 0x30U, 0x63U, 0x36U, 0x33U, 0x63U, 0x34U, 0x63U, + 0x33U, 0x36U, 0x35U, 0x29U, + }}, + + /* ==== WASM: 128 ==== */ + {R"[test.hook.gas]( + #include + extern int64_t accept (uint32_t read_ptr, uint32_t read_len, int64_t error_code); + extern int64_t float_one(); + #define SBUF(x) (uint32_t)(x), sizeof(x) + #define M_REPEAT_10(X) X X X X X X X X X X + #define M_REPEAT_100(X) M_REPEAT_10(M_REPEAT_10(X)) + #define M_REPEAT_1000(X) M_REPEAT_100(M_REPEAT_10(X)) + int64_t hook(uint32_t reserved ) + { + M_REPEAT_1000(float_one();); + return accept(0, 0, 0); + } + )[test.hook.gas]", + { + 0x00U, 0x61U, 0x73U, 0x6DU, 0x01U, 0x00U, 0x00U, 0x00U, 0x01U, 0x14U, + 0x04U, 0x60U, 0x00U, 0x01U, 0x7EU, 0x60U, 0x03U, 0x7FU, 0x7FU, 0x7EU, + 0x01U, 0x7EU, 0x60U, 0x00U, 0x00U, 0x60U, 0x01U, 0x7FU, 0x01U, 0x7EU, + 0x02U, 0x1EU, 0x02U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x09U, 0x66U, 0x6CU, + 0x6FU, 0x61U, 0x74U, 0x5FU, 0x6FU, 0x6EU, 0x65U, 0x00U, 0x00U, 0x03U, + 0x65U, 0x6EU, 0x76U, 0x06U, 0x61U, 0x63U, 0x63U, 0x65U, 0x70U, 0x74U, + 0x00U, 0x01U, 0x03U, 0x03U, 0x02U, 0x02U, 0x03U, 0x04U, 0x05U, 0x01U, + 0x70U, 0x01U, 0x01U, 0x01U, 0x05U, 0x03U, 0x01U, 0x00U, 0x02U, 0x06U, + 0x21U, 0x05U, 0x7FU, 0x01U, 0x41U, 0x80U, 0x88U, 0x04U, 0x0BU, 0x7FU, + 0x00U, 0x41U, 0x80U, 0x08U, 0x0BU, 0x7FU, 0x00U, 0x41U, 0x80U, 0x08U, + 0x0BU, 0x7FU, 0x00U, 0x41U, 0x80U, 0x88U, 0x04U, 0x0BU, 0x7FU, 0x00U, + 0x41U, 0x80U, 0x08U, 0x0BU, 0x07U, 0x5FU, 0x07U, 0x06U, 0x6DU, 0x65U, + 0x6DU, 0x6FU, 0x72U, 0x79U, 0x02U, 0x00U, 0x11U, 0x5FU, 0x5FU, 0x77U, + 0x61U, 0x73U, 0x6DU, 0x5FU, 0x63U, 0x61U, 0x6CU, 0x6CU, 0x5FU, 0x63U, + 0x74U, 0x6FU, 0x72U, 0x73U, 0x00U, 0x02U, 0x0AU, 0x5FU, 0x5FU, 0x64U, + 0x61U, 0x74U, 0x61U, 0x5FU, 0x65U, 0x6EU, 0x64U, 0x03U, 0x01U, 0x0DU, + 0x5FU, 0x5FU, 0x67U, 0x6CU, 0x6FU, 0x62U, 0x61U, 0x6CU, 0x5FU, 0x62U, + 0x61U, 0x73U, 0x65U, 0x03U, 0x02U, 0x0BU, 0x5FU, 0x5FU, 0x68U, 0x65U, + 0x61U, 0x70U, 0x5FU, 0x62U, 0x61U, 0x73U, 0x65U, 0x03U, 0x03U, 0x0CU, + 0x5FU, 0x5FU, 0x64U, 0x73U, 0x6FU, 0x5FU, 0x68U, 0x61U, 0x6EU, 0x64U, + 0x6CU, 0x65U, 0x03U, 0x04U, 0x04U, 0x68U, 0x6FU, 0x6FU, 0x6BU, 0x00U, + 0x03U, 0x0AU, 0xECU, 0x36U, 0x02U, 0x02U, 0x00U, 0x0BU, 0xE6U, 0x36U, + 0x00U, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, + 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, + 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, + 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, + 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, + 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x1AU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, + 0x1AU, 0x41U, 0x00U, 0x41U, 0x00U, 0x42U, 0x00U, 0x10U, 0x81U, 0x80U, + 0x80U, 0x80U, 0x00U, 0x0BU, 0x00U, 0x34U, 0x04U, 0x6EU, 0x61U, 0x6DU, + 0x65U, 0x01U, 0x2DU, 0x04U, 0x00U, 0x09U, 0x66U, 0x6CU, 0x6FU, 0x61U, + 0x74U, 0x5FU, 0x6FU, 0x6EU, 0x65U, 0x01U, 0x06U, 0x61U, 0x63U, 0x63U, + 0x65U, 0x70U, 0x74U, 0x02U, 0x11U, 0x5FU, 0x5FU, 0x77U, 0x61U, 0x73U, + 0x6DU, 0x5FU, 0x63U, 0x61U, 0x6CU, 0x6CU, 0x5FU, 0x63U, 0x74U, 0x6FU, + 0x72U, 0x73U, 0x03U, 0x04U, 0x68U, 0x6FU, 0x6FU, 0x6BU, 0x00U, 0x75U, + 0x09U, 0x70U, 0x72U, 0x6FU, 0x64U, 0x75U, 0x63U, 0x65U, 0x72U, 0x73U, + 0x01U, 0x0CU, 0x70U, 0x72U, 0x6FU, 0x63U, 0x65U, 0x73U, 0x73U, 0x65U, + 0x64U, 0x2DU, 0x62U, 0x79U, 0x01U, 0x05U, 0x63U, 0x6CU, 0x61U, 0x6EU, + 0x67U, 0x55U, 0x39U, 0x2EU, 0x30U, 0x2EU, 0x30U, 0x20U, 0x28U, 0x68U, + 0x74U, 0x74U, 0x70U, 0x73U, 0x3AU, 0x2FU, 0x2FU, 0x67U, 0x69U, 0x74U, + 0x68U, 0x75U, 0x62U, 0x2EU, 0x63U, 0x6FU, 0x6DU, 0x2FU, 0x6CU, 0x6CU, + 0x76U, 0x6DU, 0x2FU, 0x6CU, 0x6CU, 0x76U, 0x6DU, 0x2DU, 0x70U, 0x72U, + 0x6FU, 0x6AU, 0x65U, 0x63U, 0x74U, 0x20U, 0x30U, 0x33U, 0x39U, 0x39U, + 0x64U, 0x35U, 0x61U, 0x39U, 0x36U, 0x38U, 0x32U, 0x62U, 0x33U, 0x63U, + 0x65U, 0x66U, 0x37U, 0x31U, 0x63U, 0x36U, 0x35U, 0x33U, 0x33U, 0x37U, + 0x33U, 0x65U, 0x33U, 0x38U, 0x38U, 0x39U, 0x30U, 0x63U, 0x36U, 0x33U, + 0x63U, 0x34U, 0x63U, 0x33U, 0x36U, 0x35U, 0x29U, + }}, + }; } } // namespace ripple diff --git a/src/test/app/build_test_hooks.sh b/src/test/app/build_test_hooks.sh index 4e57701a88..ecc72c97bc 100755 --- a/src/test/app/build_test_hooks.sh +++ b/src/test/app/build_test_hooks.sh @@ -41,17 +41,28 @@ echo ' namespace ripple { namespace test { std::map> wasm = {' > $OUTPUT_FILE -COUNTER="0" -cat $INPUT_FILE | tr '\n' '\f' | - grep -Po 'R"\[test\.hook\](.*?)\[test\.hook\]"' | - sed -E 's/R"\[test\.hook\]\(//g' | - sed -E 's/\)\[test\.hook\]"[\f \t]*/\/*end*\//g' | +# Counter file for sharing between subshells +COUNTER_FILE=$(mktemp) +echo "0" > $COUNTER_FILE +trap "rm -f $COUNTER_FILE" EXIT + +# Process both [test.hook] and [test.hook.gas] blocks +process_block() { + local tag_pattern="$1" # regex pattern: "hook" or "hook\.gas" + local tag_output="$2" # output string: "hook" or "hook.gas" + local skip_cleaner="$3" # "0" for no skip, "1" for skip + + cat $INPUT_FILE | tr '\n' '\f' | + grep -Po "R\"\[test\.${tag_pattern}\](.*?)\[test\.${tag_pattern}\]\"" | + sed -E "s/R\"\[test\.${tag_pattern}\]\(//g" | + sed -E "s/\)\[test\.${tag_pattern}\]\"[\f \t]*/\/*end*\//g" | while read -r line do + COUNTER=$(cat $COUNTER_FILE) echo "/* ==== WASM: $COUNTER ==== */" >> $OUTPUT_FILE - echo -n '{ R"[test.hook](' >> $OUTPUT_FILE + echo -n "{ R\"[test.${tag_output}](" >> $OUTPUT_FILE cat <<< "$line" | sed -E 's/.{7}$//g' | tr -d '\n' | tr '\f' '\n' >> $OUTPUT_FILE - echo ')[test.hook]",' >> $OUTPUT_FILE + echo ")[test.${tag_output}]\"," >> $OUTPUT_FILE echo "{" >> $OUTPUT_FILE WAT=`grep -Eo '\(module' <<< $line | wc -l` if [ "$WAT" -eq "0" ] @@ -69,10 +80,19 @@ cat $INPUT_FILE | tr '\n' '\f' | echo "$line" exit 1 fi - wasmcc -x c /dev/stdin -o /dev/stdout -O2 -Wl,--allow-undefined <<< "`tr '\f' '\n' <<< $line`" | - hook-cleaner - - 2>/dev/null | - xxd -p -u -c 10 | - sed -E 's/../0x&U,/g' | sed -E 's/^/ /g' >> $OUTPUT_FILE + if [ "$skip_cleaner" -eq "1" ] + then + # Skip hook-cleaner for [test.hook.gas] + wasmcc -x c /dev/stdin -o /dev/stdout -O2 -Wl,--allow-undefined -Wno-int-conversion -Wno-pointer-sign -Wno-return-type <<< "`tr '\f' '\n' <<< $line`" | + xxd -p -u -c 10 | + sed -E 's/../0x&U,/g' | sed -E 's/^/ /g' >> $OUTPUT_FILE + else + # Run hook-cleaner for [test.hook] + wasmcc -x c /dev/stdin -o /dev/stdout -O2 -Wl,--allow-undefined -Wno-int-conversion -Wno-pointer-sign -Wno-return-type <<< "`tr '\f' '\n' <<< $line`" | + hook-cleaner - - 2>/dev/null | + xxd -p -u -c 10 | + sed -E 's/../0x&U,/g' | sed -E 's/^/ /g' >> $OUTPUT_FILE + fi else wat2wasm - -o /dev/stdout <<< "`tr '\f' '\n' <<< $(sed -E 's/.{7}$//g' <<< $line)`" | xxd -p -u -c 10 | @@ -85,8 +105,15 @@ cat $INPUT_FILE | tr '\n' '\f' | fi echo '}},' >> $OUTPUT_FILE echo >> $OUTPUT_FILE - COUNTER=`echo $COUNTER + 1 | bc` + echo $((COUNTER + 1)) > $COUNTER_FILE done +} + +# Process [test.hook] blocks (with hook-cleaner) +process_block "hook" "hook" "0" + +# Process [test.hook.gas] blocks (without hook-cleaner) +process_block "hook\.gas" "hook.gas" "1" echo '}; } } diff --git a/src/test/jtx/hookgas.h b/src/test/jtx/hookgas.h new file mode 100644 index 0000000000..4ed31b44d7 --- /dev/null +++ b/src/test/jtx/hookgas.h @@ -0,0 +1,80 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2025 XRPL Labs + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_TEST_JTX_HOOKGAS_H_INCLUDED +#define RIPPLE_TEST_JTX_HOOKGAS_H_INCLUDED + +#include +#include +#include + +namespace ripple { +namespace test { +namespace jtx { + +/** Set the HookGas on a JTx. */ +class hookgas +{ +private: + std::uint32_t gas_; + +public: + hookgas(std::uint32_t gas) : gas_{gas} + { + } + + void + operator()(Env&, JTx& jt) const; +}; + +/** Set the HookCallbackGas on a JTx. */ +class cbakgas +{ +private: + std::uint32_t gas_; + +public: + cbakgas(std::uint32_t gas) : gas_{gas} + { + } + + void + operator()(Env&, JTx& jt) const; +}; + +/** Set the HookWeakGas on a JTx. */ +class weakgas +{ +private: + std::uint32_t gas_; + +public: + weakgas(std::uint32_t gas) : gas_{gas} + { + } + + void + operator()(Env&, JTx& jt) const; +}; + +} // namespace jtx +} // namespace test +} // namespace ripple + +#endif diff --git a/src/test/jtx/impl/hookgas.cpp b/src/test/jtx/impl/hookgas.cpp new file mode 100644 index 0000000000..f751f18eaf --- /dev/null +++ b/src/test/jtx/impl/hookgas.cpp @@ -0,0 +1,47 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2025 XRPL Labs + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include +#include + +namespace ripple { +namespace test { +namespace jtx { + +void +hookgas::operator()(Env&, JTx& jt) const +{ + jt[sfHookGas.jsonName] = gas_; +} + +void +cbakgas::operator()(Env&, JTx& jt) const +{ + jt[sfHookCallbackGas.jsonName] = gas_; +} + +void +weakgas::operator()(Env&, JTx& jt) const +{ + jt[sfHookWeakGas.jsonName] = gas_; +} + +} // namespace jtx +} // namespace test +} // namespace ripple