mirror of
https://github.com/Xahau/xahaud.git
synced 2025-11-19 01:55:48 +00:00
add slot APIs
This commit is contained in:
@@ -206,15 +206,33 @@ public:
|
||||
Bytes& data) const;
|
||||
|
||||
/// slot APIs
|
||||
// slot
|
||||
// slot_clear
|
||||
// slot_count
|
||||
// slot_set
|
||||
// slot_size
|
||||
// slot_subarray
|
||||
// slot_subfield
|
||||
Expected<const STBase*, HookReturnCode>
|
||||
slot(uint32_t slot_no) const;
|
||||
|
||||
Expected<uint64_t, HookReturnCode>
|
||||
slot_clear(uint32_t slot_no) const;
|
||||
|
||||
Expected<uint64_t, HookReturnCode>
|
||||
slot_count(uint32_t slot_no) const;
|
||||
|
||||
Expected<uint32_t, HookReturnCode>
|
||||
slot_set(Bytes const& data, uint32_t slot_no) const;
|
||||
|
||||
Expected<uint64_t, HookReturnCode>
|
||||
slot_size(uint32_t slot_no) const;
|
||||
|
||||
Expected<uint32_t, HookReturnCode>
|
||||
slot_subarray(uint32_t parent_slot, uint32_t array_id, uint32_t new_slot)
|
||||
const;
|
||||
|
||||
Expected<uint32_t, HookReturnCode>
|
||||
slot_subfield(uint32_t parent_slot, uint32_t field_id, uint32_t new_slot)
|
||||
const;
|
||||
|
||||
// slot_type
|
||||
// slot_float
|
||||
|
||||
Expected<uint64_t, HookReturnCode>
|
||||
slot_float(uint32_t slot_no) const;
|
||||
|
||||
/// trace APIs
|
||||
// trace
|
||||
@@ -256,6 +274,9 @@ private:
|
||||
inline Expected<uint64_t, HookReturnCode>
|
||||
double_to_xfl(double x) const;
|
||||
|
||||
std::optional<ripple::Keylet>
|
||||
unserialize_keylet(Bytes const& data) const;
|
||||
|
||||
// update the state cache
|
||||
inline std::optional<
|
||||
std::reference_wrapper<std::pair<bool, ripple::Blob> const>>
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <ripple/app/hook/HookAPI.h>
|
||||
#include <ripple/app/hook/applyHook.h>
|
||||
#include <ripple/app/ledger/OpenLedger.h>
|
||||
#include <ripple/app/ledger/TransactionMaster.h>
|
||||
#include <ripple/app/misc/Transaction.h>
|
||||
#include <ripple/app/tx/apply.h>
|
||||
#include <ripple/app/tx/impl/ApplyContext.h>
|
||||
@@ -1646,15 +1647,303 @@ HookAPI::state_foreign_set(
|
||||
}
|
||||
|
||||
/// slot APIs
|
||||
// slot
|
||||
// slot_clear
|
||||
// slot_count
|
||||
// slot_set
|
||||
// slot_size
|
||||
// slot_subarray
|
||||
// slot_subfield
|
||||
|
||||
Expected<const STBase*, HookReturnCode>
|
||||
HookAPI::slot(uint32_t slot_no) const
|
||||
{
|
||||
if (hookCtx.slot.find(slot_no) == hookCtx.slot.end())
|
||||
return Unexpected(DOESNT_EXIST);
|
||||
|
||||
if (hookCtx.slot[slot_no].entry == 0)
|
||||
return Unexpected(INTERNAL_ERROR);
|
||||
|
||||
return hookCtx.slot[slot_no].entry;
|
||||
}
|
||||
|
||||
Expected<uint64_t, HookReturnCode>
|
||||
HookAPI::slot_clear(uint32_t slot_no) const
|
||||
{
|
||||
if (hookCtx.slot.find(slot_no) == hookCtx.slot.end())
|
||||
return Unexpected(DOESNT_EXIST);
|
||||
|
||||
hookCtx.slot.erase(slot_no);
|
||||
hookCtx.slot_free.push(slot_no);
|
||||
return 1;
|
||||
}
|
||||
|
||||
Expected<uint64_t, HookReturnCode>
|
||||
HookAPI::slot_count(uint32_t slot_no) const
|
||||
{
|
||||
if (hookCtx.slot.find(slot_no) == hookCtx.slot.end())
|
||||
return Unexpected(DOESNT_EXIST);
|
||||
|
||||
if (hookCtx.slot[slot_no].entry == 0)
|
||||
return Unexpected(INTERNAL_ERROR);
|
||||
|
||||
if (hookCtx.slot[slot_no].entry->getSType() != STI_ARRAY)
|
||||
return Unexpected(NOT_AN_ARRAY);
|
||||
|
||||
return hookCtx.slot[slot_no].entry->downcast<ripple::STArray>().size();
|
||||
}
|
||||
|
||||
Expected<uint32_t, HookReturnCode>
|
||||
HookAPI::slot_set(Bytes const& data, uint32_t slot_no) const
|
||||
{
|
||||
if ((data.size() != 32 && data.size() != 34) ||
|
||||
slot_no > hook_api::max_slots)
|
||||
return Unexpected(INVALID_ARGUMENT);
|
||||
|
||||
if (slot_no == 0 && no_free_slots())
|
||||
return Unexpected(NO_FREE_SLOTS);
|
||||
|
||||
std::optional<std::shared_ptr<const ripple::STObject>> slot_value =
|
||||
std::nullopt;
|
||||
|
||||
if (data.size() == 34)
|
||||
{
|
||||
std::optional<ripple::Keylet> kl = unserialize_keylet(data);
|
||||
if (!kl)
|
||||
return Unexpected(DOESNT_EXIST);
|
||||
|
||||
if (kl->key == beast::zero)
|
||||
return Unexpected(DOESNT_EXIST);
|
||||
|
||||
auto const sle = hookCtx.applyCtx.view().read(*kl);
|
||||
if (!sle)
|
||||
return Unexpected(DOESNT_EXIST);
|
||||
|
||||
slot_value = sle;
|
||||
}
|
||||
else if (data.size() == 32)
|
||||
{
|
||||
uint256 hash = ripple::base_uint<256>::fromVoid(data.data());
|
||||
|
||||
ripple::error_code_i ec{ripple::error_code_i::rpcUNKNOWN};
|
||||
|
||||
auto hTx = hookCtx.applyCtx.app.getMasterTransaction().fetch(hash, ec);
|
||||
|
||||
if (auto const* p = std::get_if<std::pair<
|
||||
std::shared_ptr<ripple::Transaction>,
|
||||
std::shared_ptr<ripple::TxMeta>>>(&hTx))
|
||||
slot_value = p->first->getSTransaction();
|
||||
else
|
||||
return Unexpected(DOESNT_EXIST);
|
||||
}
|
||||
else
|
||||
return Unexpected(INVALID_ARGUMENT);
|
||||
|
||||
if (!slot_value.has_value())
|
||||
return Unexpected(DOESNT_EXIST);
|
||||
|
||||
if (slot_no == 0)
|
||||
{
|
||||
if (auto found = get_free_slot(); found)
|
||||
slot_no = *found;
|
||||
else
|
||||
return Unexpected(NO_FREE_SLOTS);
|
||||
}
|
||||
|
||||
hookCtx.slot[slot_no] = hook::SlotEntry{.storage = *slot_value, .entry = 0};
|
||||
hookCtx.slot[slot_no].entry = &(*hookCtx.slot[slot_no].storage);
|
||||
|
||||
return slot_no;
|
||||
}
|
||||
|
||||
Expected<uint64_t, HookReturnCode>
|
||||
HookAPI::slot_size(uint32_t slot_no) const
|
||||
{
|
||||
if (hookCtx.slot.find(slot_no) == hookCtx.slot.end())
|
||||
return Unexpected(DOESNT_EXIST);
|
||||
|
||||
if (hookCtx.slot[slot_no].entry == 0)
|
||||
return Unexpected(INTERNAL_ERROR);
|
||||
|
||||
// RH TODO: this is a very expensive way of computing size, cache it
|
||||
Serializer s;
|
||||
hookCtx.slot[slot_no].entry->add(s);
|
||||
return s.getDataLength();
|
||||
}
|
||||
|
||||
Expected<uint32_t, HookReturnCode>
|
||||
HookAPI::slot_subarray(
|
||||
uint32_t parent_slot,
|
||||
uint32_t array_id,
|
||||
uint32_t new_slot) const
|
||||
{
|
||||
if (hookCtx.slot.find(parent_slot) == hookCtx.slot.end())
|
||||
return Unexpected(DOESNT_EXIST);
|
||||
|
||||
if (hookCtx.slot[parent_slot].entry == 0)
|
||||
return Unexpected(INTERNAL_ERROR);
|
||||
|
||||
if (hookCtx.slot[parent_slot].entry->getSType() != STI_ARRAY)
|
||||
return Unexpected(NOT_AN_ARRAY);
|
||||
|
||||
if (new_slot == 0 && no_free_slots())
|
||||
return Unexpected(NO_FREE_SLOTS);
|
||||
|
||||
if (new_slot > hook_api::max_slots)
|
||||
return Unexpected(INVALID_ARGUMENT);
|
||||
|
||||
bool copied = false;
|
||||
try
|
||||
{
|
||||
ripple::STArray& parent_obj =
|
||||
const_cast<ripple::STBase&>(*hookCtx.slot[parent_slot].entry)
|
||||
.downcast<ripple::STArray>();
|
||||
|
||||
if (parent_obj.size() <= array_id)
|
||||
return Unexpected(DOESNT_EXIST);
|
||||
|
||||
if (new_slot == 0)
|
||||
{
|
||||
if (auto found = get_free_slot(); found)
|
||||
new_slot = *found;
|
||||
else
|
||||
return Unexpected(NO_FREE_SLOTS);
|
||||
}
|
||||
|
||||
// copy
|
||||
if (new_slot != parent_slot)
|
||||
{
|
||||
copied = true;
|
||||
hookCtx.slot[new_slot] = hookCtx.slot[parent_slot];
|
||||
}
|
||||
hookCtx.slot[new_slot].entry = &(parent_obj[array_id]);
|
||||
return new_slot;
|
||||
}
|
||||
catch (const std::bad_cast& e)
|
||||
{
|
||||
if (copied)
|
||||
{
|
||||
hookCtx.slot.erase(new_slot);
|
||||
hookCtx.slot_free.push(new_slot);
|
||||
}
|
||||
return Unexpected(NOT_AN_ARRAY);
|
||||
}
|
||||
|
||||
return new_slot;
|
||||
}
|
||||
|
||||
Expected<uint32_t, HookReturnCode>
|
||||
HookAPI::slot_subfield(
|
||||
uint32_t parent_slot,
|
||||
uint32_t field_id,
|
||||
uint32_t new_slot) const
|
||||
{
|
||||
if (hookCtx.slot.find(parent_slot) == hookCtx.slot.end())
|
||||
return Unexpected(DOESNT_EXIST);
|
||||
|
||||
if (new_slot == 0 && no_free_slots())
|
||||
return Unexpected(NO_FREE_SLOTS);
|
||||
|
||||
if (new_slot > hook_api::max_slots)
|
||||
return Unexpected(INVALID_ARGUMENT);
|
||||
|
||||
SField const& fieldCode = ripple::SField::getField(field_id);
|
||||
|
||||
if (fieldCode == sfInvalid)
|
||||
return Unexpected(INVALID_FIELD);
|
||||
|
||||
if (hookCtx.slot[parent_slot].entry == 0)
|
||||
return Unexpected(INTERNAL_ERROR);
|
||||
|
||||
bool copied = false;
|
||||
|
||||
try
|
||||
{
|
||||
ripple::STObject& parent_obj =
|
||||
const_cast<ripple::STBase&>(*hookCtx.slot[parent_slot].entry)
|
||||
.downcast<ripple::STObject>();
|
||||
|
||||
if (!parent_obj.isFieldPresent(fieldCode))
|
||||
return Unexpected(DOESNT_EXIST);
|
||||
|
||||
if (new_slot == 0)
|
||||
{
|
||||
if (auto found = get_free_slot(); found)
|
||||
new_slot = *found;
|
||||
else
|
||||
return Unexpected(NO_FREE_SLOTS);
|
||||
}
|
||||
|
||||
// copy
|
||||
if (new_slot != parent_slot)
|
||||
{
|
||||
copied = true;
|
||||
hookCtx.slot[new_slot] = hookCtx.slot[parent_slot];
|
||||
}
|
||||
|
||||
hookCtx.slot[new_slot].entry = &(parent_obj.getField(fieldCode));
|
||||
return new_slot;
|
||||
}
|
||||
catch (const std::bad_cast& e)
|
||||
{
|
||||
if (copied)
|
||||
{
|
||||
hookCtx.slot.erase(new_slot);
|
||||
hookCtx.slot_free.push(new_slot);
|
||||
}
|
||||
return Unexpected(NOT_AN_OBJECT);
|
||||
}
|
||||
}
|
||||
|
||||
// slot_type
|
||||
// slot_float
|
||||
|
||||
Expected<uint64_t, HookReturnCode>
|
||||
HookAPI::slot_float(uint32_t slot_no) const
|
||||
{
|
||||
if (hookCtx.slot.find(slot_no) == hookCtx.slot.end())
|
||||
return Unexpected(DOESNT_EXIST);
|
||||
|
||||
if (hookCtx.slot[slot_no].entry == 0)
|
||||
return Unexpected(INTERNAL_ERROR);
|
||||
|
||||
try
|
||||
{
|
||||
ripple::STAmount& st_amt =
|
||||
const_cast<ripple::STBase&>(*hookCtx.slot[slot_no].entry)
|
||||
.downcast<ripple::STAmount>();
|
||||
|
||||
int64_t normalized = 0;
|
||||
if (st_amt.native())
|
||||
{
|
||||
ripple::XRPAmount amt = st_amt.xrp();
|
||||
int64_t drops = amt.drops();
|
||||
int32_t exp = -6;
|
||||
// normalize
|
||||
auto const ret = hook_float::normalize_xfl(drops, exp);
|
||||
if (!ret)
|
||||
{
|
||||
if (ret.error() == EXPONENT_UNDERSIZED)
|
||||
return 0;
|
||||
return Unexpected(ret.error());
|
||||
}
|
||||
normalized = ret.value();
|
||||
}
|
||||
else
|
||||
{
|
||||
ripple::IOUAmount amt = st_amt.iou();
|
||||
auto const ret = make_float(amt);
|
||||
if (!ret)
|
||||
{
|
||||
if (ret.error() == EXPONENT_UNDERSIZED)
|
||||
return 0;
|
||||
return Unexpected(ret.error());
|
||||
}
|
||||
normalized = ret.value();
|
||||
}
|
||||
|
||||
if (normalized == EXPONENT_UNDERSIZED)
|
||||
/* exponent undersized (underflow) */
|
||||
return 0; // return 0 in this case
|
||||
return normalized;
|
||||
}
|
||||
catch (const std::bad_cast& e)
|
||||
{
|
||||
return Unexpected(NOT_AN_AMOUNT);
|
||||
}
|
||||
}
|
||||
|
||||
/// trace APIs
|
||||
// trace
|
||||
@@ -1887,6 +2176,19 @@ HookAPI::double_to_xfl(double x) const
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::optional<ripple::Keylet>
|
||||
HookAPI::unserialize_keylet(Bytes const& data) const
|
||||
{
|
||||
if (data.size() != 34)
|
||||
return {};
|
||||
|
||||
uint16_t ktype = ((uint16_t)data[0] << 8) + ((uint16_t)data[1]);
|
||||
|
||||
return ripple::Keylet{
|
||||
static_cast<LedgerEntryType>(ktype),
|
||||
ripple::uint256::fromVoid(data.data() + 2)};
|
||||
}
|
||||
|
||||
inline std::optional<
|
||||
std::reference_wrapper<std::pair<bool, ripple::Blob> const>>
|
||||
HookAPI::lookup_state_cache(
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include <ripple/app/hook/HookAPI.h>
|
||||
#include <ripple/app/hook/applyHook.h>
|
||||
#include <ripple/app/ledger/OpenLedger.h>
|
||||
#include <ripple/app/ledger/TransactionMaster.h>
|
||||
#include <ripple/app/misc/HashRouter.h>
|
||||
#include <ripple/app/misc/NetworkOPs.h>
|
||||
#include <ripple/app/misc/Transaction.h>
|
||||
@@ -2136,21 +2135,20 @@ DEFINE_HOOK_FUNCTION(
|
||||
return TOO_SMALL;
|
||||
}
|
||||
|
||||
if (hookCtx.slot.find(slot_no) == hookCtx.slot.end())
|
||||
return DOESNT_EXIST;
|
||||
|
||||
if (hookCtx.slot[slot_no].entry == 0)
|
||||
return INTERNAL_ERROR;
|
||||
hook::HookAPI api(hookCtx);
|
||||
auto const result = api.slot(slot_no);
|
||||
if (!result)
|
||||
return result.error();
|
||||
|
||||
Serializer s;
|
||||
hookCtx.slot[slot_no].entry->add(s);
|
||||
(*result)->add(s);
|
||||
|
||||
WRITE_WASM_MEMORY_OR_RETURN_AS_INT64(
|
||||
write_ptr,
|
||||
write_len,
|
||||
s.getDataPtr(),
|
||||
s.getDataLength(),
|
||||
hookCtx.slot[slot_no].entry->getSType() == STI_ACCOUNT);
|
||||
(*result)->getSType() == STI_ACCOUNT);
|
||||
|
||||
HOOK_TEARDOWN();
|
||||
}
|
||||
@@ -2160,13 +2158,12 @@ DEFINE_HOOK_FUNCTION(int64_t, slot_clear, uint32_t slot_no)
|
||||
HOOK_SETUP(); // populates memory_ctx, memory, memory_length, applyCtx,
|
||||
// hookCtx on current stack
|
||||
|
||||
if (hookCtx.slot.find(slot_no) == hookCtx.slot.end())
|
||||
return DOESNT_EXIST;
|
||||
hook::HookAPI api(hookCtx);
|
||||
auto const result = api.slot_clear(slot_no);
|
||||
if (!result)
|
||||
return result.error();
|
||||
|
||||
hookCtx.slot.erase(slot_no);
|
||||
hookCtx.slot_free.push(slot_no);
|
||||
|
||||
return 1;
|
||||
return result.value();
|
||||
|
||||
HOOK_TEARDOWN();
|
||||
}
|
||||
@@ -2176,16 +2173,12 @@ DEFINE_HOOK_FUNCTION(int64_t, slot_count, uint32_t slot_no)
|
||||
HOOK_SETUP(); // populates memory_ctx, memory, memory_length, applyCtx,
|
||||
// hookCtx on current stack
|
||||
|
||||
if (hookCtx.slot.find(slot_no) == hookCtx.slot.end())
|
||||
return DOESNT_EXIST;
|
||||
hook::HookAPI api(hookCtx);
|
||||
auto const result = api.slot_count(slot_no);
|
||||
if (!result)
|
||||
return result.error();
|
||||
|
||||
if (hookCtx.slot[slot_no].entry == 0)
|
||||
return INTERNAL_ERROR;
|
||||
|
||||
if (hookCtx.slot[slot_no].entry->getSType() != STI_ARRAY)
|
||||
return NOT_AN_ARRAY;
|
||||
|
||||
return hookCtx.slot[slot_no].entry->downcast<ripple::STArray>().size();
|
||||
return result.value();
|
||||
|
||||
HOOK_TEARDOWN();
|
||||
}
|
||||
@@ -2203,68 +2196,13 @@ DEFINE_HOOK_FUNCTION(
|
||||
if (NOT_IN_BOUNDS(read_ptr, read_len, memory_length))
|
||||
return OUT_OF_BOUNDS;
|
||||
|
||||
if ((read_len != 32 && read_len != 34) || slot_into > hook_api::max_slots)
|
||||
return INVALID_ARGUMENT;
|
||||
hook::HookAPI api(hookCtx);
|
||||
Bytes data{memory + read_ptr, memory + read_ptr + read_len};
|
||||
auto const result = api.slot_set(data, slot_into);
|
||||
if (!result)
|
||||
return result.error();
|
||||
|
||||
// check if we can emplace the object to a slot
|
||||
if (slot_into == 0 && no_free_slots(hookCtx))
|
||||
return NO_FREE_SLOTS;
|
||||
|
||||
std::vector<uint8_t> slot_key{
|
||||
memory + read_ptr, memory + read_ptr + read_len};
|
||||
std::optional<std::shared_ptr<const ripple::STObject>> slot_value =
|
||||
std::nullopt;
|
||||
|
||||
if (read_len == 34)
|
||||
{
|
||||
std::optional<ripple::Keylet> kl =
|
||||
unserialize_keylet(memory + read_ptr, read_len);
|
||||
if (!kl)
|
||||
return DOESNT_EXIST;
|
||||
|
||||
if (kl->key == beast::zero)
|
||||
return DOESNT_EXIST;
|
||||
|
||||
auto const sle = applyCtx.view().read(*kl);
|
||||
if (!sle)
|
||||
return DOESNT_EXIST;
|
||||
|
||||
slot_value = sle;
|
||||
}
|
||||
else if (read_len == 32)
|
||||
{
|
||||
uint256 hash = ripple::base_uint<256>::fromVoid(memory + read_ptr);
|
||||
|
||||
ripple::error_code_i ec{ripple::error_code_i::rpcUNKNOWN};
|
||||
|
||||
auto hTx = applyCtx.app.getMasterTransaction().fetch(hash, ec);
|
||||
|
||||
if (auto const* p = std::get_if<std::pair<
|
||||
std::shared_ptr<ripple::Transaction>,
|
||||
std::shared_ptr<ripple::TxMeta>>>(&hTx))
|
||||
slot_value = p->first->getSTransaction();
|
||||
else
|
||||
return DOESNT_EXIST;
|
||||
}
|
||||
else
|
||||
return DOESNT_EXIST;
|
||||
|
||||
if (!slot_value.has_value())
|
||||
return DOESNT_EXIST;
|
||||
|
||||
if (slot_into == 0)
|
||||
{
|
||||
if (auto found = get_free_slot(hookCtx); found)
|
||||
slot_into = *found;
|
||||
else
|
||||
return NO_FREE_SLOTS;
|
||||
}
|
||||
|
||||
hookCtx.slot[slot_into] =
|
||||
hook::SlotEntry{.storage = *slot_value, .entry = 0};
|
||||
hookCtx.slot[slot_into].entry = &(*hookCtx.slot[slot_into].storage);
|
||||
|
||||
return slot_into;
|
||||
return result.value();
|
||||
|
||||
HOOK_TEARDOWN();
|
||||
}
|
||||
@@ -2274,16 +2212,12 @@ DEFINE_HOOK_FUNCTION(int64_t, slot_size, uint32_t slot_no)
|
||||
HOOK_SETUP(); // populates memory_ctx, memory, memory_length, applyCtx,
|
||||
// hookCtx on current stack
|
||||
|
||||
if (hookCtx.slot.find(slot_no) == hookCtx.slot.end())
|
||||
return DOESNT_EXIST;
|
||||
hook::HookAPI api(hookCtx);
|
||||
auto const result = api.slot_size(slot_no);
|
||||
if (!result)
|
||||
return result.error();
|
||||
|
||||
if (hookCtx.slot[slot_no].entry == 0)
|
||||
return INTERNAL_ERROR;
|
||||
|
||||
// RH TODO: this is a very expensive way of computing size, cache it
|
||||
Serializer s;
|
||||
hookCtx.slot[slot_no].entry->add(s);
|
||||
return s.getDataLength();
|
||||
return result.value();
|
||||
|
||||
HOOK_TEARDOWN();
|
||||
}
|
||||
@@ -2298,57 +2232,12 @@ DEFINE_HOOK_FUNCTION(
|
||||
HOOK_SETUP(); // populates memory_ctx, memory, memory_length, applyCtx,
|
||||
// hookCtx on current stack
|
||||
|
||||
if (hookCtx.slot.find(parent_slot) == hookCtx.slot.end())
|
||||
return DOESNT_EXIST;
|
||||
hook::HookAPI api(hookCtx);
|
||||
auto const result = api.slot_subarray(parent_slot, array_id, new_slot);
|
||||
if (!result)
|
||||
return result.error();
|
||||
|
||||
if (hookCtx.slot[parent_slot].entry == 0)
|
||||
return INTERNAL_ERROR;
|
||||
|
||||
if (hookCtx.slot[parent_slot].entry->getSType() != STI_ARRAY)
|
||||
return NOT_AN_ARRAY;
|
||||
|
||||
if (new_slot == 0 && no_free_slots(hookCtx))
|
||||
return NO_FREE_SLOTS;
|
||||
|
||||
if (new_slot > hook_api::max_slots)
|
||||
return INVALID_ARGUMENT;
|
||||
|
||||
bool copied = false;
|
||||
try
|
||||
{
|
||||
ripple::STArray& parent_obj =
|
||||
const_cast<ripple::STBase&>(*hookCtx.slot[parent_slot].entry)
|
||||
.downcast<ripple::STArray>();
|
||||
|
||||
if (parent_obj.size() <= array_id)
|
||||
return DOESNT_EXIST;
|
||||
|
||||
if (new_slot == 0)
|
||||
{
|
||||
if (auto found = get_free_slot(hookCtx); found)
|
||||
new_slot = *found;
|
||||
else
|
||||
return NO_FREE_SLOTS;
|
||||
}
|
||||
|
||||
// copy
|
||||
if (new_slot != parent_slot)
|
||||
{
|
||||
copied = true;
|
||||
hookCtx.slot[new_slot] = hookCtx.slot[parent_slot];
|
||||
}
|
||||
hookCtx.slot[new_slot].entry = &(parent_obj[array_id]);
|
||||
return new_slot;
|
||||
}
|
||||
catch (const std::bad_cast& e)
|
||||
{
|
||||
if (copied)
|
||||
{
|
||||
hookCtx.slot.erase(new_slot);
|
||||
hookCtx.slot_free.push(new_slot);
|
||||
}
|
||||
return NOT_AN_ARRAY;
|
||||
}
|
||||
return result.value();
|
||||
|
||||
HOOK_TEARDOWN();
|
||||
}
|
||||
@@ -2363,61 +2252,12 @@ DEFINE_HOOK_FUNCTION(
|
||||
HOOK_SETUP(); // populates memory_ctx, memory, memory_length, applyCtx,
|
||||
// hookCtx on current stack
|
||||
|
||||
if (hookCtx.slot.find(parent_slot) == hookCtx.slot.end())
|
||||
return DOESNT_EXIST;
|
||||
hook::HookAPI api(hookCtx);
|
||||
auto const result = api.slot_subfield(parent_slot, field_id, new_slot);
|
||||
if (!result)
|
||||
return result.error();
|
||||
|
||||
if (new_slot == 0 && no_free_slots(hookCtx))
|
||||
return NO_FREE_SLOTS;
|
||||
|
||||
if (new_slot > hook_api::max_slots)
|
||||
return INVALID_ARGUMENT;
|
||||
|
||||
SField const& fieldCode = ripple::SField::getField(field_id);
|
||||
|
||||
if (fieldCode == sfInvalid)
|
||||
return INVALID_FIELD;
|
||||
|
||||
if (hookCtx.slot[parent_slot].entry == 0)
|
||||
return INTERNAL_ERROR;
|
||||
|
||||
bool copied = false;
|
||||
|
||||
try
|
||||
{
|
||||
ripple::STObject& parent_obj =
|
||||
const_cast<ripple::STBase&>(*hookCtx.slot[parent_slot].entry)
|
||||
.downcast<ripple::STObject>();
|
||||
|
||||
if (!parent_obj.isFieldPresent(fieldCode))
|
||||
return DOESNT_EXIST;
|
||||
|
||||
if (new_slot == 0)
|
||||
{
|
||||
if (auto found = get_free_slot(hookCtx); found)
|
||||
new_slot = *found;
|
||||
else
|
||||
return NO_FREE_SLOTS;
|
||||
}
|
||||
|
||||
// copy
|
||||
if (new_slot != parent_slot)
|
||||
{
|
||||
copied = true;
|
||||
hookCtx.slot[new_slot] = hookCtx.slot[parent_slot];
|
||||
}
|
||||
|
||||
hookCtx.slot[new_slot].entry = &(parent_obj.getField(fieldCode));
|
||||
return new_slot;
|
||||
}
|
||||
catch (const std::bad_cast& e)
|
||||
{
|
||||
if (copied)
|
||||
{
|
||||
hookCtx.slot.erase(new_slot);
|
||||
hookCtx.slot_free.push(new_slot);
|
||||
}
|
||||
return NOT_AN_OBJECT;
|
||||
}
|
||||
return result.value();
|
||||
|
||||
HOOK_TEARDOWN();
|
||||
}
|
||||
@@ -2465,42 +2305,12 @@ DEFINE_HOOK_FUNCTION(int64_t, slot_float, uint32_t slot_no)
|
||||
HOOK_SETUP(); // populates memory_ctx, memory, memory_length, applyCtx,
|
||||
// hookCtx on current stack
|
||||
|
||||
if (hookCtx.slot.find(slot_no) == hookCtx.slot.end())
|
||||
return DOESNT_EXIST;
|
||||
hook::HookAPI api(hookCtx);
|
||||
auto const result = api.slot_float(slot_no);
|
||||
if (!result)
|
||||
return result.error();
|
||||
|
||||
if (hookCtx.slot[slot_no].entry == 0)
|
||||
return INTERNAL_ERROR;
|
||||
|
||||
try
|
||||
{
|
||||
ripple::STAmount& st_amt =
|
||||
const_cast<ripple::STBase&>(*hookCtx.slot[slot_no].entry)
|
||||
.downcast<ripple::STAmount>();
|
||||
|
||||
int64_t normalized = 0;
|
||||
if (st_amt.native())
|
||||
{
|
||||
ripple::XRPAmount amt = st_amt.xrp();
|
||||
int64_t drops = amt.drops();
|
||||
int32_t exp = -6;
|
||||
// normalize
|
||||
normalized = hook_float::normalize_xfl(drops, exp);
|
||||
}
|
||||
else
|
||||
{
|
||||
ripple::IOUAmount amt = st_amt.iou();
|
||||
normalized = make_float(amt);
|
||||
}
|
||||
|
||||
if (normalized ==
|
||||
EXPONENT_UNDERSIZED /* exponent undersized (underflow) */)
|
||||
return 0; // return 0 in this case
|
||||
return normalized;
|
||||
}
|
||||
catch (const std::bad_cast& e)
|
||||
{
|
||||
return NOT_AN_AMOUNT;
|
||||
}
|
||||
return result.value();
|
||||
|
||||
HOOK_TEARDOWN();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user