Host-functions perf test fixes (#5514)

This commit is contained in:
Olek
2025-06-27 09:59:28 -04:00
committed by GitHub
parent add55c4f33
commit 1cd16fab87
7 changed files with 813 additions and 40 deletions

View File

@@ -30,7 +30,6 @@
#include <xrpl/protocol/jss.h>
#include <algorithm>
#include <filesystem>
#include <iterator>
namespace ripple {

View File

@@ -22,6 +22,8 @@
#include <xrpld/app/misc/WasmHostFunc.h>
#include <xrpld/app/misc/WasmVM.h>
#include <xrpld/app/tx/detail/NFTokenUtils.h>
#include <xrpld/ledger/detail/ApplyViewBase.h>
#include <wasm_c_api.h>
@@ -385,6 +387,571 @@ public:
}
};
struct PerfHostFunctions : public HostFunctions
{
test::jtx::Env& env_;
Keylet leKey;
static int constexpr MAX_CACHE = 256;
std::array<std::shared_ptr<SLE const>, MAX_CACHE> cache;
std::shared_ptr<STTx const> tx_;
void const* rt_ = nullptr;
public:
PerfHostFunctions(
test::jtx::Env& env,
Keylet const& k,
std::shared_ptr<STTx const>&& tx)
: env_(env), leKey(k), tx_(std::move(tx))
{
}
virtual void
setRT(void const* rt) override
{
rt_ = rt;
}
virtual void const*
getRT() const override
{
return rt_;
}
beast::Journal
getJournal() override
{
return env_.journal;
}
int32_t
getLedgerSqn() override
{
return static_cast<int32_t>(env_.current()->seq());
}
int32_t
getParentLedgerTime() override
{
return env_.current()->parentCloseTime().time_since_epoch().count();
}
Hash
getParentLedgerHash() override
{
return env_.current()->info().parentHash;
}
virtual int32_t
cacheLedgerObj(Keylet const&, int32_t cacheIdx) override
{
static int32_t intIdx = 0;
if (cacheIdx < 0 || cacheIdx > MAX_CACHE)
return HF_ERR_SLOT_OUT_RANGE;
if (!cacheIdx)
{
for (cacheIdx = 0; cacheIdx < MAX_CACHE; ++cacheIdx)
if (!cache[cacheIdx])
break;
if (cacheIdx >= MAX_CACHE)
cacheIdx = intIdx++ % MAX_CACHE;
}
else
--cacheIdx;
if (cacheIdx >= MAX_CACHE)
return HF_ERR_SLOTS_FULL;
cache[cacheIdx] = env_.le(leKey);
return cache[cacheIdx] ? cacheIdx + 1 : HF_ERR_LEDGER_OBJ_NOT_FOUND;
}
static Bytes
getAnyFieldData(STBase const& obj)
{
// auto const& fname = obj.getFName();
auto const stype = obj.getSType();
switch (stype)
{
case STI_UNKNOWN:
case STI_NOTPRESENT:
return {};
break;
case STI_ACCOUNT: {
auto const& super(static_cast<STAccount const&>(obj));
auto const& data = super.value();
return {data.begin(), data.end()};
}
break;
case STI_AMOUNT: {
auto const& super(static_cast<STAmount const&>(obj));
int64_t const data = super.xrp().drops();
auto const* b = reinterpret_cast<uint8_t const*>(&data);
auto const* e = reinterpret_cast<uint8_t const*>(&data + 1);
return {b, e};
}
break;
case STI_VL: {
auto const& super(static_cast<STBlob const&>(obj));
auto const& data = super.value();
return {data.begin(), data.end()};
}
break;
case STI_UINT256: {
auto const& super(static_cast<STBitString<256> const&>(obj));
auto const& data = super.value();
return {data.begin(), data.end()};
}
break;
case STI_UINT32: {
auto const& super(
static_cast<STInteger<std::uint32_t> const&>(obj));
std::uint32_t const data = super.value();
auto const* b = reinterpret_cast<uint8_t const*>(&data);
auto const* e = reinterpret_cast<uint8_t const*>(&data + 1);
return {b, e};
}
break;
default:
break;
}
Serializer msg;
obj.add(msg);
return msg.getData();
}
Expected<Bytes, int32_t>
getTxField(SField const& fname) override
{
auto const* field = tx_->peekAtPField(fname);
if (!field)
return Unexpected(HF_ERR_FIELD_NOT_FOUND);
if ((STI_OBJECT == field->getSType()) ||
(STI_ARRAY == field->getSType()))
return Unexpected(HF_ERR_NOT_LEAF_FIELD);
return getAnyFieldData(*field);
}
Expected<Bytes, int32_t>
getCurrentLedgerObjField(SField const& fname) override
{
auto const sle = env_.le(leKey);
if (!sle)
return Unexpected(HF_ERR_LEDGER_OBJ_NOT_FOUND);
auto const* field = sle->peekAtPField(fname);
if (!field)
return Unexpected(HF_ERR_FIELD_NOT_FOUND);
if ((STI_OBJECT == field->getSType()) ||
(STI_ARRAY == field->getSType()))
return Unexpected(HF_ERR_NOT_LEAF_FIELD);
return getAnyFieldData(*field);
}
Expected<Bytes, int32_t>
getLedgerObjField(int32_t cacheIdx, SField const& fname) override
{
--cacheIdx;
if (cacheIdx < 0 || cacheIdx >= MAX_CACHE)
return Unexpected(HF_ERR_SLOT_OUT_RANGE);
if (!cache[cacheIdx])
{
// return Unexpected(HF_ERR_INVALID_SLOT);
cache[cacheIdx] = env_.le(leKey);
}
auto const* field = cache[cacheIdx]->peekAtPField(fname);
if (!field)
return Unexpected(HF_ERR_FIELD_NOT_FOUND);
if ((STI_OBJECT == field->getSType()) ||
(STI_ARRAY == field->getSType()))
return Unexpected(HF_ERR_NOT_LEAF_FIELD);
return getAnyFieldData(*field);
}
static Expected<STBase const*, int32_t>
locateField(STObject const& obj, Slice const& loc)
{
if (loc.empty() || (loc.size() & 3)) // must be multiple of 4
return Unexpected(HF_ERR_LOCATOR_MALFORMED);
int32_t const* l = reinterpret_cast<int32_t const*>(loc.data());
int32_t const sz = loc.size() / 4;
STBase const* field = nullptr;
auto const& m = SField::getKnownCodeToField();
{
int32_t const c = l[0];
auto const it = m.find(c);
if (it == m.end())
return Unexpected(HF_ERR_LOCATOR_MALFORMED);
auto const& fname(*it->second);
field = obj.peekAtPField(fname);
if (!field || (STI_NOTPRESENT == field->getSType()))
return Unexpected(HF_ERR_FIELD_NOT_FOUND);
}
for (int i = 1; i < sz; ++i)
{
int32_t const c = l[i];
if (STI_ARRAY == field->getSType())
{
auto const* arr = static_cast<STArray const*>(field);
if (c >= arr->size())
return Unexpected(HF_ERR_LOCATOR_MALFORMED);
field = &(arr->operator[](c));
}
else if (STI_OBJECT == field->getSType())
{
auto const* o = static_cast<STObject const*>(field);
auto const it = m.find(c);
if (it == m.end())
return Unexpected(HF_ERR_LOCATOR_MALFORMED);
auto const& fname(*it->second);
field = o->peekAtPField(fname);
}
else // simple field must be the last one
{
return Unexpected(HF_ERR_LOCATOR_MALFORMED);
}
if (!field || (STI_NOTPRESENT == field->getSType()))
return Unexpected(HF_ERR_FIELD_NOT_FOUND);
}
return field;
}
Expected<Bytes, int32_t>
getTxNestedField(Slice const& locator) override
{
// std::cout << tx_->getJson(JsonOptions::none).toStyledString() <<
// std::endl;
auto const r = locateField(*tx_, locator);
if (!r)
return Unexpected(r.error());
auto const* field = r.value();
if ((STI_OBJECT == field->getSType()) ||
(STI_ARRAY == field->getSType()))
return Unexpected(HF_ERR_NOT_LEAF_FIELD);
return getAnyFieldData(*field);
}
Expected<Bytes, int32_t>
getCurrentLedgerObjNestedField(Slice const& locator) override
{
auto const sle = env_.le(leKey);
if (!sle)
return Unexpected(HF_ERR_LEDGER_OBJ_NOT_FOUND);
auto const r = locateField(*sle, locator);
if (!r)
return Unexpected(r.error());
auto const* field = r.value();
if ((STI_OBJECT == field->getSType()) ||
(STI_ARRAY == field->getSType()))
return Unexpected(HF_ERR_NOT_LEAF_FIELD);
return getAnyFieldData(*field);
}
Expected<Bytes, int32_t>
getLedgerObjNestedField(int32_t cacheIdx, Slice const& locator) override
{
--cacheIdx;
if (cacheIdx < 0 || cacheIdx >= MAX_CACHE)
return Unexpected(HF_ERR_SLOT_OUT_RANGE);
if (!cache[cacheIdx])
{
// return Unexpected(HF_ERR_INVALID_SLOT);
cache[cacheIdx] = env_.le(leKey);
}
auto const r = locateField(*cache[cacheIdx], locator);
if (!r)
return Unexpected(r.error());
auto const* field = r.value();
if ((STI_OBJECT == field->getSType()) ||
(STI_ARRAY == field->getSType()))
return Unexpected(HF_ERR_NOT_LEAF_FIELD);
return getAnyFieldData(*field);
}
int32_t
getTxArrayLen(SField const& fname) override
{
if (fname.fieldType != STI_ARRAY)
return HF_ERR_NO_ARRAY;
auto const* field = tx_->peekAtPField(fname);
if (!field)
return HF_ERR_FIELD_NOT_FOUND;
if (field->getSType() != STI_ARRAY)
return HF_ERR_NO_ARRAY;
int32_t const sz = static_cast<STArray const*>(field)->size();
return sz;
}
int32_t
getCurrentLedgerObjArrayLen(SField const& fname) override
{
if (fname.fieldType != STI_ARRAY)
return HF_ERR_NO_ARRAY;
auto const sle = env_.le(leKey);
if (!sle)
return HF_ERR_LEDGER_OBJ_NOT_FOUND;
auto const* field = sle->peekAtPField(fname);
if (!field)
return HF_ERR_FIELD_NOT_FOUND;
if (field->getSType() != STI_ARRAY)
return HF_ERR_NO_ARRAY;
int32_t const sz = static_cast<STArray const*>(field)->size();
return sz;
}
int32_t
getLedgerObjArrayLen(int32_t cacheIdx, SField const& fname) override
{
if (fname.fieldType != STI_ARRAY)
return HF_ERR_NO_ARRAY;
if (cacheIdx < 0 || cacheIdx >= MAX_CACHE)
return HF_ERR_SLOT_OUT_RANGE;
if (!cache[cacheIdx])
{
// return Unexpected(HF_ERR_INVALID_SLOT);
cache[cacheIdx] = env_.le(leKey);
}
auto const* field = cache[cacheIdx]->peekAtPField(fname);
if (!field)
return HF_ERR_FIELD_NOT_FOUND;
if (field->getSType() != STI_ARRAY)
return HF_ERR_NO_ARRAY;
int32_t const sz = static_cast<STArray const*>(field)->size();
return sz;
}
int32_t
getTxNestedArrayLen(Slice const& locator) override
{
auto const r = locateField(*tx_, locator);
if (!r)
return r.error();
auto const* field = r.value();
if (field->getSType() != STI_ARRAY)
return HF_ERR_NO_ARRAY;
int32_t const sz = static_cast<STArray const*>(field)->size();
return sz;
}
int32_t
getCurrentLedgerObjNestedArrayLen(Slice const& locator) override
{
auto const sle = env_.le(leKey);
if (!sle)
return HF_ERR_LEDGER_OBJ_NOT_FOUND;
auto const r = locateField(*sle, locator);
if (!r)
return r.error();
auto const* field = r.value();
if (field->getSType() != STI_ARRAY)
return HF_ERR_NO_ARRAY;
int32_t const sz = static_cast<STArray const*>(field)->size();
return sz;
}
int32_t
getLedgerObjNestedArrayLen(int32_t cacheIdx, Slice const& locator) override
{
--cacheIdx;
if (cacheIdx < 0 || cacheIdx >= MAX_CACHE)
return HF_ERR_SLOT_OUT_RANGE;
if (!cache[cacheIdx])
{
// return Unexpected(HF_ERR_INVALID_SLOT);
cache[cacheIdx] = env_.le(leKey);
}
auto const r = locateField(*cache[cacheIdx], locator);
if (!r)
return r.error();
auto const* field = r.value();
if (field->getSType() != STI_ARRAY)
return HF_ERR_NO_ARRAY;
int32_t const sz = static_cast<STArray const*>(field)->size();
return sz;
}
int32_t
updateData(Bytes const& data) override
{
ripple::detail::ApplyViewBase v(
env_.app().openLedger().current().get(), tapNONE);
auto sle = v.peek(leKey);
if (!sle)
return HF_ERR_LEDGER_OBJ_NOT_FOUND;
sle->setFieldVL(sfData, data);
v.update(sle);
return data.size();
}
Hash
computeSha512HalfHash(Bytes const& data) override
{
auto const hash = sha512Half(data);
return hash;
}
Expected<Bytes, int32_t>
accountKeylet(AccountID const& account) override
{
if (!account)
return Unexpected(HF_ERR_INVALID_ACCOUNT);
auto const keylet = keylet::account(account);
return Bytes{keylet.key.begin(), keylet.key.end()};
}
Expected<Bytes, int32_t>
credentialKeylet(
AccountID const& subject,
AccountID const& issuer,
Bytes const& credentialType) override
{
if (!subject || !issuer || credentialType.empty() ||
credentialType.size() > maxCredentialTypeLength)
return Unexpected(HF_ERR_INVALID_PARAMS);
auto const keylet =
keylet::credential(subject, issuer, makeSlice(credentialType));
return Bytes{keylet.key.begin(), keylet.key.end()};
}
Expected<Bytes, int32_t>
escrowKeylet(AccountID const& account, std::uint32_t seq) override
{
if (!account)
return Unexpected(HF_ERR_INVALID_ACCOUNT);
auto const keylet = keylet::escrow(account, seq);
return Bytes{keylet.key.begin(), keylet.key.end()};
}
Expected<Bytes, int32_t>
oracleKeylet(AccountID const& account, std::uint32_t documentId) override
{
if (!account)
return Unexpected(HF_ERR_INVALID_ACCOUNT);
auto const keylet = keylet::oracle(account, documentId);
return Bytes{keylet.key.begin(), keylet.key.end()};
}
Expected<Bytes, int32_t>
getNFT(AccountID const& account, uint256 const& nftId) override
{
if (!account || !nftId)
{
getJournal().trace() << "WAMR getNFT: Invalid account or NFT ID";
return Unexpected(HF_ERR_INVALID_PARAMS);
}
auto obj = nft::findToken(*env_.current(), account, nftId);
if (!obj)
{
getJournal().trace() << "WAMR getNFT: NFT not found";
return Unexpected(HF_ERR_LEDGER_OBJ_NOT_FOUND);
}
auto ouri = obj->at(~sfURI);
if (!ouri)
return Bytes();
Slice const s = ouri->value();
return Bytes(s.begin(), s.end());
}
int32_t
trace(std::string const& msg, Bytes const& data, bool asHex) override
{
#ifdef DEBUG_OUTPUT
auto& j = std::cerr;
#else
auto j = getJournal().error();
#endif
if (!asHex)
j << msg
<< std::string_view(
reinterpret_cast<char const*>(data.data()), data.size());
else
{
auto const hex =
boost::algorithm::hex(std::string(data.begin(), data.end()));
j << msg << hex;
}
#ifdef DEBUG_OUTPUT
j << std::endl;
#endif
return msg.size() + data.size() * (asHex ? 2 : 1);
}
int32_t
traceNum(std::string const& msg, int64_t data) override
{
#ifdef DEBUG_OUTPUT
auto& j = std::cerr;
#else
auto j = getJournal().error();
#endif
j << msg << data;
#ifdef DEBUG_OUTPUT
j << std::endl;
#endif
return msg.size() + sizeof(data);
}
};
struct Wasm_test : public beast::unit_test::suite
{
void
@@ -831,6 +1398,103 @@ struct Wasm_test : public beast::unit_test::suite
}
}
void
perfTest()
{
testcase("Perf test host functions");
using namespace jtx;
using namespace std::chrono;
std::string const funcName("finish");
// std::string const funcName("test");
auto const& wasmHex = hfPerfTest;
// auto const& wasmHex = opcCallPerfTest;
std::string const wasmStr = boost::algorithm::unhex(wasmHex);
std::vector<uint8_t> const wasm(wasmStr.begin(), wasmStr.end());
std::string const credType = "abcde";
std::string const credType2 = "fghijk";
std::string const credType3 = "0123456";
// char const uri[] = "uri";
Account const alan{"alan"};
Account const bob{"bob"};
Account const issuer{"issuer"};
{
Env env(*this);
// Env env(*this, envconfig(), {}, nullptr,
// beast::severities::kTrace);
env.fund(XRP(5000), alan, bob, issuer);
env.close();
// // create escrow
// auto const seq = env.seq(alan);
// auto const k = keylet::escrow(alan, seq);
// // auto const allowance = 3'600;
// auto escrowCreate = escrow::create(alan, bob, XRP(1000));
// XRPAmount txnFees = env.current()->fees().base + 1000;
// env(escrowCreate,
// escrow::finish_function(wasmHex),
// escrow::finish_time(env.now() + 11s),
// escrow::cancel_time(env.now() + 100s),
// escrow::data("1000000000"), // 1000 XRP in drops
// memodata("memo1234567"),
// memodata("2memo1234567"),
// fee(txnFees));
// // create depositPreauth
// auto const k = keylet::depositPreauth(
// bob,
// {{issuer.id(), makeSlice(credType)},
// {issuer.id(), makeSlice(credType2)},
// {issuer.id(), makeSlice(credType3)}});
// env(deposit::authCredentials(
// bob,
// {{issuer, credType},
// {issuer, credType2},
// {issuer, credType3}}));
// cREATE nft
[[maybe_unused]] uint256 const nft0{
token::getNextID(env, alan, 0u)};
env(token::mint(alan, 0u));
auto const k = keylet::nftoffer(alan, 0);
[[maybe_unused]] uint256 const nft1{
token::getNextID(env, alan, 0u)};
env(token::mint(alan, 0u),
token::uri(
"https://github.com/XRPLF/XRPL-Standards/discussions/"
"279?id=github.com/XRPLF/XRPL-Standards/discussions/"
"279&ut=github.com/XRPLF/XRPL-Standards/discussions/"
"279&sid=github.com/XRPLF/XRPL-Standards/discussions/"
"279&aot=github.com/XRPLF/XRPL-Standards/disc"));
[[maybe_unused]] uint256 const nft2{
token::getNextID(env, alan, 0u)};
env(token::mint(alan, 0u));
env.close();
PerfHostFunctions nfs(env, k, env.tx());
auto re = runEscrowWasm(wasm, funcName, {}, &nfs);
if (BEAST_EXPECT(re.has_value()))
{
BEAST_EXPECT(re->result);
std::cout << "Res: " << re->result << " cost: " << re->cost
<< std::endl;
}
// env(escrow::finish(alan, alan, seq),
// escrow::comp_allowance(allowance),
// fee(txnFees),
// ter(tesSUCCESS));
env.close();
}
}
void
run() override
{
@@ -853,6 +1517,8 @@ struct Wasm_test : public beast::unit_test::suite
// TODO: fix result
testEscrowWasmDN1();
testEscrowWasmDN2();
// perfTest();
}
};

View File

@@ -11709,3 +11709,50 @@ extern std::string const reqNonexistentField =
"2e31202834656231363132353020323032352d30332d31352900490f7461726765745f6665"
"617475726573042b0f6d757461626c652d676c6f62616c732b087369676e2d6578742b0f72"
"65666572656e63652d74797065732b0a6d756c746976616c7565";
extern std::string const hfPerfTest =
"0061736d0100000001180460037f7f7e017f60057f7f7f7f7f017f600000"
"6000017f021d0203656e760974726163655f6e756d000003656e76057472"
"616365000103030202030503010002068601167f0041a0090b7f0041a011"
"0b7f0041e0080b7f0041a0080b7f0041c0080b7f004180080b7f00418408"
"0b7f004188080b7f00418c080b7f004190080b7f004194080b7f00419808"
"0b7f004180090b7f004180080b7f0041e0110b7f0041e0110b7f0041e091"
"040b7f004180080b7f0041e091040b7f00418080080b7f0041000b7f0041"
"010b07c50219066d656d6f72790200115f5f7761736d5f63616c6c5f6374"
"6f727300020666696e6973680003036275660300076c6f635f6275660301"
"036d73670302086572725f686561640303096572725f646174613103040a"
"53465f4163636f756e7403050e53465f44657374696e6174696f6e030608"
"53465f4d656d6f7303070753465f4d656d6f03080b53465f4d656d6f4461"
"746103090753465f44617461030a1753465f417574686f72697a65437265"
"64656e7469616c73030b066163635f6964030c0c5f5f64736f5f68616e64"
"6c65030d0a5f5f646174615f656e64030e0b5f5f737461636b5f6c6f7703"
"0f0c5f5f737461636b5f6869676803100d5f5f676c6f62616c5f62617365"
"03110b5f5f686561705f6261736503120a5f5f686561705f656e6403130d"
"5f5f6d656d6f72795f6261736503140c5f5f7461626c655f626173650315"
"0aa2010202000b9c0102017f017e41807821000340200041a0116a420037"
"0300200041086a22000d000b41d811420037030041d011420037030041c8"
"11420037030041c011420037030041b811420037030041b0114200370300"
"41a811428d801c37030041a011429a803c3703000240034041e008411020"
"0110004118460440200142017c220142c0843d520d010c020b0b41a00841"
"1441c0084113410010011a0b41010b0b840104004180080b340100080003"
"00080009000f000a000e000d0007001b0007001a000f0000000000676574"
"5f6c65646765725f73716e206572726f720041c0080b13696e76616c6964"
"2072657475726e2073697a650041e0080b104e6577206163636f756e7420"
"69643a20004180090b14fc4f9afac9f1a8db807fda7dc9247bb557569d58"
"007f0970726f647563657273010c70726f6365737365642d62790105636c"
"616e675f31392e312e352d776173692d73646b202868747470733a2f2f67"
"69746875622e636f6d2f6c6c766d2f6c6c766d2d70726f6a656374206162"
"346235613264623538323935386166316565333038613739306366646234"
"32626432343732302900490f7461726765745f6665617475726573042b0f"
"6d757461626c652d676c6f62616c732b087369676e2d6578742b0f726566"
"6572656e63652d74797065732b0a6d756c746976616c7565";
extern std::string const opcCallPerfTest =
"0061736d010000000112046000017e60027f7f017f6000017f6000000304"
"0303020104050170010101050401008002061c047f0141b08880040b7f00"
"41ac080b7f0041b08880040b7f01410a0b073305066d656d6f7279020004"
"6d61696e0002047465737400010a5f5f646174615f656e6403010b5f5f68"
"6561705f6261736503020a4e030400010f0b3b04017f017c017f027e4180"
"84afdf0021004494b768e11b6c9b42210141d1e3c6012102024003401000"
"200041016b220041004a0d000b0b41010f0b0b01017f1001210220020f0b"
"0b0e01004180080b07623a2025660a00";

View File

@@ -56,3 +56,7 @@ extern std::string const xrplStdExampleHex;
extern std::string const hostFunctions2Hex;
extern std::string const reqNonexistentField;
extern std::string const hfPerfTest;
extern std::string const opcCallPerfTest;

View File

@@ -28,6 +28,8 @@
// #define DEBUG_OUTPUT_WAMR 1
#endif
// #define SHOW_CALL_TIME 1
namespace ripple {
namespace {
@@ -738,6 +740,18 @@ WamrEngine::call(FuncInfo const& f, Types&&... args)
return call<NR>(f, in, std::forward<Types>(args)...);
}
#ifdef SHOW_CALL_TIME
static inline uint64_t
usecs()
{
uint64_t x =
std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::high_resolution_clock::now().time_since_epoch())
.count();
return x;
}
#endif
template <int NR, class... Types>
WamrResult
WamrEngine::call(FuncInfo const& f, std::vector<wasm_val_t>& in)
@@ -762,7 +776,19 @@ WamrEngine::call(FuncInfo const& f, std::vector<wasm_val_t>& in)
in.size(),
sizeof(std::remove_reference_t<decltype(in)>::value_type),
nullptr};
#ifdef SHOW_CALL_TIME
auto const start = usecs();
#endif
wasm_trap_t* trap = wasm_func_call(f.first, &inv, &ret.r);
#ifdef SHOW_CALL_TIME
auto const finish = usecs();
auto const delta_ms = (finish - start) / 1000;
std::cout << "wasm_func_call: " << delta_ms << "ms" << std::endl;
#endif
if (trap)
{
ret.f = true;

View File

@@ -39,7 +39,7 @@ WasmHostFunctionsImpl::getLedgerSqn()
int32_t
WasmHostFunctionsImpl::getParentLedgerTime()
{
return ctx.view().parentCloseTime().time_since_epoch().count(); // TODO try
return ctx.view().parentCloseTime().time_since_epoch().count();
}
Hash
@@ -70,7 +70,7 @@ WasmHostFunctionsImpl::cacheLedgerObj(Keylet const& keylet, int32_t cacheIdx)
return cache[cacheIdx] ? cacheIdx + 1 : HF_ERR_LEDGER_OBJ_NOT_FOUND;
}
Bytes
static Bytes
getAnyFieldData(STBase const& obj)
{
// auto const& fname = obj.getFName();
@@ -132,6 +132,9 @@ WasmHostFunctionsImpl::getTxField(SField const& fname)
auto const* field = ctx.tx.peekAtPField(fname);
if (!field)
return Unexpected(HF_ERR_FIELD_NOT_FOUND);
if ((STI_OBJECT == field->getSType()) || (STI_ARRAY == field->getSType()))
return Unexpected(HF_ERR_NOT_LEAF_FIELD);
return getAnyFieldData(*field);
}
@@ -145,6 +148,8 @@ WasmHostFunctionsImpl::getCurrentLedgerObjField(SField const& fname)
auto const* field = sle->peekAtPField(fname);
if (!field)
return Unexpected(HF_ERR_FIELD_NOT_FOUND);
if ((STI_OBJECT == field->getSType()) || (STI_ARRAY == field->getSType()))
return Unexpected(HF_ERR_NOT_LEAF_FIELD);
return getAnyFieldData(*field);
}
@@ -162,14 +167,16 @@ WasmHostFunctionsImpl::getLedgerObjField(int32_t cacheIdx, SField const& fname)
auto const* field = cache[cacheIdx]->peekAtPField(fname);
if (!field)
return Unexpected(HF_ERR_FIELD_NOT_FOUND);
if ((STI_OBJECT == field->getSType()) || (STI_ARRAY == field->getSType()))
return Unexpected(HF_ERR_NOT_LEAF_FIELD);
return getAnyFieldData(*field);
}
static Expected<STBase const*, int32_t>
locateField(STObject const* obj, Slice const& loc)
locateField(STObject const& obj, Slice const& loc)
{
if (loc.size() % 4)
if (loc.empty() || (loc.size() & 3)) // must be multiple of 4
return Unexpected(HF_ERR_LOCATOR_MALFORMED);
int32_t const* l = reinterpret_cast<int32_t const*>(loc.data());
@@ -177,22 +184,23 @@ locateField(STObject const* obj, Slice const& loc)
STBase const* field = nullptr;
auto const& m = SField::getKnownCodeToField();
for (int i = 0; i < sz; ++i)
{
int32_t const c = l[0];
auto const it = m.find(c);
if (it == m.end())
return Unexpected(HF_ERR_LOCATOR_MALFORMED);
auto const& fname(*it->second);
field = obj.peekAtPField(fname);
if (!field || (STI_NOTPRESENT == field->getSType()))
return Unexpected(HF_ERR_FIELD_NOT_FOUND);
}
for (int i = 1; i < sz; ++i)
{
int32_t const c = l[i];
if (!field)
{
auto const it = m.find(c);
if (it == m.end())
return Unexpected(HF_ERR_FIELD_NOT_FOUND);
auto const& fname(*it->second);
field = obj->peekAtPField(fname);
if (!field)
return Unexpected(HF_ERR_FIELD_NOT_FOUND);
}
else if (STI_ARRAY == field->getSType())
if (STI_ARRAY == field->getSType())
{
auto const* arr = static_cast<STArray const*>(field);
if (c >= arr->size())
@@ -205,18 +213,19 @@ locateField(STObject const* obj, Slice const& loc)
auto const it = m.find(c);
if (it == m.end())
return Unexpected(HF_ERR_FIELD_NOT_FOUND);
return Unexpected(HF_ERR_LOCATOR_MALFORMED);
auto const& fname(*it->second);
field = o->peekAtPField(fname);
if (!field)
return Unexpected(HF_ERR_FIELD_NOT_FOUND);
}
}
else // simple field must be the last one
{
return Unexpected(HF_ERR_LOCATOR_MALFORMED);
}
if (!field || (STI_OBJECT == field->getSType()) ||
(STI_ARRAY == field->getSType()))
return Unexpected(HF_ERR_LOCATOR_MALFORMED);
if (!field || (STI_NOTPRESENT == field->getSType()))
return Unexpected(HF_ERR_FIELD_NOT_FOUND);
}
return field;
}
@@ -224,11 +233,14 @@ locateField(STObject const* obj, Slice const& loc)
Expected<Bytes, int32_t>
WasmHostFunctionsImpl::getTxNestedField(Slice const& locator)
{
auto const r = locateField(&ctx.tx, locator);
if (!r.has_value())
auto const r = locateField(ctx.tx, locator);
if (!r)
return Unexpected(r.error());
auto const* field = r.value();
if ((STI_OBJECT == field->getSType()) || (STI_ARRAY == field->getSType()))
return Unexpected(HF_ERR_NOT_LEAF_FIELD);
return getAnyFieldData(*field);
}
@@ -239,11 +251,14 @@ WasmHostFunctionsImpl::getCurrentLedgerObjNestedField(Slice const& locator)
if (!sle)
return Unexpected(HF_ERR_LEDGER_OBJ_NOT_FOUND);
auto const r = locateField(sle.get(), locator);
if (!r.has_value())
auto const r = locateField(*sle, locator);
if (!r)
return Unexpected(r.error());
auto const* field = r.value();
if ((STI_OBJECT == field->getSType()) || (STI_ARRAY == field->getSType()))
return Unexpected(HF_ERR_NOT_LEAF_FIELD);
return getAnyFieldData(*field);
}
@@ -259,11 +274,14 @@ WasmHostFunctionsImpl::getLedgerObjNestedField(
if (!cache[cacheIdx])
return Unexpected(HF_ERR_INVALID_SLOT);
auto const r = locateField(cache[cacheIdx].get(), locator);
if (!r.has_value())
auto const r = locateField(*cache[cacheIdx], locator);
if (!r)
return Unexpected(r.error());
auto const* field = r.value();
if ((STI_OBJECT == field->getSType()) || (STI_ARRAY == field->getSType()))
return Unexpected(HF_ERR_NOT_LEAF_FIELD);
return getAnyFieldData(*field);
}
@@ -333,8 +351,8 @@ WasmHostFunctionsImpl::getLedgerObjArrayLen(
int32_t
WasmHostFunctionsImpl::getTxNestedArrayLen(Slice const& locator)
{
auto const r = locateField(&ctx.tx, locator);
if (!r.has_value())
auto const r = locateField(ctx.tx, locator);
if (!r)
return r.error();
auto const* field = r.value();
@@ -351,8 +369,8 @@ WasmHostFunctionsImpl::getCurrentLedgerObjNestedArrayLen(Slice const& locator)
auto const sle = ctx.view().read(leKey);
if (!sle)
return HF_ERR_LEDGER_OBJ_NOT_FOUND;
auto const r = locateField(sle.get(), locator);
if (!r.has_value())
auto const r = locateField(*sle, locator);
if (!r)
return r.error();
auto const* field = r.value();
@@ -375,8 +393,8 @@ WasmHostFunctionsImpl::getLedgerObjNestedArrayLen(
if (!cache[cacheIdx])
return HF_ERR_INVALID_SLOT;
auto const r = locateField(cache[cacheIdx].get(), locator);
if (!r.has_value())
auto const r = locateField(*cache[cacheIdx], locator);
if (!r)
return r.error();
auto const* field = r.value();
@@ -445,7 +463,7 @@ WasmHostFunctionsImpl::oracleKeylet(
AccountID const& account,
std::uint32_t documentId)
{
if (!account || account.isZero())
if (!account)
return Unexpected(HF_ERR_INVALID_ACCOUNT);
auto const keylet = keylet::oracle(account, documentId);
return Bytes{keylet.key.begin(), keylet.key.end()};
@@ -467,7 +485,11 @@ WasmHostFunctionsImpl::getNFT(AccountID const& account, uint256 const& nftId)
return Unexpected(HF_ERR_LEDGER_OBJ_NOT_FOUND);
}
Slice const s = obj->at(sfURI);
auto ouri = obj->at(~sfURI);
if (!ouri)
return Bytes();
Slice const s = ouri->value();
return Bytes(s.begin(), s.end());
}

View File

@@ -34,6 +34,9 @@ setData(
uint8_t const* src,
int32_t ssz)
{
if (!ssz)
return 0;
auto mem = rt ? rt->getMem() : wmem();
if (!mem.s)
@@ -51,6 +54,9 @@ setData(
static Expected<Bytes, int32_t>
getData(InstanceWrapper const* rt, int32_t src, int32_t ssz)
{
if (!ssz)
return Unexpected(HF_ERR_INVALID_PARAMS);
auto mem = rt ? rt->getMem() : wmem();
if (!mem.s)
return Unexpected(HF_ERR_NO_MEM_EXPORTED);
@@ -66,7 +72,7 @@ static Expected<AccountID, int32_t>
getDataAccount(InstanceWrapper const* rt, int32_t ptr, int32_t sz)
{
auto const r = getData(rt, ptr, sz);
if (r->size() < AccountID::bytes)
if (!r || (r->size() < AccountID::bytes))
return Unexpected(HF_ERR_INVALID_PARAMS);
return AccountID::fromVoid(r->data());
@@ -75,6 +81,9 @@ getDataAccount(InstanceWrapper const* rt, int32_t ptr, int32_t sz)
static Expected<std::string, int32_t>
getDataString(InstanceWrapper const* rt, int32_t src, int32_t ssz)
{
if (!ssz)
return Unexpected(HF_ERR_INVALID_PARAMS);
auto mem = rt ? rt->getMem() : wmem();
if (!mem.s)
return Unexpected(HF_ERR_NO_MEM_EXPORTED);