mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-18 10:05:51 +00:00
Compare commits
57 Commits
ripple/sma
...
ripple/wam
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 |
6
.github/CODEOWNERS
vendored
6
.github/CODEOWNERS
vendored
@@ -1,8 +1,2 @@
|
|||||||
# Allow anyone to review any change by default.
|
# Allow anyone to review any change by default.
|
||||||
*
|
*
|
||||||
|
|
||||||
# Require the rpc-reviewers team to review changes to the rpc code.
|
|
||||||
include/xrpl/protocol/ @xrplf/rpc-reviewers
|
|
||||||
src/libxrpl/protocol/ @xrplf/rpc-reviewers
|
|
||||||
src/xrpld/rpc/ @xrplf/rpc-reviewers
|
|
||||||
src/xrpld/app/misc/ @xrplf/rpc-reviewers
|
|
||||||
|
|||||||
@@ -119,6 +119,7 @@ endif()
|
|||||||
|
|
||||||
find_package(nudb REQUIRED)
|
find_package(nudb REQUIRED)
|
||||||
find_package(date REQUIRED)
|
find_package(date REQUIRED)
|
||||||
|
find_package(wasm-xrplf REQUIRED)
|
||||||
find_package(xxHash REQUIRED)
|
find_package(xxHash REQUIRED)
|
||||||
|
|
||||||
target_link_libraries(xrpl_libs INTERFACE
|
target_link_libraries(xrpl_libs INTERFACE
|
||||||
|
|||||||
@@ -63,11 +63,16 @@ target_link_libraries(xrpl.imports.main
|
|||||||
Xrpl::opts
|
Xrpl::opts
|
||||||
Xrpl::syslibs
|
Xrpl::syslibs
|
||||||
secp256k1::secp256k1
|
secp256k1::secp256k1
|
||||||
|
wasm-xrplf::wasm-xrplf
|
||||||
xrpl.libpb
|
xrpl.libpb
|
||||||
xxHash::xxhash
|
xxHash::xxhash
|
||||||
$<$<BOOL:${voidstar}>:antithesis-sdk-cpp>
|
$<$<BOOL:${voidstar}>:antithesis-sdk-cpp>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (WIN32)
|
||||||
|
target_link_libraries(xrpl.imports.main INTERFACE ntdll)
|
||||||
|
endif()
|
||||||
|
|
||||||
include(add_module)
|
include(add_module)
|
||||||
include(target_link_modules)
|
include(target_link_modules)
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
"requires": [
|
"requires": [
|
||||||
"zlib/1.3.1#b8bc2603263cf7eccbd6e17e66b0ed76%1756234269.497",
|
"zlib/1.3.1#b8bc2603263cf7eccbd6e17e66b0ed76%1756234269.497",
|
||||||
"xxhash/0.8.3#681d36a0a6111fc56e5e45ea182c19cc%1756234289.683",
|
"xxhash/0.8.3#681d36a0a6111fc56e5e45ea182c19cc%1756234289.683",
|
||||||
|
"wasm-xrplf/2.4.1-xrplf#dc67c558e283593ef0edd7eb00e9fa0d%1759862247.891",
|
||||||
"sqlite3/3.49.1#8631739a4c9b93bd3d6b753bac548a63%1756234266.869",
|
"sqlite3/3.49.1#8631739a4c9b93bd3d6b753bac548a63%1756234266.869",
|
||||||
"soci/4.0.3#a9f8d773cd33e356b5879a4b0564f287%1756234262.318",
|
"soci/4.0.3#a9f8d773cd33e356b5879a4b0564f287%1756234262.318",
|
||||||
"snappy/1.1.10#968fef506ff261592ec30c574d4a7809%1756234314.246",
|
"snappy/1.1.10#968fef506ff261592ec30c574d4a7809%1756234314.246",
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ from conan import ConanFile, __version__ as conan_version
|
|||||||
from conan.tools.cmake import CMake, CMakeToolchain, cmake_layout
|
from conan.tools.cmake import CMake, CMakeToolchain, cmake_layout
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
|
||||||
class Xrpl(ConanFile):
|
class Xrpl(ConanFile):
|
||||||
name = 'xrpl'
|
name = 'xrpl'
|
||||||
|
|
||||||
@@ -29,6 +30,7 @@ class Xrpl(ConanFile):
|
|||||||
'nudb/2.0.9',
|
'nudb/2.0.9',
|
||||||
'openssl/3.5.4',
|
'openssl/3.5.4',
|
||||||
'soci/4.0.3',
|
'soci/4.0.3',
|
||||||
|
'wasm-xrplf/2.4.1-xrplf',
|
||||||
'zlib/1.3.1',
|
'zlib/1.3.1',
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -133,6 +135,7 @@ class Xrpl(ConanFile):
|
|||||||
self.folders.generators = 'build/generators'
|
self.folders.generators = 'build/generators'
|
||||||
|
|
||||||
generators = 'CMakeDeps'
|
generators = 'CMakeDeps'
|
||||||
|
|
||||||
def generate(self):
|
def generate(self):
|
||||||
tc = CMakeToolchain(self)
|
tc = CMakeToolchain(self)
|
||||||
tc.variables['tests'] = self.options.tests
|
tc.variables['tests'] = self.options.tests
|
||||||
@@ -190,6 +193,7 @@ class Xrpl(ConanFile):
|
|||||||
'protobuf::libprotobuf',
|
'protobuf::libprotobuf',
|
||||||
'soci::soci',
|
'soci::soci',
|
||||||
'sqlite3::sqlite',
|
'sqlite3::sqlite',
|
||||||
|
'wasm-xrplf::wasm-xrplf',
|
||||||
'xxhash::xxhash',
|
'xxhash::xxhash',
|
||||||
'zlib::zlib',
|
'zlib::zlib',
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -341,6 +341,10 @@ abs(Number x) noexcept
|
|||||||
Number
|
Number
|
||||||
power(Number const& f, unsigned n);
|
power(Number const& f, unsigned n);
|
||||||
|
|
||||||
|
// logarithm with base 10
|
||||||
|
Number
|
||||||
|
lg(Number const& value);
|
||||||
|
|
||||||
// Returns f^(1/d)
|
// Returns f^(1/d)
|
||||||
// Uses Newton–Raphson iterations until the result stops changing
|
// Uses Newton–Raphson iterations until the result stops changing
|
||||||
// to find the root of the polynomial g(x) = x^d - f
|
// to find the root of the polynomial g(x) = x^d - f
|
||||||
|
|||||||
@@ -39,6 +39,13 @@ private:
|
|||||||
normalize();
|
normalize();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
/* The range for the mantissa when normalized */
|
||||||
|
static std::int64_t constexpr minMantissa = 1000000000000000ull;
|
||||||
|
static std::int64_t constexpr maxMantissa = 9999999999999999ull;
|
||||||
|
/* The range for the exponent when normalized */
|
||||||
|
static int constexpr minExponent = -96;
|
||||||
|
static int constexpr maxExponent = 80;
|
||||||
|
|
||||||
IOUAmount() = default;
|
IOUAmount() = default;
|
||||||
explicit IOUAmount(Number const& other);
|
explicit IOUAmount(Number const& other);
|
||||||
IOUAmount(beast::Zero);
|
IOUAmount(beast::Zero);
|
||||||
|
|||||||
@@ -116,6 +116,13 @@ std::uint8_t constexpr vaultMaximumIOUScale = 18;
|
|||||||
* another vault; counted from 0 */
|
* another vault; counted from 0 */
|
||||||
std::uint8_t constexpr maxAssetCheckDepth = 5;
|
std::uint8_t constexpr maxAssetCheckDepth = 5;
|
||||||
|
|
||||||
|
/** The maximum length of a Data field in Escrow object that can be updated by
|
||||||
|
* Wasm code */
|
||||||
|
std::size_t constexpr maxWasmDataLength = 4 * 1024;
|
||||||
|
|
||||||
|
/** The maximum length of a parameters passed from Wasm code*/
|
||||||
|
std::size_t constexpr maxWasmParamLength = 1024;
|
||||||
|
|
||||||
/** A ledger index. */
|
/** A ledger index. */
|
||||||
using LedgerIndex = std::uint32_t;
|
using LedgerIndex = std::uint32_t;
|
||||||
|
|
||||||
|
|||||||
@@ -122,6 +122,8 @@ enum TEMcodes : TERUnderlyingType {
|
|||||||
temARRAY_TOO_LARGE,
|
temARRAY_TOO_LARGE,
|
||||||
temBAD_TRANSFER_FEE,
|
temBAD_TRANSFER_FEE,
|
||||||
temINVALID_INNER_BATCH,
|
temINVALID_INNER_BATCH,
|
||||||
|
|
||||||
|
temBAD_WASM,
|
||||||
};
|
};
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -604,6 +604,48 @@ power(Number const& f, unsigned n)
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Continued fraction approximation of ln(x)
|
||||||
|
static Number
|
||||||
|
ln(Number const& x, unsigned iterations = 50)
|
||||||
|
{
|
||||||
|
if (x <= 0)
|
||||||
|
throw std::runtime_error("Not positive value");
|
||||||
|
|
||||||
|
Number const z = (x - 1) / (x + 1);
|
||||||
|
Number const zz = z * z;
|
||||||
|
Number denom = Number(1, -10);
|
||||||
|
|
||||||
|
// Construct the fraction from the bottom up
|
||||||
|
for (int i = iterations; i > 0; --i)
|
||||||
|
{
|
||||||
|
Number k(2 * i - 1);
|
||||||
|
denom = k - (i * i * zz / denom);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto const r = 2 * z / denom;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
Number
|
||||||
|
lg(Number const& x)
|
||||||
|
{
|
||||||
|
static Number const ln10 = ln(Number(10));
|
||||||
|
|
||||||
|
if (x <= Number(10))
|
||||||
|
{
|
||||||
|
auto const r = ln(x) / ln10;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ln(x) = ln(normX * 10^norm) = ln(normX) + norm * ln(10)
|
||||||
|
int diffExp = 15 + x.exponent();
|
||||||
|
Number const normalX = x / Number(1, diffExp); // (1 <= normalX < 10)
|
||||||
|
auto const lnX = ln(normalX) + diffExp * ln10;
|
||||||
|
|
||||||
|
auto const r = lnX / ln10;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
// Returns f^(1/d)
|
// Returns f^(1/d)
|
||||||
// Uses Newton–Raphson iterations until the result stops changing
|
// Uses Newton–Raphson iterations until the result stops changing
|
||||||
// to find the non-negative root of the polynomial g(x) = x^d - f
|
// to find the non-negative root of the polynomial g(x) = x^d - f
|
||||||
|
|||||||
@@ -39,13 +39,6 @@ setSTNumberSwitchover(bool v)
|
|||||||
*getStaticSTNumberSwitchover() = v;
|
*getStaticSTNumberSwitchover() = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The range for the mantissa when normalized */
|
|
||||||
static std::int64_t constexpr minMantissa = 1000000000000000ull;
|
|
||||||
static std::int64_t constexpr maxMantissa = 9999999999999999ull;
|
|
||||||
/* The range for the exponent when normalized */
|
|
||||||
static int constexpr minExponent = -96;
|
|
||||||
static int constexpr maxExponent = 80;
|
|
||||||
|
|
||||||
IOUAmount
|
IOUAmount
|
||||||
IOUAmount::minPositiveAmount()
|
IOUAmount::minPositiveAmount()
|
||||||
{
|
{
|
||||||
@@ -293,7 +286,8 @@ mulRatio(
|
|||||||
{
|
{
|
||||||
if (!result)
|
if (!result)
|
||||||
{
|
{
|
||||||
return IOUAmount(-minMantissa, minExponent);
|
return IOUAmount(
|
||||||
|
-IOUAmount::minMantissa, IOUAmount::minExponent);
|
||||||
}
|
}
|
||||||
// This subtraction cannot underflow because `result` is not zero
|
// This subtraction cannot underflow because `result` is not zero
|
||||||
return IOUAmount(result.mantissa() - 1, result.exponent());
|
return IOUAmount(result.mantissa() - 1, result.exponent());
|
||||||
|
|||||||
@@ -200,6 +200,7 @@ transResults()
|
|||||||
MAKE_ERROR(temARRAY_TOO_LARGE, "Malformed: Array is too large."),
|
MAKE_ERROR(temARRAY_TOO_LARGE, "Malformed: Array is too large."),
|
||||||
MAKE_ERROR(temBAD_TRANSFER_FEE, "Malformed: Transfer fee is outside valid range."),
|
MAKE_ERROR(temBAD_TRANSFER_FEE, "Malformed: Transfer fee is outside valid range."),
|
||||||
MAKE_ERROR(temINVALID_INNER_BATCH, "Malformed: Invalid inner batch transaction."),
|
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(terRETRY, "Retry transaction."),
|
||||||
MAKE_ERROR(terFUNDS_SPENT, "DEPRECATED."),
|
MAKE_ERROR(terFUNDS_SPENT, "DEPRECATED."),
|
||||||
|
|||||||
2966
src/test/app/HostFuncImpl_test.cpp
Normal file
2966
src/test/app/HostFuncImpl_test.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1342
src/test/app/TestHostFunctions.h
Normal file
1342
src/test/app/TestHostFunctions.h
Normal file
File diff suppressed because it is too large
Load Diff
711
src/test/app/Wasm_test.cpp
Normal file
711
src/test/app/Wasm_test.cpp
Normal file
@@ -0,0 +1,711 @@
|
|||||||
|
#ifdef _DEBUG
|
||||||
|
// #define DEBUG_OUTPUT 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <test/app/TestHostFunctions.h>
|
||||||
|
|
||||||
|
#include <xrpld/app/wasm/HostFuncWrapper.h>
|
||||||
|
#include <xrpld/app/wasm/WamrVM.h>
|
||||||
|
|
||||||
|
namespace ripple {
|
||||||
|
namespace test {
|
||||||
|
|
||||||
|
bool
|
||||||
|
testGetDataIncrement();
|
||||||
|
|
||||||
|
using Add_proto = int32_t(int32_t, int32_t);
|
||||||
|
static wasm_trap_t*
|
||||||
|
Add(void* env, wasm_val_vec_t const* params, wasm_val_vec_t* results)
|
||||||
|
{
|
||||||
|
int32_t Val1 = params->data[0].of.i32;
|
||||||
|
int32_t 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Wasm_test : public beast::unit_test::suite
|
||||||
|
{
|
||||||
|
void
|
||||||
|
testGetDataHelperFunctions()
|
||||||
|
{
|
||||||
|
testcase("getData helper functions");
|
||||||
|
BEAST_EXPECT(testGetDataIncrement());
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
testWasmLib()
|
||||||
|
{
|
||||||
|
testcase("wasmtime 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();
|
||||||
|
|
||||||
|
std::vector<WasmImportFunc> imports;
|
||||||
|
WasmImpFunc<Add_proto>(
|
||||||
|
imports, "func-add", reinterpret_cast<void*>(&Add));
|
||||||
|
|
||||||
|
auto re = vm.run(wasm, "addTwo", wasmParams(1234, 5678), imports);
|
||||||
|
|
||||||
|
// if (res) printf("invokeAdd get the result: %d\n", res.value());
|
||||||
|
|
||||||
|
if (BEAST_EXPECT(re.has_value()))
|
||||||
|
{
|
||||||
|
BEAST_EXPECTS(re->result == 6'912, std::to_string(re->result));
|
||||||
|
BEAST_EXPECTS(re->cost == 2, std::to_string(re->cost));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
testBadWasm()
|
||||||
|
{
|
||||||
|
testcase("bad wasm test");
|
||||||
|
|
||||||
|
using namespace test::jtx;
|
||||||
|
|
||||||
|
Env env{*this};
|
||||||
|
HostFunctions hfs;
|
||||||
|
|
||||||
|
{
|
||||||
|
auto wasmHex = "00000000";
|
||||||
|
auto wasmStr = boost::algorithm::unhex(std::string(wasmHex));
|
||||||
|
std::vector<uint8_t> wasm(wasmStr.begin(), wasmStr.end());
|
||||||
|
std::string funcName("mock_escrow");
|
||||||
|
|
||||||
|
auto re = runEscrowWasm(wasm, funcName, {}, &hfs, 15, env.journal);
|
||||||
|
BEAST_EXPECT(!re);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto wasmHex = "00112233445566778899AA";
|
||||||
|
auto wasmStr = boost::algorithm::unhex(std::string(wasmHex));
|
||||||
|
std::vector<uint8_t> wasm(wasmStr.begin(), wasmStr.end());
|
||||||
|
std::string funcName("mock_escrow");
|
||||||
|
|
||||||
|
auto const re =
|
||||||
|
preflightEscrowWasm(wasm, funcName, {}, &hfs, env.journal);
|
||||||
|
BEAST_EXPECT(!isTesSuccess(re));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// FinishFunction wrong function name
|
||||||
|
// pub fn bad() -> bool {
|
||||||
|
// unsafe { host_lib::getLedgerSqn() >= 5 }
|
||||||
|
// }
|
||||||
|
auto const badWasmHex =
|
||||||
|
"0061736d010000000105016000017f02190108686f73745f6c69620c6765"
|
||||||
|
"744c656467657253716e00000302010005030100100611027f00418080c0"
|
||||||
|
"000b7f00418080c0000b072b04066d656d6f727902000362616400010a5f"
|
||||||
|
"5f646174615f656e6403000b5f5f686561705f6261736503010a09010700"
|
||||||
|
"100041044a0b004d0970726f64756365727302086c616e67756167650104"
|
||||||
|
"52757374000c70726f6365737365642d6279010572757374631d312e3835"
|
||||||
|
"2e31202834656231363132353020323032352d30332d31352900490f7461"
|
||||||
|
"726765745f6665617475726573042b0f6d757461626c652d676c6f62616c"
|
||||||
|
"732b087369676e2d6578742b0f7265666572656e63652d74797065732b0a"
|
||||||
|
"6d756c746976616c7565";
|
||||||
|
auto wasmStr = boost::algorithm::unhex(std::string(badWasmHex));
|
||||||
|
std::vector<uint8_t> wasm(wasmStr.begin(), wasmStr.end());
|
||||||
|
|
||||||
|
auto const re = preflightEscrowWasm(
|
||||||
|
wasm, ESCROW_FUNCTION_NAME, {}, &hfs, env.journal);
|
||||||
|
BEAST_EXPECT(!isTesSuccess(re));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
testWasmLedgerSqn()
|
||||||
|
{
|
||||||
|
testcase("Wasm get ledger sequence");
|
||||||
|
|
||||||
|
auto wasmStr = boost::algorithm::unhex(ledgerSqnWasmHex);
|
||||||
|
Bytes wasm(wasmStr.begin(), wasmStr.end());
|
||||||
|
|
||||||
|
using namespace test::jtx;
|
||||||
|
|
||||||
|
Env env{*this};
|
||||||
|
TestLedgerDataProvider hf(&env);
|
||||||
|
|
||||||
|
std::vector<WasmImportFunc> imports;
|
||||||
|
WASM_IMPORT_FUNC2(imports, getLedgerSqn, "get_ledger_sqn", &hf, 33);
|
||||||
|
auto& engine = WasmEngine::instance();
|
||||||
|
|
||||||
|
auto re = engine.run(
|
||||||
|
wasm,
|
||||||
|
ESCROW_FUNCTION_NAME,
|
||||||
|
{},
|
||||||
|
imports,
|
||||||
|
&hf,
|
||||||
|
1'000'000,
|
||||||
|
env.journal);
|
||||||
|
|
||||||
|
// code takes 11 gas + 1 getLedgerSqn call
|
||||||
|
if (BEAST_EXPECT(re.has_value()))
|
||||||
|
{
|
||||||
|
BEAST_EXPECTS(re->result == 0, std::to_string(re->result));
|
||||||
|
BEAST_EXPECTS(re->cost == 39, std::to_string(re->cost));
|
||||||
|
}
|
||||||
|
|
||||||
|
env.close();
|
||||||
|
env.close();
|
||||||
|
|
||||||
|
// empty module - run the same instance
|
||||||
|
re = engine.run(
|
||||||
|
{}, ESCROW_FUNCTION_NAME, {}, imports, &hf, 1'000'000, env.journal);
|
||||||
|
|
||||||
|
// code takes 22 gas + 2 getLedgerSqn calls
|
||||||
|
if (BEAST_EXPECT(re.has_value()))
|
||||||
|
{
|
||||||
|
BEAST_EXPECTS(re->result == 5, std::to_string(re->result));
|
||||||
|
BEAST_EXPECTS(re->cost == 78, std::to_string(re->cost));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
testWasmFib()
|
||||||
|
{
|
||||||
|
testcase("Wasm fibo");
|
||||||
|
|
||||||
|
auto const ws = boost::algorithm::unhex(fibWasmHex);
|
||||||
|
Bytes const wasm(ws.begin(), ws.end());
|
||||||
|
auto& engine = WasmEngine::instance();
|
||||||
|
|
||||||
|
auto const re = engine.run(wasm, "fib", wasmParams(10));
|
||||||
|
|
||||||
|
if (BEAST_EXPECT(re.has_value()))
|
||||||
|
{
|
||||||
|
BEAST_EXPECTS(re->result == 55, std::to_string(re->result));
|
||||||
|
BEAST_EXPECTS(re->cost == 755, std::to_string(re->cost));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
testWasmSha()
|
||||||
|
{
|
||||||
|
testcase("Wasm sha");
|
||||||
|
|
||||||
|
auto const ws = boost::algorithm::unhex(sha512PureWasmHex);
|
||||||
|
Bytes const wasm(ws.begin(), ws.end());
|
||||||
|
auto& engine = WasmEngine::instance();
|
||||||
|
|
||||||
|
auto const re =
|
||||||
|
engine.run(wasm, "sha512_process", wasmParams(sha512PureWasmHex));
|
||||||
|
|
||||||
|
if (BEAST_EXPECT(re.has_value()))
|
||||||
|
{
|
||||||
|
BEAST_EXPECTS(re->result == 34'432, std::to_string(re->result));
|
||||||
|
BEAST_EXPECTS(re->cost == 157'452, std::to_string(re->cost));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
testWasmB58()
|
||||||
|
{
|
||||||
|
testcase("Wasm base58");
|
||||||
|
auto const ws = boost::algorithm::unhex(b58WasmHex);
|
||||||
|
Bytes const wasm(ws.begin(), ws.end());
|
||||||
|
auto& engine = WasmEngine::instance();
|
||||||
|
|
||||||
|
Bytes outb;
|
||||||
|
outb.resize(1024);
|
||||||
|
|
||||||
|
auto const minsz = std::min(
|
||||||
|
static_cast<std::uint32_t>(512),
|
||||||
|
static_cast<std::uint32_t>(b58WasmHex.size()));
|
||||||
|
auto const s = std::string_view(b58WasmHex.c_str(), minsz);
|
||||||
|
|
||||||
|
auto const re = engine.run(wasm, "b58enco", wasmParams(outb, s));
|
||||||
|
|
||||||
|
if (BEAST_EXPECT(re.has_value()))
|
||||||
|
{
|
||||||
|
BEAST_EXPECTS(re->result == 700, std::to_string(re->result));
|
||||||
|
BEAST_EXPECTS(re->cost == 3'066'129, std::to_string(re->cost));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
testWasmSP1Verifier()
|
||||||
|
{
|
||||||
|
testcase("Wasm sp1 zkproof verifier");
|
||||||
|
auto const ws = boost::algorithm::unhex(sp1WasmHex);
|
||||||
|
Bytes const wasm(ws.begin(), ws.end());
|
||||||
|
auto& engine = WasmEngine::instance();
|
||||||
|
|
||||||
|
auto const re = engine.run(wasm, "sp1_groth16_verifier");
|
||||||
|
|
||||||
|
if (BEAST_EXPECT(re.has_value()))
|
||||||
|
{
|
||||||
|
BEAST_EXPECTS(re->result == 1, std::to_string(re->result));
|
||||||
|
BEAST_EXPECTS(
|
||||||
|
re->cost == 4'191'711'969ll, std::to_string(re->cost));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
testWasmBG16Verifier()
|
||||||
|
{
|
||||||
|
testcase("Wasm BG16 zkproof verifier");
|
||||||
|
auto const ws = boost::algorithm::unhex(zkProofWasmHex);
|
||||||
|
Bytes const wasm(ws.begin(), ws.end());
|
||||||
|
auto& engine = WasmEngine::instance();
|
||||||
|
|
||||||
|
auto const re = engine.run(wasm, "bellman_groth16_test");
|
||||||
|
|
||||||
|
if (BEAST_EXPECT(re.has_value()))
|
||||||
|
{
|
||||||
|
BEAST_EXPECTS(re->result == 1, std::to_string(re->result));
|
||||||
|
BEAST_EXPECTS(re->cost == 332'205'984, std::to_string(re->cost));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
testHFCost()
|
||||||
|
{
|
||||||
|
testcase("wasm test host functions cost");
|
||||||
|
|
||||||
|
using namespace test::jtx;
|
||||||
|
|
||||||
|
Env env(*this);
|
||||||
|
{
|
||||||
|
std::string const wasmHex = allHostFunctionsWasmHex;
|
||||||
|
std::string const wasmStr = boost::algorithm::unhex(wasmHex);
|
||||||
|
std::vector<uint8_t> const wasm(wasmStr.begin(), wasmStr.end());
|
||||||
|
|
||||||
|
auto& engine = WasmEngine::instance();
|
||||||
|
|
||||||
|
TestHostFunctions hfs(env, 0);
|
||||||
|
std::vector<WasmImportFunc> imp = createWasmImport(&hfs);
|
||||||
|
for (auto& i : imp)
|
||||||
|
i.gas = 0;
|
||||||
|
|
||||||
|
auto re = engine.run(
|
||||||
|
wasm,
|
||||||
|
ESCROW_FUNCTION_NAME,
|
||||||
|
{},
|
||||||
|
imp,
|
||||||
|
&hfs,
|
||||||
|
1'000'000,
|
||||||
|
env.journal);
|
||||||
|
|
||||||
|
if (BEAST_EXPECT(re.has_value()))
|
||||||
|
{
|
||||||
|
BEAST_EXPECTS(re->result == 1, std::to_string(re->result));
|
||||||
|
BEAST_EXPECTS(re->cost == 838, std::to_string(re->cost));
|
||||||
|
}
|
||||||
|
|
||||||
|
env.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
env.close();
|
||||||
|
env.close();
|
||||||
|
env.close();
|
||||||
|
env.close();
|
||||||
|
env.close();
|
||||||
|
|
||||||
|
{
|
||||||
|
std::string const wasmHex = allHostFunctionsWasmHex;
|
||||||
|
std::string const wasmStr = boost::algorithm::unhex(wasmHex);
|
||||||
|
std::vector<uint8_t> const wasm(wasmStr.begin(), wasmStr.end());
|
||||||
|
|
||||||
|
auto& engine = WasmEngine::instance();
|
||||||
|
|
||||||
|
TestHostFunctions hfs(env, 0);
|
||||||
|
std::vector<WasmImportFunc> const imp = createWasmImport(&hfs);
|
||||||
|
|
||||||
|
auto re = engine.run(
|
||||||
|
wasm,
|
||||||
|
ESCROW_FUNCTION_NAME,
|
||||||
|
{},
|
||||||
|
imp,
|
||||||
|
&hfs,
|
||||||
|
1'000'000,
|
||||||
|
env.journal);
|
||||||
|
|
||||||
|
if (BEAST_EXPECT(re.has_value()))
|
||||||
|
{
|
||||||
|
BEAST_EXPECTS(re->result == 1, std::to_string(re->result));
|
||||||
|
BEAST_EXPECTS(re->cost == 40'098, std::to_string(re->cost));
|
||||||
|
}
|
||||||
|
|
||||||
|
env.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
testEscrowWasmDN()
|
||||||
|
{
|
||||||
|
testcase("escrow wasm devnet test");
|
||||||
|
|
||||||
|
std::string const wasmStr =
|
||||||
|
boost::algorithm::unhex(allHostFunctionsWasmHex);
|
||||||
|
std::vector<uint8_t> wasm(wasmStr.begin(), wasmStr.end());
|
||||||
|
|
||||||
|
using namespace test::jtx;
|
||||||
|
Env env{*this};
|
||||||
|
{
|
||||||
|
TestHostFunctions nfs(env, 0);
|
||||||
|
auto re =
|
||||||
|
runEscrowWasm(wasm, ESCROW_FUNCTION_NAME, {}, &nfs, 100'000);
|
||||||
|
if (BEAST_EXPECT(re.has_value()))
|
||||||
|
{
|
||||||
|
BEAST_EXPECTS(re->result == 1, std::to_string(re->result));
|
||||||
|
BEAST_EXPECTS(re->cost == 40'098, std::to_string(re->cost));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // fail because trying to access nonexistent field
|
||||||
|
struct BadTestHostFunctions : public TestHostFunctions
|
||||||
|
{
|
||||||
|
explicit BadTestHostFunctions(Env& env) : TestHostFunctions(env)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
Expected<Bytes, HostFunctionError>
|
||||||
|
getTxField(SField const& fname) override
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::FIELD_NOT_FOUND);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
BadTestHostFunctions nfs(env);
|
||||||
|
auto re =
|
||||||
|
runEscrowWasm(wasm, ESCROW_FUNCTION_NAME, {}, &nfs, 100'000);
|
||||||
|
if (BEAST_EXPECT(re.has_value()))
|
||||||
|
{
|
||||||
|
BEAST_EXPECTS(re->result == -201, std::to_string(re->result));
|
||||||
|
BEAST_EXPECTS(re->cost == 4'806, std::to_string(re->cost));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // fail because trying to allocate more than MAX_PAGES memory
|
||||||
|
struct BadTestHostFunctions : public TestHostFunctions
|
||||||
|
{
|
||||||
|
explicit BadTestHostFunctions(Env& env) : TestHostFunctions(env)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
Expected<Bytes, HostFunctionError>
|
||||||
|
getTxField(SField const& fname) override
|
||||||
|
{
|
||||||
|
return Bytes((MAX_PAGES + 1) * 64 * 1024, 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
BadTestHostFunctions nfs(env);
|
||||||
|
auto re =
|
||||||
|
runEscrowWasm(wasm, ESCROW_FUNCTION_NAME, {}, &nfs, 100'000);
|
||||||
|
if (BEAST_EXPECT(re.has_value()))
|
||||||
|
{
|
||||||
|
BEAST_EXPECTS(re->result == -201, std::to_string(re->result));
|
||||||
|
BEAST_EXPECTS(re->cost == 4'806, std::to_string(re->cost));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // fail because recursion too deep
|
||||||
|
|
||||||
|
auto const wasmStr = boost::algorithm::unhex(deepRecursionHex);
|
||||||
|
std::vector<uint8_t> wasm(wasmStr.begin(), wasmStr.end());
|
||||||
|
|
||||||
|
TestHostFunctionsSink nfs(env);
|
||||||
|
std::string funcName("recursive");
|
||||||
|
auto re = runEscrowWasm(wasm, funcName, {}, &nfs, 1'000'000'000);
|
||||||
|
BEAST_EXPECT(!re && re.error());
|
||||||
|
// std::cout << "bad case (deep recursion) result " << re.error()
|
||||||
|
// << std::endl;
|
||||||
|
|
||||||
|
auto const& sink = nfs.getSink();
|
||||||
|
auto countSubstr = [](std::string const& str,
|
||||||
|
std::string const& substr) {
|
||||||
|
std::size_t pos = 0;
|
||||||
|
int occurrences = 0;
|
||||||
|
while ((pos = str.find(substr, pos)) != std::string::npos)
|
||||||
|
{
|
||||||
|
occurrences++;
|
||||||
|
pos += substr.length();
|
||||||
|
}
|
||||||
|
return occurrences;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto const s = sink.messages().str();
|
||||||
|
BEAST_EXPECT(
|
||||||
|
countSubstr(s, "WAMR Error: failure to call func") == 1);
|
||||||
|
BEAST_EXPECT(
|
||||||
|
countSubstr(s, "Exception: wasm operand stack overflow") > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto wasmStr = boost::algorithm::unhex(ledgerSqnWasmHex);
|
||||||
|
Bytes wasm(wasmStr.begin(), wasmStr.end());
|
||||||
|
TestLedgerDataProvider ledgerDataProvider(&env);
|
||||||
|
|
||||||
|
std::vector<WasmImportFunc> imports;
|
||||||
|
WASM_IMPORT_FUNC2(
|
||||||
|
imports, getLedgerSqn, "get_ledger_sqn2", &ledgerDataProvider);
|
||||||
|
|
||||||
|
auto& engine = WasmEngine::instance();
|
||||||
|
|
||||||
|
auto re = engine.run(
|
||||||
|
wasm,
|
||||||
|
ESCROW_FUNCTION_NAME,
|
||||||
|
{},
|
||||||
|
imports,
|
||||||
|
nullptr,
|
||||||
|
1'000'000,
|
||||||
|
env.journal);
|
||||||
|
|
||||||
|
// expected import not provided
|
||||||
|
BEAST_EXPECT(!re);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
testFloat()
|
||||||
|
{
|
||||||
|
testcase("float point");
|
||||||
|
|
||||||
|
std::string const funcName("finish");
|
||||||
|
|
||||||
|
using namespace test::jtx;
|
||||||
|
|
||||||
|
Env env(*this);
|
||||||
|
{
|
||||||
|
std::string const wasmHex = floatTestsWasmHex;
|
||||||
|
std::string const wasmStr = boost::algorithm::unhex(wasmHex);
|
||||||
|
std::vector<uint8_t> const wasm(wasmStr.begin(), wasmStr.end());
|
||||||
|
|
||||||
|
TestHostFunctions hf(env, 0);
|
||||||
|
auto re = runEscrowWasm(wasm, funcName, {}, &hf, 100'000);
|
||||||
|
if (BEAST_EXPECT(re.has_value()))
|
||||||
|
{
|
||||||
|
BEAST_EXPECTS(re->result == 1, std::to_string(re->result));
|
||||||
|
BEAST_EXPECTS(re->cost == 97'411, std::to_string(re->cost));
|
||||||
|
}
|
||||||
|
env.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::string const wasmHex = float0Hex;
|
||||||
|
std::string const wasmStr = boost::algorithm::unhex(wasmHex);
|
||||||
|
std::vector<uint8_t> const wasm(wasmStr.begin(), wasmStr.end());
|
||||||
|
|
||||||
|
TestHostFunctions hf(env, 0);
|
||||||
|
auto re = runEscrowWasm(wasm, funcName, {}, &hf, 100'000);
|
||||||
|
if (BEAST_EXPECT(re.has_value()))
|
||||||
|
{
|
||||||
|
BEAST_EXPECTS(re->result == 1, std::to_string(re->result));
|
||||||
|
BEAST_EXPECTS(re->cost == 2'053, std::to_string(re->cost));
|
||||||
|
}
|
||||||
|
env.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
perfTest()
|
||||||
|
{
|
||||||
|
testcase("Perf test host functions");
|
||||||
|
|
||||||
|
using namespace jtx;
|
||||||
|
using namespace std::chrono;
|
||||||
|
|
||||||
|
// std::string const funcName("test");
|
||||||
|
auto const& wasmHex = hfPerfTest;
|
||||||
|
std::string const wasmStr = boost::algorithm::unhex(wasmHex);
|
||||||
|
std::vector<uint8_t> const wasm(wasmStr.begin(), wasmStr.end());
|
||||||
|
|
||||||
|
// std::string const credType = "abcde";
|
||||||
|
// std::string const credType2 = "fghijk";
|
||||||
|
// std::string const credType3 = "0123456";
|
||||||
|
// char const uri[] = "uri";
|
||||||
|
|
||||||
|
Account const alan{"alan"};
|
||||||
|
Account const bob{"bob"};
|
||||||
|
Account const issuer{"issuer"};
|
||||||
|
|
||||||
|
{
|
||||||
|
Env env(*this);
|
||||||
|
// Env env(*this, envconfig(), {}, nullptr,
|
||||||
|
// beast::severities::kTrace);
|
||||||
|
env.fund(XRP(5000), alan, bob, issuer);
|
||||||
|
env.close();
|
||||||
|
|
||||||
|
// // create escrow
|
||||||
|
// auto const seq = env.seq(alan);
|
||||||
|
// auto const k = keylet::escrow(alan, seq);
|
||||||
|
// // auto const allowance = 3'600;
|
||||||
|
// auto escrowCreate = escrow::create(alan, bob, XRP(1000));
|
||||||
|
// XRPAmount txnFees = env.current()->fees().base + 1000;
|
||||||
|
// env(escrowCreate,
|
||||||
|
// escrow::finish_function(wasmHex),
|
||||||
|
// escrow::finish_time(env.now() + 11s),
|
||||||
|
// escrow::cancel_time(env.now() + 100s),
|
||||||
|
// escrow::data("1000000000"), // 1000 XRP in drops
|
||||||
|
// memodata("memo1234567"),
|
||||||
|
// memodata("2memo1234567"),
|
||||||
|
// fee(txnFees));
|
||||||
|
|
||||||
|
// // create depositPreauth
|
||||||
|
// auto const k = keylet::depositPreauth(
|
||||||
|
// bob,
|
||||||
|
// {{issuer.id(), makeSlice(credType)},
|
||||||
|
// {issuer.id(), makeSlice(credType2)},
|
||||||
|
// {issuer.id(), makeSlice(credType3)}});
|
||||||
|
// env(deposit::authCredentials(
|
||||||
|
// bob,
|
||||||
|
// {{issuer, credType},
|
||||||
|
// {issuer, credType2},
|
||||||
|
// {issuer, credType3}}));
|
||||||
|
|
||||||
|
// create nft
|
||||||
|
[[maybe_unused]] uint256 const nft0{
|
||||||
|
token::getNextID(env, alan, 0u)};
|
||||||
|
env(token::mint(alan, 0u));
|
||||||
|
auto const k = keylet::nftoffer(alan, 0);
|
||||||
|
[[maybe_unused]] uint256 const nft1{
|
||||||
|
token::getNextID(env, alan, 0u)};
|
||||||
|
|
||||||
|
env(token::mint(alan, 0u),
|
||||||
|
token::uri(
|
||||||
|
"https://github.com/XRPLF/XRPL-Standards/discussions/"
|
||||||
|
"279?id=github.com/XRPLF/XRPL-Standards/discussions/"
|
||||||
|
"279&ut=github.com/XRPLF/XRPL-Standards/discussions/"
|
||||||
|
"279&sid=github.com/XRPLF/XRPL-Standards/discussions/"
|
||||||
|
"279&aot=github.com/XRPLF/XRPL-Standards/disc"));
|
||||||
|
[[maybe_unused]] uint256 const nft2{
|
||||||
|
token::getNextID(env, alan, 0u)};
|
||||||
|
env(token::mint(alan, 0u));
|
||||||
|
env.close();
|
||||||
|
|
||||||
|
PerfHostFunctions nfs(env, k, env.tx());
|
||||||
|
|
||||||
|
auto re = runEscrowWasm(wasm, ESCROW_FUNCTION_NAME, {}, &nfs);
|
||||||
|
if (BEAST_EXPECT(re.has_value()))
|
||||||
|
{
|
||||||
|
BEAST_EXPECT(re->result);
|
||||||
|
std::cout << "Res: " << re->result << " cost: " << re->cost
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// env(escrow::finish(alan, alan, seq),
|
||||||
|
// escrow::comp_allowance(allowance),
|
||||||
|
// fee(txnFees),
|
||||||
|
// ter(tesSUCCESS));
|
||||||
|
|
||||||
|
env.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
testCodecovWasm()
|
||||||
|
{
|
||||||
|
testcase("Codecov wasm test");
|
||||||
|
|
||||||
|
using namespace test::jtx;
|
||||||
|
|
||||||
|
Env env{*this};
|
||||||
|
|
||||||
|
auto const wasmStr = boost::algorithm::unhex(codecovTestsWasmHex);
|
||||||
|
Bytes const wasm(wasmStr.begin(), wasmStr.end());
|
||||||
|
TestHostFunctions hfs(env, 0);
|
||||||
|
|
||||||
|
auto const allowance = 152'981;
|
||||||
|
auto re = runEscrowWasm(
|
||||||
|
wasm, ESCROW_FUNCTION_NAME, {}, &hfs, allowance, env.journal);
|
||||||
|
|
||||||
|
if (BEAST_EXPECT(re.has_value()))
|
||||||
|
{
|
||||||
|
BEAST_EXPECT(re->result);
|
||||||
|
BEAST_EXPECTS(re->cost == allowance, std::to_string(re->cost));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
testDisabledFloat()
|
||||||
|
{
|
||||||
|
testcase("disabled float");
|
||||||
|
|
||||||
|
using namespace test::jtx;
|
||||||
|
Env env{*this};
|
||||||
|
|
||||||
|
auto const wasmStr = boost::algorithm::unhex(disabledFloatHex);
|
||||||
|
Bytes wasm(wasmStr.begin(), wasmStr.end());
|
||||||
|
std::string const funcName("finish");
|
||||||
|
TestHostFunctions hfs(env, 0);
|
||||||
|
|
||||||
|
{
|
||||||
|
// f32 set constant, opcode disabled exception
|
||||||
|
auto const re =
|
||||||
|
runEscrowWasm(wasm, funcName, {}, &hfs, 1'000'000, env.journal);
|
||||||
|
if (BEAST_EXPECT(!re.has_value()))
|
||||||
|
{
|
||||||
|
BEAST_EXPECT(re.error() == tecFAILED_PROCESSING);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// f32 add, can't create module exception
|
||||||
|
wasm[0x117] = 0x92;
|
||||||
|
auto const re =
|
||||||
|
runEscrowWasm(wasm, funcName, {}, &hfs, 1'000'000, env.journal);
|
||||||
|
if (BEAST_EXPECT(!re.has_value()))
|
||||||
|
{
|
||||||
|
BEAST_EXPECT(re.error() == tecFAILED_PROCESSING);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
run() override
|
||||||
|
{
|
||||||
|
using namespace test::jtx;
|
||||||
|
|
||||||
|
testGetDataHelperFunctions();
|
||||||
|
testWasmLib();
|
||||||
|
testBadWasm();
|
||||||
|
testWasmLedgerSqn();
|
||||||
|
|
||||||
|
testWasmFib();
|
||||||
|
testWasmSha();
|
||||||
|
testWasmB58();
|
||||||
|
|
||||||
|
// running too long
|
||||||
|
// testWasmSP1Verifier();
|
||||||
|
testWasmBG16Verifier();
|
||||||
|
|
||||||
|
testHFCost();
|
||||||
|
|
||||||
|
testEscrowWasmDN();
|
||||||
|
testFloat();
|
||||||
|
|
||||||
|
testCodecovWasm();
|
||||||
|
testDisabledFloat();
|
||||||
|
|
||||||
|
// perfTest();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
BEAST_DEFINE_TESTSUITE(Wasm, app, ripple);
|
||||||
|
|
||||||
|
} // namespace test
|
||||||
|
} // namespace ripple
|
||||||
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.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||||
|
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.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2"
|
||||||
|
dependencies = [
|
||||||
|
"typenum",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.177"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.103"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.41"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1"
|
||||||
|
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.108"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tinyvec"
|
||||||
|
version = "1.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa"
|
||||||
|
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.19.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.22"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "version_check"
|
||||||
|
version = "0.9.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "xrpl-address-macro"
|
||||||
|
version = "0.7.1"
|
||||||
|
source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git#d27d3e0b4abf3c0215aade729d89053805efe48e"
|
||||||
|
dependencies = [
|
||||||
|
"bs58",
|
||||||
|
"quote",
|
||||||
|
"sha2",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "xrpl-wasm-stdlib"
|
||||||
|
version = "0.7.1"
|
||||||
|
source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git#d27d3e0b4abf3c0215aade729d89053805efe48e"
|
||||||
|
dependencies = [
|
||||||
|
"xrpl-address-macro",
|
||||||
|
]
|
||||||
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" }
|
||||||
|
|
||||||
|
[profile.dev]
|
||||||
|
panic = "abort"
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
panic = "abort"
|
||||||
|
opt-level = "z"
|
||||||
|
lto = true
|
||||||
772
src/test/app/wasm_fixtures/all_host_functions/src/lib.rs
Normal file
772
src/test/app/wasm_fixtures/all_host_functions/src/lib.rs
Normal file
@@ -0,0 +1,772 @@
|
|||||||
|
#![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 sqn_result = unsafe { host::get_ledger_sqn() };
|
||||||
|
|
||||||
|
if sqn_result <= 0 {
|
||||||
|
let _ = trace_num("ERROR: get_ledger_sqn failed:", sqn_result as i64);
|
||||||
|
return -101; // Ledger sequence number test failed
|
||||||
|
}
|
||||||
|
let _ = trace_num("Ledger sequence number:", sqn_result as i64);
|
||||||
|
|
||||||
|
// Test 1.2: get_parent_ledger_time() - should return parent ledger timestamp
|
||||||
|
let time_result = unsafe { host::get_parent_ledger_time() };
|
||||||
|
|
||||||
|
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 _ = trace_num("Parent ledger time:", time_result 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::get_parent_ledger_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::get_tx_field(
|
||||||
|
sfield::Account,
|
||||||
|
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::get_tx_field(sfield::Fee, 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::get_tx_field(sfield::Sequence, 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, 0x00]; // Simple locator for first element
|
||||||
|
let mut nested_buffer = [0u8; 32];
|
||||||
|
let nested_result = unsafe {
|
||||||
|
host::get_tx_nested_field(
|
||||||
|
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::get_tx_array_len(sfield::Signers) };
|
||||||
|
let _ = trace_num("Signers array length:", signers_len as i64);
|
||||||
|
|
||||||
|
let memos_len = unsafe { host::get_tx_array_len(sfield::Memos) };
|
||||||
|
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::get_tx_nested_array_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::get_current_ledger_obj_field(
|
||||||
|
sfield::Balance,
|
||||||
|
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::get_current_ledger_obj_field(
|
||||||
|
sfield::Account,
|
||||||
|
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, 0x00]; // Simple locator
|
||||||
|
let mut current_nested_buffer = [0u8; 32];
|
||||||
|
let current_nested_result = unsafe {
|
||||||
|
host::get_current_ledger_obj_nested_field(
|
||||||
|
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::get_current_ledger_obj_array_len(sfield::Signers) };
|
||||||
|
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::get_current_ledger_obj_nested_array_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::account_keylet(
|
||||||
|
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: account_keylet failed for caching test:",
|
||||||
|
keylet_result as i64,
|
||||||
|
);
|
||||||
|
return -401; // Keylet generation failed for caching test
|
||||||
|
}
|
||||||
|
|
||||||
|
let cache_result =
|
||||||
|
unsafe { host::cache_ledger_obj(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::get_ledger_obj_field(
|
||||||
|
1,
|
||||||
|
sfield::Balance,
|
||||||
|
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, 0x00];
|
||||||
|
let nested_result = unsafe {
|
||||||
|
host::get_ledger_obj_nested_field(
|
||||||
|
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::get_ledger_obj_array_len(1, sfield::Signers) };
|
||||||
|
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::get_ledger_obj_nested_array_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::get_ledger_obj_field(
|
||||||
|
slot,
|
||||||
|
sfield::Balance,
|
||||||
|
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, 0x00];
|
||||||
|
let mut cached_nested_buffer = [0u8; 32];
|
||||||
|
let cached_nested_result = unsafe {
|
||||||
|
host::get_ledger_obj_nested_field(
|
||||||
|
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::get_ledger_obj_array_len(slot, sfield::Signers) };
|
||||||
|
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::get_ledger_obj_nested_array_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: account_keylet() - Generate keylet for account
|
||||||
|
let mut account_keylet_buffer = [0u8; 32];
|
||||||
|
let account_keylet_result = unsafe {
|
||||||
|
host::account_keylet(
|
||||||
|
account_id.0.as_ptr(),
|
||||||
|
account_id.0.len(),
|
||||||
|
account_keylet_buffer.as_mut_ptr(),
|
||||||
|
account_keylet_buffer.len(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
if account_keylet_result != 32 {
|
||||||
|
let _ = trace_num(
|
||||||
|
"ERROR: account_keylet failed:",
|
||||||
|
account_keylet_result as i64,
|
||||||
|
);
|
||||||
|
return -501; // Account keylet generation failed
|
||||||
|
}
|
||||||
|
let _ = trace_data("Account keylet:", &account_keylet_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_keylet(
|
||||||
|
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 escrow_keylet_result = unsafe {
|
||||||
|
host::escrow_keylet(
|
||||||
|
account_id.0.as_ptr(),
|
||||||
|
account_id.0.len(),
|
||||||
|
1000, // Sequence number
|
||||||
|
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 oracle_keylet_result = unsafe {
|
||||||
|
host::oracle_keylet(
|
||||||
|
account_id.0.as_ptr(),
|
||||||
|
account_id.0.len(),
|
||||||
|
42, // Document ID
|
||||||
|
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::compute_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::get_nft(
|
||||||
|
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::update_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.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||||
|
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.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2"
|
||||||
|
dependencies = [
|
||||||
|
"typenum",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.177"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.103"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.41"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1"
|
||||||
|
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.108"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tinyvec"
|
||||||
|
version = "1.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa"
|
||||||
|
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.19.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.22"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "version_check"
|
||||||
|
version = "0.9.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "xrpl-address-macro"
|
||||||
|
version = "0.7.1"
|
||||||
|
source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git#d27d3e0b4abf3c0215aade729d89053805efe48e"
|
||||||
|
dependencies = [
|
||||||
|
"bs58",
|
||||||
|
"quote",
|
||||||
|
"sha2",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "xrpl-wasm-stdlib"
|
||||||
|
version = "0.7.1"
|
||||||
|
source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git#d27d3e0b4abf3c0215aade729d89053805efe48e"
|
||||||
|
dependencies = [
|
||||||
|
"xrpl-address-macro",
|
||||||
|
]
|
||||||
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" }
|
||||||
|
|
||||||
|
[profile.dev]
|
||||||
|
panic = "abort"
|
||||||
181
src/test/app/wasm_fixtures/all_keylets/src/lib.rs
Normal file
181
src/test/app/wasm_fixtures/all_keylets/src/lib.rs
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
#![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::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::types::account_id::AccountID;
|
||||||
|
use xrpl_std::core::types::currency::Currency;
|
||||||
|
use xrpl_std::core::types::issue::{IouIssue, Issue, XrpIssue};
|
||||||
|
use xrpl_std::core::types::keylets;
|
||||||
|
use xrpl_std::core::types::mpt_id::MptId;
|
||||||
|
use xrpl_std::core::types::uint::Hash256;
|
||||||
|
use xrpl_std::host;
|
||||||
|
use xrpl_std::host::trace::{trace, trace_account, trace_data, trace_num, DataRepr};
|
||||||
|
use xrpl_std::sfield;
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub fn object_exists(
|
||||||
|
keylet_result: Result<keylets::KeyletBytes>,
|
||||||
|
keylet_type: &str,
|
||||||
|
field: i32,
|
||||||
|
) -> Result<bool> {
|
||||||
|
match keylet_result {
|
||||||
|
Ok(keylet) => {
|
||||||
|
let _ = trace_data(keylet_type, &keylet, DataRepr::AsHex);
|
||||||
|
|
||||||
|
let slot = unsafe { host::cache_ledger_obj(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.into());
|
||||||
|
match ledger_object::get_field::<Hash256>(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::<AccountID>(slot, 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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_account("Account:", &account);
|
||||||
|
|
||||||
|
let destination = escrow.get_destination().unwrap_or_panic();
|
||||||
|
let _ = trace_account("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 account_keylet = keylets::account_keylet(&account);
|
||||||
|
check_object_exists!(account_keylet, "Account", sfield::Account);
|
||||||
|
|
||||||
|
let currency_code: &[u8; 3] = b"USD";
|
||||||
|
let currency: Currency = Currency::from(*currency_code);
|
||||||
|
let line_keylet = keylets::line_keylet(&account, &destination, ¤cy);
|
||||||
|
check_object_exists!(line_keylet, "Trustline", sfield::Generic);
|
||||||
|
seq += 1;
|
||||||
|
|
||||||
|
let asset1 = Issue::XRP(XrpIssue {});
|
||||||
|
let asset2 = Issue::IOU(IouIssue::new(destination, currency));
|
||||||
|
check_object_exists!(
|
||||||
|
keylets::amm_keylet(&asset1, &asset2),
|
||||||
|
"AMM",
|
||||||
|
sfield::Account
|
||||||
|
);
|
||||||
|
|
||||||
|
let check_keylet = keylets::check_keylet(&account, seq);
|
||||||
|
check_object_exists!(check_keylet, "Check", sfield::Account);
|
||||||
|
seq += 1;
|
||||||
|
|
||||||
|
let cred_type: &[u8] = b"termsandconditions";
|
||||||
|
let credential_keylet = keylets::credential_keylet(&account, &account, cred_type);
|
||||||
|
check_object_exists!(credential_keylet, "Credential", sfield::Subject);
|
||||||
|
seq += 1;
|
||||||
|
|
||||||
|
let delegate_keylet = keylets::delegate_keylet(&account, &destination);
|
||||||
|
check_object_exists!(delegate_keylet, "Delegate", sfield::Account);
|
||||||
|
seq += 1;
|
||||||
|
|
||||||
|
let deposit_preauth_keylet = keylets::deposit_preauth_keylet(&account, &destination);
|
||||||
|
check_object_exists!(deposit_preauth_keylet, "DepositPreauth", sfield::Account);
|
||||||
|
seq += 1;
|
||||||
|
|
||||||
|
let did_keylet = keylets::did_keylet(&account);
|
||||||
|
check_object_exists!(did_keylet, "DID", sfield::Account);
|
||||||
|
seq += 1;
|
||||||
|
|
||||||
|
let escrow_keylet = keylets::escrow_keylet(&account, seq);
|
||||||
|
check_object_exists!(escrow_keylet, "Escrow", sfield::Account);
|
||||||
|
seq += 1;
|
||||||
|
|
||||||
|
let mpt_issuance_keylet = keylets::mpt_issuance_keylet(&account, seq);
|
||||||
|
let mpt_id = MptId::new(seq.try_into().unwrap(), account);
|
||||||
|
check_object_exists!(mpt_issuance_keylet, "MPTIssuance", sfield::Issuer);
|
||||||
|
seq += 1;
|
||||||
|
|
||||||
|
let mptoken_keylet = keylets::mptoken_keylet(&mpt_id, &destination);
|
||||||
|
check_object_exists!(mptoken_keylet, "MPToken", sfield::Account);
|
||||||
|
|
||||||
|
let nft_offer_keylet = keylets::nft_offer_keylet(&destination, 6);
|
||||||
|
check_object_exists!(nft_offer_keylet, "NFTokenOffer", sfield::Owner);
|
||||||
|
|
||||||
|
let offer_keylet = keylets::offer_keylet(&account, seq);
|
||||||
|
check_object_exists!(offer_keylet, "Offer", sfield::Account);
|
||||||
|
seq += 1;
|
||||||
|
|
||||||
|
let paychan_keylet = keylets::paychan_keylet(&account, &destination, seq);
|
||||||
|
check_object_exists!(paychan_keylet, "PayChannel", sfield::Account);
|
||||||
|
seq += 1;
|
||||||
|
|
||||||
|
let pd_keylet = keylets::permissioned_domain_keylet(&account, seq);
|
||||||
|
check_object_exists!(pd_keylet, "PermissionedDomain", sfield::Owner);
|
||||||
|
seq += 1;
|
||||||
|
|
||||||
|
let signers_keylet = keylets::signers_keylet(&account);
|
||||||
|
check_object_exists!(signers_keylet, "SignerList", sfield::Generic);
|
||||||
|
seq += 1;
|
||||||
|
|
||||||
|
seq += 1; // ticket sequence number is one greater
|
||||||
|
let ticket_keylet = keylets::ticket_keylet(&account, seq);
|
||||||
|
check_object_exists!(ticket_keylet, "Ticket", sfield::Account);
|
||||||
|
seq += 1;
|
||||||
|
|
||||||
|
let vault_keylet = keylets::vault_keylet(&account, seq);
|
||||||
|
check_object_exists!(vault_keylet, "Vault", sfield::Account);
|
||||||
|
// seq += 1;
|
||||||
|
|
||||||
|
1 // All keylets exist, finish the escrow.
|
||||||
|
}
|
||||||
73
src/test/app/wasm_fixtures/b58.c
Normal file
73
src/test/app/wasm_fixtures/b58.c
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
static char const b58digits_ordered[] =
|
||||||
|
"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
||||||
|
|
||||||
|
uint8_t e_data[32 * 1024];
|
||||||
|
|
||||||
|
void*
|
||||||
|
allocate(int sz)
|
||||||
|
{
|
||||||
|
static int idx = 0;
|
||||||
|
if (idx >= 32)
|
||||||
|
return 0;
|
||||||
|
if (sz > 1024)
|
||||||
|
return 0;
|
||||||
|
return &e_data[idx++ << 10];
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
deallocate(void* p)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
extern int32_t
|
||||||
|
b58enco(char* b58, int32_t b58sz, void const* data, int32_t binsz)
|
||||||
|
{
|
||||||
|
uint8_t const* bin = data;
|
||||||
|
int32_t carry;
|
||||||
|
int32_t i, j, high, zcount = 0;
|
||||||
|
int32_t size;
|
||||||
|
|
||||||
|
while (zcount < binsz && !bin[zcount])
|
||||||
|
++zcount;
|
||||||
|
|
||||||
|
size = (binsz - zcount) * 138 / 100 + 1;
|
||||||
|
uint8_t* buf = allocate(size);
|
||||||
|
if (!buf)
|
||||||
|
return 0;
|
||||||
|
// memset(buf, 0, size);
|
||||||
|
for (i = 0; i < size; ++i)
|
||||||
|
buf[i] = 0;
|
||||||
|
|
||||||
|
for (i = zcount, high = size - 1; i < binsz; ++i, high = j)
|
||||||
|
{
|
||||||
|
for (carry = bin[i], j = size - 1; (j > high) || carry; --j)
|
||||||
|
{
|
||||||
|
carry += 256 * buf[j];
|
||||||
|
buf[j] = carry % 58;
|
||||||
|
carry /= 58;
|
||||||
|
if (!j)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (j = 0; j < size && !buf[j]; ++j)
|
||||||
|
;
|
||||||
|
|
||||||
|
if (b58sz <= zcount + size - j)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (zcount)
|
||||||
|
{
|
||||||
|
// memset(b58, '1', zcount);
|
||||||
|
for (i = 0; i < zcount; ++i)
|
||||||
|
b58[i] = '1';
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = zcount; j < size; ++i, ++j)
|
||||||
|
b58[i] = b58digits_ordered[buf[j]];
|
||||||
|
b58[i] = '\0';
|
||||||
|
|
||||||
|
return i + 1;
|
||||||
|
}
|
||||||
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.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||||
|
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.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2"
|
||||||
|
dependencies = [
|
||||||
|
"typenum",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.177"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.103"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.41"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1"
|
||||||
|
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.108"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tinyvec"
|
||||||
|
version = "1.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa"
|
||||||
|
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.19.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.22"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "version_check"
|
||||||
|
version = "0.9.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "xrpl-address-macro"
|
||||||
|
version = "0.7.1"
|
||||||
|
source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git#d27d3e0b4abf3c0215aade729d89053805efe48e"
|
||||||
|
dependencies = [
|
||||||
|
"bs58",
|
||||||
|
"quote",
|
||||||
|
"sha2",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "xrpl-wasm-stdlib"
|
||||||
|
version = "0.7.1"
|
||||||
|
source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git#d27d3e0b4abf3c0215aade729d89053805efe48e"
|
||||||
|
dependencies = [
|
||||||
|
"xrpl-address-macro",
|
||||||
|
]
|
||||||
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" }
|
||||||
@@ -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 get_parent_ledger_hash(out_buff_ptr: i32, out_buff_len: i32) -> i32;
|
||||||
|
|
||||||
|
pub fn cache_ledger_obj(keylet_ptr: i32, keylet_len: i32, cache_num: i32) -> i32;
|
||||||
|
|
||||||
|
pub fn get_tx_nested_array_len(locator_ptr: i32, locator_len: i32) -> i32;
|
||||||
|
|
||||||
|
pub fn account_keylet(
|
||||||
|
account_ptr: i32,
|
||||||
|
account_len: i32,
|
||||||
|
out_buff_ptr: *mut u8,
|
||||||
|
out_buff_len: usize,
|
||||||
|
) -> i32;
|
||||||
|
|
||||||
|
pub fn line_keylet(
|
||||||
|
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;
|
||||||
|
}
|
||||||
1532
src/test/app/wasm_fixtures/codecov_tests/src/lib.rs
Normal file
1532
src/test/app/wasm_fixtures/codecov_tests/src/lib.rs
Normal file
File diff suppressed because it is too large
Load Diff
134
src/test/app/wasm_fixtures/copyFixtures.py
Normal file
134
src/test/app/wasm_fixtures/copyFixtures.py
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import subprocess
|
||||||
|
import re
|
||||||
|
|
||||||
|
OPT = "-Oz"
|
||||||
|
|
||||||
|
|
||||||
|
def update_fixture(project_name, wasm):
|
||||||
|
fixture_name = (
|
||||||
|
re.sub(r"_([a-z])", lambda m: m.group(1).upper(), project_name) + "WasmHex"
|
||||||
|
)
|
||||||
|
print(f"Updating fixture: {fixture_name}")
|
||||||
|
|
||||||
|
cpp_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "fixtures.cpp"))
|
||||||
|
h_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "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\n extern 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 process_rust(project_name):
|
||||||
|
project_path = os.path.abspath(
|
||||||
|
os.path.join(os.path.dirname(__file__), project_name)
|
||||||
|
)
|
||||||
|
wasm_location = f"target/wasm32v1-none/release/{project_name}.wasm"
|
||||||
|
build_cmd = (
|
||||||
|
f"(cd {project_path} "
|
||||||
|
f"&& cargo build --target wasm32v1-none --release "
|
||||||
|
f"&& wasm-opt {wasm_location} {OPT} -o {wasm_location}"
|
||||||
|
")"
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
result = subprocess.run(
|
||||||
|
build_cmd, shell=True, check=True, capture_output=True, text=True
|
||||||
|
)
|
||||||
|
print(f"stdout: {result.stdout}")
|
||||||
|
if result.stderr:
|
||||||
|
print(f"stderr: {result.stderr}")
|
||||||
|
print(f"WASM file for {project_name} has been built and optimized.")
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
print(f"exec error: {e}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
src_path = os.path.abspath(
|
||||||
|
os.path.join(
|
||||||
|
os.path.dirname(__file__),
|
||||||
|
f"{project_name}/target/wasm32v1-none/release/{project_name}.wasm",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
with open(src_path, "rb") as f:
|
||||||
|
data = f.read()
|
||||||
|
wasm = data.hex()
|
||||||
|
update_fixture(project_name, wasm)
|
||||||
|
|
||||||
|
|
||||||
|
def process_c(project_name):
|
||||||
|
project_path = os.path.abspath(
|
||||||
|
os.path.join(os.path.dirname(__file__), f"{project_name}.c")
|
||||||
|
)
|
||||||
|
wasm_path = os.path.abspath(
|
||||||
|
os.path.join(os.path.dirname(__file__), f"{project_name}.wasm")
|
||||||
|
)
|
||||||
|
build_cmd = (
|
||||||
|
f"$CC --sysroot=$SYSROOT "
|
||||||
|
f"-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 "
|
||||||
|
f"-o {wasm_path} {project_path}"
|
||||||
|
f"&& wasm-opt {wasm_path} {OPT} -o {wasm_path}"
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
result = subprocess.run(
|
||||||
|
build_cmd, shell=True, check=True, capture_output=True, text=True
|
||||||
|
)
|
||||||
|
print(f"stdout: {result.stdout}")
|
||||||
|
if result.stderr:
|
||||||
|
print(f"stderr: {result.stderr}")
|
||||||
|
print(
|
||||||
|
f"WASM file for {project_name} has been built with WASI support using clang."
|
||||||
|
)
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
print(f"exec error: {e}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
with open(wasm_path, "rb") as f:
|
||||||
|
data = f.read()
|
||||||
|
wasm = data.hex()
|
||||||
|
update_fixture(project_name, wasm)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
if len(sys.argv) > 2:
|
||||||
|
print("Usage: python copyFixtures.py [<project_name>]")
|
||||||
|
sys.exit(1)
|
||||||
|
if len(sys.argv) == 2:
|
||||||
|
if os.path.isdir(os.path.join(os.path.dirname(__file__), sys.argv[1])):
|
||||||
|
process_rust(sys.argv[1])
|
||||||
|
else:
|
||||||
|
process_c(sys.argv[1])
|
||||||
|
print("Fixture has been processed.")
|
||||||
|
else:
|
||||||
|
dirs = [
|
||||||
|
d
|
||||||
|
for d in os.listdir(os.path.dirname(__file__))
|
||||||
|
if os.path.isdir(os.path.join(os.path.dirname(__file__), d))
|
||||||
|
]
|
||||||
|
c_files = [f for f in os.listdir(os.path.dirname(__file__)) if f.endswith(".c")]
|
||||||
|
for d in dirs:
|
||||||
|
process_rust(d)
|
||||||
|
for c in c_files:
|
||||||
|
process_c(c[:-2])
|
||||||
|
print("All fixtures have been processed.")
|
||||||
34
src/test/app/wasm_fixtures/disableFloat.wat
Normal file
34
src/test/app/wasm_fixtures/disableFloat.wat
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
(module
|
||||||
|
(type (;0;) (func))
|
||||||
|
(type (;1;) (func (result i32)))
|
||||||
|
(func (;0;) (type 0))
|
||||||
|
(func (;1;) (type 1) (result i32)
|
||||||
|
f32.const -2048
|
||||||
|
f32.const 2050
|
||||||
|
f32.sub
|
||||||
|
drop
|
||||||
|
i32.const 1)
|
||||||
|
(memory (;0;) 2)
|
||||||
|
(global (;0;) i32 (i32.const 1024))
|
||||||
|
(global (;1;) i32 (i32.const 1024))
|
||||||
|
(global (;2;) i32 (i32.const 2048))
|
||||||
|
(global (;3;) i32 (i32.const 2048))
|
||||||
|
(global (;4;) i32 (i32.const 67584))
|
||||||
|
(global (;5;) i32 (i32.const 1024))
|
||||||
|
(global (;6;) i32 (i32.const 67584))
|
||||||
|
(global (;7;) i32 (i32.const 131072))
|
||||||
|
(global (;8;) i32 (i32.const 0))
|
||||||
|
(global (;9;) i32 (i32.const 1))
|
||||||
|
(export "memory" (memory 0))
|
||||||
|
(export "__wasm_call_ctors" (func 0))
|
||||||
|
(export "finish" (func 1))
|
||||||
|
(export "buf" (global 0))
|
||||||
|
(export "__dso_handle" (global 1))
|
||||||
|
(export "__data_end" (global 2))
|
||||||
|
(export "__stack_low" (global 3))
|
||||||
|
(export "__stack_high" (global 4))
|
||||||
|
(export "__global_base" (global 5))
|
||||||
|
(export "__heap_base" (global 6))
|
||||||
|
(export "__heap_end" (global 7))
|
||||||
|
(export "__memory_base" (global 8))
|
||||||
|
(export "__table_base" (global 9)))
|
||||||
12
src/test/app/wasm_fixtures/fib.c
Normal file
12
src/test/app/wasm_fixtures/fib.c
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
// typedef long long mint;
|
||||||
|
typedef int mint;
|
||||||
|
|
||||||
|
mint
|
||||||
|
fib(mint n)
|
||||||
|
{
|
||||||
|
if (!n)
|
||||||
|
return 0;
|
||||||
|
if (n <= 2)
|
||||||
|
return 1;
|
||||||
|
return fib(n - 1) + fib(n - 2);
|
||||||
|
}
|
||||||
10278
src/test/app/wasm_fixtures/fixtures.cpp
Normal file
10278
src/test/app/wasm_fixtures/fixtures.cpp
Normal file
File diff suppressed because it is too large
Load Diff
33
src/test/app/wasm_fixtures/fixtures.h
Normal file
33
src/test/app/wasm_fixtures/fixtures.h
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// TODO: consider moving these to separate files (and figure out the build)
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
extern std::string const ledgerSqnWasmHex;
|
||||||
|
|
||||||
|
extern std::string const allHostFunctionsWasmHex;
|
||||||
|
|
||||||
|
extern std::string const deepRecursionHex;
|
||||||
|
|
||||||
|
extern std::string const fibWasmHex;
|
||||||
|
|
||||||
|
extern std::string const b58WasmHex;
|
||||||
|
|
||||||
|
extern std::string const sha512PureWasmHex;
|
||||||
|
|
||||||
|
extern std::string const zkProofWasmHex;
|
||||||
|
|
||||||
|
extern std::string const sp1WasmHex;
|
||||||
|
|
||||||
|
extern std::string const hfPerfTest;
|
||||||
|
|
||||||
|
extern std::string const allKeyletsWasmHex;
|
||||||
|
|
||||||
|
extern std::string const codecovTestsWasmHex;
|
||||||
|
|
||||||
|
extern std::string const floatTestsWasmHex;
|
||||||
|
|
||||||
|
extern std::string const float0Hex;
|
||||||
|
|
||||||
|
extern std::string const disabledFloatHex;
|
||||||
171
src/test/app/wasm_fixtures/float_tests/Cargo.lock
generated
Normal file
171
src/test/app/wasm_fixtures/float_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 = "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.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||||
|
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 = "float_tests"
|
||||||
|
version = "0.0.1"
|
||||||
|
dependencies = [
|
||||||
|
"xrpl-wasm-stdlib",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "generic-array"
|
||||||
|
version = "0.14.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2"
|
||||||
|
dependencies = [
|
||||||
|
"typenum",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.177"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.103"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.41"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1"
|
||||||
|
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.108"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tinyvec"
|
||||||
|
version = "1.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa"
|
||||||
|
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.19.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.22"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "version_check"
|
||||||
|
version = "0.9.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "xrpl-address-macro"
|
||||||
|
version = "0.7.1"
|
||||||
|
source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git#d27d3e0b4abf3c0215aade729d89053805efe48e"
|
||||||
|
dependencies = [
|
||||||
|
"bs58",
|
||||||
|
"quote",
|
||||||
|
"sha2",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "xrpl-wasm-stdlib"
|
||||||
|
version = "0.7.1"
|
||||||
|
source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git#d27d3e0b4abf3c0215aade729d89053805efe48e"
|
||||||
|
dependencies = [
|
||||||
|
"xrpl-address-macro",
|
||||||
|
]
|
||||||
21
src/test/app/wasm_fixtures/float_tests/Cargo.toml
Normal file
21
src/test/app/wasm_fixtures/float_tests/Cargo.toml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
[package]
|
||||||
|
name = "float_tests"
|
||||||
|
version = "0.0.1"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
# 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" }
|
||||||
|
|
||||||
|
[profile.dev]
|
||||||
|
panic = "abort"
|
||||||
461
src/test/app/wasm_fixtures/float_tests/src/lib.rs
Normal file
461
src/test/app/wasm_fixtures/float_tests/src/lib.rs
Normal file
@@ -0,0 +1,461 @@
|
|||||||
|
#![allow(unused_imports)]
|
||||||
|
#![allow(unused_variables)]
|
||||||
|
#![cfg_attr(target_arch = "wasm32", no_std)]
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
extern crate std;
|
||||||
|
|
||||||
|
use xrpl_std::core::locator::Locator;
|
||||||
|
use xrpl_std::core::types::opaque_float::{FLOAT_NEGATIVE_ONE, FLOAT_ONE};
|
||||||
|
use xrpl_std::decode_hex_32;
|
||||||
|
use xrpl_std::host::trace::DataRepr::AsHex;
|
||||||
|
use xrpl_std::host::trace::{trace, trace_data, trace_float, trace_num, DataRepr};
|
||||||
|
use xrpl_std::host::{
|
||||||
|
cache_ledger_obj, float_add, float_compare, float_divide, float_from_int, float_from_uint,
|
||||||
|
float_log, float_multiply, float_pow, float_root, float_set, float_subtract,
|
||||||
|
get_ledger_obj_array_len, get_ledger_obj_field, get_ledger_obj_nested_field,
|
||||||
|
trace_opaque_float, FLOAT_ROUNDING_MODES_TO_NEAREST,
|
||||||
|
};
|
||||||
|
use xrpl_std::sfield;
|
||||||
|
use xrpl_std::sfield::{
|
||||||
|
Account, AccountTxnID, Balance, Domain, EmailHash, Flags, LedgerEntryType, MessageKey,
|
||||||
|
OwnerCount, PreviousTxnID, PreviousTxnLgrSeq, RegularKey, Sequence, TicketCount, TransferRate,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn test_float_from_wasm() {
|
||||||
|
let _ = trace("\n$$$ test_float_from_wasm $$$");
|
||||||
|
|
||||||
|
let mut f: [u8; 8] = [0u8; 8];
|
||||||
|
if 8 == unsafe { float_from_int(12300, f.as_mut_ptr(), 8, FLOAT_ROUNDING_MODES_TO_NEAREST) } {
|
||||||
|
let _ = trace_float(" float from i64 12300:", &f);
|
||||||
|
let _ = trace_data(" float from i64 12300 as HEX:", &f, AsHex);
|
||||||
|
} else {
|
||||||
|
let _ = trace(" float from i64 12300: failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
let u64_value: u64 = 12300;
|
||||||
|
if 8 == unsafe {
|
||||||
|
float_from_uint(
|
||||||
|
&u64_value as *const u64 as *const u8,
|
||||||
|
8,
|
||||||
|
f.as_mut_ptr(),
|
||||||
|
8,
|
||||||
|
FLOAT_ROUNDING_MODES_TO_NEAREST,
|
||||||
|
)
|
||||||
|
} {
|
||||||
|
let _ = trace_float(" float from u64 12300:", &f);
|
||||||
|
} else {
|
||||||
|
let _ = trace(" float from u64 12300: failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
if 8 == unsafe { float_set(2, 123, f.as_mut_ptr(), 8, FLOAT_ROUNDING_MODES_TO_NEAREST) } {
|
||||||
|
let _ = trace_float(" float from exp 2, mantissa 123:", &f);
|
||||||
|
} else {
|
||||||
|
let _ = trace(" float from exp 2, mantissa 3: failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = trace_float(" float from const 1:", &FLOAT_ONE);
|
||||||
|
let _ = trace_float(" float from const -1:", &FLOAT_NEGATIVE_ONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_float_compare() {
|
||||||
|
let _ = trace("\n$$$ test_float_compare $$$");
|
||||||
|
|
||||||
|
let mut f1: [u8; 8] = [0u8; 8];
|
||||||
|
if 8 != unsafe { float_from_int(1, f1.as_mut_ptr(), 8, FLOAT_ROUNDING_MODES_TO_NEAREST) } {
|
||||||
|
let _ = trace(" float from 1: failed");
|
||||||
|
} else {
|
||||||
|
let _ = trace_float(" float from 1:", &f1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if 0 == unsafe { float_compare(f1.as_ptr(), 8, FLOAT_ONE.as_ptr(), 8) } {
|
||||||
|
let _ = trace(" float from 1 == FLOAT_ONE");
|
||||||
|
} else {
|
||||||
|
let _ = trace(" float from 1 != FLOAT_ONE");
|
||||||
|
}
|
||||||
|
|
||||||
|
if 1 == unsafe { float_compare(f1.as_ptr(), 8, FLOAT_NEGATIVE_ONE.as_ptr(), 8) } {
|
||||||
|
let _ = trace(" float from 1 > FLOAT_NEGATIVE_ONE");
|
||||||
|
} else {
|
||||||
|
let _ = trace(" float from 1 !> FLOAT_NEGATIVE_ONE");
|
||||||
|
}
|
||||||
|
|
||||||
|
if 2 == unsafe { float_compare(FLOAT_NEGATIVE_ONE.as_ptr(), 8, f1.as_ptr(), 8) } {
|
||||||
|
let _ = trace(" FLOAT_NEGATIVE_ONE < float from 1");
|
||||||
|
} else {
|
||||||
|
let _ = trace(" FLOAT_NEGATIVE_ONE !< float from 1");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_float_add_subtract() {
|
||||||
|
let _ = trace("\n$$$ test_float_add_subtract $$$");
|
||||||
|
|
||||||
|
let mut f_compute: [u8; 8] = FLOAT_ONE;
|
||||||
|
for i in 0..9 {
|
||||||
|
unsafe {
|
||||||
|
float_add(
|
||||||
|
f_compute.as_ptr(),
|
||||||
|
8,
|
||||||
|
FLOAT_ONE.as_ptr(),
|
||||||
|
8,
|
||||||
|
f_compute.as_mut_ptr(),
|
||||||
|
8,
|
||||||
|
FLOAT_ROUNDING_MODES_TO_NEAREST,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
// let _ = trace_float(" float:", &f_compute);
|
||||||
|
}
|
||||||
|
let mut f10: [u8; 8] = [0u8; 8];
|
||||||
|
if 8 != unsafe { float_from_int(10, f10.as_mut_ptr(), 8, FLOAT_ROUNDING_MODES_TO_NEAREST) } {
|
||||||
|
// let _ = trace(" float from 10: failed");
|
||||||
|
}
|
||||||
|
if 0 == unsafe { float_compare(f10.as_ptr(), 8, f_compute.as_ptr(), 8) } {
|
||||||
|
let _ = trace(" repeated add: good");
|
||||||
|
} else {
|
||||||
|
let _ = trace(" repeated add: bad");
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 0..11 {
|
||||||
|
unsafe {
|
||||||
|
float_subtract(
|
||||||
|
f_compute.as_ptr(),
|
||||||
|
8,
|
||||||
|
FLOAT_ONE.as_ptr(),
|
||||||
|
8,
|
||||||
|
f_compute.as_mut_ptr(),
|
||||||
|
8,
|
||||||
|
FLOAT_ROUNDING_MODES_TO_NEAREST,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if 0 == unsafe { float_compare(f_compute.as_ptr(), 8, FLOAT_NEGATIVE_ONE.as_ptr(), 8) } {
|
||||||
|
let _ = trace(" repeated subtract: good");
|
||||||
|
} else {
|
||||||
|
let _ = trace(" repeated subtract: bad");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_float_multiply_divide() {
|
||||||
|
let _ = trace("\n$$$ test_float_multiply_divide $$$");
|
||||||
|
|
||||||
|
let mut f10: [u8; 8] = [0u8; 8];
|
||||||
|
unsafe { float_from_int(10, f10.as_mut_ptr(), 8, FLOAT_ROUNDING_MODES_TO_NEAREST) };
|
||||||
|
let mut f_compute: [u8; 8] = FLOAT_ONE;
|
||||||
|
for i in 0..6 {
|
||||||
|
unsafe {
|
||||||
|
float_multiply(
|
||||||
|
f_compute.as_ptr(),
|
||||||
|
8,
|
||||||
|
f10.as_ptr(),
|
||||||
|
8,
|
||||||
|
f_compute.as_mut_ptr(),
|
||||||
|
8,
|
||||||
|
FLOAT_ROUNDING_MODES_TO_NEAREST,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
// let _ = trace_float(" float:", &f_compute);
|
||||||
|
}
|
||||||
|
let mut f1000000: [u8; 8] = [0u8; 8];
|
||||||
|
unsafe {
|
||||||
|
float_from_int(
|
||||||
|
1000000,
|
||||||
|
f1000000.as_mut_ptr(),
|
||||||
|
8,
|
||||||
|
FLOAT_ROUNDING_MODES_TO_NEAREST,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
if 0 == unsafe { float_compare(f1000000.as_ptr(), 8, f_compute.as_ptr(), 8) } {
|
||||||
|
let _ = trace(" repeated multiply: good");
|
||||||
|
} else {
|
||||||
|
let _ = trace(" repeated multiply: bad");
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 0..7 {
|
||||||
|
unsafe {
|
||||||
|
float_divide(
|
||||||
|
f_compute.as_ptr(),
|
||||||
|
8,
|
||||||
|
f10.as_ptr(),
|
||||||
|
8,
|
||||||
|
f_compute.as_mut_ptr(),
|
||||||
|
8,
|
||||||
|
FLOAT_ROUNDING_MODES_TO_NEAREST,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
let mut f01: [u8; 8] = [0u8; 8];
|
||||||
|
unsafe { float_set(-1, 1, f01.as_mut_ptr(), 8, FLOAT_ROUNDING_MODES_TO_NEAREST) };
|
||||||
|
|
||||||
|
if 0 == unsafe { float_compare(f_compute.as_ptr(), 8, f01.as_ptr(), 8) } {
|
||||||
|
let _ = trace(" repeated divide: good");
|
||||||
|
} else {
|
||||||
|
let _ = trace(" repeated divide: bad");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_float_pow() {
|
||||||
|
let _ = trace("\n$$$ test_float_pow $$$");
|
||||||
|
|
||||||
|
let mut f_compute: [u8; 8] = [0u8; 8];
|
||||||
|
unsafe {
|
||||||
|
float_pow(
|
||||||
|
FLOAT_ONE.as_ptr(),
|
||||||
|
8,
|
||||||
|
3,
|
||||||
|
f_compute.as_mut_ptr(),
|
||||||
|
8,
|
||||||
|
FLOAT_ROUNDING_MODES_TO_NEAREST,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
let _ = trace_float(" float cube of 1:", &f_compute);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
float_pow(
|
||||||
|
FLOAT_NEGATIVE_ONE.as_ptr(),
|
||||||
|
8,
|
||||||
|
6,
|
||||||
|
f_compute.as_mut_ptr(),
|
||||||
|
8,
|
||||||
|
FLOAT_ROUNDING_MODES_TO_NEAREST,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
let _ = trace_float(" float 6th power of -1:", &f_compute);
|
||||||
|
|
||||||
|
let mut f9: [u8; 8] = [0u8; 8];
|
||||||
|
unsafe { float_from_int(9, f9.as_mut_ptr(), 8, FLOAT_ROUNDING_MODES_TO_NEAREST) };
|
||||||
|
unsafe {
|
||||||
|
float_pow(
|
||||||
|
f9.as_ptr(),
|
||||||
|
8,
|
||||||
|
2,
|
||||||
|
f_compute.as_mut_ptr(),
|
||||||
|
8,
|
||||||
|
FLOAT_ROUNDING_MODES_TO_NEAREST,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
let _ = trace_float(" float square of 9:", &f_compute);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
float_pow(
|
||||||
|
f9.as_ptr(),
|
||||||
|
8,
|
||||||
|
0,
|
||||||
|
f_compute.as_mut_ptr(),
|
||||||
|
8,
|
||||||
|
FLOAT_ROUNDING_MODES_TO_NEAREST,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
let _ = trace_float(" float 0th power of 9:", &f_compute);
|
||||||
|
|
||||||
|
let mut f0: [u8; 8] = [0u8; 8];
|
||||||
|
unsafe { float_from_int(0, f0.as_mut_ptr(), 8, FLOAT_ROUNDING_MODES_TO_NEAREST) };
|
||||||
|
unsafe {
|
||||||
|
float_pow(
|
||||||
|
f0.as_ptr(),
|
||||||
|
8,
|
||||||
|
2,
|
||||||
|
f_compute.as_mut_ptr(),
|
||||||
|
8,
|
||||||
|
FLOAT_ROUNDING_MODES_TO_NEAREST,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
let _ = trace_float(" float square of 0:", &f_compute);
|
||||||
|
|
||||||
|
let r = unsafe {
|
||||||
|
float_pow(
|
||||||
|
f0.as_ptr(),
|
||||||
|
8,
|
||||||
|
0,
|
||||||
|
f_compute.as_mut_ptr(),
|
||||||
|
8,
|
||||||
|
FLOAT_ROUNDING_MODES_TO_NEAREST,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
let _ = trace_num(
|
||||||
|
" float 0th power of 0 (expecting INVALID_PARAMS error):",
|
||||||
|
r as i64,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_float_root() {
|
||||||
|
let _ = trace("\n$$$ test_float_root $$$");
|
||||||
|
|
||||||
|
let mut f9: [u8; 8] = [0u8; 8];
|
||||||
|
unsafe { float_from_int(9, f9.as_mut_ptr(), 8, FLOAT_ROUNDING_MODES_TO_NEAREST) };
|
||||||
|
let mut f_compute: [u8; 8] = [0u8; 8];
|
||||||
|
unsafe {
|
||||||
|
float_root(
|
||||||
|
f9.as_ptr(),
|
||||||
|
8,
|
||||||
|
2,
|
||||||
|
f_compute.as_mut_ptr(),
|
||||||
|
8,
|
||||||
|
FLOAT_ROUNDING_MODES_TO_NEAREST,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
let _ = trace_float(" float sqrt of 9:", &f_compute);
|
||||||
|
unsafe {
|
||||||
|
float_root(
|
||||||
|
f9.as_ptr(),
|
||||||
|
8,
|
||||||
|
3,
|
||||||
|
f_compute.as_mut_ptr(),
|
||||||
|
8,
|
||||||
|
FLOAT_ROUNDING_MODES_TO_NEAREST,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
let _ = trace_float(" float cbrt of 9:", &f_compute);
|
||||||
|
|
||||||
|
let mut f1000000: [u8; 8] = [0u8; 8];
|
||||||
|
unsafe {
|
||||||
|
float_from_int(
|
||||||
|
1000000,
|
||||||
|
f1000000.as_mut_ptr(),
|
||||||
|
8,
|
||||||
|
FLOAT_ROUNDING_MODES_TO_NEAREST,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
unsafe {
|
||||||
|
float_root(
|
||||||
|
f1000000.as_ptr(),
|
||||||
|
8,
|
||||||
|
3,
|
||||||
|
f_compute.as_mut_ptr(),
|
||||||
|
8,
|
||||||
|
FLOAT_ROUNDING_MODES_TO_NEAREST,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
let _ = trace_float(" float cbrt of 1000000:", &f_compute);
|
||||||
|
unsafe {
|
||||||
|
float_root(
|
||||||
|
f1000000.as_ptr(),
|
||||||
|
8,
|
||||||
|
6,
|
||||||
|
f_compute.as_mut_ptr(),
|
||||||
|
8,
|
||||||
|
FLOAT_ROUNDING_MODES_TO_NEAREST,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
let _ = trace_float(" float 6th root of 1000000:", &f_compute);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_float_log() {
|
||||||
|
let _ = trace("\n$$$ test_float_log $$$");
|
||||||
|
|
||||||
|
let mut f1000000: [u8; 8] = [0u8; 8];
|
||||||
|
unsafe {
|
||||||
|
float_from_int(
|
||||||
|
1000000,
|
||||||
|
f1000000.as_mut_ptr(),
|
||||||
|
8,
|
||||||
|
FLOAT_ROUNDING_MODES_TO_NEAREST,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
let mut f_compute: [u8; 8] = [0u8; 8];
|
||||||
|
unsafe {
|
||||||
|
float_log(
|
||||||
|
f1000000.as_ptr(),
|
||||||
|
8,
|
||||||
|
f_compute.as_mut_ptr(),
|
||||||
|
8,
|
||||||
|
FLOAT_ROUNDING_MODES_TO_NEAREST,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
let _ = trace_float(" log_10 of 1000000:", &f_compute);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_float_negate() {
|
||||||
|
let _ = trace("\n$$$ test_float_negate $$$");
|
||||||
|
|
||||||
|
let mut f_compute: [u8; 8] = [0u8; 8];
|
||||||
|
unsafe {
|
||||||
|
float_multiply(
|
||||||
|
FLOAT_ONE.as_ptr(),
|
||||||
|
8,
|
||||||
|
FLOAT_NEGATIVE_ONE.as_ptr(),
|
||||||
|
8,
|
||||||
|
f_compute.as_mut_ptr(),
|
||||||
|
8,
|
||||||
|
FLOAT_ROUNDING_MODES_TO_NEAREST,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
// let _ = trace_float(" float:", &f_compute);
|
||||||
|
if 0 == unsafe { float_compare(FLOAT_NEGATIVE_ONE.as_ptr(), 8, f_compute.as_ptr(), 8) } {
|
||||||
|
let _ = trace(" negate const 1: good");
|
||||||
|
} else {
|
||||||
|
let _ = trace(" negate const 1: bad");
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
float_multiply(
|
||||||
|
FLOAT_NEGATIVE_ONE.as_ptr(),
|
||||||
|
8,
|
||||||
|
FLOAT_NEGATIVE_ONE.as_ptr(),
|
||||||
|
8,
|
||||||
|
f_compute.as_mut_ptr(),
|
||||||
|
8,
|
||||||
|
FLOAT_ROUNDING_MODES_TO_NEAREST,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
// let _ = trace_float(" float:", &f_compute);
|
||||||
|
if 0 == unsafe { float_compare(FLOAT_ONE.as_ptr(), 8, f_compute.as_ptr(), 8) } {
|
||||||
|
let _ = trace(" negate const -1: good");
|
||||||
|
} else {
|
||||||
|
let _ = trace(" negate const -1: bad");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_float_invert() {
|
||||||
|
let _ = trace("\n$$$ test_float_invert $$$");
|
||||||
|
|
||||||
|
let mut f_compute: [u8; 8] = [0u8; 8];
|
||||||
|
let mut f10: [u8; 8] = [0u8; 8];
|
||||||
|
unsafe { float_from_int(10, f10.as_mut_ptr(), 8, FLOAT_ROUNDING_MODES_TO_NEAREST) };
|
||||||
|
unsafe {
|
||||||
|
float_divide(
|
||||||
|
FLOAT_ONE.as_ptr(),
|
||||||
|
8,
|
||||||
|
f10.as_ptr(),
|
||||||
|
8,
|
||||||
|
f_compute.as_mut_ptr(),
|
||||||
|
8,
|
||||||
|
FLOAT_ROUNDING_MODES_TO_NEAREST,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
let _ = trace_float(" invert a float from 10:", &f_compute);
|
||||||
|
unsafe {
|
||||||
|
float_divide(
|
||||||
|
FLOAT_ONE.as_ptr(),
|
||||||
|
8,
|
||||||
|
f_compute.as_ptr(),
|
||||||
|
8,
|
||||||
|
f_compute.as_mut_ptr(),
|
||||||
|
8,
|
||||||
|
FLOAT_ROUNDING_MODES_TO_NEAREST,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
let _ = trace_float(" invert again:", &f_compute);
|
||||||
|
|
||||||
|
// if f10's value is 7, then invert twice won't match the original value
|
||||||
|
if 0 == unsafe { float_compare(f10.as_ptr(), 8, f_compute.as_ptr(), 8) } {
|
||||||
|
let _ = trace(" invert twice: good");
|
||||||
|
} else {
|
||||||
|
let _ = trace(" invert twice: bad");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub extern "C" fn finish() -> i32 {
|
||||||
|
test_float_from_wasm();
|
||||||
|
test_float_compare();
|
||||||
|
test_float_add_subtract();
|
||||||
|
test_float_multiply_divide();
|
||||||
|
test_float_pow();
|
||||||
|
test_float_root();
|
||||||
|
test_float_log();
|
||||||
|
test_float_negate();
|
||||||
|
test_float_invert();
|
||||||
|
|
||||||
|
1
|
||||||
|
}
|
||||||
27
src/test/app/wasm_fixtures/ledgerSqn.c
Normal file
27
src/test/app/wasm_fixtures/ledgerSqn.c
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
int32_t
|
||||||
|
get_ledger_sqn();
|
||||||
|
// int32_t trace(uint8_t const*, int32_t, uint8_t const*, int32_t, int32_t);
|
||||||
|
// int32_t trace_num(uint8_t const*, int32_t, int64_t);
|
||||||
|
|
||||||
|
// uint8_t buf[1024];
|
||||||
|
|
||||||
|
// char const test_res[] = "sqn: ";
|
||||||
|
// char const test_name[] = "TEST get_ledger_sqn";
|
||||||
|
|
||||||
|
int
|
||||||
|
finish()
|
||||||
|
{
|
||||||
|
// trace((uint8_t const *)test_name, sizeof(test_name) - 1, 0, 0, 0);
|
||||||
|
|
||||||
|
// memset(buf, 0, sizeof(buf));
|
||||||
|
// for(int i = 0; i < sizeof(buf); ++i) buf[i] = 0;
|
||||||
|
|
||||||
|
int x = get_ledger_sqn();
|
||||||
|
// if (x >= 0)
|
||||||
|
// x = *((int32_t*)buf);
|
||||||
|
// trace_num((uint8_t const *)test`_res, sizeof(test_res) - 1, x);
|
||||||
|
|
||||||
|
return x < 0 ? x : (x >= 5 ? x : 0);
|
||||||
|
}
|
||||||
145
src/test/app/wasm_fixtures/sha512Pure.c
Normal file
145
src/test/app/wasm_fixtures/sha512Pure.c
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
static uint64_t const K512[] = {
|
||||||
|
0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f,
|
||||||
|
0xe9b5dba58189dbbc, 0x3956c25bf348b538, 0x59f111f1b605d019,
|
||||||
|
0x923f82a4af194f9b, 0xab1c5ed5da6d8118, 0xd807aa98a3030242,
|
||||||
|
0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2,
|
||||||
|
0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235,
|
||||||
|
0xc19bf174cf692694, 0xe49b69c19ef14ad2, 0xefbe4786384f25e3,
|
||||||
|
0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65, 0x2de92c6f592b0275,
|
||||||
|
0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5,
|
||||||
|
0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f,
|
||||||
|
0xbf597fc7beef0ee4, 0xc6e00bf33da88fc2, 0xd5a79147930aa725,
|
||||||
|
0x06ca6351e003826f, 0x142929670a0e6e70, 0x27b70a8546d22ffc,
|
||||||
|
0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df,
|
||||||
|
0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6,
|
||||||
|
0x92722c851482353b, 0xa2bfe8a14cf10364, 0xa81a664bbc423001,
|
||||||
|
0xc24b8b70d0f89791, 0xc76c51a30654be30, 0xd192e819d6ef5218,
|
||||||
|
0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8,
|
||||||
|
0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99,
|
||||||
|
0x34b0bcb5e19b48a8, 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb,
|
||||||
|
0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3, 0x748f82ee5defb2fc,
|
||||||
|
0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec,
|
||||||
|
0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915,
|
||||||
|
0xc67178f2e372532b, 0xca273eceea26619c, 0xd186b8c721c0c207,
|
||||||
|
0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, 0x06f067aa72176fba,
|
||||||
|
0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b,
|
||||||
|
0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc,
|
||||||
|
0x431d67c49c100d4c, 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a,
|
||||||
|
0x5fcb6fab3ad6faec, 0x6c44198c4a475817};
|
||||||
|
|
||||||
|
#define ROTATE(x, y) (((x) >> (y)) | ((x) << (64 - (y))))
|
||||||
|
#define Sigma0(x) (ROTATE((x), 28) ^ ROTATE((x), 34) ^ ROTATE((x), 39))
|
||||||
|
#define Sigma1(x) (ROTATE((x), 14) ^ ROTATE((x), 18) ^ ROTATE((x), 41))
|
||||||
|
#define sigma0(x) (ROTATE((x), 1) ^ ROTATE((x), 8) ^ ((x) >> 7))
|
||||||
|
#define sigma1(x) (ROTATE((x), 19) ^ ROTATE((x), 61) ^ ((x) >> 6))
|
||||||
|
|
||||||
|
#define Ch(x, y, z) (((x) & (y)) ^ ((~(x)) & (z)))
|
||||||
|
#define Maj(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
|
||||||
|
|
||||||
|
static inline uint64_t
|
||||||
|
B2U64(uint8_t val, uint8_t sh)
|
||||||
|
{
|
||||||
|
return ((uint64_t)val) << sh;
|
||||||
|
}
|
||||||
|
|
||||||
|
void*
|
||||||
|
allocate(int sz)
|
||||||
|
{
|
||||||
|
return malloc(sz);
|
||||||
|
}
|
||||||
|
void
|
||||||
|
deallocate(void* p)
|
||||||
|
{
|
||||||
|
free(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t e_data[32 * 1024];
|
||||||
|
|
||||||
|
uint8_t*
|
||||||
|
sha512_process(uint8_t const* data, int32_t length)
|
||||||
|
{
|
||||||
|
static uint64_t state[8] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||||
|
|
||||||
|
uint64_t a, b, c, d, e, f, g, h, s0, s1, T1, T2;
|
||||||
|
uint64_t X[16];
|
||||||
|
|
||||||
|
uint64_t blocks = length / 128;
|
||||||
|
while (blocks--)
|
||||||
|
{
|
||||||
|
a = state[0];
|
||||||
|
b = state[1];
|
||||||
|
c = state[2];
|
||||||
|
d = state[3];
|
||||||
|
e = state[4];
|
||||||
|
f = state[5];
|
||||||
|
g = state[6];
|
||||||
|
h = state[7];
|
||||||
|
|
||||||
|
unsigned i;
|
||||||
|
for (i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
X[i] = B2U64(data[0], 56) | B2U64(data[1], 48) |
|
||||||
|
B2U64(data[2], 40) | B2U64(data[3], 32) | B2U64(data[4], 24) |
|
||||||
|
B2U64(data[5], 16) | B2U64(data[6], 8) | B2U64(data[7], 0);
|
||||||
|
data += 8;
|
||||||
|
|
||||||
|
T1 = h;
|
||||||
|
T1 += Sigma1(e);
|
||||||
|
T1 += Ch(e, f, g);
|
||||||
|
T1 += K512[i];
|
||||||
|
T1 += X[i];
|
||||||
|
|
||||||
|
T2 = Sigma0(a);
|
||||||
|
T2 += Maj(a, b, c);
|
||||||
|
|
||||||
|
h = g;
|
||||||
|
g = f;
|
||||||
|
f = e;
|
||||||
|
e = d + T1;
|
||||||
|
d = c;
|
||||||
|
c = b;
|
||||||
|
b = a;
|
||||||
|
a = T1 + T2;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 16; i < 80; i++)
|
||||||
|
{
|
||||||
|
s0 = X[(i + 1) & 0x0f];
|
||||||
|
s0 = sigma0(s0);
|
||||||
|
s1 = X[(i + 14) & 0x0f];
|
||||||
|
s1 = sigma1(s1);
|
||||||
|
|
||||||
|
T1 = X[i & 0xf] += s0 + s1 + X[(i + 9) & 0xf];
|
||||||
|
T1 += h + Sigma1(e) + Ch(e, f, g) + K512[i];
|
||||||
|
T2 = Sigma0(a) + Maj(a, b, c);
|
||||||
|
|
||||||
|
h = g;
|
||||||
|
g = f;
|
||||||
|
f = e;
|
||||||
|
e = d + T1;
|
||||||
|
d = c;
|
||||||
|
c = b;
|
||||||
|
b = a;
|
||||||
|
a = T1 + T2;
|
||||||
|
}
|
||||||
|
|
||||||
|
state[0] += a;
|
||||||
|
state[1] += b;
|
||||||
|
state[2] += c;
|
||||||
|
state[3] += d;
|
||||||
|
state[4] += e;
|
||||||
|
state[5] += f;
|
||||||
|
state[6] += g;
|
||||||
|
state[7] += h;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (uint8_t*)(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
// int main ()
|
||||||
|
//{
|
||||||
|
// return 0;
|
||||||
|
// }
|
||||||
1384
src/test/app/wasm_fixtures/sp1/Cargo.lock
generated
Normal file
1384
src/test/app/wasm_fixtures/sp1/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
16
src/test/app/wasm_fixtures/sp1/Cargo.toml
Normal file
16
src/test/app/wasm_fixtures/sp1/Cargo.toml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
[package]
|
||||||
|
edition = "2021"
|
||||||
|
name = "sp1"
|
||||||
|
version = "0.0.1"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
sp1-verifier = "4.1.3"
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
opt-level = 3 # "z" for size or "3" for speed
|
||||||
|
lto = true # Link Time Optimization
|
||||||
|
codegen-units = 1 # Single unit = better optimization
|
||||||
|
panic = "abort" # Smaller binary, faster execution
|
||||||
37
src/test/app/wasm_fixtures/sp1/src/lib.rs
Normal file
37
src/test/app/wasm_fixtures/sp1/src/lib.rs
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
use sp1_verifier::Groth16Verifier;
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub fn sp1_groth16_verifier() -> bool {
|
||||||
|
let groth16_vk = *sp1_verifier::GROTH16_VK_BYTES;
|
||||||
|
|
||||||
|
let proof: Vec<u8> = vec![
|
||||||
|
17, 182, 160, 157, 31, 189, 116, 200, 17, 224, 230, 34, 195, 108, 230, 185, 62, 91, 181,
|
||||||
|
212, 80, 111, 197, 89, 247, 206, 99, 206, 147, 13, 216, 101, 252, 192, 149, 2, 40, 4, 249,
|
||||||
|
44, 97, 227, 127, 36, 244, 18, 27, 75, 248, 3, 45, 11, 103, 45, 183, 204, 61, 217, 19, 208,
|
||||||
|
66, 73, 202, 108, 136, 162, 221, 184, 6, 189, 49, 196, 104, 128, 151, 21, 104, 109, 145,
|
||||||
|
150, 243, 51, 27, 243, 203, 75, 176, 59, 193, 51, 177, 64, 83, 13, 133, 140, 248, 242, 13,
|
||||||
|
24, 12, 103, 126, 112, 244, 181, 129, 246, 52, 110, 134, 57, 149, 23, 163, 43, 202, 7, 164,
|
||||||
|
233, 179, 160, 16, 5, 22, 45, 129, 76, 183, 76, 150, 139, 27, 224, 191, 59, 47, 105, 71,
|
||||||
|
47, 8, 176, 157, 159, 234, 253, 239, 131, 138, 120, 101, 4, 98, 236, 106, 235, 98, 76, 93,
|
||||||
|
220, 174, 153, 58, 216, 28, 141, 129, 191, 188, 40, 184, 225, 22, 61, 75, 139, 159, 162,
|
||||||
|
117, 83, 214, 239, 1, 246, 236, 255, 64, 228, 116, 107, 206, 23, 59, 3, 221, 95, 14, 170,
|
||||||
|
28, 171, 36, 179, 75, 101, 177, 40, 198, 12, 193, 82, 105, 155, 177, 62, 158, 72, 209, 252,
|
||||||
|
51, 169, 109, 32, 121, 179, 194, 73, 164, 14, 8, 206, 181, 9, 5, 38, 74, 136, 97, 0, 89,
|
||||||
|
80, 75, 88, 228, 94, 46, 196, 199, 83, 229, 11, 103, 115, 25, 31, 215, 137, 65, 159, 95,
|
||||||
|
192,
|
||||||
|
];
|
||||||
|
|
||||||
|
let sp1_public_values = vec![
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 8,
|
||||||
|
];
|
||||||
|
|
||||||
|
let sp1_vkey_hash: String =
|
||||||
|
"0x00aea8e9c83c73d74036923de1b4a66d18547d58eee4eacfee70235ed291954c".to_string();
|
||||||
|
|
||||||
|
let _ = Groth16Verifier::verify(&proof, &sp1_public_values, &sp1_vkey_hash, groth16_vk);
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
106
src/test/app/wasm_fixtures/zk_proof/Cargo.lock
generated
Normal file
106
src/test/app/wasm_fixtures/zk_proof/Cargo.lock
generated
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitvec"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c"
|
||||||
|
dependencies = [
|
||||||
|
"funty",
|
||||||
|
"radium",
|
||||||
|
"tap",
|
||||||
|
"wyz",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bls12_381"
|
||||||
|
version = "0.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d7bc6d6292be3a19e6379786dac800f551e5865a5bb51ebbe3064ab80433f403"
|
||||||
|
dependencies = [
|
||||||
|
"ff",
|
||||||
|
"group",
|
||||||
|
"pairing",
|
||||||
|
"rand_core",
|
||||||
|
"subtle",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ff"
|
||||||
|
version = "0.13.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393"
|
||||||
|
dependencies = [
|
||||||
|
"bitvec",
|
||||||
|
"rand_core",
|
||||||
|
"subtle",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "funty"
|
||||||
|
version = "2.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "group"
|
||||||
|
version = "0.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63"
|
||||||
|
dependencies = [
|
||||||
|
"ff",
|
||||||
|
"rand_core",
|
||||||
|
"subtle",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pairing"
|
||||||
|
version = "0.23.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "81fec4625e73cf41ef4bb6846cafa6d44736525f442ba45e407c4a000a13996f"
|
||||||
|
dependencies = [
|
||||||
|
"group",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "radium"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.6.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "subtle"
|
||||||
|
version = "2.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tap"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wyz"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed"
|
||||||
|
dependencies = [
|
||||||
|
"tap",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zk_proof"
|
||||||
|
version = "0.0.1"
|
||||||
|
dependencies = [
|
||||||
|
"bls12_381",
|
||||||
|
"group",
|
||||||
|
]
|
||||||
19
src/test/app/wasm_fixtures/zk_proof/Cargo.toml
Normal file
19
src/test/app/wasm_fixtures/zk_proof/Cargo.toml
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
[package]
|
||||||
|
edition = "2021"
|
||||||
|
name = "zk_proof"
|
||||||
|
version = "0.0.1"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
# bellman = "=0.14.0"
|
||||||
|
bls12_381 = "=0.8.0"
|
||||||
|
group = "0.13.0"
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
# opt-level = 3 # Optimize for time
|
||||||
|
opt-level = "z" # Optimize for size
|
||||||
|
lto = true # Enable Link Time Optimization
|
||||||
|
codegen-units = 1
|
||||||
|
panic = "abort" # Remove unnecessary panic machinery
|
||||||
254
src/test/app/wasm_fixtures/zk_proof/src/lib.rs
Normal file
254
src/test/app/wasm_fixtures/zk_proof/src/lib.rs
Normal file
@@ -0,0 +1,254 @@
|
|||||||
|
use bls12_381::multi_miller_loop;
|
||||||
|
use bls12_381::Scalar;
|
||||||
|
use bls12_381::{G1Affine, G2Affine, G2Prepared};
|
||||||
|
use group::prime::PrimeCurveAffine;
|
||||||
|
use group::Curve;
|
||||||
|
|
||||||
|
use std::mem;
|
||||||
|
use std::os::raw::c_void;
|
||||||
|
// use std::time::{Instant};
|
||||||
|
|
||||||
|
// Groth16 proof struct
|
||||||
|
pub struct Proof {
|
||||||
|
pub a: G1Affine,
|
||||||
|
pub b: G2Affine,
|
||||||
|
pub c: G1Affine,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Groth16 verification key struct
|
||||||
|
pub struct VerifyingKey {
|
||||||
|
pub alpha_g1: G1Affine,
|
||||||
|
pub beta_g1: G1Affine,
|
||||||
|
pub beta_g2: G2Affine,
|
||||||
|
pub gamma_g2: G2Affine,
|
||||||
|
pub delta_g1: G1Affine,
|
||||||
|
pub delta_g2: G2Affine,
|
||||||
|
pub ic: Vec<G1Affine>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn allocate(size: usize) -> *mut c_void {
|
||||||
|
let mut buffer = Vec::with_capacity(size);
|
||||||
|
let pointer = buffer.as_mut_ptr();
|
||||||
|
mem::forget(buffer);
|
||||||
|
pointer as *mut c_void
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
fn deserialize_g1_wasm(buffer: &mut Vec<u8>) -> G1Affine {
|
||||||
|
let d_g1 = G1Affine::from_compressed(&buffer[0..48].try_into().unwrap())
|
||||||
|
.expect("Failed to deserialize vk");
|
||||||
|
|
||||||
|
d_g1
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize_g2_wasm(buffer: &mut Vec<u8>) -> G2Affine {
|
||||||
|
let d_g2 = G2Affine::from_compressed(&buffer[0..96].try_into().unwrap())
|
||||||
|
.expect("Failed to deserialize vk");
|
||||||
|
|
||||||
|
d_g2
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
// pub extern fn bellman_groth16_test(pointer: *mut u8, capacity: usize) -> bool {
|
||||||
|
pub extern "C" fn bellman_groth16_test() -> bool {
|
||||||
|
// let mut bytes = Vec::new();
|
||||||
|
// unsafe {
|
||||||
|
// // println!("Test in vm {:?}", pointer);
|
||||||
|
// let v = Vec::from_raw_parts(pointer, capacity, capacity); //TODO no need to deallocate??
|
||||||
|
// bytes.extend_from_slice(&v);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Hardcode the input bytes for testing in different WASM VMs
|
||||||
|
// let bytes = [172, 197, 81, 189, 121, 193, 159, 27, 92, 95, 151, 164, 40, 59, 214, 96, 132, 58, 87, 37, 169, 1, 63, 230, 35, 74, 245, 6, 185, 56, 120, 108, 214, 179, 187, 21, 36, 206, 43, 160, 10, 250, 249, 73, 210, 35, 137, 87, 177, 66, 65, 154, 11, 232, 137, 246, 125, 72, 227, 222, 116, 168, 87, 24, 165, 160, 132, 109, 108, 101, 222, 143, 78, 97, 48, 95, 59, 177, 29, 247, 219, 166, 73, 249, 69, 206, 15, 151, 30, 248, 235, 63, 148, 240, 17, 22, 150, 67, 252, 141, 95, 179, 94, 111, 207, 201, 192, 144, 154, 94, 21, 2, 22, 58, 96, 144, 227, 107, 107, 182, 142, 0, 57, 27, 168, 39, 226, 40, 163, 159, 112, 83, 196, 182, 215, 74, 92, 20, 158, 60, 23, 184, 198, 143, 17, 6, 242, 7, 75, 220, 87, 47, 224, 145, 99, 169, 203, 218, 112, 185, 51, 102, 59, 56, 171, 46, 49, 255, 116, 108, 241, 50, 180, 247, 62, 218, 181, 197, 155, 80, 61, 252, 8, 41, 232, 73, 51, 250, 223, 82, 94, 8, 185, 83, 223, 187, 6, 41, 20, 62, 189, 254, 11, 11, 58, 187, 200, 88, 53, 234, 98, 172, 213, 62, 22, 34, 90, 166, 182, 133, 8, 230, 103, 219, 233, 141, 10, 137, 210, 151, 4, 129, 29, 92, 103, 251, 72, 182, 162, 59, 20, 222, 188, 232, 13, 74, 214, 182, 172, 120, 33, 198, 57, 204, 134, 93, 26, 79, 213, 45, 146, 6, 128, 103, 63, 202, 226, 120, 141, 193, 248, 65, 196, 235, 21, 184, 104, 228, 206, 117, 190, 28, 153, 183, 68, 36, 63, 60, 131, 87, 137, 213, 105, 27, 110, 37, 238, 200, 250, 145, 76, 25, 57, 81, 69, 164, 208, 255, 49, 80, 14, 64, 181, 143, 12, 58, 35, 63, 199, 35, 70, 25, 86, 158, 210, 150, 59, 159, 253, 238, 174, 211, 142, 166, 223, 51, 134, 118, 171, 27, 218, 219, 117, 163, 71, 134, 95, 142, 83, 251, 240, 241, 162, 232, 93, 248, 167, 112, 197, 212, 169, 209, 159, 101, 140, 248, 222, 234, 201, 169, 76, 242, 7, 10, 192, 30, 151, 167, 74, 186, 97, 121, 144, 36, 6, 187, 92, 7, 248, 45, 134, 85, 240, 112, 74, 224, 70, 64, 198, 59, 26, 195, 192, 140, 101, 118, 175, 17, 160, 195, 142, 133, 1, 139, 5, 130, 245, 17, 73, 176, 232, 107, 130, 172, 110, 20, 190, 37, 108, 250, 178, 187, 151, 158, 35, 248, 246, 143, 38, 212, 133, 226, 24, 45, 33, 164, 46, 125, 200, 157, 253, 225, 132, 181, 60, 90, 7, 240, 80, 232, 97, 206, 164, 28, 12, 75, 68, 126, 230, 145, 216, 45, 180, 203, 19, 152, 29, 203, 9, 4, 145, 122, 206, 146, 179, 44, 145, 191, 126, 199, 175, 171, 127, 189, 222, 108, 126, 161, 80, 190, 47, 44, 8, 40, 65, 68, 95, 61, 109, 148, 175, 113, 226, 8, 93, 126, 53, 39, 192, 196, 6, 152, 194, 105, 169, 226, 192, 201, 184, 198, 134, 210, 153, 170, 12, 241, 90, 250, 233, 20, 152, 119, 142, 120, 83, 2, 164, 80, 178, 125, 227, 253, 207, 240, 201, 127, 213, 196, 100, 90, 65, 120, 50, 108, 175, 34, 192, 197, 173, 202, 176, 210, 131, 22, 216, 57, 169, 241, 28, 40, 44, 62, 11, 42, 50, 46, 204, 242, 109, 158, 114, 41, 127, 206, 25, 194, 255, 128, 245, 232, 193, 189, 229, 51, 93, 94, 64, 117, 33, 132, 75, 253, 114, 64, 116, 155, 183, 137, 112, 201, 243, 13, 221, 142, 164, 59, 98, 152, 249, 40, 133, 70, 185, 231, 249, 151, 253, 240, 122, 214, 60, 18, 132, 177, 37, 42, 75, 206, 12, 100, 214, 248, 234, 78, 165, 74, 212, 248, 32, 162, 254, 227, 218, 46, 9, 87, 0, 118, 13, 249, 107, 83, 5, 138, 223, 9, 247, 70, 160, 228, 197, 54, 87, 18, 1, 37, 199, 162, 84, 189, 161, 10, 26, 75, 45, 168, 185, 153, 245, 243, 51, 176, 208, 187, 235, 135, 239, 231, 42, 43, 233, 150, 46, 249, 73, 229, 138, 84, 89, 75, 129, 238, 211, 80, 147, 67, 159, 227, 214, 131, 188, 130, 70, 224, 1, 77, 139, 239, 185, 53, 68, 41, 193, 207, 16, 2, 33, 139, 214, 103, 240, 14, 141, 223, 24, 236, 50, 64, 79, 178, 6, 79, 38, 165, 35, 173, 203, 101, 3, 162, 49, 51, 4, 151, 127, 49, 47, 223, 244, 157, 229, 7, 88, 106, 141, 167, 183, 220, 15, 8, 119, 12, 82, 218, 14, 207, 0, 73, 27, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
||||||
|
let bytes = [
|
||||||
|
147, 235, 138, 182, 249, 146, 149, 28, 58, 36, 144, 99, 188, 155, 153, 135, 239, 79, 76,
|
||||||
|
109, 152, 156, 202, 1, 153, 84, 239, 184, 69, 145, 133, 48, 156, 80, 122, 227, 231, 161,
|
||||||
|
137, 232, 67, 183, 34, 186, 230, 135, 25, 90, 136, 201, 110, 134, 208, 93, 78, 82, 153,
|
||||||
|
239, 208, 236, 160, 231, 192, 150, 215, 128, 193, 255, 107, 39, 133, 12, 136, 148, 119, 17,
|
||||||
|
59, 198, 100, 49, 37, 89, 132, 205, 45, 79, 151, 112, 247, 140, 94, 179, 215, 165, 52, 182,
|
||||||
|
153, 68, 204, 210, 218, 156, 69, 74, 192, 30, 160, 13, 80, 188, 23, 112, 21, 124, 91, 147,
|
||||||
|
21, 140, 217, 226, 248, 60, 182, 119, 18, 34, 32, 41, 181, 128, 165, 97, 168, 76, 98, 44,
|
||||||
|
114, 122, 128, 215, 68, 156, 18, 91, 5, 33, 22, 141, 249, 137, 49, 252, 82, 122, 206, 58,
|
||||||
|
183, 108, 176, 15, 38, 183, 87, 254, 34, 102, 195, 78, 166, 227, 96, 180, 137, 173, 131,
|
||||||
|
178, 179, 25, 89, 159, 5, 73, 125, 24, 25, 86, 227, 19, 184, 117, 228, 173, 150, 1, 82,
|
||||||
|
142, 48, 251, 236, 132, 73, 79, 201, 165, 192, 191, 195, 60, 100, 198, 251, 187, 161, 220,
|
||||||
|
63, 143, 38, 21, 189, 219, 194, 100, 64, 186, 102, 7, 186, 213, 227, 92, 228, 52, 181, 171,
|
||||||
|
223, 222, 218, 206, 221, 22, 15, 46, 77, 175, 34, 43, 221, 110, 21, 89, 149, 213, 68, 242,
|
||||||
|
140, 185, 176, 73, 88, 216, 75, 237, 209, 10, 75, 251, 152, 101, 15, 146, 168, 27, 81, 8,
|
||||||
|
61, 76, 103, 230, 171, 23, 144, 171, 6, 118, 157, 233, 234, 214, 132, 106, 30, 171, 121,
|
||||||
|
77, 147, 175, 170, 62, 48, 251, 12, 221, 202, 109, 80, 97, 180, 27, 45, 87, 162, 19, 168,
|
||||||
|
152, 27, 205, 113, 91, 83, 52, 99, 109, 17, 149, 189, 244, 174, 164, 192, 79, 133, 111,
|
||||||
|
195, 215, 232, 129, 166, 204, 3, 169, 248, 49, 18, 190, 198, 145, 177, 169, 10, 4, 66, 134,
|
||||||
|
46, 11, 163, 170, 94, 230, 234, 234, 43, 122, 51, 230, 100, 106, 149, 228, 208, 217, 87,
|
||||||
|
231, 125, 170, 47, 143, 151, 45, 208, 64, 91, 10, 188, 136, 15, 155, 131, 200, 141, 243,
|
||||||
|
200, 5, 109, 22, 98, 189, 193, 44, 40, 95, 126, 145, 234, 190, 205, 179, 172, 224, 147,
|
||||||
|
253, 238, 162, 157, 60, 126, 9, 174, 34, 16, 161, 197, 60, 243, 211, 241, 78, 114, 51, 167,
|
||||||
|
214, 53, 149, 172, 56, 149, 32, 66, 123, 48, 240, 179, 53, 154, 29, 134, 34, 141, 204, 168,
|
||||||
|
184, 158, 165, 115, 241, 119, 228, 11, 35, 82, 186, 132, 103, 65, 243, 215, 31, 105, 201,
|
||||||
|
191, 155, 210, 53, 194, 76, 63, 199, 181, 28, 138, 181, 181, 211, 145, 15, 139, 244, 38,
|
||||||
|
56, 159, 161, 95, 46, 147, 141, 163, 221, 88, 167, 134, 73, 45, 70, 98, 98, 167, 55, 52,
|
||||||
|
234, 110, 150, 79, 248, 157, 167, 84, 210, 89, 10, 193, 169, 32, 40, 218, 7, 236, 206, 85,
|
||||||
|
178, 174, 157, 132, 181, 192, 119, 60, 205, 46, 217, 120, 97, 59, 82, 121, 11, 189, 21,
|
||||||
|
213, 176, 255, 225, 57, 76, 239, 38, 99, 226, 55, 98, 227, 10, 45, 193, 69, 255, 247, 39,
|
||||||
|
121, 86, 150, 6, 220, 98, 41, 132, 237, 189, 169, 110, 213, 115, 33, 228, 197, 61, 219,
|
||||||
|
202, 58, 54, 70, 223, 179, 208, 139, 232, 103, 76, 165, 169, 68, 6, 148, 47, 244, 26, 203,
|
||||||
|
186, 110, 69, 44, 175, 128, 119, 212, 188, 167, 223, 87, 119, 238, 199, 201, 61, 78, 96,
|
||||||
|
175, 0, 156, 145, 196, 253, 162, 175, 172, 227, 80, 251, 96, 61, 189, 35, 13, 97, 22, 157,
|
||||||
|
86, 249, 128, 148, 172, 66, 80, 172, 208, 222, 131, 0, 207, 80, 163, 27, 155, 113, 57, 186,
|
||||||
|
246, 139, 111, 71, 117, 152, 184, 60, 1, 230, 44, 169, 213, 88, 82, 156, 194, 234, 41, 183,
|
||||||
|
87, 36, 175, 154, 156, 128, 59, 187, 208, 101, 9, 51, 205, 42, 174, 29, 215, 43, 150, 183,
|
||||||
|
129, 125, 2, 84, 210, 149, 245, 126, 140, 166, 255, 134, 116, 162, 107, 82, 178, 158, 38,
|
||||||
|
11, 135, 91, 224, 157, 112, 189, 164, 250, 1, 215, 49, 21, 214, 211, 73, 243, 251, 58, 198,
|
||||||
|
1, 165, 196, 122, 13, 238, 252, 227, 229, 149, 47, 13, 173, 171, 176, 185, 220, 82, 96,
|
||||||
|
163, 4, 36, 199, 152, 88, 3, 162, 49, 51, 4, 151, 127, 49, 47, 223, 244, 157, 229, 7, 88,
|
||||||
|
106, 141, 167, 183, 220, 15, 8, 119, 12, 82, 218, 14, 207, 0, 73, 27, 5, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
];
|
||||||
|
|
||||||
|
// ***** Test deserialization and reconstruction of vk *****
|
||||||
|
// let start_key_recons = Instant::now();
|
||||||
|
// println!("Start verification key reconstruction");
|
||||||
|
|
||||||
|
// alpha_g1
|
||||||
|
let mut vec_alpha_g1 = bytes[0..48].to_vec();
|
||||||
|
let r_alpha_g1 = deserialize_g1_wasm(&mut vec_alpha_g1);
|
||||||
|
|
||||||
|
// beta_g1
|
||||||
|
let mut vec_beta_g1 = bytes[48..96].to_vec();
|
||||||
|
let r_beta_g1 = deserialize_g1_wasm(&mut vec_beta_g1);
|
||||||
|
|
||||||
|
// beta_g2
|
||||||
|
let mut vec_beta_g2 = bytes[96..192].to_vec();
|
||||||
|
let r_beta_g2 = deserialize_g2_wasm(&mut vec_beta_g2);
|
||||||
|
|
||||||
|
// gamma_g2
|
||||||
|
let mut vec_gamma_g2 = bytes[192..288].to_vec();
|
||||||
|
let r_gamma_g2 = deserialize_g2_wasm(&mut vec_gamma_g2);
|
||||||
|
|
||||||
|
// delta_g1
|
||||||
|
let mut vec_delta_g1 = bytes[288..336].to_vec();
|
||||||
|
let r_delta_g1 = deserialize_g1_wasm(&mut vec_delta_g1);
|
||||||
|
|
||||||
|
// delta_g2
|
||||||
|
let mut vec_delta_g2 = bytes[336..432].to_vec();
|
||||||
|
let r_delta_g2 = deserialize_g2_wasm(&mut vec_delta_g2);
|
||||||
|
|
||||||
|
// ic
|
||||||
|
let vec_ic = bytes[432..576].to_vec();
|
||||||
|
// println!("\nic vector: {:?}", vec_ic);
|
||||||
|
let mut r_ic: Vec<G1Affine> = Vec::new();
|
||||||
|
let mut vec_ic_de = vec_ic[0..48].to_vec();
|
||||||
|
r_ic.push(deserialize_g1_wasm(&mut vec_ic_de));
|
||||||
|
vec_ic_de = vec_ic[48..96].to_vec();
|
||||||
|
r_ic.push(deserialize_g1_wasm(&mut vec_ic_de));
|
||||||
|
vec_ic_de = vec_ic[96..144].to_vec();
|
||||||
|
r_ic.push(deserialize_g1_wasm(&mut vec_ic_de));
|
||||||
|
|
||||||
|
// Reconstruct vk
|
||||||
|
// replace following if using bellman::{groth16, groth16::Proof};
|
||||||
|
// let deserialized_vk = groth16::VerifyingKey::<Bls12> {
|
||||||
|
let deserialized_vk = VerifyingKey {
|
||||||
|
alpha_g1: r_alpha_g1,
|
||||||
|
beta_g1: r_beta_g1,
|
||||||
|
beta_g2: r_beta_g2,
|
||||||
|
gamma_g2: r_gamma_g2,
|
||||||
|
delta_g1: r_delta_g1,
|
||||||
|
delta_g2: r_delta_g2,
|
||||||
|
ic: r_ic,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Uncomment following if using bellman::{groth16, groth16::Proof};
|
||||||
|
// let pvk = groth16::prepare_verifying_key(&deserialized_vk);
|
||||||
|
// println!("Key reconstruction time: {:?}", start_key_recons.elapsed());
|
||||||
|
|
||||||
|
// ***** Reconstruct proof *****
|
||||||
|
// let start_proof_recons = Instant::now();
|
||||||
|
|
||||||
|
// proof.g1
|
||||||
|
let r_a = G1Affine::from_compressed(&bytes[576..624].try_into().unwrap())
|
||||||
|
.expect("Failed to deserialize a");
|
||||||
|
// proof.g2
|
||||||
|
let r_b = G2Affine::from_compressed(&bytes[624..720].try_into().unwrap())
|
||||||
|
.expect("Failed to deserialize b");
|
||||||
|
// proof.g1
|
||||||
|
let r_c = G1Affine::from_compressed(&bytes[720..768].try_into().unwrap())
|
||||||
|
.expect("Failed to deserialize c");
|
||||||
|
|
||||||
|
// Replace following if using bellman::{groth16, groth16::Proof};
|
||||||
|
// let r_proof: Proof<Bls12> = Proof{a: r_a, b: r_b, c: r_c};
|
||||||
|
let r_proof: Proof = Proof {
|
||||||
|
a: r_a,
|
||||||
|
b: r_b,
|
||||||
|
c: r_c,
|
||||||
|
};
|
||||||
|
// println!("Proof reconstruction time: {:?}", start_proof_recons.elapsed());
|
||||||
|
|
||||||
|
// ***** Reconstruct input *****
|
||||||
|
// let start_input_recons = Instant::now();
|
||||||
|
|
||||||
|
let last_64_bytes = &bytes[bytes.len() - 64..];
|
||||||
|
|
||||||
|
let r_inputs: Vec<Scalar> = last_64_bytes
|
||||||
|
.chunks(32) // Each Scalar in bls12_381 uses 32 bytes
|
||||||
|
.map(|chunk| {
|
||||||
|
Scalar::from_bytes(chunk.try_into().unwrap()).expect("Invalid bytes for Scalar")
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// println!("Input reconstruction time: {:?}", start_input_recons.elapsed());
|
||||||
|
|
||||||
|
/***** proof verification *****/
|
||||||
|
// uncomment following if bellman groth16 is used
|
||||||
|
// assert!(groth16::verify_proof(&pvk, &r_proof, &r_inputs).is_ok());
|
||||||
|
// let start_verify = Instant::now();
|
||||||
|
|
||||||
|
// Ensure the number of inputs matches the vk.ic length minus 1 (for IC[0])
|
||||||
|
if (r_inputs.len() + 1) != deserialized_vk.ic.len() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***** Compute linear combination: input_acc = IC[0] + sum(input[i] * IC[i+1]) *****/
|
||||||
|
let mut acc = deserialized_vk.ic[0].to_curve(); // Convert G1Affine to G1Projective
|
||||||
|
|
||||||
|
// Computes multi-scalar multiplication,
|
||||||
|
// which is a weighted sum of elliptic curve points.
|
||||||
|
// In Groth16, this builds the point:
|
||||||
|
// acc = IC₀ + input₁ × IC₁ + input₂ × IC₂ + ... + inputₙ × ICₙ
|
||||||
|
// Where: ICᵢ are fixed elliptic curve points (from the verifying key).
|
||||||
|
// inputᵢ are the public inputs to the circuit.
|
||||||
|
// Example: public_inputs = [x₁, x₂], vk.ic = [IC₀, IC₁, IC₂], acc = IC₀ + x₁ * IC₁ + x₂ * IC₂
|
||||||
|
// This binds the public inputs to the proof
|
||||||
|
for (input, ic_point) in r_inputs.iter().zip(&deserialized_vk.ic[1..]) {
|
||||||
|
acc += ic_point.to_curve() * input;
|
||||||
|
}
|
||||||
|
|
||||||
|
let acc_affine = acc.to_affine(); // converts the point acc from projective form back to affine form.
|
||||||
|
|
||||||
|
// Preparing G2 elements for pairing by converting them into G2Prepared format.
|
||||||
|
let proof_b_prepared = G2Prepared::from(r_proof.b);
|
||||||
|
let gamma_g2_prepared = G2Prepared::from(deserialized_vk.gamma_g2);
|
||||||
|
let delta_g2_prepared = G2Prepared::from(deserialized_vk.delta_g2);
|
||||||
|
let beta_g2_prepared = G2Prepared::from(deserialized_vk.beta_g2);
|
||||||
|
|
||||||
|
// Compute required product of pairings in their Miller loop form
|
||||||
|
// Groth16 verifier checks if e(A, B) * e(acc, γ)⁻¹ * e(C, δ)⁻¹ * e(α, β)⁻¹ == 1
|
||||||
|
// which boils down to
|
||||||
|
// let start_miller = Instant::now();
|
||||||
|
let ml_result = multi_miller_loop(&[
|
||||||
|
(&r_proof.a, &proof_b_prepared), // e(A,B)
|
||||||
|
(&(-acc_affine), &gamma_g2_prepared), // e(acc, γ)⁻¹
|
||||||
|
(&(-r_proof.c), &delta_g2_prepared), // e(C, δ)⁻¹
|
||||||
|
(&(-deserialized_vk.alpha_g1), &beta_g2_prepared), //e(α, β)⁻¹
|
||||||
|
]);
|
||||||
|
// println!("Miller time: {:?}", start_miller.elapsed());
|
||||||
|
|
||||||
|
// let start_final = Instant::now();
|
||||||
|
let result = ml_result.final_exponentiation();
|
||||||
|
// println!("Final time: {:?}", start_final.elapsed());
|
||||||
|
// println!("Proof verification time: {:?}", start_verify.elapsed());
|
||||||
|
|
||||||
|
// true
|
||||||
|
result == bls12_381::Gt::identity()
|
||||||
|
}
|
||||||
495
src/xrpld/app/wasm/HostFunc.h
Normal file
495
src/xrpld/app/wasm/HostFunc.h
Normal file
@@ -0,0 +1,495 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <xrpld/app/wasm/ParamsHelper.h>
|
||||||
|
|
||||||
|
#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>
|
||||||
|
|
||||||
|
namespace ripple {
|
||||||
|
|
||||||
|
enum class HostFunctionError : int32_t {
|
||||||
|
INTERNAL = -1,
|
||||||
|
FIELD_NOT_FOUND = -2,
|
||||||
|
BUFFER_TOO_SMALL = -3,
|
||||||
|
NO_ARRAY = -4,
|
||||||
|
NOT_LEAF_FIELD = -5,
|
||||||
|
LOCATOR_MALFORMED = -6,
|
||||||
|
SLOT_OUT_RANGE = -7,
|
||||||
|
SLOTS_FULL = -8,
|
||||||
|
EMPTY_SLOT = -9,
|
||||||
|
LEDGER_OBJ_NOT_FOUND = -10,
|
||||||
|
DECODING = -11,
|
||||||
|
DATA_FIELD_TOO_LARGE = -12,
|
||||||
|
POINTER_OUT_OF_BOUNDS = -13,
|
||||||
|
NO_MEM_EXPORTED = -14,
|
||||||
|
INVALID_PARAMS = -15,
|
||||||
|
INVALID_ACCOUNT = -16,
|
||||||
|
INVALID_FIELD = -17,
|
||||||
|
INDEX_OUT_OF_BOUNDS = -18,
|
||||||
|
FLOAT_INPUT_MALFORMED = -19,
|
||||||
|
FLOAT_COMPUTATION_ERROR = -20,
|
||||||
|
};
|
||||||
|
|
||||||
|
inline int32_t
|
||||||
|
HfErrorToInt(HostFunctionError e)
|
||||||
|
{
|
||||||
|
return static_cast<int32_t>(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
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>
|
||||||
|
floatSetImpl(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);
|
||||||
|
|
||||||
|
Expected<Bytes, HostFunctionError>
|
||||||
|
floatLogImpl(Slice const& x, int32_t mode);
|
||||||
|
|
||||||
|
struct HostFunctions
|
||||||
|
{
|
||||||
|
// LCOV_EXCL_START
|
||||||
|
virtual void
|
||||||
|
setRT(void const*)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void const*
|
||||||
|
getRT() const
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual beast::Journal
|
||||||
|
getJournal()
|
||||||
|
{
|
||||||
|
return beast::Journal{beast::Journal::getNullSink()};
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<std::int32_t, HostFunctionError>
|
||||||
|
getLedgerSqn()
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<std::int32_t, HostFunctionError>
|
||||||
|
getParentLedgerTime()
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<Hash, HostFunctionError>
|
||||||
|
getParentLedgerHash()
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<int32_t, HostFunctionError>
|
||||||
|
getBaseFee()
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<int32_t, HostFunctionError>
|
||||||
|
isAmendmentEnabled(uint256 const& amendmentId)
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<int32_t, HostFunctionError>
|
||||||
|
isAmendmentEnabled(std::string_view const& amendmentName)
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<Bytes, HostFunctionError>
|
||||||
|
getCurrentLedgerObjField(SField const& fname)
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<Bytes, HostFunctionError>
|
||||||
|
getLedgerObjField(int32_t cacheIdx, SField const& fname)
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<Bytes, HostFunctionError>
|
||||||
|
getTxNestedField(Slice const& locator)
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<Bytes, HostFunctionError>
|
||||||
|
getCurrentLedgerObjNestedField(Slice const& locator)
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<Bytes, HostFunctionError>
|
||||||
|
getLedgerObjNestedField(int32_t cacheIdx, Slice const& locator)
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<int32_t, HostFunctionError>
|
||||||
|
getTxArrayLen(SField const& fname)
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<int32_t, HostFunctionError>
|
||||||
|
getCurrentLedgerObjArrayLen(SField const& fname)
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<int32_t, HostFunctionError>
|
||||||
|
getLedgerObjArrayLen(int32_t cacheIdx, SField const& fname)
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<int32_t, HostFunctionError>
|
||||||
|
getTxNestedArrayLen(Slice const& locator)
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<int32_t, HostFunctionError>
|
||||||
|
getCurrentLedgerObjNestedArrayLen(Slice const& locator)
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<int32_t, HostFunctionError>
|
||||||
|
getLedgerObjNestedArrayLen(int32_t cacheIdx, Slice const& locator)
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<Hash, HostFunctionError>
|
||||||
|
computeSha512HalfHash(Slice const& data)
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<Bytes, HostFunctionError>
|
||||||
|
accountKeylet(AccountID const& account)
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<Bytes, HostFunctionError>
|
||||||
|
ammKeylet(Asset const& issue1, Asset const& issue2)
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<Bytes, HostFunctionError>
|
||||||
|
checkKeylet(AccountID const& account, std::uint32_t seq)
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<Bytes, HostFunctionError>
|
||||||
|
credentialKeylet(
|
||||||
|
AccountID const& subject,
|
||||||
|
AccountID const& issuer,
|
||||||
|
Slice const& credentialType)
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<Bytes, HostFunctionError>
|
||||||
|
didKeylet(AccountID const& account)
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<Bytes, HostFunctionError>
|
||||||
|
delegateKeylet(AccountID const& account, AccountID const& authorize)
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<Bytes, HostFunctionError>
|
||||||
|
depositPreauthKeylet(AccountID const& account, AccountID const& authorize)
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<Bytes, HostFunctionError>
|
||||||
|
escrowKeylet(AccountID const& account, std::uint32_t seq)
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<Bytes, HostFunctionError>
|
||||||
|
lineKeylet(
|
||||||
|
AccountID const& account1,
|
||||||
|
AccountID const& account2,
|
||||||
|
Currency const& currency)
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<Bytes, HostFunctionError>
|
||||||
|
mptIssuanceKeylet(AccountID const& issuer, std::uint32_t seq)
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<Bytes, HostFunctionError>
|
||||||
|
mptokenKeylet(MPTID const& mptid, AccountID const& holder)
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<Bytes, HostFunctionError>
|
||||||
|
nftOfferKeylet(AccountID const& account, std::uint32_t seq)
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<Bytes, HostFunctionError>
|
||||||
|
offerKeylet(AccountID const& account, std::uint32_t seq)
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<Bytes, HostFunctionError>
|
||||||
|
oracleKeylet(AccountID const& account, std::uint32_t docId)
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<Bytes, HostFunctionError>
|
||||||
|
paychanKeylet(
|
||||||
|
AccountID const& account,
|
||||||
|
AccountID const& destination,
|
||||||
|
std::uint32_t seq)
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<Bytes, HostFunctionError>
|
||||||
|
permissionedDomainKeylet(AccountID const& account, std::uint32_t seq)
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<Bytes, HostFunctionError>
|
||||||
|
signersKeylet(AccountID const& account)
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<Bytes, HostFunctionError>
|
||||||
|
ticketKeylet(AccountID const& account, std::uint32_t seq)
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<Bytes, HostFunctionError>
|
||||||
|
vaultKeylet(AccountID const& account, std::uint32_t seq)
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<Bytes, HostFunctionError>
|
||||||
|
getNFT(AccountID const& account, uint256 const& nftId)
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<Bytes, HostFunctionError>
|
||||||
|
getNFTIssuer(uint256 const& nftId)
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<std::uint32_t, HostFunctionError>
|
||||||
|
getNFTTaxon(uint256 const& nftId)
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<int32_t, HostFunctionError>
|
||||||
|
getNFTFlags(uint256 const& nftId)
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<int32_t, HostFunctionError>
|
||||||
|
getNFTTransferFee(uint256 const& nftId)
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<std::uint32_t, HostFunctionError>
|
||||||
|
getNFTSerial(uint256 const& nftId)
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<int32_t, HostFunctionError>
|
||||||
|
trace(std::string_view const& msg, Slice const& data, bool asHex)
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<int32_t, HostFunctionError>
|
||||||
|
traceNum(std::string_view const& msg, int64_t data)
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<int32_t, HostFunctionError>
|
||||||
|
traceAccount(std::string_view const& msg, AccountID const& account)
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<int32_t, HostFunctionError>
|
||||||
|
traceFloat(std::string_view const& msg, Slice const& data)
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<int32_t, HostFunctionError>
|
||||||
|
traceAmount(std::string_view const& msg, STAmount const& amount)
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<Bytes, HostFunctionError>
|
||||||
|
floatFromInt(int64_t x, int32_t mode)
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<Bytes, HostFunctionError>
|
||||||
|
floatFromUint(uint64_t x, int32_t mode)
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<Bytes, HostFunctionError>
|
||||||
|
floatSet(int64_t mantissa, int32_t exponent, int32_t mode)
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<int32_t, HostFunctionError>
|
||||||
|
floatCompare(Slice const& x, Slice const& y)
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<Bytes, HostFunctionError>
|
||||||
|
floatAdd(Slice const& x, Slice const& y, int32_t mode)
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<Bytes, HostFunctionError>
|
||||||
|
floatSubtract(Slice const& x, Slice const& y, int32_t mode)
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<Bytes, HostFunctionError>
|
||||||
|
floatMultiply(Slice const& x, Slice const& y, int32_t mode)
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<Bytes, HostFunctionError>
|
||||||
|
floatDivide(Slice const& x, Slice const& y, int32_t mode)
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<Bytes, HostFunctionError>
|
||||||
|
floatRoot(Slice const& x, int32_t n, int32_t mode)
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<Bytes, HostFunctionError>
|
||||||
|
floatPower(Slice const& x, int32_t n, int32_t mode)
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Expected<Bytes, HostFunctionError>
|
||||||
|
floatLog(Slice const& x, int32_t mode)
|
||||||
|
{
|
||||||
|
return Unexpected(HostFunctionError::INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~HostFunctions() = default;
|
||||||
|
// LCOV_EXCL_STOP
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ripple
|
||||||
280
src/xrpld/app/wasm/HostFuncImpl.h
Normal file
280
src/xrpld/app/wasm/HostFuncImpl.h
Normal file
@@ -0,0 +1,280 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <xrpld/app/tx/detail/ApplyContext.h>
|
||||||
|
#include <xrpld/app/wasm/HostFunc.h>
|
||||||
|
|
||||||
|
namespace ripple {
|
||||||
|
class WasmHostFunctionsImpl : public HostFunctions
|
||||||
|
{
|
||||||
|
ApplyContext& ctx;
|
||||||
|
Keylet leKey;
|
||||||
|
std::shared_ptr<SLE const> currentLedgerObj = nullptr;
|
||||||
|
bool isLedgerObjCached = false;
|
||||||
|
|
||||||
|
static int constexpr MAX_CACHE = 256;
|
||||||
|
std::array<std::shared_ptr<SLE const>, MAX_CACHE> cache;
|
||||||
|
std::optional<Bytes> data_;
|
||||||
|
|
||||||
|
void const* rt_ = nullptr;
|
||||||
|
|
||||||
|
Expected<std::shared_ptr<SLE const>, HostFunctionError>
|
||||||
|
getCurrentLedgerObj()
|
||||||
|
{
|
||||||
|
if (!isLedgerObjCached)
|
||||||
|
{
|
||||||
|
isLedgerObjCached = true;
|
||||||
|
currentLedgerObj = ctx.view().read(leKey);
|
||||||
|
}
|
||||||
|
if (currentLedgerObj)
|
||||||
|
return currentLedgerObj;
|
||||||
|
return Unexpected(HostFunctionError::LEDGER_OBJ_NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
Expected<int32_t, HostFunctionError>
|
||||||
|
normalizeCacheIndex(int32_t cacheIdx)
|
||||||
|
{
|
||||||
|
--cacheIdx;
|
||||||
|
if (cacheIdx < 0 || cacheIdx >= MAX_CACHE)
|
||||||
|
return Unexpected(HostFunctionError::SLOT_OUT_RANGE);
|
||||||
|
if (!cache[cacheIdx])
|
||||||
|
return Unexpected(HostFunctionError::EMPTY_SLOT);
|
||||||
|
return cacheIdx;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
WasmHostFunctionsImpl(ApplyContext& ctx, Keylet const& leKey)
|
||||||
|
: ctx(ctx), leKey(leKey)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void
|
||||||
|
setRT(void const* rt) override
|
||||||
|
{
|
||||||
|
rt_ = rt;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void const*
|
||||||
|
getRT() const override
|
||||||
|
{
|
||||||
|
return rt_;
|
||||||
|
}
|
||||||
|
|
||||||
|
beast::Journal
|
||||||
|
getJournal() override
|
||||||
|
{
|
||||||
|
return ctx.journal;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<Bytes> const&
|
||||||
|
getData() const
|
||||||
|
{
|
||||||
|
return data_;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expected<std::int32_t, HostFunctionError>
|
||||||
|
getLedgerSqn() override;
|
||||||
|
|
||||||
|
Expected<std::int32_t, HostFunctionError>
|
||||||
|
getParentLedgerTime() override;
|
||||||
|
|
||||||
|
Expected<Hash, HostFunctionError>
|
||||||
|
getParentLedgerHash() override;
|
||||||
|
|
||||||
|
Expected<int32_t, HostFunctionError>
|
||||||
|
getBaseFee() override;
|
||||||
|
|
||||||
|
Expected<int32_t, HostFunctionError>
|
||||||
|
isAmendmentEnabled(uint256 const& amendmentId) override;
|
||||||
|
|
||||||
|
Expected<int32_t, HostFunctionError>
|
||||||
|
isAmendmentEnabled(std::string_view const& amendmentName) override;
|
||||||
|
|
||||||
|
Expected<int32_t, HostFunctionError>
|
||||||
|
cacheLedgerObj(uint256 const& objId, int32_t cacheIdx) override;
|
||||||
|
|
||||||
|
Expected<Bytes, HostFunctionError>
|
||||||
|
getTxField(SField const& fname) override;
|
||||||
|
|
||||||
|
Expected<Bytes, HostFunctionError>
|
||||||
|
getCurrentLedgerObjField(SField const& fname) override;
|
||||||
|
|
||||||
|
Expected<Bytes, HostFunctionError>
|
||||||
|
getLedgerObjField(int32_t cacheIdx, SField const& fname) override;
|
||||||
|
|
||||||
|
Expected<Bytes, HostFunctionError>
|
||||||
|
getTxNestedField(Slice const& locator) override;
|
||||||
|
|
||||||
|
Expected<Bytes, HostFunctionError>
|
||||||
|
getCurrentLedgerObjNestedField(Slice const& locator) override;
|
||||||
|
|
||||||
|
Expected<Bytes, HostFunctionError>
|
||||||
|
getLedgerObjNestedField(int32_t cacheIdx, Slice const& locator) override;
|
||||||
|
|
||||||
|
Expected<int32_t, HostFunctionError>
|
||||||
|
getTxArrayLen(SField const& fname) override;
|
||||||
|
|
||||||
|
Expected<int32_t, HostFunctionError>
|
||||||
|
getCurrentLedgerObjArrayLen(SField const& fname) override;
|
||||||
|
|
||||||
|
Expected<int32_t, HostFunctionError>
|
||||||
|
getLedgerObjArrayLen(int32_t cacheIdx, SField const& fname) override;
|
||||||
|
|
||||||
|
Expected<int32_t, HostFunctionError>
|
||||||
|
getTxNestedArrayLen(Slice const& locator) override;
|
||||||
|
|
||||||
|
Expected<int32_t, HostFunctionError>
|
||||||
|
getCurrentLedgerObjNestedArrayLen(Slice const& locator) override;
|
||||||
|
|
||||||
|
Expected<int32_t, HostFunctionError>
|
||||||
|
getLedgerObjNestedArrayLen(int32_t cacheIdx, Slice const& locator) override;
|
||||||
|
|
||||||
|
Expected<int32_t, HostFunctionError>
|
||||||
|
updateData(Slice const& data) override;
|
||||||
|
|
||||||
|
Expected<int32_t, HostFunctionError>
|
||||||
|
checkSignature(
|
||||||
|
Slice const& message,
|
||||||
|
Slice const& signature,
|
||||||
|
Slice const& pubkey) override;
|
||||||
|
|
||||||
|
Expected<Hash, HostFunctionError>
|
||||||
|
computeSha512HalfHash(Slice const& data) override;
|
||||||
|
|
||||||
|
Expected<Bytes, HostFunctionError>
|
||||||
|
accountKeylet(AccountID const& account) override;
|
||||||
|
|
||||||
|
Expected<Bytes, HostFunctionError>
|
||||||
|
ammKeylet(Asset const& issue1, Asset const& issue2) override;
|
||||||
|
|
||||||
|
Expected<Bytes, HostFunctionError>
|
||||||
|
checkKeylet(AccountID const& account, std::uint32_t seq) override;
|
||||||
|
|
||||||
|
Expected<Bytes, HostFunctionError>
|
||||||
|
credentialKeylet(
|
||||||
|
AccountID const& subject,
|
||||||
|
AccountID const& issuer,
|
||||||
|
Slice const& credentialType) override;
|
||||||
|
|
||||||
|
Expected<Bytes, HostFunctionError>
|
||||||
|
didKeylet(AccountID const& account) override;
|
||||||
|
|
||||||
|
Expected<Bytes, HostFunctionError>
|
||||||
|
delegateKeylet(AccountID const& account, AccountID const& authorize)
|
||||||
|
override;
|
||||||
|
|
||||||
|
Expected<Bytes, HostFunctionError>
|
||||||
|
depositPreauthKeylet(AccountID const& account, AccountID const& authorize)
|
||||||
|
override;
|
||||||
|
|
||||||
|
Expected<Bytes, HostFunctionError>
|
||||||
|
escrowKeylet(AccountID const& account, std::uint32_t seq) override;
|
||||||
|
|
||||||
|
Expected<Bytes, HostFunctionError>
|
||||||
|
lineKeylet(
|
||||||
|
AccountID const& account1,
|
||||||
|
AccountID const& account2,
|
||||||
|
Currency const& currency) override;
|
||||||
|
|
||||||
|
Expected<Bytes, HostFunctionError>
|
||||||
|
mptIssuanceKeylet(AccountID const& issuer, std::uint32_t seq) override;
|
||||||
|
|
||||||
|
Expected<Bytes, HostFunctionError>
|
||||||
|
mptokenKeylet(MPTID const& mptid, AccountID const& holder) override;
|
||||||
|
|
||||||
|
Expected<Bytes, HostFunctionError>
|
||||||
|
nftOfferKeylet(AccountID const& account, std::uint32_t seq) override;
|
||||||
|
|
||||||
|
Expected<Bytes, HostFunctionError>
|
||||||
|
offerKeylet(AccountID const& account, std::uint32_t seq) override;
|
||||||
|
|
||||||
|
Expected<Bytes, HostFunctionError>
|
||||||
|
oracleKeylet(AccountID const& account, std::uint32_t docId) override;
|
||||||
|
|
||||||
|
Expected<Bytes, HostFunctionError>
|
||||||
|
paychanKeylet(
|
||||||
|
AccountID const& account,
|
||||||
|
AccountID const& destination,
|
||||||
|
std::uint32_t seq) override;
|
||||||
|
|
||||||
|
Expected<Bytes, HostFunctionError>
|
||||||
|
permissionedDomainKeylet(AccountID const& account, std::uint32_t seq)
|
||||||
|
override;
|
||||||
|
|
||||||
|
Expected<Bytes, HostFunctionError>
|
||||||
|
signersKeylet(AccountID const& account) override;
|
||||||
|
|
||||||
|
Expected<Bytes, HostFunctionError>
|
||||||
|
ticketKeylet(AccountID const& account, std::uint32_t seq) override;
|
||||||
|
|
||||||
|
Expected<Bytes, HostFunctionError>
|
||||||
|
vaultKeylet(AccountID const& account, std::uint32_t seq) override;
|
||||||
|
|
||||||
|
Expected<Bytes, HostFunctionError>
|
||||||
|
getNFT(AccountID const& account, uint256 const& nftId) override;
|
||||||
|
|
||||||
|
Expected<Bytes, HostFunctionError>
|
||||||
|
getNFTIssuer(uint256 const& nftId) override;
|
||||||
|
|
||||||
|
Expected<std::uint32_t, HostFunctionError>
|
||||||
|
getNFTTaxon(uint256 const& nftId) override;
|
||||||
|
|
||||||
|
Expected<int32_t, HostFunctionError>
|
||||||
|
getNFTFlags(uint256 const& nftId) override;
|
||||||
|
|
||||||
|
Expected<int32_t, HostFunctionError>
|
||||||
|
getNFTTransferFee(uint256 const& nftId) override;
|
||||||
|
|
||||||
|
Expected<std::uint32_t, HostFunctionError>
|
||||||
|
getNFTSerial(uint256 const& nftId) override;
|
||||||
|
|
||||||
|
Expected<int32_t, HostFunctionError>
|
||||||
|
trace(std::string_view const& msg, Slice const& data, bool asHex) override;
|
||||||
|
|
||||||
|
Expected<int32_t, HostFunctionError>
|
||||||
|
traceNum(std::string_view const& msg, int64_t data) override;
|
||||||
|
|
||||||
|
Expected<int32_t, HostFunctionError>
|
||||||
|
traceAccount(std::string_view const& msg, AccountID const& account)
|
||||||
|
override;
|
||||||
|
|
||||||
|
Expected<int32_t, HostFunctionError>
|
||||||
|
traceFloat(std::string_view const& msg, Slice const& data) override;
|
||||||
|
|
||||||
|
Expected<int32_t, HostFunctionError>
|
||||||
|
traceAmount(std::string_view const& msg, STAmount const& amount) override;
|
||||||
|
|
||||||
|
Expected<Bytes, HostFunctionError>
|
||||||
|
floatFromInt(int64_t x, int32_t mode) override;
|
||||||
|
|
||||||
|
Expected<Bytes, HostFunctionError>
|
||||||
|
floatFromUint(uint64_t x, int32_t mode) override;
|
||||||
|
|
||||||
|
Expected<Bytes, HostFunctionError>
|
||||||
|
floatSet(int64_t mantissa, int32_t exponent, int32_t mode) override;
|
||||||
|
|
||||||
|
Expected<int32_t, HostFunctionError>
|
||||||
|
floatCompare(Slice const& x, Slice const& y) override;
|
||||||
|
|
||||||
|
Expected<Bytes, HostFunctionError>
|
||||||
|
floatAdd(Slice const& x, Slice const& y, int32_t mode) override;
|
||||||
|
|
||||||
|
Expected<Bytes, HostFunctionError>
|
||||||
|
floatSubtract(Slice const& x, Slice const& y, int32_t mode) override;
|
||||||
|
|
||||||
|
Expected<Bytes, HostFunctionError>
|
||||||
|
floatMultiply(Slice const& x, Slice const& y, int32_t mode) override;
|
||||||
|
|
||||||
|
Expected<Bytes, HostFunctionError>
|
||||||
|
floatDivide(Slice const& x, Slice const& y, int32_t mode) override;
|
||||||
|
|
||||||
|
Expected<Bytes, HostFunctionError>
|
||||||
|
floatRoot(Slice const& x, int32_t n, int32_t mode) override;
|
||||||
|
|
||||||
|
Expected<Bytes, HostFunctionError>
|
||||||
|
floatPower(Slice const& x, int32_t n, int32_t mode) override;
|
||||||
|
|
||||||
|
Expected<Bytes, HostFunctionError>
|
||||||
|
floatLog(Slice const& x, int32_t mode) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ripple
|
||||||
534
src/xrpld/app/wasm/HostFuncWrapper.h
Normal file
534
src/xrpld/app/wasm/HostFuncWrapper.h
Normal file
@@ -0,0 +1,534 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <xrpld/app/wasm/WamrVM.h>
|
||||||
|
|
||||||
|
namespace ripple {
|
||||||
|
|
||||||
|
using getLedgerSqn_proto = int32_t();
|
||||||
|
wasm_trap_t*
|
||||||
|
getLedgerSqn_wrap(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using getParentLedgerTime_proto = int32_t();
|
||||||
|
wasm_trap_t*
|
||||||
|
getParentLedgerTime_wrap(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using getParentLedgerHash_proto = int32_t(uint8_t*, int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
getParentLedgerHash_wrap(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using getBaseFee_proto = int32_t();
|
||||||
|
wasm_trap_t*
|
||||||
|
getBaseFee_wrap(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using isAmendmentEnabled_proto = int32_t(uint8_t const*, int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
isAmendmentEnabled_wrap(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using cacheLedgerObj_proto = int32_t(uint8_t const*, int32_t, int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
cacheLedgerObj_wrap(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using getTxField_proto = int32_t(int32_t, uint8_t*, int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
getTxField_wrap(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using getCurrentLedgerObjField_proto = int32_t(int32_t, uint8_t*, int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
getCurrentLedgerObjField_wrap(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using getLedgerObjField_proto = int32_t(int32_t, int32_t, uint8_t*, int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
getLedgerObjField_wrap(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using getTxNestedField_proto =
|
||||||
|
int32_t(uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
getTxNestedField_wrap(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using getCurrentLedgerObjNestedField_proto =
|
||||||
|
int32_t(uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
getCurrentLedgerObjNestedField_wrap(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using getLedgerObjNestedField_proto =
|
||||||
|
int32_t(int32_t, uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
getLedgerObjNestedField_wrap(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using getTxArrayLen_proto = int32_t(int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
getTxArrayLen_wrap(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using getCurrentLedgerObjArrayLen_proto = int32_t(int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
getCurrentLedgerObjArrayLen_wrap(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using getLedgerObjArrayLen_proto = int32_t(int32_t, int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
getLedgerObjArrayLen_wrap(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using getTxNestedArrayLen_proto = int32_t(uint8_t const*, int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
getTxNestedArrayLen_wrap(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using getCurrentLedgerObjNestedArrayLen_proto =
|
||||||
|
int32_t(uint8_t const*, int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
getCurrentLedgerObjNestedArrayLen_wrap(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using getLedgerObjNestedArrayLen_proto =
|
||||||
|
int32_t(int32_t, uint8_t const*, int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
getLedgerObjNestedArrayLen_wrap(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using updateData_proto = int32_t(uint8_t const*, int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
updateData_wrap(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
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(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using computeSha512HalfHash_proto =
|
||||||
|
int32_t(uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
computeSha512HalfHash_wrap(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using accountKeylet_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
accountKeylet_wrap(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using ammKeylet_proto = int32_t(
|
||||||
|
uint8_t const*,
|
||||||
|
int32_t,
|
||||||
|
uint8_t const*,
|
||||||
|
int32_t,
|
||||||
|
uint8_t*,
|
||||||
|
int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
ammKeylet_wrap(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using checkKeylet_proto =
|
||||||
|
int32_t(uint8_t const*, int32_t, int32_t, uint8_t*, int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
checkKeylet_wrap(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
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(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using delegateKeylet_proto = int32_t(
|
||||||
|
uint8_t const*,
|
||||||
|
int32_t,
|
||||||
|
uint8_t const*,
|
||||||
|
int32_t,
|
||||||
|
uint8_t*,
|
||||||
|
int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
delegateKeylet_wrap(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using depositPreauthKeylet_proto = int32_t(
|
||||||
|
uint8_t const*,
|
||||||
|
int32_t,
|
||||||
|
uint8_t const*,
|
||||||
|
int32_t,
|
||||||
|
uint8_t*,
|
||||||
|
int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
depositPreauthKeylet_wrap(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using didKeylet_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
didKeylet_wrap(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using escrowKeylet_proto =
|
||||||
|
int32_t(uint8_t const*, int32_t, int32_t, uint8_t*, int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
escrowKeylet_wrap(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
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(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using mptIssuanceKeylet_proto =
|
||||||
|
int32_t(uint8_t const*, int32_t, int32_t, uint8_t*, int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
mptIssuanceKeylet_wrap(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using mptokenKeylet_proto = int32_t(
|
||||||
|
uint8_t const*,
|
||||||
|
int32_t,
|
||||||
|
uint8_t const*,
|
||||||
|
int32_t,
|
||||||
|
uint8_t*,
|
||||||
|
int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
mptokenKeylet_wrap(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using nftOfferKeylet_proto =
|
||||||
|
int32_t(uint8_t const*, int32_t, int32_t, uint8_t*, int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
nftOfferKeylet_wrap(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using offerKeylet_proto =
|
||||||
|
int32_t(uint8_t const*, int32_t, int32_t, uint8_t*, int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
offerKeylet_wrap(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using oracleKeylet_proto =
|
||||||
|
int32_t(uint8_t const*, int32_t, int32_t, uint8_t*, int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
oracleKeylet_wrap(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using paychanKeylet_proto = int32_t(
|
||||||
|
uint8_t const*,
|
||||||
|
int32_t,
|
||||||
|
uint8_t const*,
|
||||||
|
int32_t,
|
||||||
|
int32_t,
|
||||||
|
uint8_t*,
|
||||||
|
int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
paychanKeylet_wrap(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using permissionedDomainKeylet_proto =
|
||||||
|
int32_t(uint8_t const*, int32_t, int32_t, uint8_t*, int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
permissionedDomainKeylet_wrap(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using signersKeylet_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
signersKeylet_wrap(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using ticketKeylet_proto =
|
||||||
|
int32_t(uint8_t const*, int32_t, int32_t, uint8_t*, int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
ticketKeylet_wrap(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using vaultKeylet_proto =
|
||||||
|
int32_t(uint8_t const*, int32_t, int32_t, uint8_t*, int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
vaultKeylet_wrap(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using getNFT_proto = int32_t(
|
||||||
|
uint8_t const*,
|
||||||
|
int32_t,
|
||||||
|
uint8_t const*,
|
||||||
|
int32_t,
|
||||||
|
uint8_t*,
|
||||||
|
int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
getNFT_wrap(void* env, wasm_val_vec_t const* params, wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using getNFTIssuer_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
getNFTIssuer_wrap(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using getNFTTaxon_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
getNFTTaxon_wrap(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using getNFTFlags_proto = int32_t(uint8_t const*, int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
getNFTFlags_wrap(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using getNFTTransferFee_proto = int32_t(uint8_t const*, int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
getNFTTransferFee_wrap(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using getNFTSerial_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
getNFTSerial_wrap(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using trace_proto =
|
||||||
|
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
trace_wrap(void* env, wasm_val_vec_t const* params, wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using traceNum_proto = int32_t(uint8_t const*, int32_t, int64_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
traceNum_wrap(void* env, wasm_val_vec_t const* params, wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using traceAccount_proto =
|
||||||
|
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
traceAccount_wrap(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using traceFloat_proto =
|
||||||
|
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
traceFloat_wrap(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using traceAmount_proto =
|
||||||
|
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
traceAmount_wrap(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using floatFromInt_proto = int32_t(int64_t, uint8_t*, int32_t, int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
floatFromInt_wrap(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using floatFromUint_proto =
|
||||||
|
int32_t(uint8_t const*, int32_t, uint8_t*, int32_t, int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
floatFromUint_wrap(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using floatSet_proto = int32_t(int32_t, int64_t, uint8_t*, int32_t, int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
floatSet_wrap(void* env, wasm_val_vec_t const* params, wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using floatCompare_proto =
|
||||||
|
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
floatCompare_wrap(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
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(void* env, wasm_val_vec_t const* params, wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
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(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
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(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
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(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using floatRoot_proto =
|
||||||
|
int32_t(uint8_t const*, int32_t, int32_t, uint8_t*, int32_t, int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
floatRoot_wrap(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using floatPower_proto =
|
||||||
|
int32_t(uint8_t const*, int32_t, int32_t, uint8_t*, int32_t, int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
floatPower_wrap(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using floatLog_proto =
|
||||||
|
int32_t(uint8_t const*, int32_t, uint8_t*, int32_t, int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
floatLog_wrap(void* env, wasm_val_vec_t const* params, wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
} // namespace ripple
|
||||||
248
src/xrpld/app/wasm/ParamsHelper.h
Normal file
248
src/xrpld/app/wasm/ParamsHelper.h
Normal file
@@ -0,0 +1,248 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <xrpl/basics/base_uint.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 <optional>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace bft = boost::function_types;
|
||||||
|
|
||||||
|
namespace ripple {
|
||||||
|
|
||||||
|
using Bytes = std::vector<std::uint8_t>;
|
||||||
|
using Hash = ripple::uint256;
|
||||||
|
|
||||||
|
struct wmem
|
||||||
|
{
|
||||||
|
std::uint8_t* p = nullptr;
|
||||||
|
std::size_t s = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct WasmResult
|
||||||
|
{
|
||||||
|
T result;
|
||||||
|
int64_t cost;
|
||||||
|
};
|
||||||
|
typedef WasmResult<int32_t> EscrowResult;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
enum WasmTypes { WT_I32, WT_I64, WT_U8V };
|
||||||
|
|
||||||
|
struct WasmImportFunc
|
||||||
|
{
|
||||||
|
std::string name;
|
||||||
|
std::optional<WasmTypes> result;
|
||||||
|
std::vector<WasmTypes> params;
|
||||||
|
void* udata = nullptr;
|
||||||
|
// wasm_func_callback_with_env_t
|
||||||
|
void* wrap = nullptr;
|
||||||
|
uint32_t gas = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define WASM_IMPORT_FUNC(v, f, ...) \
|
||||||
|
WasmImpFunc<f##_proto>( \
|
||||||
|
v, #f, reinterpret_cast<void*>(&f##_wrap), ##__VA_ARGS__)
|
||||||
|
|
||||||
|
#define WASM_IMPORT_FUNC2(v, f, n, ...) \
|
||||||
|
WasmImpFunc<f##_proto>( \
|
||||||
|
v, n, reinterpret_cast<void*>(&f##_wrap), ##__VA_ARGS__)
|
||||||
|
|
||||||
|
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(WT_I32);
|
||||||
|
else if constexpr (std::is_same_v<at, std::int32_t>)
|
||||||
|
e.params.push_back(WT_I32);
|
||||||
|
else if constexpr (std::is_same_v<at, std::int64_t>)
|
||||||
|
e.params.push_back(WT_I64);
|
||||||
|
else
|
||||||
|
static_assert(std::is_pointer_v<at>, "Unsupported argument type");
|
||||||
|
|
||||||
|
return WasmImpArgs<N + 1, C, mpl>(e);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename rt>
|
||||||
|
void
|
||||||
|
WasmImpRet(WasmImportFunc& e)
|
||||||
|
{
|
||||||
|
if constexpr (std::is_pointer_v<rt>)
|
||||||
|
e.result = WT_I32;
|
||||||
|
else if constexpr (std::is_same_v<rt, std::int32_t>)
|
||||||
|
e.result = WT_I32;
|
||||||
|
else if constexpr (std::is_same_v<rt, std::int64_t>)
|
||||||
|
e.result = WT_I64;
|
||||||
|
else if constexpr (std::is_void_v<rt>)
|
||||||
|
e.result.reset();
|
||||||
|
#if (defined(__GNUC__) && (__GNUC__ >= 14)) || \
|
||||||
|
((defined(__clang_major__)) && (__clang_major__ >= 18))
|
||||||
|
else
|
||||||
|
static_assert(false, "Unsupported return type");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename F>
|
||||||
|
void
|
||||||
|
WasmImpFunc(
|
||||||
|
std::vector<WasmImportFunc>& v,
|
||||||
|
std::string_view imp_name,
|
||||||
|
void* f_wrap,
|
||||||
|
void* data = nullptr,
|
||||||
|
uint32_t gas = 0)
|
||||||
|
{
|
||||||
|
WasmImportFunc e;
|
||||||
|
e.name = imp_name;
|
||||||
|
e.udata = data;
|
||||||
|
e.wrap = f_wrap;
|
||||||
|
e.gas = gas;
|
||||||
|
WasmImpFuncHelper<F>(e);
|
||||||
|
v.push_back(std::move(e));
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
struct WasmParamVec
|
||||||
|
{
|
||||||
|
std::uint8_t const* d = nullptr;
|
||||||
|
std::int32_t sz = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct WasmParam
|
||||||
|
{
|
||||||
|
WasmTypes type = WT_I32;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
std::int32_t i32;
|
||||||
|
std::int64_t i64 = 0;
|
||||||
|
float f32;
|
||||||
|
double f64;
|
||||||
|
WasmParamVec u8v;
|
||||||
|
} of;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class... Types>
|
||||||
|
inline void
|
||||||
|
wasmParamsHlp(std::vector<WasmParam>& v, std::int32_t p, Types&&... args)
|
||||||
|
{
|
||||||
|
v.push_back({.type = WT_I32, .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 = WT_I64, .of = {.i64 = p}});
|
||||||
|
wasmParamsHlp(v, std::forward<Types>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We are not supporting float/double for now
|
||||||
|
// Leaving this code here so that it is easier to add later if needed
|
||||||
|
// template <class... Types>
|
||||||
|
// inline void
|
||||||
|
// wasmParamsHlp(std::vector<WasmParam>& v, float p, Types&&... args)
|
||||||
|
// {
|
||||||
|
// v.push_back({.type = WT_F32, .of = {.f32 = p}});
|
||||||
|
// wasmParamsHlp(v, std::forward<Types>(args)...);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// template <class... Types>
|
||||||
|
// inline void
|
||||||
|
// wasmParamsHlp(std::vector<WasmParam>& v, double p, Types&&... args)
|
||||||
|
// {
|
||||||
|
// v.push_back({.type = WT_F64, .of = {.f64 = p}});
|
||||||
|
// wasmParamsHlp(v, std::forward<Types>(args)...);
|
||||||
|
// }
|
||||||
|
|
||||||
|
template <class... Types>
|
||||||
|
inline void
|
||||||
|
wasmParamsHlp(
|
||||||
|
std::vector<WasmParam>& v,
|
||||||
|
std::uint8_t const* dt,
|
||||||
|
std::int32_t sz,
|
||||||
|
Types&&... args)
|
||||||
|
{
|
||||||
|
v.push_back({.type = WT_U8V, .of = {.u8v = {.d = dt, .sz = sz}}});
|
||||||
|
wasmParamsHlp(v, std::forward<Types>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class... Types>
|
||||||
|
inline void
|
||||||
|
wasmParamsHlp(std::vector<WasmParam>& v, Bytes const& p, Types&&... args)
|
||||||
|
{
|
||||||
|
wasmParamsHlp(
|
||||||
|
v,
|
||||||
|
p.data(),
|
||||||
|
static_cast<std::int32_t>(p.size()),
|
||||||
|
std::forward<Types>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class... Types>
|
||||||
|
inline void
|
||||||
|
wasmParamsHlp(
|
||||||
|
std::vector<WasmParam>& v,
|
||||||
|
std::string_view const& p,
|
||||||
|
Types&&... args)
|
||||||
|
{
|
||||||
|
wasmParamsHlp(
|
||||||
|
v,
|
||||||
|
reinterpret_cast<std::uint8_t const*>(p.data()),
|
||||||
|
static_cast<std::int32_t>(p.size()),
|
||||||
|
std::forward<Types>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class... Types>
|
||||||
|
inline void
|
||||||
|
wasmParamsHlp(std::vector<WasmParam>& v, std::string const& p, Types&&... args)
|
||||||
|
{
|
||||||
|
wasmParamsHlp(
|
||||||
|
v,
|
||||||
|
reinterpret_cast<std::uint8_t const*>(p.c_str()),
|
||||||
|
static_cast<std::int32_t>(p.size()),
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ripple
|
||||||
309
src/xrpld/app/wasm/WamrVM.h
Normal file
309
src/xrpld/app/wasm/WamrVM.h
Normal file
@@ -0,0 +1,309 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <xrpld/app/wasm/WasmVM.h>
|
||||||
|
|
||||||
|
#include <wasm_c_api.h>
|
||||||
|
#include <wasm_export.h>
|
||||||
|
|
||||||
|
namespace ripple {
|
||||||
|
|
||||||
|
struct WamrResult
|
||||||
|
{
|
||||||
|
wasm_val_vec_t r;
|
||||||
|
bool f; // failure flag
|
||||||
|
|
||||||
|
WamrResult(unsigned N = 0) : r{0, nullptr, 0, 0, nullptr}, f(false)
|
||||||
|
{
|
||||||
|
if (N)
|
||||||
|
wasm_val_vec_new_uninitialized(&r, N);
|
||||||
|
}
|
||||||
|
|
||||||
|
~WamrResult()
|
||||||
|
{
|
||||||
|
if (r.size)
|
||||||
|
wasm_val_vec_delete(&r);
|
||||||
|
}
|
||||||
|
|
||||||
|
WamrResult(WamrResult const&) = delete;
|
||||||
|
WamrResult&
|
||||||
|
operator=(WamrResult const&) = delete;
|
||||||
|
|
||||||
|
WamrResult(WamrResult&& o)
|
||||||
|
{
|
||||||
|
*this = std::move(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
WamrResult&
|
||||||
|
operator=(WamrResult&& o)
|
||||||
|
{
|
||||||
|
r = o.r;
|
||||||
|
o.r = {0, nullptr, 0, 0, nullptr};
|
||||||
|
f = o.f;
|
||||||
|
o.f = false;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
// operator wasm_val_vec_t &() {return r;}
|
||||||
|
};
|
||||||
|
|
||||||
|
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 FuncInfo = std::pair<wasm_func_t const*, wasm_functype_t const*>;
|
||||||
|
|
||||||
|
struct InstanceWrapper
|
||||||
|
{
|
||||||
|
wasm_extern_vec_t exports_;
|
||||||
|
InstancePtr instance_;
|
||||||
|
wasm_exec_env_t execEnv_ = nullptr;
|
||||||
|
beast::Journal j_ = beast::Journal(beast::Journal::getNullSink());
|
||||||
|
|
||||||
|
private:
|
||||||
|
static InstancePtr
|
||||||
|
init(
|
||||||
|
wasm_store_t* s,
|
||||||
|
wasm_module_t* m,
|
||||||
|
int32_t maxPages,
|
||||||
|
wasm_extern_vec_t* expt,
|
||||||
|
wasm_extern_vec_t const& imports,
|
||||||
|
beast::Journal j);
|
||||||
|
|
||||||
|
public:
|
||||||
|
InstanceWrapper();
|
||||||
|
|
||||||
|
InstanceWrapper(InstanceWrapper&& o);
|
||||||
|
|
||||||
|
InstanceWrapper&
|
||||||
|
operator=(InstanceWrapper&& o);
|
||||||
|
|
||||||
|
InstanceWrapper(
|
||||||
|
wasm_store_t* s,
|
||||||
|
wasm_module_t* m,
|
||||||
|
int32_t maxPages,
|
||||||
|
int64_t gas,
|
||||||
|
wasm_extern_vec_t const& imports,
|
||||||
|
beast::Journal j);
|
||||||
|
|
||||||
|
~InstanceWrapper();
|
||||||
|
|
||||||
|
operator bool() const;
|
||||||
|
|
||||||
|
FuncInfo
|
||||||
|
getFunc(
|
||||||
|
std::string_view funcName,
|
||||||
|
wasm_exporttype_vec_t const& export_types) const;
|
||||||
|
|
||||||
|
wmem
|
||||||
|
getMem() const;
|
||||||
|
|
||||||
|
std::int64_t
|
||||||
|
getGas() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ModuleWrapper
|
||||||
|
{
|
||||||
|
ModulePtr module_;
|
||||||
|
InstanceWrapper instanceWrap_;
|
||||||
|
wasm_exporttype_vec_t exportTypes_;
|
||||||
|
beast::Journal j_ = beast::Journal(beast::Journal::getNullSink());
|
||||||
|
|
||||||
|
private:
|
||||||
|
static ModulePtr
|
||||||
|
init(wasm_store_t* s, Bytes const& wasmBin, beast::Journal j);
|
||||||
|
|
||||||
|
public:
|
||||||
|
ModuleWrapper();
|
||||||
|
ModuleWrapper(ModuleWrapper&& o);
|
||||||
|
ModuleWrapper&
|
||||||
|
operator=(ModuleWrapper&& o);
|
||||||
|
ModuleWrapper(
|
||||||
|
wasm_store_t* s,
|
||||||
|
Bytes const& wasmBin,
|
||||||
|
bool instantiate,
|
||||||
|
int32_t maxPages,
|
||||||
|
int64_t gas,
|
||||||
|
std::vector<WasmImportFunc> const& imports,
|
||||||
|
beast::Journal j);
|
||||||
|
~ModuleWrapper();
|
||||||
|
|
||||||
|
operator bool() const;
|
||||||
|
|
||||||
|
FuncInfo
|
||||||
|
getFunc(std::string_view funcName) const;
|
||||||
|
wmem
|
||||||
|
getMem() const;
|
||||||
|
|
||||||
|
InstanceWrapper const&
|
||||||
|
getInstance(int i = 0) const;
|
||||||
|
|
||||||
|
int
|
||||||
|
addInstance(
|
||||||
|
wasm_store_t* s,
|
||||||
|
int32_t maxPages,
|
||||||
|
int64_t gas,
|
||||||
|
wasm_extern_vec_t const& imports = WASM_EMPTY_VEC);
|
||||||
|
|
||||||
|
std::int64_t
|
||||||
|
getGas();
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void
|
||||||
|
makeImpParams(wasm_valtype_vec_t& v, WasmImportFunc const& imp);
|
||||||
|
static void
|
||||||
|
makeImpReturn(wasm_valtype_vec_t& v, WasmImportFunc const& imp);
|
||||||
|
wasm_extern_vec_t
|
||||||
|
buildImports(wasm_store_t* s, std::vector<WasmImportFunc> const& imports);
|
||||||
|
};
|
||||||
|
|
||||||
|
class WamrEngine
|
||||||
|
{
|
||||||
|
std::unique_ptr<wasm_engine_t, decltype(&wasm_engine_delete)> engine_;
|
||||||
|
std::unique_ptr<wasm_store_t, decltype(&wasm_store_delete)> store_;
|
||||||
|
std::unique_ptr<ModuleWrapper> moduleWrap_;
|
||||||
|
std::int32_t defMaxPages_ = -1;
|
||||||
|
beast::Journal j_ = beast::Journal(beast::Journal::getNullSink());
|
||||||
|
|
||||||
|
std::mutex m_; // 1 instance mutex
|
||||||
|
|
||||||
|
public:
|
||||||
|
WamrEngine();
|
||||||
|
~WamrEngine() = default;
|
||||||
|
|
||||||
|
Expected<WasmResult<int32_t>, TER>
|
||||||
|
run(Bytes const& wasmCode,
|
||||||
|
std::string_view funcName,
|
||||||
|
std::vector<WasmParam> const& params,
|
||||||
|
std::vector<WasmImportFunc> const& imports,
|
||||||
|
HostFunctions* hfs,
|
||||||
|
int64_t gas,
|
||||||
|
beast::Journal j);
|
||||||
|
|
||||||
|
NotTEC
|
||||||
|
check(
|
||||||
|
Bytes const& wasmCode,
|
||||||
|
std::string_view funcName,
|
||||||
|
std::vector<WasmParam> const& params,
|
||||||
|
std::vector<WasmImportFunc> const& imports,
|
||||||
|
beast::Journal j);
|
||||||
|
|
||||||
|
std::int32_t
|
||||||
|
initMaxPages(std::int32_t def);
|
||||||
|
|
||||||
|
std::int64_t
|
||||||
|
getGas();
|
||||||
|
|
||||||
|
// Host functions helper functionality
|
||||||
|
wasm_trap_t*
|
||||||
|
newTrap(std::string_view msg);
|
||||||
|
|
||||||
|
beast::Journal
|
||||||
|
getJournal() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
InstanceWrapper const&
|
||||||
|
getRT(int m = 0, int i = 0);
|
||||||
|
|
||||||
|
wmem
|
||||||
|
getMem() const;
|
||||||
|
|
||||||
|
int32_t
|
||||||
|
allocate(int32_t size);
|
||||||
|
|
||||||
|
Expected<WasmResult<int32_t>, TER>
|
||||||
|
runHlp(
|
||||||
|
Bytes const& wasmCode,
|
||||||
|
std::string_view funcName,
|
||||||
|
std::vector<WasmParam> const& params,
|
||||||
|
std::vector<WasmImportFunc> const& imports,
|
||||||
|
HostFunctions* hfs,
|
||||||
|
int64_t gas);
|
||||||
|
|
||||||
|
NotTEC
|
||||||
|
checkHlp(
|
||||||
|
Bytes const& wasmCode,
|
||||||
|
std::string_view funcName,
|
||||||
|
std::vector<WasmParam> const& params,
|
||||||
|
std::vector<WasmImportFunc> const& imports);
|
||||||
|
|
||||||
|
int
|
||||||
|
addModule(
|
||||||
|
Bytes const& wasmCode,
|
||||||
|
bool instantiate,
|
||||||
|
int64_t gas,
|
||||||
|
std::vector<WasmImportFunc> const& imports);
|
||||||
|
void
|
||||||
|
clearModules();
|
||||||
|
|
||||||
|
// int addInstance();
|
||||||
|
|
||||||
|
int32_t
|
||||||
|
runFunc(std::string_view const funcName, int32_t p);
|
||||||
|
|
||||||
|
int32_t
|
||||||
|
makeModule(
|
||||||
|
Bytes const& wasmCode,
|
||||||
|
wasm_extern_vec_t const& imports = WASM_EMPTY_VEC);
|
||||||
|
|
||||||
|
FuncInfo
|
||||||
|
getFunc(std::string_view funcName);
|
||||||
|
|
||||||
|
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
|
||||||
|
add_param(std::vector<wasm_val_t>& in, int32_t p);
|
||||||
|
static void
|
||||||
|
add_param(std::vector<wasm_val_t>& in, int64_t p);
|
||||||
|
|
||||||
|
template <int NR, class... Types>
|
||||||
|
inline WamrResult
|
||||||
|
call(std::string_view func, Types&&... args);
|
||||||
|
|
||||||
|
template <int NR, class... Types>
|
||||||
|
inline WamrResult
|
||||||
|
call(FuncInfo const& f, Types&&... args);
|
||||||
|
|
||||||
|
template <int NR, class... Types>
|
||||||
|
inline WamrResult
|
||||||
|
call(FuncInfo const& f, std::vector<wasm_val_t>& in);
|
||||||
|
|
||||||
|
template <int NR, class... Types>
|
||||||
|
inline WamrResult
|
||||||
|
call(
|
||||||
|
FuncInfo const& f,
|
||||||
|
std::vector<wasm_val_t>& in,
|
||||||
|
std::int32_t p,
|
||||||
|
Types&&... args);
|
||||||
|
|
||||||
|
template <int NR, class... Types>
|
||||||
|
inline WamrResult
|
||||||
|
call(
|
||||||
|
FuncInfo const& f,
|
||||||
|
std::vector<wasm_val_t>& in,
|
||||||
|
std::int64_t p,
|
||||||
|
Types&&... args);
|
||||||
|
|
||||||
|
template <int NR, class... Types>
|
||||||
|
inline WamrResult
|
||||||
|
call(
|
||||||
|
FuncInfo const& f,
|
||||||
|
std::vector<wasm_val_t>& in,
|
||||||
|
uint8_t const* d,
|
||||||
|
std::size_t sz,
|
||||||
|
Types&&... args);
|
||||||
|
|
||||||
|
template <int NR, class... Types>
|
||||||
|
inline WamrResult
|
||||||
|
call(
|
||||||
|
FuncInfo const& f,
|
||||||
|
std::vector<wasm_val_t>& in,
|
||||||
|
Bytes const& p,
|
||||||
|
Types&&... args);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ripple
|
||||||
93
src/xrpld/app/wasm/WasmVM.h
Normal file
93
src/xrpld/app/wasm/WasmVM.h
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <xrpld/app/wasm/HostFunc.h>
|
||||||
|
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
namespace ripple {
|
||||||
|
|
||||||
|
static std::string_view const W_ENV = "env";
|
||||||
|
static std::string_view const W_HOST_LIB = "host_lib";
|
||||||
|
static std::string_view const W_MEM = "memory";
|
||||||
|
static std::string_view const W_STORE = "store";
|
||||||
|
static std::string_view const W_LOAD = "load";
|
||||||
|
static std::string_view const W_SIZE = "size";
|
||||||
|
static std::string_view const W_ALLOC = "allocate";
|
||||||
|
static std::string_view const W_DEALLOC = "deallocate";
|
||||||
|
static std::string_view const W_PROC_EXIT = "proc_exit";
|
||||||
|
|
||||||
|
static std::string_view const ESCROW_FUNCTION_NAME = "finish";
|
||||||
|
|
||||||
|
uint32_t const MAX_PAGES = 128; // 8MB = 64KB*128
|
||||||
|
|
||||||
|
class WamrEngine;
|
||||||
|
class WasmEngine
|
||||||
|
{
|
||||||
|
std::unique_ptr<WamrEngine> const impl;
|
||||||
|
|
||||||
|
WasmEngine();
|
||||||
|
|
||||||
|
WasmEngine(WasmEngine const&) = delete;
|
||||||
|
WasmEngine(WasmEngine&&) = delete;
|
||||||
|
WasmEngine&
|
||||||
|
operator=(WasmEngine const&) = delete;
|
||||||
|
WasmEngine&
|
||||||
|
operator=(WasmEngine&&) = delete;
|
||||||
|
|
||||||
|
public:
|
||||||
|
~WasmEngine() = default;
|
||||||
|
|
||||||
|
static WasmEngine&
|
||||||
|
instance();
|
||||||
|
|
||||||
|
Expected<WasmResult<int32_t>, TER>
|
||||||
|
run(Bytes const& wasmCode,
|
||||||
|
std::string_view funcName = {},
|
||||||
|
std::vector<WasmParam> const& params = {},
|
||||||
|
std::vector<WasmImportFunc> const& imports = {},
|
||||||
|
HostFunctions* hfs = nullptr,
|
||||||
|
int64_t gasLimit = -1,
|
||||||
|
beast::Journal j = beast::Journal{beast::Journal::getNullSink()});
|
||||||
|
|
||||||
|
NotTEC
|
||||||
|
check(
|
||||||
|
Bytes const& wasmCode,
|
||||||
|
std::string_view funcName,
|
||||||
|
std::vector<WasmParam> const& params = {},
|
||||||
|
std::vector<WasmImportFunc> const& imports = {},
|
||||||
|
beast::Journal j = beast::Journal{beast::Journal::getNullSink()});
|
||||||
|
|
||||||
|
std::int32_t
|
||||||
|
initMaxPages(std::int32_t def);
|
||||||
|
|
||||||
|
// Host functions helper functionality
|
||||||
|
void*
|
||||||
|
newTrap(std::string_view msg = {});
|
||||||
|
|
||||||
|
beast::Journal
|
||||||
|
getJournal() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
std::vector<WasmImportFunc>
|
||||||
|
createWasmImport(HostFunctions* hfs);
|
||||||
|
|
||||||
|
Expected<EscrowResult, TER>
|
||||||
|
runEscrowWasm(
|
||||||
|
Bytes const& wasmCode,
|
||||||
|
std::string_view funcName = ESCROW_FUNCTION_NAME,
|
||||||
|
std::vector<WasmParam> const& params = {},
|
||||||
|
HostFunctions* hfs = nullptr,
|
||||||
|
int64_t gasLimit = -1,
|
||||||
|
beast::Journal j = beast::Journal(beast::Journal::getNullSink()));
|
||||||
|
|
||||||
|
NotTEC
|
||||||
|
preflightEscrowWasm(
|
||||||
|
Bytes const& wasmCode,
|
||||||
|
std::string_view funcName = ESCROW_FUNCTION_NAME,
|
||||||
|
std::vector<WasmParam> const& params = {},
|
||||||
|
HostFunctions* hfs = nullptr,
|
||||||
|
beast::Journal j = beast::Journal(beast::Journal::getNullSink()));
|
||||||
|
|
||||||
|
} // namespace ripple
|
||||||
1305
src/xrpld/app/wasm/detail/HostFuncImpl.cpp
Normal file
1305
src/xrpld/app/wasm/detail/HostFuncImpl.cpp
Normal file
File diff suppressed because it is too large
Load Diff
2025
src/xrpld/app/wasm/detail/HostFuncWrapper.cpp
Normal file
2025
src/xrpld/app/wasm/detail/HostFuncWrapper.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1041
src/xrpld/app/wasm/detail/WamrVM.cpp
Normal file
1041
src/xrpld/app/wasm/detail/WamrVM.cpp
Normal file
File diff suppressed because it is too large
Load Diff
223
src/xrpld/app/wasm/detail/WasmVM.cpp
Normal file
223
src/xrpld/app/wasm/detail/WasmVM.cpp
Normal file
@@ -0,0 +1,223 @@
|
|||||||
|
#ifdef _DEBUG
|
||||||
|
// #define DEBUG_OUTPUT 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <xrpld/app/wasm/HostFunc.h>
|
||||||
|
#include <xrpld/app/wasm/HostFuncWrapper.h>
|
||||||
|
#include <xrpld/app/wasm/WamrVM.h>
|
||||||
|
|
||||||
|
#include <xrpl/basics/Log.h>
|
||||||
|
#include <xrpl/protocol/AccountID.h>
|
||||||
|
#include <xrpl/protocol/Feature.h>
|
||||||
|
#include <xrpl/protocol/LedgerFormats.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace ripple {
|
||||||
|
|
||||||
|
static void
|
||||||
|
setCommonHostFunctions(HostFunctions* hfs, std::vector<WasmImportFunc>& i)
|
||||||
|
{
|
||||||
|
// clang-format off
|
||||||
|
WASM_IMPORT_FUNC2(i, getLedgerSqn, "get_ledger_sqn", hfs, 60);
|
||||||
|
WASM_IMPORT_FUNC2(i, getParentLedgerTime, "get_parent_ledger_time", hfs, 60);
|
||||||
|
WASM_IMPORT_FUNC2(i, getParentLedgerHash, "get_parent_ledger_hash", hfs, 60);
|
||||||
|
WASM_IMPORT_FUNC2(i, getBaseFee, "get_base_fee", hfs, 60);
|
||||||
|
WASM_IMPORT_FUNC2(i, isAmendmentEnabled, "amendment_enabled", hfs, 100);
|
||||||
|
|
||||||
|
WASM_IMPORT_FUNC2(i, cacheLedgerObj, "cache_ledger_obj", hfs, 5'000);
|
||||||
|
WASM_IMPORT_FUNC2(i, getTxField, "get_tx_field", hfs, 70);
|
||||||
|
WASM_IMPORT_FUNC2(i, getCurrentLedgerObjField, "get_current_ledger_obj_field", hfs, 70);
|
||||||
|
WASM_IMPORT_FUNC2(i, getLedgerObjField, "get_ledger_obj_field", hfs, 70);
|
||||||
|
WASM_IMPORT_FUNC2(i, getTxNestedField, "get_tx_nested_field", hfs, 110);
|
||||||
|
WASM_IMPORT_FUNC2(i, getCurrentLedgerObjNestedField, "get_current_ledger_obj_nested_field", hfs, 110);
|
||||||
|
WASM_IMPORT_FUNC2(i, getLedgerObjNestedField, "get_ledger_obj_nested_field", hfs, 110);
|
||||||
|
WASM_IMPORT_FUNC2(i, getTxArrayLen, "get_tx_array_len", hfs, 40);
|
||||||
|
WASM_IMPORT_FUNC2(i, getCurrentLedgerObjArrayLen, "get_current_ledger_obj_array_len", hfs, 40);
|
||||||
|
WASM_IMPORT_FUNC2(i, getLedgerObjArrayLen, "get_ledger_obj_array_len", hfs, 40);
|
||||||
|
WASM_IMPORT_FUNC2(i, getTxNestedArrayLen, "get_tx_nested_array_len", hfs, 70);
|
||||||
|
WASM_IMPORT_FUNC2(i, getCurrentLedgerObjNestedArrayLen, "get_current_ledger_obj_nested_array_len", hfs, 70);
|
||||||
|
WASM_IMPORT_FUNC2(i, getLedgerObjNestedArrayLen, "get_ledger_obj_nested_array_len", hfs, 70);
|
||||||
|
|
||||||
|
WASM_IMPORT_FUNC2(i, checkSignature, "check_sig", hfs, 300);
|
||||||
|
WASM_IMPORT_FUNC2(i, computeSha512HalfHash, "compute_sha512_half", hfs, 2000);
|
||||||
|
|
||||||
|
WASM_IMPORT_FUNC2(i, accountKeylet, "account_keylet", hfs, 350);
|
||||||
|
WASM_IMPORT_FUNC2(i, ammKeylet, "amm_keylet", hfs, 450);
|
||||||
|
WASM_IMPORT_FUNC2(i, checkKeylet, "check_keylet", hfs, 350);
|
||||||
|
WASM_IMPORT_FUNC2(i, credentialKeylet, "credential_keylet", hfs, 350);
|
||||||
|
WASM_IMPORT_FUNC2(i, delegateKeylet, "delegate_keylet", hfs, 350);
|
||||||
|
WASM_IMPORT_FUNC2(i, depositPreauthKeylet, "deposit_preauth_keylet", hfs, 350);
|
||||||
|
WASM_IMPORT_FUNC2(i, didKeylet, "did_keylet", hfs, 350);
|
||||||
|
WASM_IMPORT_FUNC2(i, escrowKeylet, "escrow_keylet", hfs, 350);
|
||||||
|
WASM_IMPORT_FUNC2(i, lineKeylet, "line_keylet", hfs, 400);
|
||||||
|
WASM_IMPORT_FUNC2(i, mptIssuanceKeylet, "mpt_issuance_keylet", hfs, 350);
|
||||||
|
WASM_IMPORT_FUNC2(i, mptokenKeylet, "mptoken_keylet", hfs, 500);
|
||||||
|
WASM_IMPORT_FUNC2(i, nftOfferKeylet, "nft_offer_keylet", hfs, 350);
|
||||||
|
WASM_IMPORT_FUNC2(i, offerKeylet, "offer_keylet", hfs, 350);
|
||||||
|
WASM_IMPORT_FUNC2(i, oracleKeylet, "oracle_keylet", hfs, 350);
|
||||||
|
WASM_IMPORT_FUNC2(i, paychanKeylet, "paychan_keylet", hfs, 350);
|
||||||
|
WASM_IMPORT_FUNC2(i, permissionedDomainKeylet, "permissioned_domain_keylet", hfs, 350);
|
||||||
|
WASM_IMPORT_FUNC2(i, signersKeylet, "signers_keylet", hfs, 350);
|
||||||
|
WASM_IMPORT_FUNC2(i, ticketKeylet, "ticket_keylet", hfs, 350);
|
||||||
|
WASM_IMPORT_FUNC2(i, vaultKeylet, "vault_keylet", hfs, 350);
|
||||||
|
|
||||||
|
WASM_IMPORT_FUNC2(i, getNFT, "get_nft", hfs, 1000);
|
||||||
|
WASM_IMPORT_FUNC2(i, getNFTIssuer, "get_nft_issuer", hfs, 70);
|
||||||
|
WASM_IMPORT_FUNC2(i, getNFTTaxon, "get_nft_taxon", hfs, 60);
|
||||||
|
WASM_IMPORT_FUNC2(i, getNFTFlags, "get_nft_flags", hfs, 60);
|
||||||
|
WASM_IMPORT_FUNC2(i, getNFTTransferFee, "get_nft_transfer_fee", hfs, 60);
|
||||||
|
WASM_IMPORT_FUNC2(i, getNFTSerial, "get_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_account", hfs, 500);
|
||||||
|
WASM_IMPORT_FUNC2(i, traceFloat, "trace_opaque_float", hfs, 500);
|
||||||
|
WASM_IMPORT_FUNC2(i, traceAmount, "trace_amount", 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, floatSet, "float_set", hfs, 100);
|
||||||
|
WASM_IMPORT_FUNC2(i, floatCompare, "float_compare", hfs, 80);
|
||||||
|
WASM_IMPORT_FUNC2(i, floatAdd, "float_add", hfs, 160);
|
||||||
|
WASM_IMPORT_FUNC2(i, floatSubtract, "float_subtract", hfs, 160);
|
||||||
|
WASM_IMPORT_FUNC2(i, floatMultiply, "float_multiply", hfs, 300);
|
||||||
|
WASM_IMPORT_FUNC2(i, floatDivide, "float_divide", hfs, 300);
|
||||||
|
WASM_IMPORT_FUNC2(i, floatRoot, "float_root", hfs, 5'500);
|
||||||
|
WASM_IMPORT_FUNC2(i, floatPower, "float_pow", hfs, 5'500);
|
||||||
|
WASM_IMPORT_FUNC2(i, floatLog, "float_log", hfs, 12'000);
|
||||||
|
// clang-format on
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<WasmImportFunc>
|
||||||
|
createWasmImport(HostFunctions* hfs)
|
||||||
|
{
|
||||||
|
std::vector<WasmImportFunc> i;
|
||||||
|
|
||||||
|
if (hfs)
|
||||||
|
{
|
||||||
|
setCommonHostFunctions(hfs, i);
|
||||||
|
WASM_IMPORT_FUNC2(i, updateData, "update_data", hfs, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expected<EscrowResult, TER>
|
||||||
|
runEscrowWasm(
|
||||||
|
Bytes const& wasmCode,
|
||||||
|
std::string_view funcName,
|
||||||
|
std::vector<WasmParam> const& params,
|
||||||
|
HostFunctions* hfs,
|
||||||
|
int64_t gasLimit,
|
||||||
|
beast::Journal j)
|
||||||
|
{
|
||||||
|
// create VM and set cost limit
|
||||||
|
auto& vm = WasmEngine::instance();
|
||||||
|
vm.initMaxPages(MAX_PAGES);
|
||||||
|
|
||||||
|
auto const ret = vm.run(
|
||||||
|
wasmCode,
|
||||||
|
funcName,
|
||||||
|
params,
|
||||||
|
createWasmImport(hfs),
|
||||||
|
hfs,
|
||||||
|
gasLimit,
|
||||||
|
hfs ? hfs->getJournal() : j);
|
||||||
|
|
||||||
|
// std::cout << "runEscrowWasm, mod size: " << wasmCode.size()
|
||||||
|
// << ", gasLimit: " << gasLimit << ", funcName: " << funcName;
|
||||||
|
|
||||||
|
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{ret->result, ret->cost};
|
||||||
|
}
|
||||||
|
|
||||||
|
NotTEC
|
||||||
|
preflightEscrowWasm(
|
||||||
|
Bytes const& wasmCode,
|
||||||
|
std::string_view funcName,
|
||||||
|
std::vector<WasmParam> const& params,
|
||||||
|
HostFunctions* hfs,
|
||||||
|
beast::Journal j)
|
||||||
|
{
|
||||||
|
// create VM and set cost limit
|
||||||
|
auto& vm = WasmEngine::instance();
|
||||||
|
vm.initMaxPages(MAX_PAGES);
|
||||||
|
|
||||||
|
auto const ret = vm.check(
|
||||||
|
wasmCode,
|
||||||
|
funcName,
|
||||||
|
params,
|
||||||
|
createWasmImport(hfs),
|
||||||
|
hfs ? hfs->getJournal() : j);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
WasmEngine::WasmEngine() : impl(std::make_unique<WamrEngine>())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
WasmEngine&
|
||||||
|
WasmEngine::instance()
|
||||||
|
{
|
||||||
|
static WasmEngine e;
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expected<WasmResult<int32_t>, TER>
|
||||||
|
WasmEngine::run(
|
||||||
|
Bytes const& wasmCode,
|
||||||
|
std::string_view funcName,
|
||||||
|
std::vector<WasmParam> const& params,
|
||||||
|
std::vector<WasmImportFunc> const& imports,
|
||||||
|
HostFunctions* hfs,
|
||||||
|
int64_t gasLimit,
|
||||||
|
beast::Journal j)
|
||||||
|
{
|
||||||
|
return impl->run(wasmCode, funcName, params, imports, hfs, gasLimit, j);
|
||||||
|
}
|
||||||
|
|
||||||
|
NotTEC
|
||||||
|
WasmEngine::check(
|
||||||
|
Bytes const& wasmCode,
|
||||||
|
std::string_view funcName,
|
||||||
|
std::vector<WasmParam> const& params,
|
||||||
|
std::vector<WasmImportFunc> const& imports,
|
||||||
|
beast::Journal j)
|
||||||
|
{
|
||||||
|
return impl->check(wasmCode, funcName, params, imports, j);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::int32_t
|
||||||
|
WasmEngine::initMaxPages(std::int32_t def)
|
||||||
|
{
|
||||||
|
return impl->initMaxPages(def);
|
||||||
|
}
|
||||||
|
|
||||||
|
void*
|
||||||
|
WasmEngine::newTrap(std::string_view msg)
|
||||||
|
{
|
||||||
|
return impl->newTrap(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
beast::Journal
|
||||||
|
WasmEngine::getJournal() const
|
||||||
|
{
|
||||||
|
return impl->getJournal();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ripple
|
||||||
Reference in New Issue
Block a user