mirror of
https://github.com/XRPLF/rippled.git
synced 2026-06-16 15:16:48 +00:00
Compare commits
225 Commits
3.2.0
...
ripple/was
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ca2d999618 | ||
|
|
5ee903befc | ||
|
|
d582ae7990 | ||
|
|
0dbe51c740 | ||
|
|
63fff4b518 | ||
|
|
d85bf722ea | ||
|
|
b664989cfb | ||
|
|
e77934302a | ||
|
|
ef7aeca6bf | ||
|
|
eec1d29b92 | ||
|
|
971ba2281e | ||
|
|
90357eeae1 | ||
|
|
597202a6f0 | ||
|
|
1600b3e7f3 | ||
|
|
ecee732187 | ||
|
|
ce2586c039 | ||
|
|
8cc2169939 | ||
|
|
826f613ad8 | ||
|
|
1259c1d5ca | ||
|
|
d2641d85bd | ||
|
|
75f66bd9fe | ||
|
|
7cd71cb659 | ||
|
|
9917f96166 | ||
|
|
e1cc82587b | ||
|
|
2cc9439fde | ||
|
|
52af9582e2 | ||
|
|
46e88dc732 | ||
|
|
bc24f2e211 | ||
|
|
7a7c993b15 | ||
|
|
9733ca8f91 | ||
|
|
18d5e3e226 | ||
|
|
b30b4e1d65 | ||
|
|
d435893602 | ||
|
|
00b0cf50f6 | ||
|
|
7ef256499c | ||
|
|
1338062be7 | ||
|
|
4fc1778ec8 | ||
|
|
65322d9e78 | ||
|
|
c5598a4284 | ||
|
|
0deb6bcadf | ||
|
|
9b013b559b | ||
|
|
1d4a3c00b8 | ||
|
|
4b34102e8e | ||
|
|
d006433579 | ||
|
|
a7ab8ee923 | ||
|
|
e0073a4402 | ||
|
|
2930ef217f | ||
|
|
9dbb301699 | ||
|
|
531e8b6ebd | ||
|
|
90397e1a52 | ||
|
|
888ca2e6d9 | ||
|
|
b6514b680f | ||
|
|
913e4b919e | ||
|
|
196e6a1b27 | ||
|
|
27468ddbcf | ||
|
|
bce5d91e45 | ||
|
|
654338fa66 | ||
|
|
9c25d18851 | ||
|
|
3a825a41e1 | ||
|
|
a9ebf786c6 | ||
|
|
5afe8cc321 | ||
|
|
bc5ec3c962 | ||
|
|
1775251e90 | ||
|
|
61bcb7621f | ||
|
|
a3f71b1774 | ||
|
|
4df7d1a4bb | ||
|
|
125df7a425 | ||
|
|
b08bcf5d21 | ||
|
|
dc413aef0c | ||
|
|
77dfd56ace | ||
|
|
953b9a3500 | ||
|
|
1d9ec84350 | ||
|
|
0392846a17 | ||
|
|
1b4a564369 | ||
|
|
fd524c4be9 | ||
|
|
495dda7f58 | ||
|
|
9c3c0280b1 | ||
|
|
f73d8a6cf2 | ||
|
|
6728ab52b7 | ||
|
|
77673663ca | ||
|
|
c1381f8ddd | ||
|
|
bd16f7989d | ||
|
|
65f9cf80c0 | ||
|
|
de55a5ebfc | ||
|
|
2ec4a1114e | ||
|
|
ba03a8a9d2 | ||
|
|
7c8279ec83 | ||
|
|
0418ffb26a | ||
|
|
b2627039f6 | ||
|
|
8f97ec3bde | ||
|
|
e85e7b1b1a | ||
|
|
803a344c65 | ||
|
|
4eb34f381a | ||
|
|
72fffb6e51 | ||
|
|
f7ee580f01 | ||
|
|
122d405750 | ||
|
|
c1c1b4ea67 | ||
|
|
977caea0a5 | ||
|
|
d7ed6d6512 | ||
|
|
f1f2e2629f | ||
|
|
917c610f96 | ||
|
|
317e533d81 | ||
|
|
4160677878 | ||
|
|
df98db1452 | ||
|
|
673476ef1b | ||
|
|
8bc6f9cd70 | ||
|
|
ba5debfecd | ||
|
|
f4a27c9b6d | ||
|
|
fd1cb318e3 | ||
|
|
8c3544a58c | ||
|
|
ed5139d4e3 | ||
|
|
42494dd4cf | ||
|
|
ce84cc8b44 | ||
|
|
9a9a7aab01 | ||
|
|
209a1a6ffa | ||
|
|
fc35a9f9c8 | ||
|
|
c5e50aa221 | ||
|
|
074b1f00d5 | ||
|
|
7a9d245950 | ||
|
|
1809fe07f2 | ||
|
|
409c67494a | ||
|
|
c626b6403a | ||
|
|
81cbc91927 | ||
|
|
1c812a6c4d | ||
|
|
0724927799 | ||
|
|
d83ec96848 | ||
|
|
375dd50b35 | ||
|
|
419d53ec4c | ||
|
|
d4d70d5675 | ||
|
|
6ab15f8377 | ||
|
|
91f3d51f3d | ||
|
|
9ed60b45f8 | ||
|
|
d5c53dcfd2 | ||
|
|
e94321fb41 | ||
|
|
bbc28b3b1c | ||
|
|
843e981c8a | ||
|
|
5aab274b7a | ||
|
|
2c30e41191 | ||
|
|
8ea5106b0b | ||
|
|
f57f67a8ae | ||
|
|
a98269f049 | ||
|
|
b66bc47ca9 | ||
|
|
0e9c7458bb | ||
|
|
1d89940653 | ||
|
|
1a1a6806ec | ||
|
|
1977df9c2e | ||
|
|
6c95548df5 | ||
|
|
69ab39d658 | ||
|
|
b9eb66eecc | ||
|
|
881087dd3d | ||
|
|
90e0bbd0fc | ||
|
|
b57df290de | ||
|
|
8a403f1241 | ||
|
|
6d2640871d | ||
|
|
c145598ff9 | ||
|
|
50e5608d86 | ||
|
|
7a7b96107c | ||
|
|
500bb68831 | ||
|
|
53eb0f60bc | ||
|
|
41205ae928 | ||
|
|
c33b0ae463 | ||
|
|
16087c9680 | ||
|
|
56bc6d58f6 | ||
|
|
ef5d335e09 | ||
|
|
25c3060fef | ||
|
|
ce9f0b38a4 | ||
|
|
35f7cbf772 | ||
|
|
0db564d261 | ||
|
|
427b7ea104 | ||
|
|
7bf6878b4b | ||
|
|
0bc1a115ff | ||
|
|
334bcfa5ef | ||
|
|
106dea4559 | ||
|
|
3ffdcf8114 | ||
|
|
4021a7eb28 | ||
|
|
0690fda0f1 | ||
|
|
d0cc48c6d3 | ||
|
|
d66e3c949e | ||
|
|
0c65a386b5 | ||
|
|
29f5430881 | ||
|
|
101f285bcd | ||
|
|
286dc6322b | ||
|
|
c9346cd40d | ||
|
|
1c5683ec78 | ||
|
|
9bee155d59 | ||
|
|
f34b05f4de | ||
|
|
97ce25f4ce | ||
|
|
9e14c14a26 | ||
|
|
c507880d8f | ||
|
|
3f8328bbf8 | ||
|
|
c10a5f9ef6 | ||
|
|
3c141de695 | ||
|
|
da2b9455f2 | ||
|
|
cb622488c0 | ||
|
|
32f971fec6 | ||
|
|
8dea76baa4 | ||
|
|
299fbe04c4 | ||
|
|
57fc1df7d7 | ||
|
|
eaba76f9e6 | ||
|
|
cb702cc238 | ||
|
|
b69b4a0a4a | ||
|
|
50d6072a73 | ||
|
|
d24cd50e61 | ||
|
|
9f5875158c | ||
|
|
c3dc33c861 | ||
|
|
6be8f2124c | ||
|
|
edfed06001 | ||
|
|
1c646dba91 | ||
|
|
6781068058 | ||
|
|
cfe57c1dfe | ||
|
|
c34d09a971 | ||
|
|
ebd90c4742 | ||
|
|
ba52d34828 | ||
|
|
1b6312afb3 | ||
|
|
bf32dc2e72 | ||
|
|
a15d65f7a2 | ||
|
|
2de8488855 | ||
|
|
129aa4bfaa | ||
|
|
b1d70db63b | ||
|
|
f03c3aafe4 | ||
|
|
51a9f106d1 | ||
|
|
bfc048e3fe | ||
|
|
83418644f7 | ||
|
|
dbc9dd5bfc | ||
|
|
45ab15d4b5 |
@@ -93,6 +93,7 @@ find_package(OpenSSL REQUIRED)
|
||||
find_package(secp256k1 REQUIRED)
|
||||
find_package(SOCI REQUIRED)
|
||||
find_package(SQLite3 REQUIRED)
|
||||
find_package(wasmi REQUIRED)
|
||||
find_package(xxHash REQUIRED)
|
||||
|
||||
target_link_libraries(
|
||||
|
||||
@@ -67,6 +67,7 @@ target_link_libraries(
|
||||
Xrpl::opts
|
||||
Xrpl::syslibs
|
||||
secp256k1::secp256k1
|
||||
wasmi::wasmi
|
||||
xrpl.libpb
|
||||
xxHash::xxhash
|
||||
$<$<BOOL:${voidstar}>:antithesis-sdk-cpp>
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
"requires": [
|
||||
"zlib/1.3.2#1cb806da49011867778ffb6ac7190fcb%1777558780.503",
|
||||
"xxhash/0.8.3#681d36a0a6111fc56e5e45ea182c19cc%1765850149.987",
|
||||
|
||||
"wasmi/1.0.9#1fecdab9b90c96698eb35ea99ca4f5cb%1772227278.324",
|
||||
"sqlite3/3.53.0#324ada52333108388a9a6108bfa96734%1776096494.149",
|
||||
"soci/4.0.3#fe32b9ad5eb47e79ab9e45a68f363945%1774450067.231",
|
||||
"snappy/1.1.10#968fef506ff261592ec30c574d4a7809%1765850147.878",
|
||||
|
||||
@@ -34,6 +34,7 @@ class Xrpl(ConanFile):
|
||||
"openssl/3.6.2",
|
||||
"secp256k1/0.7.1",
|
||||
"soci/4.0.3",
|
||||
"wasmi/1.0.9",
|
||||
"zlib/1.3.2",
|
||||
]
|
||||
|
||||
@@ -214,6 +215,7 @@ class Xrpl(ConanFile):
|
||||
"soci::soci",
|
||||
"secp256k1::secp256k1",
|
||||
"sqlite3::sqlite",
|
||||
"wasmi::wasmi",
|
||||
"xxhash::xxhash",
|
||||
"zlib::zlib",
|
||||
]
|
||||
|
||||
@@ -7,6 +7,7 @@ ignorePaths:
|
||||
- cmake/**
|
||||
- LICENSE.md
|
||||
- .clang-tidy
|
||||
- src/test/app/wasm_fixtures/*.c
|
||||
language: en
|
||||
allowCompoundWords: true # TODO (#6334)
|
||||
ignoreRandomStrings: true
|
||||
@@ -65,6 +66,7 @@ words:
|
||||
- Btrfs
|
||||
- Buildx
|
||||
- canonicality
|
||||
- cdylib
|
||||
- changespq
|
||||
- checkme
|
||||
- choco
|
||||
@@ -267,6 +269,7 @@ words:
|
||||
- STATSDCOLLECTOR
|
||||
- stissue
|
||||
- stnum
|
||||
- stnumber
|
||||
- stobj
|
||||
- stobject
|
||||
- stpath
|
||||
@@ -326,6 +329,7 @@ words:
|
||||
- wthread
|
||||
- xbridge
|
||||
- xchain
|
||||
- xfloat
|
||||
- ximinez
|
||||
- XMACRO
|
||||
- xrpkuwait
|
||||
|
||||
@@ -251,6 +251,9 @@ constexpr std::uint8_t kVaultMaximumIouScale = 18;
|
||||
* another vault; counted from 0 */
|
||||
constexpr std::uint8_t kMaxAssetCheckDepth = 5;
|
||||
|
||||
/** Maximum length of a Data field in Escrow object that can be updated by WASM code. */
|
||||
constexpr std::size_t kMaxWasmDataLength = 1 * 1024; // 1KB
|
||||
|
||||
/** A ledger index. */
|
||||
using LedgerIndex = std::uint32_t;
|
||||
|
||||
|
||||
@@ -127,7 +127,9 @@ enum TEMcodes : TERUnderlyingType {
|
||||
temARRAY_TOO_LARGE,
|
||||
temBAD_TRANSFER_FEE,
|
||||
temINVALID_INNER_BATCH,
|
||||
|
||||
temBAD_MPT,
|
||||
temBAD_WASM,
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
516
include/xrpl/tx/wasm/HostFunc.h
Normal file
516
include/xrpl/tx/wasm/HostFunc.h
Normal file
@@ -0,0 +1,516 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/basics/Expected.h>
|
||||
#include <xrpl/basics/Slice.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/Asset.h>
|
||||
#include <xrpl/protocol/Keylet.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
#include <xrpl/protocol/UintTypes.h>
|
||||
#include <xrpl/tx/wasm/WasmCommon.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
namespace wasm_float {
|
||||
|
||||
std::string
|
||||
floatToString(Slice const& data);
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatFromIntImpl(int64_t x, int32_t mode);
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatFromUintImpl(uint64_t x, int32_t mode);
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatFromSTAmountImpl(STAmount const& x, int32_t mode);
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatFromSTNumberImpl(STNumber const& x, int32_t mode);
|
||||
|
||||
Expected<int64_t, HostFunctionError>
|
||||
floatToIntImpl(Slice const& x, int32_t mode);
|
||||
|
||||
Expected<FloatPair, HostFunctionError>
|
||||
floatToMantExpImpl(Slice const& x);
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatFromMantExpImpl(int64_t mantissa, int32_t exponent, int32_t mode);
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
floatCompareImpl(Slice const& x, Slice const& y);
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatAddImpl(Slice const& x, Slice const& y, int32_t mode);
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatSubtractImpl(Slice const& x, Slice const& y, int32_t mode);
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatMultiplyImpl(Slice const& x, Slice const& y, int32_t mode);
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatDivideImpl(Slice const& x, Slice const& y, int32_t mode);
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatRootImpl(Slice const& x, int32_t n, int32_t mode);
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatPowerImpl(Slice const& x, int32_t n, int32_t mode);
|
||||
|
||||
} // namespace wasm_float
|
||||
|
||||
// Intended to work only through wasm runtime. Don't call them directly, except with unit tests
|
||||
class HostFunctions
|
||||
{
|
||||
protected:
|
||||
RTOptRef rt_;
|
||||
beast::Journal j_;
|
||||
|
||||
public:
|
||||
HostFunctions(beast::Journal j = beast::Journal{beast::Journal::getNullSink()}) : j_(j)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
setRT(WasmRuntimeWrapper& rt)
|
||||
{
|
||||
rt_ = rt;
|
||||
}
|
||||
|
||||
void
|
||||
resetRT()
|
||||
{
|
||||
rt_ = std::nullopt;
|
||||
}
|
||||
|
||||
[[nodiscard]] WasmRuntimeWrapper&
|
||||
getRT() const
|
||||
{
|
||||
if (!rt_)
|
||||
Throw<std::logic_error>("Wasm runtime not set");
|
||||
return rt_->get();
|
||||
}
|
||||
|
||||
[[nodiscard]] beast::Journal
|
||||
getJournal() const
|
||||
{
|
||||
return j_;
|
||||
}
|
||||
|
||||
// LCOV_EXCL_START
|
||||
|
||||
[[nodiscard]] virtual bool
|
||||
checkSelf() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual Expected<std::uint32_t, HostFunctionError>
|
||||
getLedgerSqn() const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<std::uint32_t, HostFunctionError>
|
||||
getParentLedgerTime() const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<Hash, HostFunctionError>
|
||||
getParentLedgerHash() const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<uint32_t, HostFunctionError>
|
||||
getBaseFee() const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<int32_t, HostFunctionError>
|
||||
isAmendmentEnabled(uint256 const& amendmentId) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<int32_t, HostFunctionError>
|
||||
isAmendmentEnabled(std::string_view const& amendmentName) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<int32_t, HostFunctionError>
|
||||
cacheLedgerObj(uint256 const& objId, int32_t cacheIdx)
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
getTxField(SField const& fname) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
getCurrentLedgerObjField(SField const& fname) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
getLedgerObjField(int32_t cacheIdx, SField const& fname) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
getTxNestedField(FieldLocator const& locator) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
getCurrentLedgerObjNestedField(FieldLocator const& locator) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
getLedgerObjNestedField(int32_t cacheIdx, FieldLocator const& locator) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<int32_t, HostFunctionError>
|
||||
getTxArrayLen(SField const& fname) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<int32_t, HostFunctionError>
|
||||
getCurrentLedgerObjArrayLen(SField const& fname) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<int32_t, HostFunctionError>
|
||||
getLedgerObjArrayLen(int32_t cacheIdx, SField const& fname) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<int32_t, HostFunctionError>
|
||||
getTxNestedArrayLen(FieldLocator const& locator) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<int32_t, HostFunctionError>
|
||||
getCurrentLedgerObjNestedArrayLen(FieldLocator const& locator) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<int32_t, HostFunctionError>
|
||||
getLedgerObjNestedArrayLen(int32_t cacheIdx, FieldLocator const& locator) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<int32_t, HostFunctionError>
|
||||
updateData(Slice const& data)
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<int32_t, HostFunctionError>
|
||||
checkSignature(Slice const& message, Slice const& signature, Slice const& pubkey) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<Hash, HostFunctionError>
|
||||
computeSha512HalfHash(Slice const& data) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
accountKeylet(AccountID const& account) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
ammKeylet(Asset const& issue1, Asset const& issue2) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
checkKeylet(AccountID const& account, std::uint32_t seq) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
credentialKeylet(AccountID const& subject, AccountID const& issuer, Slice const& credentialType)
|
||||
const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
didKeylet(AccountID const& account) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
delegateKeylet(AccountID const& account, AccountID const& authorize) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
depositPreauthKeylet(AccountID const& account, AccountID const& authorize) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
escrowKeylet(AccountID const& account, std::uint32_t seq) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
lineKeylet(AccountID const& account1, AccountID const& account2, Currency const& currency) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
mptIssuanceKeylet(AccountID const& issuer, std::uint32_t seq) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
mptokenKeylet(MPTID const& mptid, AccountID const& holder) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
nftOfferKeylet(AccountID const& account, std::uint32_t seq) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
offerKeylet(AccountID const& account, std::uint32_t seq) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
oracleKeylet(AccountID const& account, std::uint32_t docId) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
paychanKeylet(AccountID const& account, AccountID const& destination, std::uint32_t seq) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
permissionedDomainKeylet(AccountID const& account, std::uint32_t seq) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
signersKeylet(AccountID const& account) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
ticketKeylet(AccountID const& account, std::uint32_t seq) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
vaultKeylet(AccountID const& account, std::uint32_t seq) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
getNFT(AccountID const& account, uint256 const& nftId) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
getNFTIssuer(uint256 const& nftId) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<std::uint32_t, HostFunctionError>
|
||||
getNFTTaxon(uint256 const& nftId) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<int32_t, HostFunctionError>
|
||||
getNFTFlags(uint256 const& nftId) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<int32_t, HostFunctionError>
|
||||
getNFTTransferFee(uint256 const& nftId) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<std::uint32_t, HostFunctionError>
|
||||
getNFTSerial(uint256 const& nftId) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<int32_t, HostFunctionError>
|
||||
trace(std::string_view const& msg, Slice const& data, bool asHex) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<int32_t, HostFunctionError>
|
||||
traceNum(std::string_view const& msg, int64_t data) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<int32_t, HostFunctionError>
|
||||
traceAccount(std::string_view const& msg, AccountID const& account) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<int32_t, HostFunctionError>
|
||||
traceFloat(std::string_view const& msg, Slice const& data) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<int32_t, HostFunctionError>
|
||||
traceAmount(std::string_view const& msg, STAmount const& amount) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
floatFromInt(int64_t x, int32_t mode) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
floatFromUint(uint64_t x, int32_t mode) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
floatFromSTAmount(STAmount const& x, int32_t mode) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
floatFromSTNumber(STNumber const& x, int32_t mode) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<int64_t, HostFunctionError>
|
||||
floatToInt(Slice const& x, int32_t mode) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<FloatPair, HostFunctionError>
|
||||
floatToMantExp(Slice const& x) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
floatFromMantExp(int64_t mantissa, int32_t exponent, int32_t mode) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<int32_t, HostFunctionError>
|
||||
floatCompare(Slice const& x, Slice const& y) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
floatAdd(Slice const& x, Slice const& y, int32_t mode) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
floatSubtract(Slice const& x, Slice const& y, int32_t mode) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
floatMultiply(Slice const& x, Slice const& y, int32_t mode) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
floatDivide(Slice const& x, Slice const& y, int32_t mode) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
floatRoot(Slice const& x, int32_t n, int32_t mode) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
floatPower(Slice const& x, int32_t n, int32_t mode) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
virtual ~HostFunctions() = default;
|
||||
// LCOV_EXCL_STOP
|
||||
};
|
||||
|
||||
using HFRef = std::reference_wrapper<HostFunctions>;
|
||||
|
||||
} // namespace xrpl
|
||||
283
include/xrpl/tx/wasm/HostFuncImpl.h
Normal file
283
include/xrpl/tx/wasm/HostFuncImpl.h
Normal file
@@ -0,0 +1,283 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/tx/ApplyContext.h>
|
||||
#include <xrpl/tx/wasm/HostFunc.h>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
// Intended to work only through wasm runtime. Don't call them directly, except with unit tests
|
||||
class WasmHostFunctionsImpl : public HostFunctions
|
||||
{
|
||||
ApplyContext& ctx_;
|
||||
|
||||
Keylet leKey_;
|
||||
mutable std::optional<std::shared_ptr<SLE const>> currentLedgerObj_;
|
||||
|
||||
static int constexpr maxCache = 256;
|
||||
std::array<std::shared_ptr<SLE const>, maxCache> cache_;
|
||||
|
||||
std::optional<Bytes> data_;
|
||||
|
||||
public:
|
||||
Expected<std::shared_ptr<SLE const>, HostFunctionError>
|
||||
getCurrentLedgerObj() const
|
||||
{
|
||||
if (!currentLedgerObj_)
|
||||
currentLedgerObj_ = ctx_.view().read(leKey_);
|
||||
if (*currentLedgerObj_)
|
||||
return *currentLedgerObj_;
|
||||
return Unexpected(HostFunctionError::LedgerObjNotFound);
|
||||
}
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
normalizeCacheIndex(int32_t cacheIdx) const
|
||||
{
|
||||
--cacheIdx;
|
||||
if (cacheIdx < 0 || cacheIdx >= maxCache)
|
||||
return Unexpected(HostFunctionError::SlotOutRange);
|
||||
if (!cache_[cacheIdx])
|
||||
return Unexpected(HostFunctionError::EmptySlot);
|
||||
return cacheIdx;
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
void
|
||||
log(std::string_view const& msg, F&& dataFn) const
|
||||
{
|
||||
#ifdef DEBUG_OUTPUT
|
||||
auto& j = std::cerr;
|
||||
#else
|
||||
if (!getJournal().active(beast::Severity::Trace))
|
||||
return;
|
||||
auto j = getJournal().trace();
|
||||
#endif
|
||||
j << "WasmTrace[" << toShortString(leKey_.key) << "]: " << msg << " " << dataFn();
|
||||
|
||||
#ifdef DEBUG_OUTPUT
|
||||
j << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
public:
|
||||
WasmHostFunctionsImpl(ApplyContext& ct, Keylet const& leKey)
|
||||
: HostFunctions(ct.journal), ctx_(ct), leKey_(leKey)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
checkSelf() const override
|
||||
{
|
||||
return !currentLedgerObj_ && !data_ &&
|
||||
std::ranges::none_of(cache_, [](auto const& p) { return !!p; });
|
||||
}
|
||||
|
||||
std::optional<Bytes> const&
|
||||
getData() const
|
||||
{
|
||||
return data_;
|
||||
}
|
||||
|
||||
Expected<std::uint32_t, HostFunctionError>
|
||||
getLedgerSqn() const override;
|
||||
|
||||
Expected<std::uint32_t, HostFunctionError>
|
||||
getParentLedgerTime() const override;
|
||||
|
||||
Expected<Hash, HostFunctionError>
|
||||
getParentLedgerHash() const override;
|
||||
|
||||
Expected<std::uint32_t, HostFunctionError>
|
||||
getBaseFee() const override;
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
isAmendmentEnabled(uint256 const& amendmentId) const override;
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
isAmendmentEnabled(std::string_view const& amendmentName) const override;
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
cacheLedgerObj(uint256 const& objId, int32_t cacheIdx) override;
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
getTxField(SField const& fname) const override;
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
getCurrentLedgerObjField(SField const& fname) const override;
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
getLedgerObjField(int32_t cacheIdx, SField const& fname) const override;
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
getTxNestedField(FieldLocator const& locator) const override;
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
getCurrentLedgerObjNestedField(FieldLocator const& locator) const override;
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
getLedgerObjNestedField(int32_t cacheIdx, FieldLocator const& locator) const override;
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
getTxArrayLen(SField const& fname) const override;
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
getCurrentLedgerObjArrayLen(SField const& fname) const override;
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
getLedgerObjArrayLen(int32_t cacheIdx, SField const& fname) const override;
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
getTxNestedArrayLen(FieldLocator const& locator) const override;
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
getCurrentLedgerObjNestedArrayLen(FieldLocator const& locator) const override;
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
getLedgerObjNestedArrayLen(int32_t cacheIdx, FieldLocator const& locator) const override;
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
updateData(Slice const& data) override;
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
checkSignature(Slice const& message, Slice const& signature, Slice const& pubkey)
|
||||
const override;
|
||||
|
||||
Expected<Hash, HostFunctionError>
|
||||
computeSha512HalfHash(Slice const& data) const override;
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
accountKeylet(AccountID const& account) const override;
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
ammKeylet(Asset const& issue1, Asset const& issue2) const override;
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
checkKeylet(AccountID const& account, std::uint32_t seq) const override;
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
credentialKeylet(AccountID const& subject, AccountID const& issuer, Slice const& credentialType)
|
||||
const override;
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
didKeylet(AccountID const& account) const override;
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
delegateKeylet(AccountID const& account, AccountID const& authorize) const override;
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
depositPreauthKeylet(AccountID const& account, AccountID const& authorize) const override;
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
escrowKeylet(AccountID const& account, std::uint32_t seq) const override;
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
lineKeylet(AccountID const& account1, AccountID const& account2, Currency const& currency)
|
||||
const override;
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
mptIssuanceKeylet(AccountID const& issuer, std::uint32_t seq) const override;
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
mptokenKeylet(MPTID const& mptid, AccountID const& holder) const override;
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
nftOfferKeylet(AccountID const& account, std::uint32_t seq) const override;
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
offerKeylet(AccountID const& account, std::uint32_t seq) const override;
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
oracleKeylet(AccountID const& account, std::uint32_t docId) const override;
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
paychanKeylet(AccountID const& account, AccountID const& destination, std::uint32_t seq)
|
||||
const override;
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
permissionedDomainKeylet(AccountID const& account, std::uint32_t seq) const override;
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
signersKeylet(AccountID const& account) const override;
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
ticketKeylet(AccountID const& account, std::uint32_t seq) const override;
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
vaultKeylet(AccountID const& account, std::uint32_t seq) const override;
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
getNFT(AccountID const& account, uint256 const& nftId) const override;
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
getNFTIssuer(uint256 const& nftId) const override;
|
||||
|
||||
Expected<std::uint32_t, HostFunctionError>
|
||||
getNFTTaxon(uint256 const& nftId) const override;
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
getNFTFlags(uint256 const& nftId) const override;
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
getNFTTransferFee(uint256 const& nftId) const override;
|
||||
|
||||
Expected<std::uint32_t, HostFunctionError>
|
||||
getNFTSerial(uint256 const& nftId) const override;
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
trace(std::string_view const& msg, Slice const& data, bool asHex) const override;
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
traceNum(std::string_view const& msg, int64_t data) const override;
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
traceAccount(std::string_view const& msg, AccountID const& account) const override;
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
traceFloat(std::string_view const& msg, Slice const& data) const override;
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
traceAmount(std::string_view const& msg, STAmount const& amount) const override;
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatFromInt(int64_t x, int32_t mode) const override;
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatFromUint(uint64_t x, int32_t mode) const override;
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatFromSTAmount(STAmount const& x, int32_t mode) const override;
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatFromSTNumber(STNumber const& x, int32_t mode) const override;
|
||||
|
||||
Expected<int64_t, HostFunctionError>
|
||||
floatToInt(Slice const& x, int32_t mode) const override;
|
||||
|
||||
Expected<FloatPair, HostFunctionError>
|
||||
floatToMantExp(Slice const& x) const override;
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatFromMantExp(int64_t mantissa, int32_t exponent, int32_t mode) const override;
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
floatCompare(Slice const& x, Slice const& y) const override;
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatAdd(Slice const& x, Slice const& y, int32_t mode) const override;
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatSubtract(Slice const& x, Slice const& y, int32_t mode) const override;
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatMultiply(Slice const& x, Slice const& y, int32_t mode) const override;
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatDivide(Slice const& x, Slice const& y, int32_t mode) const override;
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatRoot(Slice const& x, int32_t n, int32_t mode) const override;
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatPower(Slice const& x, int32_t n, int32_t mode) const override;
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
254
include/xrpl/tx/wasm/HostFuncWrapper.h
Normal file
254
include/xrpl/tx/wasm/HostFuncWrapper.h
Normal file
@@ -0,0 +1,254 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/tx/wasm/WasmImportsHelper.h>
|
||||
|
||||
#include <wasm.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
#define WASM_CB_PARAMS_LIST void *env, wasm_val_vec_t const *params, wasm_val_vec_t *results
|
||||
#define WASM_SECONDARY_CB_PARAMS_LIST \
|
||||
HostFunctions &hf, wasm_val_vec_t const *params, wasm_val_vec_t *results
|
||||
|
||||
wasm_trap_t* HostFuncMain_wrap(WASM_CB_PARAMS_LIST);
|
||||
|
||||
using getLedgerSqn_proto = int32_t(uint8_t*, int32_t);
|
||||
wasm_trap_t* getLedgerSqn_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using getParentLedgerTime_proto = int32_t(uint8_t*, int32_t);
|
||||
wasm_trap_t* getParentLedgerTime_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using getParentLedgerHash_proto = int32_t(uint8_t*, int32_t);
|
||||
wasm_trap_t* getParentLedgerHash_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using getBaseFee_proto = int32_t(uint8_t*, int32_t);
|
||||
wasm_trap_t* getBaseFee_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using isAmendmentEnabled_proto = int32_t(uint8_t const*, int32_t);
|
||||
wasm_trap_t* isAmendmentEnabled_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using cacheLedgerObj_proto = int32_t(uint8_t const*, int32_t, int32_t);
|
||||
wasm_trap_t* cacheLedgerObj_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using getTxField_proto = int32_t(int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* getTxField_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using getCurrentLedgerObjField_proto = int32_t(int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* getCurrentLedgerObjField_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using getLedgerObjField_proto = int32_t(int32_t, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* getLedgerObjField_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using getTxNestedField_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* getTxNestedField_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using getCurrentLedgerObjNestedField_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* getCurrentLedgerObjNestedField_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using getLedgerObjNestedField_proto = int32_t(int32_t, uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* getLedgerObjNestedField_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using getTxArrayLen_proto = int32_t(int32_t);
|
||||
wasm_trap_t* getTxArrayLen_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using getCurrentLedgerObjArrayLen_proto = int32_t(int32_t);
|
||||
wasm_trap_t* getCurrentLedgerObjArrayLen_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using getLedgerObjArrayLen_proto = int32_t(int32_t, int32_t);
|
||||
wasm_trap_t* getLedgerObjArrayLen_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using getTxNestedArrayLen_proto = int32_t(uint8_t const*, int32_t);
|
||||
wasm_trap_t* getTxNestedArrayLen_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using getCurrentLedgerObjNestedArrayLen_proto = int32_t(uint8_t const*, int32_t);
|
||||
wasm_trap_t* getCurrentLedgerObjNestedArrayLen_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using getLedgerObjNestedArrayLen_proto = int32_t(int32_t, uint8_t const*, int32_t);
|
||||
wasm_trap_t* getLedgerObjNestedArrayLen_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using updateData_proto = int32_t(uint8_t const*, int32_t);
|
||||
wasm_trap_t* updateData_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using checkSignature_proto =
|
||||
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t const*, int32_t);
|
||||
wasm_trap_t* checkSignature_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using computeSha512HalfHash_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* computeSha512HalfHash_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using accountKeylet_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* accountKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using ammKeylet_proto =
|
||||
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* ammKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using checkKeylet_proto =
|
||||
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* checkKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using credentialKeylet_proto = int32_t(
|
||||
uint8_t const*,
|
||||
int32_t,
|
||||
uint8_t const*,
|
||||
int32_t,
|
||||
uint8_t const*,
|
||||
int32_t,
|
||||
uint8_t*,
|
||||
int32_t);
|
||||
wasm_trap_t* credentialKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using delegateKeylet_proto =
|
||||
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* delegateKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using depositPreauthKeylet_proto =
|
||||
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* depositPreauthKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using didKeylet_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* didKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using escrowKeylet_proto =
|
||||
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* escrowKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using lineKeylet_proto = int32_t(
|
||||
uint8_t const*,
|
||||
int32_t,
|
||||
uint8_t const*,
|
||||
int32_t,
|
||||
uint8_t const*,
|
||||
int32_t,
|
||||
uint8_t*,
|
||||
int32_t);
|
||||
wasm_trap_t* lineKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using mptIssuanceKeylet_proto =
|
||||
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* mptIssuanceKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using mptokenKeylet_proto =
|
||||
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* mptokenKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using nftOfferKeylet_proto =
|
||||
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* nftOfferKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using offerKeylet_proto =
|
||||
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* offerKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using oracleKeylet_proto =
|
||||
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* oracleKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using paychanKeylet_proto = int32_t(
|
||||
uint8_t const*,
|
||||
int32_t,
|
||||
uint8_t const*,
|
||||
int32_t,
|
||||
uint8_t const*,
|
||||
int32_t,
|
||||
uint8_t*,
|
||||
int32_t);
|
||||
wasm_trap_t* paychanKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using permissionedDomainKeylet_proto =
|
||||
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* permissionedDomainKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using signersKeylet_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* signersKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using ticketKeylet_proto =
|
||||
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* ticketKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using vaultKeylet_proto =
|
||||
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* vaultKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using getNFT_proto = int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* getNFT_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using getNFTIssuer_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* getNFTIssuer_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using getNFTTaxon_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* getNFTTaxon_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using getNFTFlags_proto = int32_t(uint8_t const*, int32_t);
|
||||
wasm_trap_t* getNFTFlags_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using getNFTTransferFee_proto = int32_t(uint8_t const*, int32_t);
|
||||
wasm_trap_t* getNFTTransferFee_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using getNFTSerial_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* getNFTSerial_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using trace_proto = int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, int32_t);
|
||||
wasm_trap_t* trace_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using traceNum_proto = int32_t(uint8_t const*, int32_t, int64_t);
|
||||
wasm_trap_t* traceNum_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using traceAccount_proto = int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t);
|
||||
wasm_trap_t* traceAccount_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using traceFloat_proto = int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t);
|
||||
wasm_trap_t* traceFloat_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using traceAmount_proto = int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t);
|
||||
wasm_trap_t* traceAmount_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using floatFromInt_proto = int32_t(int64_t, uint8_t*, int32_t, int32_t);
|
||||
wasm_trap_t* floatFromInt_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using floatFromUint_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t, int32_t);
|
||||
wasm_trap_t* floatFromUint_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using floatFromSTAmount_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t, int32_t);
|
||||
wasm_trap_t* floatFromSTAmount_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using floatFromSTNumber_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t, int32_t);
|
||||
wasm_trap_t* floatFromSTNumber_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using floatToInt_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t, int32_t);
|
||||
wasm_trap_t* floatToInt_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using floatToMantExp_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* floatToMantExp_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using floatFromMantExp_proto = int32_t(int64_t, int32_t, uint8_t*, int32_t, int32_t);
|
||||
wasm_trap_t* floatFromMantExp_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using floatCompare_proto = int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t);
|
||||
wasm_trap_t* floatCompare_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using floatAdd_proto =
|
||||
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t, int32_t);
|
||||
wasm_trap_t* floatAdd_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using floatSubtract_proto =
|
||||
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t, int32_t);
|
||||
wasm_trap_t* floatSubtract_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using floatMultiply_proto =
|
||||
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t, int32_t);
|
||||
wasm_trap_t* floatMultiply_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using floatDivide_proto =
|
||||
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t, int32_t);
|
||||
wasm_trap_t* floatDivide_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using floatRoot_proto = int32_t(uint8_t const*, int32_t, int32_t, uint8_t*, int32_t, int32_t);
|
||||
wasm_trap_t* floatRoot_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using floatPower_proto = int32_t(uint8_t const*, int32_t, int32_t, uint8_t*, int32_t, int32_t);
|
||||
wasm_trap_t* floatPower_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
} // namespace xrpl
|
||||
189
include/xrpl/tx/wasm/README.md
Normal file
189
include/xrpl/tx/wasm/README.md
Normal file
@@ -0,0 +1,189 @@
|
||||
# WASM Module for Programmable Escrows
|
||||
|
||||
This module provides WebAssembly (WASM) execution capabilities for programmable
|
||||
escrows on the XRP Ledger. When an escrow is finished, the WASM code runs to
|
||||
determine whether the escrow conditions are met, enabling custom programmable
|
||||
logic for escrow release conditions.
|
||||
|
||||
For the full specification, see
|
||||
[XLS-0102: WASM VM](https://xls.xrpl.org/xls/XLS-0102-wasm-vm.html).
|
||||
|
||||
## Architecture
|
||||
|
||||
The module follows a layered architecture:
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ WasmEngine (WasmVM.h) │
|
||||
│ runEscrowWasm(), preflightEscrowWasm() │
|
||||
│ Host function registration │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ WasmiEngine (WasmiVM.h) │
|
||||
│ Low-level wasmi interpreter integration │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ HostFuncWrapper │ HostFuncImpl │
|
||||
│ C-style WASM bridges │ C++ implementations │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ HostFunc (Interface) │
|
||||
│ Abstract base class for host functions │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Key Components
|
||||
|
||||
- **`WasmVM.h` / `detail/WasmVM.cpp`** - High-level facade providing:
|
||||
- `WasmEngine` singleton that wraps the underlying WASM interpreter
|
||||
- `runEscrowWasm()` - Execute WASM code for escrow finish
|
||||
- `preflightEscrowWasm()` - Validate WASM code during preflight
|
||||
- `createWasmImport()` - Register all host functions
|
||||
|
||||
- **`WasmiVM.h` / `detail/WasmiVM.cpp`** - Low-level integration with the
|
||||
[wasmi](https://github.com/wasmi-labs/wasmi) WebAssembly interpreter:
|
||||
- `WasmiEngine` - Manages WASM modules, instances, and execution
|
||||
- Memory management and gas metering
|
||||
- Function invocation and result handling
|
||||
|
||||
- **`HostFunc.h`** - Abstract `HostFunctions` base class defining the interface
|
||||
for all callable host functions. Each method returns
|
||||
`Expected<T, HostFunctionError>`.
|
||||
|
||||
- **`HostFuncImpl.h` / `detail/HostFuncImpl*.cpp`** - Concrete
|
||||
`WasmHostFunctionsImpl` class that implements host functions with access to
|
||||
`ApplyContext` for ledger state queries. Implementation split across files:
|
||||
- `HostFuncImpl.cpp` - Core utilities (updateData, checkSignature, etc.)
|
||||
- `HostFuncImplFloat.cpp` - Float/number arithmetic operations
|
||||
- `HostFuncImplGetter.cpp` - Field access (transaction, ledger objects)
|
||||
- `HostFuncImplKeylet.cpp` - Keylet construction functions
|
||||
- `HostFuncImplLedgerHeader.cpp` - Ledger header info access
|
||||
- `HostFuncImplNFT.cpp` - NFT-related queries
|
||||
- `HostFuncImplTrace.cpp` - Debugging/tracing functions
|
||||
|
||||
- **`HostFuncWrapper.h` / `detail/HostFuncWrapper.cpp`** - C-style wrapper
|
||||
functions that bridge WASM calls to C++ `HostFunctions` methods. Each host
|
||||
function has:
|
||||
- A `_proto` type alias defining the function signature
|
||||
- A `_wrap` function that extracts parameters and calls the implementation
|
||||
|
||||
- **`ParamsHelper.h`** - Utilities for WASM parameter handling:
|
||||
- `WASM_IMPORT_FUNC` / `WASM_IMPORT_FUNC2` macros for registration
|
||||
- `wasmParams()` helper for building parameter vectors
|
||||
- Type conversion between WASM and C++ types
|
||||
|
||||
## Host Functions
|
||||
|
||||
Host functions allow WASM code to interact with the XRP Ledger. They are
|
||||
organized into categories:
|
||||
|
||||
- **Ledger Information** - Access ledger sequence, timestamps, hashes, fees
|
||||
- **Transaction & Ledger Object Access** - Read fields from the transaction
|
||||
and ledger objects (including the current escrow object)
|
||||
- **Keylet Construction** - Build keylets to look up various ledger object types
|
||||
- **Cryptography** - Signature verification and hashing
|
||||
- **Float Arithmetic** - Mathematical operations for amount calculations
|
||||
- **NFT Operations** - Query NFT properties
|
||||
- **Tracing/Debugging** - Log messages for debugging
|
||||
|
||||
For the complete list of available host functions, their WASM names, and gas
|
||||
costs, see the [XLS-0102 specification](https://xls.xrpl.org/xls/XLS-0102-wasm-vm.html)
|
||||
or `detail/WasmVM.cpp` where they are registered via `WASM_IMPORT_FUNC2` macros.
|
||||
For method signatures, see `HostFunc.h`.
|
||||
|
||||
## Gas Model
|
||||
|
||||
Each host function has an associated gas cost. The gas cost is specified when
|
||||
registering the function in `detail/WasmVM.cpp`:
|
||||
|
||||
```cpp
|
||||
WASM_IMPORT_FUNC2(i, getLedgerSqn, "get_ledger_sqn", hfs, 60);
|
||||
// ^^ gas cost
|
||||
```
|
||||
|
||||
WASM execution is metered, and if the gas limit is exceeded, execution fails.
|
||||
|
||||
## Entry Point
|
||||
|
||||
The WASM module must export a function with the name defined by
|
||||
`ESCROW_FUNCTION_NAME` (currently `"finish"`). This function:
|
||||
|
||||
- Takes no parameters (or parameters passed via host function calls)
|
||||
- Returns an `int32_t`:
|
||||
- `1` (or positive): Escrow conditions are met, allow finish
|
||||
- `0` (or negative): Escrow conditions are not met, reject finish
|
||||
|
||||
## Adding a New Host Function
|
||||
|
||||
To add a new host function, follow these steps:
|
||||
|
||||
### 1. Add to HostFunc.h (Base Class)
|
||||
|
||||
Add a virtual method declaration with a default implementation that returns an
|
||||
error:
|
||||
|
||||
```cpp
|
||||
virtual Expected<ReturnType, HostFunctionError>
|
||||
myNewFunction(ParamType1 param1, ParamType2 param2)
|
||||
{
|
||||
return Unexpected(HostFunctionError::INTERNAL);
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Add to HostFuncImpl.h (Declaration)
|
||||
|
||||
Add the method override declaration in `WasmHostFunctionsImpl`:
|
||||
|
||||
```cpp
|
||||
Expected<ReturnType, HostFunctionError>
|
||||
myNewFunction(ParamType1 param1, ParamType2 param2) override;
|
||||
```
|
||||
|
||||
### 3. Implement in detail/HostFuncImpl\*.cpp
|
||||
|
||||
Add the implementation in the appropriate file:
|
||||
|
||||
```cpp
|
||||
Expected<ReturnType, HostFunctionError>
|
||||
WasmHostFunctionsImpl::myNewFunction(ParamType1 param1, ParamType2 param2)
|
||||
{
|
||||
// Implementation using ctx (ApplyContext) for ledger access
|
||||
return result;
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Add Wrapper to HostFuncWrapper.h
|
||||
|
||||
Add the prototype and wrapper declaration:
|
||||
|
||||
```cpp
|
||||
using myNewFunction_proto = int32_t(uint8_t const*, int32_t, ...);
|
||||
wasm_trap_t*
|
||||
myNewFunction_wrap(void* env, wasm_val_vec_t const* params, wasm_val_vec_t* results);
|
||||
```
|
||||
|
||||
### 5. Implement Wrapper in detail/HostFuncWrapper.cpp
|
||||
|
||||
Implement the C-style wrapper that bridges WASM to C++:
|
||||
|
||||
```cpp
|
||||
wasm_trap_t*
|
||||
myNewFunction_wrap(void* env, wasm_val_vec_t const* params, wasm_val_vec_t* results)
|
||||
{
|
||||
// Extract parameters from params
|
||||
// Call hfs->myNewFunction(...)
|
||||
// Set results and return
|
||||
}
|
||||
```
|
||||
|
||||
### 6. Register in WasmVM.cpp
|
||||
|
||||
Add the function registration in `setCommonHostFunctions()` or
|
||||
`createWasmImport()`:
|
||||
|
||||
```cpp
|
||||
WASM_IMPORT_FUNC2(i, myNewFunction, "my_new_function", hfs, 100);
|
||||
// ^^ WASM name ^^ gas cost
|
||||
```
|
||||
|
||||
> [!IMPORTANT]
|
||||
> New host functions MUST be amendment-gated in `WasmVM.cpp`.
|
||||
> Wrap the registration in an amendment check to ensure the function is only
|
||||
> available after the corresponding amendment is enabled on the network.
|
||||
211
include/xrpl/tx/wasm/WasmCommon.h
Normal file
211
include/xrpl/tx/wasm/WasmCommon.h
Normal file
@@ -0,0 +1,211 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/basics/contract.h>
|
||||
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
using Bytes = std::vector<std::uint8_t>;
|
||||
using Hash = xrpl::uint256;
|
||||
using FloatPair = std::pair<int64_t, int32_t>;
|
||||
|
||||
enum class HostFunctionError : int32_t {
|
||||
Internal = -1,
|
||||
FieldNotFound = -2,
|
||||
BufferTooSmall = -3,
|
||||
NoArray = -4,
|
||||
NotLeafField = -5,
|
||||
LocatorMalformed = -6,
|
||||
SlotOutRange = -7,
|
||||
SlotsFull = -8,
|
||||
EmptySlot = -9,
|
||||
LedgerObjNotFound = -10,
|
||||
Decoding = -11,
|
||||
DataFieldTooLarge = -12,
|
||||
PointerOutOfBounds = -13,
|
||||
NoMemExported = -14,
|
||||
InvalidParams = -15,
|
||||
InvalidAccount = -16,
|
||||
InvalidField = -17,
|
||||
IndexOutOfBounds = -18,
|
||||
FloatInputMalformed = -19,
|
||||
FloatComputationError = -20,
|
||||
NoRuntime = -21,
|
||||
OutOfGas = -22,
|
||||
OutOfTransferLimit = -23,
|
||||
};
|
||||
|
||||
enum class WasmTypes { WtI32, WtI64 };
|
||||
|
||||
struct Wmem
|
||||
{
|
||||
std::uint8_t* p = nullptr;
|
||||
std::size_t s = 0;
|
||||
|
||||
Wmem() = default;
|
||||
Wmem(void* ptr, std::size_t size) : p(reinterpret_cast<std::uint8_t*>(ptr)), s(size)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct WasmResult
|
||||
{
|
||||
T result;
|
||||
int64_t cost;
|
||||
};
|
||||
using EscrowResult = WasmResult<int32_t>;
|
||||
|
||||
class FieldLocator
|
||||
{
|
||||
int32_t const* ptr_ = nullptr;
|
||||
uint32_t size_ = 0;
|
||||
std::vector<int32_t> buf_;
|
||||
|
||||
public:
|
||||
FieldLocator(std::vector<int32_t>&& buf)
|
||||
: ptr_(&buf[0]), size_(buf.size()), buf_(std::move(buf))
|
||||
{
|
||||
}
|
||||
|
||||
FieldLocator(int32_t const* ptr, uint32_t const size) : ptr_(ptr), size_(size)
|
||||
{
|
||||
}
|
||||
|
||||
FieldLocator(FieldLocator const&) = delete;
|
||||
FieldLocator&
|
||||
operator=(FieldLocator const&) = delete;
|
||||
FieldLocator(FieldLocator&&) = default;
|
||||
FieldLocator&
|
||||
operator=(FieldLocator&&) = default;
|
||||
|
||||
int32_t
|
||||
operator[](unsigned i) const
|
||||
{
|
||||
if (i >= size_)
|
||||
Throw<std::runtime_error>("index out of bounds");
|
||||
return ptr_[i];
|
||||
}
|
||||
|
||||
[[nodiscard]] uint32_t
|
||||
size() const
|
||||
{
|
||||
return size_;
|
||||
}
|
||||
|
||||
[[nodiscard]] int32_t const*
|
||||
data() const
|
||||
{
|
||||
return ptr_;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool
|
||||
empty() const
|
||||
{
|
||||
return size_ == 0;
|
||||
}
|
||||
};
|
||||
|
||||
class WasmRuntimeWrapper
|
||||
{
|
||||
public:
|
||||
virtual ~WasmRuntimeWrapper() = default;
|
||||
|
||||
virtual Wmem
|
||||
getMem() = 0;
|
||||
|
||||
virtual std::int64_t
|
||||
getGas() = 0;
|
||||
|
||||
virtual std::int64_t
|
||||
setGas(std::int64_t gas) = 0;
|
||||
};
|
||||
using RTOptRef = std::optional<std::reference_wrapper<WasmRuntimeWrapper>>;
|
||||
|
||||
struct WasmParam
|
||||
{
|
||||
// We are not supporting float/double
|
||||
|
||||
WasmTypes type = WasmTypes::WtI32;
|
||||
union
|
||||
{
|
||||
std::int32_t i32;
|
||||
std::int64_t i64 = 0;
|
||||
} of;
|
||||
};
|
||||
|
||||
template <class... Types>
|
||||
inline void
|
||||
wasmParamsHlp(std::vector<WasmParam>& v, std::int32_t p, Types&&... args)
|
||||
{
|
||||
v.push_back({.type = WasmTypes::WtI32, .of = {.i32 = p}});
|
||||
wasmParamsHlp(v, std::forward<Types>(args)...);
|
||||
}
|
||||
|
||||
template <class... Types>
|
||||
inline void
|
||||
wasmParamsHlp(std::vector<WasmParam>& v, std::int64_t p, Types&&... args)
|
||||
{
|
||||
v.push_back({.type = WasmTypes::WtI64, .of = {.i64 = p}});
|
||||
wasmParamsHlp(v, std::forward<Types>(args)...);
|
||||
}
|
||||
|
||||
inline void
|
||||
wasmParamsHlp(std::vector<WasmParam>& v)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
template <class... Types>
|
||||
inline std::vector<WasmParam>
|
||||
wasmParams(Types&&... args)
|
||||
{
|
||||
std::vector<WasmParam> v;
|
||||
v.reserve(sizeof...(args));
|
||||
wasmParamsHlp(v, std::forward<Types>(args)...);
|
||||
return v;
|
||||
}
|
||||
|
||||
template <typename T, size_t Size = sizeof(T)>
|
||||
constexpr T
|
||||
adjustWasmEndianessHlp(T x)
|
||||
{
|
||||
static_assert(std::is_integral_v<T>, "Only integral types");
|
||||
if constexpr (Size > 1)
|
||||
{
|
||||
using U = std::make_unsigned_t<T>;
|
||||
U u = static_cast<U>(x);
|
||||
U const low = (u & 0xFF) << ((Size - 1) << 3);
|
||||
u = adjustWasmEndianessHlp<U, Size - 1>(u >> 8);
|
||||
return static_cast<T>(low | u);
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
template <typename T, size_t Size = sizeof(T)>
|
||||
constexpr T
|
||||
adjustWasmEndianess(T x)
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
static_assert(std::is_integral_v<T>, "Only integral types");
|
||||
if constexpr (std::endian::native == std::endian::big)
|
||||
{
|
||||
return adjustWasmEndianessHlp(x);
|
||||
}
|
||||
return x;
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
constexpr int32_t
|
||||
hfErrorToInt(HostFunctionError e)
|
||||
{
|
||||
return static_cast<int32_t>(e);
|
||||
}
|
||||
|
||||
} // namespace xrpl
|
||||
128
include/xrpl/tx/wasm/WasmImportsHelper.h
Normal file
128
include/xrpl/tx/wasm/WasmImportsHelper.h
Normal file
@@ -0,0 +1,128 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/tx/wasm/HostFunc.h>
|
||||
|
||||
#include <boost/function_types/function_arity.hpp>
|
||||
#include <boost/function_types/parameter_types.hpp>
|
||||
#include <boost/function_types/result_type.hpp>
|
||||
#include <boost/mpl/vector.hpp>
|
||||
|
||||
#include <wasm.h>
|
||||
|
||||
namespace bft = boost::function_types;
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
using wasmSecondaryCbFuncType =
|
||||
wasm_trap_t*(HostFunctions&, wasm_val_vec_t const*, wasm_val_vec_t*);
|
||||
|
||||
struct WasmImportFunc
|
||||
{
|
||||
std::string_view name;
|
||||
std::optional<WasmTypes> result;
|
||||
std::vector<WasmTypes> params;
|
||||
|
||||
wasmSecondaryCbFuncType* wrap = nullptr;
|
||||
uint32_t gas = 0;
|
||||
};
|
||||
|
||||
using WasmUserData = std::pair<HFRef, WasmImportFunc>;
|
||||
// string - import function name
|
||||
using ImportVec = std::unordered_map<std::string_view, WasmUserData>;
|
||||
|
||||
template <int N, int C, typename Mpl>
|
||||
void
|
||||
WasmImpArgs(WasmImportFunc& e)
|
||||
{
|
||||
if constexpr (N < C)
|
||||
{
|
||||
using at = typename boost::mpl::at_c<Mpl, N>::type;
|
||||
if constexpr (std::is_pointer_v<at>)
|
||||
{
|
||||
e.params.push_back(WasmTypes::WtI32);
|
||||
}
|
||||
else if constexpr (std::is_same_v<at, std::int32_t>)
|
||||
{
|
||||
e.params.push_back(WasmTypes::WtI32);
|
||||
}
|
||||
else if constexpr (std::is_same_v<at, std::int64_t>)
|
||||
{
|
||||
e.params.push_back(WasmTypes::WtI64);
|
||||
}
|
||||
else
|
||||
{
|
||||
static_assert(std::is_pointer_v<at>, "Unsupported argument type");
|
||||
}
|
||||
|
||||
return WasmImpArgs<N + 1, C, Mpl>(e);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
template <typename>
|
||||
inline constexpr bool wasmDependentFalse = false;
|
||||
|
||||
template <typename Rt>
|
||||
void
|
||||
WasmImpRet(WasmImportFunc& e)
|
||||
{
|
||||
if constexpr (std::is_pointer_v<Rt>)
|
||||
{
|
||||
e.result = WasmTypes::WtI32;
|
||||
}
|
||||
else if constexpr (std::is_same_v<Rt, std::int32_t>)
|
||||
{
|
||||
e.result = WasmTypes::WtI32;
|
||||
}
|
||||
else if constexpr (std::is_same_v<Rt, std::int64_t>)
|
||||
{
|
||||
e.result = WasmTypes::WtI64;
|
||||
}
|
||||
else if constexpr (std::is_void_v<Rt>)
|
||||
{
|
||||
e.result.reset();
|
||||
}
|
||||
else
|
||||
{
|
||||
static_assert(wasmDependentFalse<Rt>, "Unsupported return type");
|
||||
}
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
void
|
||||
WasmImpFuncHelper(WasmImportFunc& e)
|
||||
{
|
||||
using rt = typename bft::result_type<F>::type;
|
||||
using pt = typename bft::parameter_types<F>::type;
|
||||
// typename boost::mpl::at_c<mpl, N>::type
|
||||
|
||||
WasmImpRet<rt>(e);
|
||||
WasmImpArgs<0, bft::function_arity<F>::value, pt>(e);
|
||||
// WasmImpWrap(e, std::forward<F>(f));
|
||||
}
|
||||
|
||||
// imp_name - string literal, must have static lifetime
|
||||
template <typename F>
|
||||
void
|
||||
WasmImpFunc(
|
||||
ImportVec& v,
|
||||
std::string_view impName,
|
||||
wasmSecondaryCbFuncType* fWrap,
|
||||
HostFunctions& hf,
|
||||
uint32_t gas = 0)
|
||||
{
|
||||
WasmImportFunc e;
|
||||
e.name = impName;
|
||||
e.wrap = fWrap;
|
||||
e.gas = gas;
|
||||
WasmImpFuncHelper<F>(e);
|
||||
v.emplace(impName, std::make_pair(HFRef(hf), std::move(e)));
|
||||
}
|
||||
|
||||
#define WASM_IMPORT_FUNC(v, f, ...) WasmImpFunc<f##_proto>(v, #f, &f##_wrap, ##__VA_ARGS__)
|
||||
|
||||
// n - string literal name, must have static lifetime
|
||||
#define WASM_IMPORT_FUNC2(v, f, n, ...) WasmImpFunc<f##_proto>(v, n, &f##_wrap, ##__VA_ARGS__)
|
||||
|
||||
} // namespace xrpl
|
||||
89
include/xrpl/tx/wasm/WasmVM.h
Normal file
89
include/xrpl/tx/wasm/WasmVM.h
Normal file
@@ -0,0 +1,89 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/tx/wasm/HostFunc.h>
|
||||
#include <xrpl/tx/wasm/WasmImportsHelper.h>
|
||||
|
||||
#include <string_view>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
std::string_view inline constexpr wEnv = "env";
|
||||
std::string_view inline constexpr wHostLib = "host_lib";
|
||||
std::string_view inline constexpr wMem = "memory";
|
||||
std::string_view inline constexpr wStore = "store";
|
||||
std::string_view inline constexpr wLoad = "load";
|
||||
std::string_view inline constexpr wSize = "size";
|
||||
std::string_view inline constexpr wAlloc = "allocate";
|
||||
std::string_view inline constexpr wDealloc = "deallocate";
|
||||
std::string_view inline constexpr wProcExit = "proc_exit";
|
||||
|
||||
std::string_view inline constexpr escrowFunctionName = "finish";
|
||||
|
||||
uint32_t inline constexpr maxPages = 128; // 8MB = 64KB*128
|
||||
|
||||
class WasmiEngine;
|
||||
|
||||
class WasmEngine
|
||||
{
|
||||
std::unique_ptr<WasmiEngine> const impl_;
|
||||
|
||||
WasmEngine();
|
||||
|
||||
public:
|
||||
WasmEngine(WasmEngine const&) = delete;
|
||||
WasmEngine(WasmEngine&&) = delete;
|
||||
WasmEngine&
|
||||
operator=(WasmEngine const&) = delete;
|
||||
WasmEngine&
|
||||
operator=(WasmEngine&&) = delete;
|
||||
|
||||
static WasmEngine&
|
||||
instance();
|
||||
|
||||
Expected<WasmResult<int32_t>, TER>
|
||||
run(Bytes const& wasmCode,
|
||||
HostFunctions& hfs,
|
||||
int64_t gasLimit,
|
||||
std::string_view funcName = {},
|
||||
std::vector<WasmParam> const& params = {},
|
||||
ImportVec const& imports = {},
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()});
|
||||
|
||||
NotTEC
|
||||
check(
|
||||
Bytes const& wasmCode,
|
||||
HostFunctions& hfs,
|
||||
std::string_view funcName,
|
||||
std::vector<WasmParam> const& params = {},
|
||||
ImportVec const& imports = {},
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()});
|
||||
|
||||
// Host functions helper functionality
|
||||
void*
|
||||
newTrap(std::string const& txt = std::string());
|
||||
|
||||
[[nodiscard]] beast::Journal
|
||||
getJournal() const;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ImportVec
|
||||
createWasmImport(HostFunctions& hfs);
|
||||
|
||||
Expected<EscrowResult, TER>
|
||||
runEscrowWasm(
|
||||
Bytes const& wasmCode,
|
||||
HostFunctions& hfs,
|
||||
int64_t gasLimit,
|
||||
std::string_view funcName = escrowFunctionName,
|
||||
std::vector<WasmParam> const& params = {});
|
||||
|
||||
NotTEC
|
||||
preflightEscrowWasm(
|
||||
Bytes const& wasmCode,
|
||||
HostFunctions& hfs,
|
||||
std::string_view funcName = escrowFunctionName,
|
||||
std::vector<WasmParam> const& params = {});
|
||||
|
||||
} // namespace xrpl
|
||||
434
include/xrpl/tx/wasm/WasmiVM.h
Normal file
434
include/xrpl/tx/wasm/WasmiVM.h
Normal file
@@ -0,0 +1,434 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/protocol/Protocol.h>
|
||||
#include <xrpl/tx/wasm/WasmVM.h>
|
||||
|
||||
#include <wasm.h>
|
||||
#include <wasmi.h>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
template <class T, void (*Create)(T*, size_t), void (*Destroy)(T*)>
|
||||
class WasmVec
|
||||
{
|
||||
using TD = std::remove_pointer_t<decltype(T::data)>;
|
||||
T vec_;
|
||||
|
||||
public:
|
||||
WasmVec(size_t s = 0) : vec_ WASM_EMPTY_VEC
|
||||
{
|
||||
if (s > 0)
|
||||
Create(&vec_, s); // zeroes memory
|
||||
}
|
||||
|
||||
~WasmVec()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
WasmVec(WasmVec const&) = delete;
|
||||
WasmVec&
|
||||
operator=(WasmVec const&) = delete;
|
||||
|
||||
WasmVec(WasmVec&& other) noexcept : vec_ WASM_EMPTY_VEC
|
||||
{
|
||||
*this = std::move(other);
|
||||
}
|
||||
|
||||
WasmVec&
|
||||
operator=(WasmVec&& other) noexcept
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
clear();
|
||||
vec_ = other.vec_;
|
||||
other.vec_ = WASM_EMPTY_VEC;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void
|
||||
clear()
|
||||
{
|
||||
Destroy(&vec_); // call destructor for every elements too
|
||||
vec_ = WASM_EMPTY_VEC;
|
||||
}
|
||||
|
||||
T
|
||||
release()
|
||||
{
|
||||
T result = vec_;
|
||||
vec_ = WASM_EMPTY_VEC;
|
||||
return result;
|
||||
}
|
||||
|
||||
T*
|
||||
get()
|
||||
{
|
||||
return &vec_;
|
||||
}
|
||||
|
||||
[[nodiscard]] T const*
|
||||
get() const
|
||||
{
|
||||
return &vec_;
|
||||
}
|
||||
|
||||
TD&
|
||||
operator[](size_t i)
|
||||
{
|
||||
if (i >= vec_.size)
|
||||
Throw<std::runtime_error>("Out of bound");
|
||||
return vec_.data[i];
|
||||
}
|
||||
|
||||
TD const&
|
||||
operator[](size_t i) const
|
||||
{
|
||||
if (i >= vec_.size)
|
||||
Throw<std::runtime_error>("Out of bound");
|
||||
return vec_.data[i];
|
||||
}
|
||||
|
||||
[[nodiscard]] size_t
|
||||
size() const
|
||||
{
|
||||
return vec_.size;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool
|
||||
empty() const
|
||||
{
|
||||
return vec_.size == 0u;
|
||||
}
|
||||
};
|
||||
|
||||
using WasmValtypeVec =
|
||||
WasmVec<wasm_valtype_vec_t, &wasm_valtype_vec_new_uninitialized, &wasm_valtype_vec_delete>;
|
||||
using WasmValVec = WasmVec<wasm_val_vec_t, &wasm_val_vec_new_uninitialized, &wasm_val_vec_delete>;
|
||||
using WasmExternVec =
|
||||
WasmVec<wasm_extern_vec_t, &wasm_extern_vec_new_uninitialized, &wasm_extern_vec_delete>;
|
||||
using WasmExporttypeVec = WasmVec<
|
||||
wasm_exporttype_vec_t,
|
||||
&wasm_exporttype_vec_new_uninitialized,
|
||||
&wasm_exporttype_vec_delete>;
|
||||
using WasmImporttypeVec = WasmVec<
|
||||
wasm_importtype_vec_t,
|
||||
&wasm_importtype_vec_new_uninitialized,
|
||||
&wasm_importtype_vec_delete>;
|
||||
|
||||
struct WasmiResult
|
||||
{
|
||||
WasmValVec r;
|
||||
bool f{false}; // failure flag
|
||||
|
||||
WasmiResult(unsigned n = 0) : r(n)
|
||||
{
|
||||
}
|
||||
|
||||
WasmiResult() = delete;
|
||||
~WasmiResult() = default;
|
||||
WasmiResult(WasmiResult&& o) = default;
|
||||
WasmiResult&
|
||||
operator=(WasmiResult&& o) = default;
|
||||
};
|
||||
|
||||
using ModulePtr = std::unique_ptr<wasm_module_t, decltype(&wasm_module_delete)>;
|
||||
using InstancePtr = std::unique_ptr<wasm_instance_t, decltype(&wasm_instance_delete)>;
|
||||
using EnginePtr = std::unique_ptr<wasm_engine_t, decltype(&wasm_engine_delete)>;
|
||||
using StorePtr = std::unique_ptr<wasm_store_t, decltype(&wasm_store_delete)>;
|
||||
|
||||
using FuncInfo = std::pair<wasm_func_t const*, wasm_functype_t const*>;
|
||||
|
||||
class InstanceWrapper
|
||||
{
|
||||
wasm_store_t* store_ = nullptr;
|
||||
WasmExternVec exports_;
|
||||
mutable int memIdx_ = -1;
|
||||
InstancePtr instance_;
|
||||
beast::Journal j_ = beast::Journal(beast::Journal::getNullSink());
|
||||
|
||||
private:
|
||||
static InstancePtr
|
||||
init(
|
||||
StorePtr& s,
|
||||
ModulePtr& m,
|
||||
WasmExternVec& expt,
|
||||
WasmExternVec const& imports,
|
||||
beast::Journal j);
|
||||
|
||||
public:
|
||||
InstanceWrapper() : instance_(nullptr, &wasm_instance_delete) {};
|
||||
|
||||
InstanceWrapper(InstanceWrapper const&) = delete;
|
||||
|
||||
InstanceWrapper(InstanceWrapper&& o) : instance_(nullptr, &wasm_instance_delete)
|
||||
{
|
||||
*this = std::move(o); // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
InstanceWrapper(StorePtr& s, ModulePtr& m, WasmExternVec const& imports, beast::Journal j)
|
||||
: store_(s.get()), instance_(init(s, m, exports_, imports, j)), j_(j)
|
||||
{
|
||||
}
|
||||
|
||||
InstanceWrapper&
|
||||
operator=(InstanceWrapper&& o);
|
||||
|
||||
InstanceWrapper&
|
||||
operator=(InstanceWrapper const&) = delete;
|
||||
|
||||
operator bool() const
|
||||
{
|
||||
return static_cast<bool>(instance_);
|
||||
}
|
||||
|
||||
FuncInfo
|
||||
getFunc(std::string_view funcName, WasmExporttypeVec const& exportTypes) const;
|
||||
|
||||
Wmem
|
||||
getMem() const;
|
||||
|
||||
std::int64_t
|
||||
getGas() const;
|
||||
|
||||
std::int64_t
|
||||
setGas(std::int64_t) const;
|
||||
};
|
||||
|
||||
class ModuleWrapper
|
||||
{
|
||||
ModulePtr module_;
|
||||
InstanceWrapper instanceWrap_;
|
||||
WasmExporttypeVec exportTypes_;
|
||||
beast::Journal j_ = beast::Journal(beast::Journal::getNullSink());
|
||||
|
||||
public:
|
||||
// LCOV_EXCL_START
|
||||
ModuleWrapper() : module_(nullptr, &wasm_module_delete)
|
||||
{
|
||||
}
|
||||
|
||||
ModuleWrapper(ModuleWrapper&& o) : module_(nullptr, &wasm_module_delete)
|
||||
{
|
||||
*this = std::move(o);
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
ModuleWrapper&
|
||||
operator=(ModuleWrapper&& o);
|
||||
ModuleWrapper(
|
||||
StorePtr& s,
|
||||
Bytes const& wasmBin,
|
||||
bool instantiate,
|
||||
ImportVec const& imports,
|
||||
beast::Journal j);
|
||||
~ModuleWrapper() = default;
|
||||
|
||||
operator bool() const
|
||||
{
|
||||
return instanceWrap_;
|
||||
}
|
||||
|
||||
FuncInfo
|
||||
getFunc(std::string_view funcName) const
|
||||
{
|
||||
return instanceWrap_.getFunc(funcName, exportTypes_);
|
||||
}
|
||||
|
||||
wasm_functype_t*
|
||||
getFuncType(std::string_view funcName) const;
|
||||
|
||||
Wmem
|
||||
getMem() const
|
||||
{
|
||||
return instanceWrap_.getMem();
|
||||
}
|
||||
|
||||
InstanceWrapper&
|
||||
getInstance(int i = 0)
|
||||
{
|
||||
return instanceWrap_;
|
||||
}
|
||||
|
||||
InstanceWrapper const&
|
||||
getInstance(int i = 0) const
|
||||
{
|
||||
return instanceWrap_;
|
||||
}
|
||||
|
||||
int
|
||||
addInstance(StorePtr& s, WasmExternVec const& imports)
|
||||
{
|
||||
instanceWrap_ = {s, module_, imports, j_};
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::int64_t
|
||||
getGas() const
|
||||
{
|
||||
return instanceWrap_ ? instanceWrap_.getGas() : -1;
|
||||
}
|
||||
|
||||
private:
|
||||
static ModulePtr
|
||||
init(StorePtr& s, Bytes const& wasmBin, beast::Journal j);
|
||||
|
||||
WasmExternVec
|
||||
buildImports(StorePtr& s, ImportVec const& imports) const;
|
||||
};
|
||||
|
||||
class WasmiEngine
|
||||
{
|
||||
EnginePtr engine_;
|
||||
StorePtr store_;
|
||||
std::unique_ptr<ModuleWrapper> moduleWrap_;
|
||||
beast::Journal j_ = beast::Journal(beast::Journal::getNullSink());
|
||||
|
||||
std::mutex m_; // 1 instance mutex
|
||||
|
||||
public:
|
||||
WasmiEngine() : engine_(init()), store_(nullptr, &wasm_store_delete)
|
||||
{
|
||||
}
|
||||
|
||||
~WasmiEngine() = default;
|
||||
|
||||
static EnginePtr
|
||||
init();
|
||||
|
||||
Expected<WasmResult<int32_t>, TER>
|
||||
run(Bytes const& wasmCode,
|
||||
HostFunctions& hfs,
|
||||
int64_t gas,
|
||||
std::string_view funcName,
|
||||
std::vector<WasmParam> const& params,
|
||||
ImportVec const& imports,
|
||||
beast::Journal j);
|
||||
|
||||
NotTEC
|
||||
check(
|
||||
Bytes const& wasmCode,
|
||||
HostFunctions& hfs,
|
||||
std::string_view funcName,
|
||||
std::vector<WasmParam> const& params,
|
||||
ImportVec const& imports,
|
||||
beast::Journal j);
|
||||
|
||||
[[nodiscard]] std::int64_t
|
||||
getGas() const
|
||||
{
|
||||
return moduleWrap_ ? moduleWrap_->getGas() : -1; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
// Host functions helper functionality
|
||||
wasm_trap_t*
|
||||
newTrap(std::string const& msg);
|
||||
|
||||
// LCOV_EXCL_START
|
||||
[[nodiscard]] beast::Journal
|
||||
getJournal() const
|
||||
{
|
||||
return j_;
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
private:
|
||||
[[nodiscard]] InstanceWrapper&
|
||||
getRT(int m = 0, int i = 0) const
|
||||
{
|
||||
if (!moduleWrap_)
|
||||
Throw<std::runtime_error>("no module");
|
||||
return moduleWrap_->getInstance(i);
|
||||
}
|
||||
|
||||
[[nodiscard]] Wmem
|
||||
getMem() const
|
||||
{
|
||||
return moduleWrap_ ? moduleWrap_->getMem() : Wmem();
|
||||
}
|
||||
|
||||
Expected<WasmResult<int32_t>, TER>
|
||||
runHlp(
|
||||
Bytes const& wasmCode,
|
||||
HostFunctions& hfs,
|
||||
int64_t gas,
|
||||
std::string_view funcName,
|
||||
std::vector<WasmParam> const& params,
|
||||
ImportVec const& imports,
|
||||
beast::Journal j);
|
||||
|
||||
NotTEC
|
||||
checkHlp(
|
||||
Bytes const& wasmCode,
|
||||
HostFunctions& hfs,
|
||||
std::string_view funcName,
|
||||
std::vector<WasmParam> const& params,
|
||||
ImportVec const& imports,
|
||||
beast::Journal j);
|
||||
|
||||
int
|
||||
addModule(Bytes const& wasmCode, bool instantiate, ImportVec const& imports, int64_t gas);
|
||||
void
|
||||
clearModules();
|
||||
|
||||
// int addInstance();
|
||||
|
||||
int32_t
|
||||
runFunc(std::string_view const funcName, int32_t p);
|
||||
|
||||
int32_t
|
||||
makeModule(Bytes const& wasmCode, WasmExternVec const& imports = {});
|
||||
|
||||
[[nodiscard]] FuncInfo
|
||||
getFunc(std::string_view funcName) const
|
||||
{
|
||||
return moduleWrap_->getFunc(funcName);
|
||||
}
|
||||
|
||||
static std::vector<wasm_val_t>
|
||||
convertParams(std::vector<WasmParam> const& params);
|
||||
|
||||
static int
|
||||
compareParamTypes(wasm_valtype_vec_t const* ftp, std::vector<wasm_val_t> const& p);
|
||||
|
||||
static void
|
||||
addParam(std::vector<wasm_val_t>& in, int32_t p);
|
||||
static void
|
||||
addParam(std::vector<wasm_val_t>& in, int64_t p);
|
||||
|
||||
template <int NR, class... Types>
|
||||
inline WasmiResult
|
||||
call(std::string_view func, Types&&... args);
|
||||
|
||||
template <int NR, class... Types>
|
||||
inline WasmiResult
|
||||
call(FuncInfo const& f, Types&&... args);
|
||||
|
||||
template <int NR, class... Types>
|
||||
inline WasmiResult
|
||||
call(FuncInfo const& f, std::vector<wasm_val_t>& in);
|
||||
|
||||
template <int NR, class... Types>
|
||||
inline WasmiResult
|
||||
call(FuncInfo const& f, std::vector<wasm_val_t>& in, std::int32_t p, Types&&... args);
|
||||
|
||||
template <int NR, class... Types>
|
||||
inline WasmiResult
|
||||
call(FuncInfo const& f, std::vector<wasm_val_t>& in, std::int64_t p, Types&&... args);
|
||||
|
||||
template <int NR, class... Types>
|
||||
inline WasmiResult
|
||||
call(
|
||||
FuncInfo const& f,
|
||||
std::vector<wasm_val_t>& in,
|
||||
uint8_t const* d,
|
||||
int32_t sz,
|
||||
Types&&... args);
|
||||
|
||||
template <int NR, class... Types>
|
||||
inline WasmiResult
|
||||
call(FuncInfo const& f, std::vector<wasm_val_t>& in, Bytes const& p, Types&&... args);
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -199,6 +199,7 @@ transResults()
|
||||
MAKE_ERROR(temARRAY_TOO_LARGE, "Malformed: Array is too large."),
|
||||
MAKE_ERROR(temBAD_TRANSFER_FEE, "Malformed: Transfer fee is outside valid range."),
|
||||
MAKE_ERROR(temINVALID_INNER_BATCH, "Malformed: Invalid inner batch transaction."),
|
||||
MAKE_ERROR(temBAD_WASM, "Malformed: Provided WASM code is invalid."),
|
||||
|
||||
MAKE_ERROR(terRETRY, "Retry transaction."),
|
||||
MAKE_ERROR(terFUNDS_SPENT, "DEPRECATED."),
|
||||
|
||||
52
src/libxrpl/tx/wasm/HostFuncImpl.cpp
Normal file
52
src/libxrpl/tx/wasm/HostFuncImpl.cpp
Normal file
@@ -0,0 +1,52 @@
|
||||
#include <xrpl/tx/wasm/HostFuncImpl.h>
|
||||
|
||||
#include <xrpl/basics/Expected.h>
|
||||
#include <xrpl/basics/Slice.h>
|
||||
#include <xrpl/protocol/Protocol.h>
|
||||
#include <xrpl/protocol/PublicKey.h>
|
||||
#include <xrpl/protocol/digest.h>
|
||||
#include <xrpl/tx/wasm/WasmCommon.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
// =========================================================
|
||||
// SECTION: WRITE FUNCTION
|
||||
// =========================================================
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
WasmHostFunctionsImpl::updateData(Slice const& data)
|
||||
{
|
||||
if (data.size() > kMaxWasmDataLength)
|
||||
return Unexpected(HostFunctionError::DataFieldTooLarge);
|
||||
|
||||
data_ = Bytes(data.begin(), data.end());
|
||||
return data_->size();
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// SECTION: UTILS
|
||||
// =========================================================
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
WasmHostFunctionsImpl::checkSignature(
|
||||
Slice const& message,
|
||||
Slice const& signature,
|
||||
Slice const& pubkey) const
|
||||
{
|
||||
if (!publicKeyType(pubkey))
|
||||
return Unexpected(HostFunctionError::InvalidParams);
|
||||
|
||||
PublicKey const pk(pubkey);
|
||||
return verify(pk, message, signature);
|
||||
}
|
||||
|
||||
Expected<Hash, HostFunctionError>
|
||||
WasmHostFunctionsImpl::computeSha512HalfHash(Slice const& data) const
|
||||
{
|
||||
auto const hash = sha512Half(data);
|
||||
return hash;
|
||||
}
|
||||
|
||||
} // namespace xrpl
|
||||
594
src/libxrpl/tx/wasm/HostFuncImplFloat.cpp
Normal file
594
src/libxrpl/tx/wasm/HostFuncImplFloat.cpp
Normal file
@@ -0,0 +1,594 @@
|
||||
#include <xrpl/basics/Expected.h>
|
||||
#include <xrpl/basics/Number.h>
|
||||
#include <xrpl/basics/Slice.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/STNumber.h>
|
||||
#include <xrpl/protocol/Serializer.h>
|
||||
#include <xrpl/tx/wasm/HostFunc.h>
|
||||
#include <xrpl/tx/wasm/HostFuncImpl.h>
|
||||
#include <xrpl/tx/wasm/WasmCommon.h>
|
||||
|
||||
#include <boost/algorithm/hex.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#ifdef _DEBUG
|
||||
// #define DEBUG_OUTPUT 1
|
||||
#endif
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
namespace wasm_float {
|
||||
|
||||
namespace detail {
|
||||
|
||||
class WasmNumber : public Number
|
||||
{
|
||||
protected:
|
||||
static unsigned constexpr encodedFloatSize = 12;
|
||||
bool good_ = false;
|
||||
|
||||
public:
|
||||
WasmNumber(Slice const& data)
|
||||
{
|
||||
if (data.size() != encodedFloatSize)
|
||||
return;
|
||||
try
|
||||
{
|
||||
SerialIter it(data);
|
||||
Number const x = STNumber(it, sfNumber).value();
|
||||
*static_cast<Number*>(this) = x;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
good_ = true;
|
||||
}
|
||||
|
||||
WasmNumber(Number const& n) : WasmNumber(n.mantissa(), n.exponent()) // ensure Number canonized
|
||||
{
|
||||
}
|
||||
|
||||
template <class T>
|
||||
WasmNumber(T mantissa = 0, int32_t exponent = 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
Number n;
|
||||
if constexpr (std::is_signed_v<T>)
|
||||
{
|
||||
n = Number(static_cast<int64_t>(mantissa), exponent);
|
||||
}
|
||||
else
|
||||
{
|
||||
n = Number(static_cast<uint64_t>(mantissa), exponent, Number::Normalized{});
|
||||
}
|
||||
*static_cast<Number*>(this) = n;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return;
|
||||
}
|
||||
good_ = true;
|
||||
}
|
||||
|
||||
WasmNumber&
|
||||
operator=(WasmNumber const&) = default;
|
||||
|
||||
explicit
|
||||
operator bool() const
|
||||
{
|
||||
return good_;
|
||||
}
|
||||
|
||||
explicit
|
||||
operator int64_t() const
|
||||
{
|
||||
return Number::operator int64_t();
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
toBytes() const
|
||||
{
|
||||
Serializer msg;
|
||||
STNumber(sfNumber, *this).add(msg);
|
||||
auto data = msg.getData();
|
||||
|
||||
#ifdef DEBUG_OUTPUT
|
||||
std::cout << "m: " << std::setw(20) << mantissa() << ", e: " << std::setw(12) << exponent()
|
||||
<< ", hex: ";
|
||||
std::cout << std::hex << std::uppercase << std::setfill('0');
|
||||
for (auto const& c : data)
|
||||
std::cout << std::setw(2) << (unsigned)c << " ";
|
||||
std::cout << std::dec << std::setfill(' ') << std::endl;
|
||||
#endif
|
||||
return Expected<Bytes, HostFunctionError>(std::move(data));
|
||||
}
|
||||
};
|
||||
|
||||
struct FloatState
|
||||
{
|
||||
Number::RoundingMode oldMode;
|
||||
bool good = false;
|
||||
|
||||
FloatState(int32_t mode) : oldMode(Number::getround())
|
||||
{
|
||||
if (mode < static_cast<int32_t>(Number::RoundingMode::ToNearest) ||
|
||||
mode > static_cast<int32_t>(Number::RoundingMode::Upward))
|
||||
return;
|
||||
Number::setround(static_cast<Number::RoundingMode>(mode));
|
||||
good = true;
|
||||
}
|
||||
|
||||
~FloatState()
|
||||
{
|
||||
Number::setround(oldMode);
|
||||
}
|
||||
|
||||
operator bool() const
|
||||
{
|
||||
return good;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
std::string
|
||||
floatToString(Slice const& data)
|
||||
{
|
||||
// set default mode as we don't expect it will be used here
|
||||
detail::FloatState const rm(static_cast<int32_t>(Number::RoundingMode::ToNearest));
|
||||
detail::WasmNumber const num(data);
|
||||
if (!num)
|
||||
{
|
||||
std::string hex;
|
||||
hex.reserve(data.size() * 2);
|
||||
boost::algorithm::hex(data.begin(), data.end(), std::back_inserter(hex));
|
||||
return "Invalid data: " + hex;
|
||||
}
|
||||
auto const s = to_string(num);
|
||||
return s;
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatFromIntImpl(int64_t x, int32_t mode)
|
||||
{
|
||||
try
|
||||
{
|
||||
detail::FloatState const rm(mode);
|
||||
if (!rm)
|
||||
return Unexpected(HostFunctionError::FloatInputMalformed);
|
||||
|
||||
detail::WasmNumber const num(x);
|
||||
if (!num)
|
||||
return Unexpected(HostFunctionError::FloatInputMalformed); // LCOV_EXCL_LINE
|
||||
auto const r = num.toBytes();
|
||||
return r;
|
||||
}
|
||||
// LCOV_EXCL_START
|
||||
catch (...)
|
||||
{
|
||||
return Unexpected(HostFunctionError::FloatComputationError);
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatFromUintImpl(uint64_t x, int32_t mode)
|
||||
{
|
||||
try
|
||||
{
|
||||
detail::FloatState const rm(mode);
|
||||
if (!rm)
|
||||
return Unexpected(HostFunctionError::FloatInputMalformed);
|
||||
|
||||
detail::WasmNumber const num(x);
|
||||
if (!num)
|
||||
return Unexpected(HostFunctionError::FloatInputMalformed); // LCOV_EXCL_LINE
|
||||
auto const r = num.toBytes();
|
||||
return r;
|
||||
}
|
||||
// LCOV_EXCL_START
|
||||
catch (...)
|
||||
{
|
||||
return Unexpected(HostFunctionError::FloatComputationError);
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatFromSTAmountImpl(STAmount const& x, int32_t mode)
|
||||
{
|
||||
try
|
||||
{
|
||||
detail::FloatState const rm(mode);
|
||||
if (!rm)
|
||||
return Unexpected(HostFunctionError::FloatInputMalformed);
|
||||
|
||||
detail::WasmNumber const num(static_cast<Number>(x));
|
||||
if (!num)
|
||||
return Unexpected(HostFunctionError::FloatInputMalformed); // LCOV_EXCL_LINE
|
||||
auto const r = num.toBytes();
|
||||
return r;
|
||||
}
|
||||
// LCOV_EXCL_START
|
||||
catch (...)
|
||||
{
|
||||
return Unexpected(HostFunctionError::FloatComputationError);
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatFromSTNumberImpl(STNumber const& x, int32_t mode)
|
||||
{
|
||||
try
|
||||
{
|
||||
detail::FloatState const rm(mode);
|
||||
if (!rm)
|
||||
return Unexpected(HostFunctionError::FloatInputMalformed);
|
||||
|
||||
detail::WasmNumber const num(x.value());
|
||||
if (!num)
|
||||
return Unexpected(HostFunctionError::FloatInputMalformed); // LCOV_EXCL_LINE
|
||||
auto const r = num.toBytes();
|
||||
return r;
|
||||
}
|
||||
// LCOV_EXCL_START
|
||||
catch (...)
|
||||
{
|
||||
return Unexpected(HostFunctionError::FloatComputationError);
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
Expected<int64_t, HostFunctionError>
|
||||
floatToIntImpl(Slice const& x, int32_t mode)
|
||||
{
|
||||
try
|
||||
{
|
||||
detail::FloatState const rm(mode);
|
||||
if (!rm)
|
||||
return Unexpected(HostFunctionError::FloatInputMalformed);
|
||||
|
||||
detail::WasmNumber const num(x);
|
||||
if (!num)
|
||||
return Unexpected(HostFunctionError::FloatInputMalformed); // LCOV_EXCL_LINE
|
||||
int64_t const r(num);
|
||||
return r;
|
||||
}
|
||||
// LCOV_EXCL_START
|
||||
catch (...)
|
||||
{
|
||||
return Unexpected(HostFunctionError::FloatComputationError);
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
Expected<FloatPair, HostFunctionError>
|
||||
floatToMantExpImpl(Slice const& x)
|
||||
{
|
||||
try
|
||||
{
|
||||
detail::FloatState const rm(static_cast<int32_t>(Number::RoundingMode::ToNearest));
|
||||
if (!rm)
|
||||
return Unexpected(HostFunctionError::FloatInputMalformed);
|
||||
|
||||
detail::WasmNumber const num(x);
|
||||
if (!num)
|
||||
return Unexpected(HostFunctionError::FloatInputMalformed); // LCOV_EXCL_LINE
|
||||
|
||||
return FloatPair(num.mantissa(), num.exponent());
|
||||
}
|
||||
// LCOV_EXCL_START
|
||||
catch (...)
|
||||
{
|
||||
return Unexpected(HostFunctionError::FloatComputationError);
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatFromMantExpImpl(int64_t mantissa, int32_t exponent, int32_t mode)
|
||||
{
|
||||
try
|
||||
{
|
||||
detail::FloatState const rm(mode);
|
||||
if (!rm)
|
||||
return Unexpected(HostFunctionError::FloatInputMalformed);
|
||||
detail::WasmNumber const num(mantissa, exponent);
|
||||
if (!num)
|
||||
return Unexpected(HostFunctionError::FloatInputMalformed);
|
||||
return num.toBytes();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return Unexpected(HostFunctionError::FloatComputationError);
|
||||
}
|
||||
}
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
floatCompareImpl(Slice const& x, Slice const& y)
|
||||
{
|
||||
try
|
||||
{
|
||||
// set default mode as we don't expect it will be used here
|
||||
detail::FloatState const rm(static_cast<int32_t>(Number::RoundingMode::ToNearest));
|
||||
|
||||
detail::WasmNumber const xx(x);
|
||||
if (!xx)
|
||||
return Unexpected(HostFunctionError::FloatInputMalformed);
|
||||
detail::WasmNumber const yy(y);
|
||||
if (!yy)
|
||||
return Unexpected(HostFunctionError::FloatInputMalformed);
|
||||
if (xx < yy)
|
||||
return 2;
|
||||
if (xx == yy)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
// LCOV_EXCL_START
|
||||
catch (...)
|
||||
{
|
||||
return Unexpected(HostFunctionError::FloatComputationError);
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatAddImpl(Slice const& x, Slice const& y, int32_t mode)
|
||||
{
|
||||
try
|
||||
{
|
||||
detail::FloatState const rm(mode);
|
||||
if (!rm)
|
||||
return Unexpected(HostFunctionError::FloatInputMalformed);
|
||||
|
||||
detail::WasmNumber const xx(x);
|
||||
if (!xx)
|
||||
return Unexpected(HostFunctionError::FloatInputMalformed);
|
||||
detail::WasmNumber const yy(y);
|
||||
if (!yy)
|
||||
return Unexpected(HostFunctionError::FloatInputMalformed);
|
||||
detail::WasmNumber const res = xx + yy;
|
||||
|
||||
return res.toBytes();
|
||||
}
|
||||
// LCOV_EXCL_START
|
||||
catch (...)
|
||||
{
|
||||
return Unexpected(HostFunctionError::FloatComputationError);
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatSubtractImpl(Slice const& x, Slice const& y, int32_t mode)
|
||||
{
|
||||
try
|
||||
{
|
||||
detail::FloatState const rm(mode);
|
||||
if (!rm)
|
||||
return Unexpected(HostFunctionError::FloatInputMalformed);
|
||||
detail::WasmNumber const xx(x);
|
||||
if (!xx)
|
||||
return Unexpected(HostFunctionError::FloatInputMalformed);
|
||||
detail::WasmNumber const yy(y);
|
||||
if (!yy)
|
||||
return Unexpected(HostFunctionError::FloatInputMalformed);
|
||||
detail::WasmNumber const res = xx - yy;
|
||||
|
||||
return res.toBytes();
|
||||
}
|
||||
// LCOV_EXCL_START
|
||||
catch (...)
|
||||
{
|
||||
return Unexpected(HostFunctionError::FloatComputationError);
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatMultiplyImpl(Slice const& x, Slice const& y, int32_t mode)
|
||||
{
|
||||
try
|
||||
{
|
||||
detail::FloatState const rm(mode);
|
||||
if (!rm)
|
||||
return Unexpected(HostFunctionError::FloatInputMalformed);
|
||||
detail::WasmNumber const xx(x);
|
||||
if (!xx)
|
||||
return Unexpected(HostFunctionError::FloatInputMalformed);
|
||||
detail::WasmNumber const yy(y);
|
||||
if (!yy)
|
||||
return Unexpected(HostFunctionError::FloatInputMalformed);
|
||||
detail::WasmNumber const res = xx * yy;
|
||||
|
||||
return res.toBytes();
|
||||
}
|
||||
// LCOV_EXCL_START
|
||||
catch (...)
|
||||
{
|
||||
return Unexpected(HostFunctionError::FloatComputationError);
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatDivideImpl(Slice const& x, Slice const& y, int32_t mode)
|
||||
{
|
||||
try
|
||||
{
|
||||
detail::FloatState const rm(mode);
|
||||
if (!rm)
|
||||
return Unexpected(HostFunctionError::FloatInputMalformed);
|
||||
detail::WasmNumber const xx(x);
|
||||
if (!xx)
|
||||
return Unexpected(HostFunctionError::FloatInputMalformed);
|
||||
detail::WasmNumber const yy(y);
|
||||
if (!yy)
|
||||
return Unexpected(HostFunctionError::FloatInputMalformed);
|
||||
detail::WasmNumber const res = xx / yy;
|
||||
|
||||
return res.toBytes();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return Unexpected(HostFunctionError::FloatComputationError);
|
||||
}
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatRootImpl(Slice const& x, int32_t n, int32_t mode)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (n < 1)
|
||||
return Unexpected(HostFunctionError::FloatInputMalformed);
|
||||
|
||||
detail::FloatState const rm(mode);
|
||||
if (!rm)
|
||||
return Unexpected(HostFunctionError::FloatInputMalformed);
|
||||
|
||||
detail::WasmNumber const xx(x);
|
||||
if (!xx)
|
||||
return Unexpected(HostFunctionError::FloatInputMalformed);
|
||||
|
||||
detail::WasmNumber const res(root(xx, n));
|
||||
|
||||
return res.toBytes();
|
||||
}
|
||||
// LCOV_EXCL_START
|
||||
catch (...)
|
||||
{
|
||||
return Unexpected(HostFunctionError::FloatComputationError);
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatPowerImpl(Slice const& x, int32_t n, int32_t mode)
|
||||
{
|
||||
try
|
||||
{
|
||||
if ((n < 0) || (n > Number::kMaxExponent))
|
||||
return Unexpected(HostFunctionError::FloatInputMalformed);
|
||||
|
||||
detail::FloatState const rm(mode);
|
||||
if (!rm)
|
||||
return Unexpected(HostFunctionError::FloatInputMalformed);
|
||||
|
||||
detail::WasmNumber const xx(x);
|
||||
if (!xx)
|
||||
return Unexpected(HostFunctionError::FloatInputMalformed);
|
||||
if (xx == Number() && (n == 0))
|
||||
return Unexpected(HostFunctionError::InvalidParams);
|
||||
|
||||
detail::WasmNumber const res(power(xx, n, 1));
|
||||
|
||||
return res.toBytes();
|
||||
}
|
||||
// LCOV_EXCL_START
|
||||
catch (...)
|
||||
{
|
||||
return Unexpected(HostFunctionError::FloatComputationError);
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
} // namespace wasm_float
|
||||
|
||||
// =========================================================
|
||||
// ACTUAL HOST FUNCTIONS
|
||||
// =========================================================
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
WasmHostFunctionsImpl::floatFromInt(int64_t x, int32_t mode) const
|
||||
{
|
||||
return wasm_float::floatFromIntImpl(x, mode);
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
WasmHostFunctionsImpl::floatFromUint(uint64_t x, int32_t mode) const
|
||||
{
|
||||
return wasm_float::floatFromUintImpl(x, mode);
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
WasmHostFunctionsImpl::floatFromSTAmount(STAmount const& x, int32_t mode) const
|
||||
{
|
||||
return wasm_float::floatFromSTAmountImpl(x, mode);
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
WasmHostFunctionsImpl::floatFromSTNumber(STNumber const& x, int32_t mode) const
|
||||
{
|
||||
return wasm_float::floatFromSTNumberImpl(x, mode);
|
||||
}
|
||||
|
||||
Expected<int64_t, HostFunctionError>
|
||||
WasmHostFunctionsImpl::floatToInt(Slice const& x, int32_t mode) const
|
||||
{
|
||||
return wasm_float::floatToIntImpl(x, mode);
|
||||
}
|
||||
|
||||
Expected<FloatPair, HostFunctionError>
|
||||
WasmHostFunctionsImpl::floatToMantExp(Slice const& x) const
|
||||
{
|
||||
return wasm_float::floatToMantExpImpl(x);
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
WasmHostFunctionsImpl::floatFromMantExp(int64_t mantissa, int32_t exponent, int32_t mode) const
|
||||
{
|
||||
return wasm_float::floatFromMantExpImpl(mantissa, exponent, mode);
|
||||
}
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
WasmHostFunctionsImpl::floatCompare(Slice const& x, Slice const& y) const
|
||||
{
|
||||
return wasm_float::floatCompareImpl(x, y);
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
WasmHostFunctionsImpl::floatAdd(Slice const& x, Slice const& y, int32_t mode) const
|
||||
{
|
||||
return wasm_float::floatAddImpl(x, y, mode);
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
WasmHostFunctionsImpl::floatSubtract(Slice const& x, Slice const& y, int32_t mode) const
|
||||
{
|
||||
return wasm_float::floatSubtractImpl(x, y, mode);
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
WasmHostFunctionsImpl::floatMultiply(Slice const& x, Slice const& y, int32_t mode) const
|
||||
{
|
||||
return wasm_float::floatMultiplyImpl(x, y, mode);
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
WasmHostFunctionsImpl::floatDivide(Slice const& x, Slice const& y, int32_t mode) const
|
||||
{
|
||||
return wasm_float::floatDivideImpl(x, y, mode);
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
WasmHostFunctionsImpl::floatRoot(Slice const& x, int32_t n, int32_t mode) const
|
||||
{
|
||||
return wasm_float::floatRootImpl(x, n, mode);
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
WasmHostFunctionsImpl::floatPower(Slice const& x, int32_t n, int32_t mode) const
|
||||
{
|
||||
return wasm_float::floatPowerImpl(x, n, mode);
|
||||
}
|
||||
|
||||
} // namespace xrpl
|
||||
395
src/libxrpl/tx/wasm/HostFuncImplGetter.cpp
Normal file
395
src/libxrpl/tx/wasm/HostFuncImplGetter.cpp
Normal file
@@ -0,0 +1,395 @@
|
||||
#include <xrpl/basics/Expected.h>
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/protocol/Asset.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/MPTIssue.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/STBase.h>
|
||||
#include <xrpl/protocol/STBitString.h>
|
||||
#include <xrpl/protocol/STObject.h>
|
||||
#include <xrpl/protocol/Serializer.h>
|
||||
#include <xrpl/tx/wasm/HostFuncImpl.h>
|
||||
#include <xrpl/tx/wasm/WasmCommon.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <utility>
|
||||
#include <variant>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
using FieldValue = std::variant<STBase const*, uint256 const*>;
|
||||
|
||||
template <class T>
|
||||
Bytes
|
||||
getIntBytes(STBase const* obj)
|
||||
{
|
||||
static_assert(std::is_integral_v<T>, "Only integral types");
|
||||
XRPL_ASSERT(obj, "getIntBytes null pointer");
|
||||
|
||||
auto const* num(static_cast<STInteger<T> const*>(obj)); // NOLINT
|
||||
T const data = adjustWasmEndianess(num->value());
|
||||
uint8_t const* b = reinterpret_cast<uint8_t const*>(&data);
|
||||
return Bytes{b, b + sizeof(T)};
|
||||
}
|
||||
|
||||
static Expected<Bytes, HostFunctionError>
|
||||
getAnyFieldData(STBase const* obj)
|
||||
{
|
||||
if (obj == nullptr)
|
||||
return Unexpected(HostFunctionError::FieldNotFound);
|
||||
|
||||
auto const stype = obj->getSType();
|
||||
switch (stype)
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
case STI_UNKNOWN:
|
||||
case STI_NOTPRESENT:
|
||||
return Unexpected(HostFunctionError::FieldNotFound);
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
case STI_OBJECT:
|
||||
case STI_ARRAY:
|
||||
case STI_VECTOR256:
|
||||
return Unexpected(HostFunctionError::NotLeafField);
|
||||
|
||||
case STI_ACCOUNT: {
|
||||
auto const* account(static_cast<STAccount const*>(obj)); // NOLINT
|
||||
auto const& data = account->value();
|
||||
return Bytes{data.begin(), data.end()};
|
||||
}
|
||||
|
||||
case STI_ISSUE: {
|
||||
auto const* issue(static_cast<STIssue const*>(obj)); // NOLINT
|
||||
Asset const& asset(issue->value());
|
||||
// XRP and IOU will be processed by serializer
|
||||
if (asset.holds<MPTIssue>())
|
||||
{
|
||||
auto const& mptIssue = asset.get<MPTIssue>();
|
||||
auto const& mptID = mptIssue.getMptID();
|
||||
return Bytes{mptID.cbegin(), mptID.cend()};
|
||||
}
|
||||
break; // Use serializer
|
||||
}
|
||||
|
||||
case STI_VL: {
|
||||
auto const* vl(static_cast<STBlob const*>(obj)); // NOLINT
|
||||
auto const& data = vl->value();
|
||||
return Bytes{data.begin(), data.end()};
|
||||
}
|
||||
|
||||
case STI_UINT16:
|
||||
return getIntBytes<std::uint16_t>(obj);
|
||||
|
||||
case STI_UINT32:
|
||||
return getIntBytes<std::uint32_t>(obj);
|
||||
|
||||
// LCOV_EXCL_START
|
||||
case STI_UINT64:
|
||||
return getIntBytes<std::uint64_t>(obj);
|
||||
|
||||
case STI_INT32:
|
||||
return getIntBytes<std::int32_t>(obj);
|
||||
|
||||
case STI_INT64:
|
||||
return getIntBytes<std::int64_t>(obj);
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
case STI_UINT256: {
|
||||
auto const* uint256Obj(static_cast<STUInt256 const*>(obj)); // NOLINT
|
||||
auto const& data = uint256Obj->value();
|
||||
return Bytes{data.begin(), data.end()};
|
||||
}
|
||||
|
||||
case STI_AMOUNT:
|
||||
case STI_NUMBER:
|
||||
default:
|
||||
break; // Use serializer
|
||||
}
|
||||
|
||||
Serializer msg;
|
||||
obj->add(msg);
|
||||
return msg.getData();
|
||||
}
|
||||
|
||||
static Expected<Bytes, HostFunctionError>
|
||||
getAnyFieldData(FieldValue const& variantObj)
|
||||
{
|
||||
if (STBase const* const* obj = std::get_if<STBase const*>(&variantObj))
|
||||
return getAnyFieldData(*obj);
|
||||
|
||||
if (uint256 const* const* u = std::get_if<uint256 const*>(&variantObj))
|
||||
return Bytes((*u)->begin(), (*u)->end());
|
||||
|
||||
return Unexpected(HostFunctionError::Internal); // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
static inline bool
|
||||
noField(STBase const* field)
|
||||
{
|
||||
return (field == nullptr) || (STI_NOTPRESENT == field->getSType()) ||
|
||||
(STI_UNKNOWN == field->getSType());
|
||||
}
|
||||
|
||||
static Expected<FieldValue, HostFunctionError>
|
||||
locateField(STObject const& obj, FieldLocator const& locator)
|
||||
{
|
||||
STBase const* field = nullptr;
|
||||
auto const& knownSFields = SField::getKnownCodeToField();
|
||||
|
||||
{
|
||||
int32_t const sfieldCode = adjustWasmEndianess(locator[0]);
|
||||
auto const it = knownSFields.find(sfieldCode);
|
||||
if (it == knownSFields.end())
|
||||
return Unexpected(HostFunctionError::InvalidField);
|
||||
|
||||
auto const& fname(*it->second);
|
||||
field = obj.peekAtPField(fname);
|
||||
if (noField(field))
|
||||
return Unexpected(HostFunctionError::FieldNotFound);
|
||||
}
|
||||
|
||||
for (unsigned i = 1; i < locator.size(); ++i)
|
||||
{
|
||||
int32_t const sfieldCode = adjustWasmEndianess(locator[i]);
|
||||
|
||||
if (STI_ARRAY == field->getSType())
|
||||
{
|
||||
auto const* arr = static_cast<STArray const*>(field); // NOLINT
|
||||
if (sfieldCode < 0 || std::cmp_greater_equal(sfieldCode, arr->size()))
|
||||
return Unexpected(HostFunctionError::IndexOutOfBounds);
|
||||
field = &(arr->operator[](sfieldCode));
|
||||
}
|
||||
else if (STI_OBJECT == field->getSType())
|
||||
{
|
||||
auto const* o = static_cast<STObject const*>(field); // NOLINT
|
||||
|
||||
auto const it = knownSFields.find(sfieldCode);
|
||||
if (it == knownSFields.end())
|
||||
return Unexpected(HostFunctionError::InvalidField);
|
||||
|
||||
auto const& fname(*it->second);
|
||||
field = o->peekAtPField(fname);
|
||||
}
|
||||
else if (STI_VECTOR256 == field->getSType())
|
||||
{
|
||||
auto const* v = static_cast<STVector256 const*>(field); // NOLINT
|
||||
if (sfieldCode < 0 || std::cmp_greater_equal(sfieldCode, v->size()))
|
||||
return Unexpected(HostFunctionError::IndexOutOfBounds);
|
||||
return FieldValue(&(v->operator[](sfieldCode)));
|
||||
}
|
||||
else // simple field must be the last one
|
||||
{
|
||||
return Unexpected(HostFunctionError::LocatorMalformed);
|
||||
}
|
||||
|
||||
if (noField(field))
|
||||
return Unexpected(HostFunctionError::FieldNotFound);
|
||||
}
|
||||
|
||||
return FieldValue(field);
|
||||
}
|
||||
|
||||
static inline Expected<int32_t, HostFunctionError>
|
||||
getArrayLen(FieldValue const& variantField)
|
||||
{
|
||||
if (STBase const* const* field = std::get_if<STBase const*>(&variantField))
|
||||
{
|
||||
if ((*field)->getSType() == STI_VECTOR256)
|
||||
return static_cast<STVector256 const*>(*field)->size(); // NOLINT
|
||||
if ((*field)->getSType() == STI_ARRAY)
|
||||
return static_cast<STArray const*>(*field)->size(); // NOLINT
|
||||
}
|
||||
// uint256 is not an array so that variant should still return NO_ARRAY
|
||||
|
||||
return Unexpected(HostFunctionError::NoArray); // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
WasmHostFunctionsImpl::cacheLedgerObj(uint256 const& objId, int32_t cacheIdx)
|
||||
{
|
||||
auto const& keylet = keylet::unchecked(objId);
|
||||
if (cacheIdx < 0 || cacheIdx > maxCache)
|
||||
return Unexpected(HostFunctionError::SlotOutRange);
|
||||
|
||||
if (cacheIdx == 0)
|
||||
{
|
||||
for (cacheIdx = 0; cacheIdx < maxCache; ++cacheIdx)
|
||||
{
|
||||
if (!cache_[cacheIdx])
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cacheIdx--; // convert to 0-based index
|
||||
}
|
||||
|
||||
if (cacheIdx >= maxCache)
|
||||
return Unexpected(HostFunctionError::SlotsFull);
|
||||
|
||||
cache_[cacheIdx] = ctx_.view().read(keylet);
|
||||
if (!cache_[cacheIdx])
|
||||
return Unexpected(HostFunctionError::LedgerObjNotFound);
|
||||
return cacheIdx + 1; // return 1-based index
|
||||
}
|
||||
|
||||
// Subsection: top level getters
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
WasmHostFunctionsImpl::getTxField(SField const& fname) const
|
||||
{
|
||||
return getAnyFieldData(ctx_.tx.peekAtPField(fname));
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
WasmHostFunctionsImpl::getCurrentLedgerObjField(SField const& fname) const
|
||||
{
|
||||
auto const sle = getCurrentLedgerObj();
|
||||
if (!sle.has_value())
|
||||
return Unexpected(sle.error());
|
||||
return getAnyFieldData(sle.value()->peekAtPField(fname));
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
WasmHostFunctionsImpl::getLedgerObjField(int32_t cacheIdx, SField const& fname) const
|
||||
{
|
||||
auto const normalizedIdx = normalizeCacheIndex(cacheIdx);
|
||||
if (!normalizedIdx.has_value())
|
||||
return Unexpected(normalizedIdx.error());
|
||||
return getAnyFieldData(cache_[normalizedIdx.value()]->peekAtPField(fname));
|
||||
}
|
||||
|
||||
// Subsection: nested getters
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
WasmHostFunctionsImpl::getTxNestedField(FieldLocator const& locator) const
|
||||
{
|
||||
auto const r = locateField(ctx_.tx, locator);
|
||||
if (!r)
|
||||
return Unexpected(r.error());
|
||||
|
||||
return getAnyFieldData(r.value());
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
WasmHostFunctionsImpl::getCurrentLedgerObjNestedField(FieldLocator const& locator) const
|
||||
{
|
||||
auto const sle = getCurrentLedgerObj();
|
||||
if (!sle.has_value())
|
||||
return Unexpected(sle.error());
|
||||
|
||||
auto const r = locateField(*sle.value(), locator);
|
||||
if (!r)
|
||||
return Unexpected(r.error());
|
||||
|
||||
return getAnyFieldData(r.value());
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
WasmHostFunctionsImpl::getLedgerObjNestedField(int32_t cacheIdx, FieldLocator const& locator) const
|
||||
{
|
||||
auto const normalizedIdx = normalizeCacheIndex(cacheIdx);
|
||||
if (!normalizedIdx.has_value())
|
||||
return Unexpected(normalizedIdx.error());
|
||||
|
||||
auto const r = locateField(*cache_[normalizedIdx.value()], locator);
|
||||
if (!r)
|
||||
return Unexpected(r.error());
|
||||
|
||||
return getAnyFieldData(r.value());
|
||||
}
|
||||
|
||||
// Subsection: array length getters
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
WasmHostFunctionsImpl::getTxArrayLen(SField const& fname) const
|
||||
{
|
||||
if (fname.fieldType != STI_ARRAY && fname.fieldType != STI_VECTOR256)
|
||||
return Unexpected(HostFunctionError::NoArray);
|
||||
|
||||
auto const* field = ctx_.tx.peekAtPField(fname);
|
||||
if (noField(field))
|
||||
return Unexpected(HostFunctionError::FieldNotFound);
|
||||
|
||||
return getArrayLen(field);
|
||||
}
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
WasmHostFunctionsImpl::getCurrentLedgerObjArrayLen(SField const& fname) const
|
||||
{
|
||||
if (fname.fieldType != STI_ARRAY && fname.fieldType != STI_VECTOR256)
|
||||
return Unexpected(HostFunctionError::NoArray);
|
||||
|
||||
auto const sle = getCurrentLedgerObj();
|
||||
if (!sle.has_value())
|
||||
return Unexpected(sle.error());
|
||||
|
||||
auto const* field = sle.value()->peekAtPField(fname);
|
||||
if (noField(field))
|
||||
return Unexpected(HostFunctionError::FieldNotFound);
|
||||
|
||||
return getArrayLen(field);
|
||||
}
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
WasmHostFunctionsImpl::getLedgerObjArrayLen(int32_t cacheIdx, SField const& fname) const
|
||||
{
|
||||
if (fname.fieldType != STI_ARRAY && fname.fieldType != STI_VECTOR256)
|
||||
return Unexpected(HostFunctionError::NoArray);
|
||||
|
||||
auto const normalizedIdx = normalizeCacheIndex(cacheIdx);
|
||||
if (!normalizedIdx.has_value())
|
||||
return Unexpected(normalizedIdx.error());
|
||||
|
||||
auto const* field = cache_[normalizedIdx.value()]->peekAtPField(fname);
|
||||
if (noField(field))
|
||||
return Unexpected(HostFunctionError::FieldNotFound);
|
||||
|
||||
return getArrayLen(field);
|
||||
}
|
||||
|
||||
// Subsection: nested array length getters
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
WasmHostFunctionsImpl::getTxNestedArrayLen(FieldLocator const& locator) const
|
||||
{
|
||||
auto const r = locateField(ctx_.tx, locator);
|
||||
if (!r)
|
||||
return Unexpected(r.error());
|
||||
|
||||
auto const& field = r.value();
|
||||
return getArrayLen(field);
|
||||
}
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
WasmHostFunctionsImpl::getCurrentLedgerObjNestedArrayLen(FieldLocator const& locator) const
|
||||
{
|
||||
auto const sle = getCurrentLedgerObj();
|
||||
if (!sle.has_value())
|
||||
return Unexpected(sle.error());
|
||||
auto const r = locateField(*sle.value(), locator);
|
||||
if (!r)
|
||||
return Unexpected(r.error());
|
||||
|
||||
auto const& field = r.value();
|
||||
return getArrayLen(field);
|
||||
}
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
WasmHostFunctionsImpl::getLedgerObjNestedArrayLen(int32_t cacheIdx, FieldLocator const& locator)
|
||||
const
|
||||
{
|
||||
auto const normalizedIdx = normalizeCacheIndex(cacheIdx);
|
||||
if (!normalizedIdx.has_value())
|
||||
return Unexpected(normalizedIdx.error());
|
||||
|
||||
auto const r = locateField(*cache_[normalizedIdx.value()], locator);
|
||||
if (!r)
|
||||
return Unexpected(r.error());
|
||||
|
||||
auto const& field = r.value();
|
||||
return getArrayLen(field);
|
||||
}
|
||||
|
||||
} // namespace xrpl
|
||||
222
src/libxrpl/tx/wasm/HostFuncImplKeylet.cpp
Normal file
222
src/libxrpl/tx/wasm/HostFuncImplKeylet.cpp
Normal file
@@ -0,0 +1,222 @@
|
||||
#include <xrpl/basics/Expected.h>
|
||||
#include <xrpl/basics/Slice.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/Asset.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/MPTIssue.h>
|
||||
#include <xrpl/protocol/Protocol.h>
|
||||
#include <xrpl/protocol/UintTypes.h>
|
||||
#include <xrpl/tx/wasm/HostFuncImpl.h>
|
||||
#include <xrpl/tx/wasm/WasmCommon.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
WasmHostFunctionsImpl::accountKeylet(AccountID const& account) const
|
||||
{
|
||||
if (!account)
|
||||
return Unexpected(HostFunctionError::InvalidAccount);
|
||||
auto const keylet = keylet::account(account);
|
||||
return Bytes{keylet.key.begin(), keylet.key.end()};
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
WasmHostFunctionsImpl::ammKeylet(Asset const& issue1, Asset const& issue2) const
|
||||
{
|
||||
if (issue1 == issue2)
|
||||
return Unexpected(HostFunctionError::InvalidParams);
|
||||
|
||||
// note: this should be removed with the MPT DEX amendment
|
||||
if (issue1.holds<MPTIssue>() || issue2.holds<MPTIssue>())
|
||||
return Unexpected(HostFunctionError::InvalidParams);
|
||||
|
||||
auto const keylet = keylet::amm(issue1, issue2);
|
||||
return Bytes{keylet.key.begin(), keylet.key.end()};
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
WasmHostFunctionsImpl::checkKeylet(AccountID const& account, std::uint32_t seq) const
|
||||
{
|
||||
if (!account)
|
||||
return Unexpected(HostFunctionError::InvalidAccount);
|
||||
auto const keylet = keylet::check(account, seq);
|
||||
return Bytes{keylet.key.begin(), keylet.key.end()};
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
WasmHostFunctionsImpl::credentialKeylet(
|
||||
AccountID const& subject,
|
||||
AccountID const& issuer,
|
||||
Slice const& credentialType) const
|
||||
{
|
||||
if (!subject || !issuer)
|
||||
return Unexpected(HostFunctionError::InvalidAccount);
|
||||
|
||||
if (credentialType.empty() || credentialType.size() > kMaxCredentialTypeLength)
|
||||
return Unexpected(HostFunctionError::InvalidParams);
|
||||
|
||||
auto const keylet = keylet::credential(subject, issuer, credentialType);
|
||||
|
||||
return Bytes{keylet.key.begin(), keylet.key.end()};
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
WasmHostFunctionsImpl::didKeylet(AccountID const& account) const
|
||||
{
|
||||
if (!account)
|
||||
return Unexpected(HostFunctionError::InvalidAccount);
|
||||
auto const keylet = keylet::did(account);
|
||||
return Bytes{keylet.key.begin(), keylet.key.end()};
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
WasmHostFunctionsImpl::delegateKeylet(AccountID const& account, AccountID const& authorize) const
|
||||
{
|
||||
if (!account || !authorize)
|
||||
return Unexpected(HostFunctionError::InvalidAccount);
|
||||
if (account == authorize)
|
||||
return Unexpected(HostFunctionError::InvalidParams);
|
||||
auto const keylet = keylet::delegate(account, authorize);
|
||||
return Bytes{keylet.key.begin(), keylet.key.end()};
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
WasmHostFunctionsImpl::depositPreauthKeylet(AccountID const& account, AccountID const& authorize)
|
||||
const
|
||||
{
|
||||
if (!account || !authorize)
|
||||
return Unexpected(HostFunctionError::InvalidAccount);
|
||||
if (account == authorize)
|
||||
return Unexpected(HostFunctionError::InvalidParams);
|
||||
auto const keylet = keylet::depositPreauth(account, authorize);
|
||||
return Bytes{keylet.key.begin(), keylet.key.end()};
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
WasmHostFunctionsImpl::escrowKeylet(AccountID const& account, std::uint32_t seq) const
|
||||
{
|
||||
if (!account)
|
||||
return Unexpected(HostFunctionError::InvalidAccount);
|
||||
auto const keylet = keylet::escrow(account, seq);
|
||||
return Bytes{keylet.key.begin(), keylet.key.end()};
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
WasmHostFunctionsImpl::lineKeylet(
|
||||
AccountID const& account1,
|
||||
AccountID const& account2,
|
||||
Currency const& currency) const
|
||||
{
|
||||
if (!account1 || !account2)
|
||||
return Unexpected(HostFunctionError::InvalidAccount);
|
||||
if (account1 == account2)
|
||||
return Unexpected(HostFunctionError::InvalidParams);
|
||||
if (currency.isZero())
|
||||
return Unexpected(HostFunctionError::InvalidParams);
|
||||
|
||||
auto const keylet = keylet::line(account1, account2, currency);
|
||||
return Bytes{keylet.key.begin(), keylet.key.end()};
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
WasmHostFunctionsImpl::mptIssuanceKeylet(AccountID const& issuer, std::uint32_t seq) const
|
||||
{
|
||||
if (!issuer)
|
||||
return Unexpected(HostFunctionError::InvalidAccount);
|
||||
|
||||
auto const keylet = keylet::mptIssuance(seq, issuer);
|
||||
return Bytes{keylet.key.begin(), keylet.key.end()};
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
WasmHostFunctionsImpl::mptokenKeylet(MPTID const& mptid, AccountID const& holder) const
|
||||
{
|
||||
if (!mptid)
|
||||
return Unexpected(HostFunctionError::InvalidParams);
|
||||
if (!holder)
|
||||
return Unexpected(HostFunctionError::InvalidAccount);
|
||||
|
||||
auto const keylet = keylet::mptoken(mptid, holder);
|
||||
return Bytes{keylet.key.begin(), keylet.key.end()};
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
WasmHostFunctionsImpl::nftOfferKeylet(AccountID const& account, std::uint32_t seq) const
|
||||
{
|
||||
if (!account)
|
||||
return Unexpected(HostFunctionError::InvalidAccount);
|
||||
auto const keylet = keylet::nftoffer(account, seq);
|
||||
return Bytes{keylet.key.begin(), keylet.key.end()};
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
WasmHostFunctionsImpl::offerKeylet(AccountID const& account, std::uint32_t seq) const
|
||||
{
|
||||
if (!account)
|
||||
return Unexpected(HostFunctionError::InvalidAccount);
|
||||
auto const keylet = keylet::offer(account, seq);
|
||||
return Bytes{keylet.key.begin(), keylet.key.end()};
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
WasmHostFunctionsImpl::oracleKeylet(AccountID const& account, std::uint32_t documentId) const
|
||||
{
|
||||
if (!account)
|
||||
return Unexpected(HostFunctionError::InvalidAccount);
|
||||
auto const keylet = keylet::oracle(account, documentId);
|
||||
return Bytes{keylet.key.begin(), keylet.key.end()};
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
WasmHostFunctionsImpl::paychanKeylet(
|
||||
AccountID const& account,
|
||||
AccountID const& destination,
|
||||
std::uint32_t seq) const
|
||||
{
|
||||
if (!account || !destination)
|
||||
return Unexpected(HostFunctionError::InvalidAccount);
|
||||
if (account == destination)
|
||||
return Unexpected(HostFunctionError::InvalidParams);
|
||||
auto const keylet = keylet::payChan(account, destination, seq);
|
||||
return Bytes{keylet.key.begin(), keylet.key.end()};
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
WasmHostFunctionsImpl::permissionedDomainKeylet(AccountID const& account, std::uint32_t seq) const
|
||||
{
|
||||
if (!account)
|
||||
return Unexpected(HostFunctionError::InvalidAccount);
|
||||
auto const keylet = keylet::permissionedDomain(account, seq);
|
||||
return Bytes{keylet.key.begin(), keylet.key.end()};
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
WasmHostFunctionsImpl::signersKeylet(AccountID const& account) const
|
||||
{
|
||||
if (!account)
|
||||
return Unexpected(HostFunctionError::InvalidAccount);
|
||||
auto const keylet = keylet::signers(account);
|
||||
return Bytes{keylet.key.begin(), keylet.key.end()};
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
WasmHostFunctionsImpl::ticketKeylet(AccountID const& account, std::uint32_t seq) const
|
||||
{
|
||||
if (!account)
|
||||
return Unexpected(HostFunctionError::InvalidAccount);
|
||||
auto const keylet = keylet::kTicket(account, seq);
|
||||
return Bytes{keylet.key.begin(), keylet.key.end()};
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
WasmHostFunctionsImpl::vaultKeylet(AccountID const& account, std::uint32_t seq) const
|
||||
{
|
||||
if (!account)
|
||||
return Unexpected(HostFunctionError::InvalidAccount);
|
||||
auto const keylet = keylet::vault(account, seq);
|
||||
return Bytes{keylet.key.begin(), keylet.key.end()};
|
||||
}
|
||||
|
||||
} // namespace xrpl
|
||||
55
src/libxrpl/tx/wasm/HostFuncImplLedgerHeader.cpp
Normal file
55
src/libxrpl/tx/wasm/HostFuncImplLedgerHeader.cpp
Normal file
@@ -0,0 +1,55 @@
|
||||
#include <xrpl/basics/Expected.h>
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/ledger/AmendmentTable.h>
|
||||
#include <xrpl/tx/wasm/HostFuncImpl.h>
|
||||
#include <xrpl/tx/wasm/WasmCommon.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
// =========================================================
|
||||
// SECTION: LEDGER HEADER FUNCTIONS
|
||||
// =========================================================
|
||||
|
||||
Expected<std::uint32_t, HostFunctionError>
|
||||
WasmHostFunctionsImpl::getLedgerSqn() const
|
||||
{
|
||||
return ctx_.view().seq();
|
||||
}
|
||||
|
||||
Expected<std::uint32_t, HostFunctionError>
|
||||
WasmHostFunctionsImpl::getParentLedgerTime() const
|
||||
{
|
||||
return ctx_.view().parentCloseTime().time_since_epoch().count();
|
||||
}
|
||||
|
||||
Expected<Hash, HostFunctionError>
|
||||
WasmHostFunctionsImpl::getParentLedgerHash() const
|
||||
{
|
||||
return ctx_.view().header().parentHash;
|
||||
}
|
||||
|
||||
Expected<std::uint32_t, HostFunctionError>
|
||||
WasmHostFunctionsImpl::getBaseFee() const
|
||||
{
|
||||
return ctx_.view().fees().base.drops();
|
||||
}
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
WasmHostFunctionsImpl::isAmendmentEnabled(uint256 const& amendmentId) const
|
||||
{
|
||||
return ctx_.view().rules().enabled(amendmentId);
|
||||
}
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
WasmHostFunctionsImpl::isAmendmentEnabled(std::string_view const& amendmentName) const
|
||||
{
|
||||
auto const& table = ctx_.registry.get().getAmendmentTable();
|
||||
auto const amendment = table.find(std::string(amendmentName));
|
||||
return ctx_.view().rules().enabled(amendment);
|
||||
}
|
||||
|
||||
} // namespace xrpl
|
||||
74
src/libxrpl/tx/wasm/HostFuncImplNFT.cpp
Normal file
74
src/libxrpl/tx/wasm/HostFuncImplNFT.cpp
Normal file
@@ -0,0 +1,74 @@
|
||||
#include <xrpl/basics/Expected.h>
|
||||
#include <xrpl/basics/Slice.h>
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/ledger/helpers/NFTokenHelpers.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/nft.h>
|
||||
#include <xrpl/tx/wasm/HostFuncImpl.h>
|
||||
#include <xrpl/tx/wasm/WasmCommon.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
// =========================================================
|
||||
// SECTION: NFT UTILS
|
||||
// =========================================================
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
WasmHostFunctionsImpl::getNFT(AccountID const& account, uint256 const& nftId) const
|
||||
{
|
||||
if (!account)
|
||||
return Unexpected(HostFunctionError::InvalidAccount);
|
||||
|
||||
if (!nftId)
|
||||
return Unexpected(HostFunctionError::InvalidParams);
|
||||
|
||||
auto obj = nft::findToken(ctx_.view(), account, nftId);
|
||||
if (!obj)
|
||||
return Unexpected(HostFunctionError::LedgerObjNotFound);
|
||||
|
||||
auto objUri = obj->at(~sfURI);
|
||||
if (!objUri)
|
||||
return Unexpected(HostFunctionError::FieldNotFound);
|
||||
|
||||
Slice const s = objUri->value();
|
||||
return Bytes(s.begin(), s.end());
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
WasmHostFunctionsImpl::getNFTIssuer(uint256 const& nftId) const
|
||||
{
|
||||
auto const issuer = nft::getIssuer(nftId);
|
||||
if (!issuer)
|
||||
return Unexpected(HostFunctionError::InvalidParams);
|
||||
|
||||
return Bytes{issuer.begin(), issuer.end()};
|
||||
}
|
||||
|
||||
Expected<std::uint32_t, HostFunctionError>
|
||||
WasmHostFunctionsImpl::getNFTTaxon(uint256 const& nftId) const
|
||||
{
|
||||
return nft::toUInt32(nft::getTaxon(nftId));
|
||||
}
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
WasmHostFunctionsImpl::getNFTFlags(uint256 const& nftId) const
|
||||
{
|
||||
return nft::getFlags(nftId);
|
||||
}
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
WasmHostFunctionsImpl::getNFTTransferFee(uint256 const& nftId) const
|
||||
{
|
||||
return nft::getTransferFee(nftId);
|
||||
}
|
||||
|
||||
Expected<std::uint32_t, HostFunctionError>
|
||||
WasmHostFunctionsImpl::getNFTSerial(uint256 const& nftId) const
|
||||
{
|
||||
return nft::getSerial(nftId);
|
||||
}
|
||||
|
||||
} // namespace xrpl
|
||||
71
src/libxrpl/tx/wasm/HostFuncImplTrace.cpp
Normal file
71
src/libxrpl/tx/wasm/HostFuncImplTrace.cpp
Normal file
@@ -0,0 +1,71 @@
|
||||
#include <xrpl/basics/Expected.h>
|
||||
#include <xrpl/basics/Slice.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/STAmount.h>
|
||||
#include <xrpl/tx/wasm/HostFunc.h>
|
||||
#include <xrpl/tx/wasm/HostFuncImpl.h>
|
||||
|
||||
#include <boost/algorithm/hex.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#ifdef _DEBUG
|
||||
// #define DEBUG_OUTPUT 1
|
||||
#endif
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
WasmHostFunctionsImpl::trace(std::string_view const& msg, Slice const& data, bool asHex) const
|
||||
{
|
||||
if (!asHex)
|
||||
{
|
||||
log(msg, [&data] {
|
||||
return std::string_view(reinterpret_cast<char const*>(data.data()), data.size());
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
log(msg, [&data] {
|
||||
std::string hex;
|
||||
hex.reserve(data.size() * 2);
|
||||
boost::algorithm::hex(data.begin(), data.end(), std::back_inserter(hex));
|
||||
return hex;
|
||||
});
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
WasmHostFunctionsImpl::traceNum(std::string_view const& msg, int64_t data) const
|
||||
{
|
||||
log(msg, [data] { return data; });
|
||||
return 0;
|
||||
}
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
WasmHostFunctionsImpl::traceAccount(std::string_view const& msg, AccountID const& account) const
|
||||
{
|
||||
log(msg, [&account] { return toBase58(account); });
|
||||
return 0;
|
||||
}
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
WasmHostFunctionsImpl::traceFloat(std::string_view const& msg, Slice const& data) const
|
||||
{
|
||||
log(msg, [&data] { return wasm_float::floatToString(data); });
|
||||
return 0;
|
||||
}
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
WasmHostFunctionsImpl::traceAmount(std::string_view const& msg, STAmount const& amount) const
|
||||
{
|
||||
log(msg, [&amount] { return amount.getFullText(); });
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace xrpl
|
||||
1834
src/libxrpl/tx/wasm/HostFuncWrapper.cpp
Normal file
1834
src/libxrpl/tx/wasm/HostFuncWrapper.cpp
Normal file
File diff suppressed because it is too large
Load Diff
216
src/libxrpl/tx/wasm/WasmVM.cpp
Normal file
216
src/libxrpl/tx/wasm/WasmVM.cpp
Normal file
@@ -0,0 +1,216 @@
|
||||
#include <xrpl/tx/wasm/WasmVM.h>
|
||||
|
||||
#include <xrpl/basics/Expected.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
#include <xrpl/tx/wasm/HostFuncWrapper.h> // IWYU pragma: keep
|
||||
#include <xrpl/tx/wasm/WasmCommon.h>
|
||||
#include <xrpl/tx/wasm/WasmImportsHelper.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#ifdef _DEBUG
|
||||
// #define DEBUG_OUTPUT 1
|
||||
#endif
|
||||
|
||||
#include <xrpl/tx/wasm/HostFunc.h>
|
||||
#include <xrpl/tx/wasm/WasmiVM.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace xrpl {
|
||||
// WARNING: Per XLS-0102, the host functions registered here form a stable
|
||||
// ABI. Their name, semantics, parameters, and return types must NEVER be
|
||||
// changed, as there may always be a program that uses it. New host functions
|
||||
// may be added and existing gas costs may be adjusted, but every such change
|
||||
// must be gated by an amendment.
|
||||
// See XLS-0102 §6.5 (Future-Proofing):
|
||||
// https://github.com/XRPLF/XRPL-Standards/tree/master/XLS-0102-wasm-vm#65-future-proofing
|
||||
static void
|
||||
setCommonHostFunctions(HostFunctions& hfs, ImportVec& i)
|
||||
{
|
||||
// clang-format off
|
||||
WASM_IMPORT_FUNC2(i, getLedgerSqn, "ldgr_index", hfs, 60);
|
||||
WASM_IMPORT_FUNC2(i, getParentLedgerTime, "parent_ldgr_time", hfs, 60);
|
||||
WASM_IMPORT_FUNC2(i, getParentLedgerHash, "parent_ldgr_hash", hfs, 60);
|
||||
WASM_IMPORT_FUNC2(i, getBaseFee, "base_fee", hfs, 60);
|
||||
WASM_IMPORT_FUNC2(i, isAmendmentEnabled, "amendment_enabled", hfs, 100);
|
||||
|
||||
WASM_IMPORT_FUNC2(i, cacheLedgerObj, "cache_le", hfs, 5'000);
|
||||
WASM_IMPORT_FUNC2(i, getTxField, "tx_field", hfs, 70);
|
||||
WASM_IMPORT_FUNC2(i, getCurrentLedgerObjField, "home_le_field", hfs, 70);
|
||||
WASM_IMPORT_FUNC2(i, getLedgerObjField, "le_field", hfs, 70);
|
||||
WASM_IMPORT_FUNC2(i, getTxNestedField, "tx_inner", hfs, 110);
|
||||
WASM_IMPORT_FUNC2(i, getCurrentLedgerObjNestedField, "home_le_inner", hfs, 110);
|
||||
WASM_IMPORT_FUNC2(i, getLedgerObjNestedField, "le_inner", hfs, 110);
|
||||
WASM_IMPORT_FUNC2(i, getTxArrayLen, "tx_arr_len", hfs, 40);
|
||||
WASM_IMPORT_FUNC2(i, getCurrentLedgerObjArrayLen, "home_le_arr_len", hfs, 40);
|
||||
WASM_IMPORT_FUNC2(i, getLedgerObjArrayLen, "le_arr_len", hfs, 40);
|
||||
WASM_IMPORT_FUNC2(i, getTxNestedArrayLen, "tx_inner_arr_len", hfs, 70);
|
||||
WASM_IMPORT_FUNC2(i, getCurrentLedgerObjNestedArrayLen, "home_le_inner_arr_len", hfs, 70);
|
||||
WASM_IMPORT_FUNC2(i, getLedgerObjNestedArrayLen, "le_inner_arr_len", hfs, 70);
|
||||
|
||||
WASM_IMPORT_FUNC2(i, checkSignature, "check_sig", hfs, 300);
|
||||
WASM_IMPORT_FUNC2(i, computeSha512HalfHash, "sha512_half", hfs, 2000);
|
||||
|
||||
WASM_IMPORT_FUNC2(i, accountKeylet, "accountroot_id", hfs, 350);
|
||||
WASM_IMPORT_FUNC2(i, ammKeylet, "amm_id", hfs, 450);
|
||||
WASM_IMPORT_FUNC2(i, checkKeylet, "check_id", hfs, 350);
|
||||
WASM_IMPORT_FUNC2(i, credentialKeylet, "credential_id", hfs, 350);
|
||||
WASM_IMPORT_FUNC2(i, delegateKeylet, "delegate_id", hfs, 350);
|
||||
WASM_IMPORT_FUNC2(i, depositPreauthKeylet, "deposit_preauth_id", hfs, 350);
|
||||
WASM_IMPORT_FUNC2(i, didKeylet, "did_id", hfs, 350);
|
||||
WASM_IMPORT_FUNC2(i, escrowKeylet, "escrow_id", hfs, 350);
|
||||
WASM_IMPORT_FUNC2(i, lineKeylet, "trustline_id", hfs, 400);
|
||||
WASM_IMPORT_FUNC2(i, mptIssuanceKeylet, "mpt_issuance_id", hfs, 350);
|
||||
WASM_IMPORT_FUNC2(i, mptokenKeylet, "mptoken_id", hfs, 500);
|
||||
WASM_IMPORT_FUNC2(i, nftOfferKeylet, "nft_offer_id", hfs, 350);
|
||||
WASM_IMPORT_FUNC2(i, offerKeylet, "offer_id", hfs, 350);
|
||||
WASM_IMPORT_FUNC2(i, oracleKeylet, "oracle_id", hfs, 350);
|
||||
WASM_IMPORT_FUNC2(i, paychanKeylet, "paychan_id", hfs, 350);
|
||||
WASM_IMPORT_FUNC2(i, permissionedDomainKeylet, "permissioned_domain_id", hfs, 350);
|
||||
WASM_IMPORT_FUNC2(i, signersKeylet, "signers_id", hfs, 350);
|
||||
WASM_IMPORT_FUNC2(i, ticketKeylet, "ticket_id", hfs, 350);
|
||||
WASM_IMPORT_FUNC2(i, vaultKeylet, "vault_id", hfs, 350);
|
||||
|
||||
WASM_IMPORT_FUNC2(i, getNFT, "nft_uri", hfs, 5'000);
|
||||
WASM_IMPORT_FUNC2(i, getNFTIssuer, "nft_issuer", hfs, 70);
|
||||
WASM_IMPORT_FUNC2(i, getNFTTaxon, "nft_taxon", hfs, 60);
|
||||
WASM_IMPORT_FUNC2(i, getNFTFlags, "nft_flags", hfs, 60);
|
||||
WASM_IMPORT_FUNC2(i, getNFTTransferFee, "nft_xfer_fee", hfs, 60);
|
||||
WASM_IMPORT_FUNC2(i, getNFTSerial, "nft_serial", hfs, 60);
|
||||
|
||||
WASM_IMPORT_FUNC (i, trace, hfs, 500);
|
||||
WASM_IMPORT_FUNC2(i, traceNum, "trace_num", hfs, 500);
|
||||
WASM_IMPORT_FUNC2(i, traceAccount, "trace_acct", hfs, 500);
|
||||
WASM_IMPORT_FUNC2(i, traceFloat, "trace_xfloat", hfs, 500);
|
||||
WASM_IMPORT_FUNC2(i, traceAmount, "trace_amt", hfs, 500);
|
||||
|
||||
WASM_IMPORT_FUNC2(i, floatFromInt, "float_from_int", hfs, 100);
|
||||
WASM_IMPORT_FUNC2(i, floatFromUint, "float_from_uint", hfs, 130);
|
||||
WASM_IMPORT_FUNC2(i, floatFromSTAmount, "float_from_stamount", hfs, 150);
|
||||
WASM_IMPORT_FUNC2(i, floatFromSTNumber, "float_from_stnumber", hfs, 150);
|
||||
WASM_IMPORT_FUNC2(i, floatToInt, "float_to_int", hfs, 130);
|
||||
WASM_IMPORT_FUNC2(i, floatToMantExp, "float_to_mant_exp", hfs, 130);
|
||||
WASM_IMPORT_FUNC2(i, floatFromMantExp, "float_from_mant_exp", hfs, 100);
|
||||
WASM_IMPORT_FUNC2(i, floatCompare, "float_cmp", hfs, 80);
|
||||
WASM_IMPORT_FUNC2(i, floatAdd, "float_add", hfs, 160);
|
||||
WASM_IMPORT_FUNC2(i, floatSubtract, "float_sub", hfs, 160);
|
||||
WASM_IMPORT_FUNC2(i, floatMultiply, "float_mult", hfs, 300);
|
||||
WASM_IMPORT_FUNC2(i, floatDivide, "float_div", hfs, 300);
|
||||
WASM_IMPORT_FUNC2(i, floatRoot, "float_root", hfs, 5'500);
|
||||
WASM_IMPORT_FUNC2(i, floatPower, "float_pow", hfs, 5'500);
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
ImportVec
|
||||
createWasmImport(HostFunctions& hfs)
|
||||
{
|
||||
ImportVec i;
|
||||
|
||||
setCommonHostFunctions(hfs, i);
|
||||
WASM_IMPORT_FUNC2(i, updateData, "set_data", hfs, 1000);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
Expected<EscrowResult, TER>
|
||||
runEscrowWasm(
|
||||
Bytes const& wasmCode,
|
||||
HostFunctions& hfs,
|
||||
int64_t gasLimit,
|
||||
std::string_view funcName,
|
||||
std::vector<WasmParam> const& params)
|
||||
{
|
||||
// create VM and set cost limit
|
||||
auto& vm = WasmEngine::instance();
|
||||
// vm.initMaxPages(MAX_PAGES);
|
||||
|
||||
auto const ret =
|
||||
vm.run(wasmCode, hfs, gasLimit, funcName, params, createWasmImport(hfs), hfs.getJournal());
|
||||
|
||||
if (!ret)
|
||||
{
|
||||
#ifdef DEBUG_OUTPUT
|
||||
std::cout << ", error: " << ret.error() << std::endl;
|
||||
#endif
|
||||
return Unexpected<TER>(ret.error());
|
||||
}
|
||||
|
||||
#ifdef DEBUG_OUTPUT
|
||||
std::cout << ", ret: " << ret->result << ", gas spent: " << ret->cost << std::endl;
|
||||
#endif
|
||||
return EscrowResult{.result = ret->result, .cost = ret->cost};
|
||||
}
|
||||
|
||||
NotTEC
|
||||
preflightEscrowWasm(
|
||||
Bytes const& wasmCode,
|
||||
HostFunctions& hfs,
|
||||
std::string_view funcName,
|
||||
std::vector<WasmParam> const& params)
|
||||
{
|
||||
// create VM and set cost limit
|
||||
auto& vm = WasmEngine::instance();
|
||||
// vm.initMaxPages(MAX_PAGES);
|
||||
|
||||
auto const ret =
|
||||
vm.check(wasmCode, hfs, funcName, params, createWasmImport(hfs), hfs.getJournal());
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
WasmEngine::WasmEngine() : impl_(std::make_unique<WasmiEngine>())
|
||||
{
|
||||
}
|
||||
|
||||
WasmEngine&
|
||||
WasmEngine::instance()
|
||||
{
|
||||
static WasmEngine e;
|
||||
return e;
|
||||
}
|
||||
|
||||
Expected<WasmResult<int32_t>, TER>
|
||||
WasmEngine::run(
|
||||
Bytes const& wasmCode,
|
||||
HostFunctions& hfs,
|
||||
int64_t gasLimit,
|
||||
std::string_view funcName,
|
||||
std::vector<WasmParam> const& params,
|
||||
ImportVec const& imports,
|
||||
beast::Journal j)
|
||||
{
|
||||
return impl_->run(wasmCode, hfs, gasLimit, funcName, params, imports, j);
|
||||
}
|
||||
|
||||
NotTEC
|
||||
WasmEngine::check(
|
||||
Bytes const& wasmCode,
|
||||
HostFunctions& hfs,
|
||||
std::string_view funcName,
|
||||
std::vector<WasmParam> const& params,
|
||||
ImportVec const& imports,
|
||||
beast::Journal j)
|
||||
{
|
||||
return impl_->check(wasmCode, hfs, funcName, params, imports, j);
|
||||
}
|
||||
|
||||
void*
|
||||
WasmEngine::newTrap(std::string const& msg)
|
||||
{
|
||||
return impl_->newTrap(msg);
|
||||
}
|
||||
|
||||
// LCOV_EXCL_START
|
||||
beast::Journal
|
||||
WasmEngine::getJournal() const
|
||||
{
|
||||
return impl_->getJournal();
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
} // namespace xrpl
|
||||
865
src/libxrpl/tx/wasm/WasmiVM.cpp
Normal file
865
src/libxrpl/tx/wasm/WasmiVM.cpp
Normal file
@@ -0,0 +1,865 @@
|
||||
#include <xrpl/tx/wasm/WasmiVM.h>
|
||||
|
||||
#include <xrpl/basics/Expected.h>
|
||||
#include <xrpl/basics/contract.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
#include <xrpl/tx/wasm/HostFunc.h>
|
||||
#include <xrpl/tx/wasm/WasmCommon.h>
|
||||
#include <xrpl/tx/wasm/WasmImportsHelper.h>
|
||||
#include <xrpl/tx/wasm/WasmVM.h>
|
||||
|
||||
#include <wasmi/config.h>
|
||||
#include <wasmi/error.h>
|
||||
|
||||
#include <wasm.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <exception>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#ifdef _DEBUG
|
||||
// #define DEBUG_OUTPUT 1
|
||||
#endif
|
||||
// #define SHOW_CALL_TIME 1
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
wasm_trap_t*
|
||||
HostFuncMain_wrap(void* env, wasm_val_vec_t const* params, wasm_val_vec_t* results);
|
||||
|
||||
namespace {
|
||||
|
||||
void
|
||||
printWasmError(std::string_view msg, wasm_trap_t* trap, beast::Journal jlog)
|
||||
{
|
||||
#ifdef DEBUG_OUTPUT
|
||||
auto& j = std::cerr;
|
||||
#else
|
||||
auto j = jlog.warn();
|
||||
if (jlog.active(beast::Severity::Warning))
|
||||
#endif
|
||||
{
|
||||
wasm_byte_vec_t errorMessage WASM_EMPTY_VEC;
|
||||
|
||||
if (trap != nullptr)
|
||||
wasm_trap_message(trap, &errorMessage);
|
||||
|
||||
if (errorMessage.size != 0u)
|
||||
{
|
||||
j << "WASMI Error: " << msg << ", "
|
||||
<< std::string_view(errorMessage.data, errorMessage.size - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
j << "WASMI Error: " << msg;
|
||||
}
|
||||
|
||||
if (errorMessage.size != 0u)
|
||||
wasm_byte_vec_delete(&errorMessage);
|
||||
}
|
||||
|
||||
if (trap != nullptr)
|
||||
wasm_trap_delete(trap);
|
||||
|
||||
#ifdef DEBUG_OUTPUT
|
||||
j << std::endl;
|
||||
#endif
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
} // namespace
|
||||
|
||||
class WasmiRuntimeWrapper : public WasmRuntimeWrapper
|
||||
{
|
||||
InstanceWrapper& iw_;
|
||||
|
||||
public:
|
||||
WasmiRuntimeWrapper(InstanceWrapper& iw) : iw_(iw)
|
||||
{
|
||||
}
|
||||
|
||||
Wmem
|
||||
getMem() override
|
||||
{
|
||||
return iw_.getMem();
|
||||
}
|
||||
|
||||
std::int64_t
|
||||
getGas() override
|
||||
{
|
||||
return iw_.getGas();
|
||||
}
|
||||
|
||||
std::int64_t
|
||||
setGas(std::int64_t gas) override
|
||||
{
|
||||
return iw_.setGas(gas);
|
||||
}
|
||||
};
|
||||
|
||||
InstancePtr
|
||||
InstanceWrapper::init(
|
||||
StorePtr& s,
|
||||
ModulePtr& m,
|
||||
WasmExternVec& expt,
|
||||
WasmExternVec const& imports,
|
||||
beast::Journal j)
|
||||
{
|
||||
wasm_trap_t* trap = nullptr;
|
||||
InstancePtr mi = InstancePtr(
|
||||
wasm_instance_new(s.get(), m.get(), imports.get(), &trap), &wasm_instance_delete);
|
||||
|
||||
if (!mi || (trap != nullptr))
|
||||
{
|
||||
printWasmError("can't create instance", trap, j);
|
||||
Throw<std::runtime_error>("can't create instance");
|
||||
}
|
||||
wasm_instance_exports(mi.get(), expt.get());
|
||||
return mi;
|
||||
}
|
||||
|
||||
InstanceWrapper&
|
||||
InstanceWrapper::operator=(InstanceWrapper&& o)
|
||||
{
|
||||
if (this == &o)
|
||||
return *this; // LCOV_EXCL_LINE
|
||||
|
||||
store_ = o.store_;
|
||||
o.store_ = nullptr;
|
||||
exports_ = std::move(o.exports_);
|
||||
memIdx_ = o.memIdx_;
|
||||
o.memIdx_ = -1;
|
||||
instance_ = std::move(o.instance_);
|
||||
|
||||
j_ = o.j_;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
FuncInfo
|
||||
InstanceWrapper::getFunc(std::string_view funcName, WasmExporttypeVec const& exportTypes) const
|
||||
{
|
||||
wasm_func_t const* f = nullptr;
|
||||
wasm_functype_t const* ft = nullptr;
|
||||
|
||||
if (!instance_)
|
||||
Throw<std::runtime_error>("no instance"); // LCOV_EXCL_LINE
|
||||
|
||||
if (exportTypes.empty())
|
||||
Throw<std::runtime_error>("no export"); // LCOV_EXCL_LINE
|
||||
if (exportTypes.size() != exports_.size())
|
||||
Throw<std::runtime_error>("invalid export"); // LCOV_EXCL_LINE
|
||||
|
||||
for (unsigned i = 0; i < exportTypes.size(); ++i)
|
||||
{
|
||||
auto const* expType(exportTypes[i]);
|
||||
|
||||
wasm_name_t const* name = wasm_exporttype_name(expType);
|
||||
wasm_externtype_t const* exnType = wasm_exporttype_type(expType);
|
||||
if (wasm_externtype_kind(exnType) == WASM_EXTERN_FUNC)
|
||||
{
|
||||
if (funcName != std::string_view(name->data, name->size))
|
||||
continue;
|
||||
|
||||
auto const* exn(exports_[i]);
|
||||
if (wasm_extern_kind(exn) != WASM_EXTERN_FUNC)
|
||||
Throw<std::runtime_error>("invalid export"); // LCOV_EXCL_LINE
|
||||
|
||||
ft = wasm_externtype_as_functype_const(exnType);
|
||||
f = wasm_extern_as_func_const(exn);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((f == nullptr) || (ft == nullptr))
|
||||
Throw<std::runtime_error>("can't find function <" + std::string(funcName) + ">");
|
||||
|
||||
return {f, ft};
|
||||
}
|
||||
|
||||
Wmem
|
||||
InstanceWrapper::getMem() const
|
||||
{
|
||||
if (memIdx_ >= 0)
|
||||
{
|
||||
auto* e(exports_[memIdx_]);
|
||||
wasm_memory_t* mem = wasm_extern_as_memory(e);
|
||||
return Wmem(wasm_memory_data(mem), wasm_memory_data_size(mem));
|
||||
}
|
||||
|
||||
wasm_memory_t* mem = nullptr;
|
||||
for (int i = 0; i < exports_.size(); ++i)
|
||||
{
|
||||
auto* e(exports_[i]);
|
||||
if (wasm_extern_kind(e) == WASM_EXTERN_MEMORY)
|
||||
{
|
||||
memIdx_ = i;
|
||||
mem = wasm_extern_as_memory(e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (mem == nullptr)
|
||||
return {}; // LCOV_EXCL_LINE
|
||||
|
||||
return Wmem(wasm_memory_data(mem), wasm_memory_data_size(mem));
|
||||
}
|
||||
|
||||
std::int64_t
|
||||
InstanceWrapper::getGas() const
|
||||
{
|
||||
if (store_ == nullptr)
|
||||
return -1; // LCOV_EXCL_LINE
|
||||
std::uint64_t gas = 0;
|
||||
wasm_store_get_fuel(store_, &gas);
|
||||
return static_cast<std::int64_t>(gas);
|
||||
}
|
||||
|
||||
std::int64_t
|
||||
InstanceWrapper::setGas(std::int64_t gas) const
|
||||
{
|
||||
if (store_ == nullptr)
|
||||
return -1; // LCOV_EXCL_LINE
|
||||
|
||||
if (gas < 0)
|
||||
gas = std::numeric_limits<decltype(gas)>::max();
|
||||
wasmi_error_t* err = wasm_store_set_fuel(store_, static_cast<std::uint64_t>(gas));
|
||||
if (err != nullptr)
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
printWasmError("Can't set instance gas", nullptr, j_);
|
||||
wasmi_error_delete(err);
|
||||
return -1;
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
return gas;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ModulePtr
|
||||
ModuleWrapper::init(StorePtr& s, Bytes const& wasmBin, beast::Journal j)
|
||||
{
|
||||
wasm_byte_vec_t const code{.size = wasmBin.size(), .data = (char*)(wasmBin.data())};
|
||||
ModulePtr m = ModulePtr(wasm_module_new(s.get(), &code), &wasm_module_delete);
|
||||
if (!m)
|
||||
throw std::runtime_error("can't create module");
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
ModuleWrapper::ModuleWrapper(
|
||||
StorePtr& s,
|
||||
Bytes const& wasmBin,
|
||||
bool instantiate,
|
||||
ImportVec const& imports,
|
||||
beast::Journal j)
|
||||
: module_(init(s, wasmBin, j)), j_(j)
|
||||
{
|
||||
wasm_module_exports(module_.get(), exportTypes_.get());
|
||||
auto wimports = buildImports(s, imports);
|
||||
if (instantiate)
|
||||
{
|
||||
addInstance(s, wimports);
|
||||
}
|
||||
}
|
||||
|
||||
// LCOV_EXCL_START
|
||||
ModuleWrapper&
|
||||
ModuleWrapper::operator=(ModuleWrapper&& o)
|
||||
{
|
||||
if (this == &o)
|
||||
return *this;
|
||||
|
||||
module_ = std::move(o.module_);
|
||||
instanceWrap_ = std::move(o.instanceWrap_);
|
||||
exportTypes_ = std::move(o.exportTypes_);
|
||||
j_ = o.j_;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
static WasmValtypeVec
|
||||
makeImpParams(WasmImportFunc const& imp)
|
||||
{
|
||||
auto const paramSize = imp.params.size();
|
||||
if (paramSize == 0u)
|
||||
return {};
|
||||
|
||||
WasmValtypeVec v(paramSize);
|
||||
|
||||
for (unsigned i = 0; i < paramSize; ++i)
|
||||
{
|
||||
auto const vt = imp.params[i];
|
||||
switch (vt)
|
||||
{
|
||||
case WasmTypes::WtI32:
|
||||
v[i] = wasm_valtype_new_i32();
|
||||
break;
|
||||
case WasmTypes::WtI64:
|
||||
v[i] = wasm_valtype_new_i64();
|
||||
break;
|
||||
// LCOV_EXCL_START
|
||||
default:
|
||||
throw std::runtime_error("invalid import type");
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
static WasmValtypeVec
|
||||
makeImpReturn(WasmImportFunc const& imp)
|
||||
{
|
||||
if (!imp.result)
|
||||
return {}; // LCOV_EXCL_LINE
|
||||
|
||||
WasmValtypeVec v(1);
|
||||
switch (*imp.result)
|
||||
{
|
||||
case WasmTypes::WtI32:
|
||||
v[0] = wasm_valtype_new_i32();
|
||||
break;
|
||||
// LCOV_EXCL_START
|
||||
case WasmTypes::WtI64:
|
||||
v[0] = wasm_valtype_new_i64();
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("invalid return type");
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
WasmExternVec
|
||||
ModuleWrapper::buildImports(StorePtr& s, ImportVec const& imports) const
|
||||
{
|
||||
WasmImporttypeVec importTypes;
|
||||
wasm_module_imports(module_.get(), importTypes.get());
|
||||
|
||||
if (importTypes.empty())
|
||||
return {};
|
||||
if (imports.empty())
|
||||
Throw<std::runtime_error>("Empty imports");
|
||||
|
||||
WasmExternVec wimports(importTypes.size());
|
||||
|
||||
unsigned impCnt = 0;
|
||||
for (unsigned i = 0; i < importTypes.size(); ++i)
|
||||
{
|
||||
wasm_importtype_t const* importType = importTypes[i];
|
||||
|
||||
// wasm_name_t const* mn = wasm_importtype_module(importtype);
|
||||
// auto modName = std::string_view(mn->data, mn->num_elems);
|
||||
wasm_name_t const* fn = wasm_importtype_name(importType);
|
||||
auto fieldName = std::string_view(fn->data, fn->size);
|
||||
|
||||
wasm_externkind_t const itype = wasm_externtype_kind(wasm_importtype_type(importType));
|
||||
if ((itype) != WASM_EXTERN_FUNC)
|
||||
{
|
||||
Throw<std::runtime_error>(
|
||||
"Invalid import type " + std::to_string(itype)); // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
// for multi-module support
|
||||
// if ((W_ENV != modName) && (W_HOST_LIB != modName))
|
||||
// continue;
|
||||
|
||||
auto const it = imports.find(fieldName);
|
||||
if (it == imports.end())
|
||||
{
|
||||
printWasmError("Import not found: " + std::string(fieldName), nullptr, j_);
|
||||
continue; // print all missed import
|
||||
}
|
||||
|
||||
WasmUserData const& obj = it->second;
|
||||
WasmImportFunc const& imp = obj.second;
|
||||
|
||||
WasmValtypeVec params(makeImpParams(imp));
|
||||
WasmValtypeVec results(makeImpReturn(imp));
|
||||
|
||||
std::unique_ptr<wasm_functype_t, decltype(&wasm_functype_delete)> const ftype(
|
||||
wasm_functype_new(params.get(), results.get()), &wasm_functype_delete);
|
||||
|
||||
params.release();
|
||||
results.release();
|
||||
|
||||
wasm_func_t* func =
|
||||
wasm_func_new_with_env(s.get(), ftype.get(), HostFuncMain_wrap, (void*)&obj, nullptr);
|
||||
if (func == nullptr)
|
||||
{
|
||||
Throw<std::runtime_error>(
|
||||
"can't create import function " + std::string(imp.name)); // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
wimports[i] = wasm_func_as_extern(func);
|
||||
++impCnt;
|
||||
}
|
||||
|
||||
if (impCnt != importTypes.size())
|
||||
{
|
||||
printWasmError(
|
||||
std::string("Imports not finished: ") + std::to_string(impCnt) + "/" +
|
||||
std::to_string(importTypes.size()),
|
||||
nullptr,
|
||||
j_);
|
||||
Throw<std::runtime_error>("Missing imports");
|
||||
}
|
||||
|
||||
return wimports;
|
||||
}
|
||||
|
||||
wasm_functype_t*
|
||||
ModuleWrapper::getFuncType(std::string_view funcName) const
|
||||
{
|
||||
for (size_t i = 0; i < exportTypes_.size(); i++)
|
||||
{
|
||||
auto const* expType(exportTypes_[i]);
|
||||
wasm_name_t const* name = wasm_exporttype_name(expType);
|
||||
wasm_externtype_t const* exnType = wasm_exporttype_type(expType);
|
||||
if (wasm_externtype_kind(exnType) == WASM_EXTERN_FUNC &&
|
||||
funcName == std::string_view(name->data, name->size))
|
||||
{
|
||||
return wasm_externtype_as_functype(const_cast<wasm_externtype_t*>(exnType));
|
||||
}
|
||||
}
|
||||
|
||||
throw std::runtime_error("can't find function <" + std::string(funcName) + ">");
|
||||
}
|
||||
|
||||
// int
|
||||
// my_module_t::delInstance(int i)
|
||||
// {
|
||||
// if (i >= mod_inst.size())
|
||||
// return -1;
|
||||
// if (!mod_inst[i])
|
||||
// mod_inst[i] = my_mod_inst_t();
|
||||
// return i;
|
||||
// }
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// void
|
||||
// WasmiEngine::clearModules()
|
||||
// {
|
||||
// modules.clear();
|
||||
// store.reset(); // to free the memory before creating new store
|
||||
// store = {wasm_store_new(engine.get()), &wasm_store_delete};
|
||||
// }
|
||||
|
||||
std::unique_ptr<wasm_engine_t, decltype(&wasm_engine_delete)>
|
||||
WasmiEngine::init()
|
||||
{
|
||||
wasm_config_t* config = wasm_config_new();
|
||||
if (config == nullptr)
|
||||
{
|
||||
return std::unique_ptr<wasm_engine_t, decltype(&wasm_engine_delete)>{
|
||||
nullptr, &wasm_engine_delete}; // LCOV_EXCL_LINE
|
||||
}
|
||||
wasmi_config_consume_fuel_set(config, true);
|
||||
wasmi_config_ignore_custom_sections_set(config, true);
|
||||
wasmi_config_wasm_mutable_globals_set(config, false);
|
||||
wasmi_config_wasm_multi_value_set(config, false);
|
||||
wasmi_config_wasm_sign_extension_set(config, false);
|
||||
wasmi_config_wasm_saturating_float_to_int_set(config, false);
|
||||
wasmi_config_wasm_bulk_memory_set(config, false);
|
||||
wasmi_config_wasm_reference_types_set(config, false);
|
||||
wasmi_config_wasm_tail_call_set(config, false);
|
||||
wasmi_config_wasm_extended_const_set(config, false);
|
||||
wasmi_config_floats_set(config, false);
|
||||
wasmi_config_wasm_multi_memory_set(config, false);
|
||||
wasmi_config_wasm_custom_page_sizes_set(config, false);
|
||||
wasmi_config_wasm_memory64_set(config, false);
|
||||
wasmi_config_wasm_wide_arithmetic_set(config, false);
|
||||
|
||||
return std::unique_ptr<wasm_engine_t, decltype(&wasm_engine_delete)>(
|
||||
wasm_engine_new_with_config(config), &wasm_engine_delete);
|
||||
}
|
||||
|
||||
int
|
||||
WasmiEngine::addModule(
|
||||
Bytes const& wasmCode,
|
||||
bool instantiate,
|
||||
ImportVec const& imports,
|
||||
int64_t gas)
|
||||
{
|
||||
moduleWrap_.reset();
|
||||
store_.reset(); // to free the memory before creating new store
|
||||
store_ = {wasm_store_new_with_memory_max_pages(engine_.get(), maxPages), &wasm_store_delete};
|
||||
|
||||
if (gas < 0)
|
||||
gas = std::numeric_limits<decltype(gas)>::max();
|
||||
wasmi_error_t* err = wasm_store_set_fuel(store_.get(), static_cast<std::uint64_t>(gas));
|
||||
if (err != nullptr)
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
printWasmError("Error setting gas", nullptr, j_);
|
||||
wasmi_error_delete(err);
|
||||
throw std::runtime_error("can't set gas");
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
moduleWrap_ = std::make_unique<ModuleWrapper>(store_, wasmCode, instantiate, imports, j_);
|
||||
|
||||
if (!moduleWrap_)
|
||||
throw std::runtime_error("can't create module wrapper"); // LCOV_EXCL_LINE
|
||||
|
||||
return moduleWrap_ ? 0 : -1;
|
||||
}
|
||||
|
||||
// int
|
||||
// WasmiEngine::addInstance()
|
||||
// {
|
||||
// return module->addInstance(store.get());
|
||||
// }
|
||||
|
||||
std::vector<wasm_val_t>
|
||||
WasmiEngine::convertParams(std::vector<WasmParam> const& params)
|
||||
{
|
||||
std::vector<wasm_val_t> v;
|
||||
v.reserve(params.size());
|
||||
for (auto const& p : params)
|
||||
{
|
||||
switch (p.type)
|
||||
{
|
||||
case WasmTypes::WtI32:
|
||||
v.push_back(WASM_I32_VAL(p.of.i32));
|
||||
break;
|
||||
// LCOV_EXCL_START
|
||||
case WasmTypes::WtI64:
|
||||
v.push_back(WASM_I64_VAL(p.of.i64));
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error(
|
||||
"unknown parameter type: " + std::to_string(static_cast<int>(p.type)));
|
||||
break;
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
int
|
||||
WasmiEngine::compareParamTypes(wasm_valtype_vec_t const* ftp, std::vector<wasm_val_t> const& p)
|
||||
{
|
||||
if (ftp->size != p.size())
|
||||
return std::min(ftp->size, p.size());
|
||||
|
||||
for (unsigned i = 0; i < ftp->size; ++i)
|
||||
{
|
||||
auto const t1 = wasm_valtype_kind(ftp->data[i]);
|
||||
auto const t2 = p[i].kind;
|
||||
if (t1 != t2)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// LCOV_EXCL_START
|
||||
void
|
||||
WasmiEngine::addParam(std::vector<wasm_val_t>& in, int32_t p)
|
||||
{
|
||||
in.emplace_back();
|
||||
auto& el(in.back());
|
||||
memset(&el, 0, sizeof(el));
|
||||
el = WASM_I32_VAL(p); // WASM_I32;
|
||||
}
|
||||
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
void
|
||||
WasmiEngine::addParam(std::vector<wasm_val_t>& in, int64_t p)
|
||||
{
|
||||
in.emplace_back();
|
||||
auto& el(in.back());
|
||||
el = WASM_I64_VAL(p);
|
||||
}
|
||||
|
||||
template <int NR, class... Types>
|
||||
WasmiResult
|
||||
WasmiEngine::call(std::string_view func, Types&&... args)
|
||||
{
|
||||
// Lookup our export function
|
||||
auto f = getFunc(func);
|
||||
return call<NR>(f, std::forward<Types>(args)...);
|
||||
}
|
||||
|
||||
template <int NR, class... Types>
|
||||
WasmiResult
|
||||
WasmiEngine::call(FuncInfo const& f, Types&&... args)
|
||||
{
|
||||
std::vector<wasm_val_t> in;
|
||||
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>
|
||||
WasmiResult
|
||||
WasmiEngine::call(FuncInfo const& f, std::vector<wasm_val_t>& in)
|
||||
{
|
||||
WasmiResult ret(NR);
|
||||
wasm_val_vec_t const inv = in.empty() ? wasm_val_vec_t WASM_EMPTY_VEC
|
||||
: wasm_val_vec_t{.size = in.size(), .data = in.data()};
|
||||
|
||||
#ifdef SHOW_CALL_TIME
|
||||
auto const start = usecs();
|
||||
#endif
|
||||
|
||||
wasm_trap_t* trap = wasm_func_call(f.first, &inv, ret.r.get());
|
||||
|
||||
#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;
|
||||
printWasmError("failure to call func", trap, j_);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <int NR, class... Types>
|
||||
WasmiResult
|
||||
WasmiEngine::call(FuncInfo const& f, std::vector<wasm_val_t>& in, std::int32_t p, Types&&... args)
|
||||
{
|
||||
addParam(in, p);
|
||||
return call<NR>(f, in, std::forward<Types>(args)...);
|
||||
}
|
||||
|
||||
template <int NR, class... Types>
|
||||
WasmiResult
|
||||
WasmiEngine::call(FuncInfo const& f, std::vector<wasm_val_t>& in, std::int64_t p, Types&&... args)
|
||||
{
|
||||
addParam(in, p);
|
||||
return call<NR>(f, in, std::forward<Types>(args)...);
|
||||
}
|
||||
|
||||
template <int NR, class... Types>
|
||||
WasmiResult
|
||||
WasmiEngine::call(FuncInfo const& f, std::vector<wasm_val_t>& in, Bytes const& p, Types&&... args)
|
||||
{
|
||||
return call<NR>(f, in, p.data(), p.size(), std::forward<Types>(args)...);
|
||||
}
|
||||
|
||||
static inline void
|
||||
checkImports(ImportVec const& imports, HostFunctions* hfs)
|
||||
{
|
||||
for (auto const& obj : imports)
|
||||
{
|
||||
if (hfs != &obj.second.first.get())
|
||||
Throw<std::runtime_error>("Imports hf unsync");
|
||||
}
|
||||
}
|
||||
|
||||
Expected<WasmResult<int32_t>, TER>
|
||||
WasmiEngine::run(
|
||||
Bytes const& wasmCode,
|
||||
HostFunctions& hfs,
|
||||
int64_t gas,
|
||||
std::string_view funcName,
|
||||
std::vector<WasmParam> const& params,
|
||||
ImportVec const& imports,
|
||||
beast::Journal j)
|
||||
{
|
||||
if (gas <= 0)
|
||||
return Unexpected<TER>(temBAD_AMOUNT);
|
||||
|
||||
try
|
||||
{
|
||||
checkImports(imports, &hfs);
|
||||
return runHlp(wasmCode, hfs, gas, funcName, params, imports, j);
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
printWasmError(std::string("exception: ") + e.what(), nullptr, j);
|
||||
}
|
||||
// LCOV_EXCL_START
|
||||
catch (...)
|
||||
{
|
||||
printWasmError(std::string("exception: unknown"), nullptr, j);
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
return Unexpected<TER>(tecFAILED_PROCESSING);
|
||||
}
|
||||
|
||||
Expected<WasmResult<int32_t>, TER>
|
||||
WasmiEngine::runHlp(
|
||||
Bytes const& wasmCode,
|
||||
HostFunctions& hfs,
|
||||
int64_t gas,
|
||||
std::string_view funcName,
|
||||
std::vector<WasmParam> const& params,
|
||||
ImportVec const& imports,
|
||||
beast::Journal j)
|
||||
{
|
||||
// currently only 1 module support, possible parallel UT run
|
||||
std::scoped_lock const lg(m_);
|
||||
j_ = j;
|
||||
|
||||
if (wasmCode.empty())
|
||||
throw std::runtime_error("empty module");
|
||||
if (!hfs.checkSelf())
|
||||
throw std::runtime_error("hfs isn't clean");
|
||||
|
||||
// Create and instantiate the module.
|
||||
[[maybe_unused]] int const m = addModule(wasmCode, true, imports, gas);
|
||||
|
||||
if (!moduleWrap_ || !moduleWrap_->getInstance())
|
||||
throw std::runtime_error("no instance"); // LCOV_EXCL_LINE
|
||||
|
||||
auto clearRT = [](HostFunctions* p) { p->resetRT(); };
|
||||
std::unique_ptr<HostFunctions, decltype(clearRT)> const clearGuard(&hfs, clearRT);
|
||||
WasmiRuntimeWrapper iw(getRT());
|
||||
hfs.setRT(iw);
|
||||
|
||||
// Call main
|
||||
auto const f = getFunc(!funcName.empty() ? funcName : "_start");
|
||||
auto const* ftp = wasm_functype_params(f.second);
|
||||
|
||||
// not const because passed directly to VM function (which accept non
|
||||
// const)
|
||||
auto p = convertParams(params);
|
||||
|
||||
if (int const comp = compareParamTypes(ftp, p); comp >= 0)
|
||||
throw std::runtime_error("invalid parameter type #" + std::to_string(comp));
|
||||
|
||||
auto const res = call<1>(f, p);
|
||||
|
||||
if (res.f)
|
||||
Throw<std::runtime_error>("<" + std::string(funcName) + "> failure");
|
||||
|
||||
if (res.r.empty())
|
||||
{
|
||||
Throw<std::runtime_error>(
|
||||
"<" + std::string(funcName) + "> return nothing"); // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
if (res.r[0].kind != WASM_I32)
|
||||
{
|
||||
Throw<std::runtime_error>(
|
||||
"<" + std::string(funcName) +
|
||||
"> return type mismatch, ret: " + std::to_string(static_cast<int>(res.r[0].kind)));
|
||||
}
|
||||
|
||||
if (gas == -1)
|
||||
gas = std::numeric_limits<decltype(gas)>::max();
|
||||
WasmResult<int32_t> const ret{.result = res.r[0].of.i32, .cost = gas - moduleWrap_->getGas()};
|
||||
|
||||
// #ifdef DEBUG_OUTPUT
|
||||
// auto& j = std::cerr;
|
||||
// #else
|
||||
// auto j = j_.debug();
|
||||
// #endif
|
||||
// j << "WASMI Res: " << ret.result << " cost: " << ret.cost << std::endl;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
NotTEC
|
||||
WasmiEngine::check(
|
||||
Bytes const& wasmCode,
|
||||
HostFunctions& hfs,
|
||||
std::string_view funcName,
|
||||
std::vector<WasmParam> const& params,
|
||||
ImportVec const& imports,
|
||||
beast::Journal j)
|
||||
{
|
||||
try
|
||||
{
|
||||
checkImports(imports, &hfs);
|
||||
return checkHlp(wasmCode, hfs, funcName, params, imports, j);
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
printWasmError(std::string("exception: ") + e.what(), nullptr, j);
|
||||
}
|
||||
// LCOV_EXCL_START
|
||||
catch (...)
|
||||
{
|
||||
printWasmError(std::string("exception: unknown"), nullptr, j);
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
return temBAD_WASM;
|
||||
}
|
||||
|
||||
NotTEC
|
||||
WasmiEngine::checkHlp(
|
||||
Bytes const& wasmCode,
|
||||
HostFunctions& hfs,
|
||||
std::string_view funcName,
|
||||
std::vector<WasmParam> const& params,
|
||||
ImportVec const& imports,
|
||||
beast::Journal j)
|
||||
{
|
||||
// currently only 1 module support, possible parallel UT run
|
||||
std::scoped_lock const lg(m_);
|
||||
j_ = j;
|
||||
|
||||
// Create and instantiate the module.
|
||||
if (wasmCode.empty())
|
||||
throw std::runtime_error("empty module");
|
||||
|
||||
int const m = addModule(wasmCode, false, imports, -1);
|
||||
if ((m < 0) || !moduleWrap_)
|
||||
throw std::runtime_error("no module"); // LCOV_EXCL_LINE
|
||||
|
||||
// Looking for a func and compare parameter types
|
||||
auto const f = moduleWrap_->getFuncType(!funcName.empty() ? funcName : "_start");
|
||||
auto const* ftp = wasm_functype_params(f);
|
||||
auto const p = convertParams(params);
|
||||
|
||||
if (int const comp = compareParamTypes(ftp, p); comp >= 0)
|
||||
throw std::runtime_error("invalid parameter type #" + std::to_string(comp));
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
wasm_trap_t*
|
||||
WasmiEngine::newTrap(std::string const& txt)
|
||||
{
|
||||
static char empty[1] = {0};
|
||||
wasm_message_t msg = {.size = 1, .data = empty};
|
||||
|
||||
if (!txt.empty())
|
||||
wasm_name_new(&msg, txt.size() + 1, txt.c_str()); // include 0
|
||||
|
||||
wasm_trap_t* trap = wasm_trap_new(store_.get(), &msg); // NOLINT
|
||||
|
||||
if (!txt.empty())
|
||||
wasm_byte_vec_delete(&msg);
|
||||
|
||||
return trap;
|
||||
}
|
||||
|
||||
} // namespace xrpl
|
||||
6107
src/test/app/HostFuncImpl_test.cpp
Normal file
6107
src/test/app/HostFuncImpl_test.cpp
Normal file
File diff suppressed because it is too large
Load Diff
531
src/test/app/TestHostFunctions.h
Normal file
531
src/test/app/TestHostFunctions.h
Normal file
@@ -0,0 +1,531 @@
|
||||
#pragma once
|
||||
|
||||
#include <test/app/wasm_fixtures/fixtures.h>
|
||||
#include <test/jtx/Env.h>
|
||||
#include <test/unit_test/SuiteJournal.h>
|
||||
|
||||
#include <xrpl/ledger/AmendmentTable.h>
|
||||
#include <xrpl/ledger/detail/ApplyViewBase.h>
|
||||
#include <xrpl/ledger/helpers/NFTokenHelpers.h>
|
||||
#include <xrpl/protocol/digest.h>
|
||||
#include <xrpl/tx/wasm/HostFunc.h>
|
||||
#include <xrpl/tx/wasm/WasmVM.h>
|
||||
|
||||
#include <boost/algorithm/hex.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
namespace xrpl::test {
|
||||
|
||||
class TestLedgerDataProvider : public HostFunctions
|
||||
{
|
||||
jtx::Env& env_;
|
||||
|
||||
public:
|
||||
TestLedgerDataProvider(jtx::Env& env) : HostFunctions(env.journal), env_(env)
|
||||
{
|
||||
}
|
||||
|
||||
Expected<std::uint32_t, HostFunctionError>
|
||||
getLedgerSqn() const override
|
||||
{
|
||||
return env_.current()->seq();
|
||||
}
|
||||
};
|
||||
|
||||
class TestHostFunctions : public HostFunctions
|
||||
{
|
||||
protected:
|
||||
test::jtx::Env& env_;
|
||||
AccountID accountID_;
|
||||
Bytes data_;
|
||||
|
||||
public:
|
||||
TestHostFunctions(test::jtx::Env& env) : HostFunctions(env.journal), env_(env)
|
||||
{
|
||||
accountID_ = env.master.id();
|
||||
std::string t = "10000";
|
||||
data_ = Bytes{t.begin(), t.end()};
|
||||
}
|
||||
|
||||
Expected<std::uint32_t, HostFunctionError>
|
||||
getLedgerSqn() const override
|
||||
{
|
||||
return 12345;
|
||||
}
|
||||
|
||||
Expected<std::uint32_t, HostFunctionError>
|
||||
getParentLedgerTime() const override
|
||||
{
|
||||
return 67890;
|
||||
}
|
||||
|
||||
Expected<Hash, HostFunctionError>
|
||||
getParentLedgerHash() const override
|
||||
{
|
||||
return env_.current()->header().parentHash;
|
||||
}
|
||||
|
||||
Expected<std::uint32_t, HostFunctionError>
|
||||
getBaseFee() const override
|
||||
{
|
||||
return 10;
|
||||
}
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
isAmendmentEnabled(uint256 const& amendmentId) const override
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
isAmendmentEnabled(std::string_view const& amendmentName) const override
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
cacheLedgerObj(uint256 const& objId, int32_t cacheIdx) override
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
getTxField(SField const& fname) const override
|
||||
{
|
||||
if (fname == sfAccount)
|
||||
return Bytes(accountID_.begin(), accountID_.end());
|
||||
|
||||
if (fname == sfFee)
|
||||
{
|
||||
int64_t x = 235;
|
||||
uint8_t const* p = reinterpret_cast<uint8_t const*>(&x);
|
||||
return Bytes{p, p + sizeof(x)};
|
||||
}
|
||||
|
||||
if (fname == sfSequence)
|
||||
{
|
||||
auto const x = getLedgerSqn();
|
||||
if (!x)
|
||||
return Unexpected(x.error());
|
||||
std::uint32_t const data = x.value();
|
||||
auto const* b = reinterpret_cast<uint8_t const*>(&data);
|
||||
auto const* e = reinterpret_cast<uint8_t const*>(&data + 1);
|
||||
return Bytes{b, e};
|
||||
}
|
||||
|
||||
return Bytes();
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
getCurrentLedgerObjField(SField const& fname) const override
|
||||
{
|
||||
auto const& sn = fname.getName();
|
||||
if (sn == "Destination" || sn == "Account")
|
||||
return Bytes(accountID_.begin(), accountID_.end());
|
||||
if (sn == "Data")
|
||||
return data_;
|
||||
if (sn == "FinishAfter")
|
||||
{
|
||||
auto t = env_.current()->parentCloseTime().time_since_epoch().count();
|
||||
std::string s = std::to_string(t);
|
||||
return Bytes{s.begin(), s.end()};
|
||||
}
|
||||
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
getLedgerObjField(int32_t, SField const& fname) const override
|
||||
{
|
||||
if (fname == sfBalance)
|
||||
{
|
||||
int64_t x = 10'000;
|
||||
uint8_t const* p = reinterpret_cast<uint8_t const*>(&x);
|
||||
return Bytes{p, p + sizeof(x)};
|
||||
}
|
||||
|
||||
if (fname == sfAccount)
|
||||
return Bytes(accountID_.begin(), accountID_.end());
|
||||
|
||||
return data_;
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
getTxNestedField(FieldLocator const& locator) const override
|
||||
{
|
||||
if (locator.size() == 1)
|
||||
{
|
||||
int32_t const* l = locator.data();
|
||||
int32_t const sfield = l[0];
|
||||
if (sfield == sfAccount.getCode())
|
||||
return Bytes(accountID_.begin(), accountID_.end());
|
||||
}
|
||||
|
||||
uint8_t const a[] = {0x2b, 0x6a, 0x23, 0x2a, 0xa4, 0xc4, 0xbe, 0x41, 0xbf, 0x49, 0xd2,
|
||||
0x45, 0x9f, 0xa4, 0xa0, 0x34, 0x7e, 0x1b, 0x54, 0x3a, 0x4c, 0x92,
|
||||
0xfc, 0xee, 0x08, 0x21, 0xc0, 0x20, 0x1e, 0x2e, 0x9a, 0x00};
|
||||
return Bytes(&a[0], &a[sizeof(a)]);
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
getCurrentLedgerObjNestedField(FieldLocator const& locator) const override
|
||||
{
|
||||
if (locator.size() == 1)
|
||||
{
|
||||
int32_t const* l = locator.data();
|
||||
int32_t const sfield = l[0];
|
||||
if (sfield == sfAccount.getCode())
|
||||
return Bytes(accountID_.begin(), accountID_.end());
|
||||
}
|
||||
|
||||
uint8_t const a[] = {0x2b, 0x6a, 0x23, 0x2a, 0xa4, 0xc4, 0xbe, 0x41, 0xbf, 0x49, 0xd2,
|
||||
0x45, 0x9f, 0xa4, 0xa0, 0x34, 0x7e, 0x1b, 0x54, 0x3a, 0x4c, 0x92,
|
||||
0xfc, 0xee, 0x08, 0x21, 0xc0, 0x20, 0x1e, 0x2e, 0x9a, 0x00};
|
||||
return Bytes(&a[0], &a[sizeof(a)]);
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
getLedgerObjNestedField(int32_t cacheIdx, FieldLocator const& locator) const override
|
||||
{
|
||||
if (locator.size() == 1)
|
||||
{
|
||||
int32_t const* l = locator.data();
|
||||
int32_t const sfield = l[0];
|
||||
if (sfield == sfAccount.getCode())
|
||||
return Bytes(accountID_.begin(), accountID_.end());
|
||||
}
|
||||
|
||||
uint8_t const a[] = {0x2b, 0x6a, 0x23, 0x2a, 0xa4, 0xc4, 0xbe, 0x41, 0xbf, 0x49, 0xd2,
|
||||
0x45, 0x9f, 0xa4, 0xa0, 0x34, 0x7e, 0x1b, 0x54, 0x3a, 0x4c, 0x92,
|
||||
0xfc, 0xee, 0x08, 0x21, 0xc0, 0x20, 0x1e, 0x2e, 0x9a, 0x00};
|
||||
return Bytes(&a[0], &a[sizeof(a)]);
|
||||
}
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
getTxArrayLen(SField const& fname) const override
|
||||
{
|
||||
return 32;
|
||||
}
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
getCurrentLedgerObjArrayLen(SField const& fname) const override
|
||||
{
|
||||
return 32;
|
||||
}
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
getLedgerObjArrayLen(int32_t cacheIdx, SField const& fname) const override
|
||||
{
|
||||
return 32;
|
||||
}
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
getTxNestedArrayLen(FieldLocator const& locator) const override
|
||||
{
|
||||
return 32;
|
||||
}
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
getCurrentLedgerObjNestedArrayLen(FieldLocator const& locator) const override
|
||||
{
|
||||
return 32;
|
||||
}
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
getLedgerObjNestedArrayLen(int32_t cacheIdx, FieldLocator const& locator) const override
|
||||
{
|
||||
return 32;
|
||||
}
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
updateData(Slice const& data) override
|
||||
{
|
||||
return data.size();
|
||||
}
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
checkSignature(Slice const& message, Slice const& signature, Slice const& pubkey) const override
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
Expected<Hash, HostFunctionError>
|
||||
computeSha512HalfHash(Slice const& data) const override
|
||||
{
|
||||
return env_.current()->header().parentHash;
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
accountKeylet(AccountID const& account) const override
|
||||
{
|
||||
if (!account)
|
||||
return Unexpected(HostFunctionError::InvalidAccount);
|
||||
auto const keylet = keylet::account(account);
|
||||
return Bytes{keylet.key.begin(), keylet.key.end()};
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
ammKeylet(Asset const& issue1, Asset const& issue2) const override
|
||||
{
|
||||
if (issue1 == issue2)
|
||||
return Unexpected(HostFunctionError::InvalidParams);
|
||||
if (issue1.holds<MPTIssue>() || issue2.holds<MPTIssue>())
|
||||
return Unexpected(HostFunctionError::InvalidParams);
|
||||
auto const keylet = keylet::amm(issue1, issue2);
|
||||
return Bytes{keylet.key.begin(), keylet.key.end()};
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
checkKeylet(AccountID const& account, std::uint32_t seq) const override
|
||||
{
|
||||
if (!account)
|
||||
return Unexpected(HostFunctionError::InvalidAccount);
|
||||
auto const keylet = keylet::check(account, seq);
|
||||
return Bytes{keylet.key.begin(), keylet.key.end()};
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
credentialKeylet(AccountID const& subject, AccountID const& issuer, Slice const& credentialType)
|
||||
const override
|
||||
{
|
||||
if (!subject || !issuer || credentialType.empty() ||
|
||||
credentialType.size() > kMaxCredentialTypeLength)
|
||||
return Unexpected(HostFunctionError::InvalidAccount);
|
||||
auto const keylet = keylet::credential(subject, issuer, credentialType);
|
||||
return Bytes{keylet.key.begin(), keylet.key.end()};
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
escrowKeylet(AccountID const& account, std::uint32_t seq) const override
|
||||
{
|
||||
if (!account)
|
||||
return Unexpected(HostFunctionError::InvalidAccount);
|
||||
auto const keylet = keylet::escrow(account, seq);
|
||||
return Bytes{keylet.key.begin(), keylet.key.end()};
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
oracleKeylet(AccountID const& account, std::uint32_t documentId) const override
|
||||
{
|
||||
if (!account)
|
||||
return Unexpected(HostFunctionError::InvalidAccount);
|
||||
auto const keylet = keylet::oracle(account, documentId);
|
||||
return Bytes{keylet.key.begin(), keylet.key.end()};
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
getNFT(AccountID const& account, uint256 const& nftId) const override
|
||||
{
|
||||
if (!account || !nftId)
|
||||
return Unexpected(HostFunctionError::InvalidParams);
|
||||
|
||||
std::string s = "https://ripple.com";
|
||||
return Bytes(s.begin(), s.end());
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
getNFTIssuer(uint256 const& nftId) const override
|
||||
{
|
||||
return Bytes(accountID_.begin(), accountID_.end());
|
||||
}
|
||||
|
||||
Expected<std::uint32_t, HostFunctionError>
|
||||
getNFTTaxon(uint256 const& nftId) const override
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
getNFTFlags(uint256 const& nftId) const override
|
||||
{
|
||||
return 8;
|
||||
}
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
getNFTTransferFee(uint256 const& nftId) const override
|
||||
{
|
||||
return 10;
|
||||
}
|
||||
|
||||
Expected<std::uint32_t, HostFunctionError>
|
||||
getNFTSerial(uint256 const& nftId) const override
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
void
|
||||
log(std::string_view const& msg, F&& dataFn) const
|
||||
{
|
||||
#ifdef DEBUG_OUTPUT
|
||||
auto& j = std::cerr;
|
||||
#else
|
||||
if (!getJournal().active(beast::Severity::Trace))
|
||||
return;
|
||||
auto j = getJournal().trace();
|
||||
#endif
|
||||
j << "WasmTrace: " << msg << " " << dataFn();
|
||||
|
||||
#ifdef DEBUG_OUTPUT
|
||||
j << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
trace(std::string_view const& msg, Slice const& data, bool asHex) const override
|
||||
{
|
||||
if (!asHex)
|
||||
{
|
||||
log(msg, [&data] {
|
||||
return std::string_view(reinterpret_cast<char const*>(data.data()), data.size());
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
log(msg, [&data] {
|
||||
std::string hex;
|
||||
hex.reserve(data.size() * 2);
|
||||
boost::algorithm::hex(data.begin(), data.end(), std::back_inserter(hex));
|
||||
return hex;
|
||||
});
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
traceNum(std::string_view const& msg, int64_t data) const override
|
||||
{
|
||||
log(msg, [data] { return data; });
|
||||
return 0;
|
||||
}
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
traceAccount(std::string_view const& msg, AccountID const& account) const override
|
||||
{
|
||||
log(msg, [&account] { return toBase58(account); });
|
||||
return 0;
|
||||
}
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
traceFloat(std::string_view const& msg, Slice const& data) const override
|
||||
{
|
||||
log(msg, [&data] { return wasm_float::floatToString(data); });
|
||||
return 0;
|
||||
}
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
traceAmount(std::string_view const& msg, STAmount const& amount) const override
|
||||
{
|
||||
log(msg, [&amount] { return amount.getFullText(); });
|
||||
return 0;
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatFromInt(int64_t x, int32_t mode) const override
|
||||
{
|
||||
return wasm_float::floatFromIntImpl(x, mode);
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatFromUint(uint64_t x, int32_t mode) const override
|
||||
{
|
||||
return wasm_float::floatFromUintImpl(x, mode);
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatFromSTAmount(STAmount const& x, int32_t mode) const override
|
||||
{
|
||||
return wasm_float::floatFromSTAmountImpl(x, mode);
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatFromSTNumber(STNumber const& x, int32_t mode) const override
|
||||
{
|
||||
return wasm_float::floatFromSTNumberImpl(x, mode);
|
||||
}
|
||||
|
||||
Expected<int64_t, HostFunctionError>
|
||||
floatToInt(Slice const& x, int32_t mode) const override
|
||||
{
|
||||
return wasm_float::floatToIntImpl(x, mode);
|
||||
}
|
||||
|
||||
Expected<FloatPair, HostFunctionError>
|
||||
floatToMantExp(Slice const& x) const override
|
||||
{
|
||||
return wasm_float::floatToMantExpImpl(x);
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatFromMantExp(int64_t mantissa, int32_t exponent, int32_t mode) const override
|
||||
{
|
||||
return wasm_float::floatFromMantExpImpl(mantissa, exponent, mode);
|
||||
}
|
||||
|
||||
Expected<int32_t, HostFunctionError>
|
||||
floatCompare(Slice const& x, Slice const& y) const override
|
||||
{
|
||||
return wasm_float::floatCompareImpl(x, y);
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatAdd(Slice const& x, Slice const& y, int32_t mode) const override
|
||||
{
|
||||
return wasm_float::floatAddImpl(x, y, mode);
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatSubtract(Slice const& x, Slice const& y, int32_t mode) const override
|
||||
{
|
||||
return wasm_float::floatSubtractImpl(x, y, mode);
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatMultiply(Slice const& x, Slice const& y, int32_t mode) const override
|
||||
{
|
||||
return wasm_float::floatMultiplyImpl(x, y, mode);
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatDivide(Slice const& x, Slice const& y, int32_t mode) const override
|
||||
{
|
||||
return wasm_float::floatDivideImpl(x, y, mode);
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatRoot(Slice const& x, int32_t n, int32_t mode) const override
|
||||
{
|
||||
return wasm_float::floatRootImpl(x, n, mode);
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
floatPower(Slice const& x, int32_t n, int32_t mode) const override
|
||||
{
|
||||
return wasm_float::floatPowerImpl(x, n, mode);
|
||||
}
|
||||
};
|
||||
|
||||
class TestHostFunctionsSink : public TestHostFunctions
|
||||
{
|
||||
test::StreamSink sink_;
|
||||
|
||||
public:
|
||||
explicit TestHostFunctionsSink(test::jtx::Env& env)
|
||||
: TestHostFunctions(env), sink_(beast::Severity::Debug)
|
||||
{
|
||||
j_ = beast::Journal(sink_);
|
||||
}
|
||||
|
||||
test::StreamSink&
|
||||
getSink()
|
||||
{
|
||||
return sink_;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace xrpl::test
|
||||
467
src/test/app/Wasm_test.cpp
Normal file
467
src/test/app/Wasm_test.cpp
Normal file
@@ -0,0 +1,467 @@
|
||||
#ifdef _DEBUG
|
||||
// #define DEBUG_OUTPUT 1
|
||||
#endif
|
||||
|
||||
#include <test/app/TestHostFunctions.h>
|
||||
#include <test/app/wasm_fixtures/fixtures.h>
|
||||
#include <test/jtx/Env.h>
|
||||
|
||||
#include <xrpl/basics/Expected.h>
|
||||
#include <xrpl/beast/unit_test/suite.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
#include <xrpl/tx/wasm/HostFunc.h>
|
||||
#include <xrpl/tx/wasm/HostFuncWrapper.h> // IWYU pragma: keep
|
||||
#include <xrpl/tx/wasm/WasmCommon.h>
|
||||
#include <xrpl/tx/wasm/WasmImportsHelper.h>
|
||||
#include <xrpl/tx/wasm/WasmVM.h>
|
||||
|
||||
#include <boost/algorithm/hex.hpp>
|
||||
|
||||
#include <wasm.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <source_location>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace xrpl::test {
|
||||
|
||||
bool
|
||||
testGetDataIncrement();
|
||||
|
||||
using Add_proto = int32_t(int32_t, int32_t);
|
||||
static wasm_trap_t*
|
||||
add(HostFunctions&, wasm_val_vec_t const* params, wasm_val_vec_t* results)
|
||||
{
|
||||
int32_t const val1 = params->data[0].of.i32;
|
||||
int32_t const val2 = params->data[1].of.i32;
|
||||
// printf("Host function \"Add\": %d + %d\n", Val1, Val2);
|
||||
results->data[0] = WASM_I32_VAL(val1 + val2);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<uint8_t>
|
||||
hexToBytes(std::string const& hex)
|
||||
{
|
||||
auto const ws = boost::algorithm::unhex(hex);
|
||||
return Bytes(ws.begin(), ws.end());
|
||||
}
|
||||
|
||||
struct Wasm_test : public beast::unit_test::Suite
|
||||
{
|
||||
void
|
||||
checkResult(
|
||||
Expected<WasmResult<int32_t>, TER> re,
|
||||
int32_t expectedResult,
|
||||
int64_t expectedCost,
|
||||
std::source_location const location = std::source_location::current())
|
||||
{
|
||||
auto const lineStr = " (" + std::to_string(location.line()) + ")";
|
||||
if (BEAST_EXPECTS(re.has_value(), transToken(re.error()) + lineStr))
|
||||
{
|
||||
BEAST_EXPECTS(re->result == expectedResult, std::to_string(re->result) + lineStr);
|
||||
BEAST_EXPECTS(re->cost == expectedCost, std::to_string(re->cost) + lineStr);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testGetDataHelperFunctions()
|
||||
{
|
||||
testcase("getData helper functions");
|
||||
BEAST_EXPECT(testGetDataIncrement());
|
||||
}
|
||||
|
||||
void
|
||||
testWasmLib()
|
||||
{
|
||||
testcase("wasm lib test");
|
||||
// clang-format off
|
||||
/* The WASM module buffer. */
|
||||
Bytes const wasm = {/* WASM header */
|
||||
0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00,
|
||||
/* Type section */
|
||||
0x01, 0x07, 0x01,
|
||||
/* function type {i32, i32} -> {i32} */
|
||||
0x60, 0x02, 0x7F, 0x7F, 0x01, 0x7F,
|
||||
/* Import section */
|
||||
0x02, 0x13, 0x01,
|
||||
/* module name: "extern" */
|
||||
0x06, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6E,
|
||||
/* extern name: "func-add" */
|
||||
0x08, 0x66, 0x75, 0x6E, 0x63, 0x2D, 0x61, 0x64, 0x64,
|
||||
/* import desc: func 0 */
|
||||
0x00, 0x00,
|
||||
/* Function section */
|
||||
0x03, 0x02, 0x01, 0x00,
|
||||
/* Export section */
|
||||
0x07, 0x0A, 0x01,
|
||||
/* export name: "addTwo" */
|
||||
0x06, 0x61, 0x64, 0x64, 0x54, 0x77, 0x6F,
|
||||
/* export desc: func 0 */
|
||||
0x00, 0x01,
|
||||
/* Code section */
|
||||
0x0A, 0x0A, 0x01,
|
||||
/* code body */
|
||||
0x08, 0x00, 0x20, 0x00, 0x20, 0x01, 0x10, 0x00, 0x0B};
|
||||
// clang-format on
|
||||
auto& vm = WasmEngine::instance();
|
||||
|
||||
HostFunctions hfs;
|
||||
ImportVec imports;
|
||||
WasmImpFunc<Add_proto>(imports, "func-add", add, hfs);
|
||||
|
||||
auto re = vm.run(wasm, hfs, 10'000'000, "addTwo", wasmParams(1234, 5678), imports);
|
||||
|
||||
// if (res) printf("invokeAdd get the result: %d\n", res.value());
|
||||
|
||||
checkResult(re, 6'912, 59);
|
||||
}
|
||||
|
||||
void
|
||||
testBadWasm()
|
||||
{
|
||||
testcase("bad wasm test");
|
||||
|
||||
using namespace test::jtx;
|
||||
|
||||
Env const env{*this};
|
||||
HostFunctions hfs(env.journal);
|
||||
|
||||
{
|
||||
auto wasm = hexToBytes("00000000");
|
||||
std::string const funcName("mock_escrow");
|
||||
|
||||
auto re = runEscrowWasm(wasm, hfs, 15, funcName, {});
|
||||
BEAST_EXPECT(!re);
|
||||
}
|
||||
|
||||
{
|
||||
auto wasm = hexToBytes("00112233445566778899AA");
|
||||
std::string const funcName("mock_escrow");
|
||||
|
||||
auto const re = preflightEscrowWasm(wasm, hfs, funcName);
|
||||
BEAST_EXPECT(!isTesSuccess(re));
|
||||
}
|
||||
|
||||
{
|
||||
// FinishFunction wrong function name
|
||||
// pub fn bad() -> bool {
|
||||
// unsafe { host_lib::getLedgerSqn() >= 5 }
|
||||
// }
|
||||
auto const badWasm = hexToBytes(
|
||||
"0061736d010000000105016000017f02190108686f73745f6c69620c6765"
|
||||
"744c656467657253716e00000302010005030100100611027f00418080c0"
|
||||
"000b7f00418080c0000b072b04066d656d6f727902000362616400010a5f"
|
||||
"5f646174615f656e6403000b5f5f686561705f6261736503010a09010700"
|
||||
"100041044a0b004d0970726f64756365727302086c616e67756167650104"
|
||||
"52757374000c70726f6365737365642d6279010572757374631d312e3835"
|
||||
"2e31202834656231363132353020323032352d30332d31352900490f7461"
|
||||
"726765745f6665617475726573042b0f6d757461626c652d676c6f62616c"
|
||||
"732b087369676e2d6578742b0f7265666572656e63652d74797065732b0a"
|
||||
"6d756c746976616c7565");
|
||||
|
||||
auto const re = preflightEscrowWasm(badWasm, hfs, escrowFunctionName);
|
||||
BEAST_EXPECT(!isTesSuccess(re));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testWasmLedgerSqn()
|
||||
{
|
||||
testcase("Wasm get ledger sequence");
|
||||
|
||||
auto ledgerSqnWasm = hexToBytes(kLedgerSqnWasmHex);
|
||||
|
||||
using namespace test::jtx;
|
||||
|
||||
Env env{*this};
|
||||
TestLedgerDataProvider hfs(env);
|
||||
ImportVec imports;
|
||||
WASM_IMPORT_FUNC2(imports, getLedgerSqn, "ldgr_index", hfs, 33);
|
||||
auto& engine = WasmEngine::instance();
|
||||
|
||||
auto re =
|
||||
engine.run(ledgerSqnWasm, hfs, 1'000'000, escrowFunctionName, {}, imports, env.journal);
|
||||
|
||||
checkResult(re, 0, 440);
|
||||
|
||||
env.close();
|
||||
env.close();
|
||||
|
||||
// empty module, throwing exception
|
||||
re = engine.run({}, hfs, 1'000'000, escrowFunctionName, {}, imports, env.journal);
|
||||
BEAST_EXPECT(!re);
|
||||
env.close();
|
||||
}
|
||||
|
||||
void
|
||||
testHFCost()
|
||||
{
|
||||
testcase("wasm test host functions cost");
|
||||
|
||||
using namespace test::jtx;
|
||||
|
||||
Env env(*this);
|
||||
{
|
||||
auto const allHostFuncWasm = hexToBytes(kAllHostFunctionsWasmHex);
|
||||
|
||||
auto& engine = WasmEngine::instance();
|
||||
|
||||
TestHostFunctions hfs(env);
|
||||
auto imp = createWasmImport(hfs);
|
||||
for (auto& i : imp)
|
||||
i.second.second.gas = 0;
|
||||
|
||||
auto re = engine.run(
|
||||
allHostFuncWasm, hfs, 1'000'000, escrowFunctionName, {}, imp, env.journal);
|
||||
|
||||
checkResult(re, 1, 27'032);
|
||||
|
||||
env.close();
|
||||
}
|
||||
|
||||
env.close();
|
||||
env.close();
|
||||
env.close();
|
||||
env.close();
|
||||
env.close();
|
||||
|
||||
{
|
||||
auto const allHostFuncWasm = hexToBytes(kAllHostFunctionsWasmHex);
|
||||
|
||||
auto& engine = WasmEngine::instance();
|
||||
|
||||
TestHostFunctions hfs(env);
|
||||
auto const imp = createWasmImport(hfs);
|
||||
|
||||
auto re = engine.run(
|
||||
allHostFuncWasm, hfs, 1'000'000, escrowFunctionName, {}, imp, env.journal);
|
||||
|
||||
checkResult(re, 1, 68'792);
|
||||
|
||||
env.close();
|
||||
}
|
||||
|
||||
// not enough gas
|
||||
{
|
||||
auto const allHostFuncWasm = hexToBytes(kAllHostFunctionsWasmHex);
|
||||
|
||||
auto& engine = WasmEngine::instance();
|
||||
|
||||
TestHostFunctions hfs(env);
|
||||
auto const imp = createWasmImport(hfs);
|
||||
|
||||
auto re =
|
||||
engine.run(allHostFuncWasm, hfs, 200, escrowFunctionName, {}, imp, env.journal);
|
||||
|
||||
if (BEAST_EXPECT(!re))
|
||||
{
|
||||
BEAST_EXPECTS(
|
||||
re.error() == tecFAILED_PROCESSING, std::to_string(TERtoInt(re.error())));
|
||||
}
|
||||
|
||||
env.close();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testEscrowWasmDN()
|
||||
{
|
||||
testcase("escrow wasm devnet test");
|
||||
|
||||
auto const allHFWasm = hexToBytes(kAllHostFunctionsWasmHex);
|
||||
|
||||
using namespace test::jtx;
|
||||
Env env{*this};
|
||||
{
|
||||
TestHostFunctions hfs(env);
|
||||
auto re = runEscrowWasm(allHFWasm, hfs, 100'000, escrowFunctionName, {});
|
||||
checkResult(re, 1, 68'792);
|
||||
}
|
||||
|
||||
{
|
||||
// Invalid gas limit (0) should be rejected (boundary condition)
|
||||
TestHostFunctions hfs(env);
|
||||
auto re = runEscrowWasm(allHFWasm, hfs, -1, escrowFunctionName, {});
|
||||
BEAST_EXPECT(!re.has_value());
|
||||
BEAST_EXPECT(re.error() == temBAD_AMOUNT);
|
||||
}
|
||||
|
||||
{
|
||||
// Invalid gas limit (-1) should be rejected
|
||||
TestHostFunctions hfs(env);
|
||||
auto re = runEscrowWasm(allHFWasm, hfs, 0, escrowFunctionName, {});
|
||||
BEAST_EXPECT(!re.has_value());
|
||||
BEAST_EXPECT(re.error() == temBAD_AMOUNT);
|
||||
}
|
||||
|
||||
{
|
||||
// max<int64_t>() gas
|
||||
TestHostFunctions hfs(env);
|
||||
auto re = runEscrowWasm(
|
||||
allHFWasm, hfs, std::numeric_limits<int64_t>::max(), escrowFunctionName, {});
|
||||
checkResult(re, 1, 68'792);
|
||||
}
|
||||
|
||||
{ // fail because trying to access nonexistent field
|
||||
struct FieldNotFoundHostFunctions : public TestHostFunctions
|
||||
{
|
||||
explicit FieldNotFoundHostFunctions(Env& env) : TestHostFunctions(env)
|
||||
{
|
||||
}
|
||||
Expected<Bytes, HostFunctionError>
|
||||
getTxField(SField const& fname) const override
|
||||
{
|
||||
return Unexpected(HostFunctionError::FieldNotFound);
|
||||
}
|
||||
};
|
||||
|
||||
FieldNotFoundHostFunctions hfs(env);
|
||||
auto re = runEscrowWasm(allHFWasm, hfs, 100'000, escrowFunctionName, {});
|
||||
checkResult(re, -201, 28'965);
|
||||
}
|
||||
|
||||
{ // fail because trying to allocate more than MAX_PAGES memory
|
||||
struct OversizedFieldHostFunctions : public TestHostFunctions
|
||||
{
|
||||
explicit OversizedFieldHostFunctions(Env& env) : TestHostFunctions(env)
|
||||
{
|
||||
}
|
||||
Expected<Bytes, HostFunctionError>
|
||||
getTxField(SField const& fname) const override
|
||||
{
|
||||
return Bytes((128 + 1) * 64 * 1024, 1);
|
||||
}
|
||||
};
|
||||
|
||||
OversizedFieldHostFunctions hfs(env);
|
||||
auto re = runEscrowWasm(allHFWasm, hfs, 100'000, escrowFunctionName, {});
|
||||
checkResult(re, -201, 28'965);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testCodecovWasm()
|
||||
{
|
||||
testcase("Codecov wasm test");
|
||||
|
||||
using namespace test::jtx;
|
||||
|
||||
Env env{*this};
|
||||
|
||||
auto const codecovWasm = hexToBytes(kCodecovTestsWasmHex);
|
||||
TestHostFunctions hfs(env);
|
||||
|
||||
auto const allowance = 204'624;
|
||||
auto re = runEscrowWasm(codecovWasm, hfs, allowance, escrowFunctionName, {});
|
||||
|
||||
checkResult(re, 1, allowance);
|
||||
}
|
||||
|
||||
void
|
||||
testBadAlign()
|
||||
{
|
||||
testcase("Wasm Bad Align");
|
||||
|
||||
// bad_align.c
|
||||
auto const badAlignWasm = hexToBytes(kBadAlignWasmHex);
|
||||
|
||||
using namespace test::jtx;
|
||||
|
||||
Env env{*this};
|
||||
TestHostFunctions hfs(env);
|
||||
auto imports = createWasmImport(hfs);
|
||||
|
||||
{ // Calls float_from_uint with bad alignment.
|
||||
// Can be checked through codecov
|
||||
auto& engine = WasmEngine::instance();
|
||||
|
||||
auto re = engine.run(badAlignWasm, hfs, 1'000'000, "test", {}, imports, env.journal);
|
||||
if (BEAST_EXPECTS(re, transToken(re.error())))
|
||||
{
|
||||
BEAST_EXPECTS(re->result == 0x47308594, std::to_string(re->result));
|
||||
}
|
||||
}
|
||||
|
||||
env.close();
|
||||
}
|
||||
|
||||
void
|
||||
testSwapBytes()
|
||||
{
|
||||
testcase("Wasm swap bytes");
|
||||
|
||||
uint64_t const swapDataU64 = 0x123456789abcdeffull;
|
||||
uint64_t const reverseSwapDataU64 = 0xffdebc9a78563412ull;
|
||||
int64_t const swapDataI64 = 0x123456789abcdeffll;
|
||||
int64_t const reverseSwapDataI64 = 0xffdebc9a78563412ll;
|
||||
|
||||
uint32_t const swapDataU32 = 0x12789aff;
|
||||
uint32_t const reverseSwapDataU32 = 0xff9a7812;
|
||||
int32_t const swapDataI32 = 0x12789aff;
|
||||
int32_t const reverseSwapDataI32 = 0xff9a7812;
|
||||
|
||||
uint16_t const swapDataU16 = 0x12ff;
|
||||
uint16_t const reverseSwapDataU16 = 0xff12;
|
||||
int16_t const swapDataI16 = 0x12ff;
|
||||
int16_t const reverseSwapDataI16 = 0xff12;
|
||||
|
||||
uint64_t b1 = swapDataU64;
|
||||
int64_t b2 = swapDataI64;
|
||||
b1 = adjustWasmEndianessHlp(b1);
|
||||
b2 = adjustWasmEndianessHlp(b2);
|
||||
BEAST_EXPECT(b1 == reverseSwapDataU64);
|
||||
BEAST_EXPECT(b2 == reverseSwapDataI64);
|
||||
b1 = adjustWasmEndianessHlp(b1);
|
||||
b2 = adjustWasmEndianessHlp(b2);
|
||||
BEAST_EXPECT(b1 == swapDataU64);
|
||||
BEAST_EXPECT(b2 == swapDataI64);
|
||||
|
||||
uint32_t b3 = swapDataU32;
|
||||
int32_t b4 = swapDataI32;
|
||||
b3 = adjustWasmEndianessHlp(b3);
|
||||
b4 = adjustWasmEndianessHlp(b4);
|
||||
BEAST_EXPECT(b3 == reverseSwapDataU32);
|
||||
BEAST_EXPECT(b4 == reverseSwapDataI32);
|
||||
b3 = adjustWasmEndianessHlp(b3);
|
||||
b4 = adjustWasmEndianessHlp(b4);
|
||||
BEAST_EXPECT(b3 == swapDataU32);
|
||||
BEAST_EXPECT(b4 == swapDataI32);
|
||||
|
||||
uint16_t b5 = swapDataU16;
|
||||
int16_t b6 = swapDataI16;
|
||||
b5 = adjustWasmEndianessHlp(b5);
|
||||
b6 = adjustWasmEndianessHlp(b6);
|
||||
BEAST_EXPECT(b5 == reverseSwapDataU16);
|
||||
BEAST_EXPECT(b6 == reverseSwapDataI16);
|
||||
b5 = adjustWasmEndianessHlp(b5);
|
||||
b6 = adjustWasmEndianessHlp(b6);
|
||||
BEAST_EXPECT(b5 == swapDataU16);
|
||||
BEAST_EXPECT(b6 == swapDataI16);
|
||||
}
|
||||
|
||||
void
|
||||
run() override
|
||||
{
|
||||
using namespace test::jtx;
|
||||
|
||||
testGetDataHelperFunctions();
|
||||
testWasmLib();
|
||||
testBadWasm();
|
||||
testWasmLedgerSqn();
|
||||
|
||||
testHFCost();
|
||||
testEscrowWasmDN();
|
||||
|
||||
testCodecovWasm();
|
||||
|
||||
testBadAlign();
|
||||
testSwapBytes();
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(Wasm, app, xrpl);
|
||||
|
||||
} // namespace xrpl::test
|
||||
3
src/test/app/wasm_fixtures/.gitignore
vendored
Normal file
3
src/test/app/wasm_fixtures/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
**/target
|
||||
**/debug
|
||||
*.wasm
|
||||
171
src/test/app/wasm_fixtures/all_host_functions/Cargo.lock
generated
Normal file
171
src/test/app/wasm_fixtures/all_host_functions/Cargo.lock
generated
Normal file
@@ -0,0 +1,171 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "all_host_functions"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"xrpl-wasm-stdlib",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.10.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bs58"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4"
|
||||
dependencies = [
|
||||
"tinyvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"crypto-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.186"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.106"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.10.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.117"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3"
|
||||
dependencies = [
|
||||
"tinyvec_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec_macros"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
|
||||
[[package]]
|
||||
name = "xrpl-macros"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git?branch=renames#9822d645870908a79d87a57b0244caa6359cb9cf"
|
||||
dependencies = [
|
||||
"bs58",
|
||||
"quote",
|
||||
"sha2",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xrpl-wasm-stdlib"
|
||||
version = "0.8.0"
|
||||
source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git?branch=renames#9822d645870908a79d87a57b0244caa6359cb9cf"
|
||||
dependencies = [
|
||||
"xrpl-macros",
|
||||
]
|
||||
21
src/test/app/wasm_fixtures/all_host_functions/Cargo.toml
Normal file
21
src/test/app/wasm_fixtures/all_host_functions/Cargo.toml
Normal file
@@ -0,0 +1,21 @@
|
||||
[package]
|
||||
name = "all_host_functions"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
# This empty workspace definition keeps this project independent of the parent workspace
|
||||
[workspace]
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
xrpl-std = { git = "https://github.com/ripple/xrpl-wasm-stdlib.git", package = "xrpl-wasm-stdlib", branch = "renames" }
|
||||
|
||||
[profile.dev]
|
||||
panic = "abort"
|
||||
|
||||
[profile.release]
|
||||
panic = "abort"
|
||||
opt-level = "z"
|
||||
lto = true
|
||||
791
src/test/app/wasm_fixtures/all_host_functions/src/lib.rs
Normal file
791
src/test/app/wasm_fixtures/all_host_functions/src/lib.rs
Normal file
@@ -0,0 +1,791 @@
|
||||
#![cfg_attr(target_arch = "wasm32", no_std)]
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
extern crate std;
|
||||
|
||||
//
|
||||
// Host Functions Test
|
||||
// Tests 26 host functions (across 7 categories)
|
||||
//
|
||||
// With craft you can run this test with:
|
||||
// craft test --project host_functions_test --test-case host_functions_test
|
||||
//
|
||||
// Amount Format Update:
|
||||
// - XRP amounts now return as 8-byte serialized rippled objects
|
||||
// - IOU and MPT amounts return in variable-length serialized format
|
||||
// - Format details: https://xrpl.org/docs/references/protocol/binary-format#amount-fields
|
||||
//
|
||||
// Error Code Ranges:
|
||||
// -100 to -199: Ledger Header Functions (3 functions)
|
||||
// -200 to -299: Transaction Data Functions (5 functions)
|
||||
// -300 to -399: Current Ledger Object Functions (4 functions)
|
||||
// -400 to -499: Any Ledger Object Functions (5 functions)
|
||||
// -500 to -599: Keylet Generation Functions (4 functions)
|
||||
// -600 to -699: Utility Functions (4 functions)
|
||||
// -700 to -799: Data Update Functions (1 function)
|
||||
//
|
||||
|
||||
use xrpl_std::core::current_tx::escrow_finish::EscrowFinish;
|
||||
use xrpl_std::core::current_tx::traits::TransactionCommonFields;
|
||||
use xrpl_std::host;
|
||||
use xrpl_std::host::trace::{trace, trace_account_buf, trace_data, trace_num, DataRepr};
|
||||
use xrpl_std::sfield;
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "C" fn finish() -> i32 {
|
||||
let _ = trace("=== HOST FUNCTIONS TEST ===");
|
||||
let _ = trace("Testing 26 host functions");
|
||||
|
||||
// Category 1: Ledger Header Data Functions (3 functions)
|
||||
// Error range: -100 to -199
|
||||
match test_ledger_header_functions() {
|
||||
0 => (),
|
||||
err => return err,
|
||||
}
|
||||
|
||||
// Category 2: Transaction Data Functions (5 functions)
|
||||
// Error range: -200 to -299
|
||||
match test_transaction_data_functions() {
|
||||
0 => (),
|
||||
err => return err,
|
||||
}
|
||||
|
||||
// Category 3: Current Ledger Object Functions (4 functions)
|
||||
// Error range: -300 to -399
|
||||
match test_current_ledger_object_functions() {
|
||||
0 => (),
|
||||
err => return err,
|
||||
}
|
||||
|
||||
// Category 4: Any Ledger Object Functions (5 functions)
|
||||
// Error range: -400 to -499
|
||||
match test_any_ledger_object_functions() {
|
||||
0 => (),
|
||||
err => return err,
|
||||
}
|
||||
|
||||
// Category 5: Keylet Generation Functions (4 functions)
|
||||
// Error range: -500 to -599
|
||||
match test_keylet_generation_functions() {
|
||||
0 => (),
|
||||
err => return err,
|
||||
}
|
||||
|
||||
// Category 6: Utility Functions (4 functions)
|
||||
// Error range: -600 to -699
|
||||
match test_utility_functions() {
|
||||
0 => (),
|
||||
err => return err,
|
||||
}
|
||||
|
||||
// Category 7: Data Update Functions (1 function)
|
||||
// Error range: -700 to -799
|
||||
match test_data_update_functions() {
|
||||
0 => (),
|
||||
err => return err,
|
||||
}
|
||||
|
||||
let _ = trace("SUCCESS: All host function tests passed!");
|
||||
1 // Success return code for WASM finish function
|
||||
}
|
||||
|
||||
/// Test Category 1: Ledger Header Data Functions (3 functions)
|
||||
/// - get_ledger_sqn() - Get ledger sequence number
|
||||
/// - get_parent_ledger_time() - Get parent ledger timestamp
|
||||
/// - get_parent_ledger_hash() - Get parent ledger hash
|
||||
fn test_ledger_header_functions() -> i32 {
|
||||
let _ = trace("--- Category 1: Ledger Header Functions ---");
|
||||
|
||||
// Test 1.1: get_ledger_sqn() - should return current ledger sequence number
|
||||
let mut sqn_buffer = [0u8; 4];
|
||||
let sqn_result = unsafe { host::ldgr_index(sqn_buffer.as_mut_ptr(), sqn_buffer.len()) };
|
||||
|
||||
if sqn_result <= 0 {
|
||||
let _ = trace_num("ERROR: get_ledger_sqn failed:", sqn_result as i64);
|
||||
return -101; // Ledger sequence number test failed
|
||||
}
|
||||
let ledger_sqn = u32::from_be_bytes(sqn_buffer);
|
||||
let _ = trace_num("Ledger sequence number:", ledger_sqn as i64);
|
||||
|
||||
// Test 1.2: get_parent_ledger_time() - should return parent ledger timestamp
|
||||
let mut time_buffer = [0u8; 4];
|
||||
let time_result =
|
||||
unsafe { host::parent_ldgr_time(time_buffer.as_mut_ptr(), time_buffer.len()) };
|
||||
|
||||
if time_result <= 0 {
|
||||
let _ = trace_num("ERROR: get_parent_ledger_time failed:", time_result as i64);
|
||||
return -102; // Parent ledger time test failed
|
||||
}
|
||||
let parent_ledger_time = u32::from_be_bytes(time_buffer);
|
||||
let _ = trace_num("Parent ledger time:", parent_ledger_time as i64);
|
||||
|
||||
// Test 1.3: get_parent_ledger_hash() - should return parent ledger hash (32 bytes)
|
||||
let mut hash_buffer = [0u8; 32];
|
||||
let hash_result =
|
||||
unsafe { host::parent_ldgr_hash(hash_buffer.as_mut_ptr(), hash_buffer.len()) };
|
||||
|
||||
if hash_result != 32 {
|
||||
let _ = trace_num(
|
||||
"ERROR: get_parent_ledger_hash wrong length:",
|
||||
hash_result as i64,
|
||||
);
|
||||
return -103; // Parent ledger hash test failed - should be exactly 32 bytes
|
||||
}
|
||||
let _ = trace_data("Parent ledger hash:", &hash_buffer, DataRepr::AsHex);
|
||||
|
||||
let _ = trace("SUCCESS: Ledger header functions");
|
||||
0
|
||||
}
|
||||
|
||||
/// Test Category 2: Transaction Data Functions (5 functions)
|
||||
/// Tests all functions for accessing current transaction data
|
||||
fn test_transaction_data_functions() -> i32 {
|
||||
let _ = trace("--- Category 2: Transaction Data Functions ---");
|
||||
|
||||
// Test 2.1: get_tx_field() - Basic transaction field access
|
||||
// Test with Account field (required, 20 bytes)
|
||||
let mut account_buffer = [0u8; 20];
|
||||
let account_len = unsafe {
|
||||
host::tx_field(
|
||||
sfield::Account.into(),
|
||||
account_buffer.as_mut_ptr(),
|
||||
account_buffer.len(),
|
||||
)
|
||||
};
|
||||
|
||||
if account_len != 20 {
|
||||
let _ = trace_num(
|
||||
"ERROR: get_tx_field(Account) wrong length:",
|
||||
account_len as i64,
|
||||
);
|
||||
return -201; // Basic transaction field test failed
|
||||
}
|
||||
let _ = trace_account_buf("Transaction Account:", &account_buffer);
|
||||
|
||||
// Test with Fee field (XRP amount - 8 bytes in new serialized format)
|
||||
// New format: XRP amounts are always 8 bytes (positive: value | cPositive flag, negative: just value)
|
||||
let mut fee_buffer = [0u8; 8];
|
||||
let fee_len = unsafe {
|
||||
host::tx_field(
|
||||
sfield::Fee.into(),
|
||||
fee_buffer.as_mut_ptr(),
|
||||
fee_buffer.len(),
|
||||
)
|
||||
};
|
||||
|
||||
if fee_len != 8 {
|
||||
let _ = trace_num(
|
||||
"ERROR: get_tx_field(Fee) wrong length (expected 8 bytes for XRP):",
|
||||
fee_len as i64,
|
||||
);
|
||||
return -202; // Fee field test failed - XRP amounts should be exactly 8 bytes
|
||||
}
|
||||
let _ = trace_num("Transaction Fee length:", fee_len as i64);
|
||||
let _ = trace_data(
|
||||
"Transaction Fee (serialized XRP amount):",
|
||||
&fee_buffer,
|
||||
DataRepr::AsHex,
|
||||
);
|
||||
|
||||
// Test with Sequence field (required, 4 bytes uint32)
|
||||
let mut seq_buffer = [0u8; 4];
|
||||
let seq_len = unsafe {
|
||||
host::tx_field(
|
||||
sfield::Sequence.into(),
|
||||
seq_buffer.as_mut_ptr(),
|
||||
seq_buffer.len(),
|
||||
)
|
||||
};
|
||||
|
||||
if seq_len != 4 {
|
||||
let _ = trace_num(
|
||||
"ERROR: get_tx_field(Sequence) wrong length:",
|
||||
seq_len as i64,
|
||||
);
|
||||
return -203; // Sequence field test failed
|
||||
}
|
||||
let _ = trace_data("Transaction Sequence:", &seq_buffer, DataRepr::AsHex);
|
||||
|
||||
// NOTE: get_tx_field2() through get_tx_field6() have been deprecated.
|
||||
// Use get_tx_field() with appropriate parameters for all transaction field access.
|
||||
|
||||
// Test 2.2: get_tx_nested_field() - Nested field access with locator
|
||||
let locator = [0x01_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8]; // Two int32s in little-endian: [1, 0]
|
||||
let mut nested_buffer = [0u8; 32];
|
||||
let nested_result = unsafe {
|
||||
host::tx_inner(
|
||||
locator.as_ptr(),
|
||||
locator.len(),
|
||||
nested_buffer.as_mut_ptr(),
|
||||
nested_buffer.len(),
|
||||
)
|
||||
};
|
||||
|
||||
if nested_result < 0 {
|
||||
let _ = trace_num(
|
||||
"INFO: get_tx_nested_field not applicable:",
|
||||
nested_result as i64,
|
||||
);
|
||||
// Expected - locator may not match transaction structure
|
||||
} else {
|
||||
let _ = trace_num("Nested field length:", nested_result as i64);
|
||||
let _ = trace_data(
|
||||
"Nested field:",
|
||||
&nested_buffer[..nested_result as usize],
|
||||
DataRepr::AsHex,
|
||||
);
|
||||
}
|
||||
|
||||
// Test 2.3: get_tx_array_len() - Get array length
|
||||
let signers_len = unsafe { host::tx_arr_len(sfield::Signers.into()) };
|
||||
let _ = trace_num("Signers array length:", signers_len as i64);
|
||||
|
||||
let memos_len = unsafe { host::tx_arr_len(sfield::Memos.into()) };
|
||||
let _ = trace_num("Memos array length:", memos_len as i64);
|
||||
|
||||
// Test 2.4: get_tx_nested_array_len() - Get nested array length with locator
|
||||
let nested_array_len = unsafe { host::tx_inner_arr_len(locator.as_ptr(), locator.len()) };
|
||||
|
||||
if nested_array_len < 0 {
|
||||
let _ = trace_num(
|
||||
"INFO: get_tx_nested_array_len not applicable:",
|
||||
nested_array_len as i64,
|
||||
);
|
||||
} else {
|
||||
let _ = trace_num("Nested array length:", nested_array_len as i64);
|
||||
}
|
||||
|
||||
let _ = trace("SUCCESS: Transaction data functions");
|
||||
0
|
||||
}
|
||||
|
||||
/// Test Category 3: Current Ledger Object Functions (4 functions)
|
||||
/// Tests functions that access the current ledger object being processed
|
||||
fn test_current_ledger_object_functions() -> i32 {
|
||||
let _ = trace("--- Category 3: Current Ledger Object Functions ---");
|
||||
|
||||
// Test 3.1: get_current_ledger_obj_field() - Access field from current ledger object
|
||||
// Test with Balance field (XRP amount - 8 bytes in new serialized format)
|
||||
let mut balance_buffer = [0u8; 8];
|
||||
let balance_result = unsafe {
|
||||
host::home_le_field(
|
||||
sfield::Balance.into(),
|
||||
balance_buffer.as_mut_ptr(),
|
||||
balance_buffer.len(),
|
||||
)
|
||||
};
|
||||
|
||||
if balance_result <= 0 {
|
||||
let _ = trace_num(
|
||||
"INFO: get_current_ledger_obj_field(Balance) failed (may be expected):",
|
||||
balance_result as i64,
|
||||
);
|
||||
// This might fail if current ledger object doesn't have balance field
|
||||
} else if balance_result == 8 {
|
||||
let _ = trace_num(
|
||||
"Current object balance length (XRP amount):",
|
||||
balance_result as i64,
|
||||
);
|
||||
let _ = trace_data(
|
||||
"Current object balance (serialized XRP amount):",
|
||||
&balance_buffer,
|
||||
DataRepr::AsHex,
|
||||
);
|
||||
} else {
|
||||
let _ = trace_num(
|
||||
"Current object balance length (non-XRP amount):",
|
||||
balance_result as i64,
|
||||
);
|
||||
let _ = trace_data(
|
||||
"Current object balance:",
|
||||
&balance_buffer[..balance_result as usize],
|
||||
DataRepr::AsHex,
|
||||
);
|
||||
}
|
||||
|
||||
// Test with Account field
|
||||
let mut current_account_buffer = [0u8; 20];
|
||||
let current_account_result = unsafe {
|
||||
host::home_le_field(
|
||||
sfield::Account.into(),
|
||||
current_account_buffer.as_mut_ptr(),
|
||||
current_account_buffer.len(),
|
||||
)
|
||||
};
|
||||
|
||||
if current_account_result <= 0 {
|
||||
let _ = trace_num(
|
||||
"INFO: get_current_ledger_obj_field(Account) failed:",
|
||||
current_account_result as i64,
|
||||
);
|
||||
} else {
|
||||
let _ = trace_account_buf("Current ledger object account:", ¤t_account_buffer);
|
||||
}
|
||||
|
||||
// Test 3.2: get_current_ledger_obj_nested_field() - Nested field access
|
||||
let locator = [0x01_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8]; // Two int32s in little-endian: [1, 0]
|
||||
let mut current_nested_buffer = [0u8; 32];
|
||||
let current_nested_result = unsafe {
|
||||
host::home_le_inner(
|
||||
locator.as_ptr(),
|
||||
locator.len(),
|
||||
current_nested_buffer.as_mut_ptr(),
|
||||
current_nested_buffer.len(),
|
||||
)
|
||||
};
|
||||
|
||||
if current_nested_result < 0 {
|
||||
let _ = trace_num(
|
||||
"INFO: get_current_ledger_obj_nested_field not applicable:",
|
||||
current_nested_result as i64,
|
||||
);
|
||||
} else {
|
||||
let _ = trace_num("Current nested field length:", current_nested_result as i64);
|
||||
let _ = trace_data(
|
||||
"Current nested field:",
|
||||
¤t_nested_buffer[..current_nested_result as usize],
|
||||
DataRepr::AsHex,
|
||||
);
|
||||
}
|
||||
|
||||
// Test 3.3: get_current_ledger_obj_array_len() - Array length in current object
|
||||
let current_array_len = unsafe { host::home_le_arr_len(sfield::Signers.into()) };
|
||||
let _ = trace_num(
|
||||
"Current object Signers array length:",
|
||||
current_array_len as i64,
|
||||
);
|
||||
|
||||
// Test 3.4: get_current_ledger_obj_nested_array_len() - Nested array length
|
||||
let current_nested_array_len =
|
||||
unsafe { host::home_le_inner_arr_len(locator.as_ptr(), locator.len()) };
|
||||
|
||||
if current_nested_array_len < 0 {
|
||||
let _ = trace_num(
|
||||
"INFO: get_current_ledger_obj_nested_array_len not applicable:",
|
||||
current_nested_array_len as i64,
|
||||
);
|
||||
} else {
|
||||
let _ = trace_num(
|
||||
"Current nested array length:",
|
||||
current_nested_array_len as i64,
|
||||
);
|
||||
}
|
||||
|
||||
let _ = trace("SUCCESS: Current ledger object functions");
|
||||
0
|
||||
}
|
||||
|
||||
/// Test Category 4: Any Ledger Object Functions (5 functions)
|
||||
/// Tests functions that work with cached ledger objects
|
||||
fn test_any_ledger_object_functions() -> i32 {
|
||||
let _ = trace("--- Category 4: Any Ledger Object Functions ---");
|
||||
|
||||
// First we need to cache a ledger object to test the other functions
|
||||
// Get the account from transaction and generate its keylet
|
||||
let escrow_finish = EscrowFinish;
|
||||
let account_id = escrow_finish.get_account().unwrap();
|
||||
|
||||
// Test 4.1: cache_ledger_obj() - Cache a ledger object
|
||||
let mut keylet_buffer = [0u8; 32];
|
||||
let keylet_result = unsafe {
|
||||
host::accountroot_id(
|
||||
account_id.0.as_ptr(),
|
||||
account_id.0.len(),
|
||||
keylet_buffer.as_mut_ptr(),
|
||||
keylet_buffer.len(),
|
||||
)
|
||||
};
|
||||
|
||||
if keylet_result != 32 {
|
||||
let _ = trace_num(
|
||||
"ERROR: accountroot_id failed for caching test:",
|
||||
keylet_result as i64,
|
||||
);
|
||||
return -401; // Keylet generation failed for caching test
|
||||
}
|
||||
|
||||
let cache_result = unsafe { host::cache_le(keylet_buffer.as_ptr(), keylet_result as usize, 0) };
|
||||
|
||||
if cache_result <= 0 {
|
||||
let _ = trace_num(
|
||||
"INFO: cache_ledger_obj failed (expected with test fixtures):",
|
||||
cache_result as i64,
|
||||
);
|
||||
// Test fixtures may not contain the account object - this is expected
|
||||
// We'll test the interface but expect failures
|
||||
|
||||
// Test 4.2-4.5 with invalid slot (should fail gracefully)
|
||||
let mut test_buffer = [0u8; 32];
|
||||
|
||||
// Test get_ledger_obj_field with invalid slot
|
||||
let field_result = unsafe {
|
||||
host::le_field(
|
||||
1,
|
||||
sfield::Balance.into(),
|
||||
test_buffer.as_mut_ptr(),
|
||||
test_buffer.len(),
|
||||
)
|
||||
};
|
||||
if field_result < 0 {
|
||||
let _ = trace_num(
|
||||
"INFO: get_ledger_obj_field failed as expected (no cached object):",
|
||||
field_result as i64,
|
||||
);
|
||||
}
|
||||
|
||||
// Test get_ledger_obj_nested_field with invalid slot
|
||||
let locator = [0x01_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8]; // Two int32s in little-endian: [1, 0]
|
||||
let nested_result = unsafe {
|
||||
host::le_inner(
|
||||
1,
|
||||
locator.as_ptr(),
|
||||
locator.len(),
|
||||
test_buffer.as_mut_ptr(),
|
||||
test_buffer.len(),
|
||||
)
|
||||
};
|
||||
if nested_result < 0 {
|
||||
let _ = trace_num(
|
||||
"INFO: get_ledger_obj_nested_field failed as expected:",
|
||||
nested_result as i64,
|
||||
);
|
||||
}
|
||||
|
||||
// Test get_ledger_obj_array_len with invalid slot
|
||||
let array_result = unsafe { host::le_arr_len(1, sfield::Signers.into()) };
|
||||
if array_result < 0 {
|
||||
let _ = trace_num(
|
||||
"INFO: get_ledger_obj_array_len failed as expected:",
|
||||
array_result as i64,
|
||||
);
|
||||
}
|
||||
|
||||
// Test get_ledger_obj_nested_array_len with invalid slot
|
||||
let nested_array_result =
|
||||
unsafe { host::le_inner_arr_len(1, locator.as_ptr(), locator.len()) };
|
||||
if nested_array_result < 0 {
|
||||
let _ = trace_num(
|
||||
"INFO: get_ledger_obj_nested_array_len failed as expected:",
|
||||
nested_array_result as i64,
|
||||
);
|
||||
}
|
||||
|
||||
let _ = trace("SUCCESS: Any ledger object functions (interface tested)");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// If we successfully cached an object, test the access functions
|
||||
let slot = cache_result;
|
||||
let _ = trace_num("Successfully cached object in slot:", slot as i64);
|
||||
|
||||
// Test 4.2: get_ledger_obj_field() - Access field from cached object
|
||||
let mut cached_balance_buffer = [0u8; 8];
|
||||
let cached_balance_result = unsafe {
|
||||
host::le_field(
|
||||
slot,
|
||||
sfield::Balance.into(),
|
||||
cached_balance_buffer.as_mut_ptr(),
|
||||
cached_balance_buffer.len(),
|
||||
)
|
||||
};
|
||||
|
||||
if cached_balance_result <= 0 {
|
||||
let _ = trace_num(
|
||||
"INFO: get_ledger_obj_field(Balance) failed:",
|
||||
cached_balance_result as i64,
|
||||
);
|
||||
} else if cached_balance_result == 8 {
|
||||
let _ = trace_num(
|
||||
"Cached object balance length (XRP amount):",
|
||||
cached_balance_result as i64,
|
||||
);
|
||||
let _ = trace_data(
|
||||
"Cached object balance (serialized XRP amount):",
|
||||
&cached_balance_buffer,
|
||||
DataRepr::AsHex,
|
||||
);
|
||||
} else {
|
||||
let _ = trace_num(
|
||||
"Cached object balance length (non-XRP amount):",
|
||||
cached_balance_result as i64,
|
||||
);
|
||||
let _ = trace_data(
|
||||
"Cached object balance:",
|
||||
&cached_balance_buffer[..cached_balance_result as usize],
|
||||
DataRepr::AsHex,
|
||||
);
|
||||
}
|
||||
|
||||
// Test 4.3: get_ledger_obj_nested_field() - Nested field from cached object
|
||||
let locator = [0x01_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8]; // Two int32s in little-endian: [1, 0]
|
||||
let mut cached_nested_buffer = [0u8; 32];
|
||||
let cached_nested_result = unsafe {
|
||||
host::le_inner(
|
||||
slot,
|
||||
locator.as_ptr(),
|
||||
locator.len(),
|
||||
cached_nested_buffer.as_mut_ptr(),
|
||||
cached_nested_buffer.len(),
|
||||
)
|
||||
};
|
||||
|
||||
if cached_nested_result < 0 {
|
||||
let _ = trace_num(
|
||||
"INFO: get_ledger_obj_nested_field not applicable:",
|
||||
cached_nested_result as i64,
|
||||
);
|
||||
} else {
|
||||
let _ = trace_num("Cached nested field length:", cached_nested_result as i64);
|
||||
let _ = trace_data(
|
||||
"Cached nested field:",
|
||||
&cached_nested_buffer[..cached_nested_result as usize],
|
||||
DataRepr::AsHex,
|
||||
);
|
||||
}
|
||||
|
||||
// Test 4.4: get_ledger_obj_array_len() - Array length from cached object
|
||||
let cached_array_len = unsafe { host::le_arr_len(slot, sfield::Signers.into()) };
|
||||
let _ = trace_num(
|
||||
"Cached object Signers array length:",
|
||||
cached_array_len as i64,
|
||||
);
|
||||
|
||||
// Test 4.5: get_ledger_obj_nested_array_len() - Nested array length from cached object
|
||||
let cached_nested_array_len =
|
||||
unsafe { host::le_inner_arr_len(slot, locator.as_ptr(), locator.len()) };
|
||||
|
||||
if cached_nested_array_len < 0 {
|
||||
let _ = trace_num(
|
||||
"INFO: get_ledger_obj_nested_array_len not applicable:",
|
||||
cached_nested_array_len as i64,
|
||||
);
|
||||
} else {
|
||||
let _ = trace_num(
|
||||
"Cached nested array length:",
|
||||
cached_nested_array_len as i64,
|
||||
);
|
||||
}
|
||||
|
||||
let _ = trace("SUCCESS: Any ledger object functions");
|
||||
0
|
||||
}
|
||||
|
||||
/// Test Category 5: Keylet Generation Functions (4 functions)
|
||||
/// Tests keylet generation functions for different ledger entry types
|
||||
fn test_keylet_generation_functions() -> i32 {
|
||||
let _ = trace("--- Category 5: Keylet Generation Functions ---");
|
||||
|
||||
let escrow_finish = EscrowFinish;
|
||||
let account_id = escrow_finish.get_account().unwrap();
|
||||
|
||||
// Test 5.1: accountroot_id() - Generate keylet for account
|
||||
let mut accountroot_id_buffer = [0u8; 32];
|
||||
let accountroot_id_result = unsafe {
|
||||
host::accountroot_id(
|
||||
account_id.0.as_ptr(),
|
||||
account_id.0.len(),
|
||||
accountroot_id_buffer.as_mut_ptr(),
|
||||
accountroot_id_buffer.len(),
|
||||
)
|
||||
};
|
||||
|
||||
if accountroot_id_result != 32 {
|
||||
let _ = trace_num(
|
||||
"ERROR: accountroot_id failed:",
|
||||
accountroot_id_result as i64,
|
||||
);
|
||||
return -501; // Account keylet generation failed
|
||||
}
|
||||
let _ = trace_data("Account keylet:", &accountroot_id_buffer, DataRepr::AsHex);
|
||||
|
||||
// Test 5.2: credential_keylet() - Generate keylet for credential
|
||||
let mut credential_keylet_buffer = [0u8; 32];
|
||||
let credential_keylet_result = unsafe {
|
||||
host::credential_id(
|
||||
account_id.0.as_ptr(), // Subject
|
||||
account_id.0.len(),
|
||||
account_id.0.as_ptr(), // Issuer - same account for test
|
||||
account_id.0.len(),
|
||||
b"TestType".as_ptr(), // Credential type
|
||||
9usize, // Length of "TestType"
|
||||
credential_keylet_buffer.as_mut_ptr(),
|
||||
credential_keylet_buffer.len(),
|
||||
)
|
||||
};
|
||||
|
||||
if credential_keylet_result <= 0 {
|
||||
let _ = trace_num(
|
||||
"INFO: credential_keylet failed (expected - interface issue):",
|
||||
credential_keylet_result as i64,
|
||||
);
|
||||
// This is expected to fail due to unusual parameter types
|
||||
} else {
|
||||
let _ = trace_data(
|
||||
"Credential keylet:",
|
||||
&credential_keylet_buffer[..credential_keylet_result as usize],
|
||||
DataRepr::AsHex,
|
||||
);
|
||||
}
|
||||
|
||||
// Test 5.3: escrow_keylet() - Generate keylet for escrow
|
||||
let mut escrow_keylet_buffer = [0u8; 32];
|
||||
let sequence_number: i32 = 1000;
|
||||
let sequence_number_bytes = sequence_number.to_be_bytes();
|
||||
let escrow_keylet_result = unsafe {
|
||||
host::escrow_id(
|
||||
account_id.0.as_ptr(),
|
||||
account_id.0.len(),
|
||||
sequence_number_bytes.as_ptr(),
|
||||
sequence_number_bytes.len(),
|
||||
escrow_keylet_buffer.as_mut_ptr(),
|
||||
escrow_keylet_buffer.len(),
|
||||
)
|
||||
};
|
||||
|
||||
if escrow_keylet_result != 32 {
|
||||
let _ = trace_num("ERROR: escrow_keylet failed:", escrow_keylet_result as i64);
|
||||
return -503; // Escrow keylet generation failed
|
||||
}
|
||||
let _ = trace_data("Escrow keylet:", &escrow_keylet_buffer, DataRepr::AsHex);
|
||||
|
||||
// Test 5.4: oracle_keylet() - Generate keylet for oracle
|
||||
let mut oracle_keylet_buffer = [0u8; 32];
|
||||
let document_id: i32 = 42;
|
||||
let document_id_bytes = document_id.to_be_bytes();
|
||||
let oracle_keylet_result = unsafe {
|
||||
host::oracle_id(
|
||||
account_id.0.as_ptr(),
|
||||
account_id.0.len(),
|
||||
document_id_bytes.as_ptr(),
|
||||
document_id_bytes.len(),
|
||||
oracle_keylet_buffer.as_mut_ptr(),
|
||||
oracle_keylet_buffer.len(),
|
||||
)
|
||||
};
|
||||
|
||||
if oracle_keylet_result != 32 {
|
||||
let _ = trace_num("ERROR: oracle_keylet failed:", oracle_keylet_result as i64);
|
||||
return -504; // Oracle keylet generation failed
|
||||
}
|
||||
let _ = trace_data("Oracle keylet:", &oracle_keylet_buffer, DataRepr::AsHex);
|
||||
|
||||
let _ = trace("SUCCESS: Keylet generation functions");
|
||||
0
|
||||
}
|
||||
|
||||
/// Test Category 6: Utility Functions (4 functions)
|
||||
/// Tests utility functions for hashing, NFT access, and tracing
|
||||
fn test_utility_functions() -> i32 {
|
||||
let _ = trace("--- Category 6: Utility Functions ---");
|
||||
|
||||
// Test 6.1: compute_sha512_half() - SHA512 hash computation (first 32 bytes)
|
||||
let test_data = b"Hello, XRPL WASM world!";
|
||||
let mut hash_output = [0u8; 32];
|
||||
let hash_result = unsafe {
|
||||
host::sha512_half(
|
||||
test_data.as_ptr(),
|
||||
test_data.len(),
|
||||
hash_output.as_mut_ptr(),
|
||||
hash_output.len(),
|
||||
)
|
||||
};
|
||||
|
||||
if hash_result != 32 {
|
||||
let _ = trace_num("ERROR: compute_sha512_half failed:", hash_result as i64);
|
||||
return -601; // SHA512 half computation failed
|
||||
}
|
||||
let _ = trace_data("Input data:", test_data, DataRepr::AsHex);
|
||||
let _ = trace_data("SHA512 half hash:", &hash_output, DataRepr::AsHex);
|
||||
|
||||
// Test 6.2: get_nft() - NFT data retrieval
|
||||
let escrow_finish = EscrowFinish;
|
||||
let account_id = escrow_finish.get_account().unwrap();
|
||||
let nft_id = [0u8; 32]; // Dummy NFT ID for testing
|
||||
let mut nft_buffer = [0u8; 256];
|
||||
let nft_result = unsafe {
|
||||
host::nft_uri(
|
||||
account_id.0.as_ptr(),
|
||||
account_id.0.len(),
|
||||
nft_id.as_ptr(),
|
||||
nft_id.len(),
|
||||
nft_buffer.as_mut_ptr(),
|
||||
nft_buffer.len(),
|
||||
)
|
||||
};
|
||||
|
||||
if nft_result <= 0 {
|
||||
let _ = trace_num(
|
||||
"INFO: get_nft failed (expected - no such NFT):",
|
||||
nft_result as i64,
|
||||
);
|
||||
// This is expected - test account likely doesn't own the dummy NFT
|
||||
} else {
|
||||
let _ = trace_num("NFT data length:", nft_result as i64);
|
||||
let _ = trace_data(
|
||||
"NFT data:",
|
||||
&nft_buffer[..nft_result as usize],
|
||||
DataRepr::AsHex,
|
||||
);
|
||||
}
|
||||
|
||||
// Test 6.3: trace() - Debug logging with data
|
||||
let trace_message = b"Test trace message";
|
||||
let trace_data_payload = b"payload";
|
||||
let trace_result = unsafe {
|
||||
host::trace(
|
||||
trace_message.as_ptr(),
|
||||
trace_message.len(),
|
||||
trace_data_payload.as_ptr(),
|
||||
trace_data_payload.len(),
|
||||
1, // as_hex = true
|
||||
)
|
||||
};
|
||||
|
||||
if trace_result < 0 {
|
||||
let _ = trace_num("ERROR: trace() failed:", trace_result as i64);
|
||||
return -603; // Trace function failed
|
||||
}
|
||||
let _ = trace_num("Trace function bytes written:", trace_result as i64);
|
||||
|
||||
// Test 6.4: trace_num() - Debug logging with number
|
||||
let test_number = 42i64;
|
||||
let trace_num_result = trace_num("Test number trace", test_number);
|
||||
|
||||
use xrpl_std::host::Result;
|
||||
match trace_num_result {
|
||||
Result::Ok(_) => {
|
||||
let _ = trace_num("Trace_num function succeeded", 0);
|
||||
}
|
||||
Result::Err(_) => {
|
||||
let _ = trace_num("ERROR: trace_num() failed:", -604);
|
||||
return -604; // Trace number function failed
|
||||
}
|
||||
}
|
||||
|
||||
let _ = trace("SUCCESS: Utility functions");
|
||||
0
|
||||
}
|
||||
|
||||
/// Test Category 7: Data Update Functions (1 function)
|
||||
/// Tests the function for modifying the current ledger entry
|
||||
fn test_data_update_functions() -> i32 {
|
||||
let _ = trace("--- Category 7: Data Update Functions ---");
|
||||
|
||||
// Test 7.1: update_data() - Update current ledger entry data
|
||||
let update_payload = b"Updated ledger entry data from WASM test";
|
||||
|
||||
let update_result = unsafe { host::set_data(update_payload.as_ptr(), update_payload.len()) };
|
||||
|
||||
if update_result != update_payload.len() as i32 {
|
||||
let _ = trace_num("ERROR: update_data failed:", update_result as i64);
|
||||
return -701; // Data update failed
|
||||
}
|
||||
|
||||
let _ = trace_data(
|
||||
"Successfully updated ledger entry with:",
|
||||
update_payload,
|
||||
DataRepr::AsHex,
|
||||
);
|
||||
let _ = trace("SUCCESS: Data update functions");
|
||||
0
|
||||
}
|
||||
171
src/test/app/wasm_fixtures/all_keylets/Cargo.lock
generated
Normal file
171
src/test/app/wasm_fixtures/all_keylets/Cargo.lock
generated
Normal file
@@ -0,0 +1,171 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "all_keylets"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"xrpl-wasm-stdlib",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.10.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bs58"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4"
|
||||
dependencies = [
|
||||
"tinyvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"crypto-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.186"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.106"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.10.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.117"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3"
|
||||
dependencies = [
|
||||
"tinyvec_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec_macros"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
|
||||
[[package]]
|
||||
name = "xrpl-macros"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git?branch=renames#21c522f34a24b460297ebb6be1822680459bf37e"
|
||||
dependencies = [
|
||||
"bs58",
|
||||
"quote",
|
||||
"sha2",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xrpl-wasm-stdlib"
|
||||
version = "0.8.0"
|
||||
source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git?branch=renames#21c522f34a24b460297ebb6be1822680459bf37e"
|
||||
dependencies = [
|
||||
"xrpl-macros",
|
||||
]
|
||||
21
src/test/app/wasm_fixtures/all_keylets/Cargo.toml
Normal file
21
src/test/app/wasm_fixtures/all_keylets/Cargo.toml
Normal file
@@ -0,0 +1,21 @@
|
||||
[package]
|
||||
edition = "2024"
|
||||
name = "all_keylets"
|
||||
version = "0.0.1"
|
||||
|
||||
# This empty workspace definition keeps this project independent of the parent workspace
|
||||
[workspace]
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
opt-level = 's'
|
||||
panic = "abort"
|
||||
|
||||
[dependencies]
|
||||
xrpl-std = { git = "https://github.com/ripple/xrpl-wasm-stdlib.git", package = "xrpl-wasm-stdlib", branch = "renames" }
|
||||
|
||||
[profile.dev]
|
||||
panic = "abort"
|
||||
176
src/test/app/wasm_fixtures/all_keylets/src/lib.rs
Normal file
176
src/test/app/wasm_fixtures/all_keylets/src/lib.rs
Normal file
@@ -0,0 +1,176 @@
|
||||
#![cfg_attr(target_arch = "wasm32", no_std)]
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
extern crate std;
|
||||
|
||||
use crate::host::{Error, Result, Result::Err, Result::Ok};
|
||||
use xrpl_std::core::keylets;
|
||||
use xrpl_std::core::ledger_objects::current_escrow::get_current_escrow;
|
||||
use xrpl_std::core::ledger_objects::current_escrow::CurrentEscrow;
|
||||
use xrpl_std::core::ledger_objects::ledger_object;
|
||||
use xrpl_std::core::ledger_objects::traits::CurrentEscrowFields;
|
||||
use xrpl_std::core::ledger_objects::LedgerObjectFieldGetter;
|
||||
use xrpl_std::core::types::currency::Currency;
|
||||
use xrpl_std::core::types::issue::{IouIssue, Issue, XrpIssue};
|
||||
use xrpl_std::core::types::mpt_id::MptId;
|
||||
use xrpl_std::host;
|
||||
use xrpl_std::host::trace::{trace, trace_acct, trace_data, trace_num, DataRepr};
|
||||
use xrpl_std::sfield;
|
||||
|
||||
pub fn object_exists<T: LedgerObjectFieldGetter, const CODE: i32>(
|
||||
keylet_result: Result<keylets::KeyletBytes>,
|
||||
keylet_type: &str,
|
||||
sfield: sfield::SField<T, CODE>,
|
||||
) -> Result<bool> {
|
||||
let field = CODE;
|
||||
match keylet_result {
|
||||
Ok(keylet) => {
|
||||
let _ = trace_data(keylet_type, &keylet, DataRepr::AsHex);
|
||||
|
||||
let slot = unsafe { host::cache_le(keylet.as_ptr(), keylet.len(), 0) };
|
||||
if slot <= 0 {
|
||||
let _ = trace_num("Error: ", slot.into());
|
||||
return Err(Error::from_code(slot));
|
||||
}
|
||||
if field == 0 {
|
||||
let new_field = sfield::PreviousTxnID;
|
||||
let _ = trace_num("Getting field: ", new_field.clone().into());
|
||||
match ledger_object::get_field(slot, new_field) {
|
||||
Ok(data) => {
|
||||
let _ = trace_data("Field data: ", &data.0, DataRepr::AsHex);
|
||||
}
|
||||
Err(result_code) => {
|
||||
let _ = trace_num("Error getting field: ", result_code.into());
|
||||
return Err(result_code);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let _ = trace_num("Getting field: ", field.into());
|
||||
match ledger_object::get_field(slot, sfield) {
|
||||
Ok(_data) => {
|
||||
let _ = trace("Field data: retrieved");
|
||||
}
|
||||
Err(result_code) => {
|
||||
let _ = trace_num("Error getting field: ", result_code.into());
|
||||
return Err(result_code);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
Err(error) => {
|
||||
let _ = trace_num("Error getting keylet: ", error.into());
|
||||
Err(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "C" fn finish() -> i32 {
|
||||
let _ = trace("$$$$$ STARTING WASM EXECUTION $$$$$");
|
||||
|
||||
let escrow: CurrentEscrow = get_current_escrow();
|
||||
|
||||
let account = escrow.get_account().unwrap_or_panic();
|
||||
let _ = trace_acct("Account:", &account);
|
||||
|
||||
let destination = escrow.get_destination().unwrap_or_panic();
|
||||
let _ = trace_acct("Destination:", &destination);
|
||||
|
||||
let mut seq = 5;
|
||||
|
||||
macro_rules! check_object_exists {
|
||||
($keylet:expr, $type:expr, $field:expr) => {
|
||||
match object_exists($keylet, $type, $field) {
|
||||
Ok(_exists) => {
|
||||
// false isn't returned
|
||||
let _ = trace(concat!(
|
||||
$type,
|
||||
" object exists, proceeding with escrow finish."
|
||||
));
|
||||
}
|
||||
Err(error) => {
|
||||
let _ = trace_num("Current seq value:", seq.try_into().unwrap());
|
||||
return error.code();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
let accountroot_id = keylets::accountroot_id(&account);
|
||||
check_object_exists!(accountroot_id, "Account", sfield::Account);
|
||||
|
||||
let currency_code: &[u8; 3] = b"USD";
|
||||
let currency: Currency = Currency::from(*currency_code);
|
||||
let trustline_id = keylets::trustline_id(&account, &destination, ¤cy);
|
||||
check_object_exists!(trustline_id, "Trustline", sfield::Generic);
|
||||
seq += 1;
|
||||
|
||||
let asset1 = Issue::XRP(XrpIssue {});
|
||||
let asset2 = Issue::IOU(IouIssue::new(destination, currency));
|
||||
check_object_exists!(keylets::amm_id(&asset1, &asset2), "AMM", sfield::Account);
|
||||
|
||||
let check_id = keylets::check_id(&account, seq);
|
||||
check_object_exists!(check_id, "Check", sfield::Account);
|
||||
seq += 1;
|
||||
|
||||
let cred_type: &[u8] = b"termsandconditions";
|
||||
let credential_id = keylets::credential_id(&account, &account, cred_type);
|
||||
check_object_exists!(credential_id, "Credential", sfield::Subject);
|
||||
seq += 1;
|
||||
|
||||
let delegate_id = keylets::delegate_id(&account, &destination);
|
||||
check_object_exists!(delegate_id, "Delegate", sfield::Account);
|
||||
seq += 1;
|
||||
|
||||
let deposit_preauth_id = keylets::deposit_preauth_id(&account, &destination);
|
||||
check_object_exists!(deposit_preauth_id, "DepositPreauth", sfield::Account);
|
||||
seq += 1;
|
||||
|
||||
let did_id = keylets::did_id(&account);
|
||||
check_object_exists!(did_id, "DID", sfield::Account);
|
||||
seq += 1;
|
||||
|
||||
let escrow_id = keylets::escrow_id(&account, seq);
|
||||
check_object_exists!(escrow_id, "Escrow", sfield::Account);
|
||||
seq += 1;
|
||||
|
||||
let mpt_issuance_id = keylets::mpt_issuance_id(&account, seq);
|
||||
let mpt_id = MptId::new(seq.try_into().unwrap(), account);
|
||||
check_object_exists!(mpt_issuance_id, "MPTIssuance", sfield::Issuer);
|
||||
seq += 1;
|
||||
|
||||
let mptoken_id = keylets::mptoken_id(&mpt_id, &destination);
|
||||
check_object_exists!(mptoken_id, "MPToken", sfield::Account);
|
||||
|
||||
let nft_offer_id = keylets::nft_offer_id(&destination, 6);
|
||||
check_object_exists!(nft_offer_id, "NFTokenOffer", sfield::Owner);
|
||||
|
||||
let offer_id = keylets::offer_id(&account, seq);
|
||||
check_object_exists!(offer_id, "Offer", sfield::Account);
|
||||
seq += 1;
|
||||
|
||||
let paychan_id = keylets::paychan_id(&account, &destination, seq);
|
||||
check_object_exists!(paychan_id, "PayChannel", sfield::Account);
|
||||
seq += 1;
|
||||
|
||||
let pd_id = keylets::permissioned_domain_id(&account, seq);
|
||||
check_object_exists!(pd_id, "PermissionedDomain", sfield::Owner);
|
||||
seq += 1;
|
||||
|
||||
let signers_id = keylets::signers_id(&account);
|
||||
check_object_exists!(signers_id, "SignerList", sfield::Generic);
|
||||
seq += 1;
|
||||
|
||||
seq += 1; // ticket sequence number is one greater
|
||||
let ticket_id = keylets::ticket_id(&account, seq);
|
||||
check_object_exists!(ticket_id, "Ticket", sfield::Account);
|
||||
seq += 1;
|
||||
|
||||
let vault_id = keylets::vault_id(&account, seq);
|
||||
check_object_exists!(vault_id, "Vault", sfield::Account);
|
||||
// seq += 1;
|
||||
|
||||
1 // All keylets exist, finish the escrow.
|
||||
}
|
||||
42
src/test/app/wasm_fixtures/bad_align.c
Normal file
42
src/test/app/wasm_fixtures/bad_align.c
Normal file
@@ -0,0 +1,42 @@
|
||||
#include <stdint.h>
|
||||
|
||||
int32_t float_from_uint(uint8_t const *, int32_t, uint8_t *, int32_t, int32_t);
|
||||
int32_t check_id(uint8_t const *, int32_t, uint8_t const *, int32_t, uint8_t *,
|
||||
int32_t);
|
||||
|
||||
uint8_t e_data1[32 * 1024];
|
||||
uint8_t e_data2[32 * 1024];
|
||||
|
||||
int32_t test1()
|
||||
{
|
||||
e_data1[1] = 0xFF;
|
||||
e_data1[2] = 0xFF;
|
||||
e_data1[3] = 0xFF;
|
||||
e_data1[4] = 0xFF;
|
||||
e_data1[5] = 0xFF;
|
||||
e_data1[6] = 0xFF;
|
||||
e_data1[7] = 0xFF;
|
||||
e_data1[8] = 0xFF;
|
||||
int32_t result = float_from_uint(&e_data1[1], 8, &e_data1[35], 12, 0);
|
||||
return result >= 0 ? *((int32_t *)(&e_data1[36])) : result;
|
||||
}
|
||||
|
||||
int32_t test2()
|
||||
{
|
||||
// Set up misaligned uint32 (seq) at offset 1
|
||||
e_data2[1] = 0xFF;
|
||||
e_data2[2] = 0xFF;
|
||||
e_data2[3] = 0xFF;
|
||||
e_data2[4] = 0xFF;
|
||||
// Set up valid non-zero AccountID (20 bytes) at offset 10
|
||||
for (int i = 0; i < 20; i++)
|
||||
e_data2[10 + i] = i + 1;
|
||||
// Call check_id with misaligned uint32 at &e_data2[1] to hit line 72 in
|
||||
// HostFuncWrapper.cpp
|
||||
int32_t result = check_id(&e_data2[10], 20, &e_data2[1], 4, &e_data2[35], 32);
|
||||
// Return the misaligned value directly to validate it was read correctly (-1
|
||||
// if all 0xFF)
|
||||
return result >= 0 ? *((int32_t *)(&e_data2[36])) : result;
|
||||
}
|
||||
|
||||
int32_t test() { return test1() + test2(); }
|
||||
171
src/test/app/wasm_fixtures/codecov_tests/Cargo.lock
generated
Normal file
171
src/test/app/wasm_fixtures/codecov_tests/Cargo.lock
generated
Normal file
@@ -0,0 +1,171 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.10.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bs58"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4"
|
||||
dependencies = [
|
||||
"tinyvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||
|
||||
[[package]]
|
||||
name = "codecov_tests"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"xrpl-wasm-stdlib",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"crypto-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.186"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.106"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.10.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.117"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3"
|
||||
dependencies = [
|
||||
"tinyvec_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec_macros"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
|
||||
[[package]]
|
||||
name = "xrpl-macros"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git?branch=renames#9822d645870908a79d87a57b0244caa6359cb9cf"
|
||||
dependencies = [
|
||||
"bs58",
|
||||
"quote",
|
||||
"sha2",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xrpl-wasm-stdlib"
|
||||
version = "0.8.0"
|
||||
source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git?branch=renames#9822d645870908a79d87a57b0244caa6359cb9cf"
|
||||
dependencies = [
|
||||
"xrpl-macros",
|
||||
]
|
||||
18
src/test/app/wasm_fixtures/codecov_tests/Cargo.toml
Normal file
18
src/test/app/wasm_fixtures/codecov_tests/Cargo.toml
Normal file
@@ -0,0 +1,18 @@
|
||||
[package]
|
||||
edition = "2024"
|
||||
name = "codecov_tests"
|
||||
version = "0.0.1"
|
||||
|
||||
# This empty workspace definition keeps this project independent of the parent workspace
|
||||
[workspace]
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
opt-level = 's'
|
||||
panic = "abort"
|
||||
|
||||
[dependencies]
|
||||
xrpl-std = { git = "https://github.com/ripple/xrpl-wasm-stdlib.git", package = "xrpl-wasm-stdlib", branch = "renames" }
|
||||
@@ -0,0 +1,47 @@
|
||||
//TODO add docs after discussing the interface
|
||||
//Note that Craft currently does not honor the rounding modes
|
||||
#[allow(unused)]
|
||||
pub const FLOAT_ROUNDING_MODES_TO_NEAREST: i32 = 0;
|
||||
#[allow(unused)]
|
||||
pub const FLOAT_ROUNDING_MODES_TOWARDS_ZERO: i32 = 1;
|
||||
#[allow(unused)]
|
||||
pub const FLOAT_ROUNDING_MODES_DOWNWARD: i32 = 2;
|
||||
#[allow(unused)]
|
||||
pub const FLOAT_ROUNDING_MODES_UPWARD: i32 = 3;
|
||||
|
||||
// pub enum RippledRoundingModes{
|
||||
// ToNearest = 0,
|
||||
// TowardsZero = 1,
|
||||
// DOWNWARD = 2,
|
||||
// UPWARD = 3
|
||||
// }
|
||||
|
||||
#[allow(unused)]
|
||||
#[link(wasm_import_module = "host_lib")]
|
||||
unsafe extern "C" {
|
||||
pub fn parent_ldgr_hash(out_buff_ptr: i32, out_buff_len: i32) -> i32;
|
||||
|
||||
pub fn cache_le(keylet_ptr: i32, keylet_len: i32, cache_num: i32) -> i32;
|
||||
|
||||
pub fn tx_inner_arr_len(locator_ptr: i32, locator_len: i32) -> i32;
|
||||
|
||||
pub fn accountroot_id(
|
||||
account_ptr: i32,
|
||||
account_len: i32,
|
||||
out_buff_ptr: *mut u8,
|
||||
out_buff_len: usize,
|
||||
) -> i32;
|
||||
|
||||
pub fn trustline_id(
|
||||
account1_ptr: *const u8,
|
||||
account1_len: usize,
|
||||
account2_ptr: *const u8,
|
||||
account2_len: usize,
|
||||
currency_ptr: i32,
|
||||
currency_len: i32,
|
||||
out_buff_ptr: *mut u8,
|
||||
out_buff_len: usize,
|
||||
) -> i32;
|
||||
|
||||
pub fn trace_num(msg_read_ptr: i32, msg_read_len: i32, number: i64) -> i32;
|
||||
}
|
||||
1782
src/test/app/wasm_fixtures/codecov_tests/src/lib.rs
Normal file
1782
src/test/app/wasm_fixtures/codecov_tests/src/lib.rs
Normal file
File diff suppressed because it is too large
Load Diff
287
src/test/app/wasm_fixtures/copyFixtures.py
Normal file
287
src/test/app/wasm_fixtures/copyFixtures.py
Normal file
@@ -0,0 +1,287 @@
|
||||
# cspell: disable
|
||||
import os
|
||||
import re
|
||||
import shlex
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import zipfile
|
||||
from difflib import get_close_matches
|
||||
|
||||
OPT = "-Oz"
|
||||
BASE_PATH = os.path.abspath(os.path.dirname(__file__))
|
||||
|
||||
|
||||
def pascal_case(name):
|
||||
return "".join(word[:1].upper() + word[1:] for word in re.split(r"[_\W]+", name))
|
||||
|
||||
|
||||
def normalize_name(name):
|
||||
name = re.sub(r"([a-z0-9])([A-Z])", r"\1_\2", name)
|
||||
return re.sub(r"[^a-z0-9]", "", name.lower())
|
||||
|
||||
|
||||
def fixture_key(name):
|
||||
name = normalize_name(name).removeprefix("k")
|
||||
return name.removesuffix("wasmhex").removesuffix("hex")
|
||||
|
||||
|
||||
def declared_fixtures():
|
||||
h_path = os.path.join(BASE_PATH, "fixtures.h")
|
||||
with open(h_path, "r", encoding="utf8") as f:
|
||||
return re.findall(
|
||||
r"extern std::string const ([A-Za-z_][A-Za-z0-9_]*);", f.read()
|
||||
)
|
||||
|
||||
|
||||
def find_fixture_name(project_name, suffix):
|
||||
default = re.sub(r"_([a-z])", lambda m: m.group(1).upper(), project_name) + suffix
|
||||
k_default = f"k{pascal_case(project_name)}{suffix}"
|
||||
declarations = declared_fixtures()
|
||||
normalized = {normalize_name(name): name for name in declarations}
|
||||
fixture_keys = {fixture_key(name): name for name in declarations}
|
||||
|
||||
for name in (default, k_default):
|
||||
if normalize_name(name) in normalized:
|
||||
return normalized[normalize_name(name)]
|
||||
|
||||
project_key = normalize_name(project_name)
|
||||
matches = [
|
||||
name
|
||||
for key, name in fixture_keys.items()
|
||||
if key.endswith(project_key)
|
||||
or key.startswith(project_key)
|
||||
or project_key.endswith(key)
|
||||
or project_key.startswith(key)
|
||||
]
|
||||
if len(matches) == 1:
|
||||
return matches[0]
|
||||
|
||||
close = get_close_matches(project_key, fixture_keys.keys(), n=1, cutoff=0.82)
|
||||
if close:
|
||||
return fixture_keys[close[0]]
|
||||
|
||||
return k_default
|
||||
|
||||
|
||||
def fixture_cpp_path(fixture_name):
|
||||
pattern = rf"extern std::string const {fixture_name} ="
|
||||
for file_name in os.listdir(BASE_PATH):
|
||||
if not file_name.endswith(".cpp"):
|
||||
continue
|
||||
cpp_path = os.path.join(BASE_PATH, file_name)
|
||||
with open(cpp_path, "r", encoding="utf8") as f:
|
||||
if re.search(pattern, f.read()):
|
||||
return cpp_path
|
||||
return os.path.join(BASE_PATH, "fixtures.cpp")
|
||||
|
||||
|
||||
def update_fixture(project_name, wasm, suffix="WasmHex"):
|
||||
fixture_name = find_fixture_name(project_name, suffix)
|
||||
print(f"Updating fixture: {fixture_name}")
|
||||
|
||||
cpp_path = fixture_cpp_path(fixture_name)
|
||||
h_path = os.path.join(BASE_PATH, "fixtures.h")
|
||||
with open(cpp_path, "r", encoding="utf8") as f:
|
||||
cpp_content = f.read()
|
||||
|
||||
pattern = rf'extern std::string const {fixture_name} =[ \n]+"[^;]*;'
|
||||
if re.search(pattern, cpp_content, flags=re.MULTILINE):
|
||||
updated_cpp_content = re.sub(
|
||||
pattern,
|
||||
f'extern std::string const {fixture_name} = "{wasm}";',
|
||||
cpp_content,
|
||||
flags=re.MULTILINE,
|
||||
)
|
||||
else:
|
||||
with open(h_path, "r", encoding="utf8") as f:
|
||||
h_content = f.read()
|
||||
updated_h_content = (
|
||||
h_content.rstrip() + f"\n\nextern std::string const {fixture_name};\n"
|
||||
)
|
||||
with open(h_path, "w", encoding="utf8") as f:
|
||||
f.write(updated_h_content)
|
||||
updated_cpp_content = (
|
||||
cpp_content.rstrip()
|
||||
+ f'\n\nextern std::string const {fixture_name} = "{wasm}";\n'
|
||||
)
|
||||
|
||||
with open(cpp_path, "w", encoding="utf8") as f:
|
||||
f.write(updated_cpp_content)
|
||||
|
||||
|
||||
def read_wasm_hex(path):
|
||||
with open(path, "rb") as f:
|
||||
return f.read().hex()
|
||||
|
||||
|
||||
def process_rust(project_name):
|
||||
project_path = os.path.join(BASE_PATH, project_name)
|
||||
wasm_location = os.path.join(
|
||||
project_path, "target", "wasm32v1-none", "release", f"{project_name}.wasm"
|
||||
)
|
||||
try:
|
||||
subprocess.run(
|
||||
["cargo", "build", "--target", "wasm32v1-none", "--release"],
|
||||
cwd=project_path,
|
||||
check=True,
|
||||
)
|
||||
subprocess.run(
|
||||
["wasm-opt", wasm_location, OPT, "-o", wasm_location], check=True
|
||||
)
|
||||
print(f"WASM file for {project_name} has been built and optimized.")
|
||||
except FileNotFoundError as e:
|
||||
print(f"exec error: {e.filename} is required to build Rust fixtures")
|
||||
sys.exit(1)
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"exec error: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
update_fixture(project_name, read_wasm_hex(wasm_location))
|
||||
|
||||
|
||||
def process_c(project_name):
|
||||
project_path = os.path.join(BASE_PATH, f"{project_name}.c")
|
||||
wasm_path = os.path.join(BASE_PATH, f"{project_name}.wasm")
|
||||
cc = os.environ.get("CC")
|
||||
sysroot = os.environ.get("SYSROOT")
|
||||
if not cc or not sysroot:
|
||||
print("exec error: CC and SYSROOT are required to build C fixtures")
|
||||
sys.exit(1)
|
||||
|
||||
build_cmd = [
|
||||
*shlex.split(cc),
|
||||
f"--sysroot={sysroot}",
|
||||
"-O3",
|
||||
"-ffast-math",
|
||||
"--target=wasm32",
|
||||
"-fno-exceptions",
|
||||
"-fno-threadsafe-statics",
|
||||
"-fvisibility=default",
|
||||
"-Wl,--export-all",
|
||||
"-Wl,--no-entry",
|
||||
"-Wl,--allow-undefined",
|
||||
"-DNDEBUG",
|
||||
"--no-standard-libraries",
|
||||
"-fno-builtin-memset",
|
||||
"-o",
|
||||
wasm_path,
|
||||
project_path,
|
||||
]
|
||||
try:
|
||||
subprocess.run(build_cmd, check=True)
|
||||
subprocess.run(["wasm-opt", wasm_path, OPT, "-o", wasm_path], check=True)
|
||||
print(
|
||||
f"WASM file for {project_name} has been built with WASI support using clang."
|
||||
)
|
||||
except FileNotFoundError as e:
|
||||
print(f"exec error: {e.filename} is required to build C fixtures")
|
||||
sys.exit(1)
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"exec error: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
update_fixture(project_name, read_wasm_hex(wasm_path))
|
||||
|
||||
|
||||
def wat_to_wasm(wat_path, wasm_path):
|
||||
build_cmd = ["wat2wasm", wat_path, "-o", wasm_path]
|
||||
try:
|
||||
subprocess.run(build_cmd, check=True)
|
||||
print(f"WASM file for {os.path.basename(wat_path)} has been built.")
|
||||
except FileNotFoundError:
|
||||
print("exec error: wat2wasm is required to build WAT fixtures")
|
||||
sys.exit(1)
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"exec error: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def process_wat_file(wat_path):
|
||||
project_name = os.path.splitext(os.path.basename(wat_path))[0]
|
||||
with open(wat_path, "r", encoding="utf8") as f:
|
||||
if "(module" not in f.read():
|
||||
print(f"Skipping WAT fixture without a module: {project_name}")
|
||||
return
|
||||
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
wasm_path = os.path.join(tmpdir, f"{project_name}.wasm")
|
||||
wat_to_wasm(wat_path, wasm_path)
|
||||
update_fixture(project_name, read_wasm_hex(wasm_path), "Hex")
|
||||
|
||||
|
||||
def process_wat_zip(zip_path):
|
||||
project_name = os.path.splitext(os.path.basename(zip_path))[0]
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
with zipfile.ZipFile(zip_path) as archive:
|
||||
wat_names = [name for name in archive.namelist() if name.endswith(".wat")]
|
||||
if len(wat_names) != 1:
|
||||
print(f"exec error: expected one .wat file in {zip_path}")
|
||||
sys.exit(1)
|
||||
archive.extract(wat_names[0], tmpdir)
|
||||
|
||||
wasm_path = os.path.join(tmpdir, f"{project_name}.wasm")
|
||||
wat_to_wasm(os.path.join(tmpdir, wat_names[0]), wasm_path)
|
||||
update_fixture(project_name, read_wasm_hex(wasm_path), "Hex")
|
||||
|
||||
|
||||
def process_wat(project_name):
|
||||
candidates = [
|
||||
os.path.join(BASE_PATH, f"{project_name}.wat"),
|
||||
os.path.join(BASE_PATH, "wat", f"{project_name}.wat"),
|
||||
os.path.join(BASE_PATH, "wat", f"{project_name}.zip"),
|
||||
]
|
||||
for path in candidates:
|
||||
if os.path.isfile(path):
|
||||
if path.endswith(".zip"):
|
||||
process_wat_zip(path)
|
||||
else:
|
||||
process_wat_file(path)
|
||||
return
|
||||
|
||||
print(f"exec error: fixture {project_name} not found")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) > 2:
|
||||
print("Usage: python copyFixtures.py [<project_name>]")
|
||||
sys.exit(1)
|
||||
|
||||
if len(sys.argv) == 2:
|
||||
project_name = os.path.splitext(os.path.basename(sys.argv[1]))[0]
|
||||
if os.path.isfile(os.path.join(BASE_PATH, project_name, "Cargo.toml")):
|
||||
process_rust(project_name)
|
||||
elif os.path.isfile(os.path.join(BASE_PATH, f"{project_name}.c")):
|
||||
process_c(project_name)
|
||||
else:
|
||||
process_wat(project_name)
|
||||
print("Fixture has been processed.")
|
||||
else:
|
||||
dirs = [
|
||||
d
|
||||
for d in os.listdir(BASE_PATH)
|
||||
if os.path.isfile(os.path.join(BASE_PATH, d, "Cargo.toml"))
|
||||
]
|
||||
c_files = [f for f in os.listdir(BASE_PATH) if f.endswith(".c")]
|
||||
wat_files = [f for f in os.listdir(BASE_PATH) if f.endswith(".wat")]
|
||||
wat_path = os.path.join(BASE_PATH, "wat")
|
||||
wat_fixture_files = [
|
||||
f
|
||||
for f in (os.listdir(wat_path) if os.path.isdir(wat_path) else [])
|
||||
if f.endswith((".wat", ".zip"))
|
||||
]
|
||||
|
||||
for d in sorted(dirs):
|
||||
process_rust(d)
|
||||
for c in sorted(c_files):
|
||||
process_c(c[:-2])
|
||||
for wat in sorted(wat_files):
|
||||
process_wat_file(os.path.join(BASE_PATH, wat))
|
||||
for wat_fixture in sorted(wat_fixture_files):
|
||||
path = os.path.join(wat_path, wat_fixture)
|
||||
if wat_fixture.endswith(".zip"):
|
||||
process_wat_zip(path)
|
||||
else:
|
||||
process_wat_file(path)
|
||||
print("All fixtures have been processed.")
|
||||
650
src/test/app/wasm_fixtures/fixtures.cpp
Normal file
650
src/test/app/wasm_fixtures/fixtures.cpp
Normal file
@@ -0,0 +1,650 @@
|
||||
// TODO: consider moving these to separate files (and figure out the build)
|
||||
|
||||
#include <test/app/wasm_fixtures/fixtures.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
extern std::string const kLedgerSqnWasmHex =
|
||||
"0061736d01000000010e0360027f7f017f6000006000017f02120103656e760a6c6467725f696e6465780000030302"
|
||||
"01020503010002062b077f01418088040b7f004180080b7f004180080b7f004180080b7f00418088040b7f0041000b"
|
||||
"7f0041010b07800109066d656d6f72790200115f5f7761736d5f63616c6c5f63746f727300010666696e6973680002"
|
||||
"0c5f5f64736f5f68616e646c6503010a5f5f646174615f656e6403020d5f5f676c6f62616c5f6261736503030b5f5f"
|
||||
"686561705f6261736503040d5f5f6d656d6f72795f6261736503050c5f5f7461626c655f6261736503060a3d020200"
|
||||
"0b3801037f230041106b220024002000410c6a410410002101200028020c2102200041106a24002001410541002002"
|
||||
"41054f1b20014100481b0b002f0970726f647563657273010c70726f6365737365642d6279010e486f6d6562726577"
|
||||
"20636c616e670631342e302e36";
|
||||
|
||||
extern std::string const kAllHostFunctionsWasmHex =
|
||||
"0061736d0100000001540c60027f7f017f60037f7f7f017f60047f7f7f7f017f60017f017f60067f7f7f7f7f7f017f"
|
||||
"60037f7f7f0060057f7f7f7f7f017f60037f7f7e017f60087f7f7f7f7f7f7f7f017f60017f0060027f7f006000017f"
|
||||
"02dc041a08686f73745f6c69620874785f6669656c64000108686f73745f6c69620974726163655f6e756d00070868"
|
||||
"6f73745f6c6962057472616365000608686f73745f6c69620a6c6467725f696e646578000008686f73745f6c696210"
|
||||
"706172656e745f6c6467725f74696d65000008686f73745f6c696210706172656e745f6c6467725f68617368000008"
|
||||
"686f73745f6c69620874785f696e6e6572000208686f73745f6c69620a74785f6172725f6c656e000308686f73745f"
|
||||
"6c69621074785f696e6e65725f6172725f6c656e000008686f73745f6c69620d686f6d655f6c655f6669656c640001"
|
||||
"08686f73745f6c69620d686f6d655f6c655f696e6e6572000208686f73745f6c69620f686f6d655f6c655f6172725f"
|
||||
"6c656e000308686f73745f6c696215686f6d655f6c655f696e6e65725f6172725f6c656e000008686f73745f6c6962"
|
||||
"0863616368655f6c65000108686f73745f6c69620d63726564656e7469616c5f6964000808686f73745f6c69620965"
|
||||
"7363726f775f6964000408686f73745f6c6962096f7261636c655f6964000408686f73745f6c69620b736861353132"
|
||||
"5f68616c66000208686f73745f6c6962076e66745f757269000408686f73745f6c6962087365745f64617461000008"
|
||||
"686f73745f6c6962086c655f6669656c64000208686f73745f6c6962086c655f696e6e6572000608686f73745f6c69"
|
||||
"620a6c655f6172725f6c656e000008686f73745f6c6962106c655f696e6e65725f6172725f6c656e000108686f7374"
|
||||
"5f6c69620e6163636f756e74726f6f745f6964000208686f73745f6c69620a74726163655f616363740002030c0b09"
|
||||
"0a05050b05000101030005030100110619037f01418080c0000b7f0041af99c0000b7f0041b099c0000b072e04066d"
|
||||
"656d6f727902000666696e697368001e0a5f5f646174615f656e6403010b5f5f686561705f6261736503020ac61d0b"
|
||||
"990101027f230041306b220124002000027f418180202001411c6a4114100022024114470440417f20022002417f4e"
|
||||
"1b210241010c010b200020012f001c3b0001200041036a2001411e6a2d00003a000020012001290023370308200120"
|
||||
"0141286a29000037000d200128001f21022000410d6a200129000d3700002000200129030837020841000b3a000020"
|
||||
"002002360204200141306a24000b460020012d00004101460440418080c000410b20013402041001000b2000200129"
|
||||
"0001370000200041106a200141116a280000360000200041086a200141096a2900003700000b1900200241094f0440"
|
||||
"000b20002002360204200020013602000b1900200241214f0440000b20002002360204200020013602000bde1a0109"
|
||||
"7f230041b0036b22002400418b80c000411b41014100410010021a41a680c000411941014100410010021a41e780c0"
|
||||
"00412b41014100410010021a2000410036027002400240024002400240024002400240200041f0006a220741041003"
|
||||
"220141004a0440419281c00041172000280270220141187420014180fe03714108747220014108764180fe03712001"
|
||||
"4118767272ad10011a200041003602900120004190016a220341041004220141004c0d0141a981c000411320002802"
|
||||
"9001220141187420014180fe03714108747220014108764180fe037120014118767272ad10011a200041c8016a2202"
|
||||
"4200370300200041c0016a22054200370300200041b8016a22044200370300200042003703b001200041b0016a2206"
|
||||
"4120100522014120470d0241bc81c000411320064120410110021a41cf81c000412041014100410010021a41dc82c0"
|
||||
"00412e41014100410010021a200041a0016a410036020020004198016a420037030020004200370390014181802020"
|
||||
"034114100022014114470d03418a83c00041142003101f200042003703704188801820074108100022014108470d04"
|
||||
"419e83c0004117420810011a41b583c000412820074108410110021a2000410036024841848008200041c8006a2203"
|
||||
"4104100022014104470d0541dd83c000411520034104410110021a200041013b003420024200370300200542003703"
|
||||
"0020044200370300200042003703b0010240200041346a4102200641201006220141004e044041f283c00041142001"
|
||||
"ad10011a200041286a20062001101d418684c000410d2000280228200028022c410110021a0c010b419384c0004129"
|
||||
"2001ac10011a0b41bc84c00041154183803c1007ac10011a41d184c00041134189803c1007ac10011a024020004134"
|
||||
"6a41021008220141004e044041e484c00041142001ad10011a0c010b41f884c000412d2001ac10011a0b41a585c000"
|
||||
"412341014100410010021a41de86c000413341014100410010021a2000420037037041828018200041f0006a220141"
|
||||
"081009220341004c0d0620034108460440419187c000412b420810011a41bc87c000412f20014108410110021a0c08"
|
||||
"0b41eb87c000412f2003ad10011a200041206a200041f0006a2003101c419a88c00041172000280220200028022441"
|
||||
"0110021a0c070b41bf82c000411d2001ac10011a419b7f21020c070b419a82c00041252001ac10011a419a7f21020c"
|
||||
"060b41ef81c000412b2001ac10011a41997f21020c050b41b486c000412a2001ac10011a41b77e21020c040b41f385"
|
||||
"c00041c1002001ac10011a41b67e21020c030b41c885c000412b2001ac10011a41b57e21020c020b41b188c00041c5"
|
||||
"002003ac10011a0b200041a0016a410036020020004198016a42003703002000420037039001024041818020200041"
|
||||
"90016a220341141009220141004a044041f688c000411e2003101f0c010b419489c00041332001ac10011a0b200041"
|
||||
"013b0048200041c8016a4200370300200041c0016a4200370300200041b8016a4200370300200042003703b0010240"
|
||||
"200041c8006a4102200041b0016a22014120100a220341004e044041c789c000411c2003ad10011a200041186a2001"
|
||||
"2003101d41e389c00041152000280218200028021c410110021a0c010b41f889c00041392003ac10011a0b41b18ac0"
|
||||
"0041244183803c100bac10011a0240200041c8006a4102100c220141004e044041d58ac000411c2001ad10011a0c01"
|
||||
"0b41f18ac000413d2001ac10011a0b41ae8bc000412841014100410010021a41d68bc000412f41014100410010021a"
|
||||
"200041b0016a2203101a200041f0006a22012003101b200041a8016a4200370300200041a0016a4200370300200041"
|
||||
"98016a4200370300200042003703900102400240024002400240200120004190016a22031020220141204604402003"
|
||||
"41204100100d220441004a044041858cc00041232004ad10011a200042003703482004200041c8006a220141081021"
|
||||
"220341004c0d022003410846044041a88cc000412a420810011a41d28cc000412e20014108410110021a0c060b4180"
|
||||
"8dc000412e2003ad10011a200041106a200041c8006a2003101c41ae8dc00041162000280210200028021441011002"
|
||||
"1a0c050b41e68fc000413c2004ac10011a200041c8016a4200370300200041c0016a4200370300200041b8016a4200"
|
||||
"370300200042003703b0014101200041b0016a4120102122014100480d020c030b41ba92c000412e2001ac10011a41"
|
||||
"ef7c21020c050b41c48dc000412b2003ac10011a0c020b41a290c00041c1002001ac10011a0b200041013b00484101"
|
||||
"200041c8006a200041b0016a10222201410048044041e390c00041352001ac10011a0b410110232201410048044041"
|
||||
"9891c00041322001ac10011a0b4101200041c8006a10242201410048044041ca91c00041392001ac10011a0b418392"
|
||||
"c000413741014100410010021a0c010b200041013b0034200041c8016a4200370300200041c0016a42003703002000"
|
||||
"41b8016a4200370300200042003703b00102402004200041346a200041b0016a22011022220341004e044041ef8dc0"
|
||||
"00411b2003ad10011a200041086a20012003101d418a8ec00041142000280208200028020c410110021a0c010b419e"
|
||||
"8ec00041312003ac10011a0b41cf8ec000412320041023ac10011a02402004200041346a1024220141004e044041f2"
|
||||
"8ec000411b2001ad10011a0c010b418d8fc00041352001ac10011a0b41c28fc000412441014100410010021a0b41e8"
|
||||
"92c000412f41014100410010021a200041b0016a2201101a200041346a22042001101b200041e0006a420037030020"
|
||||
"0041d8006a4200370300200041d0006a420037030020004200370348024002400240024002402004200041c8006a22"
|
||||
"03102022014120460440419793c000410f20034120410110021a20004188016a420037030020004180016a42003703"
|
||||
"00200041f8006a4200370300200042003703700240200441142004411441a693c0004109200041f0006a2201412010"
|
||||
"0e220341004a0440200020012003101d41ae93c000411220002802002000280204410110021a0c010b41c093c00041"
|
||||
"3c2003ac10011a0b200041a8016a22064200370300200041a0016a2202420037030020004198016a22054200370300"
|
||||
"200042003703900120004180808cc07e360268200041346a22034114200041e8006a410420004190016a2208412010"
|
||||
"0f22014120470d0141fc93c000410e20084120410110021a200041c8016a4200370300200041c0016a420037030020"
|
||||
"0041b8016a4200370300200042003703b001200041808080d00236026c20034114200041ec006a4104200041b0016a"
|
||||
"22044120101022014120470d02418a94c000410e20044120410110021a419894c000412441014100410010021a4191"
|
||||
"95c000412541014100410010021a20004188016a420037030020004180016a4200370300200041f8006a4200370300"
|
||||
"2000420037037041b695c0004117200041f0006a22034120101122014120470d0341cd95c000410b41b695c0004117"
|
||||
"410110021a41d895c000411120034120410110021a2004101a200041c8006a22072004101b20064200370300200242"
|
||||
"0037030020054200370300200042003703900102404100200422026b410371220320026a220520024d0d0020030440"
|
||||
"200321010340200241003a0000200241016a2102200141016b22010d000b0b200341016b4107490d00034020024100"
|
||||
"3a0000200241076a41003a0000200241066a41003a0000200241056a41003a0000200241046a41003a000020024103"
|
||||
"6a41003a0000200241026a41003a0000200241016a41003a0000200241086a22022005470d000b0b20054180022003"
|
||||
"6b2201417c716a220220054b0440034020054100360200200541046a22052002490d000b0b02402002200141037122"
|
||||
"0120026a22034f0d002001220504400340200241003a0000200241016a2102200541016b22050d000b0b200141016b"
|
||||
"4107490d000340200241003a0000200241076a41003a0000200241066a41003a0000200241056a41003a0000200241"
|
||||
"046a41003a0000200241036a41003a0000200241026a41003a0000200241016a41003a0000200241086a2202200347"
|
||||
"0d000b0b0240200741142008412020044180021012220141004a044041e995c00041102001ad10011a20014181024f"
|
||||
"0d0641f995c000410920042001410110021a0c010b418296c000412e2001ac10011a0b41b096c000411241c296c000"
|
||||
"41074101100222014100480d0541c996c000411d2001ad10011a41e696c0004111422a1001410048044041ad97c000"
|
||||
"411a42a47b10011a41a47b21020c070b41f796c000411c420010011a41012102419397c000411a4101410041001002"
|
||||
"1a41ff97c000412941014100410010021a41a898c000412810132201412846044041d098c000412741a898c0004128"
|
||||
"410110021a41f798c000411e41014100410010021a41bf80c000412841014100410010021a0c070b419599c000411a"
|
||||
"2001ac10011a41c37a21020c060b41f494c000411d2001ac10011a418b7c21020c050b41d894c000411c2001ac1001"
|
||||
"1a41897c21020c040b41bc94c000411c2001ac10011a41887c21020c030b41dd97c00041222001ac10011a41a77b21"
|
||||
"020c020b000b41c797c00041162001ac10011a41a57b21020b200041b0036a240020020b0d00200020012002411410"
|
||||
"191a0b0c00200041142001412010180b0e002000418280182001200210140b0e002000200141022002412010150b0a"
|
||||
"0020004183803c10160b0a0020002001410210170b0bb9190100418080c0000baf196572726f725f636f64653d3d3d"
|
||||
"3d20484f53542046554e4354494f4e532054455354203d3d3d54657374696e6720323620686f73742066756e637469"
|
||||
"6f6e73535543434553533a20416c6c20686f73742066756e6374696f6e20746573747320706173736564212d2d2d20"
|
||||
"43617465676f727920313a204c6564676572204865616465722046756e6374696f6e73202d2d2d4c65646765722073"
|
||||
"657175656e6365206e756d6265723a506172656e74206c65646765722074696d653a506172656e74206c6564676572"
|
||||
"20686173683a535543434553533a204c6564676572206865616465722066756e6374696f6e734552524f523a206765"
|
||||
"745f706172656e745f6c65646765725f686173682077726f6e67206c656e6774683a4552524f523a206765745f7061"
|
||||
"72656e745f6c65646765725f74696d65206661696c65643a4552524f523a206765745f6c65646765725f73716e2066"
|
||||
"61696c65643a2d2d2d2043617465676f727920323a205472616e73616374696f6e20446174612046756e6374696f6e"
|
||||
"73202d2d2d5472616e73616374696f6e204163636f756e743a5472616e73616374696f6e20466565206c656e677468"
|
||||
"3a5472616e73616374696f6e20466565202873657269616c697a65642058525020616d6f756e74293a5472616e7361"
|
||||
"6374696f6e2053657175656e63653a4e6573746564206669656c64206c656e6774683a4e6573746564206669656c64"
|
||||
"3a494e464f3a206765745f74785f6e65737465645f6669656c64206e6f74206170706c696361626c653a5369676e65"
|
||||
"7273206172726179206c656e6774683a4d656d6f73206172726179206c656e6774683a4e6573746564206172726179"
|
||||
"206c656e6774683a494e464f3a206765745f74785f6e65737465645f61727261795f6c656e206e6f74206170706c69"
|
||||
"6361626c653a535543434553533a205472616e73616374696f6e20646174612066756e6374696f6e734552524f523a"
|
||||
"206765745f74785f6669656c642853657175656e6365292077726f6e67206c656e6774683a4552524f523a20676574"
|
||||
"5f74785f6669656c6428466565292077726f6e67206c656e6774682028657870656374656420382062797465732066"
|
||||
"6f7220585250293a4552524f523a206765745f74785f6669656c64284163636f756e74292077726f6e67206c656e67"
|
||||
"74683a2d2d2d2043617465676f727920333a2043757272656e74204c6564676572204f626a6563742046756e637469"
|
||||
"6f6e73202d2d2d43757272656e74206f626a6563742062616c616e6365206c656e677468202858525020616d6f756e"
|
||||
"74293a43757272656e74206f626a6563742062616c616e6365202873657269616c697a65642058525020616d6f756e"
|
||||
"74293a43757272656e74206f626a6563742062616c616e6365206c656e67746820286e6f6e2d58525020616d6f756e"
|
||||
"74293a43757272656e74206f626a6563742062616c616e63653a494e464f3a206765745f63757272656e745f6c6564"
|
||||
"6765725f6f626a5f6669656c642842616c616e636529206661696c656420286d617920626520657870656374656429"
|
||||
"3a43757272656e74206c6564676572206f626a656374206163636f756e743a494e464f3a206765745f63757272656e"
|
||||
"745f6c65646765725f6f626a5f6669656c64284163636f756e7429206661696c65643a43757272656e74206e657374"
|
||||
"6564206669656c64206c656e6774683a43757272656e74206e6573746564206669656c643a494e464f3a206765745f"
|
||||
"63757272656e745f6c65646765725f6f626a5f6e65737465645f6669656c64206e6f74206170706c696361626c653a"
|
||||
"43757272656e74206f626a656374205369676e657273206172726179206c656e6774683a43757272656e74206e6573"
|
||||
"746564206172726179206c656e6774683a494e464f3a206765745f63757272656e745f6c65646765725f6f626a5f6e"
|
||||
"65737465645f61727261795f6c656e206e6f74206170706c696361626c653a535543434553533a2043757272656e74"
|
||||
"206c6564676572206f626a6563742066756e6374696f6e732d2d2d2043617465676f727920343a20416e79204c6564"
|
||||
"676572204f626a6563742046756e6374696f6e73202d2d2d5375636365737366756c6c7920636163686564206f626a"
|
||||
"65637420696e20736c6f743a436163686564206f626a6563742062616c616e6365206c656e67746820285852502061"
|
||||
"6d6f756e74293a436163686564206f626a6563742062616c616e6365202873657269616c697a65642058525020616d"
|
||||
"6f756e74293a436163686564206f626a6563742062616c616e6365206c656e67746820286e6f6e2d58525020616d6f"
|
||||
"756e74293a436163686564206f626a6563742062616c616e63653a494e464f3a206765745f6c65646765725f6f626a"
|
||||
"5f6669656c642842616c616e636529206661696c65643a436163686564206e6573746564206669656c64206c656e67"
|
||||
"74683a436163686564206e6573746564206669656c643a494e464f3a206765745f6c65646765725f6f626a5f6e6573"
|
||||
"7465645f6669656c64206e6f74206170706c696361626c653a436163686564206f626a656374205369676e65727320"
|
||||
"6172726179206c656e6774683a436163686564206e6573746564206172726179206c656e6774683a494e464f3a2067"
|
||||
"65745f6c65646765725f6f626a5f6e65737465645f61727261795f6c656e206e6f74206170706c696361626c653a53"
|
||||
"5543434553533a20416e79206c6564676572206f626a6563742066756e6374696f6e73494e464f3a2063616368655f"
|
||||
"6c65646765725f6f626a206661696c6564202865787065637465642077697468207465737420666978747572657329"
|
||||
"3a494e464f3a206765745f6c65646765725f6f626a5f6669656c64206661696c656420617320657870656374656420"
|
||||
"286e6f20636163686564206f626a656374293a494e464f3a206765745f6c65646765725f6f626a5f6e65737465645f"
|
||||
"6669656c64206661696c65642061732065787065637465643a494e464f3a206765745f6c65646765725f6f626a5f61"
|
||||
"727261795f6c656e206661696c65642061732065787065637465643a494e464f3a206765745f6c65646765725f6f62"
|
||||
"6a5f6e65737465645f61727261795f6c656e206661696c65642061732065787065637465643a535543434553533a20"
|
||||
"416e79206c6564676572206f626a6563742066756e6374696f6e732028696e74657266616365207465737465642945"
|
||||
"52524f523a206163636f756e74726f6f745f6964206661696c656420666f722063616368696e6720746573743a2d2d"
|
||||
"2d2043617465676f727920353a204b65796c65742047656e65726174696f6e2046756e6374696f6e73202d2d2d4163"
|
||||
"636f756e74206b65796c65743a546573745479706543726564656e7469616c206b65796c65743a494e464f3a206372"
|
||||
"6564656e7469616c5f6b65796c6574206661696c656420286578706563746564202d20696e74657266616365206973"
|
||||
"737565293a457363726f77206b65796c65743a4f7261636c65206b65796c65743a535543434553533a204b65796c65"
|
||||
"742067656e65726174696f6e2066756e6374696f6e734552524f523a206f7261636c655f6b65796c6574206661696c"
|
||||
"65643a4552524f523a20657363726f775f6b65796c6574206661696c65643a4552524f523a206163636f756e74726f"
|
||||
"6f745f6964206661696c65643a2d2d2d2043617465676f727920363a205574696c6974792046756e6374696f6e7320"
|
||||
"2d2d2d48656c6c6f2c205852504c205741534d20776f726c6421496e70757420646174613a5348413531322068616c"
|
||||
"6620686173683a4e46542064617461206c656e6774683a4e465420646174613a494e464f3a206765745f6e66742066"
|
||||
"61696c656420286578706563746564202d206e6f2073756368204e4654293a54657374207472616365206d65737361"
|
||||
"67657061796c6f616454726163652066756e6374696f6e206279746573207772697474656e3a54657374206e756d62"
|
||||
"657220747261636554726163655f6e756d2066756e6374696f6e20737563636565646564535543434553533a205574"
|
||||
"696c6974792066756e6374696f6e734552524f523a2074726163655f6e756d2829206661696c65643a4552524f523a"
|
||||
"2074726163652829206661696c65643a4552524f523a20636f6d707574655f7368613531325f68616c66206661696c"
|
||||
"65643a2d2d2d2043617465676f727920373a2044617461205570646174652046756e6374696f6e73202d2d2d557064"
|
||||
"61746564206c656467657220656e74727920646174612066726f6d205741534d20746573745375636365737366756c"
|
||||
"6c792075706461746564206c656467657220656e74727920776974683a535543434553533a20446174612075706461"
|
||||
"74652066756e6374696f6e734552524f523a207570646174655f64617461206661696c65643a004d0970726f647563"
|
||||
"65727302086c616e6775616765010452757374000c70726f6365737365642d6279010572757374631d312e38372e30"
|
||||
"202831373036376539616320323032352d30352d303929002c0f7461726765745f6665617475726573022b0f6d7574"
|
||||
"61626c652d676c6f62616c732b087369676e2d657874";
|
||||
|
||||
extern std::string const kAllKeyletsWasmHex =
|
||||
"0061736d0100000001500a60067f7f7f7f7f7f017f60047f7f7f7f017f60087f7f7f7f7f7f7f7f017f60047f7f7f7f"
|
||||
"0060037f7f7f017f60037f7f7e017f60057f7f7f7f7f017f6000017f60037f7f7f0060067f7f7f7f7f7e00029f0418"
|
||||
"08686f73745f6c69620974726163655f6e756d000508686f73745f6c6962057472616365000608686f73745f6c6962"
|
||||
"0863616368655f6c65000408686f73745f6c6962086c655f6669656c64000108686f73745f6c69620d686f6d655f6c"
|
||||
"655f6669656c64000408686f73745f6c69620a74726163655f61636374000108686f73745f6c69620e6163636f756e"
|
||||
"74726f6f745f6964000108686f73745f6c69620c74727573746c696e655f6964000208686f73745f6c696206616d6d"
|
||||
"5f6964000008686f73745f6c696208636865636b5f6964000008686f73745f6c69620d63726564656e7469616c5f69"
|
||||
"64000208686f73745f6c69620b64656c65676174655f6964000008686f73745f6c6962126465706f7369745f707265"
|
||||
"617574685f6964000008686f73745f6c6962066469645f6964000108686f73745f6c696209657363726f775f696400"
|
||||
"0008686f73745f6c69620f6d70745f69737375616e63655f6964000008686f73745f6c69620a6d70746f6b656e5f69"
|
||||
"64000008686f73745f6c69620c6e66745f6f666665725f6964000008686f73745f6c6962086f666665725f69640000"
|
||||
"08686f73745f6c69620a7061796368616e5f6964000208686f73745f6c6962167065726d697373696f6e65645f646f"
|
||||
"6d61696e5f6964000008686f73745f6c69620a7369676e6572735f6964000108686f73745f6c6962097469636b6574"
|
||||
"5f6964000008686f73745f6c6962087661756c745f6964000003070603030307080905030100110619037f01418080"
|
||||
"c0000b7f0041c28ac0000b7f0041d08ac0000b072e04066d656d6f727902000666696e697368001b0a5f5f64617461"
|
||||
"5f656e6403010b5f5f686561705f6261736503020ae83706140020002001200220034182802042828020101d0b1400"
|
||||
"20002001200220034181802042818020101d0bd10302017f017e230041a0016b22042400024020012d000041014604"
|
||||
"4041d780c000411620012802042201ac10001a200041013a0000200020013602040c010b200441186a200141196a29"
|
||||
"0000370300200441106a200141116a290000370300200441086a200141096a29000037030020042001290001370300"
|
||||
"2002200320044120410110011a2004412041001002220141004c044041d080c00041072001ac10001a200041013a00"
|
||||
"00200020013602040c010b418b80c000410f4285801410001a20014185801420044180016a41201003220141204704"
|
||||
"4041af80c0004115417f20012001417f4e1b2201ac10001a200041013a0000200020013602040c010b200441c2006a"
|
||||
"20044182016a2d00003a0000200441f0006a20044197016a2900002205370300200441286a22012004418f016a2900"
|
||||
"00370300200441306a22022005370300200441386a22032004419f016a2d00003a0000200420042f0080013b014020"
|
||||
"042004290087013703202004200428008301360043200441df006a20032d00003a0000200441d7006a200229030037"
|
||||
"0000200441cf006a20012903003700002004200429032037004741c480c000410c200441406b4120410110011a2000"
|
||||
"4180023b01000b200441a0016a24000bd32c02097f027e23004180076b2200240041ed80c000412341014100410010"
|
||||
"011a02402000027f02404181802020004190016a220741141004220641144604402000410e6a20004192016a22032d"
|
||||
"00003a000020002000290097013703e80120002000419c016a22012900003700ed01200020002f0090013b010c2000"
|
||||
"20002903e8013703d806200020002900ed013700dd06200020002800930136000f200041186a20002900dd06370000"
|
||||
"200020002903d806370013419081c00041082000410c6a2204411410051a4183802020074114100422064114470d03"
|
||||
"200041226a20032d00003a000020002000290097013703e801200020012900003700ed01200020002f0090013b0120"
|
||||
"200020002903e8013703d806200020002900ed013700dd0620002000280093013600232000412c6a20002900dd0637"
|
||||
"0000200020002903d806370027419881c000410c200041206a411410051a200041a8016a22034200370300200041a0"
|
||||
"016a2201420037030020004198016a420037030020004200370390012004411420074120100622044120460d010240"
|
||||
"20044100480440200020043602380c010b2000417f3602380b41010c020b0c020b200041cd006a2003290300370000"
|
||||
"200041c5006a20012903003700002000413d6a20004198016a290300370000200020002903900137003541000b3a00"
|
||||
"3420004190016a200041346a41a481c00041071019024020002d00900141014604402000280294012106419c8ac000"
|
||||
"4112420510001a0c010b4100210641ab81c000413541014100410010011a200041e6006a41c4003a0000200041e000"
|
||||
"6a4100360200200041eb006a41003a0000200041d5a6013b01642000420037035820004100360067200041a8016a22"
|
||||
"044200370300200041a0016a2203420037030020004198016a22014200370300200042003703900102402000410c6a"
|
||||
"4114200041206a4114200041d8006a411420004190016a412010072207412047044002402007410048044020002007"
|
||||
"3602700c010b2000417f3602700b410121060c010b20004185016a2004290300370000200041fd006a200329030037"
|
||||
"0000200041f5006a2001290300370000200020002903900137006d0b200020063a006c20004190016a200041ec006a"
|
||||
"41e081c0004109101a20002d00900141014604402000280294012106419c8ac0004112420510001a0c010b41002106"
|
||||
"41e981c000413741014100410010011a200041f8016a200041306a2204280100360200200041f0016a200041286a22"
|
||||
"0329010037030020004184026a200041e0006a290300220a3702002000418c026a200041e8006a2802002201360200"
|
||||
"200020002901203703e8012000200029035822093702fc01200041e8066a22052001360200200041e0066a2207200a"
|
||||
"370300200020093703d806200041f4066a2003290100370200200041fc066a20042801003602002000200029012037"
|
||||
"02ec0620004190026a200041d8066a22034128101c20004194016a200041e8016a41d000101c200041013602900120"
|
||||
"0041f0066a220142003703002005420037030020074200370300200042003703d806024041ae8ac0004114200041bc"
|
||||
"016a412820034120100822034120470440024020034100480440200020033602ec010c010b2000417f3602ec010b41"
|
||||
"0121060c010b20004181026a2001290300370000200041f9016a2005290300370000200041f1016a20072903003700"
|
||||
"00200020002903d8063700e9010b200020063a00e801200041bc026a200041e8016a41a082c0004103101920002d00"
|
||||
"bc02410146044020002802c0022106419c8ac0004112420610001a0c010b4100210641a382c0004131410141004100"
|
||||
"10011a200041063602d80620004180026a22044200370300200041f8016a22034200370300200041f0016a22014200"
|
||||
"370300200042003703e80102402000410c6a4114200041d8066a4104200041e8016a41201009220741204704400240"
|
||||
"20074100480440200020073602c8020c010b2000417f3602c8020b410121060c010b200041dd026a20042903003700"
|
||||
"00200041d5026a2003290300370000200041cd026a2001290300370000200020002903e8013700c5020b200020063a"
|
||||
"00c402200041e8016a200041c4026a41d482c0004105101920002d00e801410146044020002802ec012106419c8ac0"
|
||||
"004112420610001a0c010b41d982c000413341014100410010011a20004180026a4200370300200041f8016a420037"
|
||||
"0300200041f0016a4200370300200042003703e801024002402000410c6a2201411420014114418c83c00041122000"
|
||||
"41e8016a4120100a2201412047044041d780c0004116417f20012001417f4e1b2206ac10001a0c010b200041da066a"
|
||||
"20002d00ea013a0000200041f0026a200041f7016a290000220a370300200041f8026a200041ff016a290000220937"
|
||||
"030020004180036a20004187026a2d000022013a0000200041e7066a200a370000200041ef066a2009370000200041"
|
||||
"f7066a20013a0000200020002f01e8013b01d806200020002900ef0122093703e802200020002800eb013600db0620"
|
||||
"0020093700df06419e83c000410a200041d8066a22014120410110011a2001412041001002220641004c044041d080"
|
||||
"c00041072006ac10001a0c010b418b80c000410f4298802010001a200641988020200041e8016a4114100322014114"
|
||||
"460d0141af80c0004115417f20012001417f4e1b2206ac10001a0b419c8ac0004112420710001a0c010b419a80c000"
|
||||
"411541014100410010011a41a883c000413841014100410010011a230041206b22082400200841186a220742003703"
|
||||
"00200841106a22044200370300200841086a220342003703002008420037030020004184036a2201027f2000410c6a"
|
||||
"22064114200041206a2202411420084120100b22054120470440024020054100480440200120053602040c010b2001"
|
||||
"417f3602040b41010c010b20012008290300370001200141196a2007290300370000200141116a2004290300370000"
|
||||
"200141096a200329030037000041000b3a0000200841206a2400200041e8016a2205200141e083c000410810192000"
|
||||
"2d00e80145044041e883c000413641014100410010011a230041206b22082400200841186a22074200370300200841"
|
||||
"106a22044200370300200841086a2203420037030020084200370300200041a8036a2201027f200641142002411420"
|
||||
"084120100c22024120470440024020024100480440200120023602040c010b2001417f3602040b41010c010b200120"
|
||||
"08290300370001200141196a2007290300370000200141116a2004290300370000200141096a200329030037000041"
|
||||
"000b3a0000200841206a240020052001419e84c000410e101920002d00e801410146044020002802ec012106419c8a"
|
||||
"c0004112420910001a0c020b41ac84c000413c41014100410010011a230041206b22022400200241186a2207420037"
|
||||
"0300200241106a22044200370300200241086a2203420037030020024200370300200041cc036a2201027f2000410c"
|
||||
"6a411420024120100d22054120470440024020054100480440200120053602040c010b2001417f3602040b41010c01"
|
||||
"0b20012002290300370001200141196a2007290300370000200141116a2004290300370000200141096a2003290300"
|
||||
"37000041000b3a0000200241206a2400200041e8016a200141e884c0004103101920002d00e8014101460440200028"
|
||||
"02ec012106419c8ac0004112420a10001a0c020b41eb84c000413141014100410010011a230041306b220224002002"
|
||||
"410b36020c200241286a22074200370300200241206a22044200370300200241186a22034200370300200242003703"
|
||||
"10200041f0036a2201027f2000410c6a41142002410c6a4104200241106a4120100e22054120470440024020054100"
|
||||
"480440200120053602040c010b2001417f3602040b41010c010b20012002290310370001200141196a200729030037"
|
||||
"0000200141116a2004290300370000200141096a200329030037000041000b3a0000200241306a2400200041e8016a"
|
||||
"2001419c85c0004106101920002d00e801410146044020002802ec012106419c8ac0004112420b10001a0c020b41a2"
|
||||
"85c000413441014100410010011a230041306b220224002002410c36020c200241286a22074200370300200241206a"
|
||||
"22044200370300200241186a220342003703002002420037031020004194046a2201027f2000410c6a41142002410c"
|
||||
"6a4104200241106a4120100f22054120470440024020054100480440200120053602040c010b2001417f3602040b41"
|
||||
"010c010b20012002290310370001200141196a2007290300370000200141116a2004290300370000200141096a2003"
|
||||
"29030037000041000b3a0000200241306a2400200041fc016a2000411c6a280100360200200041f4016a200041146a"
|
||||
"2901003702002000200029010c3702ec01200041808080e0003602e801200041d8066a2103230041406a2204240002"
|
||||
"4020012d0000410146044041d780c000411620012802042201ac10001a200341013a0000200320013602040c010b20"
|
||||
"0441206a200141196a290000370300200441186a200141116a290000370300200441106a200141096a290000370300"
|
||||
"2004200129000137030841d685c000410b200441086a22014120410110011a02400240200141204100100222014100"
|
||||
"4c044041d080c00041072001ac10001a0c010b418b80c000410f4284802010001a2001418480202004412c6a411410"
|
||||
"0322014114460d0141af80c0004115417f20012001417f4e1b2201ac10001a0b200341013a0000200320013602040c"
|
||||
"010b419a80c000411541014100410010011a20034180023b01000b200441406b240020002d00d80641014604402000"
|
||||
"2802dc062106419c8ac0004112420c10001a0c020b41e185c000413941014100410010011a230041206b2202240020"
|
||||
"0241186a22074200370300200241106a22044200370300200241086a2203420037030020024200370300200041b804"
|
||||
"6a2201027f200041e8016a4118200041206a4114200241201010220541204704400240200541004804402001200536"
|
||||
"02040c010b2001417f3602040b41010c010b20012002290300370001200141196a2007290300370000200141116a20"
|
||||
"04290300370000200141096a200329030037000041000b3a0000200241206a2400200041d8066a2001419a86c00041"
|
||||
"07101920002d00d806410146044020002802dc062106419c8ac0004112420d10001a0c020b41a186c0004135410141"
|
||||
"00410010011a230041306b220224002002410636020c200241286a22074200370300200241206a2204420037030020"
|
||||
"0241186a2203420037030020024200370310200041dc046a2201027f200041206a41142002410c6a4104200241106a"
|
||||
"4120101122054120470440024020054100480440200120053602040c010b2001417f3602040b41010c010b20012002"
|
||||
"290310370001200141196a2007290300370000200141116a2004290300370000200141096a20032903003700004100"
|
||||
"0b3a0000200241306a2400200041d8066a200141d686c000410c101820002d00d806410146044020002802dc062106"
|
||||
"419c8ac0004112420d10001a0c020b41e286c000413a41014100410010011a230041306b220224002002410d36020c"
|
||||
"200241286a22074200370300200241206a22044200370300200241186a220342003703002002420037031020004180"
|
||||
"056a2201027f2000410c6a41142002410c6a4104200241106a41201012220541204704400240200541004804402001"
|
||||
"20053602040c010b2001417f3602040b41010c010b20012002290310370001200141196a2007290300370000200141"
|
||||
"116a2004290300370000200141096a200329030037000041000b3a0000200241306a2400200041d8066a2001419c87"
|
||||
"c0004105101920002d00d806410146044020002802dc062106419c8ac0004112420d10001a0c020b41a187c0004133"
|
||||
"41014100410010011a230041306b220224002002410e36020c200241286a22074200370300200241206a2204420037"
|
||||
"0300200241186a2203420037030020024200370310200041a4056a2201027f2000410c6a4114200041206a41142002"
|
||||
"410c6a4104200241106a4120101322054120470440024020054100480440200120053602040c010b2001417f360204"
|
||||
"0b41010c010b20012002290310370001200141196a2007290300370000200141116a2004290300370000200141096a"
|
||||
"200329030037000041000b3a0000200241306a2400200041d8066a200141d487c000410a101920002d00d806410146"
|
||||
"044020002802dc062106419c8ac0004112420e10001a0c020b41de87c000413841014100410010011a230041306b22"
|
||||
"0224002002410f36020c200241286a22074200370300200241206a22044200370300200241186a2203420037030020"
|
||||
"024200370310200041c8056a2201027f2000410c6a41142002410c6a4104200241106a412010142205412047044002"
|
||||
"4020054100480440200120053602040c010b2001417f3602040b41010c010b20012002290310370001200141196a20"
|
||||
"07290300370000200141116a2004290300370000200141096a200329030037000041000b3a0000200241306a240020"
|
||||
"0041d8066a2001419688c0004112101820002d00d806410146044020002802dc062106419c8ac0004112420f10001a"
|
||||
"0c020b41a888c00041c00041014100410010011a230041206b22022400200241186a22074200370300200241106a22"
|
||||
"044200370300200241086a2203420037030020024200370300200041ec056a2201027f2000410c6a41142002412010"
|
||||
"1522054120470440024020054100480440200120053602040c010b2001417f3602040b41010c010b20012002290300"
|
||||
"370001200141196a2007290300370000200141116a2004290300370000200141096a200329030037000041000b3a00"
|
||||
"00200241206a2400200041d8066a200141e888c000410a101a20002d00d806410146044020002802dc062106419c8a"
|
||||
"c0004112421010001a0c020b41f288c000413841014100410010011a230041306b220224002002411236020c200241"
|
||||
"286a22074200370300200241206a22044200370300200241186a220342003703002002420037031020004190066a22"
|
||||
"01027f2000410c6a41142002410c6a4104200241106a41201016220541204704400240200541004804402001200536"
|
||||
"02040c010b2001417f3602040b41010c010b20012002290310370001200141196a2007290300370000200141116a20"
|
||||
"04290300370000200141096a200329030037000041000b3a0000200241306a2400200041d8066a200141aa89c00041"
|
||||
"06101920002d00d806410146044020002802dc062106419c8ac0004112421210001a0c020b4101210641b089c00041"
|
||||
"3441014100410010011a230041306b220224002002411336020c200241286a22074200370300200241206a22044200"
|
||||
"370300200241186a2203420037030020024200370310200041b4066a2201027f2000410c6a41142002410c6a410420"
|
||||
"0241106a4120101722054120470440024020054100480440200120053602040c010b2001417f3602040b41010c010b"
|
||||
"20012002290310370001200141196a2007290300370000200141116a2004290300370000200141096a200329030037"
|
||||
"000041000b3a0000200241306a2400200041d8066a200141e489c0004105101920002d00d806410146044020002802"
|
||||
"dc062106419c8ac0004112421310001a0c020b41e989c000413341014100410010011a0c010b20002802ec01210641"
|
||||
"9c8ac0004112420810001a0b20004180076a240020060f0b418080c000410b417f20062006417f4e1bac1000000bfd"
|
||||
"0401067f200241104f0440024020002000410020006b41037122056a22044f0d002001210320050440200521060340"
|
||||
"200020032d00003a0000200341016a2103200041016a2100200641016b22060d000b0b200541016b4107490d000340"
|
||||
"200020032d00003a0000200041016a200341016a2d00003a0000200041026a200341026a2d00003a0000200041036a"
|
||||
"200341036a2d00003a0000200041046a200341046a2d00003a0000200041056a200341056a2d00003a000020004106"
|
||||
"6a200341066a2d00003a0000200041076a200341076a2d00003a0000200341086a2103200041086a22002004470d00"
|
||||
"0b0b2004200220056b2207417c7122086a21000240200120056a2206410371450440200020044d0d01200621010340"
|
||||
"20042001280200360200200141046a2101200441046a22042000490d000b0c010b200020044d0d0020064103742205"
|
||||
"41187121032006417c71220241046a2101410020056b41187121052002280200210203402004200220037620012802"
|
||||
"00220220057472360200200141046a2101200441046a22042000490d000b0b20074103712102200620086a21010b02"
|
||||
"402000200020026a22064f0d002002410771220304400340200020012d00003a0000200141016a2101200041016a21"
|
||||
"00200341016b22030d000b0b200241016b4107490d000340200020012d00003a0000200041016a200141016a2d0000"
|
||||
"3a0000200041026a200141026a2d00003a0000200041036a200141036a2d00003a0000200041046a200141046a2d00"
|
||||
"003a0000200041056a200141056a2d00003a0000200041066a200141066a2d00003a0000200041076a200141076a2d"
|
||||
"00003a0000200141086a2101200041086a22002006470d000b0b0b940201017f230041406a22062400024020012d00"
|
||||
"00410146044041d780c000411620012802042201ac10001a200041013a0000200020013602040c010b200641206a20"
|
||||
"0141196a290000370300200641186a200141116a290000370300200641106a200141096a2900003703002006200129"
|
||||
"000137030820022003200641086a22014120410110011a024002402001412041001002220141004c044041d080c000"
|
||||
"41072001ac10001a0c010b418b80c000410f200510001a200120042006412c6a4114100322014114460d0141af80c0"
|
||||
"004115417f20012001417f4e1b2201ac10001a0b200041013a0000200020013602040c010b419a80c0004115410141"
|
||||
"00410010011a20004180023b01000b200641406b24000b0bb80a0100418080c0000bae0a6572726f725f636f64653d"
|
||||
"47657474696e67206669656c643a204669656c6420646174613a207265747269657665644572726f72206765747469"
|
||||
"6e67206669656c643a204669656c6420646174613a204572726f723a204572726f722067657474696e67206b65796c"
|
||||
"65743a202424242424205354415254494e47205741534d20455845435554494f4e2024242424244163636f756e743a"
|
||||
"44657374696e6174696f6e3a4163636f756e744163636f756e74206f626a656374206578697374732c2070726f6365"
|
||||
"6564696e67207769746820657363726f772066696e6973682e54727573746c696e6554727573746c696e65206f626a"
|
||||
"656374206578697374732c2070726f63656564696e67207769746820657363726f772066696e6973682e414d4d414d"
|
||||
"4d206f626a656374206578697374732c2070726f63656564696e67207769746820657363726f772066696e6973682e"
|
||||
"436865636b436865636b206f626a656374206578697374732c2070726f63656564696e67207769746820657363726f"
|
||||
"772066696e6973682e7465726d73616e64636f6e646974696f6e7343726564656e7469616c43726564656e7469616c"
|
||||
"206f626a656374206578697374732c2070726f63656564696e67207769746820657363726f772066696e6973682e44"
|
||||
"656c656761746544656c6567617465206f626a656374206578697374732c2070726f63656564696e67207769746820"
|
||||
"657363726f772066696e6973682e4465706f736974507265617574684465706f73697450726561757468206f626a65"
|
||||
"6374206578697374732c2070726f63656564696e67207769746820657363726f772066696e6973682e444944444944"
|
||||
"206f626a656374206578697374732c2070726f63656564696e67207769746820657363726f772066696e6973682e45"
|
||||
"7363726f77457363726f77206f626a656374206578697374732c2070726f63656564696e6720776974682065736372"
|
||||
"6f772066696e6973682e4d505449737375616e63654d505449737375616e6365206f626a656374206578697374732c"
|
||||
"2070726f63656564696e67207769746820657363726f772066696e6973682e4d50546f6b656e4d50546f6b656e206f"
|
||||
"626a656374206578697374732c2070726f63656564696e67207769746820657363726f772066696e6973682e4e4654"
|
||||
"6f6b656e4f666665724e46546f6b656e4f66666572206f626a656374206578697374732c2070726f63656564696e67"
|
||||
"207769746820657363726f772066696e6973682e4f666665724f66666572206f626a656374206578697374732c2070"
|
||||
"726f63656564696e67207769746820657363726f772066696e6973682e5061794368616e6e656c5061794368616e6e"
|
||||
"656c206f626a656374206578697374732c2070726f63656564696e67207769746820657363726f772066696e697368"
|
||||
"2e5065726d697373696f6e6564446f6d61696e5065726d697373696f6e6564446f6d61696e206f626a656374206578"
|
||||
"697374732c2070726f63656564696e67207769746820657363726f772066696e6973682e5369676e65724c69737453"
|
||||
"69676e65724c697374206f626a656374206578697374732c2070726f63656564696e67207769746820657363726f77"
|
||||
"2066696e6973682e5469636b65745469636b6574206f626a656374206578697374732c2070726f63656564696e6720"
|
||||
"7769746820657363726f772066696e6973682e5661756c745661756c74206f626a656374206578697374732c207072"
|
||||
"6f63656564696e67207769746820657363726f772066696e6973682e43757272656e74207365712076616c75653a00"
|
||||
"4d0970726f64756365727302086c616e6775616765010452757374000c70726f6365737365642d6279010572757374"
|
||||
"631d312e38372e30202831373036376539616320323032352d30352d303929002c0f7461726765745f666561747572"
|
||||
"6573022b0f6d757461626c652d676c6f62616c732b087369676e2d657874";
|
||||
|
||||
extern std::string const kCodecovTestsWasmHex =
|
||||
"0061736d0100000001570b60067f7f7f7f7f7f017f60047f7f7f7f017f60027f7f017f60037f7f7f017f60077f7f7f"
|
||||
"7f7f7f7f017f60057f7f7f7f7f017f60087f7f7f7f7f7f7f7f017f60017f017f60037f7f7e017f60047f7f7f7f0060"
|
||||
"00017f02c60a3b08686f73745f6c6962057472616365000508686f73745f6c69620974726163655f6e756d00080868"
|
||||
"6f73745f6c69620a6c6467725f696e646578000208686f73745f6c696210706172656e745f6c6467725f74696d6500"
|
||||
"0208686f73745f6c696210706172656e745f6c6467725f68617368000208686f73745f6c696208626173655f666565"
|
||||
"000208686f73745f6c696211616d656e646d656e745f656e61626c6564000208686f73745f6c69620874785f666965"
|
||||
"6c64000308686f73745f6c69620e6163636f756e74726f6f745f6964000108686f73745f6c69620863616368655f6c"
|
||||
"65000308686f73745f6c69620d686f6d655f6c655f6669656c64000308686f73745f6c6962086c655f6669656c6400"
|
||||
"0108686f73745f6c69620874785f696e6e6572000108686f73745f6c69620d686f6d655f6c655f696e6e6572000108"
|
||||
"686f73745f6c6962086c655f696e6e6572000508686f73745f6c69620a74785f6172725f6c656e000708686f73745f"
|
||||
"6c69620f686f6d655f6c655f6172725f6c656e000708686f73745f6c69620a6c655f6172725f6c656e000208686f73"
|
||||
"745f6c69621074785f696e6e65725f6172725f6c656e000208686f73745f6c696215686f6d655f6c655f696e6e6572"
|
||||
"5f6172725f6c656e000208686f73745f6c6962106c655f696e6e65725f6172725f6c656e000308686f73745f6c6962"
|
||||
"087365745f64617461000208686f73745f6c69620b7368613531325f68616c66000108686f73745f6c696209636865"
|
||||
"636b5f736967000008686f73745f6c6962076e66745f757269000008686f73745f6c69620a6e66745f697373756572"
|
||||
"000108686f73745f6c6962096e66745f7461786f6e000108686f73745f6c6962096e66745f666c616773000208686f"
|
||||
"73745f6c69620c6e66745f786665725f666565000208686f73745f6c69620a6e66745f73657269616c000108686f73"
|
||||
"745f6c69620a74726163655f61636374000108686f73745f6c69620974726163655f616d74000108686f73745f6c69"
|
||||
"6208636865636b5f6964000008686f73745f6c69620f666c6f61745f66726f6d5f75696e74000508686f73745f6c69"
|
||||
"620c74727573746c696e655f6964000608686f73745f6c696206616d6d5f6964000008686f73745f6c69620d637265"
|
||||
"64656e7469616c5f6964000608686f73745f6c69620a6d70746f6b656e5f6964000008686f73745f6c69620c747261"
|
||||
"63655f78666c6f6174000108686f73745f6c696209666c6f61745f636d70000108686f73745f6c696209666c6f6174"
|
||||
"5f616464000408686f73745f6c696209666c6f61745f737562000408686f73745f6c69620a666c6f61745f6d756c74"
|
||||
"000408686f73745f6c696209666c6f61745f646976000408686f73745f6c69620a666c6f61745f726f6f7400000868"
|
||||
"6f73745f6c696209666c6f61745f706f77000008686f73745f6c696209657363726f775f6964000008686f73745f6c"
|
||||
"69620f6d70745f69737375616e63655f6964000008686f73745f6c69620c6e66745f6f666665725f6964000008686f"
|
||||
"73745f6c6962086f666665725f6964000008686f73745f6c6962096f7261636c655f6964000008686f73745f6c6962"
|
||||
"0a7061796368616e5f6964000608686f73745f6c6962167065726d697373696f6e65645f646f6d61696e5f69640000"
|
||||
"08686f73745f6c6962097469636b65745f6964000008686f73745f6c6962087661756c745f6964000008686f73745f"
|
||||
"6c69620b64656c65676174655f6964000008686f73745f6c6962126465706f7369745f707265617574685f69640000"
|
||||
"08686f73745f6c6962066469645f6964000108686f73745f6c69620a7369676e6572735f69640001030302090a0503"
|
||||
"0100110619037f01418080c0000b7f0041cf9bc0000b7f0041d09bc0000b072e04066d656d6f727902000666696e69"
|
||||
"7368003c0a5f5f646174615f656e6403010b5f5f686561705f6261736503020a8c2f02460002402000200147044020"
|
||||
"02200341014100410010001a20004100480d01418b80c000410b2000ad1001000b200220032000ac10011a0f0b418b"
|
||||
"80c000410b2000ac1001000bc22e020b7f017e23004190026b22002400419680c000412341014100410010001a2000"
|
||||
"4100360260200041e0006a220241041002410441888ac000410a103b20004100360260200241041003410441928ac0"
|
||||
"004110103b200041f8006a22054200370300200041f0006a22014200370300200041e8006a22064200370300200042"
|
||||
"00370360200241201004412041a28ac0004110103b20004100360260200241041005410441b28ac0004108103b2000"
|
||||
"41106a2208428182848890a0c08001370300200041186a2209428182848890a0c08001370300200041206a220a4281"
|
||||
"82848890a0c080013703002000428182848890a0c0800137030841b980c000410e1006410141c780c0004111103b20"
|
||||
"0041086a41201006410141c780c0004111103b418180202002411410072203411446044002402000412e6a200041e2"
|
||||
"006a2d00003a0000200020002900673703e8012000200041ec006a2900003700ed01200020002f00603b012c200020"
|
||||
"002903e8013703a801200020002900ed013700ad012000200028006336002f200041386a20002900ad013700002000"
|
||||
"20002903a801370033200542003703002001420037030020064200370300200042003703602000412c6a2205411420"
|
||||
"024120100822034120470d00200041c2006a20002d00623a0000200041f0016a2207200041ef006a290000220b3703"
|
||||
"00200041cf006a200b370000200041d7006a200041f7006a290000370000200041df006a200041ff006a2d00003a00"
|
||||
"00200020002f01603b01402000200028006336004320002000290067370047200041406b412041001009410141d880"
|
||||
"c0004108103b2001410036020020064200370300200042003703604181802020024114100a411441ba8ac000410d10"
|
||||
"3b20014100360200200642003703002000420037036041014181802020024114100b411441c78ac0004108103b0240"
|
||||
"4100200041e4006a22046b410371220320046a220120044d0d0020030440200321060340200441003a000020044101"
|
||||
"6a2104200641016b22060d000b0b200341016b4107490d000340200441003a0000200441076a41003a000020044106"
|
||||
"6a41003a0000200441056a41003a0000200441046a41003a0000200441036a41003a0000200441026a41003a000020"
|
||||
"0441016a41003a0000200441086a22042001470d000b0b2001413c20036b2203417c716a220420014b044003402001"
|
||||
"4100360200200141046a22012004490d000b0b024020042003410371220320046a22064f0d00200322010440034020"
|
||||
"0441003a0000200441016a2104200141016b22010d000b0b200341016b4107490d000340200441003a000020044107"
|
||||
"6a41003a0000200441066a41003a0000200441056a41003a0000200441046a41003a0000200441036a41003a000020"
|
||||
"0441026a41003a0000200441016a41003a0000200441086a22042006470d000b0b200041043602a001200041818020"
|
||||
"360260200041f8016a2203410036020020074200370300200042003703e80120024104200041e8016a22014114100c"
|
||||
"411441cf8ac0004108103b2003410036020020074200370300200042003703e801200220002802a00120014114100d"
|
||||
"411441d78ac000410d103b2003410036020020074200370300200042003703e8014101200220002802a00120014114"
|
||||
"100e411441e48ac0004108103b4189803c100f412041e080c000410a103b4189803c1010412041ea80c000410f103b"
|
||||
"41014189803c1011412041f980c000410a103b200220002802a00110124120418381c0004110103b200220002802a0"
|
||||
"0110134120419381c0004115103b4101200220002802a0011014412041a881c0004110103b200541141015411441b8"
|
||||
"81c0004108103b20004180026a220642003703002003420037030020074200370300200042003703e8012002200028"
|
||||
"02a001200141201016412041ec8ac000410b103b41c081c000410c41cc81c000410b41d781c000410e1017410141e5"
|
||||
"81c0004109103b200041c0016a200a290300370300200041b8016a2009290300370300200041b0016a200829030037"
|
||||
"0300200020002903083703a801200341003b010020074200370300200042003703e80120054114200041a8016a2204"
|
||||
"4120200141121018411241f78ac0004107103b2003410036020020074200370300200042003703e801200441202001"
|
||||
"41141019411441fe8ac000410a103b200041003602e8012004412020014104101a410441888bc0004109103b200441"
|
||||
"20101b410841ee81c0004109103b20044120101c410a41f781c000410c103b200041003602e8012004412020014104"
|
||||
"101d410441918bc000410a103b418382c000410d20054114101e4100419082c000410a103b418382c000410d419a82"
|
||||
"c0004108101f410041a282c0004109103b418382c000410d41ab82c0004108101f410041b382c000410e103b417f41"
|
||||
"041004417141c182c0004118103b200041003602e8012001417f10044171419b8bc0004118103b200041ea016a4100"
|
||||
"3a0000200041003b01e801200141031004417d41b38bc000411e103b200041003602e8012001418094ebdc03100441"
|
||||
"7341d18bc000411d103b4102100f416f41d982c0004119103b417f20002802a0011012417141f282c0004118103b20"
|
||||
"02417f10124171418a83c0004118103b20024181081012417441a283c0004119103b200041e094ebdc036a22082000"
|
||||
"2802a0011012417341bb83c0004118103b200642003703002003420037030020074200370300200042003703e80120"
|
||||
"05411420084108200141201020417341ee8bc0004114103b2006420037030020034200370300200742003703002000"
|
||||
"42003703e8012005411420054114200141201020417141828cc0004116103b20064200370300200342003703002007"
|
||||
"4200370300200042003703e801200841082001412041001021417341988cc0004117103b2006420037030020034200"
|
||||
"37030020074200370300200042003703e801200220002802a0012001412041001021417141af8cc0004120103b2008"
|
||||
"20002802a00141011009417341d383c0004110103b200220002802a00141011009417141e383c0004112103b200642"
|
||||
"003703002003420037030020074200370300200042003703e801200820002802a001200141201008417341cf8cc000"
|
||||
"4116103b200642003703002003420037030020074200370300200042003703e801200220002802a001200141201008"
|
||||
"417141e58cc0004118103b200642003703002003420037030020074200370300200042003703e80120054114200541"
|
||||
"14200820002802a001200141201022417341fd8cc000411d103b200642003703002003420037030020074200370300"
|
||||
"200042003703e8012005411420054114200220002802a0012001412010224171419a8dc000411f103b200642003703"
|
||||
"002003420037030020074200370300200042003703e80141bb9bc0004114200820002802a001200141201023417341"
|
||||
"b98dc0004115103b200642003703002003420037030020074200370300200042003703e80141bb9bc0004114200220"
|
||||
"002802a001200141201023417141ce8dc000411b103b20064200370300200342003703002007420037030020004200"
|
||||
"3703e80141bb9bc000411441f583c0004114200141201023417141e98dc0004125103b200642003703002003420037"
|
||||
"030020074200370300200042003703e801418984c000412841bb9bc00041142001412010234171418e8ec000412110"
|
||||
"3b200041dc016a2000413c6a280100360200200041d4016a200041346a2901003702002000200029012c3702cc0120"
|
||||
"0041808080083602c801200041003b01e801200041c8016a2209411841bb9bc0004114200141021023417141af8ec0"
|
||||
"00410a103b200820002802a001422a1001417341b184c0004111103b200041003b01e8014102200141021007416f41"
|
||||
"b98ec0004117103b200041003b01e801410220014102100a416f41d08ec000411c103b200041003b01e80141014102"
|
||||
"20014102100b416f41ec8ec0004117103b4102100f416f41d982c0004119103b41021010416f41c284c000411e103b"
|
||||
"410141021011416f41e084c0004119103b41b980c0004181081006417441f984c000411f103b41b980c00041c10010"
|
||||
"064174419885c000411a103b200041003b01e801200241810820014102100c417441838fc0004116103b200041003b"
|
||||
"01e801200241810820014102100d417441998fc000411b103b200041003b01e8014101200241810820014102100e41"
|
||||
"7441b48fc0004116103b20024181081012417441b285c000411e103b20024181081013417441d085c0004123103b41"
|
||||
"0120024181081014417441f385c000411e103b200241812010154174419186c0004116103b418382c00041810841cc"
|
||||
"81c000410b41d781c000410e1017417441e581c0004109103b418382c000410d41cc81c00041810841d781c000410e"
|
||||
"1017417441e581c0004109103b418382c000410d41cc81c000410b41d781c0004181081017417441e581c000410910"
|
||||
"3b200041003b01e8012002418108200141021016417441ca8fc0004119103b200041003b01e80141bb9bc000418108"
|
||||
"41bb9bc0004114200141021023417441e38fc0004114103b200041003b01e801200541142005411420024181082001"
|
||||
"41021024417441f78fc000411b103b200041003b01e8012009418108200541142001410210254174419290c000411e"
|
||||
"103b418382c000410d200820002802a00141001000417341a786c000410f103b200042d487b6f4c7d4b1c0003700e0"
|
||||
"01418382c000410d200041e095ebdc036a220441081026417341b686c0004116103b418382c000410d200820002802"
|
||||
"a001101f417341cc86c0004113103b20044108200041e0016a220841081027417341df86c0004114103b2008410820"
|
||||
"0441081027417341f386c0004114103b200041003b01e80120044108200841082001410241001028417341b090c000"
|
||||
"4114103b200041003b01e80120084108200441082001410241001028417341c490c0004114103b200041003b01e801"
|
||||
"20044108200841082001410241001029417341d890c0004114103b200041003b01e801200841082004410820014102"
|
||||
"41001029417341ec90c0004114103b200041003b01e8012004410820084108200141024100102a4173418091c00041"
|
||||
"15103b200041003b01e8012008410820044108200141024100102a4173419591c0004115103b200041003b01e80120"
|
||||
"04410820084108200141024100102b417341aa91c0004114103b200041003b01e80120084108200441082001410241"
|
||||
"00102b417341be91c0004114103b200041003b01e801200441084103200141024100102c417341d291c0004114103b"
|
||||
"200041003b01e801200441084103200141024100102d417341e691c0004113103b2006420037030020034200370300"
|
||||
"20074200370300200042003703e801200541142005411420014120102e417141f991c000411b103b20064200370300"
|
||||
"2003420037030020074200370300200042003703e801200541142005411420014120102f4171419492c0004121103b"
|
||||
"200642003703002003420037030020074200370300200042003703e8012005411420054114200141201030417141b5"
|
||||
"92c000411e103b200642003703002003420037030020074200370300200042003703e8012005411420054114200141"
|
||||
"201031417141d392c000411a103b200642003703002003420037030020074200370300200042003703e80120054114"
|
||||
"20054114200141201032417141ed92c000411b103b2006420037030020034200370300200742003703002000420037"
|
||||
"03e8012005411420054114200541142001412010334171418893c000411c103b200642003703002003420037030020"
|
||||
"074200370300200042003703e8012005411420054114200141201034417141a493c0004128103b2006420037030020"
|
||||
"03420037030020074200370300200042003703e8012005411420054114200141201035417141cc93c000411b103b20"
|
||||
"0642003703002003420037030020074200370300200042003703e8012005411420054114200141201036417141e793"
|
||||
"c000411a103b200220002802a001410010094171418787c000411b103b200041003b01e80120054114200220002802"
|
||||
"a0012001410210184171418194c000411a103b200041003b01e801200220002802a0012001410210194171419b94c0"
|
||||
"00411d103b200041003b01e801200220002802a00120014102101a417141b894c000411c103b200220002802a00110"
|
||||
"1b417141a287c000411c103b200220002802a001101c417141be87c000411f103b200041003602e801200220002802"
|
||||
"a00120014104101d417141d494c000411d103b200041003b01e801200220002802a001200141021008417141f194c0"
|
||||
"004124103b200041808080083602e801200041003b018e02200220002802a001200141042000418e026a2203410210"
|
||||
"204171419595c000411e103b200041003b018e02200220002802a00122062005411420022006200341021024417141"
|
||||
"b395c0004124103b200041003b018e0220054114200220002802a001220620022006200341021024417141d795c000"
|
||||
"4124103b200041003b018e02200220002802a00120054114200341021037417141fb95c0004122103b200041003b01"
|
||||
"8e0220054114200220002802a0012003410210374171419d96c0004122103b200041003b018e02200220002802a001"
|
||||
"20054114200341021038417141bf96c0004129103b200041003b018e0220054114200220002802a001200341021038"
|
||||
"417141e896c0004129103b200041003b018e02200220002802a0012003410210394171419197c000411c103b200041"
|
||||
"003b018e02200220002802a0012001410420034102102e417141ad97c000411f103b200041003b018e022002200028"
|
||||
"02a0012005411441f583c0004114200341021022417141cc97c0004123103b200041003b018e022005411420022000"
|
||||
"2802a00141f583c0004114200341021022417141ef97c0004123103b200041003b018e02200220002802a001200141"
|
||||
"0420034102102f4171419298c0004125103b200041003b018e0220094118200220002802a001200341021025417141"
|
||||
"b798c0004120103b200041003b018e02200220002802a00120014104200341021030417141d798c0004122103b2000"
|
||||
"41003b018e02200220002802a00120014104200341021031417141f998c000411e103b200041003b018e0220022000"
|
||||
"2802a001200141042003410210324171419799c000411f103b200041003b018e02200220002802a001200541142001"
|
||||
"4104200341021033417141b699c0004121103b200041003b018e0220054114200220002802a0012001410420034102"
|
||||
"1033417141d799c0004121103b200041003b018e02200220002802a00120014104200341021034417141f899c00041"
|
||||
"2c103b200041003b018e02200220002802a00120034102103a417141a49ac0004120103b200041003b018e02200220"
|
||||
"002802a00120014104200341021035417141c49ac000411f103b200041003b018e02200220002802a0012001410420"
|
||||
"0341021036417141e39ac000411e103b200041003b018e02200220002802a00141dd87c00041202003410210184171"
|
||||
"41819bc000411d103b418382c000410d200220002802a001101e417141fd87c0004120103b418396abdd03410d41dd"
|
||||
"87c0004120410010004173419d88c0004110103b418396abdd03410d200841081026417341ad88c0004117103b4183"
|
||||
"96abdd03410d20054114101e417341c488c0004115103b418396abdd03410d41ab82c0004108101f417341d988c000"
|
||||
"4114103b200220002802a001200241810841001000417441ed88c000410e103b200241810842011001417441fb88c0"
|
||||
"004112103b418382c0004181082008410810264174418d89c0004115103b418382c00041810820054114101e417441"
|
||||
"a289c0004113103b418382c00041810841ab82c0004108101f417441b589c0004112103b418382c000410d20022000"
|
||||
"2802a001101f417141c789c0004116103b200041003b018e02200220002802a001200541142003410210254171419e"
|
||||
"9bc000411d103b418382c000410d200220002802a00141021000417141dd89c0004114103b4101410020054114101e"
|
||||
"410041f189c0004117103b20004190026a240041010f0b0b418080c000410b417f20032003417f4e1bac1001000b0b"
|
||||
"a61b0200418080c0000b89046572726f725f636f64653d54455354204641494c45442424242424205354415254494e"
|
||||
"47205741534d20455845435554494f4e202424242424746573745f616d656e646d656e74616d656e646d656e745f65"
|
||||
"6e61626c656463616368655f6c6574785f6172725f6c656e686f6d655f6c655f6172725f6c656e6c655f6172725f6c"
|
||||
"656e74785f696e6e65725f6172725f6c656e686f6d655f6c655f696e6e65725f6172725f6c656e6c655f696e6e6572"
|
||||
"5f6172725f6c656e7365745f6461746174657374206d65737361676574657374207075626b65797465737420736967"
|
||||
"6e6174757265636865636b5f7369676e66745f666c6167736e66745f786665725f66656574657374696e6720747261"
|
||||
"636574726163655f61636374400000000000005f74726163655f616d74400000000000000074726163655f616d745f"
|
||||
"7a65726f706172656e745f6c6467725f686173685f6e65675f70747274785f6172725f6c656e5f696e76616c69645f"
|
||||
"736669656c6474785f696e6e65725f6172725f6c656e5f6e65675f70747274785f696e6e65725f6172725f6c656e5f"
|
||||
"6e65675f6c656e74785f696e6e65725f6172725f6c656e5f746f6f5f6c6f6e6774785f696e6e65725f6172725f6c65"
|
||||
"6e5f7074725f6f6f6263616368655f6c655f7074725f6f6f6263616368655f6c655f77726f6e675f6c656e55534430"
|
||||
"303030303030303030303030303030300041b184c0000b8a1774726163655f6e756d5f6f6f625f737472686f6d655f"
|
||||
"6c655f6172725f6c656e5f696e76616c69645f736669656c646c655f6172725f6c656e5f696e76616c69645f736669"
|
||||
"656c64616d656e646d656e745f656e61626c65645f746f6f5f6269675f736c696365616d656e646d656e745f656e61"
|
||||
"626c65645f746f6f5f6c6f6e6774785f696e6e65725f6172725f6c656e5f746f6f5f6269675f736c696365686f6d65"
|
||||
"5f6c655f696e6e65725f6172725f6c656e5f746f6f5f6269675f736c6963656c655f696e6e65725f6172725f6c656e"
|
||||
"5f746f6f5f6269675f736c6963657365745f646174615f746f6f5f6269675f736c69636574726163655f6f6f625f73"
|
||||
"6c69636574726163655f78666c6f61745f6f6f625f736c69636574726163655f616d745f6f6f625f736c696365666c"
|
||||
"6f61745f636d705f6f6f625f736c69636531666c6f61745f636d705f6f6f625f736c6963653263616368655f6c655f"
|
||||
"77726f6e675f73697a655f75696e743235366e66745f666c6167735f77726f6e675f73697a655f75696e743235366e"
|
||||
"66745f786665725f6665655f77726f6e675f73697a655f75696e743235363030303030303030303030303030303030"
|
||||
"30303030303030303030303030303174726163655f616363745f77726f6e675f73697a655f6163636f756e745f6964"
|
||||
"74726163655f6f6f625f737472696e6774726163655f78666c6f61745f6f6f625f737472696e6774726163655f6163"
|
||||
"63745f6f6f625f737472696e6774726163655f616d745f6f6f625f737472696e6774726163655f746f6f5f6c6f6e67"
|
||||
"74726163655f6e756d5f746f6f5f6c6f6e6774726163655f78666c6f61745f746f6f5f6c6f6e6774726163655f6163"
|
||||
"63745f746f6f5f6c6f6e6774726163655f616d745f746f6f5f6c6f6e6774726163655f616d745f77726f6e675f6c65"
|
||||
"6e67746874726163655f696e76616c69645f61735f68657874726163655f616363745f636865636b5f646573796e63"
|
||||
"6c6467725f696e646578706172656e745f6c6467725f74696d65706172656e745f6c6467725f68617368626173655f"
|
||||
"666565686f6d655f6c655f6669656c646c655f6669656c6474785f696e6e6572686f6d655f6c655f696e6e65726c65"
|
||||
"5f696e6e65727368613531325f68616c666e66745f7572696e66745f6973737565726e66745f7461786f6e6e66745f"
|
||||
"73657269616c706172656e745f6c6467725f686173685f6e65675f6c656e706172656e745f6c6467725f686173685f"
|
||||
"6275665f746f6f5f736d616c6c706172656e745f6c6467725f686173685f6c656e5f746f6f5f6c6f6e67636865636b"
|
||||
"5f69645f6f6f625f6c656e5f753332636865636b5f69645f77726f6e675f6c656e5f753332666c6f61745f66726f6d"
|
||||
"5f75696e745f6c656e5f6f6f62666c6f61745f66726f6d5f75696e745f77726f6e675f6c656e5f75696e7436346163"
|
||||
"636f756e74726f6f745f69645f6c656e5f6f6f626163636f756e74726f6f745f69645f77726f6e675f6c656e747275"
|
||||
"73746c696e655f69645f6c656e5f6f6f625f63757272656e637974727573746c696e655f69645f77726f6e675f6c65"
|
||||
"6e5f63757272656e6379616d6d5f69645f6c656e5f6f6f625f617373657432616d6d5f69645f6c656e5f77726f6e67"
|
||||
"5f6c656e5f617373657432616d6d5f69645f6c656e5f77726f6e675f6e6f6e5f7872705f63757272656e63795f6c65"
|
||||
"6e616d6d5f69645f6c656e5f77726f6e675f7872705f63757272656e63795f6c656e616d6d5f69645f6d707474785f"
|
||||
"6669656c645f696e76616c69645f736669656c64686f6d655f6c655f6669656c645f696e76616c69645f736669656c"
|
||||
"646c655f6669656c645f696e76616c69645f736669656c6474785f696e6e65725f746f6f5f6269675f736c69636568"
|
||||
"6f6d655f6c655f696e6e65725f746f6f5f6269675f736c6963656c655f696e6e65725f746f6f5f6269675f736c6963"
|
||||
"657368613531325f68616c665f746f6f5f6269675f736c696365616d6d5f69645f746f6f5f6269675f736c69636563"
|
||||
"726564656e7469616c5f69645f746f6f5f6269675f736c6963656d70746f6b656e5f69645f746f6f5f6269675f736c"
|
||||
"6963655f6d70746964666c6f61745f6164645f6f6f625f736c69636531666c6f61745f6164645f6f6f625f736c6963"
|
||||
"6532666c6f61745f7375625f6f6f625f736c69636531666c6f61745f7375625f6f6f625f736c69636532666c6f6174"
|
||||
"5f6d756c745f6f6f625f736c69636531666c6f61745f6d756c745f6f6f625f736c69636532666c6f61745f6469765f"
|
||||
"6f6f625f736c69636531666c6f61745f6469765f6f6f625f736c69636532666c6f61745f726f6f745f6f6f625f736c"
|
||||
"696365666c6f61745f706f775f6f6f625f736c696365657363726f775f69645f77726f6e675f73697a655f75696e74"
|
||||
"33326d70745f69737375616e63655f69645f77726f6e675f73697a655f75696e7433326e66745f6f666665725f6964"
|
||||
"5f77726f6e675f73697a655f75696e7433326f666665725f69645f77726f6e675f73697a655f75696e7433326f7261"
|
||||
"636c655f69645f77726f6e675f73697a655f75696e7433327061796368616e5f69645f77726f6e675f73697a655f75"
|
||||
"696e7433327065726d697373696f6e65645f646f6d61696e5f69645f77726f6e675f73697a655f75696e7433327469"
|
||||
"636b65745f69645f77726f6e675f73697a655f75696e7433327661756c745f69645f77726f6e675f73697a655f7569"
|
||||
"6e7433326e66745f7572695f77726f6e675f73697a655f75696e743235366e66745f6973737565725f77726f6e675f"
|
||||
"73697a655f75696e743235366e66745f7461786f6e5f77726f6e675f73697a655f75696e743235366e66745f736572"
|
||||
"69616c5f77726f6e675f73697a655f75696e743235366163636f756e74726f6f745f69645f77726f6e675f73697a65"
|
||||
"5f6163636f756e745f6964636865636b5f69645f77726f6e675f73697a655f6163636f756e745f696463726564656e"
|
||||
"7469616c5f69645f77726f6e675f73697a655f6163636f756e745f69643163726564656e7469616c5f69645f77726f"
|
||||
"6e675f73697a655f6163636f756e745f69643264656c65676174655f69645f77726f6e675f73697a655f6163636f75"
|
||||
"6e745f69643164656c65676174655f69645f77726f6e675f73697a655f6163636f756e745f6964326465706f736974"
|
||||
"5f707265617574685f69645f77726f6e675f73697a655f6163636f756e745f6964316465706f7369745f7072656175"
|
||||
"74685f69645f77726f6e675f73697a655f6163636f756e745f6964326469645f69645f77726f6e675f73697a655f61"
|
||||
"63636f756e745f6964657363726f775f69645f77726f6e675f73697a655f6163636f756e745f696474727573746c69"
|
||||
"6e655f69645f77726f6e675f73697a655f6163636f756e745f69643174727573746c696e655f69645f77726f6e675f"
|
||||
"73697a655f6163636f756e745f6964326d70745f69737375616e63655f69645f77726f6e675f73697a655f6163636f"
|
||||
"756e745f69646d70746f6b656e5f69645f77726f6e675f73697a655f6163636f756e745f69646e66745f6f66666572"
|
||||
"5f69645f77726f6e675f73697a655f6163636f756e745f69646f666665725f69645f77726f6e675f73697a655f6163"
|
||||
"636f756e745f69646f7261636c655f69645f77726f6e675f73697a655f6163636f756e745f69647061796368616e5f"
|
||||
"69645f77726f6e675f73697a655f6163636f756e745f6964317061796368616e5f69645f77726f6e675f73697a655f"
|
||||
"6163636f756e745f6964327065726d697373696f6e65645f646f6d61696e5f69645f77726f6e675f73697a655f6163"
|
||||
"636f756e745f69647369676e6572735f69645f77726f6e675f73697a655f6163636f756e745f69647469636b65745f"
|
||||
"69645f77726f6e675f73697a655f6163636f756e745f69647661756c745f69645f77726f6e675f73697a655f616363"
|
||||
"6f756e745f69646e66745f7572695f77726f6e675f73697a655f6163636f756e745f69646d70746f6b656e5f69645f"
|
||||
"6d707469645f77726f6e675f6c656e677468004d0970726f64756365727302086c616e677561676501045275737400"
|
||||
"0c70726f6365737365642d6279010572757374631d312e38372e30202831373036376539616320323032352d30352d"
|
||||
"303929002c0f7461726765745f6665617475726573022b0f6d757461626c652d676c6f62616c732b087369676e2d65"
|
||||
"7874";
|
||||
|
||||
extern std::string const kBadAlignWasmHex =
|
||||
"0061736d01000000011b046000017f60057f7f7f7f7f017f60067f7f7f7f7f7f017f60000002260203656e760f666c"
|
||||
"6f61745f66726f6d5f75696e74000103656e7608636865636b5f6964000203050403000000050301000306470b7f00"
|
||||
"4180080b7f00418088020b7f004180080b7f00418088040b7f00418088040b7f00418088080b7f004180080b7f0041"
|
||||
"8088080b7f004180800c0b7f0041000b7f0041010b07cc0110066d656d6f72790200115f5f7761736d5f63616c6c"
|
||||
"5f63746f72730002057465737431000307655f64617461310300057465737432000407655f64617461320301047465"
|
||||
"737400050c5f5f64736f5f68616e646c6503020a5f5f646174615f656e6403030b5f5f737461636b5f6c6f770304"
|
||||
"0c5f5f737461636b5f6869676803050d5f5f676c6f62616c5f6261736503060b5f5f686561705f6261736503070a"
|
||||
"5f5f686561705f656e6403080d5f5f6d656d6f72795f6261736503090c5f5f7461626c655f62617365030a0a9902"
|
||||
"0402000b2801017f418108427f370000418108410841a308410c41001000220041a40828020020004100481b0b5f01"
|
||||
"017f419a88024191a4cca00136010041928802428994ace0d0c1c38710370100418a88024281848ca0d0c0c1830837"
|
||||
"010041818802417f360000418a8802411441818802410441a3880241201001220041a4880228020020004100481b0b"
|
||||
"8a0101037f418108427f370000418108410841a308410c410010002100419a88024191a4cca0013601004192880242"
|
||||
"8994ace0d0c1c38710370100418a88024281848ca0d0c0c1830837010041818802417f36000041a408280200210141"
|
||||
"8a8802411441818802410441a3880241201001220241a4880228020020024100481b2000200120004100481b6a0b00"
|
||||
"7f0970726f647563657273010c70726f6365737365642d62790105636c616e675f31392e312e352d776173692d7364"
|
||||
"6b202868747470733a2f2f6769746875622e636f6d2f6c6c766d2f6c6c766d2d70726f6a6563742061623462356132"
|
||||
"6462353832393538616631656533303861373930636664623432626432343732302900490f7461726765745f666561"
|
||||
"7475726573042b0f6d757461626c652d676c6f62616c732b087369676e2d6578742b0f7265666572656e63652d7479"
|
||||
"7065732b0a6d756c746976616c7565";
|
||||
12
src/test/app/wasm_fixtures/fixtures.h
Normal file
12
src/test/app/wasm_fixtures/fixtures.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
// TODO: consider moving these to separate files (and figure out the build)
|
||||
|
||||
#include <string>
|
||||
|
||||
extern std::string const kLedgerSqnWasmHex;
|
||||
extern std::string const kAllHostFunctionsWasmHex;
|
||||
extern std::string const kAllKeyletsWasmHex;
|
||||
extern std::string const kCodecovTestsWasmHex;
|
||||
|
||||
extern std::string const kBadAlignWasmHex;
|
||||
14
src/test/app/wasm_fixtures/ledgerSqn.c
Normal file
14
src/test/app/wasm_fixtures/ledgerSqn.c
Normal file
@@ -0,0 +1,14 @@
|
||||
#include <stdint.h>
|
||||
|
||||
int32_t ldgr_index(uint8_t *, int32_t);
|
||||
|
||||
int finish()
|
||||
{
|
||||
uint32_t sqn;
|
||||
int32_t result = ldgr_index((uint8_t *)&sqn, sizeof(sqn));
|
||||
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
||||
return sqn >= 5 ? 5 : 0;
|
||||
}
|
||||
Reference in New Issue
Block a user