#ifndef APPLY_HOOK_INCLUDED #define APPLY_HOOK_INCLUDED 1 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace hook { struct HookContext; struct HookResult; bool isEmittedTxn(ripple::STTx const& tx); // This map type acts as both a read and write cache for hook execution // and is preserved across the execution of the set of hook chains // being executed in the current transaction. It is committed to lgr // only upon tesSuccess for the otxn. using HookStateMap = std::map< ripple::AccountID, // account that owns the state std::pair< int64_t, // remaining available ownercount std::map>>>>; // the value using namespace ripple; static const std::map TSHAllowances = { {ttPAYMENT, tshROLLBACK }, {ttESCROW_CREATE, tshROLLBACK }, {ttESCROW_FINISH, tshROLLBACK }, {ttACCOUNT_SET, tshNONE }, {ttESCROW_CANCEL, tshCOLLECT }, {ttREGULAR_KEY_SET, tshROLLBACK }, {ttOFFER_CREATE, tshCOLLECT }, {ttOFFER_CANCEL, tshNONE }, {ttTICKET_CREATE, tshNONE }, {ttSIGNER_LIST_SET, tshROLLBACK }, {ttPAYCHAN_CREATE, tshROLLBACK }, {ttPAYCHAN_FUND, tshCOLLECT }, {ttPAYCHAN_CLAIM, tshCOLLECT }, {ttCHECK_CREATE, tshROLLBACK }, {ttCHECK_CASH, tshROLLBACK }, {ttCHECK_CANCEL, tshCOLLECT }, {ttDEPOSIT_PREAUTH, tshROLLBACK }, {ttTRUST_SET, tshCOLLECT }, {ttACCOUNT_DELETE, tshROLLBACK }, {ttHOOK_SET, tshNONE }, {ttNFTOKEN_MINT, tshROLLBACK }, {ttNFTOKEN_BURN, tshCOLLECT }, {ttNFTOKEN_CREATE_OFFER, tshROLLBACK }, {ttNFTOKEN_CANCEL_OFFER, tshCOLLECT }, {ttNFTOKEN_ACCEPT_OFFER, tshROLLBACK }, {ttCLAIM_REWARD, tshROLLBACK } }; std::vector> getTransactionalStakeHolders(STTx const& tx, ReadView const& rv); } namespace hook_api { #define TER_TO_HOOK_RETURN_CODE(x)\ (((TERtoInt(x)) << 16)*-1) // for debugging if you want a lot of output change to 1 #define HOOK_DBG 0 #define DBG_PRINTF if (HOOK_DBG) printf #define DBG_FPRINTF if (HOOK_DBG) fprintf DECLARE_HOOK_FUNCTION(int32_t, _g, uint32_t guard_id, uint32_t maxiter ); DECLARE_HOOK_FUNCTION(int64_t, accept, uint32_t read_ptr, uint32_t read_len, int64_t error_code ); DECLARE_HOOK_FUNCTION(int64_t, rollback, uint32_t read_ptr, uint32_t read_len, int64_t error_code ); DECLARE_HOOK_FUNCTION(int64_t, util_raddr, uint32_t write_ptr, uint32_t write_len, uint32_t read_ptr, uint32_t read_len ); DECLARE_HOOK_FUNCTION(int64_t, util_accid, uint32_t write_ptr, uint32_t write_len, uint32_t read_ptr, uint32_t read_len ); DECLARE_HOOK_FUNCTION(int64_t, util_verify, uint32_t dread_ptr, uint32_t dread_len, uint32_t sread_ptr, uint32_t sread_len, uint32_t kread_ptr, uint32_t kread_len ); DECLARE_HOOK_FUNCTION(int64_t, sto_validate, uint32_t tread_ptr, uint32_t tread_len ); DECLARE_HOOK_FUNCTION(int64_t, sto_subfield, uint32_t read_ptr, uint32_t read_len, uint32_t field_id ); DECLARE_HOOK_FUNCTION(int64_t, sto_subarray, uint32_t read_ptr, uint32_t read_len, uint32_t array_id ); DECLARE_HOOK_FUNCTION(int64_t, sto_emplace, uint32_t write_ptr, uint32_t write_len, uint32_t sread_ptr, uint32_t sread_len, uint32_t fread_ptr, uint32_t fread_len, uint32_t field_id ); DECLARE_HOOK_FUNCTION(int64_t, sto_erase, uint32_t write_ptr, uint32_t write_len, uint32_t read_ptr, uint32_t read_len, uint32_t field_id ); DECLARE_HOOK_FUNCTION(int64_t, util_sha512h, uint32_t write_ptr, uint32_t write_len, uint32_t read_ptr, uint32_t read_len ); DECLARE_HOOK_FUNCTION(int64_t, util_keylet, uint32_t write_ptr, uint32_t write_len, uint32_t keylet_type, uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint32_t e, uint32_t f ); DECLARE_HOOK_FUNCNARG(int64_t, etxn_burden ); DECLARE_HOOK_FUNCTION(int64_t, etxn_details, uint32_t write_ptr, uint32_t write_len ); DECLARE_HOOK_FUNCTION(int64_t, etxn_fee_base, uint32_t read_ptr, uint32_t read_len ); DECLARE_HOOK_FUNCTION(int64_t, etxn_reserve, uint32_t count ); DECLARE_HOOK_FUNCNARG(int64_t, etxn_generation ); DECLARE_HOOK_FUNCTION(int64_t, etxn_nonce, uint32_t write_ptr, uint32_t write_len ); DECLARE_HOOK_FUNCTION(int64_t, emit, uint32_t write_ptr, uint32_t write_len, uint32_t read_ptr, uint32_t read_len ); DECLARE_HOOK_FUNCTION(int64_t, float_set, int32_t exponent, int64_t mantissa ); DECLARE_HOOK_FUNCTION(int64_t, float_multiply, int64_t float1, int64_t float2 ); DECLARE_HOOK_FUNCTION(int64_t, float_mulratio, int64_t float1, uint32_t round_up, uint32_t numerator, uint32_t denominator ); DECLARE_HOOK_FUNCTION(int64_t, float_negate, int64_t float1 ); DECLARE_HOOK_FUNCTION(int64_t, float_compare, int64_t float1, int64_t float2, uint32_t mode ); DECLARE_HOOK_FUNCTION(int64_t, float_sum, int64_t float1, int64_t float2 ); DECLARE_HOOK_FUNCTION(int64_t, float_sto, uint32_t write_ptr, uint32_t write_len, uint32_t cread_ptr, uint32_t cread_len, uint32_t iread_ptr, uint32_t iread_len, int64_t float1, uint32_t field_code); DECLARE_HOOK_FUNCTION(int64_t, float_sto_set, uint32_t read_ptr, uint32_t read_len ); DECLARE_HOOK_FUNCTION(int64_t, float_invert, int64_t float1 ); DECLARE_HOOK_FUNCTION(int64_t, float_divide, int64_t float1, int64_t float2 ); DECLARE_HOOK_FUNCNARG(int64_t, float_one ); DECLARE_HOOK_FUNCTION(int64_t, float_mantissa, int64_t float1 ); DECLARE_HOOK_FUNCTION(int64_t, float_sign, int64_t float1 ); DECLARE_HOOK_FUNCTION(int64_t, float_int, int64_t float1, uint32_t decimal_places, uint32_t abs ); DECLARE_HOOK_FUNCTION(int64_t, float_log, int64_t float1 ); DECLARE_HOOK_FUNCTION(int64_t, float_root, int64_t float1, uint32_t n ); DECLARE_HOOK_FUNCTION(int64_t, hook_account, uint32_t write_ptr, uint32_t write_len ); DECLARE_HOOK_FUNCTION(int64_t, hook_hash, uint32_t write_ptr, uint32_t write_len, int32_t hook_no ); DECLARE_HOOK_FUNCNARG(int64_t, fee_base ); DECLARE_HOOK_FUNCNARG(int64_t, ledger_seq ); DECLARE_HOOK_FUNCNARG(int64_t, ledger_last_time ); DECLARE_HOOK_FUNCTION(int64_t, ledger_last_hash, uint32_t write_ptr, uint32_t write_len ); DECLARE_HOOK_FUNCTION(int64_t, ledger_nonce, uint32_t write_ptr, uint32_t write_len ); DECLARE_HOOK_FUNCTION(int64_t, ledger_keylet, uint32_t write_ptr, uint32_t write_len, uint32_t lread_ptr, uint32_t lread_len, uint32_t hread_ptr, uint32_t hread_len ); DECLARE_HOOK_FUNCTION(int64_t, hook_param_set, uint32_t read_ptr, uint32_t read_len, uint32_t kread_ptr, uint32_t kread_len, uint32_t hread_ptr, uint32_t hread_len); DECLARE_HOOK_FUNCTION(int64_t, hook_param, uint32_t write_ptr, uint32_t write_len, uint32_t read_ptr, uint32_t read_len); DECLARE_HOOK_FUNCNARG(int64_t, hook_again); DECLARE_HOOK_FUNCTION(int64_t, hook_skip, uint32_t read_ptr, uint32_t read_len, uint32_t flags); DECLARE_HOOK_FUNCNARG(int64_t, hook_pos); DECLARE_HOOK_FUNCTION(int64_t, slot, uint32_t write_ptr, uint32_t write_len, uint32_t slot ); DECLARE_HOOK_FUNCTION(int64_t, slot_clear, uint32_t slot ); DECLARE_HOOK_FUNCTION(int64_t, slot_count, uint32_t slot ); DECLARE_HOOK_FUNCTION(int64_t, slot_set, uint32_t read_ptr, uint32_t read_len, uint32_t slot ); DECLARE_HOOK_FUNCTION(int64_t, slot_size, uint32_t slot ); DECLARE_HOOK_FUNCTION(int64_t, slot_subarray, uint32_t parent_slot, uint32_t array_id, uint32_t new_slot ); DECLARE_HOOK_FUNCTION(int64_t, slot_subfield, uint32_t parent_slot, uint32_t field_id, uint32_t new_slot ); DECLARE_HOOK_FUNCTION(int64_t, slot_type, uint32_t slot_no, uint32_t flags ); DECLARE_HOOK_FUNCTION(int64_t, slot_float, uint32_t slot_no ); DECLARE_HOOK_FUNCTION(int64_t, state_set, uint32_t read_ptr, uint32_t read_len, uint32_t kread_ptr, uint32_t kread_len ); DECLARE_HOOK_FUNCTION(int64_t, state_foreign_set, uint32_t read_ptr, uint32_t read_len, uint32_t kread_ptr, uint32_t kread_len, uint32_t nread_ptr, uint32_t nread_len, uint32_t aread_ptr, uint32_t aread_len ); DECLARE_HOOK_FUNCTION(int64_t, state, uint32_t write_ptr, uint32_t write_len, uint32_t kread_ptr, uint32_t kread_len ); DECLARE_HOOK_FUNCTION(int64_t, state_foreign, uint32_t write_ptr, uint32_t write_len, uint32_t kread_ptr, uint32_t kread_len, uint32_t nread_ptr, uint32_t nread_len, uint32_t aread_ptr, uint32_t aread_len ); DECLARE_HOOK_FUNCTION(int64_t, trace, uint32_t mread_ptr, uint32_t mread_len, uint32_t dread_ptr, uint32_t dread_len, uint32_t as_hex ); DECLARE_HOOK_FUNCTION(int64_t, trace_num, uint32_t read_ptr, uint32_t read_len, int64_t number ); DECLARE_HOOK_FUNCTION(int64_t, trace_float, uint32_t read_ptr, uint32_t read_len, int64_t float1 ); DECLARE_HOOK_FUNCNARG(int64_t, otxn_burden ); DECLARE_HOOK_FUNCTION(int64_t, otxn_field, uint32_t write_ptr, uint32_t write_len, uint32_t field_id ); DECLARE_HOOK_FUNCNARG(int64_t, otxn_generation ); DECLARE_HOOK_FUNCTION(int64_t, otxn_id, uint32_t write_ptr, uint32_t write_len, uint32_t flags ); DECLARE_HOOK_FUNCNARG(int64_t, otxn_type ); DECLARE_HOOK_FUNCTION(int64_t, otxn_slot, uint32_t slot_no ); DECLARE_HOOK_FUNCTION(int64_t, meta_slot, uint32_t slot_no ); DECLARE_HOOK_FUNCTION(int64_t, str_find, uint32_t hread_ptr, uint32_t hread_len, uint32_t nread_ptr, uint32_t nread_len, uint32_t mode, uint32_t n); DECLARE_HOOK_FUNCTION(int64_t, str_replace, uint32_t write_ptr, uint32_t write_len, uint32_t hread_ptr, uint32_t hread_len, uint32_t nread_ptr, uint32_t nread_len, uint32_t rread_ptr, uint32_t rread_len, uint32_t mode, uint32_t n); DECLARE_HOOK_FUNCTION(int64_t, str_compare, uint32_t fread_ptr, uint32_t fread_len, uint32_t sread_ptr, uint32_t sread_len, uint32_t mode); DECLARE_HOOK_FUNCTION(int64_t, str_concat, uint32_t write_ptr, uint32_t write_len, uint32_t read_ptr, uint32_t read_len, uint64_t operand, uint32_t operand_type); } /* end namespace hook_api */ namespace hook { bool canHook(ripple::TxType txType, uint64_t hookOn); struct HookResult; HookResult apply( ripple::uint256 const& hookSetTxnID, /* this is the txid of the sethook, used for caching (one day) */ ripple::uint256 const& hookHash, /* hash of the actual hook byte code, used for metadata */ ripple::uint256 const& hookNamespace, ripple::Blob const& wasm, std::map< std::vector, /* param name */ std::vector /* param value */ > const& hookParams, std::map< ripple::uint256, /* hook hash */ std::map< std::vector, std::vector >> const& hookParamOverrides, HookStateMap& stateMap, ripple::ApplyContext& applyCtx, ripple::AccountID const& account, /* the account the hook is INSTALLED ON not always the otxn account */ bool hasCallback, bool isCallback, bool isStrongTSH, uint32_t wasmParam, uint8_t hookChainPosition, // result of apply() if this is weak exec std::shared_ptr const& provisionalMeta ); struct HookContext; uint32_t maxHookStateDataSize(void); uint32_t maxHookWasmSize(void); uint32_t maxHookParameterKeySize(void); uint32_t maxHookParameterValueSize(void); uint32_t maxHookChainLength(void); uint32_t computeHookStateOwnerCount(uint32_t hookStateCount); int64_t computeExecutionFee(uint64_t instructionCount); int64_t computeCreationFee(uint64_t byteCount); struct HookResult { ripple::uint256 const hookSetTxnID; ripple::uint256 const hookHash; ripple::Keylet const accountKeylet; ripple::Keylet const ownerDirKeylet; ripple::Keylet const hookKeylet; ripple::AccountID const account; ripple::AccountID const otxnAccount; ripple::uint256 const hookNamespace; std::queue> emittedTxn {}; // etx stored here until accept/rollback HookStateMap& stateMap; uint16_t changedStateCount = 0; std::map< ripple::uint256, // hook hash std::map< std::vector, // hook param name std::vector // hook param value >> hookParamOverrides; std::map< std::vector, std::vector> const& hookParams; std::set hookSkips; hook_api::ExitType exitType = hook_api::ExitType::ROLLBACK; std::string exitReason {""}; int64_t exitCode {-1}; uint64_t instructionCount {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 bool isStrong = false; uint32_t wasmParam = 0; uint32_t overrideCount = 0; uint8_t hookChainPosition = 0; bool foreignStateSetDisabled = false; bool executeAgainAsWeak = false; // hook_again allows strong pre-apply to nominate // additional weak post-apply execution std::shared_ptr provisionalMeta; }; class HookExecutor; struct SlotEntry { std::shared_ptr storage; const ripple::STBase* entry; // raw pointer into the storage, that can be freely pointed around inside }; struct HookContext { ripple::ApplyContext& applyCtx; // slots are used up by requesting objects from inside the hook // the map stores pairs consisting of a memory view and whatever shared or unique ptr is required to // keep the underlying object alive for the duration of the hook's execution // slot number -> { keylet or hash, { pointer to current object, storage for that object } } std::map slot {}; std::queue slot_free {}; uint32_t slot_counter { 0 }; // uint16 to avoid accidental overflow and to allow more slots in future uint16_t emit_nonce_counter { 0 }; // incremented whenever nonce is called to ensure unique nonces uint16_t ledger_nonce_counter { 0 }; int64_t expected_etxn_count { -1 }; // make this a 64bit int so the uint32 from the hookapi cant overflow it std::map nonce_used {}; uint32_t generation = 0; // used for caching, only generated when txn_generation is called uint64_t burden = 0; // used for caching, only generated when txn_burden is called std::map guard_map {}; // iteration guard map upto_iteration> HookResult result; std::optional emitFailure; // if this is a callback from a failed // emitted txn then this optional becomes // populated with the SLE const HookExecutor* module = 0; }; bool addHookNamespaceEntry( ripple::SLE& sleAccount, ripple::uint256 ns); bool removeHookNamespaceEntry( ripple::SLE& sleAccount, ripple::uint256 ns); ripple::TER setHookState( ripple::ApplyContext& applyCtx, ripple::AccountID const& acc, ripple::uint256 const& ns, ripple::uint256 const & key, ripple::Slice const& data); // write hook execution metadata and remove emitted transaction ledger entries ripple::TER finalizeHookResult( hook::HookResult& hookResult, ripple::ApplyContext&, bool doEmit); // write state map to ledger ripple::TER finalizeHookState( HookStateMap const&, ripple::ApplyContext&, ripple::uint256 const&); // if the txn being executed was an emitted txn then this removes it from the emission directory ripple::TER removeEmissionEntry( ripple::ApplyContext& applyCtx); bool /* retval of true means an error */ gatherHookParameters( std::shared_ptr const& hookDef, ripple::STObject const* hookObj, std::map, std::vector>& parameters, beast::Journal const& j_); // RH TODO: call destruct for these on rippled shutdown #define ADD_HOOK_FUNCTION(F, ctx)\ {\ WasmEdge_FunctionInstanceContext* hf = WasmEdge_FunctionInstanceCreate(\ hook_api::WasmFunctionType##F,\ hook_api::WasmFunction##F,\ (void*)(&ctx), 0);\ WasmEdge_ModuleInstanceAddFunction (importObj, hook_api::WasmFunctionName##F, hf);\ } #define HR_ACC() hookResult.account << "-" << hookResult.otxnAccount #define HC_ACC() hookCtx.result.account << "-" << hookCtx.result.otxnAccount // create these once at boot and keep them static WasmEdge_String exportName = WasmEdge_StringCreateByCString("env"); static WasmEdge_String tableName = WasmEdge_StringCreateByCString("table"); static auto* tableType = WasmEdge_TableTypeCreate(WasmEdge_RefType_FuncRef, {.HasMax = true, .Shared = false, .Min = 10, .Max = 20}); static auto* memType = WasmEdge_MemoryTypeCreate({.HasMax = true, .Shared = false, .Min = 1, .Max = 1}); static WasmEdge_String memName = WasmEdge_StringCreateByCString("memory"); static WasmEdge_String cbakFunctionName = WasmEdge_StringCreateByCString("cbak"); static WasmEdge_String hookFunctionName = WasmEdge_StringCreateByCString("hook"); // see: lib/system/allocator.cpp #define WasmEdge_kPageSize 65536ULL /** * HookExecutor is effectively a two-part function: * The first part sets up the Hook Api inside the wasm import, ready for use * (this is done during object construction.) * The second part is actually executing webassembly instructions * this is done during execteWasm function. * The instance is single use. */ class HookExecutor { private: bool spent = false; // a HookExecutor can only be used once public: HookContext hookCtx; WasmEdge_ModuleInstanceContext* importObj; /** * Validate that a web assembly blob can be loaded by wasmedge */ static std::optional validateWasm(const void* wasm, size_t len) { std::optional ret; WasmEdge_ConfigureContext* confCtx = WasmEdge_ConfigureCreate(); WasmEdge_VMContext* vmCtx = WasmEdge_VMCreate(confCtx, NULL); WasmEdge_Result res = WasmEdge_VMLoadWasmFromBuffer(vmCtx, reinterpret_cast(wasm), len); if (!WasmEdge_ResultOK(res)) ret = "VMLoadWasmFromBuffer failed"; else { res = WasmEdge_VMValidate(vmCtx); if (!WasmEdge_ResultOK(res)) ret = "VMValidate failed"; } WasmEdge_VMDelete(vmCtx); WasmEdge_ConfigureDelete(confCtx); return ret; } /** * Execute web assembly byte code against the constructed Hook Context * Once execution has occured the exector is spent and cannot be used again and should be destructed * Information about the execution is populated into hookCtx */ void executeWasm(const void* wasm, size_t len, bool callback, uint32_t wasmParam, beast::Journal const& j) { // HookExecutor can only execute once assert(!spent); spent = true; JLOG(j.trace()) << "HookInfo[" << HC_ACC() << "]: creating wasm instance"; WasmEdge_ConfigureContext* confCtx = WasmEdge_ConfigureCreate(); WasmEdge_ConfigureStatisticsSetInstructionCounting(confCtx, true); WasmEdge_VMContext* vmCtx = WasmEdge_VMCreate(confCtx, NULL); WasmEdge_Result res = WasmEdge_VMRegisterModuleFromImport(vmCtx, this->importObj); if (!WasmEdge_ResultOK(res)) { hookCtx.result.exitType = hook_api::ExitType::WASM_ERROR; JLOG(j.trace()) << "HookError[" << HC_ACC() << "]: Import phase failed " << WasmEdge_ResultGetMessage(res); } else { WasmEdge_Value params[1] = { WasmEdge_ValueGenI32((int64_t)wasmParam) }; WasmEdge_Value returns[1]; /* printf("executing hook wasm:\n"); for (int j = 0; j < len; j++) { if (j % 16 == 0) printf("0x%08X:\t", j); printf("%02X%s", (reinterpret_cast(wasm))[j], (j % 16 == 15 ? "\n" : (j % 4 == 3 ? " " : (j % 2 == 1 ? " " : "")))); } printf("\n----\n"); */ res = WasmEdge_VMRunWasmFromBuffer(vmCtx, reinterpret_cast(wasm), len, callback ? cbakFunctionName : hookFunctionName, params, 1, returns, 1); if (!WasmEdge_ResultOK(res)) { JLOG(j.warn()) << "HookError[" << HC_ACC() << "]: WASM VM error " << WasmEdge_ResultGetMessage(res); hookCtx.result.exitType = hook_api::ExitType::WASM_ERROR; } else { auto* statsCtx= WasmEdge_VMGetStatisticsContext(vmCtx); hookCtx.result.instructionCount = WasmEdge_StatisticsGetInstrCount(statsCtx); } } WasmEdge_ConfigureDelete(confCtx); WasmEdge_VMDelete(vmCtx); } HookExecutor(HookContext& ctx) : hookCtx(ctx) , importObj(WasmEdge_ModuleInstanceCreate(exportName)) { ctx.module = this; WasmEdge_LogSetDebugLevel(); ADD_HOOK_FUNCTION(_g, ctx); ADD_HOOK_FUNCTION(accept, ctx); ADD_HOOK_FUNCTION(rollback, ctx); ADD_HOOK_FUNCTION(util_raddr, ctx); ADD_HOOK_FUNCTION(util_accid, ctx); ADD_HOOK_FUNCTION(util_verify, ctx); ADD_HOOK_FUNCTION(util_sha512h, ctx); ADD_HOOK_FUNCTION(sto_validate, ctx); ADD_HOOK_FUNCTION(sto_subfield, ctx); ADD_HOOK_FUNCTION(sto_subarray, ctx); ADD_HOOK_FUNCTION(sto_emplace, ctx); ADD_HOOK_FUNCTION(sto_erase, ctx); ADD_HOOK_FUNCTION(util_keylet, ctx); ADD_HOOK_FUNCTION(emit, ctx); ADD_HOOK_FUNCTION(etxn_burden, ctx); ADD_HOOK_FUNCTION(etxn_fee_base, ctx); ADD_HOOK_FUNCTION(etxn_details, ctx); ADD_HOOK_FUNCTION(etxn_reserve, ctx); ADD_HOOK_FUNCTION(etxn_generation, ctx); ADD_HOOK_FUNCTION(etxn_nonce, ctx); ADD_HOOK_FUNCTION(float_set, ctx); ADD_HOOK_FUNCTION(float_multiply, ctx); ADD_HOOK_FUNCTION(float_mulratio, ctx); ADD_HOOK_FUNCTION(float_negate, ctx); ADD_HOOK_FUNCTION(float_compare, ctx); ADD_HOOK_FUNCTION(float_sum, ctx); ADD_HOOK_FUNCTION(float_sto, ctx); ADD_HOOK_FUNCTION(float_sto_set, ctx); ADD_HOOK_FUNCTION(float_invert, ctx); ADD_HOOK_FUNCTION(float_divide, ctx); ADD_HOOK_FUNCTION(float_one, ctx); ADD_HOOK_FUNCTION(float_mantissa, ctx); ADD_HOOK_FUNCTION(float_sign, ctx); ADD_HOOK_FUNCTION(float_int, ctx); ADD_HOOK_FUNCTION(float_log, ctx); ADD_HOOK_FUNCTION(float_root, ctx); ADD_HOOK_FUNCTION(otxn_burden, ctx); ADD_HOOK_FUNCTION(otxn_generation, ctx); ADD_HOOK_FUNCTION(otxn_field, ctx); ADD_HOOK_FUNCTION(otxn_id, ctx); ADD_HOOK_FUNCTION(otxn_type, ctx); ADD_HOOK_FUNCTION(otxn_slot, ctx); ADD_HOOK_FUNCTION(hook_account, ctx); ADD_HOOK_FUNCTION(hook_hash, ctx); ADD_HOOK_FUNCTION(hook_again, ctx); ADD_HOOK_FUNCTION(fee_base, ctx); ADD_HOOK_FUNCTION(ledger_seq, ctx); ADD_HOOK_FUNCTION(ledger_last_hash, ctx); ADD_HOOK_FUNCTION(ledger_last_time, ctx); ADD_HOOK_FUNCTION(ledger_nonce, ctx); ADD_HOOK_FUNCTION(ledger_keylet, ctx); ADD_HOOK_FUNCTION(hook_param, ctx); ADD_HOOK_FUNCTION(hook_param_set, ctx); ADD_HOOK_FUNCTION(hook_skip, ctx); ADD_HOOK_FUNCTION(hook_pos, ctx); ADD_HOOK_FUNCTION(state, ctx); ADD_HOOK_FUNCTION(state_foreign, ctx); ADD_HOOK_FUNCTION(state_set, ctx); ADD_HOOK_FUNCTION(state_foreign_set, ctx); ADD_HOOK_FUNCTION(slot, ctx); ADD_HOOK_FUNCTION(slot_clear, ctx); ADD_HOOK_FUNCTION(slot_count, ctx); ADD_HOOK_FUNCTION(slot_set, ctx); ADD_HOOK_FUNCTION(slot_size, ctx); ADD_HOOK_FUNCTION(slot_subarray, ctx); ADD_HOOK_FUNCTION(slot_subfield, ctx); ADD_HOOK_FUNCTION(slot_type, ctx); ADD_HOOK_FUNCTION(slot_float, ctx); ADD_HOOK_FUNCTION(trace, ctx); ADD_HOOK_FUNCTION(trace_num, ctx); ADD_HOOK_FUNCTION(trace_float, ctx); ADD_HOOK_FUNCTION(meta_slot, ctx); ADD_HOOK_FUNCTION(str_find, ctx); ADD_HOOK_FUNCTION(str_replace, ctx); ADD_HOOK_FUNCTION(str_compare, ctx); ADD_HOOK_FUNCTION(str_concat, ctx); WasmEdge_TableInstanceContext* hostTable = WasmEdge_TableInstanceCreate(tableType); WasmEdge_ModuleInstanceAddTable(importObj, tableName, hostTable); WasmEdge_MemoryInstanceContext* hostMem = WasmEdge_MemoryInstanceCreate(memType); WasmEdge_ModuleInstanceAddMemory(importObj, memName, hostMem); } ~HookExecutor() { WasmEdge_ModuleInstanceDelete(importObj); }; }; } #endif