From 90333b6fd0bca95ce9e68e47b04ada12dc28045a Mon Sep 17 00:00:00 2001 From: tequ Date: Tue, 26 May 2026 10:02:17 +0900 Subject: [PATCH] Fix HookAPI Expected and Refactor Enum classes (#729) --- hook/generate_error.sh | 4 +- include/xrpl/hook/Enum.h | 4 +- include/xrpl/hook/Macro.h | 109 +++++---- src/test/app/HookAPI_test.cpp | 245 +++++++++++++++++++ src/xrpld/app/hook/HookAPI.h | 297 ++++++++++++++++++++++- src/xrpld/app/hook/detail/HookAPI.cpp | 306 ++---------------------- src/xrpld/app/hook/detail/applyHook.cpp | 289 ++++++---------------- 7 files changed, 689 insertions(+), 565 deletions(-) diff --git a/hook/generate_error.sh b/hook/generate_error.sh index 5aa232f2b..b1e85092b 100755 --- a/hook/generate_error.sh +++ b/hook/generate_error.sh @@ -9,7 +9,7 @@ ENUM_FILE="$SCRIPT_DIR/../include/xrpl/hook/Enum.h" echo '// For documentation please see: https://xrpl-hooks.readme.io/reference/' echo '// Generated using generate_error.sh' echo '#ifndef HOOK_ERROR_CODES' -sed -n '/enum hook_return_code/,/};/p' "$ENUM_FILE" | +sed -n '/enum class hook_return_code/,/};/p' "$ENUM_FILE" | awk ' function ltrim(s) { sub(/^[[:space:]]+/, "", s); return s } function rtrim(s) { sub(/[[:space:]]+$/, "", s); return s } @@ -31,7 +31,7 @@ sed -n '/enum hook_return_code/,/};/p' "$ENUM_FILE" | { line = $0 - if (line ~ /enum[[:space:]]+hook_return_code/) + if (line ~ /enum[[:space:]]+class[[:space:]]+hook_return_code/) next if (line ~ /^[[:space:]]*\{/) next diff --git a/include/xrpl/hook/Enum.h b/include/xrpl/hook/Enum.h index 97657f9c4..9dbce0f33 100644 --- a/include/xrpl/hook/Enum.h +++ b/include/xrpl/hook/Enum.h @@ -320,7 +320,7 @@ namespace compare_mode { enum compare_mode : uint32_t { EQUAL = 1, LESS = 2, GREATER = 4 }; } -enum hook_return_code : int64_t { +enum class hook_return_code : int64_t { SUCCESS = 0, // return codes > 0 are reserved for hook apis to return "success" OUT_OF_BOUNDS = @@ -387,7 +387,7 @@ enum hook_return_code : int64_t { TOO_MANY_NAMESPACES = -45 }; -enum ExitType : uint8_t { +enum class ExitType : uint8_t { UNSET = 0, WASM_ERROR = 1, ROLLBACK = 2, diff --git a/include/xrpl/hook/Macro.h b/include/xrpl/hook/Macro.h index 99d1f42f7..45e6a8db9 100644 --- a/include/xrpl/hook/Macro.h +++ b/include/xrpl/hook/Macro.h @@ -89,58 +89,69 @@ #define WASM_VAL_TYPE(T, b) CAT2(TYP_, T) -#define DECLARE_HOOK_FUNCTION(R, F, ...) \ - R F(hook::HookContext& hookCtx, \ - WasmEdge_CallingFrameContext const& frameCtx __VA_OPT__( \ - COMMA __VA_ARGS__)); \ - extern WasmEdge_Result WasmFunction##F( \ - void* data_ptr, \ - const WasmEdge_CallingFrameContext* frameCtx, \ - const WasmEdge_Value* in, \ - WasmEdge_Value* out); \ - extern WasmEdge_ValType WasmFunctionParams##F[]; \ - extern WasmEdge_ValType WasmFunctionResult##F[]; \ - extern WasmEdge_FunctionTypeContext* WasmFunctionType##F; \ +#define UNSIGNED_TYPE(T) std::make_unsigned_t + +#define DECLARE_HOOK_FUNCTION(R, F, ...) \ + std::variant F( \ + hook::HookContext& hookCtx, \ + WasmEdge_CallingFrameContext const& frameCtx __VA_OPT__( \ + COMMA __VA_ARGS__)); \ + extern WasmEdge_Result WasmFunction##F( \ + void* data_ptr, \ + const WasmEdge_CallingFrameContext* frameCtx, \ + const WasmEdge_Value* in, \ + WasmEdge_Value* out); \ + extern WasmEdge_ValType WasmFunctionParams##F[]; \ + extern WasmEdge_ValType WasmFunctionResult##F[]; \ + extern WasmEdge_FunctionTypeContext* WasmFunctionType##F; \ extern WasmEdge_String WasmFunctionName##F; -#define DEFINE_HOOK_FUNCTION(R, F, ...) \ - WasmEdge_Result hook_api::WasmFunction##F( \ - void* data_ptr, \ - const WasmEdge_CallingFrameContext* frameCtx, \ - const WasmEdge_Value* in, \ - WasmEdge_Value* out) \ - { \ - __VA_OPT__(int _stack = 0;) \ - __VA_OPT__(FOR_VARS(VAR_ASSIGN, 2, __VA_ARGS__);) \ - hook::HookContext* hookCtx = \ - reinterpret_cast(data_ptr); \ - R return_code = hook_api::F( \ - *hookCtx, \ - *const_cast(frameCtx) \ - __VA_OPT__(COMMA STRIP_TYPES(__VA_ARGS__))); \ - if (return_code == RC_ROLLBACK || return_code == RC_ACCEPT) \ - return WasmEdge_Result_Terminate; \ - out[0] = RET_ASSIGN(R, return_code); \ - return WasmEdge_Result_Success; \ - }; \ - WasmEdge_ValType hook_api::WasmFunctionParams##F[] = { \ - __VA_OPT__(FOR_VARS(WASM_VAL_TYPE, 0, __VA_ARGS__))}; \ - WasmEdge_ValType hook_api::WasmFunctionResult##F[1] = { \ - WASM_VAL_TYPE(R, dummy)}; \ - WasmEdge_FunctionTypeContext* hook_api::WasmFunctionType##F = \ - WasmEdge_FunctionTypeCreate( \ - WasmFunctionParams##F, \ - VA_NARGS(NULL __VA_OPT__(, __VA_ARGS__)), \ - WasmFunctionResult##F, \ - 1); \ - WasmEdge_String hook_api::WasmFunctionName##F = \ - WasmEdge_StringCreateByCString(#F); \ - R hook_api::F( \ - hook::HookContext& hookCtx, \ - WasmEdge_CallingFrameContext const& frameCtx __VA_OPT__( \ +#define DEFINE_HOOK_FUNCTION(R, F, ...) \ + WasmEdge_Result hook_api::WasmFunction##F( \ + void* data_ptr, \ + const WasmEdge_CallingFrameContext* frameCtx, \ + const WasmEdge_Value* in, \ + WasmEdge_Value* out) \ + { \ + __VA_OPT__(int _stack = 0;) \ + __VA_OPT__(FOR_VARS(VAR_ASSIGN, 2, __VA_ARGS__);) \ + hook::HookContext* hookCtx = \ + reinterpret_cast(data_ptr); \ + auto const& return_code = hook_api::F( \ + *hookCtx, \ + *const_cast(frameCtx) \ + __VA_OPT__(COMMA STRIP_TYPES(__VA_ARGS__))); \ + if (std::holds_alternative(return_code) && \ + (std::get(return_code) == \ + RC_ROLLBACK || \ + std::get(return_code) == RC_ACCEPT)) \ + return WasmEdge_Result_Terminate; \ + out[0] = RET_ASSIGN( \ + R, \ + std::holds_alternative(return_code) \ + ? std::get(return_code) \ + : R(std::get(return_code))); \ + return WasmEdge_Result_Success; \ + }; \ + WasmEdge_ValType hook_api::WasmFunctionParams##F[] = { \ + __VA_OPT__(FOR_VARS(WASM_VAL_TYPE, 0, __VA_ARGS__))}; \ + WasmEdge_ValType hook_api::WasmFunctionResult##F[1] = { \ + WASM_VAL_TYPE(R, dummy)}; \ + WasmEdge_FunctionTypeContext* hook_api::WasmFunctionType##F = \ + WasmEdge_FunctionTypeCreate( \ + WasmFunctionParams##F, \ + VA_NARGS(NULL __VA_OPT__(, __VA_ARGS__)), \ + WasmFunctionResult##F, \ + 1); \ + WasmEdge_String hook_api::WasmFunctionName##F = \ + WasmEdge_StringCreateByCString(#F); \ + std::variant hook_api::F( \ + hook::HookContext& hookCtx, \ + WasmEdge_CallingFrameContext const& frameCtx __VA_OPT__( \ COMMA __VA_ARGS__)) #define HOOK_SETUP() \ + using enum hook_api::hook_return_code; \ try \ { \ [[maybe_unused]] ApplyContext& applyCtx = hookCtx.applyCtx; \ @@ -203,7 +214,7 @@ host_memory_ptr, \ guest_memory_length) \ { \ - int64_t bytes_written = 0; \ + uint64_t bytes_written = 0; \ WRITE_WASM_MEMORY( \ bytes_written, \ guest_dst_ptr, \ @@ -272,7 +283,7 @@ data_ptr < (data_ptr_in)) \ return INTERNAL_ERROR; \ if (data_len == 0) \ - return 0; \ + return 0ULL; \ if ((write_ptr_in) == 0) \ return data_as_int64(data_ptr, data_len); \ if (data_len > (write_len_in)) \ diff --git a/src/test/app/HookAPI_test.cpp b/src/test/app/HookAPI_test.cpp index c50cef346..6a3546016 100644 --- a/src/test/app/HookAPI_test.cpp +++ b/src/test/app/HookAPI_test.cpp @@ -50,6 +50,7 @@ private: } public: + using enum hook_api::hook_return_code; void test_accept(FeatureBitset features) { @@ -4513,6 +4514,249 @@ public: BEAST_EXPECT(ok.value()); } + void + testHookFloat(FeatureBitset features) + { + // testcase("Test hook float"); + using namespace jtx; + using namespace hook::hook_float; + + { + // get_exponent + testcase << "get_exponent"; + BEAST_EXPECT(get_exponent(-1).error() == INVALID_FLOAT); + BEAST_EXPECT(get_exponent(0).value() == 0); + // 1234567891000000 * 10^(-5) + BEAST_EXPECT(get_exponent(6270245249190730432).value() == -5); + } + + { + // get_mantissa + testcase << "get_mantissa"; + BEAST_EXPECT(get_mantissa(-1).error() == INVALID_FLOAT); + BEAST_EXPECT(get_mantissa(0).value() == 0); + // 1234567891000000 * 10^(-5) + BEAST_EXPECT( + get_mantissa(6270245249190730432).value() == 1234567891000000); + } + + { + // is_negative + testcase << "is_negative"; + // 1234567891000000 * 10^(-5) + BEAST_EXPECT(is_negative(6270245249190730432) == false); + // -1234567891000000 * 10^(-5) + BEAST_EXPECT(is_negative(1658559230763342528) == true); + } + + { + // invert_sign + testcase << "invert_sign"; + BEAST_EXPECT( + invert_sign(6270245249190730432) == 1658559230763342528); + BEAST_EXPECT( + invert_sign(1658559230763342528) == 6270245249190730432); + } + + { + // set_sign + testcase << "set_sign"; + BEAST_EXPECT( + set_sign(6270245249190730432, true) == 1658559230763342528); + BEAST_EXPECT( + set_sign(1658559230763342528, false) == 6270245249190730432); + BEAST_EXPECT( + set_sign(6270245249190730432, false) == 6270245249190730432); + BEAST_EXPECT( + set_sign(1658559230763342528, true) == 1658559230763342528); + } + + { + // set_mantissa + testcase << "set_mantissa"; + + BEAST_EXPECT( + set_mantissa(6270245249190730432, maxMantissa + 1).error() == + MANTISSA_OVERSIZED); + BEAST_EXPECT( + set_mantissa(6270245249190730432, minMantissa - 1).error() == + MANTISSA_UNDERSIZED); + + BEAST_EXPECT( + set_mantissa(6270245249190730432, 1234567891000000).value() == + 6270245249190730432); + BEAST_EXPECT( + set_mantissa(1658559230763342528, 1234567891000000).value() == + 1658559230763342528); + + BEAST_EXPECT( + set_mantissa(6270245249190730432, 1098765432100000).value() == + 6270109446731830432); + BEAST_EXPECT( + set_mantissa(1658559230763342528, 1098765432100000).value() == + 1658423428304442528); + } + + { + // set_exponent + testcase << "set_exponent"; + BEAST_EXPECT( + set_exponent(6270245249190730432, maxExponent + 1).error() == + EXPONENT_OVERSIZED); + BEAST_EXPECT( + set_exponent(6270245249190730432, minExponent - 1).error() == + EXPONENT_UNDERSIZED); + + BEAST_EXPECT( + set_exponent(6270245249190730432, 40).value() == + 7080893182117419712); + BEAST_EXPECT( + set_exponent(6270245249190730432, -40).value() == + 5639741301358860992); + } + + { + // make_float + testcase << "make_float"; + + BEAST_EXPECT(make_float(0, -5, false).value() == 0); + + // invalid mantissa + BEAST_EXPECT( + make_float(maxMantissa + 1, -5, false).error() == + MANTISSA_OVERSIZED); + BEAST_EXPECT( + make_float(minMantissa - 1, -5, false).error() == + MANTISSA_UNDERSIZED); + + // invalid exponent + BEAST_EXPECT( + make_float(1234567891000000, maxExponent + 1, false).error() == + EXPONENT_OVERSIZED); + BEAST_EXPECT( + make_float(1234567891000000, minExponent - 1, false).error() == + EXPONENT_UNDERSIZED); + + BEAST_EXPECT( + make_float(1234567891000000, -5, false).value() == + 6270245249190730432); + BEAST_EXPECT( + make_float(1234567891000000, -5, true).value() == + 1658559230763342528); + } + + { + // normalize_xfl + testcase << "normalize_xfl"; + + { + // zero + uint64_t mantissa = 0; + int32_t exponent = -5; + + BEAST_EXPECT( + normalize_xfl(mantissa, exponent, false).value() == 0); + BEAST_EXPECT(mantissa == 0); + BEAST_EXPECT(exponent == -5); + } + + { + // scale the mantissa up into the canonical range + uint64_t mantissa = 12345; + int32_t exponent = 0; + + BEAST_EXPECT( + normalize_xfl(mantissa, exponent, false).value() == + make_float(1234500000000000ULL, -11, false).value()); + BEAST_EXPECT(mantissa == 1234500000000000ULL); + BEAST_EXPECT(exponent == -11); + } + + { + // scale the mantissa down into the canonical range + uint64_t mantissa = 1234567891000000000ULL; + int32_t exponent = -5; + + BEAST_EXPECT( + normalize_xfl(mantissa, exponent, false).value() == + make_float(1234567891000000ULL, -2, false).value()); + BEAST_EXPECT(mantissa == 1234567891000000ULL); + BEAST_EXPECT(exponent == -2); + } + + { + // explicit negative sign + uint64_t mantissa = 12345; + int32_t exponent = 0; + + BEAST_EXPECT( + normalize_xfl(mantissa, exponent, true).value() == + make_float(1234500000000000ULL, -11, true).value()); + BEAST_EXPECT(mantissa == 1234500000000000ULL); + BEAST_EXPECT(exponent == -11); + } + + { + // signed negative mantissa + int64_t mantissa = -12345; + int32_t exponent = 0; + + BEAST_EXPECT( + normalize_xfl(mantissa, exponent).value() == + make_float(1234500000000000ULL, -11, true).value()); + BEAST_EXPECT(mantissa == -1234500000000000LL); + BEAST_EXPECT(exponent == -11); + } + + { + // signed minimum is adjusted before taking the absolute value + int64_t mantissa = std::numeric_limits::min(); + int32_t exponent = 0; + + BEAST_EXPECT( + normalize_xfl(mantissa, exponent).value() == + make_float(9223372036854775ULL, 3, true).value()); + BEAST_EXPECT(mantissa == -9223372036854775LL); + BEAST_EXPECT(exponent == 3); + } + + { + // one below the minimum mantissa is rounded into range + uint64_t mantissa = minMantissa - 1; + int32_t exponent = -5; + + BEAST_EXPECT( + normalize_xfl(mantissa, exponent, false).value() == + make_float(minMantissa, -5, false).value()); + BEAST_EXPECT(mantissa == minMantissa); + BEAST_EXPECT(exponent == -5); + } + + { + // underflow returns canonical zero + uint64_t mantissa = 1; + int32_t exponent = minExponent; + + BEAST_EXPECT( + normalize_xfl(mantissa, exponent, false).value() == 0); + BEAST_EXPECT(mantissa == 0); + BEAST_EXPECT(exponent == 0); + } + + { + // exponent overflow is reported + uint64_t mantissa = minMantissa; + int32_t exponent = maxExponent + 1; + + BEAST_EXPECT( + normalize_xfl(mantissa, exponent, false).error() == + XFL_OVERFLOW); + BEAST_EXPECT(mantissa == minMantissa); + BEAST_EXPECT(exponent == maxExponent + 1); + } + } + } + void testWithFeatures(FeatureBitset features) { @@ -4615,6 +4859,7 @@ public: { using namespace test::jtx; testWithFeatures(supported_amendments()); + testHookFloat(supported_amendments()); } }; diff --git a/src/xrpld/app/hook/HookAPI.h b/src/xrpld/app/hook/HookAPI.h index 91c23e091..abd07c053 100644 --- a/src/xrpld/app/hook/HookAPI.h +++ b/src/xrpld/app/hook/HookAPI.h @@ -3,11 +3,298 @@ #include #include +#include namespace hook { -using namespace ripple; + using HookReturnCode = hook_api::hook_return_code; +namespace hook_float { +using enum hook_api::hook_return_code; + +// power of 10 LUT for fast integer math +static int64_t power_of_ten[19] = { + 1LL, + 10LL, + 100LL, + 1000LL, + 10000LL, + 100000LL, + 1000000LL, + 10000000LL, + 100000000LL, + 1000000000LL, + 10000000000LL, + 100000000000LL, + 1000000000000LL, + 10000000000000LL, + 100000000000000LL, + 1000000000000000LL, // 15 + 10000000000000000LL, + 100000000000000000LL, + 1000000000000000000LL, +}; + +using namespace hook_api; +static int64_t const minMantissa = 1000000000000000ull; +static int64_t const maxMantissa = 9999999999999999ull; +static int32_t const minExponent = -96; +static int32_t const maxExponent = 80; + +inline Expected +get_exponent(int64_t float1) +{ + using enum hook_api::hook_return_code; + if (float1 < 0) + return Unexpected(INVALID_FLOAT); + if (float1 == 0) + return 0u; + uint64_t float_in = (uint64_t)float1; + float_in >>= 54U; + float_in &= 0xFFU; + return static_cast(float_in) - 97; +} + +inline Expected +get_mantissa(int64_t float1) +{ + using enum hook_api::hook_return_code; + if (float1 < 0) + return Unexpected(INVALID_FLOAT); + if (float1 == 0) + return 0ULL; + float1 -= ((((uint64_t)float1) >> 54U) << 54U); + return float1; +} + +inline bool +is_negative(int64_t float1) +{ + return ((float1 >> 62U) & 1ULL) == 0; +} + +inline int64_t +invert_sign(int64_t float1) +{ + int64_t r = (int64_t)(((uint64_t)float1) ^ (1ULL << 62U)); + return r; +} + +inline int64_t +set_sign(int64_t float1, bool set_negative) +{ + bool neg = is_negative(float1); + if ((neg && set_negative) || (!neg && !set_negative)) + return float1; + + return invert_sign(float1); +} + +inline Expected +set_mantissa(int64_t float1, uint64_t mantissa) +{ + using enum hook_api::hook_return_code; + if (mantissa > maxMantissa) + return Unexpected(MANTISSA_OVERSIZED); + if (mantissa < minMantissa) + return Unexpected(MANTISSA_UNDERSIZED); + return float1 - get_mantissa(float1).value() + mantissa; +} + +inline Expected +set_exponent(int64_t float1, int32_t exponent) +{ + using enum hook_api::hook_return_code; + if (exponent > maxExponent) + return Unexpected(EXPONENT_OVERSIZED); + if (exponent < minExponent) + return Unexpected(EXPONENT_UNDERSIZED); + + uint64_t exp = (exponent + 97); + exp <<= 54U; + float1 &= ~(0xFFLL << 54); + float1 += (int64_t)exp; + return float1; +} + +inline Expected +make_float(ripple::IOUAmount& amt) +{ + using enum hook_api::hook_return_code; + int64_t man_out = amt.mantissa(); + int64_t float_out = 0; + bool neg = man_out < 0; + if (neg) + man_out *= -1; + + float_out = set_sign(float_out, neg); + auto const mantissa = set_mantissa(float_out, (uint64_t)man_out); + if (!mantissa) + // TODO: This change requires the amendment. + // return Unexpected(mantissa.error()); + float_out = (int64_t)mantissa.error(); + else + float_out = mantissa.value(); + auto const exponent = set_exponent(float_out, amt.exponent()); + if (!exponent) + return Unexpected(exponent.error()); + float_out = exponent.value(); + return float_out; +} + +inline Expected +make_float(uint64_t mantissa, int32_t exponent, bool neg) +{ + using enum hook_api::hook_return_code; + if (mantissa == 0) + return 0ULL; + if (mantissa > maxMantissa) + return Unexpected(MANTISSA_OVERSIZED); + if (mantissa < minMantissa) + return Unexpected(MANTISSA_UNDERSIZED); + if (exponent > maxExponent) + return Unexpected(EXPONENT_OVERSIZED); + if (exponent < minExponent) + return Unexpected(EXPONENT_UNDERSIZED); + int64_t out = 0; + + auto const m = set_mantissa(out, mantissa); + if (!m) + return Unexpected(m.error()); // LCOV_EXCL_LINE + out = m.value(); + + auto const e = set_exponent(out, exponent); + if (!e) + return Unexpected(e.error()); // LCOV_EXCL_LINE + out = e.value(); + + out = set_sign(out, neg); + return out; +} + +/** + * This function normalizes the mantissa and exponent passed, if it can. + * It returns the XFL and mutates the supplied manitssa and exponent. + * If a negative mantissa is provided then the returned XFL has the negative + * flag set. If there is an overflow error return XFL_OVERFLOW. On underflow + * returns canonical 0 + */ +template +inline Expected +normalize_xfl(T& man, int32_t& exp, bool neg = false) +{ + if (man == 0) + return 0ULL; + + if (man == std::numeric_limits::min()) + man++; + + constexpr bool sman = std::is_same::value; + static_assert(sman || std::is_same()); + + if constexpr (sman) + { + if (man < 0) + { + man *= -1LL; + neg = true; + } + } + + // mantissa order + std::feclearexcept(FE_ALL_EXCEPT); + int32_t mo = log10(man); + // defensively ensure log10 produces a sane result; we'll borrow the + // overflow error code if it didn't + if (std::fetestexcept(FE_INVALID)) + return Unexpected(XFL_OVERFLOW); // LCOV_EXCL_LINE + + int32_t adjust = 15 - mo; + + if (adjust > 0) + { + // defensive check + if (adjust > 18) + return 0ULL; // LCOV_EXCL_LINE + man *= power_of_ten[adjust]; + exp -= adjust; + } + else if (adjust < 0) + { + // defensive check + if (-adjust > 18) + return Unexpected(XFL_OVERFLOW); // LCOV_EXCL_LINE + man /= power_of_ten[-adjust]; + exp -= adjust; + } + + if (man == 0) + { + exp = 0; + return 0ULL; + } + + // even after adjustment the mantissa can be outside the range by one place + // improving the math above would probably alleviate the need for these + // branches + if (man < minMantissa) + { + if (man == minMantissa - 1LL) + man += 1LL; + else + { + man *= 10LL; + exp--; + } + } + + if (man > maxMantissa) + { + if (man == maxMantissa + 1LL) + man -= 1LL; + else + { + man /= 10LL; + exp++; + } + } + + if (exp < minExponent) + { + man = 0; + exp = 0; + return 0ULL; + } + + if (man == 0) + { + exp = 0; + return 0ULL; + } + + if (exp > maxExponent) + return Unexpected(XFL_OVERFLOW); + + auto const ret = make_float((uint64_t)man, exp, neg); + if constexpr (sman) + { + if (neg) + man *= -1LL; + } + + if (!ret) + return Unexpected(ret.error()); + + return ret; +} + +const int64_t float_one_internal = + make_float(1000000000000000ull, -15, false).value(); + +} // namespace hook_float + +using namespace ripple; + using Bytes = std::vector; struct HookContext; // defined in applyHook.h @@ -170,7 +457,7 @@ public: Expected hook_hash(int32_t hook_no) const; - Expected + Expected hook_again() const; Expected @@ -320,7 +607,7 @@ private: bool modified) const; // these are only used by get_stobject_length below - enum parse_error { + enum class STOParseErrorCode { pe_unexpected_end = -1, pe_unknown_type_early = -2, // detected early pe_unknown_type_late = -3, // end of function @@ -329,8 +616,8 @@ private: }; inline Expected< - int32_t, - parse_error> + uint32_t, + STOParseErrorCode> get_stobject_length( unsigned char* start, // in - begin iterator unsigned char* maxptr, // in - end iterator diff --git a/src/xrpld/app/hook/detail/HookAPI.cpp b/src/xrpld/app/hook/detail/HookAPI.cpp index a676230a7..3818cee3a 100644 --- a/src/xrpld/app/hook/detail/HookAPI.cpp +++ b/src/xrpld/app/hook/detail/HookAPI.cpp @@ -5,285 +5,8 @@ #include #include #include -#include namespace hook { -namespace hook_float { - -// power of 10 LUT for fast integer math -static int64_t power_of_ten[19] = { - 1LL, - 10LL, - 100LL, - 1000LL, - 10000LL, - 100000LL, - 1000000LL, - 10000000LL, - 100000000LL, - 1000000000LL, - 10000000000LL, - 100000000000LL, - 1000000000000LL, - 10000000000000LL, - 100000000000000LL, - 1000000000000000LL, // 15 - 10000000000000000LL, - 100000000000000000LL, - 1000000000000000000LL, -}; - -using namespace hook_api; -static int64_t const minMantissa = 1000000000000000ull; -static int64_t const maxMantissa = 9999999999999999ull; -static int32_t const minExponent = -96; -static int32_t const maxExponent = 80; - -inline Expected -get_exponent(int64_t float1) -{ - if (float1 < 0) - return Unexpected(INVALID_FLOAT); - if (float1 == 0) - return 0; - uint64_t float_in = (uint64_t)float1; - float_in >>= 54U; - float_in &= 0xFFU; - return ((int32_t)float_in) - 97; -} - -inline Expected -get_mantissa(int64_t float1) -{ - if (float1 < 0) - return Unexpected(INVALID_FLOAT); - if (float1 == 0) - return 0; - float1 -= ((((uint64_t)float1) >> 54U) << 54U); - return float1; -} - -inline bool -is_negative(int64_t float1) -{ - return ((float1 >> 62U) & 1ULL) == 0; -} - -inline int64_t -invert_sign(int64_t float1) -{ - int64_t r = (int64_t)(((uint64_t)float1) ^ (1ULL << 62U)); - return r; -} - -inline int64_t -set_sign(int64_t float1, bool set_negative) -{ - bool neg = is_negative(float1); - if ((neg && set_negative) || (!neg && !set_negative)) - return float1; - - return invert_sign(float1); -} - -inline Expected -set_mantissa(int64_t float1, uint64_t mantissa) -{ - if (mantissa > maxMantissa) - return Unexpected(MANTISSA_OVERSIZED); - if (mantissa < minMantissa) - return Unexpected(MANTISSA_UNDERSIZED); - return float1 - get_mantissa(float1).value() + mantissa; -} - -inline Expected -set_exponent(int64_t float1, int32_t exponent) -{ - if (exponent > maxExponent) - return Unexpected(EXPONENT_OVERSIZED); - if (exponent < minExponent) - return Unexpected(EXPONENT_UNDERSIZED); - - uint64_t exp = (exponent + 97); - exp <<= 54U; - float1 &= ~(0xFFLL << 54); - float1 += (int64_t)exp; - return float1; -} - -inline Expected -make_float(ripple::IOUAmount& amt) -{ - int64_t man_out = amt.mantissa(); - int64_t float_out = 0; - bool neg = man_out < 0; - if (neg) - man_out *= -1; - - float_out = set_sign(float_out, neg); - auto const mantissa = set_mantissa(float_out, (uint64_t)man_out); - if (!mantissa) - // TODO: This change requires the amendment. - // return Unexpected(mantissa.error()); - float_out = mantissa.error(); - else - float_out = mantissa.value(); - auto const exponent = set_exponent(float_out, amt.exponent()); - if (!exponent) - return Unexpected(exponent.error()); - float_out = exponent.value(); - return float_out; -} - -inline Expected -make_float(uint64_t mantissa, int32_t exponent, bool neg) -{ - if (mantissa == 0) - return 0; - if (mantissa > maxMantissa) - return Unexpected(MANTISSA_OVERSIZED); - if (mantissa < minMantissa) - return Unexpected(MANTISSA_UNDERSIZED); - if (exponent > maxExponent) - return Unexpected(EXPONENT_OVERSIZED); - if (exponent < minExponent) - return Unexpected(EXPONENT_UNDERSIZED); - int64_t out = 0; - - auto const m = set_mantissa(out, mantissa); - if (!m) - return m.error(); - out = m.value(); - - auto const e = set_exponent(out, exponent); - if (!e) - return e.error(); - out = e.value(); - - out = set_sign(out, neg); - return out; -} - -/** - * This function normalizes the mantissa and exponent passed, if it can. - * It returns the XFL and mutates the supplied manitssa and exponent. - * If a negative mantissa is provided then the returned XFL has the negative - * flag set. If there is an overflow error return XFL_OVERFLOW. On underflow - * returns canonical 0 - */ -template -inline Expected -normalize_xfl(T& man, int32_t& exp, bool neg = false) -{ - if (man == 0) - return 0; - - if (man == std::numeric_limits::min()) - man++; - - constexpr bool sman = std::is_same::value; - static_assert(sman || std::is_same()); - - if constexpr (sman) - { - if (man < 0) - { - man *= -1LL; - neg = true; - } - } - - // mantissa order - std::feclearexcept(FE_ALL_EXCEPT); - int32_t mo = log10(man); - // defensively ensure log10 produces a sane result; we'll borrow the - // overflow error code if it didn't - if (std::fetestexcept(FE_INVALID)) - return Unexpected(XFL_OVERFLOW); - - int32_t adjust = 15 - mo; - - if (adjust > 0) - { - // defensive check - if (adjust > 18) - return 0; - man *= power_of_ten[adjust]; - exp -= adjust; - } - else if (adjust < 0) - { - // defensive check - if (-adjust > 18) - return Unexpected(XFL_OVERFLOW); - man /= power_of_ten[-adjust]; - exp -= adjust; - } - - if (man == 0) - { - exp = 0; - return 0; - } - - // even after adjustment the mantissa can be outside the range by one place - // improving the math above would probably alleviate the need for these - // branches - if (man < minMantissa) - { - if (man == minMantissa - 1LL) - man += 1LL; - else - { - man *= 10LL; - exp--; - } - } - - if (man > maxMantissa) - { - if (man == maxMantissa + 1LL) - man -= 1LL; - else - { - man /= 10LL; - exp++; - } - } - - if (exp < minExponent) - { - man = 0; - exp = 0; - return 0; - } - - if (man == 0) - { - exp = 0; - return 0; - } - - if (exp > maxExponent) - return Unexpected(XFL_OVERFLOW); - - auto const ret = make_float((uint64_t)man, exp, neg); - if constexpr (sman) - { - if (neg) - man *= -1LL; - } - - if (!ret) - return ret.error(); - - return ret; -} - -const int64_t float_one_internal = - make_float(1000000000000000ull, -15, false).value(); - -} // namespace hook_float using namespace ripple; using namespace hook_float; @@ -1178,7 +901,7 @@ HookAPI::etxn_details(uint8_t* out_ptr) const auto hash = etxn_nonce(); if (!hash.has_value()) - return INTERNAL_ERROR; + return Unexpected(INTERNAL_ERROR); memcpy(out, hash->data(), 32); @@ -1273,7 +996,7 @@ HookAPI::float_set(int32_t exponent, int64_t mantissa) const { if (normalized.error() == XFL_OVERFLOW) return Unexpected(INVALID_FLOAT); - return normalized.error(); + return Unexpected(normalized.error()); } if (normalized.value() == 0) return Unexpected(INVALID_FLOAT); @@ -1321,7 +1044,7 @@ HookAPI::float_mulratio( auto const result = make_float((uint64_t)man1, exp1, is_negative(float1)); if (!result) - return result.error(); + return Unexpected(result.error()); return result; } @@ -1932,7 +1655,7 @@ HookAPI::hook_hash(int32_t hook_no) const return hook.getFieldH256(sfHookHash); } -Expected +Expected HookAPI::hook_again() const { if (hookCtx.result.executeAgainAsWeak) @@ -1941,7 +1664,7 @@ HookAPI::hook_again() const if (hookCtx.result.isStrong) { hookCtx.result.executeAgainAsWeak = true; - return 1; + return 1ULL; } return Unexpected(PREREQUISITE_NOT_MET); @@ -2607,7 +2330,7 @@ HookAPI::slot_float(uint32_t slot_no) const normalized = ret.value(); } - if (normalized == EXPONENT_UNDERSIZED) + if (normalized == (int64_t)EXPONENT_UNDERSIZED) /* exponent undersized (underflow) */ return 0; // return 0 in this case return normalized; @@ -3134,8 +2857,8 @@ HookAPI::set_state_cache( // including header bytes (and footer bytes in the event of array or object) // negative indicates error inline Expected< - int32_t, - HookAPI::parse_error> + uint32_t, + HookAPI::STOParseErrorCode> HookAPI::get_stobject_length( unsigned char* start, // in - begin iterator unsigned char* maxptr, // in - end iterator @@ -3148,6 +2871,7 @@ HookAPI::get_stobject_length( int recursion_depth) // used internally const { + using enum HookAPI::STOParseErrorCode; if (recursion_depth > 10) return Unexpected(pe_excessive_nesting); @@ -3156,7 +2880,7 @@ HookAPI::get_stobject_length( : STI_VECTOR256; if (type > max_sti_type) - return pe_unknown_type_early; + return Unexpected(pe_unknown_type_early); unsigned char* end = maxptr; unsigned char* upto = start; @@ -3216,7 +2940,7 @@ HookAPI::get_stobject_length( // not supported types if (type == STI_NUMBER || type == STI_UINT96 || type == STI_UINT192 || type == STI_UINT384 || type == STI_UINT512) - return pe_unknown_type_early; + return Unexpected(pe_unknown_type_early); bool is_vl = (type == STI_ACCOUNT || type == STI_VL || @@ -3286,7 +3010,7 @@ HookAPI::get_stobject_length( length = 20; break; default: - return -1; + return Unexpected(pe_unknown_type_late); } } else if (type == STI_AMOUNT) /* AMOUNT */ @@ -3308,7 +3032,7 @@ HookAPI::get_stobject_length( int flag = *(upto + length++); // flag shoud be 0x01 or 0x10 or 0x20 or those union if (flag == 0 || flag & ~(0x01 | 0x10 | 0x20)) - return pe_unexpected_end; + return Unexpected(pe_unexpected_end); if (flag & 0x01) // account length += 20; if (flag & 0x10) // currency @@ -3329,10 +3053,10 @@ HookAPI::get_stobject_length( else if (lastflag == 0x00) break; // end byte else - return pe_unexpected_end; + return Unexpected(pe_unexpected_end); } if (upto >= end) - return pe_unexpected_end; + return Unexpected(pe_unexpected_end); } else if (type == STI_ISSUE) { diff --git a/src/xrpld/app/hook/detail/applyHook.cpp b/src/xrpld/app/hook/detail/applyHook.cpp index 42b91202a..14855b73c 100644 --- a/src/xrpld/app/hook/detail/applyHook.cpp +++ b/src/xrpld/app/hook/detail/applyHook.cpp @@ -14,8 +14,6 @@ #include #include #include -#include -#include #include #include #include @@ -598,160 +596,9 @@ getTransactionalStakeHolders(STTx const& tx, ReadView const& rv) } // namespace hook -namespace hook_float { - -using namespace hook_api; -static int64_t const minMantissa = 1000000000000000ull; -static int64_t const maxMantissa = 9999999999999999ull; -static int32_t const minExponent = -96; -static int32_t const maxExponent = 80; -inline int32_t -get_exponent(int64_t float1) -{ - if (float1 < 0) - return INVALID_FLOAT; - if (float1 == 0) - return 0; - uint64_t float_in = (uint64_t)float1; - float_in >>= 54U; - float_in &= 0xFFU; - return ((int32_t)float_in) - 97; -} - -inline int64_t -get_mantissa(int64_t float1) -{ - if (float1 < 0) - return INVALID_FLOAT; - if (float1 == 0) - return 0; - float1 -= ((((uint64_t)float1) >> 54U) << 54U); - return float1; -} - -inline bool -is_negative(int64_t float1) -{ - return ((float1 >> 62U) & 1ULL) == 0; -} - -inline int64_t -invert_sign(int64_t float1) -{ - int64_t r = (int64_t)(((uint64_t)float1) ^ (1ULL << 62U)); - return r; -} - -inline int64_t -set_sign(int64_t float1, bool set_negative) -{ - bool neg = is_negative(float1); - if ((neg && set_negative) || (!neg && !set_negative)) - return float1; - - return invert_sign(float1); -} - -inline int64_t -set_mantissa(int64_t float1, uint64_t mantissa) -{ - if (mantissa > maxMantissa) - return MANTISSA_OVERSIZED; - if (mantissa < minMantissa) - return MANTISSA_UNDERSIZED; - return float1 - get_mantissa(float1) + mantissa; -} - -inline int64_t -set_exponent(int64_t float1, int32_t exponent) -{ - if (exponent > maxExponent) - return EXPONENT_OVERSIZED; - if (exponent < minExponent) - return EXPONENT_UNDERSIZED; - - uint64_t exp = (exponent + 97); - exp <<= 54U; - float1 &= ~(0xFFLL << 54); - float1 += (int64_t)exp; - return float1; -} - -inline int64_t -make_float(ripple::IOUAmount& amt) -{ - int64_t man_out = amt.mantissa(); - int64_t float_out = 0; - bool neg = man_out < 0; - if (neg) - man_out *= -1; - - float_out = set_sign(float_out, neg); - float_out = set_mantissa(float_out, (uint64_t)man_out); - float_out = set_exponent(float_out, amt.exponent()); - return float_out; -} - -inline int64_t -make_float(uint64_t mantissa, int32_t exponent, bool neg) -{ - if (mantissa == 0) - return 0; - if (mantissa > maxMantissa) - return MANTISSA_OVERSIZED; - if (mantissa < minMantissa) - return MANTISSA_UNDERSIZED; - if (exponent > maxExponent) - return EXPONENT_OVERSIZED; - if (exponent < minExponent) - return EXPONENT_UNDERSIZED; - int64_t out = 0; - out = set_mantissa(out, mantissa); - out = set_exponent(out, exponent); - out = set_sign(out, neg); - return out; -} - -} // namespace hook_float -using namespace hook_float; +using namespace hook::hook_float; using hook::Bytes; -inline int32_t -no_free_slots(hook::HookContext& hookCtx) -{ - return hook_api::max_slots - hookCtx.slot.size() <= 0; -} - -inline std::optional -get_free_slot(hook::HookContext& hookCtx) -{ - // allocate a slot - int32_t slot_into = 0; - if (hookCtx.slot_free.size() > 0) - { - slot_into = hookCtx.slot_free.front(); - hookCtx.slot_free.pop(); - return slot_into; - } - - // no slots were available in the queue so increment slot counter until we - // find a free slot usually this will be the next available but the hook - // developer may have allocated any slot ahead of when the counter gets - // there - do - { - slot_into = ++hookCtx.slot_counter; - } while (hookCtx.slot.find(slot_into) != hookCtx.slot.end() && - // this condition should always be met, if for some reason, somehow - // it is not then we will return the final slot every time. - hookCtx.slot_counter <= hook_api::max_slots); - - if (hookCtx.slot_counter > hook_api::max_slots) - return {}; - - return slot_into; -} - // cu_ptr is a pointer into memory, bounds check is assumed to have already // happened inline std::optional @@ -807,7 +654,7 @@ parseCurrency(uint8_t* cu_ptr, uint32_t cu_len) return {}; } -inline int64_t +inline std::variant serialize_keylet( ripple::Keylet& kl, uint8_t* memory, @@ -815,7 +662,7 @@ serialize_keylet( uint32_t write_len) { if (write_len < 34) - return hook_api::TOO_SMALL; + return TOO_SMALL; memory[write_ptr + 0] = (kl.type >> 8) & 0xFFU; memory[write_ptr + 1] = (kl.type >> 0) & 0xFFU; @@ -823,7 +670,7 @@ serialize_keylet( for (int i = 0; i < 32; ++i) memory[write_ptr + 2 + i] = kl.key.data()[i]; - return 34; + return 34ULL; } std::optional @@ -866,19 +713,19 @@ hook::computeCreationFee(uint64_t byteCount) } // many datatypes can be encoded into an int64_t -inline int64_t +inline std::variant data_as_int64(void const* ptr_raw, uint32_t len) { if (len > 8) - return hook_api::hook_return_code::TOO_BIG; + return TOO_BIG; uint8_t const* ptr = reinterpret_cast(ptr_raw); uint64_t output = 0; for (int i = 0, j = (len - 1) * 8; i < len; ++i, j -= 8) output += (((uint64_t)ptr[i]) << j); if ((1ULL << 63U) & output) - return hook_api::hook_return_code::TOO_BIG; - return (int64_t)output; + return TOO_BIG; + return output; } /* returns true iff every even char is ascii and every odd char is 00 @@ -1265,7 +1112,7 @@ DEFINE_HOOK_FUNCTION( return OUT_OF_BOUNDS; if (!j.trace()) - return 0; + return 0ULL; if (read_len > 128) read_len = 128; @@ -1283,12 +1130,12 @@ DEFINE_HOOK_FUNCTION( (const char*)memory + read_ptr, read_len) << ": " << number; - return 0; + return 0ULL; } } j.trace() << "HookTrace[" << HC_ACC() << "]: " << number; - return 0; + return 0ULL; HOOK_TEARDOWN(); } @@ -1308,7 +1155,7 @@ DEFINE_HOOK_FUNCTION( return OUT_OF_BOUNDS; if (!j.trace()) - return 0; + return 0ULL; if (mread_len > 128) mread_len = 128; @@ -1371,7 +1218,7 @@ DEFINE_HOOK_FUNCTION( << std::string_view((const char*)output_storage, out_len); } - return 0; + return 0ULL; HOOK_TEARDOWN(); } @@ -1476,7 +1323,8 @@ DEFINE_HOOK_FUNCTION( auto const sleAccount = view.peek(hookCtx.result.accountKeylet); if (!sleAccount && view.rules().enabled(featureExtendedHookState)) - return tefINTERNAL; + // should return hook_api::hook_return_code + return static_cast(tefINTERNAL); uint16_t const hookStateScale = sleAccount->isFieldPresent(sfHookStateScale) ? sleAccount->getFieldU16(sfHookStateScale) @@ -1500,7 +1348,8 @@ DEFINE_HOOK_FUNCTION( { auto const sleAccount = view.peek(hookCtx.result.accountKeylet); if (!sleAccount) - return tefINTERNAL; + // should return hook_api::hook_return_code + return static_cast(tefINTERNAL); } if (!key) @@ -1715,7 +1564,8 @@ hook::finalizeHookResult( // add a metadata entry for this hook execution result { STObject meta{sfHookExecution}; - meta.setFieldU8(sfHookResult, hookResult.exitType); + meta.setFieldU8( + sfHookResult, static_cast(hookResult.exitType)); meta.setAccountID(sfHookAccount, hookResult.account); // RH NOTE: this is probably not necessary, a direct cast should always @@ -2225,7 +2075,7 @@ DEFINE_HOOK_FUNCTION(int64_t, slot_type, uint32_t slot_no, uint32_t flags) if (flags == 0) { auto const base = std::get<0>(*result); - return base.getFName().fieldCode; + return static_cast(base.getFName().fieldCode); } else { @@ -2836,7 +2686,8 @@ DEFINE_HOOK_FUNCTION( if (NOT_IN_BOUNDS(write_ptr, txID.size(), memory_length)) return OUT_OF_BOUNDS; - auto const write_txid = [&]() -> int64_t { + auto const write_txid = + [&]() -> std::variant { WRITE_WASM_MEMORY_AND_RETURN( write_ptr, txID.size(), @@ -2846,12 +2697,15 @@ DEFINE_HOOK_FUNCTION( memory_length); }; - int64_t result = write_txid(); + auto result = write_txid(); + if (std::holds_alternative(result)) + return std::get(result); - if (result == 32) + auto const value = std::get(result); + if (value == 32) hookCtx.result.emittedTxn.push(tpTrans); - return result; + return value; HOOK_TEARDOWN(); } @@ -3340,7 +3194,7 @@ DEFINE_HOOK_FUNCTION( uint32_t field_id) { // proxy only no setup or teardown - int64_t ret = sto_emplace( + auto ret = sto_emplace( hookCtx, frameCtx, write_ptr, @@ -3351,8 +3205,12 @@ DEFINE_HOOK_FUNCTION( 0, field_id); - if (ret > 0 && ret == read_len) - return DOESNT_EXIST; + if (std::holds_alternative(ret)) + { + auto const value = std::get(ret); + if (value > 0 && value == read_len) + return DOESNT_EXIST; + } return ret; } @@ -3375,7 +3233,7 @@ DEFINE_HOOK_FUNCTION( auto const result = api.sto_validate(data); if (!result) return result.error(); - return result.value() ? 1 : 0; + return result.value() ? 1ULL : 0ULL; HOOK_TEARDOWN(); } @@ -3411,7 +3269,7 @@ DEFINE_HOOK_FUNCTION( auto const result = api.util_verify(data, sig, key); if (!result) return result.error(); - return result.value() ? 1 : 0; + return result.value() ? 1ULL : 0ULL; HOOK_TEARDOWN(); } @@ -3506,26 +3364,30 @@ DEFINE_HOOK_FUNCTION(int32_t, _g, uint32_t id, uint32_t maxitr) << "Iterations: " << hookCtx.guard_map[id]; } hookCtx.result.exitType = hook_api::ExitType::ROLLBACK; - hookCtx.result.exitCode = GUARD_VIOLATION; + hookCtx.result.exitCode = (int64_t)GUARD_VIOLATION; return RC_ROLLBACK; } - return 1; + return 1U; HOOK_TEARDOWN(); } -#define RETURN_IF_INVALID_FLOAT(float1) \ - { \ - if (float1 < 0) \ - return hook_api::INVALID_FLOAT; \ - if (float1 != 0) \ - { \ - uint64_t mantissa = get_mantissa(float1); \ - int32_t exponent = get_exponent(float1); \ - if (mantissa < minMantissa || mantissa > maxMantissa || \ - exponent > maxExponent || exponent < minExponent) \ - return INVALID_FLOAT; \ - } \ +#define RETURN_IF_INVALID_FLOAT(float1) \ + { \ + if (float1 < 0) \ + return INVALID_FLOAT; \ + if (float1 != 0) \ + { \ + auto const mantissa = get_mantissa(float1); \ + auto const exponent = get_exponent(float1); \ + if (!mantissa || !exponent) \ + return INVALID_FLOAT; \ + if (mantissa.value() < minMantissa || \ + mantissa.value() > maxMantissa || \ + exponent.value() > maxExponent || \ + exponent.value() < minExponent) \ + return INVALID_FLOAT; \ + } \ } DEFINE_HOOK_FUNCTION( @@ -3542,7 +3404,7 @@ DEFINE_HOOK_FUNCTION( return OUT_OF_BOUNDS; if (!j.trace()) - return 0; + return 0ULL; if (read_len > 128) read_len = 128; @@ -3552,38 +3414,33 @@ DEFINE_HOOK_FUNCTION( *((const char*)memory + read_ptr + read_len - 1) == '\0') read_len--; + auto const messageKey = (read_len == 0) + ? "" + : std::string_view((const char*)memory + read_ptr, read_len); + if (float1 == 0) { - j.trace() << "HookTrace[" << HC_ACC() << "]: " - << (read_len == 0 - ? "" - : std::string_view( - (const char*)memory + read_ptr, read_len)) + j.trace() << "HookTrace[" << HC_ACC() << "]: " << messageKey << ": Float 0*10^(0) "; - return 0; + return 0ULL; } - uint64_t man = get_mantissa(float1); - int32_t exp = get_exponent(float1); + auto const man = get_mantissa(float1); + auto const exp = get_exponent(float1); bool neg = is_negative(float1); - if (man < minMantissa || man > maxMantissa || exp < minExponent || - exp > maxExponent) + if (!man || !exp || man.value() < minMantissa || + man.value() > maxMantissa || exp.value() < minExponent || + exp.value() > maxExponent) { - j.trace() << "HookTrace[" << HC_ACC() << "]:" - << (read_len == 0 - ? "" - : std::string_view( - (const char*)memory + read_ptr, read_len)) + j.trace() << "HookTrace[" << HC_ACC() << "]: " << messageKey << ": Float "; - return 0; + return 0ULL; } - j.trace() << "HookTrace[" << HC_ACC() << "]:" - << (read_len == 0 ? "" - : std::string_view( - (const char*)memory + read_ptr, read_len)) - << ": Float " << (neg ? "-" : "") << man << "*10^(" << exp << ")"; - return 0; + j.trace() << "HookTrace[" << HC_ACC() << "]:" << messageKey << ": Float " + << (neg ? "-" : "") << man.value() << "*10^(" << exp.value() + << ")"; + return 0ULL; HOOK_TEARDOWN(); }