mirror of
https://github.com/Xahau/xahaud.git
synced 2026-06-02 16:26:37 +00:00
Fix HookAPI Expected and Refactor Enum classes (#729)
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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<T>
|
||||
|
||||
#define DECLARE_HOOK_FUNCTION(R, F, ...) \
|
||||
std::variant<UNSIGNED_TYPE(R), hook_api::hook_return_code> 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<hook::HookContext*>(data_ptr); \
|
||||
R return_code = hook_api::F( \
|
||||
*hookCtx, \
|
||||
*const_cast<WasmEdge_CallingFrameContext*>(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<hook::HookContext*>(data_ptr); \
|
||||
auto const& return_code = hook_api::F( \
|
||||
*hookCtx, \
|
||||
*const_cast<WasmEdge_CallingFrameContext*>(frameCtx) \
|
||||
__VA_OPT__(COMMA STRIP_TYPES(__VA_ARGS__))); \
|
||||
if (std::holds_alternative<hook_api::hook_return_code>(return_code) && \
|
||||
(std::get<hook_api::hook_return_code>(return_code) == \
|
||||
RC_ROLLBACK || \
|
||||
std::get<hook_api::hook_return_code>(return_code) == RC_ACCEPT)) \
|
||||
return WasmEdge_Result_Terminate; \
|
||||
out[0] = RET_ASSIGN( \
|
||||
R, \
|
||||
std::holds_alternative<UNSIGNED_TYPE(R)>(return_code) \
|
||||
? std::get<UNSIGNED_TYPE(R)>(return_code) \
|
||||
: R(std::get<hook_api::hook_return_code>(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<UNSIGNED_TYPE(R), hook_api::hook_return_code> 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)) \
|
||||
|
||||
@@ -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<int64_t>::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());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -3,11 +3,298 @@
|
||||
|
||||
#include <xrpld/app/misc/Transaction.h>
|
||||
#include <xrpl/hook/Enum.h>
|
||||
#include <cfenv>
|
||||
|
||||
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<int32_t, HookReturnCode>
|
||||
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<int32_t>(float_in) - 97;
|
||||
}
|
||||
|
||||
inline Expected<uint64_t, HookReturnCode>
|
||||
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<uint64_t, HookReturnCode>
|
||||
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<uint64_t, HookReturnCode>
|
||||
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<uint64_t, HookReturnCode>
|
||||
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<uint64_t, HookReturnCode>
|
||||
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 <typename T>
|
||||
inline Expected<uint64_t, HookReturnCode>
|
||||
normalize_xfl(T& man, int32_t& exp, bool neg = false)
|
||||
{
|
||||
if (man == 0)
|
||||
return 0ULL;
|
||||
|
||||
if (man == std::numeric_limits<int64_t>::min())
|
||||
man++;
|
||||
|
||||
constexpr bool sman = std::is_same<T, int64_t>::value;
|
||||
static_assert(sman || std::is_same<T, uint64_t>());
|
||||
|
||||
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<std::uint8_t>;
|
||||
|
||||
struct HookContext; // defined in applyHook.h
|
||||
@@ -170,7 +457,7 @@ public:
|
||||
Expected<ripple::uint256, HookReturnCode>
|
||||
hook_hash(int32_t hook_no) const;
|
||||
|
||||
Expected<int64_t, HookReturnCode>
|
||||
Expected<uint64_t, HookReturnCode>
|
||||
hook_again() const;
|
||||
|
||||
Expected<Blob, HookReturnCode>
|
||||
@@ -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
|
||||
|
||||
@@ -5,285 +5,8 @@
|
||||
#include <xrpld/app/ledger/TransactionMaster.h>
|
||||
#include <xrpld/app/tx/detail/Import.h>
|
||||
#include <xrpl/protocol/STParsedJSON.h>
|
||||
#include <cfenv>
|
||||
|
||||
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<int32_t, HookReturnCode>
|
||||
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<uint64_t, HookReturnCode>
|
||||
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<uint64_t, HookReturnCode>
|
||||
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<uint64_t, HookReturnCode>
|
||||
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<uint64_t, HookReturnCode>
|
||||
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<uint64_t, HookReturnCode>
|
||||
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 <typename T>
|
||||
inline Expected<uint64_t, HookReturnCode>
|
||||
normalize_xfl(T& man, int32_t& exp, bool neg = false)
|
||||
{
|
||||
if (man == 0)
|
||||
return 0;
|
||||
|
||||
if (man == std::numeric_limits<int64_t>::min())
|
||||
man++;
|
||||
|
||||
constexpr bool sman = std::is_same<T, int64_t>::value;
|
||||
static_assert(sman || std::is_same<T, uint64_t>());
|
||||
|
||||
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<int64_t, HookReturnCode>
|
||||
Expected<uint64_t, HookReturnCode>
|
||||
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)
|
||||
{
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
#include <xrpl/protocol/st.h>
|
||||
#include <xrpl/protocol/tokens.h>
|
||||
#include <boost/multiprecision/cpp_dec_float.hpp>
|
||||
#include <any>
|
||||
#include <cfenv>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
@@ -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<int32_t>
|
||||
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<Currency>
|
||||
@@ -807,7 +654,7 @@ parseCurrency(uint8_t* cu_ptr, uint32_t cu_len)
|
||||
return {};
|
||||
}
|
||||
|
||||
inline int64_t
|
||||
inline std::variant<uint64_t, hook_api::hook_return_code>
|
||||
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<ripple::Keylet>
|
||||
@@ -866,19 +713,19 @@ hook::computeCreationFee(uint64_t byteCount)
|
||||
}
|
||||
|
||||
// many datatypes can be encoded into an int64_t
|
||||
inline int64_t
|
||||
inline std::variant<uint64_t, hook_api::hook_return_code>
|
||||
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<uint8_t const*>(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<hook_api::hook_return_code>(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<hook_api::hook_return_code>(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<uint8_t>(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<uint64_t>(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<uint64_t, hook_api::hook_return_code> {
|
||||
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<hook_api::hook_return_code>(result))
|
||||
return std::get<hook_api::hook_return_code>(result);
|
||||
|
||||
if (result == 32)
|
||||
auto const value = std::get<uint64_t>(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<uint64_t>(ret))
|
||||
{
|
||||
auto const value = std::get<uint64_t>(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) <ZERO>";
|
||||
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 <INVALID>";
|
||||
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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user