mirror of
https://github.com/Xahau/xahaud.git
synced 2026-10-23 12:17:37 +00:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b3e7d4ae05 | ||
|
|
697149aaa9 |
No files matched your search
@@ -1308,6 +1308,15 @@
|
||||
# Example:
|
||||
# owner_reserve = 2000000 # 2 XAH
|
||||
#
|
||||
# hook_gas_price = <uint32_t>
|
||||
#
|
||||
# The gas price for hooks is used to calculate the execution fee for hooks.
|
||||
#
|
||||
# If this parameter is unspecified, xahaud will use an internal
|
||||
# default. Don't change this without understanding the consequences.
|
||||
#
|
||||
# Example:
|
||||
# hook_gas_price = 1000000
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
# 9. Misc Settings
|
||||
|
||||
@@ -72,6 +72,7 @@
|
||||
#define sfLockCount ((2U << 16U) + 49U)
|
||||
#define sfFirstNFTokenSequence ((2U << 16U) + 50U)
|
||||
#define sfOracleDocumentID ((2U << 16U) + 51U)
|
||||
#define sfHookGasPrice ((2U << 16U) + 92U)
|
||||
#define sfStartTime ((2U << 16U) + 93U)
|
||||
#define sfRepeatCount ((2U << 16U) + 94U)
|
||||
#define sfDelaySeconds ((2U << 16U) + 95U)
|
||||
@@ -105,6 +106,8 @@
|
||||
#define sfMPTAmount ((3U << 16U) + 26U)
|
||||
#define sfIssuerNode ((3U << 16U) + 27U)
|
||||
#define sfSubjectNode ((3U << 16U) + 28U)
|
||||
#define sfHookCost ((3U << 16U) + 95U)
|
||||
#define sfHookCallbackCost ((3U << 16U) + 96U)
|
||||
#define sfTouchCount ((3U << 16U) + 97U)
|
||||
#define sfAccountIndex ((3U << 16U) + 98U)
|
||||
#define sfAccountCount ((3U << 16U) + 99U)
|
||||
|
||||
@@ -61,6 +61,7 @@
|
||||
#define ttNFTOKEN_MODIFY 70
|
||||
#define ttPERMISSIONED_DOMAIN_SET 71
|
||||
#define ttPERMISSIONED_DOMAIN_DELETE 72
|
||||
#define ttHOOK_DEFINITION_UPDATE 90
|
||||
#define ttMANIFEST_SET 91
|
||||
#define ttCRON 92
|
||||
#define ttCRON_SET 93
|
||||
|
||||
@@ -115,3 +115,7 @@ enum AMMClawbackFlags : uint32_t {
|
||||
enum BridgeModifyFlags : uint32_t {
|
||||
tfClearAccountCreateAmount = 0x00010000,
|
||||
};
|
||||
|
||||
enum HookDefinitionUpdateFlags : uint32_t {
|
||||
tfValidateGuards = 0x00000001,
|
||||
};
|
||||
@@ -0,0 +1,6 @@
|
||||
!guard_checker.cpp
|
||||
|
||||
# binary
|
||||
guard_checker
|
||||
# directory
|
||||
guard_checker*/**
|
||||
@@ -17,6 +17,7 @@
|
||||
#define featureHooksUpdate2 "1"
|
||||
#define fix20250131 "1"
|
||||
#define fixGuardDepth32 "1"
|
||||
#define featureHookFeeV3 "1"
|
||||
namespace hook_api {
|
||||
struct Rules
|
||||
{
|
||||
@@ -402,7 +403,17 @@ const uint8_t max_emit = 255;
|
||||
const uint8_t max_params = 16;
|
||||
const double fee_base_multiplier = 1.1f;
|
||||
|
||||
using APIWhitelist = std::map<std::string, std::vector<uint8_t>>;
|
||||
// HookFeeV2 execution cost units: every wasm instruction costs one unit and
|
||||
// every hook api call costs api_call_cost units on top of its call
|
||||
// instruction. cost_units_per_drop units make one drop, so an instruction
|
||||
// costs 0.1 drop and an api call 10 drops. HookFeeV3 replaces the flat
|
||||
// api_call_cost with the per-api HOOK_API_COST table and prices the units
|
||||
// with the ledger's HookGasPrice.
|
||||
const uint32_t api_call_cost = 100;
|
||||
const uint32_t cost_units_per_drop = 10;
|
||||
|
||||
using APIWhitelist =
|
||||
std::map<std::string, std::pair<std::vector<uint8_t>, uint32_t>>;
|
||||
|
||||
// RH NOTE: Find descriptions of api functions in ./impl/applyHook.cpp and
|
||||
// hookapi.h (include for hooks) this is a map of the api name to its return
|
||||
@@ -413,7 +424,9 @@ getImportWhitelist(Rules const& rules)
|
||||
APIWhitelist whitelist;
|
||||
|
||||
#pragma push_macro("HOOK_API_DEFINITION")
|
||||
#pragma push_macro("HOOK_API_COST")
|
||||
#undef HOOK_API_DEFINITION
|
||||
#undef HOOK_API_COST
|
||||
|
||||
#define int64_t 0x7EU
|
||||
#define int32_t 0x7FU
|
||||
@@ -425,17 +438,34 @@ getImportWhitelist(Rules const& rules)
|
||||
RETURN_TYPE, FUNCTION_NAME, PARAMS_TUPLE, AMENDMENT) \
|
||||
if (AMENDMENT == uint256{} || rules.enabled(AMENDMENT)) \
|
||||
whitelist[#FUNCTION_NAME] = { \
|
||||
RETURN_TYPE, HOOK_WRAP_PARAMS PARAMS_TUPLE};
|
||||
{RETURN_TYPE, HOOK_WRAP_PARAMS PARAMS_TUPLE}, api_call_cost};
|
||||
|
||||
// per-api costs only apply under HookFeeV3; use find() so a cost line never
|
||||
// whitelists an api whose definition is gated off
|
||||
#define HOOK_API_COST(FUNCTION_NAME, COST, AMENDMENT) \
|
||||
if (rules.enabled(featureHookFeeV3) && \
|
||||
(AMENDMENT == uint256{} || rules.enabled(AMENDMENT))) \
|
||||
if (auto it = whitelist.find(#FUNCTION_NAME); it != whitelist.end()) \
|
||||
it->second.second = COST;
|
||||
|
||||
#include "hook_api.macro"
|
||||
|
||||
#undef HOOK_API_COST
|
||||
#undef HOOK_API_DEFINITION
|
||||
#undef HOOK_WRAP_PARAMS
|
||||
#undef int64_t
|
||||
#undef int32_t
|
||||
#undef uint32_t
|
||||
#pragma pop_macro("HOOK_API_COST")
|
||||
#pragma pop_macro("HOOK_API_DEFINITION")
|
||||
|
||||
// all cost should > 0
|
||||
for (auto& [function, pair] : whitelist)
|
||||
{
|
||||
if (pair.second <= 0)
|
||||
return {};
|
||||
}
|
||||
|
||||
return whitelist;
|
||||
}
|
||||
|
||||
|
||||
+74
-30
@@ -145,6 +145,7 @@ struct WasmBlkInf
|
||||
uint32_t sanity_check;
|
||||
uint32_t iteration_bound;
|
||||
uint32_t instruction_count;
|
||||
uint32_t execution_cost;
|
||||
WasmBlkInf* parent;
|
||||
std::vector<WasmBlkInf*> children;
|
||||
uint32_t start_byte;
|
||||
@@ -159,6 +160,7 @@ struct WasmBlkInf
|
||||
: sanity_check(0x1234ABCDU)
|
||||
, iteration_bound(iteration_bound_)
|
||||
, instruction_count(instruction_count_)
|
||||
, execution_cost(0)
|
||||
, parent(parent_)
|
||||
, children({})
|
||||
, start_byte(start_byte_)
|
||||
@@ -194,7 +196,7 @@ struct WasmBlkInf
|
||||
level, \
|
||||
" " \
|
||||
" ", \
|
||||
worst_case_execution, \
|
||||
instruction_count, \
|
||||
blk->start_byte, \
|
||||
blk->instruction_count, \
|
||||
blk->iteration_bound, \
|
||||
@@ -203,7 +205,7 @@ struct WasmBlkInf
|
||||
&(blk->parent)); \
|
||||
}
|
||||
// compute worst case execution time
|
||||
inline uint64_t
|
||||
inline std::pair<uint64_t, uint64_t>
|
||||
compute_wce(
|
||||
const WasmBlkInf* blk,
|
||||
int level,
|
||||
@@ -213,14 +215,14 @@ compute_wce(
|
||||
if (level > max_level)
|
||||
{
|
||||
*recursion_limit_reached = true;
|
||||
return 0;
|
||||
return {0, 0};
|
||||
}
|
||||
|
||||
if (blk->sanity_check != 0x1234ABCDU)
|
||||
{
|
||||
printf("!!! sanity check failed\n");
|
||||
*recursion_limit_reached = true;
|
||||
return (uint64_t)-1;
|
||||
return {(uint64_t)-1, (uint64_t)-1};
|
||||
}
|
||||
|
||||
WasmBlkInf const* parent = blk->parent;
|
||||
@@ -229,23 +231,28 @@ compute_wce(
|
||||
{
|
||||
printf("!!! parent sanity check failed\n");
|
||||
*recursion_limit_reached = true;
|
||||
return (uint64_t)-1;
|
||||
return {(uint64_t)-1, (uint64_t)-1};
|
||||
}
|
||||
|
||||
uint64_t worst_case_execution = blk->instruction_count;
|
||||
uint64_t instruction_count = blk->instruction_count;
|
||||
uint64_t execution_cost = blk->execution_cost;
|
||||
double multiplier = 1.0;
|
||||
|
||||
if (blk->children.size() > 0)
|
||||
for (auto const& child : blk->children)
|
||||
worst_case_execution += compute_wce(
|
||||
{
|
||||
auto [child_instruction_count, child_execution_cost] = compute_wce(
|
||||
child, level + 1, max_level, recursion_limit_reached);
|
||||
instruction_count += child_instruction_count;
|
||||
execution_cost += child_execution_cost;
|
||||
}
|
||||
|
||||
if (parent == 0 ||
|
||||
parent->iteration_bound ==
|
||||
0) // this condtion should never occur [defensively programmed]
|
||||
{
|
||||
PRINT_WCE(1);
|
||||
return worst_case_execution;
|
||||
return {instruction_count, execution_cost};
|
||||
}
|
||||
|
||||
// if the block has a parent then the quotient of its guard and its parent's
|
||||
@@ -254,12 +261,18 @@ compute_wce(
|
||||
multiplier =
|
||||
((double)(blk->iteration_bound)) / ((double)(parent->iteration_bound));
|
||||
|
||||
worst_case_execution *= multiplier;
|
||||
if (worst_case_execution < 1.0)
|
||||
worst_case_execution = 1.0;
|
||||
instruction_count *= multiplier;
|
||||
if (instruction_count < 1.0)
|
||||
instruction_count = 1.0;
|
||||
|
||||
// the loop multiplier must apply to the execution cost as well, otherwise
|
||||
// an api call inside a loop is only ever charged for a single iteration
|
||||
execution_cost *= multiplier;
|
||||
if (execution_cost < 1.0)
|
||||
execution_cost = 1.0;
|
||||
|
||||
PRINT_WCE(3);
|
||||
return worst_case_execution;
|
||||
return {instruction_count, execution_cost};
|
||||
};
|
||||
|
||||
// checks the WASM binary for the appropriate required _g guard calls and
|
||||
@@ -267,16 +280,19 @@ compute_wce(
|
||||
// expr under analysis begins and end_offset is where it ends returns {worst
|
||||
// case instruction count} if valid or {} if invalid may throw overflow_error,
|
||||
// length_error
|
||||
inline std::optional<uint64_t>
|
||||
inline std::optional<uint64_t> // count or cost depending on returnCost
|
||||
check_guard(
|
||||
std::vector<uint8_t> const& wasm,
|
||||
int codesec,
|
||||
int start_offset,
|
||||
int end_offset,
|
||||
std::map<int, std::map<int, std::string>> import_type_map,
|
||||
std::map<int, uint32_t> const& import_cost_map,
|
||||
int guard_func_idx,
|
||||
int last_import_idx,
|
||||
GuardLog guardLog,
|
||||
std::string guardLogAccStr,
|
||||
bool returnCost,
|
||||
/* RH NOTE:
|
||||
* rules version is a bit field, so rule update 1 is 0x01, update 2 is 0x02
|
||||
* and update 3 is 0x04 ideally at rule version 3 all bits so far are set
|
||||
@@ -337,6 +353,7 @@ check_guard(
|
||||
ADVANCE(1);
|
||||
|
||||
current->instruction_count++;
|
||||
current->execution_cost++;
|
||||
|
||||
// unreachable and nop instructions
|
||||
if (instr == 0x00U || // unreachable
|
||||
@@ -516,6 +533,10 @@ check_guard(
|
||||
GUARD_ERROR("Too many guard calls! Limit is 1024");
|
||||
}
|
||||
|
||||
if (auto const it = import_cost_map.find(callee_idx);
|
||||
it != import_cost_map.end())
|
||||
current->execution_cost += it->second;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -795,7 +816,7 @@ check_guard(
|
||||
int max_level = 16;
|
||||
if (rulesVersion & hook_api::GuardRuleDepth32)
|
||||
max_level = 32;
|
||||
uint64_t wce =
|
||||
auto [instruction_count, execution_cost] =
|
||||
compute_wce(&(*root), 0, max_level, &recursion_limit_reached);
|
||||
if (recursion_limit_reached)
|
||||
{
|
||||
@@ -807,11 +828,7 @@ check_guard(
|
||||
return {};
|
||||
}
|
||||
|
||||
GUARDLOG(hook::log::INSTRUCTION_COUNT)
|
||||
<< "GuardCheck "
|
||||
<< "Total worse-case execution count: " << wce << "\n";
|
||||
|
||||
if (wce >= 0xFFFFU)
|
||||
if (instruction_count >= 0xFFFFU)
|
||||
{
|
||||
GUARDLOG(hook::log::INSTRUCTION_EXCESS)
|
||||
<< "GuardCheck "
|
||||
@@ -821,7 +838,10 @@ check_guard(
|
||||
<< "\n";
|
||||
return {};
|
||||
}
|
||||
return wce;
|
||||
if (returnCost)
|
||||
return execution_cost;
|
||||
else
|
||||
return instruction_count;
|
||||
}
|
||||
|
||||
// RH TODO: reprogram this function to use REQUIRE/ADVANCE
|
||||
@@ -835,6 +855,7 @@ validateGuards(
|
||||
std::vector<uint8_t> const& wasm,
|
||||
GuardLog guardLog,
|
||||
std::string guardLogAccStr,
|
||||
bool returnCost,
|
||||
hook_api::APIWhitelist const import_whitelist,
|
||||
/* RH NOTE:
|
||||
* rules version is a bit field, so rule update 1 is 0x01, update 2 is 0x02
|
||||
@@ -883,11 +904,16 @@ validateGuards(
|
||||
// this maps function ids to type ids, used for looking up the type of cbak
|
||||
// and hook as established inside the wasm binary.
|
||||
std::map<int, int> func_type_map;
|
||||
// used to check that every import sharing a type has the same signature
|
||||
std::map<
|
||||
int /* type idx */,
|
||||
std::map<int /* import index */, std::string /* api name */>>
|
||||
import_type_map;
|
||||
|
||||
// api costs must be keyed by function index, which is the index space a
|
||||
// call instruction refers to, not by type index
|
||||
std::map<int /* import func idx */, uint32_t /* cost */> import_cost_map;
|
||||
|
||||
// now we check for guards... first check if _g is imported
|
||||
int guard_import_number = -1;
|
||||
int last_import_number = -1;
|
||||
@@ -1030,15 +1056,18 @@ validateGuards(
|
||||
int type_idx = parseLeb128(wasm, i, &i);
|
||||
CHECK_SHORT_HOOK();
|
||||
|
||||
uint32_t cost = 0;
|
||||
|
||||
auto it = import_whitelist.find(import_name);
|
||||
auto it_end = import_whitelist.end();
|
||||
bool found_in_whitelist = (it != it_end);
|
||||
|
||||
if (import_name == "_g")
|
||||
{
|
||||
guard_import_number = func_upto;
|
||||
}
|
||||
if (!found_in_whitelist)
|
||||
|
||||
if (found_in_whitelist)
|
||||
cost = it->second.second;
|
||||
else
|
||||
{
|
||||
GUARDLOG(hook::log::IMPORT_ILLEGAL)
|
||||
<< "Malformed transaction. "
|
||||
@@ -1050,13 +1079,11 @@ validateGuards(
|
||||
return {};
|
||||
}
|
||||
|
||||
import_cost_map[func_upto] = cost;
|
||||
|
||||
// add to import map
|
||||
if (import_type_map.find(type_idx) == import_type_map.end())
|
||||
import_type_map[type_idx] = {
|
||||
{func_upto, std::move(import_name)}};
|
||||
else
|
||||
import_type_map[type_idx].emplace(
|
||||
func_upto, std::move(import_name));
|
||||
import_type_map[type_idx].emplace(
|
||||
func_upto, std::move(import_name));
|
||||
|
||||
func_upto++;
|
||||
}
|
||||
@@ -1262,7 +1289,7 @@ validateGuards(
|
||||
for (auto const& [import_idx, api_name] : usage->second)
|
||||
{
|
||||
auto const& api_signature =
|
||||
import_whitelist.find(api_name)->second;
|
||||
import_whitelist.find(api_name)->second.first;
|
||||
|
||||
if (!first_signature)
|
||||
{
|
||||
@@ -1501,19 +1528,36 @@ validateGuards(
|
||||
j,
|
||||
i,
|
||||
code_end,
|
||||
import_type_map,
|
||||
import_cost_map,
|
||||
guard_import_number,
|
||||
last_import_number,
|
||||
guardLog,
|
||||
guardLogAccStr,
|
||||
returnCost,
|
||||
rulesVersion);
|
||||
|
||||
if (!valid)
|
||||
return {};
|
||||
|
||||
if (hook_func_idx && *hook_func_idx == j)
|
||||
{
|
||||
GUARDLOG(hook::log::INSTRUCTION_COUNT)
|
||||
<< "GuardCheck "
|
||||
<< "Total hook worse-case execution "
|
||||
<< (returnCost ? "cost: " : "count: ") << *valid
|
||||
<< "\n";
|
||||
maxInstrCountHook = *valid;
|
||||
}
|
||||
else if (cbak_func_idx && *cbak_func_idx == j)
|
||||
{
|
||||
GUARDLOG(hook::log::INSTRUCTION_COUNT)
|
||||
<< "GuardCheck "
|
||||
<< "Total cbak worse-case execution "
|
||||
<< (returnCost ? "cost: " : "count: ") << *valid
|
||||
<< "\n";
|
||||
maxInstrCountCbak = *valid;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (DEBUG_GUARD)
|
||||
|
||||
@@ -88,6 +88,7 @@ main(int argc, char** argv)
|
||||
hook,
|
||||
std::cout,
|
||||
"",
|
||||
true,
|
||||
hook_api::getImportWhitelist(rules),
|
||||
hook_api::getGuardRulesVersion(rules));
|
||||
|
||||
|
||||
@@ -2,373 +2,448 @@
|
||||
HOOK_API_DEFINITION(
|
||||
int32_t, _g, (uint32_t, uint32_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(_g, 70, uint256{})
|
||||
|
||||
// int64_t accept(uint32_t read_ptr, uint32_t read_len, int64_t error_code);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, accept, (uint32_t, uint32_t, int64_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(accept, 80, uint256{})
|
||||
|
||||
// int64_t rollback(uint32_t read_ptr, uint32_t read_len, int64_t error_code);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, rollback, (uint32_t, uint32_t, int64_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(rollback, 80, uint256{})
|
||||
|
||||
// int64_t util_raddr(uint32_t write_ptr, uint32_t write_len, uint32_t read_ptr, uint32_t read_len);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, util_raddr, (uint32_t, uint32_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(util_raddr, 120, uint256{})
|
||||
|
||||
// int64_t util_accid(uint32_t write_ptr, uint32_t write_len, uint32_t read_ptr, uint32_t read_len);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, util_accid, (uint32_t, uint32_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(util_accid, 110, uint256{})
|
||||
|
||||
// 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);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, util_verify, (uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(util_verify, 4300, uint256{})
|
||||
|
||||
// int64_t util_sha512h(uint32_t write_ptr, uint32_t write_len, uint32_t read_ptr, uint32_t read_len);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, util_sha512h, (uint32_t, uint32_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(util_sha512h, 950, uint256{})
|
||||
|
||||
// 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);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, util_keylet, (uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(util_keylet, 100, uint256{})
|
||||
|
||||
// int64_t sto_validate(uint32_t tread_ptr, uint32_t tread_len);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, sto_validate, (uint32_t, uint32_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(sto_validate, 120, uint256{})
|
||||
|
||||
// int64_t sto_subfield(uint32_t read_ptr, uint32_t read_len, uint32_t field_id);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, sto_subfield, (uint32_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(sto_subfield, 90, uint256{})
|
||||
|
||||
// int64_t sto_subarray(uint32_t read_ptr, uint32_t read_len, uint32_t array_id);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, sto_subarray, (uint32_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(sto_subarray, 80, uint256{})
|
||||
|
||||
// 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);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, sto_emplace, (uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(sto_emplace, 100, uint256{})
|
||||
|
||||
// int64_t sto_erase(uint32_t write_ptr, uint32_t write_len, uint32_t read_ptr, uint32_t read_len, uint32_t field_id);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, sto_erase, (uint32_t, uint32_t, uint32_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(sto_erase, 80, uint256{})
|
||||
|
||||
// int64_t etxn_burden();
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, etxn_burden, (),
|
||||
uint256{})
|
||||
HOOK_API_COST(etxn_burden, 70, uint256{})
|
||||
|
||||
// int64_t etxn_details(uint32_t write_ptr, uint32_t write_len);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, etxn_details, (uint32_t, uint32_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(etxn_details, 140, uint256{})
|
||||
|
||||
// int64_t etxn_fee_base(uint32_t read_ptr, uint32_t read_len);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, etxn_fee_base, (uint32_t, uint32_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(etxn_fee_base, 800, uint256{})
|
||||
|
||||
// int64_t etxn_reserve(uint32_t count);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, etxn_reserve, (uint32_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(etxn_reserve, 90, uint256{})
|
||||
|
||||
// int64_t etxn_generation();
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, etxn_generation, (),
|
||||
uint256{})
|
||||
HOOK_API_COST(etxn_generation, 60, uint256{})
|
||||
|
||||
// int64_t etxn_nonce(uint32_t write_ptr, uint32_t write_len);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, etxn_nonce, (uint32_t, uint32_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(etxn_nonce, 110, uint256{})
|
||||
|
||||
// int64_t emit(uint32_t write_ptr, uint32_t write_len, uint32_t read_ptr, uint32_t read_len);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, emit, (uint32_t, uint32_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(emit, 1800, uint256{})
|
||||
|
||||
// int64_t float_set(int32_t exponent, int64_t mantissa);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, float_set, (int32_t, int64_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(float_set, 80, uint256{})
|
||||
|
||||
// int64_t float_multiply(int64_t float1, int64_t float2);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, float_multiply, (int64_t, int64_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(float_multiply, 80, uint256{})
|
||||
|
||||
// int64_t float_mulratio(int64_t float1, uint32_t round_up, uint32_t numerator, uint32_t denominator);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, float_mulratio, (int64_t, uint32_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(float_mulratio, 70, uint256{})
|
||||
|
||||
// int64_t float_negate(int64_t float1);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, float_negate, (int64_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(float_negate, 60, uint256{})
|
||||
|
||||
// int64_t float_compare(int64_t float1, int64_t float2, uint32_t mode);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, float_compare, (int64_t, int64_t, uint32_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(float_compare, 70, uint256{})
|
||||
|
||||
// int64_t float_sum(int64_t float1, int64_t float2);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, float_sum, (int64_t, int64_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(float_sum, 70, uint256{})
|
||||
|
||||
// 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);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, float_sto, (uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, int64_t, uint32_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(float_sto, 60, uint256{})
|
||||
|
||||
// int64_t float_sto_set(uint32_t read_ptr, uint32_t read_len);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, float_sto_set, (uint32_t, uint32_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(float_sto_set, 60, uint256{})
|
||||
|
||||
// int64_t float_invert(int64_t float1);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, float_invert, (int64_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(float_invert, 60, uint256{})
|
||||
|
||||
// int64_t float_divide(int64_t float1, int64_t float2);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, float_divide, (int64_t, int64_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(float_divide, 60, uint256{})
|
||||
|
||||
// int64_t float_one();
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, float_one, (),
|
||||
uint256{})
|
||||
HOOK_API_COST(float_one, 50, uint256{})
|
||||
|
||||
// int64_t float_mantissa(int64_t float1);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, float_mantissa, (int64_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(float_mantissa, 60, uint256{})
|
||||
|
||||
// int64_t float_sign(int64_t float1);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, float_sign, (int64_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(float_sign, 60, uint256{})
|
||||
|
||||
// int64_t float_int(int64_t float1, uint32_t decimal_places, uint32_t abs);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, float_int, (int64_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(float_int, 60, uint256{})
|
||||
|
||||
// int64_t float_log(int64_t float1);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, float_log, (int64_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(float_log, 60, uint256{})
|
||||
|
||||
// int64_t float_root(int64_t float1, uint32_t n);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, float_root, (int64_t, uint32_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(float_root, 70, uint256{})
|
||||
|
||||
// int64_t fee_base();
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, fee_base, (),
|
||||
uint256{})
|
||||
HOOK_API_COST(fee_base, 60, uint256{})
|
||||
|
||||
// int64_t ledger_seq();
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, ledger_seq, (),
|
||||
uint256{})
|
||||
HOOK_API_COST(ledger_seq, 60, uint256{})
|
||||
|
||||
// int64_t ledger_last_time();
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, ledger_last_time, (),
|
||||
uint256{})
|
||||
HOOK_API_COST(ledger_last_time, 60, uint256{})
|
||||
|
||||
// int64_t ledger_last_hash(uint32_t write_ptr, uint32_t write_len);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, ledger_last_hash, (uint32_t, uint32_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(ledger_last_hash, 60, uint256{})
|
||||
|
||||
// int64_t ledger_nonce(uint32_t write_ptr, uint32_t write_len);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, ledger_nonce, (uint32_t, uint32_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(ledger_nonce, 90, uint256{})
|
||||
|
||||
// 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);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, ledger_keylet, (uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(ledger_keylet, 140, uint256{})
|
||||
|
||||
// int64_t hook_account(uint32_t write_ptr, uint32_t write_len);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, hook_account, (uint32_t, uint32_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(hook_account, 60, uint256{})
|
||||
|
||||
// int64_t hook_hash(uint32_t write_ptr, uint32_t write_len, int32_t hook_no);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, hook_hash, (uint32_t, uint32_t, int32_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(hook_hash, 70, uint256{})
|
||||
|
||||
// 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);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, hook_param_set, (uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(hook_param_set, 90, uint256{})
|
||||
|
||||
// int64_t hook_param(uint32_t write_ptr, uint32_t write_len, uint32_t read_ptr, uint32_t read_len);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, hook_param, (uint32_t, uint32_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(hook_param, 70, uint256{})
|
||||
|
||||
// int64_t hook_again();
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, hook_again, (),
|
||||
uint256{})
|
||||
HOOK_API_COST(hook_again, 80, uint256{})
|
||||
|
||||
// int64_t hook_skip(uint32_t read_ptr, uint32_t read_len, uint32_t flags);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, hook_skip, (uint32_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(hook_skip, 70, uint256{})
|
||||
|
||||
// int64_t hook_pos();
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, hook_pos, (),
|
||||
uint256{})
|
||||
HOOK_API_COST(hook_pos, 50, uint256{})
|
||||
|
||||
// int64_t slot(uint32_t write_ptr, uint32_t write_len, uint32_t slot);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, slot, (uint32_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(slot, 120, uint256{})
|
||||
|
||||
// int64_t slot_clear(uint32_t slot);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, slot_clear, (uint32_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(slot_clear, 80, uint256{})
|
||||
|
||||
// int64_t slot_count(uint32_t slot);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, slot_count, (uint32_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(slot_count, 60, uint256{})
|
||||
|
||||
// int64_t slot_set(uint32_t read_ptr, uint32_t read_len, uint32_t slot);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, slot_set, (uint32_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(slot_set, 320, uint256{})
|
||||
|
||||
// int64_t slot_size(uint32_t slot);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, slot_size, (uint32_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(slot_size, 90, uint256{})
|
||||
|
||||
// int64_t slot_subarray(uint32_t parent_slot, uint32_t array_id, uint32_t new_slot);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, slot_subarray, (uint32_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(slot_subarray, 60, uint256{})
|
||||
|
||||
// int64_t slot_subfield(uint32_t parent_slot, uint32_t field_id, uint32_t new_slot);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, slot_subfield, (uint32_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(slot_subfield, 60, uint256{})
|
||||
|
||||
// int64_t slot_type(uint32_t slot_no, uint32_t flags);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, slot_type, (uint32_t, uint32_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(slot_type, 60, uint256{})
|
||||
|
||||
// int64_t slot_float(uint32_t slot_no);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, slot_float, (uint32_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(slot_float, 70, uint256{})
|
||||
|
||||
// int64_t state_set(uint32_t read_ptr, uint32_t read_len, uint32_t kread_ptr, uint32_t kread_len);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, state_set, (uint32_t, uint32_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(state_set, 650, uint256{})
|
||||
|
||||
// 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);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, state_foreign_set, (uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(state_foreign_set, 6000, uint256{})
|
||||
|
||||
// int64_t state(uint32_t write_ptr, uint32_t write_len, uint32_t kread_ptr, uint32_t kread_len);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, state, (uint32_t, uint32_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(state, 410, uint256{})
|
||||
|
||||
// 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);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, state_foreign, (uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(state_foreign, 430, uint256{})
|
||||
|
||||
// int64_t trace(uint32_t mread_ptr, uint32_t mread_len, uint32_t dread_ptr, uint32_t dread_len, uint32_t as_hex);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, trace, (uint32_t, uint32_t, uint32_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(trace, 240, uint256{})
|
||||
|
||||
// int64_t trace_num(uint32_t read_ptr, uint32_t read_len, int64_t number);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, trace_num, (uint32_t, uint32_t, int64_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(trace_num, 90, uint256{})
|
||||
|
||||
// int64_t trace_float(uint32_t read_ptr, uint32_t read_len, int64_t float1);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, trace_float, (uint32_t, uint32_t, int64_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(trace_float, 100, uint256{})
|
||||
|
||||
// int64_t otxn_burden();
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, otxn_burden, (),
|
||||
uint256{})
|
||||
HOOK_API_COST(otxn_burden, 70, uint256{})
|
||||
|
||||
// int64_t otxn_field(uint32_t write_ptr, uint32_t write_len, uint32_t field_id);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, otxn_field, (uint32_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(otxn_field, 70, uint256{})
|
||||
|
||||
// int64_t otxn_generation();
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, otxn_generation, (),
|
||||
uint256{})
|
||||
HOOK_API_COST(otxn_generation, 70, uint256{})
|
||||
|
||||
// int64_t otxn_id(uint32_t write_ptr, uint32_t write_len, uint32_t flags);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, otxn_id, (uint32_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(otxn_id, 60, uint256{})
|
||||
|
||||
// int64_t otxn_type();
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, otxn_type, (),
|
||||
uint256{})
|
||||
HOOK_API_COST(otxn_type, 60, uint256{})
|
||||
|
||||
// int64_t otxn_slot(uint32_t slot_no);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, otxn_slot, (uint32_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(otxn_slot, 120, uint256{})
|
||||
|
||||
// int64_t otxn_param(uint32_t write_ptr, uint32_t write_len, uint32_t read_ptr, uint32_t read_len);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, otxn_param, (uint32_t, uint32_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(otxn_param, 80, uint256{})
|
||||
|
||||
// int64_t meta_slot(uint32_t slot_no);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, meta_slot, (uint32_t),
|
||||
uint256{})
|
||||
HOOK_API_COST(meta_slot, 60, uint256{})
|
||||
|
||||
// int64_t xpop_slot(uint32_t slot_no_tx, uint32_t slot_no_meta);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, xpop_slot, (uint32_t, uint32_t),
|
||||
featureHooksUpdate1)
|
||||
HOOK_API_COST(xpop_slot, 5000, uint256{})
|
||||
|
||||
// int64_t prepare(uint32_t write_ptr, uint32_t write_len, uint32_t read_ptr, uint32_t read_len);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, prepare, (uint32_t, uint32_t, uint32_t, uint32_t),
|
||||
featureHooksUpdate2)
|
||||
HOOK_API_COST(prepare, 5600, uint256{})
|
||||
@@ -35,6 +35,8 @@ struct Fees
|
||||
XRPAmount reserve{0}; // Reserve base (drops)
|
||||
XRPAmount increment{0}; // Reserve increment (drops)
|
||||
|
||||
std::uint32_t hookGasPrice{0}; // price per cost unit for hooks
|
||||
|
||||
explicit Fees() = default;
|
||||
Fees(Fees const&) = default;
|
||||
Fees&
|
||||
|
||||
@@ -274,6 +274,12 @@ enum BridgeModifyFlags : uint32_t {
|
||||
tfClearAccountCreateAmount = 0x00010000,
|
||||
};
|
||||
constexpr std::uint32_t tfBridgeModifyMask = ~(tfUniversal | tfClearAccountCreateAmount);
|
||||
|
||||
// HookDefinitionUpdate flags:
|
||||
enum HookDefinitionUpdateFlags : uint32_t {
|
||||
tfValidateGuards = 0x00000001,
|
||||
};
|
||||
constexpr std::uint32_t tfHookDefinitionUpdateMask = ~(tfUniversal | tfValidateGuards);
|
||||
// clang-format on
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
@@ -34,6 +34,8 @@
|
||||
// If you add an amendment here, then do not forget to increment `numFeatures`
|
||||
// in include/xrpl/protocol/Feature.h.
|
||||
|
||||
XRPL_FEATURE(HookFeeV3, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(HookFeeV2, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(EscrowDestinationCancel, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (20260929, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(HookOnV2_1, Supported::yes, VoteBehavior::DefaultNo)
|
||||
|
||||
@@ -103,8 +103,10 @@ LEDGER_ENTRY(ltHOOK_DEFINITION, 'D', HookDefinition, hook_definition, ({
|
||||
{sfCreateCode, soeREQUIRED},
|
||||
{sfHookSetTxnID, soeREQUIRED},
|
||||
{sfReferenceCount, soeREQUIRED},
|
||||
{sfFee, soeREQUIRED},
|
||||
{sfFee, soeOPTIONAL},
|
||||
{sfHookCallbackFee, soeOPTIONAL},
|
||||
{sfHookCost, soeOPTIONAL},
|
||||
{sfHookCallbackCost, soeOPTIONAL},
|
||||
{sfPreviousTxnID, soeOPTIONAL},
|
||||
{sfPreviousTxnLgrSeq, soeOPTIONAL},
|
||||
}))
|
||||
@@ -420,6 +422,7 @@ LEDGER_ENTRY(ltFEE_SETTINGS, 0x0073, FeeSettings, fee, ({
|
||||
{sfXahauActivationLgrSeq, soeOPTIONAL},
|
||||
{sfAccountCount, soeOPTIONAL},
|
||||
{sfNetworkID, soeOPTIONAL},
|
||||
{sfHookGasPrice, soeOPTIONAL},
|
||||
{sfPreviousTxnID, soeOPTIONAL},
|
||||
{sfPreviousTxnLgrSeq, soeOPTIONAL},
|
||||
}))
|
||||
|
||||
@@ -115,6 +115,7 @@ TYPED_SFIELD(sfLockCount, UINT32, 49)
|
||||
TYPED_SFIELD(sfFirstNFTokenSequence, UINT32, 50)
|
||||
TYPED_SFIELD(sfOracleDocumentID, UINT32, 51)
|
||||
|
||||
TYPED_SFIELD(sfHookGasPrice, UINT32, 92)
|
||||
TYPED_SFIELD(sfStartTime, UINT32, 93)
|
||||
TYPED_SFIELD(sfRepeatCount, UINT32, 94)
|
||||
TYPED_SFIELD(sfDelaySeconds, UINT32, 95)
|
||||
@@ -153,6 +154,8 @@ TYPED_SFIELD(sfOutstandingAmount, UINT64, 25, SField::sMD_BaseTen|SFie
|
||||
TYPED_SFIELD(sfMPTAmount, UINT64, 26, SField::sMD_BaseTen|SField::sMD_Default)
|
||||
TYPED_SFIELD(sfIssuerNode, UINT64, 27)
|
||||
TYPED_SFIELD(sfSubjectNode, UINT64, 28)
|
||||
TYPED_SFIELD(sfHookCost, UINT64, 95)
|
||||
TYPED_SFIELD(sfHookCallbackCost, UINT64, 96)
|
||||
TYPED_SFIELD(sfTouchCount, UINT64, 97)
|
||||
TYPED_SFIELD(sfAccountIndex, UINT64, 98)
|
||||
TYPED_SFIELD(sfAccountCount, UINT64, 99)
|
||||
|
||||
@@ -500,6 +500,11 @@ TRANSACTION(ttPERMISSIONED_DOMAIN_DELETE, 72, PermissionedDomainDelete, ({
|
||||
{sfDomainID, soeREQUIRED},
|
||||
}))
|
||||
|
||||
/** This transaction type updates a hook definition */
|
||||
TRANSACTION(ttHOOK_DEFINITION_UPDATE, 90, HookDefinitionUpdate, ({
|
||||
{sfHookHash, soeREQUIRED},
|
||||
|
||||
}))
|
||||
/* sfAccount is supplied by TxFormats::commonFields; listing it here as well
|
||||
makes the SOTemplate reject the format at construction. */
|
||||
TRANSACTION(ttMANIFEST_SET, 91, SetManifest, ({
|
||||
@@ -590,6 +595,8 @@ TRANSACTION(ttFEE, 101, SetFee, ({
|
||||
{sfBaseFeeDrops, soeOPTIONAL},
|
||||
{sfReserveBaseDrops, soeOPTIONAL},
|
||||
{sfReserveIncrementDrops, soeOPTIONAL},
|
||||
// HookCost
|
||||
{sfHookGasPrice, soeOPTIONAL},
|
||||
}))
|
||||
|
||||
/** This system-generated transaction type is used to update the network's negative UNL
|
||||
|
||||
@@ -358,6 +358,7 @@ JSS(highest_sequence); // out: AccountInfo
|
||||
JSS(highest_ticket); // out: AccountInfo
|
||||
JSS(historical_perminute); // historical_perminute.
|
||||
JSS(holders); // out: MPTHolders
|
||||
JSS(hook_gas_price); //
|
||||
JSS(hostid); // out: NetworkOPs
|
||||
JSS(hotwallet); // in: GatewayBalances
|
||||
JSS(id); // websocket.
|
||||
|
||||
@@ -66,6 +66,8 @@ STValidation::validationFormat()
|
||||
{sfBaseFeeDrops, soeOPTIONAL},
|
||||
{sfReserveBaseDrops, soeOPTIONAL},
|
||||
{sfReserveIncrementDrops, soeOPTIONAL},
|
||||
// HookCost
|
||||
{sfHookGasPrice, soeOPTIONAL},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -1407,7 +1407,8 @@ private:
|
||||
{
|
||||
using namespace jtx;
|
||||
FeatureBitset const all{
|
||||
supported_amendments() | featureAMM | featureAMMClawback};
|
||||
(supported_amendments() | featureAMM | featureAMMClawback) -
|
||||
featureHookFeeV3};
|
||||
testRmFundedOffer(all);
|
||||
testEnforceNoRipple(all);
|
||||
testFillModes(all);
|
||||
@@ -3217,7 +3218,9 @@ private:
|
||||
testcase("RippleState Freeze");
|
||||
|
||||
using namespace test::jtx;
|
||||
Env env(*this, features - featureXahauGenesis - featureTouch);
|
||||
Env env(
|
||||
*this,
|
||||
features - featureXahauGenesis - featureTouch - featureHookFeeV3);
|
||||
|
||||
Account const G1{"G1"};
|
||||
Account const alice{"alice"};
|
||||
|
||||
@@ -37,36 +37,42 @@ class FeeVote_test : public beast::unit_test::suite
|
||||
BEAST_EXPECT(setup.reference_fee == defaultSetup.reference_fee);
|
||||
BEAST_EXPECT(setup.account_reserve == defaultSetup.account_reserve);
|
||||
BEAST_EXPECT(setup.owner_reserve == defaultSetup.owner_reserve);
|
||||
BEAST_EXPECT(setup.hook_gas_price == defaultSetup.hook_gas_price);
|
||||
}
|
||||
{
|
||||
Section config;
|
||||
config.append(
|
||||
{"reference_fee = 50",
|
||||
"account_reserve = 1234567",
|
||||
"owner_reserve = 1234"});
|
||||
"owner_reserve = 1234",
|
||||
"hook_gas_price = 12345"});
|
||||
auto setup = setup_FeeVote(config);
|
||||
BEAST_EXPECT(setup.reference_fee == 50);
|
||||
BEAST_EXPECT(setup.account_reserve == 1234567);
|
||||
BEAST_EXPECT(setup.owner_reserve == 1234);
|
||||
BEAST_EXPECT(setup.hook_gas_price == 12345);
|
||||
}
|
||||
{
|
||||
Section config;
|
||||
config.append(
|
||||
{"reference_fee = blah",
|
||||
"account_reserve = yada",
|
||||
"owner_reserve = foo"});
|
||||
"owner_reserve = foo",
|
||||
"hook_gas_price = baa"});
|
||||
// Illegal values are ignored, and the defaults left unchanged
|
||||
auto setup = setup_FeeVote(config);
|
||||
BEAST_EXPECT(setup.reference_fee == defaultSetup.reference_fee);
|
||||
BEAST_EXPECT(setup.account_reserve == defaultSetup.account_reserve);
|
||||
BEAST_EXPECT(setup.owner_reserve == defaultSetup.owner_reserve);
|
||||
BEAST_EXPECT(setup.hook_gas_price == defaultSetup.hook_gas_price);
|
||||
}
|
||||
{
|
||||
Section config;
|
||||
config.append(
|
||||
{"reference_fee = -50",
|
||||
"account_reserve = -1234567",
|
||||
"owner_reserve = -1234"});
|
||||
"owner_reserve = -1234",
|
||||
"hook_gas_price = -12345"});
|
||||
// Illegal values are ignored, and the defaults left unchanged
|
||||
auto setup = setup_FeeVote(config);
|
||||
BEAST_EXPECT(setup.reference_fee == defaultSetup.reference_fee);
|
||||
@@ -74,6 +80,8 @@ class FeeVote_test : public beast::unit_test::suite
|
||||
setup.account_reserve == static_cast<std::uint32_t>(-1234567));
|
||||
BEAST_EXPECT(
|
||||
setup.owner_reserve == static_cast<std::uint32_t>(-1234));
|
||||
BEAST_EXPECT(
|
||||
setup.hook_gas_price == static_cast<std::uint32_t>(-12345));
|
||||
}
|
||||
{
|
||||
const auto big64 = std::to_string(
|
||||
@@ -84,12 +92,14 @@ class FeeVote_test : public beast::unit_test::suite
|
||||
config.append(
|
||||
{"reference_fee = " + big64,
|
||||
"account_reserve = " + big64,
|
||||
"owner_reserve = " + big64});
|
||||
"owner_reserve = " + big64,
|
||||
"hook_gas_price = " + big64});
|
||||
// Illegal values are ignored, and the defaults left unchanged
|
||||
auto setup = setup_FeeVote(config);
|
||||
BEAST_EXPECT(setup.reference_fee == defaultSetup.reference_fee);
|
||||
BEAST_EXPECT(setup.account_reserve == defaultSetup.account_reserve);
|
||||
BEAST_EXPECT(setup.owner_reserve == defaultSetup.owner_reserve);
|
||||
BEAST_EXPECT(setup.hook_gas_price == defaultSetup.hook_gas_price);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -682,6 +682,7 @@ public:
|
||||
auto const sa = supported_amendments();
|
||||
testWithFeats(sa);
|
||||
testWithFeats(sa - fixHookAPI20251128);
|
||||
testWithFeats(sa - featureHookFeeV2);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,166 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2023 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 S
|
||||
OFTWARE 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 <test/jtx.h>
|
||||
#include <test/jtx/genesis.h>
|
||||
#include <test/jtx/hook.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace test {
|
||||
|
||||
class HookDefinitionUpdate_test : public beast::unit_test::suite
|
||||
{
|
||||
static Json::Value
|
||||
hookDefUpdateTx(
|
||||
jtx::Account const& account,
|
||||
std::string const& hookHash,
|
||||
uint32_t flags = tfValidateGuards)
|
||||
{
|
||||
using namespace jtx;
|
||||
Json::Value jv;
|
||||
jv[jss::TransactionType] = jss::HookDefinitionUpdate;
|
||||
jv[jss::Account] = account.human();
|
||||
jv[jss::HookHash] = hookHash;
|
||||
jv[jss::Flags] = flags;
|
||||
return jv;
|
||||
}
|
||||
|
||||
void
|
||||
testInvalidPreflight(FeatureBitset features)
|
||||
{
|
||||
testcase("hook definition update invalid preflight");
|
||||
|
||||
using namespace test::jtx;
|
||||
|
||||
auto const alice = Account("alice");
|
||||
|
||||
// temDISABLED
|
||||
{
|
||||
Env env{*this, features - featureHookFeeV2};
|
||||
env.fund(XRP(1000), alice);
|
||||
env.close();
|
||||
|
||||
env(hookDefUpdateTx(alice, ""), ter(temDISABLED));
|
||||
}
|
||||
|
||||
// temINVALID_FLAG
|
||||
{
|
||||
Env env{*this, features};
|
||||
env.fund(XRP(1000), alice);
|
||||
env.close();
|
||||
|
||||
env(hookDefUpdateTx(alice, "", 0x00000002), ter(temINVALID_FLAG));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testInvalidPreclaim(FeatureBitset features)
|
||||
{
|
||||
testcase("hook definition update invalid preclaim");
|
||||
|
||||
using namespace test::jtx;
|
||||
auto const alice = Account("alice");
|
||||
|
||||
// tecNO_ENTRY
|
||||
{
|
||||
Env env{*this};
|
||||
env.fund(XRP(1000), alice);
|
||||
env.close();
|
||||
|
||||
env(hookDefUpdateTx(alice, ""), ter(tecNO_ENTRY));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testDoApply(FeatureBitset features)
|
||||
{
|
||||
testcase("hook definition update do apply");
|
||||
|
||||
using namespace test::jtx;
|
||||
auto const alice = Account("alice");
|
||||
|
||||
Env env{*this, features - featureHookFeeV2};
|
||||
env.fund(XRP(1000), alice);
|
||||
env.close();
|
||||
|
||||
auto const hookCode = jtx::genesis::AcceptHook;
|
||||
uint256 const hash = ripple::sha512Half_s(
|
||||
ripple::Slice(hookCode.data(), hookCode.size()));
|
||||
|
||||
// prepare: Create Hook Definition without HookFeeV2
|
||||
auto hookObj = hso(hookCode);
|
||||
env(hook(alice, {{hookObj}}, 0), fee(XRP(1)));
|
||||
env.close();
|
||||
// prepare: enable HookFeeV2
|
||||
env.enableFeature(featureHookFeeV2);
|
||||
env.close();
|
||||
|
||||
// 1. Update Hook Definition (Fee -> Cost)
|
||||
{
|
||||
auto leb = env.le(keylet::hookDefinition(hash));
|
||||
BEAST_EXPECT(leb->isFieldPresent(sfFee));
|
||||
BEAST_EXPECT(!leb->isFieldPresent(sfHookCost));
|
||||
env(hookDefUpdateTx(alice, to_string(hash)), fee(XRP(1)));
|
||||
env.close();
|
||||
|
||||
auto lea = env.le(keylet::hookDefinition(hash));
|
||||
BEAST_EXPECT(lea->isFieldPresent(sfHookCost));
|
||||
BEAST_EXPECT(!lea->isFieldPresent(sfFee));
|
||||
}
|
||||
// 2. Update Hook Definition (Cost -> Cost)
|
||||
{
|
||||
env(hookDefUpdateTx(alice, to_string(hash)), fee(XRP(1)));
|
||||
env.close();
|
||||
auto const meta = env.meta();
|
||||
BEAST_EXPECT(meta->isFieldPresent(sfAffectedNodes));
|
||||
|
||||
auto& nodes = meta->getFieldArray(sfAffectedNodes);
|
||||
BEAST_EXPECT(nodes.size() == 1);
|
||||
// no update for ltHookDefinition
|
||||
BEAST_EXPECT(
|
||||
nodes[0].getFieldU16(sfLedgerEntryType) == ltACCOUNT_ROOT);
|
||||
}
|
||||
|
||||
// TODO: test callback cost
|
||||
}
|
||||
|
||||
public:
|
||||
void
|
||||
run() override
|
||||
{
|
||||
using namespace test::jtx;
|
||||
FeatureBitset const all{supported_amendments()};
|
||||
testWithFeats(all);
|
||||
}
|
||||
|
||||
void
|
||||
testWithFeats(FeatureBitset features)
|
||||
{
|
||||
testInvalidPreflight(features);
|
||||
testInvalidPreclaim(features);
|
||||
testDoApply(features);
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(HookDefinitionUpdate, app, ripple);
|
||||
|
||||
} // namespace test
|
||||
} // namespace ripple
|
||||
@@ -6072,7 +6072,14 @@ class Import_test : public beast::unit_test::suite
|
||||
test::jtx::Env env{
|
||||
*this,
|
||||
network::makeGenesisConfig(
|
||||
features, 21337, keys, "10", "1000000", "200000", 1999998),
|
||||
features,
|
||||
21337,
|
||||
keys,
|
||||
"10",
|
||||
"1000000",
|
||||
"200000",
|
||||
"1000000",
|
||||
1999998),
|
||||
features};
|
||||
|
||||
// confirm total coins header
|
||||
@@ -6116,7 +6123,14 @@ class Import_test : public beast::unit_test::suite
|
||||
test::jtx::Env env{
|
||||
*this,
|
||||
network::makeGenesisConfig(
|
||||
features, 21337, keys, "10", "1000000", "200000", 1999998),
|
||||
features,
|
||||
21337,
|
||||
keys,
|
||||
"10",
|
||||
"1000000",
|
||||
"200000",
|
||||
"1000000",
|
||||
1999998),
|
||||
features};
|
||||
|
||||
// confirm total coins header
|
||||
@@ -6161,7 +6175,14 @@ class Import_test : public beast::unit_test::suite
|
||||
test::jtx::Env env{
|
||||
*this,
|
||||
network::makeGenesisConfig(
|
||||
features, 21337, keys, "10", "1000000", "200000", 1999998),
|
||||
features,
|
||||
21337,
|
||||
keys,
|
||||
"10",
|
||||
"1000000",
|
||||
"200000",
|
||||
"1000000",
|
||||
1999998),
|
||||
features};
|
||||
|
||||
// confirm total coins header
|
||||
@@ -6207,7 +6228,14 @@ class Import_test : public beast::unit_test::suite
|
||||
test::jtx::Env env{
|
||||
*this,
|
||||
network::makeGenesisConfig(
|
||||
features, 21337, keys, "10", "1000000", "200000", 4999999),
|
||||
features,
|
||||
21337,
|
||||
keys,
|
||||
"10",
|
||||
"1000000",
|
||||
"200000",
|
||||
"1000000",
|
||||
4999999),
|
||||
features};
|
||||
|
||||
// confirm total coins header
|
||||
@@ -6251,7 +6279,14 @@ class Import_test : public beast::unit_test::suite
|
||||
test::jtx::Env env{
|
||||
*this,
|
||||
network::makeGenesisConfig(
|
||||
features, 21337, keys, "10", "1000000", "200000", 19999999),
|
||||
features,
|
||||
21337,
|
||||
keys,
|
||||
"10",
|
||||
"1000000",
|
||||
"200000",
|
||||
"1000000",
|
||||
19999999),
|
||||
features};
|
||||
|
||||
// confirm total coins header
|
||||
@@ -6295,7 +6330,14 @@ class Import_test : public beast::unit_test::suite
|
||||
test::jtx::Env env{
|
||||
*this,
|
||||
network::makeGenesisConfig(
|
||||
features, 21337, keys, "10", "1000000", "200000", 29999998),
|
||||
features,
|
||||
21337,
|
||||
keys,
|
||||
"10",
|
||||
"1000000",
|
||||
"200000",
|
||||
"1000000",
|
||||
29999998),
|
||||
features};
|
||||
|
||||
// confirm total coins header
|
||||
@@ -6339,7 +6381,14 @@ class Import_test : public beast::unit_test::suite
|
||||
test::jtx::Env env{
|
||||
*this,
|
||||
network::makeGenesisConfig(
|
||||
features, 21337, keys, "10", "1000000", "200000", 29999998),
|
||||
features,
|
||||
21337,
|
||||
keys,
|
||||
"10",
|
||||
"1000000",
|
||||
"200000",
|
||||
"1000000",
|
||||
29999998),
|
||||
features};
|
||||
|
||||
// confirm total coins header
|
||||
@@ -6382,7 +6431,14 @@ class Import_test : public beast::unit_test::suite
|
||||
test::jtx::Env env{
|
||||
*this,
|
||||
network::makeGenesisConfig(
|
||||
features, 21337, keys, "10", "1000000", "200000", 50000000),
|
||||
features,
|
||||
21337,
|
||||
keys,
|
||||
"10",
|
||||
"1000000",
|
||||
"200000",
|
||||
"1000000",
|
||||
50000000),
|
||||
features};
|
||||
|
||||
// confirm total coins header
|
||||
|
||||
@@ -4913,9 +4913,11 @@ private:
|
||||
env.close(std::chrono::seconds(300));
|
||||
Oracle oracle(
|
||||
env,
|
||||
{.owner = account,
|
||||
.series = {{"XRP", "USD", 740, 1}},
|
||||
.fee = 10000});
|
||||
{
|
||||
.owner = account,
|
||||
.series = {{"XRP", "USD", 740, 1}},
|
||||
.fee = 1'000'000,
|
||||
});
|
||||
|
||||
// verify tsh hook triggered
|
||||
testTSHStrongWeak(env, tshSTRONG, __LINE__);
|
||||
@@ -4952,6 +4954,7 @@ private:
|
||||
{
|
||||
.owner = account,
|
||||
.series = {{"XRP", "USD", 740, 1}},
|
||||
.fee = 1'000'000,
|
||||
});
|
||||
|
||||
// set tsh collect
|
||||
@@ -4964,7 +4967,7 @@ private:
|
||||
// delete oracle
|
||||
oracle.remove(oracle::RemoveArg{
|
||||
.documentID = oracle.documentID(),
|
||||
.fee = 10000,
|
||||
.fee = 1'000'000,
|
||||
});
|
||||
|
||||
// verify tsh hook triggered
|
||||
@@ -8248,6 +8251,15 @@ private:
|
||||
testTSHStrongWeak(env, tx->getTransactionID(), expected, __LINE__);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testHookDefinitionUpdateTSH(FeatureBitset features)
|
||||
{
|
||||
testcase("hook definition update tsh");
|
||||
// TODO
|
||||
BEAST_EXPECT(true);
|
||||
}
|
||||
|
||||
void
|
||||
testEmissionOrdering(FeatureBitset features)
|
||||
{
|
||||
@@ -8535,9 +8547,10 @@ public:
|
||||
using namespace test::jtx;
|
||||
static FeatureBitset const all{supported_amendments()};
|
||||
|
||||
static std::array<FeatureBitset, 3> const feats{
|
||||
static std::array<FeatureBitset, 4> const feats{
|
||||
all,
|
||||
all - featureEscrowDestinationCancel,
|
||||
all - featureHookFeeV2,
|
||||
all - featureIOUIssuerWeakTSH,
|
||||
};
|
||||
|
||||
@@ -8568,11 +8581,13 @@ public:
|
||||
};
|
||||
|
||||
SETHOOKTSH_TEST(1, false)
|
||||
SETHOOKTSH_TEST(2, true)
|
||||
SETHOOKTSH_TEST(2, false)
|
||||
SETHOOKTSH_TEST(3, true)
|
||||
|
||||
BEAST_DEFINE_TESTSUITE_PRIO(SetHookTSH0, app, ripple, 2);
|
||||
BEAST_DEFINE_TESTSUITE_PRIO(SetHookTSH1, app, ripple, 2);
|
||||
BEAST_DEFINE_TESTSUITE_PRIO(SetHookTSH2, app, ripple, 2);
|
||||
BEAST_DEFINE_TESTSUITE_PRIO(SetHookTSH3, app, ripple, 2);
|
||||
|
||||
} // namespace test
|
||||
} // namespace ripple
|
||||
+563
-31
File diff suppressed because it is too large.
Load diff
+259
-141
@@ -594,6 +594,109 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
|
||||
0x6AU, 0x24U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x20U, 0x05U, 0x0BU,
|
||||
}},
|
||||
|
||||
{R"[test.hook](
|
||||
#include <stdint.h>
|
||||
extern int32_t _g (uint32_t id, uint32_t maxiter);
|
||||
#define GUARD(maxiter) _g((1ULL << 31U) + __LINE__, (maxiter)+1)
|
||||
extern int64_t accept (uint32_t read_ptr, uint32_t read_len, int64_t error_code);
|
||||
extern int64_t hook_account (uint32_t, uint32_t);
|
||||
int64_t hook(uint32_t reserved)
|
||||
{
|
||||
uint8_t acc[20];
|
||||
for (int i = 0; i < 10; ++i)
|
||||
{
|
||||
_g(1, 11);
|
||||
for (int j = 0; j < 2; ++j)
|
||||
{
|
||||
_g(2, 30);
|
||||
for (int k = 0; k < 5; ++k)
|
||||
{
|
||||
_g(3, 120);
|
||||
hook_account(acc, 20);
|
||||
}
|
||||
for (int k = 0; k < 5; ++k)
|
||||
{
|
||||
_g(4, 120);
|
||||
hook_account(acc, 20);
|
||||
}
|
||||
}
|
||||
}
|
||||
return accept(0,0,2);
|
||||
}
|
||||
)[test.hook]",
|
||||
{
|
||||
0x00U, 0x61U, 0x73U, 0x6DU, 0x01U, 0x00U, 0x00U, 0x00U, 0x01U, 0x19U,
|
||||
0x04U, 0x60U, 0x02U, 0x7FU, 0x7FU, 0x01U, 0x7FU, 0x60U, 0x02U, 0x7FU,
|
||||
0x7FU, 0x01U, 0x7EU, 0x60U, 0x03U, 0x7FU, 0x7FU, 0x7EU, 0x01U, 0x7EU,
|
||||
0x60U, 0x01U, 0x7FU, 0x01U, 0x7EU, 0x02U, 0x2AU, 0x03U, 0x03U, 0x65U,
|
||||
0x6EU, 0x76U, 0x02U, 0x5FU, 0x67U, 0x00U, 0x00U, 0x03U, 0x65U, 0x6EU,
|
||||
0x76U, 0x0CU, 0x68U, 0x6FU, 0x6FU, 0x6BU, 0x5FU, 0x61U, 0x63U, 0x63U,
|
||||
0x6FU, 0x75U, 0x6EU, 0x74U, 0x00U, 0x01U, 0x03U, 0x65U, 0x6EU, 0x76U,
|
||||
0x06U, 0x61U, 0x63U, 0x63U, 0x65U, 0x70U, 0x74U, 0x00U, 0x02U, 0x03U,
|
||||
0x02U, 0x01U, 0x03U, 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, 0x08U, 0x01U, 0x04U, 0x68U, 0x6FU, 0x6FU,
|
||||
0x6BU, 0x00U, 0x03U, 0x0AU, 0xB3U, 0x84U, 0x00U, 0x01U, 0xAFU, 0x84U,
|
||||
0x00U, 0x02U, 0x02U, 0x7FU, 0x01U, 0x7EU, 0x23U, 0x80U, 0x80U, 0x80U,
|
||||
0x80U, 0x00U, 0x41U, 0x20U, 0x6BU, 0x22U, 0x01U, 0x24U, 0x80U, 0x80U,
|
||||
0x80U, 0x80U, 0x00U, 0x41U, 0x0AU, 0x21U, 0x02U, 0x03U, 0x40U, 0x41U,
|
||||
0x01U, 0x41U, 0x0BU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU,
|
||||
0x41U, 0x02U, 0x41U, 0x1EU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U,
|
||||
0x1AU, 0x41U, 0x03U, 0x41U, 0xF8U, 0x00U, 0x10U, 0x80U, 0x80U, 0x80U,
|
||||
0x80U, 0x00U, 0x1AU, 0x20U, 0x01U, 0x41U, 0x14U, 0x10U, 0x81U, 0x80U,
|
||||
0x80U, 0x80U, 0x00U, 0x1AU, 0x41U, 0x03U, 0x41U, 0xF8U, 0x00U, 0x10U,
|
||||
0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x20U, 0x01U, 0x41U, 0x14U,
|
||||
0x10U, 0x81U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x41U, 0x03U, 0x41U,
|
||||
0xF8U, 0x00U, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x20U,
|
||||
0x01U, 0x41U, 0x14U, 0x10U, 0x81U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU,
|
||||
0x41U, 0x03U, 0x41U, 0xF8U, 0x00U, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U,
|
||||
0x00U, 0x1AU, 0x20U, 0x01U, 0x41U, 0x14U, 0x10U, 0x81U, 0x80U, 0x80U,
|
||||
0x80U, 0x00U, 0x1AU, 0x41U, 0x03U, 0x41U, 0xF8U, 0x00U, 0x10U, 0x80U,
|
||||
0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x20U, 0x01U, 0x41U, 0x14U, 0x10U,
|
||||
0x81U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x41U, 0x04U, 0x41U, 0xF8U,
|
||||
0x00U, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x20U, 0x01U,
|
||||
0x41U, 0x14U, 0x10U, 0x81U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x41U,
|
||||
0x04U, 0x41U, 0xF8U, 0x00U, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U,
|
||||
0x1AU, 0x20U, 0x01U, 0x41U, 0x14U, 0x10U, 0x81U, 0x80U, 0x80U, 0x80U,
|
||||
0x00U, 0x1AU, 0x41U, 0x04U, 0x41U, 0xF8U, 0x00U, 0x10U, 0x80U, 0x80U,
|
||||
0x80U, 0x80U, 0x00U, 0x1AU, 0x20U, 0x01U, 0x41U, 0x14U, 0x10U, 0x81U,
|
||||
0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x41U, 0x04U, 0x41U, 0xF8U, 0x00U,
|
||||
0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x20U, 0x01U, 0x41U,
|
||||
0x14U, 0x10U, 0x81U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x41U, 0x04U,
|
||||
0x41U, 0xF8U, 0x00U, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU,
|
||||
0x20U, 0x01U, 0x41U, 0x14U, 0x10U, 0x81U, 0x80U, 0x80U, 0x80U, 0x00U,
|
||||
0x1AU, 0x41U, 0x02U, 0x41U, 0x1EU, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U,
|
||||
0x00U, 0x1AU, 0x41U, 0x03U, 0x41U, 0xF8U, 0x00U, 0x10U, 0x80U, 0x80U,
|
||||
0x80U, 0x80U, 0x00U, 0x1AU, 0x20U, 0x01U, 0x41U, 0x14U, 0x10U, 0x81U,
|
||||
0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x41U, 0x03U, 0x41U, 0xF8U, 0x00U,
|
||||
0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x20U, 0x01U, 0x41U,
|
||||
0x14U, 0x10U, 0x81U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x41U, 0x03U,
|
||||
0x41U, 0xF8U, 0x00U, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU,
|
||||
0x20U, 0x01U, 0x41U, 0x14U, 0x10U, 0x81U, 0x80U, 0x80U, 0x80U, 0x00U,
|
||||
0x1AU, 0x41U, 0x03U, 0x41U, 0xF8U, 0x00U, 0x10U, 0x80U, 0x80U, 0x80U,
|
||||
0x80U, 0x00U, 0x1AU, 0x20U, 0x01U, 0x41U, 0x14U, 0x10U, 0x81U, 0x80U,
|
||||
0x80U, 0x80U, 0x00U, 0x1AU, 0x41U, 0x03U, 0x41U, 0xF8U, 0x00U, 0x10U,
|
||||
0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x20U, 0x01U, 0x41U, 0x14U,
|
||||
0x10U, 0x81U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x41U, 0x04U, 0x41U,
|
||||
0xF8U, 0x00U, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x20U,
|
||||
0x01U, 0x41U, 0x14U, 0x10U, 0x81U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU,
|
||||
0x41U, 0x04U, 0x41U, 0xF8U, 0x00U, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U,
|
||||
0x00U, 0x1AU, 0x20U, 0x01U, 0x41U, 0x14U, 0x10U, 0x81U, 0x80U, 0x80U,
|
||||
0x80U, 0x00U, 0x1AU, 0x41U, 0x04U, 0x41U, 0xF8U, 0x00U, 0x10U, 0x80U,
|
||||
0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x20U, 0x01U, 0x41U, 0x14U, 0x10U,
|
||||
0x81U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x41U, 0x04U, 0x41U, 0xF8U,
|
||||
0x00U, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x20U, 0x01U,
|
||||
0x41U, 0x14U, 0x10U, 0x81U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x41U,
|
||||
0x04U, 0x41U, 0xF8U, 0x00U, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U,
|
||||
0x1AU, 0x20U, 0x01U, 0x41U, 0x14U, 0x10U, 0x81U, 0x80U, 0x80U, 0x80U,
|
||||
0x00U, 0x1AU, 0x20U, 0x02U, 0x41U, 0x7FU, 0x6AU, 0x22U, 0x02U, 0x0DU,
|
||||
0x00U, 0x0BU, 0x41U, 0x00U, 0x41U, 0x00U, 0x42U, 0x02U, 0x10U, 0x82U,
|
||||
0x80U, 0x80U, 0x80U, 0x00U, 0x21U, 0x03U, 0x20U, 0x01U, 0x41U, 0x20U,
|
||||
0x6AU, 0x24U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x20U, 0x03U, 0x0BU,
|
||||
}},
|
||||
|
||||
{R"[test.hook](
|
||||
#include <stdint.h>
|
||||
extern int32_t _g(uint32_t, uint32_t);
|
||||
@@ -1669,13 +1772,21 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
|
||||
etxn_reserve(1);
|
||||
ASSERT(etxn_details((uint32_t)det, 116) == 116);
|
||||
|
||||
uint8_t expected1[49] = {
|
||||
uint8_t expected1[16] = {
|
||||
0xEDU, 0x20U, 0x2EU, 0x00U, 0x00U, 0x00U, 0x01U, 0x3DU, 0x00U, 0x00U,
|
||||
0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x01U, 0x5BU, 0xBCU, 0x09U, 0x95U,
|
||||
0xFDU, 0x03U, 0x0FU, 0xF1U, 0x85U, 0xF4U, 0xECU, 0xACU, 0x94U, 0xDBU,
|
||||
0x02U, 0x19U, 0x26U, 0xFEU, 0x58U, 0xD4U, 0x8DU, 0x48U, 0x21U, 0xCCU,
|
||||
0x82U, 0x2EU, 0x4AU, 0x6AU, 0xC9U, 0xC8U, 0xC6U, 0x7CU, 0x88U
|
||||
};
|
||||
// 0x5B
|
||||
// EmitParentTxnID 32bytes
|
||||
uint8_t expected_emit_parent_txn_id[32] = {
|
||||
0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU,
|
||||
0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU,
|
||||
0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU,
|
||||
0xFFU, 0xFFU
|
||||
};
|
||||
// 0x5CU
|
||||
// EmitNonce 32bytes
|
||||
uint8_t expected_emit_nonce[32] = {
|
||||
@@ -1697,10 +1808,14 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
|
||||
// current hook hash
|
||||
ASSERT(hook_hash((uint32_t)expected_hook_hash, 32, -1) == 32);
|
||||
|
||||
for (int i = 0; GUARD(49), i < sizeof(expected1); ++i)
|
||||
for (int i = 0; GUARD(16), i < sizeof(expected1); ++i)
|
||||
ASSERT(det[i] == expected1[i]);
|
||||
ASSERT(det[16] == 0x5BU);
|
||||
// TODO: need to test EmitParentTxnID
|
||||
// for (int i = 0; GUARD(32), i < sizeof(expected_emit_parent_txn_id); ++i)
|
||||
// ASSERT(det[17 + i] == expected_emit_parent_txn_id[i]);
|
||||
ASSERT(det[49] == 0x5CU);
|
||||
// TODO: need to test this
|
||||
// TODO: need to test EmitNonce
|
||||
// for (int i = 0; GUARD(32), i < sizeof(expected_emit_nonce); ++i)
|
||||
// ASSERT(det[50 + i] == expected_emit_nonce[i]);
|
||||
ASSERT(det[82] == 0x5DU);
|
||||
@@ -1727,11 +1842,11 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
|
||||
0x68U, 0x00U, 0x04U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x06U, 0x61U, 0x63U,
|
||||
0x63U, 0x65U, 0x70U, 0x74U, 0x00U, 0x02U, 0x03U, 0x02U, 0x01U, 0x03U,
|
||||
0x05U, 0x03U, 0x01U, 0x00U, 0x02U, 0x06U, 0x21U, 0x05U, 0x7FU, 0x01U,
|
||||
0x41U, 0xD0U, 0x8BU, 0x04U, 0x0BU, 0x7FU, 0x00U, 0x41U, 0xC6U, 0x0BU,
|
||||
0x41U, 0xC0U, 0x8BU, 0x04U, 0x0BU, 0x7FU, 0x00U, 0x41U, 0xB6U, 0x0BU,
|
||||
0x0BU, 0x7FU, 0x00U, 0x41U, 0x80U, 0x08U, 0x0BU, 0x7FU, 0x00U, 0x41U,
|
||||
0xD0U, 0x8BU, 0x04U, 0x0BU, 0x7FU, 0x00U, 0x41U, 0x80U, 0x08U, 0x0BU,
|
||||
0xC0U, 0x8BU, 0x04U, 0x0BU, 0x7FU, 0x00U, 0x41U, 0x80U, 0x08U, 0x0BU,
|
||||
0x07U, 0x08U, 0x01U, 0x04U, 0x68U, 0x6FU, 0x6FU, 0x6BU, 0x00U, 0x06U,
|
||||
0x0AU, 0xF4U, 0x84U, 0x00U, 0x01U, 0xF0U, 0x84U, 0x00U, 0x02U, 0x03U,
|
||||
0x0AU, 0x97U, 0x85U, 0x00U, 0x01U, 0x93U, 0x85U, 0x00U, 0x02U, 0x03U,
|
||||
0x7FU, 0x01U, 0x7EU, 0x23U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x41U,
|
||||
0xA0U, 0x01U, 0x6BU, 0x22U, 0x01U, 0x24U, 0x80U, 0x80U, 0x80U, 0x80U,
|
||||
0x00U, 0x41U, 0x01U, 0x41U, 0x01U, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U,
|
||||
@@ -1760,87 +1875,89 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
|
||||
0x7FU, 0x37U, 0x03U, 0x00U, 0x20U, 0x01U, 0x42U, 0x7FU, 0x37U, 0x03U,
|
||||
0x08U, 0x20U, 0x01U, 0x42U, 0x7FU, 0x37U, 0x03U, 0x00U, 0x02U, 0x40U,
|
||||
0x20U, 0x01U, 0x41U, 0x20U, 0x41U, 0x7FU, 0x10U, 0x84U, 0x80U, 0x80U,
|
||||
0x80U, 0x00U, 0x42U, 0x20U, 0x51U, 0x0DU, 0x00U, 0x41U, 0xA1U, 0x8AU,
|
||||
0x80U, 0x80U, 0x00U, 0x41U, 0x36U, 0x42U, 0x3AU, 0x10U, 0x82U, 0x80U,
|
||||
0x80U, 0x80U, 0x00U, 0x1AU, 0x0BU, 0x41U, 0xBCU, 0x80U, 0x80U, 0x80U,
|
||||
0x78U, 0x41U, 0x32U, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU,
|
||||
0x41U, 0x00U, 0x21U, 0x02U, 0x03U, 0x40U, 0x41U, 0xBCU, 0x80U, 0x80U,
|
||||
0x80U, 0x78U, 0x41U, 0x32U, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U,
|
||||
0x1AU, 0x02U, 0x40U, 0x20U, 0x01U, 0x41U, 0x20U, 0x6AU, 0x20U, 0x02U,
|
||||
0x6AU, 0x2DU, 0x00U, 0x00U, 0x20U, 0x02U, 0x41U, 0xF0U, 0x89U, 0x80U,
|
||||
0x80U, 0x00U, 0x6AU, 0x2DU, 0x00U, 0x00U, 0x46U, 0x0DU, 0x00U, 0x41U,
|
||||
0xD7U, 0x8AU, 0x80U, 0x80U, 0x00U, 0x41U, 0x17U, 0x42U, 0x3DU, 0x10U,
|
||||
0x82U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x0BU, 0x20U, 0x02U, 0x41U,
|
||||
0x01U, 0x6AU, 0x22U, 0x02U, 0x41U, 0x31U, 0x47U, 0x0DU, 0x00U, 0x0BU,
|
||||
0x02U, 0x40U, 0x20U, 0x01U, 0x2DU, 0x00U, 0x51U, 0x41U, 0xDCU, 0x00U,
|
||||
0x46U, 0x0DU, 0x00U, 0x41U, 0xEEU, 0x8AU, 0x80U, 0x80U, 0x00U, 0x41U,
|
||||
0x11U, 0x42U, 0x3EU, 0x10U, 0x82U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU,
|
||||
0x0BU, 0x02U, 0x40U, 0x20U, 0x01U, 0x2DU, 0x00U, 0x72U, 0x41U, 0xDDU,
|
||||
0x00U, 0x46U, 0x0DU, 0x00U, 0x41U, 0xFFU, 0x8AU, 0x80U, 0x80U, 0x00U,
|
||||
0x41U, 0x11U, 0x42U, 0xC2U, 0x00U, 0x10U, 0x82U, 0x80U, 0x80U, 0x80U,
|
||||
0x00U, 0x1AU, 0x0BU, 0x41U, 0xC3U, 0x80U, 0x80U, 0x80U, 0x78U, 0x41U,
|
||||
0x21U, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x20U, 0x01U,
|
||||
0x41U, 0xF3U, 0x00U, 0x6AU, 0x21U, 0x03U, 0x41U, 0x00U, 0x21U, 0x02U,
|
||||
0x03U, 0x40U, 0x41U, 0xC3U, 0x80U, 0x80U, 0x80U, 0x78U, 0x41U, 0x21U,
|
||||
0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x02U, 0x40U, 0x20U,
|
||||
0x03U, 0x20U, 0x02U, 0x6AU, 0x2DU, 0x00U, 0x00U, 0x20U, 0x01U, 0x20U,
|
||||
0x02U, 0x6AU, 0x2DU, 0x00U, 0x00U, 0x46U, 0x0DU, 0x00U, 0x41U, 0x90U,
|
||||
0x8BU, 0x80U, 0x80U, 0x00U, 0x41U, 0x25U, 0x42U, 0xC4U, 0x00U, 0x10U,
|
||||
0x82U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x0BU, 0x20U, 0x02U, 0x41U,
|
||||
0x01U, 0x6AU, 0x22U, 0x02U, 0x41U, 0x20U, 0x47U, 0x0DU, 0x00U, 0x0BU,
|
||||
0x02U, 0x40U, 0x20U, 0x01U, 0x2DU, 0x00U, 0x93U, 0x01U, 0x41U, 0xE1U,
|
||||
0x01U, 0x46U, 0x0DU, 0x00U, 0x41U, 0xB5U, 0x8BU, 0x80U, 0x80U, 0x00U,
|
||||
0x41U, 0x11U, 0x42U, 0xC5U, 0x00U, 0x10U, 0x82U, 0x80U, 0x80U, 0x80U,
|
||||
0x00U, 0x1AU, 0x0BU, 0x41U, 0x00U, 0x41U, 0x00U, 0x42U, 0x00U, 0x10U,
|
||||
0x85U, 0x80U, 0x80U, 0x80U, 0x00U, 0x21U, 0x04U, 0x20U, 0x01U, 0x41U,
|
||||
0xA0U, 0x01U, 0x6AU, 0x24U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x20U,
|
||||
0x04U, 0x0BU, 0x0BU, 0xCEU, 0x03U, 0x01U, 0x00U, 0x41U, 0x80U, 0x08U,
|
||||
0x0BU, 0xC6U, 0x03U, 0x65U, 0x74U, 0x78U, 0x6EU, 0x5FU, 0x64U, 0x65U,
|
||||
0x74U, 0x61U, 0x69U, 0x6CU, 0x73U, 0x28U, 0x31U, 0x30U, 0x30U, 0x30U,
|
||||
0x30U, 0x30U, 0x30U, 0x2CU, 0x20U, 0x31U, 0x31U, 0x36U, 0x29U, 0x20U,
|
||||
0x3DU, 0x3DU, 0x20U, 0x4FU, 0x55U, 0x54U, 0x5FU, 0x4FU, 0x46U, 0x5FU,
|
||||
0x42U, 0x4FU, 0x55U, 0x4EU, 0x44U, 0x53U, 0x00U, 0x65U, 0x74U, 0x78U,
|
||||
0x80U, 0x00U, 0x42U, 0x20U, 0x51U, 0x0DU, 0x00U, 0x41U, 0x80U, 0x8AU,
|
||||
0x80U, 0x80U, 0x00U, 0x41U, 0x36U, 0x42U, 0xC2U, 0x00U, 0x10U, 0x82U,
|
||||
0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x0BU, 0x41U, 0xC4U, 0x80U, 0x80U,
|
||||
0x80U, 0x78U, 0x41U, 0x11U, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U,
|
||||
0x1AU, 0x41U, 0x00U, 0x21U, 0x02U, 0x03U, 0x40U, 0x41U, 0xC4U, 0x80U,
|
||||
0x80U, 0x80U, 0x78U, 0x41U, 0x11U, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U,
|
||||
0x00U, 0x1AU, 0x02U, 0x40U, 0x20U, 0x01U, 0x41U, 0x20U, 0x6AU, 0x20U,
|
||||
0x02U, 0x6AU, 0x2DU, 0x00U, 0x00U, 0x20U, 0x02U, 0x41U, 0xF0U, 0x89U,
|
||||
0x80U, 0x80U, 0x00U, 0x6AU, 0x2DU, 0x00U, 0x00U, 0x46U, 0x0DU, 0x00U,
|
||||
0x41U, 0xB6U, 0x8AU, 0x80U, 0x80U, 0x00U, 0x41U, 0x17U, 0x42U, 0xC5U,
|
||||
0x00U, 0x10U, 0x82U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x0BU, 0x20U,
|
||||
0x02U, 0x41U, 0x01U, 0x6AU, 0x22U, 0x02U, 0x41U, 0x10U, 0x47U, 0x0DU,
|
||||
0x00U, 0x0BU, 0x02U, 0x40U, 0x20U, 0x01U, 0x2DU, 0x00U, 0x30U, 0x41U,
|
||||
0xDBU, 0x00U, 0x46U, 0x0DU, 0x00U, 0x41U, 0xCDU, 0x8AU, 0x80U, 0x80U,
|
||||
0x00U, 0x41U, 0x11U, 0x42U, 0xC6U, 0x00U, 0x10U, 0x82U, 0x80U, 0x80U,
|
||||
0x80U, 0x00U, 0x1AU, 0x0BU, 0x02U, 0x40U, 0x20U, 0x01U, 0x2DU, 0x00U,
|
||||
0x51U, 0x41U, 0xDCU, 0x00U, 0x46U, 0x0DU, 0x00U, 0x41U, 0xDEU, 0x8AU,
|
||||
0x80U, 0x80U, 0x00U, 0x41U, 0x11U, 0x42U, 0xCAU, 0x00U, 0x10U, 0x82U,
|
||||
0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x0BU, 0x02U, 0x40U, 0x20U, 0x01U,
|
||||
0x2DU, 0x00U, 0x72U, 0x41U, 0xDDU, 0x00U, 0x46U, 0x0DU, 0x00U, 0x41U,
|
||||
0xEFU, 0x8AU, 0x80U, 0x80U, 0x00U, 0x41U, 0x11U, 0x42U, 0xCEU, 0x00U,
|
||||
0x10U, 0x82U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x0BU, 0x41U, 0xCFU,
|
||||
0x80U, 0x80U, 0x80U, 0x78U, 0x41U, 0x21U, 0x10U, 0x80U, 0x80U, 0x80U,
|
||||
0x80U, 0x00U, 0x1AU, 0x20U, 0x01U, 0x41U, 0xF3U, 0x00U, 0x6AU, 0x21U,
|
||||
0x03U, 0x41U, 0x00U, 0x21U, 0x02U, 0x03U, 0x40U, 0x41U, 0xCFU, 0x80U,
|
||||
0x80U, 0x80U, 0x78U, 0x41U, 0x21U, 0x10U, 0x80U, 0x80U, 0x80U, 0x80U,
|
||||
0x00U, 0x1AU, 0x02U, 0x40U, 0x20U, 0x03U, 0x20U, 0x02U, 0x6AU, 0x2DU,
|
||||
0x00U, 0x00U, 0x20U, 0x01U, 0x20U, 0x02U, 0x6AU, 0x2DU, 0x00U, 0x00U,
|
||||
0x46U, 0x0DU, 0x00U, 0x41U, 0x80U, 0x8BU, 0x80U, 0x80U, 0x00U, 0x41U,
|
||||
0x25U, 0x42U, 0xD0U, 0x00U, 0x10U, 0x82U, 0x80U, 0x80U, 0x80U, 0x00U,
|
||||
0x1AU, 0x0BU, 0x20U, 0x02U, 0x41U, 0x01U, 0x6AU, 0x22U, 0x02U, 0x41U,
|
||||
0x20U, 0x47U, 0x0DU, 0x00U, 0x0BU, 0x02U, 0x40U, 0x20U, 0x01U, 0x2DU,
|
||||
0x00U, 0x93U, 0x01U, 0x41U, 0xE1U, 0x01U, 0x46U, 0x0DU, 0x00U, 0x41U,
|
||||
0xA5U, 0x8BU, 0x80U, 0x80U, 0x00U, 0x41U, 0x11U, 0x42U, 0xD1U, 0x00U,
|
||||
0x10U, 0x82U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x0BU, 0x41U, 0x00U,
|
||||
0x41U, 0x00U, 0x42U, 0x00U, 0x10U, 0x85U, 0x80U, 0x80U, 0x80U, 0x00U,
|
||||
0x21U, 0x04U, 0x20U, 0x01U, 0x41U, 0xA0U, 0x01U, 0x6AU, 0x24U, 0x80U,
|
||||
0x80U, 0x80U, 0x80U, 0x00U, 0x20U, 0x04U, 0x0BU, 0x0BU, 0xBEU, 0x03U,
|
||||
0x01U, 0x00U, 0x41U, 0x80U, 0x08U, 0x0BU, 0xB6U, 0x03U, 0x65U, 0x74U,
|
||||
0x78U, 0x6EU, 0x5FU, 0x64U, 0x65U, 0x74U, 0x61U, 0x69U, 0x6CU, 0x73U,
|
||||
0x28U, 0x31U, 0x30U, 0x30U, 0x30U, 0x30U, 0x30U, 0x30U, 0x2CU, 0x20U,
|
||||
0x31U, 0x31U, 0x36U, 0x29U, 0x20U, 0x3DU, 0x3DU, 0x20U, 0x4FU, 0x55U,
|
||||
0x54U, 0x5FU, 0x4FU, 0x46U, 0x5FU, 0x42U, 0x4FU, 0x55U, 0x4EU, 0x44U,
|
||||
0x53U, 0x00U, 0x65U, 0x74U, 0x78U, 0x6EU, 0x5FU, 0x64U, 0x65U, 0x74U,
|
||||
0x61U, 0x69U, 0x6CU, 0x73U, 0x28U, 0x30U, 0x2CU, 0x20U, 0x31U, 0x30U,
|
||||
0x30U, 0x30U, 0x30U, 0x30U, 0x30U, 0x29U, 0x20U, 0x3DU, 0x3DU, 0x20U,
|
||||
0x4FU, 0x55U, 0x54U, 0x5FU, 0x4FU, 0x46U, 0x5FU, 0x42U, 0x4FU, 0x55U,
|
||||
0x4EU, 0x44U, 0x53U, 0x00U, 0x65U, 0x74U, 0x78U, 0x6EU, 0x5FU, 0x64U,
|
||||
0x65U, 0x74U, 0x61U, 0x69U, 0x6CU, 0x73U, 0x28U, 0x28U, 0x75U, 0x69U,
|
||||
0x6EU, 0x74U, 0x33U, 0x32U, 0x5FU, 0x74U, 0x29U, 0x64U, 0x65U, 0x74U,
|
||||
0x2CU, 0x20U, 0x31U, 0x31U, 0x35U, 0x29U, 0x20U, 0x3DU, 0x3DU, 0x20U,
|
||||
0x54U, 0x4FU, 0x4FU, 0x5FU, 0x53U, 0x4DU, 0x41U, 0x4CU, 0x4CU, 0x00U,
|
||||
0x65U, 0x74U, 0x78U, 0x6EU, 0x5FU, 0x64U, 0x65U, 0x74U, 0x61U, 0x69U,
|
||||
0x6CU, 0x73U, 0x28U, 0x28U, 0x75U, 0x69U, 0x6EU, 0x74U, 0x33U, 0x32U,
|
||||
0x5FU, 0x74U, 0x29U, 0x64U, 0x65U, 0x74U, 0x2CU, 0x20U, 0x31U, 0x31U,
|
||||
0x36U, 0x29U, 0x20U, 0x3DU, 0x3DU, 0x20U, 0x50U, 0x52U, 0x45U, 0x52U,
|
||||
0x45U, 0x51U, 0x55U, 0x49U, 0x53U, 0x49U, 0x54U, 0x45U, 0x5FU, 0x4EU,
|
||||
0x4FU, 0x54U, 0x5FU, 0x4DU, 0x45U, 0x54U, 0x00U, 0x65U, 0x74U, 0x78U,
|
||||
0x6EU, 0x5FU, 0x64U, 0x65U, 0x74U, 0x61U, 0x69U, 0x6CU, 0x73U, 0x28U,
|
||||
0x30U, 0x2CU, 0x20U, 0x31U, 0x30U, 0x30U, 0x30U, 0x30U, 0x30U, 0x30U,
|
||||
0x29U, 0x20U, 0x3DU, 0x3DU, 0x20U, 0x4FU, 0x55U, 0x54U, 0x5FU, 0x4FU,
|
||||
0x46U, 0x5FU, 0x42U, 0x4FU, 0x55U, 0x4EU, 0x44U, 0x53U, 0x00U, 0x65U,
|
||||
0x74U, 0x78U, 0x6EU, 0x5FU, 0x64U, 0x65U, 0x74U, 0x61U, 0x69U, 0x6CU,
|
||||
0x73U, 0x28U, 0x28U, 0x75U, 0x69U, 0x6EU, 0x74U, 0x33U, 0x32U, 0x5FU,
|
||||
0x74U, 0x29U, 0x64U, 0x65U, 0x74U, 0x2CU, 0x20U, 0x31U, 0x31U, 0x35U,
|
||||
0x29U, 0x20U, 0x3DU, 0x3DU, 0x20U, 0x54U, 0x4FU, 0x4FU, 0x5FU, 0x53U,
|
||||
0x4DU, 0x41U, 0x4CU, 0x4CU, 0x00U, 0x65U, 0x74U, 0x78U, 0x6EU, 0x5FU,
|
||||
0x64U, 0x65U, 0x74U, 0x61U, 0x69U, 0x6CU, 0x73U, 0x28U, 0x28U, 0x75U,
|
||||
0x69U, 0x6EU, 0x74U, 0x33U, 0x32U, 0x5FU, 0x74U, 0x29U, 0x64U, 0x65U,
|
||||
0x74U, 0x2CU, 0x20U, 0x31U, 0x31U, 0x36U, 0x29U, 0x20U, 0x3DU, 0x3DU,
|
||||
0x20U, 0x50U, 0x52U, 0x45U, 0x52U, 0x45U, 0x51U, 0x55U, 0x49U, 0x53U,
|
||||
0x49U, 0x54U, 0x45U, 0x5FU, 0x4EU, 0x4FU, 0x54U, 0x5FU, 0x4DU, 0x45U,
|
||||
0x54U, 0x00U, 0x65U, 0x74U, 0x78U, 0x6EU, 0x5FU, 0x64U, 0x65U, 0x74U,
|
||||
0x61U, 0x69U, 0x6CU, 0x73U, 0x28U, 0x28U, 0x75U, 0x69U, 0x6EU, 0x74U,
|
||||
0x33U, 0x32U, 0x5FU, 0x74U, 0x29U, 0x64U, 0x65U, 0x74U, 0x2CU, 0x20U,
|
||||
0x31U, 0x31U, 0x36U, 0x29U, 0x20U, 0x3DU, 0x3DU, 0x20U, 0x31U, 0x31U,
|
||||
0x36U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U,
|
||||
0x00U, 0x00U, 0x00U, 0xEDU, 0x20U, 0x2EU, 0x00U, 0x00U, 0x00U, 0x01U,
|
||||
0x3DU, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x01U, 0x5BU,
|
||||
0xBCU, 0x09U, 0x95U, 0xFDU, 0x03U, 0x0FU, 0xF1U, 0x85U, 0xF4U, 0xECU,
|
||||
0xACU, 0x94U, 0xDBU, 0x02U, 0x19U, 0x26U, 0xFEU, 0x58U, 0xD4U, 0x8DU,
|
||||
0x48U, 0x21U, 0xCCU, 0x82U, 0x2EU, 0x4AU, 0x6AU, 0xC9U, 0xC8U, 0xC6U,
|
||||
0x7CU, 0x88U, 0x68U, 0x6FU, 0x6FU, 0x6BU, 0x5FU, 0x68U, 0x61U, 0x73U,
|
||||
0x68U, 0x28U, 0x28U, 0x75U, 0x69U, 0x6EU, 0x74U, 0x33U, 0x32U, 0x5FU,
|
||||
0x74U, 0x29U, 0x65U, 0x78U, 0x70U, 0x65U, 0x63U, 0x74U, 0x65U, 0x64U,
|
||||
0x5FU, 0x68U, 0x6FU, 0x6FU, 0x6BU, 0x5FU, 0x68U, 0x61U, 0x73U, 0x68U,
|
||||
0x2CU, 0x20U, 0x33U, 0x32U, 0x2CU, 0x20U, 0x2DU, 0x31U, 0x29U, 0x20U,
|
||||
0x3DU, 0x3DU, 0x20U, 0x33U, 0x32U, 0x00U, 0x64U, 0x65U, 0x74U, 0x5BU,
|
||||
0x69U, 0x5DU, 0x20U, 0x3DU, 0x3DU, 0x20U, 0x65U, 0x78U, 0x70U, 0x65U,
|
||||
0x63U, 0x74U, 0x65U, 0x64U, 0x31U, 0x5BU, 0x69U, 0x5DU, 0x00U, 0x64U,
|
||||
0x65U, 0x74U, 0x5BU, 0x34U, 0x39U, 0x5DU, 0x20U, 0x3DU, 0x3DU, 0x20U,
|
||||
0x30U, 0x78U, 0x35U, 0x43U, 0x55U, 0x00U, 0x64U, 0x65U, 0x74U, 0x5BU,
|
||||
0x38U, 0x32U, 0x5DU, 0x20U, 0x3DU, 0x3DU, 0x20U, 0x30U, 0x78U, 0x35U,
|
||||
0x44U, 0x55U, 0x00U, 0x64U, 0x65U, 0x74U, 0x5BU, 0x38U, 0x33U, 0x20U,
|
||||
0x2BU, 0x20U, 0x69U, 0x5DU, 0x20U, 0x3DU, 0x3DU, 0x20U, 0x65U, 0x78U,
|
||||
0x70U, 0x65U, 0x63U, 0x74U, 0x65U, 0x64U, 0x5FU, 0x68U, 0x6FU, 0x6FU,
|
||||
0x6BU, 0x5FU, 0x68U, 0x61U, 0x73U, 0x68U, 0x5BU, 0x69U, 0x5DU, 0x00U,
|
||||
0x64U, 0x65U, 0x74U, 0x5BU, 0x31U, 0x31U, 0x35U, 0x5DU, 0x20U, 0x3DU,
|
||||
0x3DU, 0x20U, 0x30U, 0x78U, 0x45U, 0x31U, 0x00U,
|
||||
0x28U, 0x75U, 0x69U, 0x6EU, 0x74U, 0x33U, 0x32U, 0x5FU, 0x74U, 0x29U,
|
||||
0x64U, 0x65U, 0x74U, 0x2CU, 0x20U, 0x31U, 0x31U, 0x36U, 0x29U, 0x20U,
|
||||
0x3DU, 0x3DU, 0x20U, 0x31U, 0x31U, 0x36U, 0x00U, 0x00U, 0x00U, 0x00U,
|
||||
0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0xEDU, 0x20U,
|
||||
0x2EU, 0x00U, 0x00U, 0x00U, 0x01U, 0x3DU, 0x00U, 0x00U, 0x00U, 0x00U,
|
||||
0x00U, 0x00U, 0x00U, 0x01U, 0x68U, 0x6FU, 0x6FU, 0x6BU, 0x5FU, 0x68U,
|
||||
0x61U, 0x73U, 0x68U, 0x28U, 0x28U, 0x75U, 0x69U, 0x6EU, 0x74U, 0x33U,
|
||||
0x32U, 0x5FU, 0x74U, 0x29U, 0x65U, 0x78U, 0x70U, 0x65U, 0x63U, 0x74U,
|
||||
0x65U, 0x64U, 0x5FU, 0x68U, 0x6FU, 0x6FU, 0x6BU, 0x5FU, 0x68U, 0x61U,
|
||||
0x73U, 0x68U, 0x2CU, 0x20U, 0x33U, 0x32U, 0x2CU, 0x20U, 0x2DU, 0x31U,
|
||||
0x29U, 0x20U, 0x3DU, 0x3DU, 0x20U, 0x33U, 0x32U, 0x00U, 0x64U, 0x65U,
|
||||
0x74U, 0x5BU, 0x69U, 0x5DU, 0x20U, 0x3DU, 0x3DU, 0x20U, 0x65U, 0x78U,
|
||||
0x70U, 0x65U, 0x63U, 0x74U, 0x65U, 0x64U, 0x31U, 0x5BU, 0x69U, 0x5DU,
|
||||
0x00U, 0x64U, 0x65U, 0x74U, 0x5BU, 0x31U, 0x36U, 0x5DU, 0x20U, 0x3DU,
|
||||
0x3DU, 0x20U, 0x30U, 0x78U, 0x35U, 0x42U, 0x55U, 0x00U, 0x64U, 0x65U,
|
||||
0x74U, 0x5BU, 0x34U, 0x39U, 0x5DU, 0x20U, 0x3DU, 0x3DU, 0x20U, 0x30U,
|
||||
0x78U, 0x35U, 0x43U, 0x55U, 0x00U, 0x64U, 0x65U, 0x74U, 0x5BU, 0x38U,
|
||||
0x32U, 0x5DU, 0x20U, 0x3DU, 0x3DU, 0x20U, 0x30U, 0x78U, 0x35U, 0x44U,
|
||||
0x55U, 0x00U, 0x64U, 0x65U, 0x74U, 0x5BU, 0x38U, 0x33U, 0x20U, 0x2BU,
|
||||
0x20U, 0x69U, 0x5DU, 0x20U, 0x3DU, 0x3DU, 0x20U, 0x65U, 0x78U, 0x70U,
|
||||
0x65U, 0x63U, 0x74U, 0x65U, 0x64U, 0x5FU, 0x68U, 0x6FU, 0x6FU, 0x6BU,
|
||||
0x5FU, 0x68U, 0x61U, 0x73U, 0x68U, 0x5BU, 0x69U, 0x5DU, 0x00U, 0x64U,
|
||||
0x65U, 0x74U, 0x5BU, 0x31U, 0x31U, 0x35U, 0x5DU, 0x20U, 0x3DU, 0x3DU,
|
||||
0x20U, 0x30U, 0x78U, 0x45U, 0x31U, 0x00U,
|
||||
}},
|
||||
|
||||
{R"[test.hook](
|
||||
@@ -12786,7 +12903,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
|
||||
ASSERT(s > 0);
|
||||
|
||||
// pull the object out into a buffer, check the number of bytes written is correct
|
||||
uint8_t buf[4096];
|
||||
uint8_t buf[8210]; // ltSkip(3)+FLS(6)+LLS(6)+ Hashes(3+8,192(32*256))
|
||||
ASSERT(slot(SBUF(buf), 1) == s);
|
||||
|
||||
// check the object is valid
|
||||
@@ -12817,63 +12934,64 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
|
||||
0x41U, 0x80U, 0x08U, 0x0BU, 0x7FU, 0x00U, 0x41U, 0xE0U, 0x89U, 0x04U,
|
||||
0x0BU, 0x7FU, 0x00U, 0x41U, 0x80U, 0x08U, 0x0BU, 0x7FU, 0x00U, 0x41U,
|
||||
0x80U, 0x08U, 0x0BU, 0x07U, 0x08U, 0x01U, 0x04U, 0x68U, 0x6FU, 0x6FU,
|
||||
0x6BU, 0x00U, 0x07U, 0x0AU, 0xCCU, 0x82U, 0x00U, 0x01U, 0xC8U, 0x82U,
|
||||
0x6BU, 0x00U, 0x07U, 0x0AU, 0xCFU, 0x82U, 0x00U, 0x01U, 0xCBU, 0x82U,
|
||||
0x00U, 0x02U, 0x01U, 0x7FU, 0x01U, 0x7EU, 0x23U, 0x80U, 0x80U, 0x80U,
|
||||
0x80U, 0x00U, 0x41U, 0x80U, 0x20U, 0x6BU, 0x22U, 0x01U, 0x24U, 0x80U,
|
||||
0x80U, 0x80U, 0x80U, 0x00U, 0x41U, 0x01U, 0x41U, 0x01U, 0x10U, 0x80U,
|
||||
0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x02U, 0x40U, 0x41U, 0x01U, 0x10U,
|
||||
0x81U, 0x80U, 0x80U, 0x80U, 0x00U, 0x42U, 0x7BU, 0x51U, 0x0DU, 0x00U,
|
||||
0x41U, 0xA2U, 0x88U, 0x80U, 0x80U, 0x00U, 0x41U, 0x1DU, 0x42U, 0x21U,
|
||||
0x10U, 0x82U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x0BU, 0x02U, 0x40U,
|
||||
0x41U, 0x80U, 0x88U, 0x80U, 0x80U, 0x00U, 0x41U, 0x22U, 0x41U, 0x01U,
|
||||
0x10U, 0x83U, 0x80U, 0x80U, 0x80U, 0x00U, 0x42U, 0x01U, 0x51U, 0x0DU,
|
||||
0x00U, 0x41U, 0xBFU, 0x88U, 0x80U, 0x80U, 0x00U, 0x41U, 0x1EU, 0x42U,
|
||||
0x24U, 0x10U, 0x82U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x0BU, 0x02U,
|
||||
0x80U, 0x00U, 0x41U, 0xA0U, 0xC0U, 0x00U, 0x6BU, 0x22U, 0x01U, 0x24U,
|
||||
0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x41U, 0x01U, 0x41U, 0x01U, 0x10U,
|
||||
0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x02U, 0x40U, 0x41U, 0x01U,
|
||||
0x10U, 0x81U, 0x80U, 0x80U, 0x80U, 0x00U, 0x42U, 0x7BU, 0x51U, 0x0DU,
|
||||
0x00U, 0x41U, 0xA2U, 0x88U, 0x80U, 0x80U, 0x00U, 0x41U, 0x1DU, 0x42U,
|
||||
0x21U, 0x10U, 0x82U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x0BU, 0x02U,
|
||||
0x40U, 0x41U, 0x80U, 0x88U, 0x80U, 0x80U, 0x00U, 0x41U, 0x22U, 0x41U,
|
||||
0xFFU, 0x01U, 0x10U, 0x83U, 0x80U, 0x80U, 0x80U, 0x00U, 0x42U, 0xFFU,
|
||||
0x01U, 0x51U, 0x0DU, 0x00U, 0x41U, 0xDDU, 0x88U, 0x80U, 0x80U, 0x00U,
|
||||
0x41U, 0x22U, 0x42U, 0x25U, 0x10U, 0x82U, 0x80U, 0x80U, 0x80U, 0x00U,
|
||||
0x1AU, 0x0BU, 0x02U, 0x40U, 0x41U, 0x01U, 0x10U, 0x81U, 0x80U, 0x80U,
|
||||
0x80U, 0x00U, 0x41U, 0xFFU, 0x01U, 0x10U, 0x81U, 0x80U, 0x80U, 0x80U,
|
||||
0x00U, 0x51U, 0x0DU, 0x00U, 0x41U, 0xFFU, 0x88U, 0x80U, 0x80U, 0x00U,
|
||||
0x41U, 0x1FU, 0x42U, 0x28U, 0x10U, 0x82U, 0x80U, 0x80U, 0x80U, 0x00U,
|
||||
0x1AU, 0x0BU, 0x02U, 0x40U, 0x41U, 0x01U, 0x10U, 0x81U, 0x80U, 0x80U,
|
||||
0x80U, 0x00U, 0x22U, 0x02U, 0x42U, 0x00U, 0x55U, 0x0DU, 0x00U, 0x41U,
|
||||
0x9EU, 0x89U, 0x80U, 0x80U, 0x00U, 0x41U, 0x06U, 0x42U, 0x2CU, 0x10U,
|
||||
0x01U, 0x10U, 0x83U, 0x80U, 0x80U, 0x80U, 0x00U, 0x42U, 0x01U, 0x51U,
|
||||
0x0DU, 0x00U, 0x41U, 0xBFU, 0x88U, 0x80U, 0x80U, 0x00U, 0x41U, 0x1EU,
|
||||
0x42U, 0x24U, 0x10U, 0x82U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x0BU,
|
||||
0x02U, 0x40U, 0x41U, 0x80U, 0x88U, 0x80U, 0x80U, 0x00U, 0x41U, 0x22U,
|
||||
0x41U, 0xFFU, 0x01U, 0x10U, 0x83U, 0x80U, 0x80U, 0x80U, 0x00U, 0x42U,
|
||||
0xFFU, 0x01U, 0x51U, 0x0DU, 0x00U, 0x41U, 0xDDU, 0x88U, 0x80U, 0x80U,
|
||||
0x00U, 0x41U, 0x22U, 0x42U, 0x25U, 0x10U, 0x82U, 0x80U, 0x80U, 0x80U,
|
||||
0x00U, 0x1AU, 0x0BU, 0x02U, 0x40U, 0x41U, 0x01U, 0x10U, 0x81U, 0x80U,
|
||||
0x80U, 0x80U, 0x00U, 0x41U, 0xFFU, 0x01U, 0x10U, 0x81U, 0x80U, 0x80U,
|
||||
0x80U, 0x00U, 0x51U, 0x0DU, 0x00U, 0x41U, 0xFFU, 0x88U, 0x80U, 0x80U,
|
||||
0x00U, 0x41U, 0x1FU, 0x42U, 0x28U, 0x10U, 0x82U, 0x80U, 0x80U, 0x80U,
|
||||
0x00U, 0x1AU, 0x0BU, 0x02U, 0x40U, 0x41U, 0x01U, 0x10U, 0x81U, 0x80U,
|
||||
0x80U, 0x80U, 0x00U, 0x22U, 0x02U, 0x42U, 0x00U, 0x55U, 0x0DU, 0x00U,
|
||||
0x41U, 0x9EU, 0x89U, 0x80U, 0x80U, 0x00U, 0x41U, 0x06U, 0x42U, 0x2CU,
|
||||
0x10U, 0x82U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x0BU, 0x02U, 0x40U,
|
||||
0x20U, 0x01U, 0x41U, 0x92U, 0xC0U, 0x00U, 0x41U, 0x01U, 0x10U, 0x84U,
|
||||
0x80U, 0x80U, 0x80U, 0x00U, 0x20U, 0x02U, 0x51U, 0x0DU, 0x00U, 0x41U,
|
||||
0xA4U, 0x89U, 0x80U, 0x80U, 0x00U, 0x41U, 0x18U, 0x42U, 0x30U, 0x10U,
|
||||
0x82U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x0BU, 0x02U, 0x40U, 0x20U,
|
||||
0x01U, 0x41U, 0x80U, 0x20U, 0x41U, 0x01U, 0x10U, 0x84U, 0x80U, 0x80U,
|
||||
0x80U, 0x00U, 0x20U, 0x02U, 0x51U, 0x0DU, 0x00U, 0x41U, 0xA4U, 0x89U,
|
||||
0x80U, 0x80U, 0x00U, 0x41U, 0x18U, 0x42U, 0x30U, 0x10U, 0x82U, 0x80U,
|
||||
0x80U, 0x80U, 0x00U, 0x1AU, 0x0BU, 0x02U, 0x40U, 0x20U, 0x01U, 0x20U,
|
||||
0x02U, 0xA7U, 0x10U, 0x85U, 0x80U, 0x80U, 0x80U, 0x00U, 0x42U, 0x01U,
|
||||
0x51U, 0x0DU, 0x00U, 0x41U, 0xBCU, 0x89U, 0x80U, 0x80U, 0x00U, 0x41U,
|
||||
0x1AU, 0x42U, 0x33U, 0x10U, 0x82U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU,
|
||||
0x0BU, 0x41U, 0x00U, 0x41U, 0x00U, 0x42U, 0x00U, 0x10U, 0x86U, 0x80U,
|
||||
0x80U, 0x80U, 0x00U, 0x1AU, 0x20U, 0x01U, 0x41U, 0x80U, 0x20U, 0x6AU,
|
||||
0x24U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x20U, 0x02U, 0x0BU, 0x0BU,
|
||||
0xE4U, 0x01U, 0x02U, 0x00U, 0x41U, 0x80U, 0x08U, 0x0BU, 0x22U, 0x00U,
|
||||
0x68U, 0xB4U, 0x97U, 0x9AU, 0x36U, 0xCDU, 0xC7U, 0xF3U, 0xD3U, 0xD5U,
|
||||
0xC3U, 0x1AU, 0x4EU, 0xAEU, 0x2AU, 0xC7U, 0xD7U, 0x20U, 0x9DU, 0xDAU,
|
||||
0x87U, 0x75U, 0x88U, 0xB9U, 0xAFU, 0xC6U, 0x67U, 0x99U, 0x69U, 0x2AU,
|
||||
0xB0U, 0xD6U, 0x6BU, 0x00U, 0x41U, 0xA2U, 0x08U, 0x0BU, 0xB4U, 0x01U,
|
||||
0x73U, 0x6CU, 0x6FU, 0x74U, 0x5FU, 0x73U, 0x69U, 0x7AU, 0x65U, 0x28U,
|
||||
0x31U, 0x29U, 0x20U, 0x3DU, 0x3DU, 0x20U, 0x44U, 0x4FU, 0x45U, 0x53U,
|
||||
0x4EU, 0x54U, 0x5FU, 0x45U, 0x58U, 0x49U, 0x53U, 0x54U, 0x00U, 0x73U,
|
||||
0x6CU, 0x6FU, 0x74U, 0x5FU, 0x73U, 0x65U, 0x74U, 0x28U, 0x53U, 0x42U,
|
||||
0x55U, 0x46U, 0x28U, 0x6BU, 0x6CU, 0x5FU, 0x73U, 0x6BU, 0x29U, 0x2CU,
|
||||
0x20U, 0x31U, 0x29U, 0x20U, 0x3DU, 0x3DU, 0x20U, 0x31U, 0x00U, 0x73U,
|
||||
0x6CU, 0x6FU, 0x74U, 0x5FU, 0x73U, 0x65U, 0x74U, 0x28U, 0x53U, 0x42U,
|
||||
0x55U, 0x46U, 0x28U, 0x6BU, 0x6CU, 0x5FU, 0x73U, 0x6BU, 0x29U, 0x2CU,
|
||||
0x20U, 0x32U, 0x35U, 0x35U, 0x29U, 0x20U, 0x3DU, 0x3DU, 0x20U, 0x32U,
|
||||
0x35U, 0x35U, 0x00U, 0x73U, 0x6CU, 0x6FU, 0x74U, 0x5FU, 0x73U, 0x69U,
|
||||
0x7AU, 0x65U, 0x28U, 0x31U, 0x29U, 0x20U, 0x3DU, 0x3DU, 0x20U, 0x73U,
|
||||
0x6CU, 0x6FU, 0x74U, 0x5FU, 0x73U, 0x69U, 0x7AU, 0x65U, 0x28U, 0x32U,
|
||||
0x35U, 0x35U, 0x29U, 0x00U, 0x73U, 0x20U, 0x3EU, 0x20U, 0x30U, 0x00U,
|
||||
0x73U, 0x6CU, 0x6FU, 0x74U, 0x28U, 0x53U, 0x42U, 0x55U, 0x46U, 0x28U,
|
||||
0x62U, 0x75U, 0x66U, 0x29U, 0x2CU, 0x20U, 0x31U, 0x29U, 0x20U, 0x3DU,
|
||||
0x3DU, 0x20U, 0x73U, 0x00U, 0x73U, 0x74U, 0x6FU, 0x5FU, 0x76U, 0x61U,
|
||||
0x6CU, 0x69U, 0x64U, 0x61U, 0x74U, 0x65U, 0x28U, 0x62U, 0x75U, 0x66U,
|
||||
0x2CU, 0x20U, 0x73U, 0x29U, 0x20U, 0x3DU, 0x3DU, 0x20U, 0x31U, 0x00U,
|
||||
0x01U, 0x20U, 0x02U, 0xA7U, 0x10U, 0x85U, 0x80U, 0x80U, 0x80U, 0x00U,
|
||||
0x42U, 0x01U, 0x51U, 0x0DU, 0x00U, 0x41U, 0xBCU, 0x89U, 0x80U, 0x80U,
|
||||
0x00U, 0x41U, 0x1AU, 0x42U, 0x33U, 0x10U, 0x82U, 0x80U, 0x80U, 0x80U,
|
||||
0x00U, 0x1AU, 0x0BU, 0x41U, 0x00U, 0x41U, 0x00U, 0x42U, 0x00U, 0x10U,
|
||||
0x86U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x20U, 0x01U, 0x41U, 0xA0U,
|
||||
0xC0U, 0x00U, 0x6AU, 0x24U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x20U,
|
||||
0x02U, 0x0BU, 0x0BU, 0xE4U, 0x01U, 0x02U, 0x00U, 0x41U, 0x80U, 0x08U,
|
||||
0x0BU, 0x22U, 0x00U, 0x68U, 0xB4U, 0x97U, 0x9AU, 0x36U, 0xCDU, 0xC7U,
|
||||
0xF3U, 0xD3U, 0xD5U, 0xC3U, 0x1AU, 0x4EU, 0xAEU, 0x2AU, 0xC7U, 0xD7U,
|
||||
0x20U, 0x9DU, 0xDAU, 0x87U, 0x75U, 0x88U, 0xB9U, 0xAFU, 0xC6U, 0x67U,
|
||||
0x99U, 0x69U, 0x2AU, 0xB0U, 0xD6U, 0x6BU, 0x00U, 0x41U, 0xA2U, 0x08U,
|
||||
0x0BU, 0xB4U, 0x01U, 0x73U, 0x6CU, 0x6FU, 0x74U, 0x5FU, 0x73U, 0x69U,
|
||||
0x7AU, 0x65U, 0x28U, 0x31U, 0x29U, 0x20U, 0x3DU, 0x3DU, 0x20U, 0x44U,
|
||||
0x4FU, 0x45U, 0x53U, 0x4EU, 0x54U, 0x5FU, 0x45U, 0x58U, 0x49U, 0x53U,
|
||||
0x54U, 0x00U, 0x73U, 0x6CU, 0x6FU, 0x74U, 0x5FU, 0x73U, 0x65U, 0x74U,
|
||||
0x28U, 0x53U, 0x42U, 0x55U, 0x46U, 0x28U, 0x6BU, 0x6CU, 0x5FU, 0x73U,
|
||||
0x6BU, 0x29U, 0x2CU, 0x20U, 0x31U, 0x29U, 0x20U, 0x3DU, 0x3DU, 0x20U,
|
||||
0x31U, 0x00U, 0x73U, 0x6CU, 0x6FU, 0x74U, 0x5FU, 0x73U, 0x65U, 0x74U,
|
||||
0x28U, 0x53U, 0x42U, 0x55U, 0x46U, 0x28U, 0x6BU, 0x6CU, 0x5FU, 0x73U,
|
||||
0x6BU, 0x29U, 0x2CU, 0x20U, 0x32U, 0x35U, 0x35U, 0x29U, 0x20U, 0x3DU,
|
||||
0x3DU, 0x20U, 0x32U, 0x35U, 0x35U, 0x00U, 0x73U, 0x6CU, 0x6FU, 0x74U,
|
||||
0x5FU, 0x73U, 0x69U, 0x7AU, 0x65U, 0x28U, 0x31U, 0x29U, 0x20U, 0x3DU,
|
||||
0x3DU, 0x20U, 0x73U, 0x6CU, 0x6FU, 0x74U, 0x5FU, 0x73U, 0x69U, 0x7AU,
|
||||
0x65U, 0x28U, 0x32U, 0x35U, 0x35U, 0x29U, 0x00U, 0x73U, 0x20U, 0x3EU,
|
||||
0x20U, 0x30U, 0x00U, 0x73U, 0x6CU, 0x6FU, 0x74U, 0x28U, 0x53U, 0x42U,
|
||||
0x55U, 0x46U, 0x28U, 0x62U, 0x75U, 0x66U, 0x29U, 0x2CU, 0x20U, 0x31U,
|
||||
0x29U, 0x20U, 0x3DU, 0x3DU, 0x20U, 0x73U, 0x00U, 0x73U, 0x74U, 0x6FU,
|
||||
0x5FU, 0x76U, 0x61U, 0x6CU, 0x69U, 0x64U, 0x61U, 0x74U, 0x65U, 0x28U,
|
||||
0x62U, 0x75U, 0x66U, 0x2CU, 0x20U, 0x73U, 0x29U, 0x20U, 0x3DU, 0x3DU,
|
||||
0x20U, 0x31U, 0x00U,
|
||||
}},
|
||||
|
||||
{R"[test.hook](
|
||||
|
||||
@@ -1410,6 +1410,7 @@ public:
|
||||
testAllTxns(sa);
|
||||
testAllTxns(sa - fixHookAPI20251128);
|
||||
testAllTxns(sa - featureTouch - fixHookAPI20251128);
|
||||
testAllTxns(sa - featureHookFeeV2);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -5068,7 +5068,8 @@ public:
|
||||
// fragile: hardcoded ordering by txID XOR parentHash
|
||||
// parentHash < txTree Hash < txMeta < PreviousTxnID
|
||||
testTieBreaking(
|
||||
all - fixProvisionalDoubleThreading - fixHookAPI20251128);
|
||||
all - fixProvisionalDoubleThreading - fixHookAPI20251128 -
|
||||
featureHookFeeV3);
|
||||
testAcctTxnID(all);
|
||||
testMaximum(all);
|
||||
testUnexpectedBalanceChange(all);
|
||||
@@ -5089,7 +5090,8 @@ public:
|
||||
// fragile: hardcoded ordering by txID XOR parentHash
|
||||
// parentHash < txTree Hash < txMeta < PreviousTxnID
|
||||
testFullQueueGapFill(
|
||||
all - fixProvisionalDoubleThreading - fixHookAPI20251128);
|
||||
all - fixProvisionalDoubleThreading - fixHookAPI20251128 -
|
||||
featureHookFeeV3);
|
||||
testSignAndSubmitSequence(all);
|
||||
testAccountInfo(all);
|
||||
testServerInfo(all);
|
||||
|
||||
@@ -35,7 +35,8 @@ class Wildcard_test : public beast::unit_test::suite
|
||||
config.append(
|
||||
{"reference_fee = 10",
|
||||
"account_reserve = 1000000",
|
||||
"owner_reserve = 200000"});
|
||||
"owner_reserve = 200000",
|
||||
"hook_gas_price = 1000000"});
|
||||
auto setup = setup_FeeVote(config);
|
||||
cfg->FEES = setup;
|
||||
return cfg;
|
||||
|
||||
@@ -4830,6 +4830,7 @@ struct XahauGenesis_test : public beast::unit_test::suite
|
||||
std::string fee,
|
||||
std::string a_res,
|
||||
std::string o_res,
|
||||
std::string g_res,
|
||||
uint32_t ledgerID)
|
||||
{
|
||||
using namespace jtx;
|
||||
@@ -4937,7 +4938,8 @@ struct XahauGenesis_test : public beast::unit_test::suite
|
||||
config.append(
|
||||
{"reference_fee = " + fee,
|
||||
"account_reserve = " + a_res,
|
||||
"owner_reserve = " + o_res});
|
||||
"owner_reserve = " + o_res,
|
||||
"hook_gas_price = " + g_res});
|
||||
auto setup = setup_FeeVote(config);
|
||||
cfg->FEES = setup;
|
||||
|
||||
@@ -4975,6 +4977,7 @@ struct XahauGenesis_test : public beast::unit_test::suite
|
||||
"10",
|
||||
"1000000",
|
||||
"200000",
|
||||
"1000000",
|
||||
0),
|
||||
features - featureXahauGenesis};
|
||||
|
||||
|
||||
+16
-5
@@ -154,6 +154,17 @@ private:
|
||||
|
||||
AppBundle bundle_;
|
||||
|
||||
// Features must be in the config before the Application is built so
|
||||
// that the genesis ledger's Rules (and its FeeSettings) reflect them.
|
||||
static std::unique_ptr<Config>
|
||||
withFeatures(std::unique_ptr<Config> config, FeatureBitset const& features)
|
||||
{
|
||||
foreachFeature(features, [&config](uint256 const& f) {
|
||||
config->features.insert(f);
|
||||
});
|
||||
return config;
|
||||
}
|
||||
|
||||
public:
|
||||
beast::Journal const journal;
|
||||
|
||||
@@ -183,15 +194,15 @@ public:
|
||||
std::unique_ptr<Logs> logs = nullptr,
|
||||
beast::severities::Severity thresh = beast::severities::kError)
|
||||
: test(suite_)
|
||||
, bundle_(suite_, std::move(config), std::move(logs), thresh)
|
||||
, bundle_(
|
||||
suite_,
|
||||
withFeatures(std::move(config), features),
|
||||
std::move(logs),
|
||||
thresh)
|
||||
, journal{bundle_.app->journal("Env")}
|
||||
{
|
||||
memoize(Account::master);
|
||||
Pathfinder::initPathTable();
|
||||
foreachFeature(
|
||||
features, [&appFeats = app().config().features](uint256 const& f) {
|
||||
appFeats.insert(f);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -36,6 +36,7 @@ setupConfigForUnitTests(Config& cfg)
|
||||
cfg.FEES.reference_fee = 10;
|
||||
cfg.FEES.account_reserve = XRP(200).value().xrp().drops();
|
||||
cfg.FEES.owner_reserve = XRP(50).value().xrp().drops();
|
||||
cfg.FEES.hook_gas_price = 10'000;
|
||||
|
||||
// The Beta API (currently v2) is always available to tests
|
||||
cfg.BETA_RPC_API = true;
|
||||
|
||||
@@ -37,7 +37,8 @@ makeNetworkConfig(
|
||||
uint32_t networkID,
|
||||
std::string fee,
|
||||
std::string a_res,
|
||||
std::string o_res)
|
||||
std::string o_res,
|
||||
std::string g_res)
|
||||
{
|
||||
using namespace jtx;
|
||||
return envconfig([&](std::unique_ptr<Config> cfg) {
|
||||
@@ -46,9 +47,11 @@ makeNetworkConfig(
|
||||
config.append(
|
||||
{"reference_fee = " + fee,
|
||||
"account_reserve = " + a_res,
|
||||
"owner_reserve = " + o_res});
|
||||
"owner_reserve = " + o_res,
|
||||
"hook_gas_price = " + g_res});
|
||||
auto setup = setup_FeeVote(config);
|
||||
cfg->FEES = setup;
|
||||
cfg->section("voting") = config;
|
||||
return cfg;
|
||||
});
|
||||
}
|
||||
@@ -59,7 +62,8 @@ makeNetworkVLConfig(
|
||||
std::vector<std::string> keys,
|
||||
std::string fee,
|
||||
std::string a_res,
|
||||
std::string o_res)
|
||||
std::string o_res,
|
||||
std::string g_res)
|
||||
{
|
||||
using namespace jtx;
|
||||
return envconfig([&](std::unique_ptr<Config> cfg) {
|
||||
@@ -68,7 +72,8 @@ makeNetworkVLConfig(
|
||||
config.append(
|
||||
{"reference_fee = " + fee,
|
||||
"account_reserve = " + a_res,
|
||||
"owner_reserve = " + o_res});
|
||||
"owner_reserve = " + o_res,
|
||||
"hook_gas_price = " + g_res});
|
||||
auto setup = setup_FeeVote(config);
|
||||
cfg->FEES = setup;
|
||||
|
||||
@@ -98,6 +103,7 @@ makeGenesisConfig(
|
||||
std::string fee,
|
||||
std::string a_res,
|
||||
std::string o_res,
|
||||
std::string g_res,
|
||||
uint32_t ledgerID)
|
||||
{
|
||||
using namespace jtx;
|
||||
@@ -129,7 +135,8 @@ makeGenesisConfig(
|
||||
config.append(
|
||||
{"reference_fee = " + fee,
|
||||
"account_reserve = " + a_res,
|
||||
"owner_reserve = " + o_res});
|
||||
"owner_reserve = " + o_res,
|
||||
"hook_gas_price = " + g_res});
|
||||
auto setup = setup_FeeVote(config);
|
||||
cfg->FEES = setup;
|
||||
|
||||
|
||||
@@ -35,7 +35,8 @@ makeNetworkConfig(
|
||||
uint32_t networkID,
|
||||
std::string fee = "10",
|
||||
std::string a_res = "1000000",
|
||||
std::string o_res = "200000");
|
||||
std::string o_res = "200000",
|
||||
std::string g_res = "100000");
|
||||
|
||||
std::unique_ptr<Config>
|
||||
makeNetworkVLConfig(
|
||||
@@ -43,7 +44,8 @@ makeNetworkVLConfig(
|
||||
std::vector<std::string> keys,
|
||||
std::string fee = "10",
|
||||
std::string a_res = "1000000",
|
||||
std::string o_res = "200000");
|
||||
std::string o_res = "200000",
|
||||
std::string g_res = "10000");
|
||||
|
||||
std::unique_ptr<Config>
|
||||
makeGenesisConfig(
|
||||
@@ -53,6 +55,7 @@ makeGenesisConfig(
|
||||
std::string fee = "10",
|
||||
std::string a_res = "1000000",
|
||||
std::string o_res = "200000",
|
||||
std::string g_res = "10000",
|
||||
uint32_t ledgerID = 0);
|
||||
|
||||
} // namespace network
|
||||
|
||||
@@ -225,6 +225,7 @@ public:
|
||||
using namespace test::jtx;
|
||||
FeatureBitset const all{supported_amendments()};
|
||||
testErrors(all);
|
||||
testErrors(all - featureHookFeeV3);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -117,7 +117,8 @@ class AccountTx_test : public beast::unit_test::suite
|
||||
|
||||
Env env(
|
||||
*this,
|
||||
supported_amendments() - featureXahauGenesis - fixHookAPI20251128);
|
||||
supported_amendments() - featureXahauGenesis - fixHookAPI20251128 -
|
||||
featureHookFeeV3);
|
||||
Account A1{"A1"};
|
||||
env.fund(XRP(10000), A1);
|
||||
env.close();
|
||||
|
||||
@@ -3392,7 +3392,8 @@ public:
|
||||
return cfg;
|
||||
}),
|
||||
supported_amendments() - featureXahauGenesis -
|
||||
fixProvisionalDoubleThreading - fixHookAPI20251128};
|
||||
fixProvisionalDoubleThreading - fixHookAPI20251128 -
|
||||
featureHookFeeV3};
|
||||
|
||||
Json::Value jv;
|
||||
jv[jss::ledger_index] = "current";
|
||||
|
||||
@@ -310,10 +310,13 @@ public:
|
||||
{
|
||||
using namespace test::jtx;
|
||||
using namespace std::chrono_literals;
|
||||
Env env{*this, envconfig([](std::unique_ptr<Config> cfg) {
|
||||
cfg->NODE_SIZE = 0;
|
||||
return cfg;
|
||||
})};
|
||||
Env env{
|
||||
*this,
|
||||
envconfig([](std::unique_ptr<Config> cfg) {
|
||||
cfg->NODE_SIZE = 0;
|
||||
return cfg;
|
||||
}),
|
||||
supported_amendments() - featureHookFeeV3};
|
||||
Account const gw{"gateway"};
|
||||
auto const USD = gw["USD"];
|
||||
env.fund(XRP(100000), gw);
|
||||
|
||||
@@ -316,7 +316,9 @@ public:
|
||||
using namespace std::chrono_literals;
|
||||
using namespace jtx;
|
||||
Env env(
|
||||
*this, supported_amendments() - featureXahauGenesis - featureTouch);
|
||||
*this,
|
||||
supported_amendments() - featureXahauGenesis - featureTouch -
|
||||
featureHookFeeV3);
|
||||
auto wsc = makeWSClient(env.app().config());
|
||||
Json::Value stream{Json::objectValue};
|
||||
|
||||
|
||||
@@ -153,7 +153,7 @@ class TransactionEntry_test : public beast::unit_test::suite
|
||||
Env env{
|
||||
*this,
|
||||
supported_amendments() - featureXahauGenesis - featureTouch -
|
||||
fixHookAPI20251128,
|
||||
fixHookAPI20251128 - featureHookFeeV3,
|
||||
};
|
||||
|
||||
auto check_tx = [this, &env, apiVersion](
|
||||
|
||||
@@ -922,7 +922,8 @@ public:
|
||||
forAllApiVersions(std::bind_front(
|
||||
&Transaction_test::testBinaryRequest,
|
||||
this,
|
||||
supported_amendments() - featureXahauGenesis - fixHookAPI20251128));
|
||||
supported_amendments() - featureXahauGenesis - fixHookAPI20251128 -
|
||||
featureHookFeeV3));
|
||||
return;
|
||||
FeatureBitset const all{supported_amendments()};
|
||||
testWithFeats(all);
|
||||
@@ -938,7 +939,7 @@ public:
|
||||
forAllApiVersions(std::bind_front(
|
||||
&Transaction_test::testRequest,
|
||||
this,
|
||||
features - featureXahauGenesis - featureTouch));
|
||||
features - featureXahauGenesis - featureTouch - featureHookFeeV3));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -65,14 +65,17 @@ namespace hook_api {
|
||||
|
||||
#pragma push_macro("HOOK_API_DEFINITION")
|
||||
#undef HOOK_API_DEFINITION
|
||||
#undef HOOK_API_COST
|
||||
|
||||
#define HOOK_WRAP_PARAMS(...) __VA_ARGS__
|
||||
#define HOOK_API_DEFINITION(RETURN_TYPE, FUNCTION_NAME, PARAMS_TUPLE, ...) \
|
||||
DECLARE_HOOK_FUNCTION( \
|
||||
RETURN_TYPE, FUNCTION_NAME, HOOK_WRAP_PARAMS PARAMS_TUPLE);
|
||||
#define HOOK_API_COST(...)
|
||||
|
||||
#include <xrpl/hook/hook_api.macro>
|
||||
|
||||
#undef HOOK_API_COST
|
||||
#undef HOOK_API_DEFINITION
|
||||
#undef HOOK_WRAP_PARAMS
|
||||
#pragma pop_macro("HOOK_API_DEFINITION")
|
||||
@@ -137,6 +140,18 @@ computeExecutionFee(uint64_t instructionCount);
|
||||
int64_t
|
||||
computeCreationFee(uint64_t byteCount);
|
||||
|
||||
constexpr uint32_t MICRO_DROPS_PER_DROP{1'000'000};
|
||||
|
||||
XRPAmount
|
||||
hookCostToFee(ReadView const& view, uint64_t hookCost);
|
||||
|
||||
std::optional<std::pair<uint64_t, uint64_t>>
|
||||
doValidateGuards(
|
||||
STTx const& tx,
|
||||
Blob const& wasm,
|
||||
Rules const& rules,
|
||||
beast::Journal const& j);
|
||||
|
||||
struct HookResult
|
||||
{
|
||||
ripple::uint256 const hookSetTxnID;
|
||||
@@ -276,14 +291,14 @@ gatherHookParameters(
|
||||
beast::Journal const& j_);
|
||||
|
||||
// RH TODO: call destruct for these on rippled shutdown
|
||||
#define ADD_HOOK_FUNCTION(F, ctx) \
|
||||
#define ADD_HOOK_FUNCTION(F, ctx, cost) \
|
||||
{ \
|
||||
WasmEdge_FunctionInstanceContext* hf = \
|
||||
WasmEdge_FunctionInstanceCreate( \
|
||||
hook_api::WasmFunctionType##F, \
|
||||
hook_api::WasmFunction##F, \
|
||||
(void*)(&ctx), \
|
||||
0); \
|
||||
cost); \
|
||||
WasmEdge_ModuleInstanceAddFunction( \
|
||||
importObj, hook_api::WasmFunctionName##F, hf); \
|
||||
}
|
||||
@@ -475,14 +490,17 @@ public:
|
||||
|
||||
#pragma push_macro("HOOK_API_DEFINITION")
|
||||
#undef HOOK_API_DEFINITION
|
||||
#undef HOOK_API_COST
|
||||
|
||||
#define HOOK_WRAP_PARAMS(...) __VA_ARGS__
|
||||
#define HOOK_API_DEFINITION(RETURN_TYPE, FUNCTION_NAME, PARAMS_TUPLE, ...) \
|
||||
ADD_HOOK_FUNCTION(FUNCTION_NAME, ctx);
|
||||
ADD_HOOK_FUNCTION(FUNCTION_NAME, ctx, 0);
|
||||
#define HOOK_API_COST(...)
|
||||
|
||||
#include <xrpl/hook/hook_api.macro>
|
||||
|
||||
#undef HOOK_API_DEFINITION
|
||||
#undef HOOK_API_COST
|
||||
#undef HOOK_WRAP_PARAMS
|
||||
#pragma pop_macro("HOOK_API_DEFINITION")
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <xrpld/app/tx/detail/NFTokenUtils.h>
|
||||
#include <xrpl/basics/Log.h>
|
||||
#include <xrpl/basics/Slice.h>
|
||||
#include <xrpl/hook/Guard.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/ErrorCodes.h>
|
||||
#include <xrpl/protocol/PublicKey.h>
|
||||
@@ -553,6 +554,9 @@ getTransactionalStakeHolders(STTx const& tx, ReadView const& rv)
|
||||
case ttREMARKS_SET: {
|
||||
break;
|
||||
}
|
||||
case ttHOOK_DEFINITION_UPDATE: {
|
||||
break;
|
||||
}
|
||||
// pseudo transactions
|
||||
case ttAMENDMENT:
|
||||
case ttFEE:
|
||||
@@ -691,6 +695,93 @@ hook::computeCreationFee(uint64_t byteCount)
|
||||
return fee;
|
||||
}
|
||||
|
||||
XRPAmount
|
||||
hook::hookCostToFee(ReadView const& view, uint64_t hookCost)
|
||||
{
|
||||
if (!view.rules().enabled(featureHookFeeV3))
|
||||
{
|
||||
// HookFeeV2: fixed price, rounded up. The quotient of a uint64 by 10
|
||||
// always fits in an int64.
|
||||
uint64_t const drops = hookCost / hook_api::cost_units_per_drop +
|
||||
(hookCost % hook_api::cost_units_per_drop != 0);
|
||||
return XRPAmount{static_cast<XRPAmount::value_type>(drops)};
|
||||
}
|
||||
|
||||
XRPAmount fee{0};
|
||||
auto const HOOK_GAS_PRICE = view.fees().hookGasPrice;
|
||||
double const gas_cost =
|
||||
double(HOOK_GAS_PRICE) / double(hook::MICRO_DROPS_PER_DROP);
|
||||
fee = uint64_t(hookCost * gas_cost);
|
||||
return fee;
|
||||
}
|
||||
|
||||
std::optional<std::pair<uint64_t, uint64_t>>
|
||||
hook::doValidateGuards(
|
||||
STTx const& tx,
|
||||
Blob const& wasm,
|
||||
Rules const& rules,
|
||||
beast::Journal const& j)
|
||||
{
|
||||
// RH NOTE: validateGuards has a generic non-rippled specific
|
||||
// interface so it can be used in other projects (i.e. tooling).
|
||||
// As such the calling here is a bit convoluted.
|
||||
|
||||
std::optional<std::reference_wrapper<std::basic_ostream<char>>> logger;
|
||||
std::ostringstream loggerStream;
|
||||
std::string hsacc{""};
|
||||
if (j.trace())
|
||||
{
|
||||
logger = loggerStream;
|
||||
std::stringstream ss;
|
||||
|
||||
#define HS_ACC() tx.getAccountID(sfAccount) << "-" << tx.getTransactionID()
|
||||
ss << HS_ACC();
|
||||
#undef HS_ACC
|
||||
hsacc = ss.str();
|
||||
}
|
||||
|
||||
auto result = validateGuards(
|
||||
wasm, // wasm to verify
|
||||
logger,
|
||||
hsacc,
|
||||
rules.enabled(featureHookFeeV2),
|
||||
hook_api::getImportWhitelist(rules),
|
||||
hook_api::getGuardRulesVersion(rules));
|
||||
|
||||
if (j.trace())
|
||||
{
|
||||
// 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<char> 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)
|
||||
{
|
||||
if (data[i] == '\n')
|
||||
{
|
||||
data[i] = '\0';
|
||||
j.trace() << last;
|
||||
last = data + i;
|
||||
}
|
||||
}
|
||||
|
||||
if (last < data + i)
|
||||
j.trace() << last;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// many datatypes can be encoded into an int64_t
|
||||
inline std::variant<uint64_t, hook_api::hook_return_code>
|
||||
data_as_int64(void const* ptr_raw, uint32_t len)
|
||||
|
||||
@@ -244,6 +244,15 @@ Ledger::Ledger(
|
||||
sle->at(sfReserveIncrement) = *f;
|
||||
sle->at(sfReferenceFeeUnits) = Config::FEE_UNITS_DEPRECATED;
|
||||
}
|
||||
|
||||
// rules_ covers config.features (unit tests), amendments covers
|
||||
// a FRESH start where the desired amendments are pre-enabled.
|
||||
if (rules_.enabled(featureHookFeeV3) ||
|
||||
std::find(amendments.begin(), amendments.end(), featureHookFeeV3) !=
|
||||
amendments.end())
|
||||
{
|
||||
sle->at(sfHookGasPrice) = config.FEES.hook_gas_price;
|
||||
}
|
||||
rawInsert(sle);
|
||||
}
|
||||
|
||||
@@ -662,6 +671,7 @@ Ledger::setup()
|
||||
{
|
||||
bool oldFees = false;
|
||||
bool newFees = false;
|
||||
bool hookFees = false;
|
||||
{
|
||||
auto const baseFee = sle->at(~sfBaseFee);
|
||||
auto const reserveBase = sle->at(~sfReserveBase);
|
||||
@@ -695,12 +705,26 @@ Ledger::setup()
|
||||
assign(fees_.increment, reserveIncrementXRP);
|
||||
newFees = baseFeeXRP || reserveBaseXRP || reserveIncrementXRP;
|
||||
}
|
||||
{
|
||||
auto const hookGasPrice = sle->at(~sfHookGasPrice);
|
||||
auto assign = [](std::uint32_t& dest,
|
||||
std::optional<std::uint32_t> const& src) {
|
||||
if (src)
|
||||
dest = src.value();
|
||||
};
|
||||
assign(fees_.hookGasPrice, hookGasPrice);
|
||||
hookFees = !!hookGasPrice;
|
||||
}
|
||||
if (oldFees && newFees)
|
||||
// Should be all of one or the other, but not both
|
||||
ret = false;
|
||||
if (!rules_.enabled(featureXRPFees) && newFees)
|
||||
// Can't populate the new fees before the amendment is enabled
|
||||
ret = false;
|
||||
if (!rules_.enabled(featureHookFeeV3) && hookFees)
|
||||
// Can't populate the Hook Fee V3 before the amendment is
|
||||
// enabled
|
||||
ret = false;
|
||||
}
|
||||
}
|
||||
catch (SHAMapMissingNode const&)
|
||||
@@ -720,7 +744,8 @@ void
|
||||
Ledger::defaultFees(Config const& config)
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
fees_.base == 0 && fees_.reserve == 0 && fees_.increment == 0,
|
||||
fees_.base == 0 && fees_.reserve == 0 && fees_.increment == 0 &&
|
||||
fees_.hookGasPrice == 0,
|
||||
"ripple::Ledger::defaultFees : zero fees");
|
||||
if (fees_.base == 0)
|
||||
fees_.base = config.FEES.reference_fee;
|
||||
@@ -728,6 +753,9 @@ Ledger::defaultFees(Config const& config)
|
||||
fees_.reserve = config.FEES.account_reserve;
|
||||
if (fees_.increment == 0)
|
||||
fees_.increment = config.FEES.owner_reserve;
|
||||
|
||||
if (fees_.hookGasPrice == 0)
|
||||
fees_.hookGasPrice = config.FEES.hook_gas_price;
|
||||
}
|
||||
|
||||
std::shared_ptr<SLE>
|
||||
|
||||
@@ -29,10 +29,10 @@ namespace ripple {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename value_type>
|
||||
class VotableValue
|
||||
{
|
||||
private:
|
||||
using value_type = XRPAmount;
|
||||
value_type const current_; // The current setting
|
||||
value_type const target_; // The setting we want
|
||||
std::map<value_type, int> voteMap_;
|
||||
@@ -67,8 +67,9 @@ public:
|
||||
getVotes() const;
|
||||
};
|
||||
|
||||
auto
|
||||
VotableValue::getVotes() const -> std::pair<value_type, bool>
|
||||
template <typename value_type>
|
||||
std::pair<value_type, bool>
|
||||
VotableValue<value_type>::getVotes() const
|
||||
{
|
||||
value_type ourVote = current_;
|
||||
int weight = 0;
|
||||
@@ -191,6 +192,28 @@ FeeVoteImpl::doValidation(
|
||||
"reserve increment",
|
||||
sfReserveIncrement);
|
||||
}
|
||||
|
||||
if (rules.enabled(featureHookFeeV3))
|
||||
{
|
||||
auto vote = [&v, this](
|
||||
auto const current,
|
||||
std::uint32_t target,
|
||||
char const* name,
|
||||
auto const& sfield) {
|
||||
if (current != target)
|
||||
{
|
||||
JLOG(journal_.info())
|
||||
<< "Voting for " << name << " of " << target;
|
||||
|
||||
v[sfield] = target;
|
||||
}
|
||||
};
|
||||
vote(
|
||||
lastFees.hookGasPrice,
|
||||
target_.hook_gas_price,
|
||||
"hook gas price",
|
||||
sfHookGasPrice);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -213,11 +236,14 @@ FeeVoteImpl::doVoting(
|
||||
detail::VotableValue incReserveVote(
|
||||
lastClosedLedger->fees().increment, target_.owner_reserve);
|
||||
|
||||
detail::VotableValue hookGasPriceVote(
|
||||
lastClosedLedger->fees().hookGasPrice, target_.hook_gas_price);
|
||||
|
||||
auto const& rules = lastClosedLedger->rules();
|
||||
if (rules.enabled(featureXRPFees))
|
||||
{
|
||||
auto doVote = [](std::shared_ptr<STValidation> const& val,
|
||||
detail::VotableValue& value,
|
||||
detail::VotableValue<XRPAmount>& value,
|
||||
SF_AMOUNT const& xrpField) {
|
||||
if (auto const field = ~val->at(~xrpField);
|
||||
field && field->native())
|
||||
@@ -246,7 +272,7 @@ FeeVoteImpl::doVoting(
|
||||
else
|
||||
{
|
||||
auto doVote = [](std::shared_ptr<STValidation> const& val,
|
||||
detail::VotableValue& value,
|
||||
detail::VotableValue<XRPAmount>& value,
|
||||
auto const& valueField) {
|
||||
if (auto const field = val->at(~valueField))
|
||||
{
|
||||
@@ -277,6 +303,23 @@ FeeVoteImpl::doVoting(
|
||||
doVote(val, incReserveVote, sfReserveIncrement);
|
||||
}
|
||||
}
|
||||
if (rules.enabled(featureHookFeeV3))
|
||||
{
|
||||
auto doVote = [](std::shared_ptr<STValidation> const& val,
|
||||
detail::VotableValue<std::uint32_t>& value,
|
||||
SF_UINT32 const& valueField) {
|
||||
if (auto const field = ~val->at(~valueField); field)
|
||||
value.addVote(field.value());
|
||||
else
|
||||
value.noVote();
|
||||
};
|
||||
for (auto const& val : set)
|
||||
{
|
||||
if (!val->isTrusted())
|
||||
continue;
|
||||
doVote(val, hookGasPriceVote, sfHookGasPrice);
|
||||
}
|
||||
}
|
||||
|
||||
// choose our positions
|
||||
// TODO: Use structured binding once LLVM 16 is the minimum supported
|
||||
@@ -285,15 +328,18 @@ FeeVoteImpl::doVoting(
|
||||
auto const baseFee = baseFeeVote.getVotes();
|
||||
auto const baseReserve = baseReserveVote.getVotes();
|
||||
auto const incReserve = incReserveVote.getVotes();
|
||||
auto const hookGasPrice = hookGasPriceVote.getVotes();
|
||||
|
||||
auto const seq = lastClosedLedger->info().seq + 1;
|
||||
|
||||
// add transactions to our position
|
||||
if (baseFee.second || baseReserve.second || incReserve.second)
|
||||
if (baseFee.second || baseReserve.second || incReserve.second ||
|
||||
hookGasPrice.second)
|
||||
{
|
||||
JLOG(journal_.warn())
|
||||
<< "We are voting for a fee change: " << baseFee.first << "/"
|
||||
<< baseReserve.first << "/" << incReserve.first;
|
||||
<< baseReserve.first << "/" << incReserve.first << "/"
|
||||
<< hookGasPrice.first;
|
||||
|
||||
STTx feeTx(ttFEE, [=, &rules](auto& obj) {
|
||||
obj[sfAccount] = AccountID();
|
||||
@@ -317,6 +363,8 @@ FeeVoteImpl::doVoting(
|
||||
incReserveVote.current());
|
||||
obj[sfReferenceFeeUnits] = Config::FEE_UNITS_DEPRECATED;
|
||||
}
|
||||
if (rules.enabled(featureHookFeeV3))
|
||||
obj[sfHookGasPrice] = hookGasPrice.first;
|
||||
});
|
||||
|
||||
uint256 txID = feeTx.getTransactionID();
|
||||
|
||||
@@ -2453,6 +2453,9 @@ NetworkOPsImp::pubValidation(std::shared_ptr<STValidation> const& val)
|
||||
reserveIncXRP && reserveIncXRP->native())
|
||||
jvObj[jss::reserve_inc] = reserveIncXRP->xrp().jsonClipped();
|
||||
|
||||
if (auto const hookGasPrice = ~val->at(~sfHookGasPrice); hookGasPrice)
|
||||
jvObj[jss::hook_gas_price] = *hookGasPrice;
|
||||
|
||||
// NOTE Use MultiApiJson to publish two slightly different JSON objects
|
||||
// for consumers supporting different API versions
|
||||
MultiApiJson multiObj{jvObj};
|
||||
@@ -2920,12 +2923,16 @@ NetworkOPsImp::getServerInfo(bool human, bool admin, bool counters)
|
||||
l[jss::seq] = Json::UInt(lpClosed->info().seq);
|
||||
l[jss::hash] = to_string(lpClosed->info().hash);
|
||||
|
||||
auto const hookFeeV3 = lpClosed->rules().enabled(featureHookFeeV3);
|
||||
|
||||
if (!human)
|
||||
{
|
||||
l[jss::base_fee] = baseFee.jsonClipped();
|
||||
l[jss::reserve_base] =
|
||||
lpClosed->fees().accountReserve(0).jsonClipped();
|
||||
l[jss::reserve_inc] = lpClosed->fees().increment.jsonClipped();
|
||||
if (hookFeeV3)
|
||||
l[jss::hook_gas_price] = lpClosed->fees().hookGasPrice;
|
||||
l[jss::close_time] = Json::Value::UInt(
|
||||
lpClosed->info().closeTime.time_since_epoch().count());
|
||||
}
|
||||
@@ -2941,6 +2948,8 @@ NetworkOPsImp::getServerInfo(bool human, bool admin, bool counters)
|
||||
lpClosed->fees().accountReserve(0).decimalXRP();
|
||||
l[jss::reserve_inc_native] =
|
||||
lpClosed->fees().increment.decimalXRP();
|
||||
if (hookFeeV3)
|
||||
l[jss::hook_gas_price] = lpClosed->fees().hookGasPrice;
|
||||
|
||||
if (auto const closeOffset = app_.timeKeeper().closeOffset();
|
||||
std::abs(closeOffset.count()) >= 60)
|
||||
@@ -3131,6 +3140,9 @@ NetworkOPsImp::pubLedger(std::shared_ptr<ReadView const> const& lpAccepted)
|
||||
jvObj[jss::reserve_inc] =
|
||||
lpAccepted->fees().increment.jsonClipped();
|
||||
|
||||
if (lpAccepted->rules().enabled(featureHookFeeV3))
|
||||
jvObj[jss::hook_gas_price] = lpAccepted->fees().hookGasPrice;
|
||||
|
||||
jvObj[jss::txn_count] = Json::UInt(alpAccepted->size());
|
||||
|
||||
if (mMode >= OperatingMode::SYNCING)
|
||||
@@ -4185,6 +4197,8 @@ NetworkOPsImp::subLedger(InfoSub::ref isrListener, Json::Value& jvResult)
|
||||
jvResult[jss::reserve_base] =
|
||||
lpClosed->fees().accountReserve(0).jsonClipped();
|
||||
jvResult[jss::reserve_inc] = lpClosed->fees().increment.jsonClipped();
|
||||
if (lpClosed->rules().enabled(featureHookFeeV3))
|
||||
jvResult[jss::hook_gas_price] = lpClosed->fees().hookGasPrice;
|
||||
}
|
||||
|
||||
if ((mMode >= OperatingMode::SYNCING) && !isNeedNetworkLedger())
|
||||
|
||||
@@ -152,6 +152,16 @@ Change::preclaim(PreclaimContext const& ctx)
|
||||
ctx.tx.isFieldPresent(sfReserveIncrementDrops))
|
||||
return temDISABLED;
|
||||
}
|
||||
if (ctx.view.rules().enabled(featureHookFeeV3))
|
||||
{
|
||||
if (!ctx.tx.isFieldPresent(sfHookGasPrice))
|
||||
return temMALFORMED;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ctx.tx.isFieldPresent(sfHookGasPrice))
|
||||
return temDISABLED;
|
||||
}
|
||||
return tesSUCCESS;
|
||||
case ttAMENDMENT:
|
||||
case ttUNL_MODIFY:
|
||||
@@ -605,6 +615,7 @@ Change::activateXahauGenesis()
|
||||
wasmBytes, // wasm to verify
|
||||
loggerStream,
|
||||
"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
|
||||
false,
|
||||
hook_api::getImportWhitelist(ctx_.view().rules()),
|
||||
hook_api::getGuardRulesVersion(ctx_.view().rules()));
|
||||
|
||||
@@ -1034,6 +1045,8 @@ Change::applyFee()
|
||||
set(feeObject, ctx_.tx, sfReserveBase);
|
||||
set(feeObject, ctx_.tx, sfReserveIncrement);
|
||||
}
|
||||
if (view().rules().enabled(featureHookFeeV3))
|
||||
set(feeObject, ctx_.tx, sfHookGasPrice);
|
||||
|
||||
view().update(feeObject);
|
||||
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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 <xrpld/app/tx/detail/HookDefinitionUpdate.h>
|
||||
#include <xrpl/protocol/TxFlags.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
NotTEC
|
||||
HookDefinitionUpdate::preflight(PreflightContext const& ctx)
|
||||
{
|
||||
if (!ctx.rules.enabled(featureHookFeeV2))
|
||||
return temDISABLED;
|
||||
|
||||
if (auto const ret = preflight1(ctx); !isTesSuccess(ret))
|
||||
return ret;
|
||||
|
||||
auto const& tx = ctx.tx;
|
||||
|
||||
if (tx.getFlags() & tfHookDefinitionUpdateMask)
|
||||
return temINVALID_FLAG;
|
||||
|
||||
return preflight2(ctx);
|
||||
}
|
||||
|
||||
TER
|
||||
HookDefinitionUpdate::preclaim(PreclaimContext const& ctx)
|
||||
{
|
||||
auto const& view = ctx.view;
|
||||
auto const& tx = ctx.tx;
|
||||
|
||||
if (!view.exists(keylet::hookDefinition(tx.getFieldH256(sfHookHash))))
|
||||
return tecNO_ENTRY;
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
TER
|
||||
HookDefinitionUpdate::doApply()
|
||||
{
|
||||
auto& view = ctx_.view();
|
||||
auto const& tx = ctx_.tx;
|
||||
|
||||
auto hookDefSle =
|
||||
view.peek(keylet::hookDefinition(tx.getFieldH256(sfHookHash)));
|
||||
if (!hookDefSle)
|
||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
Blob hook = hookDefSle->getFieldVL(sfCreateCode);
|
||||
|
||||
if (!tx.isFlag(tfValidateGuards))
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
auto const result =
|
||||
hook::doValidateGuards(tx, hook, view.rules(), ctx_.journal);
|
||||
if (!result)
|
||||
// TODO: TEQU better error code
|
||||
// For compatibility, if an already deployed HookDefinition fails with a
|
||||
// new guard-checker, don't update/delete it
|
||||
return tecINTERNAL;
|
||||
|
||||
auto const [hookCost, callbackCost] = *result;
|
||||
|
||||
{
|
||||
// if result is same as old, don't update sle
|
||||
if (hookCost == hookDefSle->getFieldU64(sfHookCost) &&
|
||||
callbackCost == hookDefSle->getFieldU64(sfHookCallbackCost))
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
{
|
||||
// set new cost fields
|
||||
hookDefSle->setFieldU64(sfHookCost, hookCost);
|
||||
if (callbackCost > 0)
|
||||
hookDefSle->setFieldU64(sfHookCallbackCost, callbackCost);
|
||||
else if (hookDefSle->isFieldPresent(sfHookCallbackCost))
|
||||
hookDefSle->makeFieldAbsent(sfHookCallbackCost);
|
||||
}
|
||||
|
||||
{
|
||||
// remove old fee fields
|
||||
if (hookDefSle->isFieldPresent(sfFee))
|
||||
hookDefSle->makeFieldAbsent(sfFee);
|
||||
if (hookDefSle->isFieldPresent(sfHookCallbackFee))
|
||||
hookDefSle->makeFieldAbsent(sfHookCallbackFee);
|
||||
}
|
||||
|
||||
view.update(hookDefSle);
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
XRPAmount
|
||||
HookDefinitionUpdate::calculateBaseFee(ReadView const& view, STTx const& tx)
|
||||
{
|
||||
auto const baseFee = Transactor::calculateBaseFee(view, tx);
|
||||
|
||||
auto const& hookDefSle =
|
||||
view.read(keylet::hookDefinition(tx.getFieldH256(sfHookHash)));
|
||||
|
||||
if (!hookDefSle || !hookDefSle->isFieldPresent(sfCreateCode))
|
||||
// if hook definition is not present, doValidateGuards will not call, so
|
||||
// no additional fee is needed
|
||||
return baseFee;
|
||||
|
||||
auto const hookCodeSize = hookDefSle->getFieldVL(sfCreateCode).size();
|
||||
|
||||
return baseFee + XRPAmount{hook::computeCreationFee(hookCodeSize)};
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
@@ -0,0 +1,53 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_TX_HOOKDEFINITIONUPDATE_H_INCLUDED
|
||||
#define RIPPLE_TX_HOOKDEFINITIONUPDATE_H_INCLUDED
|
||||
|
||||
#include <xrpld/app/tx/detail/Transactor.h>
|
||||
#include <xrpl/basics/Log.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
class HookDefinitionUpdate : public Transactor
|
||||
{
|
||||
public:
|
||||
static constexpr ConsequencesFactoryType ConsequencesFactory{Normal};
|
||||
|
||||
explicit HookDefinitionUpdate(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static XRPAmount
|
||||
calculateBaseFee(ReadView const& view, STTx const& tx);
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const&);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
@@ -556,59 +556,8 @@ SetHook::validateHookSetEntry(SetHookCtx& ctx, STObject const& hookSetObj)
|
||||
|
||||
Blob hook = hookSetObj.getFieldVL(sfCreateCode);
|
||||
|
||||
// RH NOTE: validateGuards has a generic non-rippled specific
|
||||
// interface so it can be used in other projects (i.e. tooling).
|
||||
// As such the calling here is a bit convoluted.
|
||||
|
||||
std::optional<std::reference_wrapper<std::basic_ostream<char>>>
|
||||
logger;
|
||||
std::ostringstream loggerStream;
|
||||
std::string hsacc{""};
|
||||
if (ctx.j.trace())
|
||||
{
|
||||
logger = loggerStream;
|
||||
std::stringstream ss;
|
||||
ss << HS_ACC();
|
||||
hsacc = ss.str();
|
||||
}
|
||||
|
||||
auto result = validateGuards(
|
||||
hook, // wasm to verify
|
||||
logger,
|
||||
hsacc,
|
||||
hook_api::getImportWhitelist(ctx.rules),
|
||||
hook_api::getGuardRulesVersion(ctx.rules));
|
||||
|
||||
if (ctx.j.trace())
|
||||
{
|
||||
// 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<char> 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)
|
||||
{
|
||||
if (data[i] == '\n')
|
||||
{
|
||||
data[i] = '\0';
|
||||
ctx.j.trace() << last;
|
||||
last = data + i;
|
||||
}
|
||||
}
|
||||
|
||||
if (last < data + i)
|
||||
ctx.j.trace() << last;
|
||||
}
|
||||
auto const result =
|
||||
hook::doValidateGuards(ctx.tx, hook, ctx.rules, ctx.j);
|
||||
|
||||
if (!result)
|
||||
return false;
|
||||
@@ -1871,9 +1820,11 @@ SetHook::setHook()
|
||||
"SetHook::hsoCREATE : should never happen");
|
||||
}
|
||||
|
||||
// otherwise assign instruction counts
|
||||
std::tie(maxInstrCountHook, maxInstrCountCbak) =
|
||||
auto const instrCounts =
|
||||
std::get<std::pair<uint64_t, uint64_t>>(valid);
|
||||
|
||||
std::tie(maxInstrCountHook, maxInstrCountCbak) =
|
||||
instrCounts;
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
@@ -1927,15 +1878,26 @@ SetHook::setHook()
|
||||
newHookDef->setFieldH256(
|
||||
sfHookSetTxnID, ctx.tx.getTransactionID());
|
||||
newHookDef->setFieldU64(sfReferenceCount, 1);
|
||||
newHookDef->setFieldAmount(
|
||||
sfFee,
|
||||
XRPAmount{
|
||||
hook::computeExecutionFee(maxInstrCountHook)});
|
||||
if (maxInstrCountCbak > 0)
|
||||
|
||||
if (view().rules().enabled(featureHookFeeV2))
|
||||
{
|
||||
newHookDef->setFieldU64(sfHookCost, maxInstrCountHook);
|
||||
if (maxInstrCountCbak > 0)
|
||||
newHookDef->setFieldU64(
|
||||
sfHookCallbackCost, maxInstrCountCbak);
|
||||
}
|
||||
else
|
||||
{
|
||||
newHookDef->setFieldAmount(
|
||||
sfHookCallbackFee,
|
||||
sfFee,
|
||||
XRPAmount{
|
||||
hook::computeExecutionFee(maxInstrCountCbak)});
|
||||
hook::computeExecutionFee(maxInstrCountHook)});
|
||||
if (maxInstrCountCbak > 0)
|
||||
newHookDef->setFieldAmount(
|
||||
sfHookCallbackFee,
|
||||
XRPAmount{hook::computeExecutionFee(
|
||||
maxInstrCountCbak)});
|
||||
}
|
||||
|
||||
if (flags)
|
||||
newHookDef->setFieldU32(sfFlags, newFlags);
|
||||
|
||||
@@ -251,7 +251,7 @@ Transactor::Transactor(ApplyContext& ctx)
|
||||
|
||||
// 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
|
||||
std::pair<XRPAmount, uint64_t>
|
||||
Transactor::calculateHookChainFee(
|
||||
ReadView const& view,
|
||||
STTx const& tx,
|
||||
@@ -261,9 +261,10 @@ Transactor::calculateHookChainFee(
|
||||
{
|
||||
std::shared_ptr<SLE const> hookSLE = view.read(hookKeylet);
|
||||
if (!hookSLE)
|
||||
return XRPAmount{0};
|
||||
return std::make_pair(XRPAmount{0}, 0);
|
||||
|
||||
XRPAmount fee{0};
|
||||
uint64_t hookCost{0};
|
||||
|
||||
auto const& hooks = hookSLE->getFieldArray(sfHooks);
|
||||
|
||||
@@ -302,19 +303,35 @@ Transactor::calculateHookChainFee(
|
||||
if (hook::canHook(tx, hookOn, hookName) &&
|
||||
(!collectCallsOnly || (flags & hook::hsfCOLLECT)))
|
||||
{
|
||||
XRPAmount const toAdd{hookDef->getFieldAmount(sfFee).xrp().drops()};
|
||||
if (hookDef->isFieldPresent(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()};
|
||||
// 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
|
||||
fee += toAdd;
|
||||
{
|
||||
uint64_t const toAdd{hookDef->getFieldU64(sfHookCost)};
|
||||
|
||||
// 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 (hookCost + toAdd < hookCost)
|
||||
hookCost = std::numeric_limits<uint64_t>::max();
|
||||
else
|
||||
hookCost += toAdd;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fee;
|
||||
return std::make_pair(fee, hookCost);
|
||||
}
|
||||
|
||||
XRPAmount
|
||||
@@ -340,6 +357,7 @@ Transactor::calculateBaseFee(ReadView const& view, STTx const& tx)
|
||||
tx.isFieldPresent(sfSigners) ? tx.getFieldArray(sfSigners).size() : 0;
|
||||
|
||||
XRPAmount hookExecutionFee{0};
|
||||
uint64_t hookCost{0};
|
||||
uint64_t burden{1};
|
||||
if (view.rules().enabled(featureHooks))
|
||||
{
|
||||
@@ -362,18 +380,32 @@ Transactor::calculateBaseFee(ReadView const& view, STTx const& tx)
|
||||
std::shared_ptr<SLE const> hookDef =
|
||||
view.read(keylet::hookDefinition(callbackHookHash));
|
||||
|
||||
if (hookDef && hookDef->isFieldPresent(sfHookCallbackFee))
|
||||
if (hookDef)
|
||||
{
|
||||
XRPAmount const toAdd{
|
||||
hookDef->getFieldAmount(sfHookCallbackFee).xrp().drops()};
|
||||
if (hookDef->isFieldPresent(sfHookCallbackFee))
|
||||
{
|
||||
XRPAmount const toAdd{
|
||||
hookDef->getFieldAmount(sfHookCallbackFee)
|
||||
.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 (hookExecutionFee + toAdd < hookExecutionFee)
|
||||
hookExecutionFee = XRPAmount{INITIAL_XRP.drops()};
|
||||
else
|
||||
hookExecutionFee += toAdd;
|
||||
// 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 (hookExecutionFee + toAdd < hookExecutionFee)
|
||||
hookExecutionFee = XRPAmount{INITIAL_XRP.drops()};
|
||||
else
|
||||
hookExecutionFee += toAdd;
|
||||
}
|
||||
if (hookDef->isFieldPresent(sfHookCallbackCost))
|
||||
{
|
||||
uint64_t const toAdd{
|
||||
hookDef->getFieldU64(sfHookCallbackCost)};
|
||||
if (hookCost + toAdd < hookCost)
|
||||
hookCost = std::numeric_limits<uint64_t>::max();
|
||||
else
|
||||
hookCost += toAdd;
|
||||
}
|
||||
}
|
||||
|
||||
XRPL_ASSERT(
|
||||
@@ -383,8 +415,12 @@ Transactor::calculateBaseFee(ReadView const& view, STTx const& tx)
|
||||
burden = emitDetails.getFieldU64(sfEmitBurden);
|
||||
}
|
||||
else
|
||||
hookExecutionFee += calculateHookChainFee(
|
||||
{
|
||||
auto const hookChainFee = calculateHookChainFee(
|
||||
view, tx, keylet::hook(tx.getAccountID(sfAccount)), true);
|
||||
hookExecutionFee += hookChainFee.first;
|
||||
hookCost += hookChainFee.second;
|
||||
}
|
||||
|
||||
// find any additional stakeholders whose hooks will be executed and
|
||||
// charged to this transaction
|
||||
@@ -393,8 +429,12 @@ Transactor::calculateBaseFee(ReadView const& view, STTx const& tx)
|
||||
|
||||
for (auto& [tshAcc, canRollback] : tsh)
|
||||
if (canRollback)
|
||||
hookExecutionFee += calculateHookChainFee(
|
||||
{
|
||||
auto const hookChainFee = calculateHookChainFee(
|
||||
view, tx, keylet::hook(tshAcc), false);
|
||||
hookExecutionFee += hookChainFee.first;
|
||||
hookCost += hookChainFee.second;
|
||||
}
|
||||
}
|
||||
|
||||
XRPAmount accumulator = baseFee;
|
||||
@@ -448,6 +488,8 @@ Transactor::calculateBaseFee(ReadView const& view, STTx const& tx)
|
||||
// transaction.
|
||||
do
|
||||
{
|
||||
hookExecutionFee += hook::hookCostToFee(view, hookCost);
|
||||
|
||||
if (accumulator * burden < accumulator)
|
||||
break;
|
||||
|
||||
@@ -1408,7 +1450,8 @@ Transactor::executeHookChain(
|
||||
return tecINTERNAL;
|
||||
}
|
||||
|
||||
bool hasCallback = hookDef->isFieldPresent(sfHookCallbackFee);
|
||||
bool hasCallback = hookDef->isFieldPresent(sfHookCallbackFee) ||
|
||||
hookDef->isFieldPresent(sfHookCallbackCost);
|
||||
|
||||
try
|
||||
{
|
||||
@@ -1513,7 +1556,8 @@ Transactor::doHookCallback(
|
||||
return;
|
||||
}
|
||||
|
||||
if (!hookDef->isFieldPresent(sfHookCallbackFee))
|
||||
if (!hookDef->isFieldPresent(sfHookCallbackFee) &&
|
||||
!hookDef->isFieldPresent(sfHookCallbackCost))
|
||||
{
|
||||
JLOG(j_.trace()) << "HookInfo[" << callbackAccountID
|
||||
<< "]: Callback specified by emitted txn "
|
||||
@@ -1732,8 +1776,11 @@ Transactor::doTSH(
|
||||
continue;
|
||||
|
||||
// compute and deduct fees for the TSH if applicable
|
||||
XRPAmount tshFeeDrops = calculateHookChainFee(
|
||||
auto const tshFee = calculateHookChainFee(
|
||||
view, ctx_.tx, klTshHook, false, !canRollback);
|
||||
XRPAmount tshFeeDrops{tshFee.first};
|
||||
|
||||
tshFeeDrops += hook::hookCostToFee(view, tshFee.second);
|
||||
|
||||
// no hooks to execute, skip tsh
|
||||
if (tshFeeDrops == 0)
|
||||
@@ -1888,7 +1935,8 @@ Transactor::doAgainAsWeak(
|
||||
stateMap,
|
||||
ctx_,
|
||||
hookAccountID,
|
||||
hookDef->isFieldPresent(sfHookCallbackFee),
|
||||
hookDef->isFieldPresent(sfHookCallbackFee) ||
|
||||
hookDef->isFieldPresent(sfHookCallbackCost),
|
||||
false,
|
||||
false,
|
||||
2UL, // param 2 = aaw
|
||||
|
||||
@@ -174,7 +174,7 @@ public:
|
||||
|
||||
// Hooks
|
||||
|
||||
static XRPAmount
|
||||
static std::pair<XRPAmount, uint64_t>
|
||||
calculateHookChainFee(
|
||||
ReadView const& view,
|
||||
STTx const& tx,
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
#include <xrpld/app/tx/detail/DepositPreauth.h>
|
||||
#include <xrpld/app/tx/detail/Escrow.h>
|
||||
#include <xrpld/app/tx/detail/GenesisMint.h>
|
||||
#include <xrpld/app/tx/detail/HookDefinitionUpdate.h>
|
||||
#include <xrpld/app/tx/detail/Import.h>
|
||||
#include <xrpld/app/tx/detail/Invoke.h>
|
||||
#include <xrpld/app/tx/detail/LedgerStateFix.h>
|
||||
|
||||
@@ -82,6 +82,9 @@ struct FeeSetup
|
||||
/** The per-owned item reserve requirement in drops. */
|
||||
XRPAmount owner_reserve{2 * DROPS_PER_XRP};
|
||||
|
||||
/** The gas price for hooks in drops. */
|
||||
std::uint32_t hook_gas_price{1'000'000}; // TODO: default value
|
||||
|
||||
/* (Remember to update the example cfg files when changing any of these
|
||||
* values.) */
|
||||
};
|
||||
|
||||
@@ -1194,6 +1194,13 @@ setup_FeeVote(Section const& section)
|
||||
if (set(temp, "owner_reserve", section))
|
||||
setup.owner_reserve = temp;
|
||||
}
|
||||
{
|
||||
std::uint32_t temp;
|
||||
if (set(temp, "hook_gas_price", section))
|
||||
{
|
||||
setup.hook_gas_price = temp;
|
||||
}
|
||||
}
|
||||
return setup;
|
||||
}
|
||||
} // namespace ripple
|
||||
Reference in new issue
Block a user