Compare commits

..

16 Commits

Author SHA1 Message Date
Ed Hennis
fe179afb51 Merge branch 'develop' into ximinez/sync-script 2026-05-20 07:21:29 -04:00
Vito Tumas
93ac1aa7aa fix: Disable unnecessary sanity-check in VaultDeposit (#7288) 2026-05-19 16:38:50 +00:00
dependabot[bot]
d9a3af8207 ci: [DEPENDABOT] bump actions/upload-artifact from 7.0.0 to 7.0.1 (#7286)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-19 16:35:38 +00:00
Ayaz Salikhov
8d1083e5ea ci: Only run reusable package in public repos (#7293) 2026-05-19 13:15:11 +00:00
Fomo
1e45d363c5 fix: Set default peering port to 2459 (#6848)
Co-authored-by: Bart <bthomee@users.noreply.github.com>
2026-05-19 06:05:47 +00:00
Ed Hennis
59c7ad68f2 Merge branch 'develop' into ximinez/sync-script 2026-05-14 20:39:57 -04:00
Ed Hennis
53768ded97 Merge branch 'develop' into ximinez/sync-script 2026-05-14 10:49:20 -04:00
Ed Hennis
7dbd98d3eb Merge branch 'develop' into ximinez/sync-script 2026-05-13 12:04:40 -04:00
Ed Hennis
283e1742ed Merge branch 'develop' into ximinez/sync-script 2026-05-12 20:12:06 -04:00
Ed Hennis
71a1aa95d1 Merge branch 'develop' into ximinez/sync-script 2026-05-07 18:11:00 -04:00
Ed Hennis
eb6ff26f3d Merge branch 'develop' into ximinez/sync-script 2026-05-07 14:20:09 -04:00
Ed Hennis
43c8c719ff Merge branch 'develop' into ximinez/sync-script 2026-05-07 13:29:28 -04:00
Ed Hennis
a83f3e25fd Merge branch 'develop' into ximinez/sync-script 2026-05-06 22:35:21 -04:00
Ed Hennis
96166dcfa0 Merge branch 'develop' into ximinez/sync-script 2026-05-06 14:19:02 -04:00
Ed Hennis
cf8a3588ca Merge branch 'develop' into ximinez/sync-script 2026-05-05 15:21:38 -04:00
Ed Hennis
97059761a6 chore: Add script to cherry-pick new commits from develop to a release 2026-05-04 19:56:08 -04:00
65 changed files with 262 additions and 18997 deletions

View File

@@ -58,6 +58,7 @@ jobs:
package:
needs: [generate-matrix, generate-version]
if: ${{ github.event.repository.visibility == 'public' }}
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.generate-matrix.outputs.matrix) }}
@@ -88,8 +89,7 @@ jobs:
run: ./package/build_pkg.sh
- name: Upload package artifact
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
if: ${{ github.event.repository.visibility == 'public' }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: ${{ matrix.artifact_name }}-pkg-${{ needs.generate-version.outputs.version }}
path: |

View File

@@ -93,7 +93,6 @@ find_package(OpenSSL REQUIRED)
find_package(secp256k1 REQUIRED)
find_package(SOCI REQUIRED)
find_package(SQLite3 REQUIRED)
find_package(wasmi REQUIRED)
find_package(xxHash REQUIRED)
target_link_libraries(

159
bin/git/sync-to-release.sh Executable file
View File

@@ -0,0 +1,159 @@
#!/bin/bash -e
set -o pipefail
_usage()
{
self=$( basename -- $( echo $0 ) )
cat << USAGE
Usage: $self release_branch develop_branch working_branch [new_version]
This script is intended to be used to synchronize changes between two
branches where the "release_branch" has a few insignificant changes (e.g.
version numbers) compared to the "develop_branch", which has active
ongoing development. It has not (yet) been tested in scenarios where the
branches have significantly diverged, or where one has been merged to
the other.
release_branch: Usually a pending release branch, this is the low
activity branch which needs to be updated from develop_branch.
develop_branch: The active development branch.
working_branch: This branch will be created from the release_branch to
have the new commits applied. If it exists, it will be assumed to have
been created by an earlier invocation, and will be used for
comparisons instead of release_branch. When the script is done, this
branch will NOT be pushed. The user must manually push the branch and
create a pull request.
new_version: OPTIONAL. If provided, will update the version string in
BuildInfo.cpp to this value, and create a version_setting commit.
USAGE
if [[ $# -ne 0 ]]; then
echo "Error: ${@}"
echo
fi
exit 1
}
if [[ $# -lt 3 || $# -gt 4 ]]; then
_usage
fi
release_branch="$1"
shift
develop_branch="$1"
shift
working_branch="$1"
shift
if [[ $# -ne 0 ]]; then
new_version="$1"
shift
fi
_run()
{
echo
echo "\$ ${@}"
"${@}"
}
if git rev-parse --quiet --verify --end-of-options "refs/heads/${working_branch}" > /dev/null; then
release_branch="${working_branch}"
_run git checkout "${working_branch}"
else
_run git checkout --no-track -B "${working_branch}" "${release_branch}"
fi
# Fetch if it hasn't been done in a while
if find "$( git rev-parse --git-dir )/FETCH_HEAD" -type f -mmin +10 | grep -q "FETCH"; then
_run git fetch --all
fi
temp=$( mktemp )
# The "word-diff" option doesn't seem to have any meaningful effect on the output.
# This may make this script fragile across git versions with differing output formats.
_run git range-diff --word-diff=porcelain --no-patch --right-only \
"${release_branch}"..."${develop_branch}" | tee "${temp}"
first_commit=$( cat "${temp}" | \
awk '( $1 == "-:" && $2 ~ /-+/ && $3 == ">" ) { print $5; exit; }' )
if [[ "${first_commit}" == "" && "${new_version}" == "" ]]; then
_usage No divergence found
exit 1
fi
if [[ "${first_commit}" == "" ]]; then
echo -e "\nNo divergence found. Continue to update version number"
else
echo -e "\nFound first unique commit in ${develop_branch}: ${first_commit}"
first_commit=$( git rev-parse --quiet "${first_commit}" )
echo "Full commit ID is: ${first_commit}"
merge_base=$( git merge-base --octopus "${first_commit}" "${develop_branch}" )
if [[ "${first_commit}" != "${merge_base}" ]]; then
echo "Bad first commit: ${first_commit} is not an ancestor of ${develop_branch}"
exit 1
fi
_run git diff "${first_commit}~" "${release_branch}"
read -n 1 -s -p "Does the diff look reasonable? (y to continue / any other key to abort)" continue
echo
if [[ ! ( "${continue}" =~ [yY] ) ]]; then
echo Abort
exit 1
fi
# Dilemma: if the cherry-pick is interrupted, for example, because of a conflict, the script
# will abort, and can not easily be resumed. This will prevent the final step(s) from running.
if ! _run git cherry-pick --empty=drop "${first_commit}~..${develop_branch}"; then
# Solution: if the cherry-pick is interrupted, run the command again.
if [[ "${new_version}" != "" ]]; then
echo
echo "Cherry pick failed or was interrupted. Resolve issues, finish the"
echo " cherry pick, then run this script again to with the same parameters"
echo " to update the version number."
fi
exit 1
fi
if [[ "${new_version}" == "" ]]; then
# If there is no version number change to make, we're done.
exit 0
fi
fi
# There should only be one matching file, but loop in case not.
buildfiles=( $( git ls-files | grep "BuildInfo.cpp" ) )
for build in "${buildfiles[@]}"; do
sed 's/\(^.*versionString =\).*$/\1 "'${new_version}'"/' ${build} > version.cpp && \
_run diff "${build}" version.cpp && exit 1 || \
mv -vi version.cpp ${build}
git add ${build}
done
_run git commit -S -m "Set version to ${new_version}"
_run git log --oneline --first-parent ${release_branch}^..
cat << PUSH
-------------------------------------------------------------------
This script will not push to remote. Verify everything is correct,
then push, and create a PR as described in CONTRIBUTING.md.
-------------------------------------------------------------------
PUSH

View File

@@ -1466,10 +1466,7 @@ admin = 127.0.0.1
protocol = http
[port_peer]
# Many servers still use the legacy port of 51235, so for backward-compatibility
# we maintain that port number here. However, for new servers we recommend
# changing this to the default port of 2459.
port = 51235
port = 2459
ip = 0.0.0.0
# alternatively, to accept connections on IPv4 + IPv6, use:
#ip = ::

View File

@@ -67,7 +67,6 @@ target_link_libraries(
Xrpl::opts
Xrpl::syslibs
secp256k1::secp256k1
wasmi::wasmi
xrpl.libpb
xxHash::xxhash
$<$<BOOL:${voidstar}>:antithesis-sdk-cpp>

View File

@@ -3,8 +3,6 @@
"requires": [
"zlib/1.3.2#1cb806da49011867778ffb6ac7190fcb%1777558780.503",
"xxhash/0.8.3#681d36a0a6111fc56e5e45ea182c19cc%1765850149.987",
"wasmi/1.0.9#1fecdab9b90c96698eb35ea99ca4f5cb%1772227278.324",
"sqlite3/3.53.0#324ada52333108388a9a6108bfa96734%1776096494.149",
"soci/4.0.3#fe32b9ad5eb47e79ab9e45a68f363945%1774450067.231",
"snappy/1.1.10#968fef506ff261592ec30c574d4a7809%1765850147.878",

View File

@@ -34,7 +34,6 @@ class Xrpl(ConanFile):
"openssl/3.6.2",
"secp256k1/0.7.1",
"soci/4.0.3",
"wasmi/1.0.9",
"zlib/1.3.2",
]
@@ -215,7 +214,6 @@ class Xrpl(ConanFile):
"soci::soci",
"secp256k1::secp256k1",
"sqlite3::sqlite",
"wasmi::wasmi",
"xxhash::xxhash",
"zlib::zlib",
]

View File

@@ -7,7 +7,6 @@ ignorePaths:
- cmake/**
- LICENSE.md
- .clang-tidy
- src/test/app/wasm_fixtures/*.c
language: en
allowCompoundWords: true # TODO (#6334)
ignoreRandomStrings: true
@@ -66,7 +65,6 @@ words:
- Btrfs
- Buildx
- canonicality
- cdylib
- changespq
- checkme
- choco
@@ -269,7 +267,6 @@ words:
- STATSDCOLLECTOR
- stissue
- stnum
- stnumber
- stobj
- stobject
- stpath
@@ -329,7 +326,6 @@ words:
- wthread
- xbridge
- xchain
- xfloat
- ximinez
- XMACRO
- xrpkuwait

View File

@@ -251,12 +251,6 @@ constexpr std::uint8_t kVaultMaximumIouScale = 18;
* another vault; counted from 0 */
constexpr std::uint8_t kMaxAssetCheckDepth = 5;
/** Maximum length of a Data field in Escrow object that can be updated by WASM code. */
constexpr std::size_t kMaxWasmDataLength = 1 * 1024; // 1KB
/** Maximum amount of data transfer across hostfunction<->wasm border. */
constexpr std::size_t kWasmTransferLimit = 1 << 20; // 1MB
/** A ledger index. */
using LedgerIndex = std::uint32_t;

View File

@@ -127,9 +127,7 @@ enum TEMcodes : TERUnderlyingType {
temARRAY_TOO_LARGE,
temBAD_TRANSFER_FEE,
temINVALID_INNER_BATCH,
temBAD_MPT,
temBAD_WASM,
};
//------------------------------------------------------------------------------
@@ -360,7 +358,6 @@ enum TECcodes : TERUnderlyingType {
tecLIMIT_EXCEEDED = 195,
tecPSEUDO_ACCOUNT = 196,
tecPRECISION_LOSS = 197,
tecOUT_OF_GAS = 200,
};
//------------------------------------------------------------------------------

View File

@@ -1,37 +0,0 @@
#pragma once
#include <xrpl/basics/Expected.h>
#include <xrpl/tx/wasm/CodecEnvelope.h>
namespace xrpl::wasm {
// ─────────────────────────────────────────────────────────────────────────
// Public wasm codec API.
//
// This header is what host-function code includes. It intentionally contains
// NO codec machinery, NO registered-codec list, and NO concrete type
// registrations — only the two entry points. Their definitions are provided by
// explicit instantiation in src/libxrpl/tx/wasm/codecs/CodecRegistry.cpp, so
// including this header does not instantiate the (consteval) dispatch tables.
//
// A decode<T>/encode<T> for an unregistered T is a link error by design.
//
// To add a codec, see include/xrpl/tx/wasm/detail/codec_types.macro.
// ─────────────────────────────────────────────────────────────────────────
// Decode a value of the statically-known type T from a self-describing
// envelope. The envelope carries its own (type_code, version), so no revision
// context is needed here.
template <typename T>
[[nodiscard]] Expected<T, CodecError>
decode(CodecEnvelope const& env);
// Encode `value` toward a contract that declared codec revision
// `declaredRevision`. The wire version emitted is chosen by the revision policy
// (wireVersionFor); if the value cannot be represented in that version the
// result is NotRepresentable (the graceful-fail path).
template <typename T>
[[nodiscard]] Expected<CodecEnvelope, CodecError>
encode(CodecVersion declaredRevision, T const& value);
} // namespace xrpl::wasm

View File

@@ -1,35 +0,0 @@
#pragma once
#include <cstdint>
namespace xrpl::wasm {
using CodecTypeCode = std::uint16_t;
using CodecVersion = std::uint8_t;
using CodecLength = std::uint32_t;
enum class CodecError : std::uint8_t {
Ok = 0,
UnknownType = 1, // no type code registered for the type
UnsupportedVersion = 2, // The envelope's version has no registered codec
TypeMismatch = 3, // When decoding, the codec called does not match the type of the envelope
Truncated = 4, // payload size != fixed payload size
NotRepresentable = 5, // when encoding, the value doesn't fit within the requested version
TypeNotInRevision = 6, // There is no codec for the type in the requested version
UnknownCodecVersion = 7, // The codec version is not registered
};
// Defines the header of the binary payload for each parameter based through the host functions
struct CodecEnvelopeHeader {
CodecTypeCode type_code;
CodecVersion version;
CodecLength payload_size; // I would prefer a variable sized integer, will need to revisit this part.
};
// Defines the binary payload for each parameter based through the host functions
struct CodecEnvelope {
CodecEnvelopeHeader header;
std::uint8_t const* payload; // Unclear if this can be a pointer into the wasm payload or a vector holding a copy.
};
} // namespace xrpl::wasm

View File

@@ -1,516 +0,0 @@
#pragma once
#include <xrpl/basics/Expected.h>
#include <xrpl/basics/Slice.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Asset.h>
#include <xrpl/protocol/Keylet.h>
#include <xrpl/protocol/TER.h>
#include <xrpl/protocol/UintTypes.h>
#include <xrpl/tx/wasm/WasmCommon.h>
#include <stdexcept>
#include <string>
namespace xrpl {
namespace wasm_float {
std::string
floatToString(Slice const& data);
Expected<Bytes, HostFunctionError>
floatFromIntImpl(int64_t x, int32_t mode);
Expected<Bytes, HostFunctionError>
floatFromUintImpl(uint64_t x, int32_t mode);
Expected<Bytes, HostFunctionError>
floatFromSTAmountImpl(STAmount const& x, int32_t mode);
Expected<Bytes, HostFunctionError>
floatFromSTNumberImpl(STNumber const& x, int32_t mode);
Expected<int64_t, HostFunctionError>
floatToIntImpl(Slice const& x, int32_t mode);
Expected<FloatPair, HostFunctionError>
floatToMantExpImpl(Slice const& x);
Expected<Bytes, HostFunctionError>
floatFromMantExpImpl(int64_t mantissa, int32_t exponent, int32_t mode);
Expected<int32_t, HostFunctionError>
floatCompareImpl(Slice const& x, Slice const& y);
Expected<Bytes, HostFunctionError>
floatAddImpl(Slice const& x, Slice const& y, int32_t mode);
Expected<Bytes, HostFunctionError>
floatSubtractImpl(Slice const& x, Slice const& y, int32_t mode);
Expected<Bytes, HostFunctionError>
floatMultiplyImpl(Slice const& x, Slice const& y, int32_t mode);
Expected<Bytes, HostFunctionError>
floatDivideImpl(Slice const& x, Slice const& y, int32_t mode);
Expected<Bytes, HostFunctionError>
floatRootImpl(Slice const& x, int32_t n, int32_t mode);
Expected<Bytes, HostFunctionError>
floatPowerImpl(Slice const& x, int32_t n, int32_t mode);
} // namespace wasm_float
// Intended to work only through wasm runtime. Don't call them directly, except with unit tests
class HostFunctions
{
protected:
RTOptRef rt_;
beast::Journal j_;
public:
HostFunctions(beast::Journal j = beast::Journal{beast::Journal::getNullSink()}) : j_(j)
{
}
void
setRT(WasmRuntimeWrapper& rt)
{
rt_ = rt;
}
void
resetRT()
{
rt_ = std::nullopt;
}
[[nodiscard]] WasmRuntimeWrapper&
getRT() const
{
if (!rt_)
Throw<std::logic_error>("Wasm runtime not set");
return rt_->get();
}
[[nodiscard]] beast::Journal
getJournal() const
{
return j_;
}
// LCOV_EXCL_START
[[nodiscard]] virtual bool
checkSelf() const
{
return true;
}
virtual Expected<std::uint32_t, HostFunctionError>
getLedgerSqn() const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<std::uint32_t, HostFunctionError>
getParentLedgerTime() const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<Hash, HostFunctionError>
getParentLedgerHash() const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<uint32_t, HostFunctionError>
getBaseFee() const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<int32_t, HostFunctionError>
isAmendmentEnabled(uint256 const& amendmentId) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<int32_t, HostFunctionError>
isAmendmentEnabled(std::string_view const& amendmentName) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<int32_t, HostFunctionError>
cacheLedgerObj(uint256 const& objId, int32_t cacheIdx)
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<Bytes, HostFunctionError>
getTxField(SField const& fname) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<Bytes, HostFunctionError>
getCurrentLedgerObjField(SField const& fname) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<Bytes, HostFunctionError>
getLedgerObjField(int32_t cacheIdx, SField const& fname) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<Bytes, HostFunctionError>
getTxNestedField(FieldLocator const& locator) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<Bytes, HostFunctionError>
getCurrentLedgerObjNestedField(FieldLocator const& locator) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<Bytes, HostFunctionError>
getLedgerObjNestedField(int32_t cacheIdx, FieldLocator const& locator) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<int32_t, HostFunctionError>
getTxArrayLen(SField const& fname) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<int32_t, HostFunctionError>
getCurrentLedgerObjArrayLen(SField const& fname) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<int32_t, HostFunctionError>
getLedgerObjArrayLen(int32_t cacheIdx, SField const& fname) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<int32_t, HostFunctionError>
getTxNestedArrayLen(FieldLocator const& locator) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<int32_t, HostFunctionError>
getCurrentLedgerObjNestedArrayLen(FieldLocator const& locator) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<int32_t, HostFunctionError>
getLedgerObjNestedArrayLen(int32_t cacheIdx, FieldLocator const& locator) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<int32_t, HostFunctionError>
updateData(Slice const& data)
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<int32_t, HostFunctionError>
checkSignature(Slice const& message, Slice const& signature, Slice const& pubkey) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<Hash, HostFunctionError>
computeSha512HalfHash(Slice const& data) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<Bytes, HostFunctionError>
accountKeylet(AccountID const& account) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<Bytes, HostFunctionError>
ammKeylet(Asset const& issue1, Asset const& issue2) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<Bytes, HostFunctionError>
checkKeylet(AccountID const& account, std::uint32_t seq) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<Bytes, HostFunctionError>
credentialKeylet(AccountID const& subject, AccountID const& issuer, Slice const& credentialType)
const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<Bytes, HostFunctionError>
didKeylet(AccountID const& account) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<Bytes, HostFunctionError>
delegateKeylet(AccountID const& account, AccountID const& authorize) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<Bytes, HostFunctionError>
depositPreauthKeylet(AccountID const& account, AccountID const& authorize) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<Bytes, HostFunctionError>
escrowKeylet(AccountID const& account, std::uint32_t seq) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<Bytes, HostFunctionError>
lineKeylet(AccountID const& account1, AccountID const& account2, Currency const& currency) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<Bytes, HostFunctionError>
mptIssuanceKeylet(AccountID const& issuer, std::uint32_t seq) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<Bytes, HostFunctionError>
mptokenKeylet(MPTID const& mptid, AccountID const& holder) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<Bytes, HostFunctionError>
nftOfferKeylet(AccountID const& account, std::uint32_t seq) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<Bytes, HostFunctionError>
offerKeylet(AccountID const& account, std::uint32_t seq) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<Bytes, HostFunctionError>
oracleKeylet(AccountID const& account, std::uint32_t docId) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<Bytes, HostFunctionError>
paychanKeylet(AccountID const& account, AccountID const& destination, std::uint32_t seq) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<Bytes, HostFunctionError>
permissionedDomainKeylet(AccountID const& account, std::uint32_t seq) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<Bytes, HostFunctionError>
signersKeylet(AccountID const& account) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<Bytes, HostFunctionError>
ticketKeylet(AccountID const& account, std::uint32_t seq) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<Bytes, HostFunctionError>
vaultKeylet(AccountID const& account, std::uint32_t seq) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<Bytes, HostFunctionError>
getNFT(AccountID const& account, uint256 const& nftId) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<Bytes, HostFunctionError>
getNFTIssuer(uint256 const& nftId) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<std::uint32_t, HostFunctionError>
getNFTTaxon(uint256 const& nftId) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<int32_t, HostFunctionError>
getNFTFlags(uint256 const& nftId) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<int32_t, HostFunctionError>
getNFTTransferFee(uint256 const& nftId) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<std::uint32_t, HostFunctionError>
getNFTSerial(uint256 const& nftId) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<int32_t, HostFunctionError>
trace(std::string_view const& msg, Slice const& data, bool asHex) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<int32_t, HostFunctionError>
traceNum(std::string_view const& msg, int64_t data) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<int32_t, HostFunctionError>
traceAccount(std::string_view const& msg, AccountID const& account) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<int32_t, HostFunctionError>
traceFloat(std::string_view const& msg, Slice const& data) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<int32_t, HostFunctionError>
traceAmount(std::string_view const& msg, STAmount const& amount) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<Bytes, HostFunctionError>
floatFromInt(int64_t x, int32_t mode) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<Bytes, HostFunctionError>
floatFromUint(uint64_t x, int32_t mode) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<Bytes, HostFunctionError>
floatFromSTAmount(STAmount const& x, int32_t mode) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<Bytes, HostFunctionError>
floatFromSTNumber(STNumber const& x, int32_t mode) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<int64_t, HostFunctionError>
floatToInt(Slice const& x, int32_t mode) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<FloatPair, HostFunctionError>
floatToMantExp(Slice const& x) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<Bytes, HostFunctionError>
floatFromMantExp(int64_t mantissa, int32_t exponent, int32_t mode) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<int32_t, HostFunctionError>
floatCompare(Slice const& x, Slice const& y) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<Bytes, HostFunctionError>
floatAdd(Slice const& x, Slice const& y, int32_t mode) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<Bytes, HostFunctionError>
floatSubtract(Slice const& x, Slice const& y, int32_t mode) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<Bytes, HostFunctionError>
floatMultiply(Slice const& x, Slice const& y, int32_t mode) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<Bytes, HostFunctionError>
floatDivide(Slice const& x, Slice const& y, int32_t mode) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<Bytes, HostFunctionError>
floatRoot(Slice const& x, int32_t n, int32_t mode) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual Expected<Bytes, HostFunctionError>
floatPower(Slice const& x, int32_t n, int32_t mode) const
{
return Unexpected(HostFunctionError::Unimplemented);
}
virtual ~HostFunctions() = default;
// LCOV_EXCL_STOP
};
using HFRef = std::reference_wrapper<HostFunctions>;
} // namespace xrpl

View File

@@ -1,283 +0,0 @@
#pragma once
#include <xrpl/tx/ApplyContext.h>
#include <xrpl/tx/wasm/HostFunc.h>
namespace xrpl {
// Intended to work only through wasm runtime. Don't call them directly, except with unit tests
class WasmHostFunctionsImpl : public HostFunctions
{
ApplyContext& ctx_;
Keylet leKey_;
mutable std::optional<std::shared_ptr<SLE const>> currentLedgerObj_;
static int constexpr maxCache = 256;
std::array<std::shared_ptr<SLE const>, maxCache> cache_;
std::optional<Bytes> data_;
public:
Expected<std::shared_ptr<SLE const>, HostFunctionError>
getCurrentLedgerObj() const
{
if (!currentLedgerObj_)
currentLedgerObj_ = ctx_.view().read(leKey_);
if (*currentLedgerObj_)
return *currentLedgerObj_;
return Unexpected(HostFunctionError::LedgerObjNotFound);
}
Expected<int32_t, HostFunctionError>
normalizeCacheIndex(int32_t cacheIdx) const
{
--cacheIdx;
if (cacheIdx < 0 || cacheIdx >= maxCache)
return Unexpected(HostFunctionError::SlotOutRange);
if (!cache_[cacheIdx])
return Unexpected(HostFunctionError::EmptySlot);
return cacheIdx;
}
template <typename F>
void
log(std::string_view const& msg, F&& dataFn) const
{
#ifdef DEBUG_OUTPUT
auto& j = std::cerr;
#else
if (!getJournal().active(beast::Severity::Trace))
return;
auto j = getJournal().trace();
#endif
j << "WasmTrace[" << toShortString(leKey_.key) << "]: " << msg << " " << dataFn();
#ifdef DEBUG_OUTPUT
j << std::endl;
#endif
}
public:
WasmHostFunctionsImpl(ApplyContext& ct, Keylet const& leKey)
: HostFunctions(ct.journal), ctx_(ct), leKey_(leKey)
{
}
bool
checkSelf() const override
{
return !currentLedgerObj_ && !data_ &&
std::ranges::none_of(cache_, [](auto const& p) { return !!p; });
}
std::optional<Bytes> const&
getData() const
{
return data_;
}
Expected<std::uint32_t, HostFunctionError>
getLedgerSqn() const override;
Expected<std::uint32_t, HostFunctionError>
getParentLedgerTime() const override;
Expected<Hash, HostFunctionError>
getParentLedgerHash() const override;
Expected<std::uint32_t, HostFunctionError>
getBaseFee() const override;
Expected<int32_t, HostFunctionError>
isAmendmentEnabled(uint256 const& amendmentId) const override;
Expected<int32_t, HostFunctionError>
isAmendmentEnabled(std::string_view const& amendmentName) const override;
Expected<int32_t, HostFunctionError>
cacheLedgerObj(uint256 const& objId, int32_t cacheIdx) override;
Expected<Bytes, HostFunctionError>
getTxField(SField const& fname) const override;
Expected<Bytes, HostFunctionError>
getCurrentLedgerObjField(SField const& fname) const override;
Expected<Bytes, HostFunctionError>
getLedgerObjField(int32_t cacheIdx, SField const& fname) const override;
Expected<Bytes, HostFunctionError>
getTxNestedField(FieldLocator const& locator) const override;
Expected<Bytes, HostFunctionError>
getCurrentLedgerObjNestedField(FieldLocator const& locator) const override;
Expected<Bytes, HostFunctionError>
getLedgerObjNestedField(int32_t cacheIdx, FieldLocator const& locator) const override;
Expected<int32_t, HostFunctionError>
getTxArrayLen(SField const& fname) const override;
Expected<int32_t, HostFunctionError>
getCurrentLedgerObjArrayLen(SField const& fname) const override;
Expected<int32_t, HostFunctionError>
getLedgerObjArrayLen(int32_t cacheIdx, SField const& fname) const override;
Expected<int32_t, HostFunctionError>
getTxNestedArrayLen(FieldLocator const& locator) const override;
Expected<int32_t, HostFunctionError>
getCurrentLedgerObjNestedArrayLen(FieldLocator const& locator) const override;
Expected<int32_t, HostFunctionError>
getLedgerObjNestedArrayLen(int32_t cacheIdx, FieldLocator const& locator) const override;
Expected<int32_t, HostFunctionError>
updateData(Slice const& data) override;
Expected<int32_t, HostFunctionError>
checkSignature(Slice const& message, Slice const& signature, Slice const& pubkey)
const override;
Expected<Hash, HostFunctionError>
computeSha512HalfHash(Slice const& data) const override;
Expected<Bytes, HostFunctionError>
accountKeylet(AccountID const& account) const override;
Expected<Bytes, HostFunctionError>
ammKeylet(Asset const& issue1, Asset const& issue2) const override;
Expected<Bytes, HostFunctionError>
checkKeylet(AccountID const& account, std::uint32_t seq) const override;
Expected<Bytes, HostFunctionError>
credentialKeylet(AccountID const& subject, AccountID const& issuer, Slice const& credentialType)
const override;
Expected<Bytes, HostFunctionError>
didKeylet(AccountID const& account) const override;
Expected<Bytes, HostFunctionError>
delegateKeylet(AccountID const& account, AccountID const& authorize) const override;
Expected<Bytes, HostFunctionError>
depositPreauthKeylet(AccountID const& account, AccountID const& authorize) const override;
Expected<Bytes, HostFunctionError>
escrowKeylet(AccountID const& account, std::uint32_t seq) const override;
Expected<Bytes, HostFunctionError>
lineKeylet(AccountID const& account1, AccountID const& account2, Currency const& currency)
const override;
Expected<Bytes, HostFunctionError>
mptIssuanceKeylet(AccountID const& issuer, std::uint32_t seq) const override;
Expected<Bytes, HostFunctionError>
mptokenKeylet(MPTID const& mptid, AccountID const& holder) const override;
Expected<Bytes, HostFunctionError>
nftOfferKeylet(AccountID const& account, std::uint32_t seq) const override;
Expected<Bytes, HostFunctionError>
offerKeylet(AccountID const& account, std::uint32_t seq) const override;
Expected<Bytes, HostFunctionError>
oracleKeylet(AccountID const& account, std::uint32_t docId) const override;
Expected<Bytes, HostFunctionError>
paychanKeylet(AccountID const& account, AccountID const& destination, std::uint32_t seq)
const override;
Expected<Bytes, HostFunctionError>
permissionedDomainKeylet(AccountID const& account, std::uint32_t seq) const override;
Expected<Bytes, HostFunctionError>
signersKeylet(AccountID const& account) const override;
Expected<Bytes, HostFunctionError>
ticketKeylet(AccountID const& account, std::uint32_t seq) const override;
Expected<Bytes, HostFunctionError>
vaultKeylet(AccountID const& account, std::uint32_t seq) const override;
Expected<Bytes, HostFunctionError>
getNFT(AccountID const& account, uint256 const& nftId) const override;
Expected<Bytes, HostFunctionError>
getNFTIssuer(uint256 const& nftId) const override;
Expected<std::uint32_t, HostFunctionError>
getNFTTaxon(uint256 const& nftId) const override;
Expected<int32_t, HostFunctionError>
getNFTFlags(uint256 const& nftId) const override;
Expected<int32_t, HostFunctionError>
getNFTTransferFee(uint256 const& nftId) const override;
Expected<std::uint32_t, HostFunctionError>
getNFTSerial(uint256 const& nftId) const override;
Expected<int32_t, HostFunctionError>
trace(std::string_view const& msg, Slice const& data, bool asHex) const override;
Expected<int32_t, HostFunctionError>
traceNum(std::string_view const& msg, int64_t data) const override;
Expected<int32_t, HostFunctionError>
traceAccount(std::string_view const& msg, AccountID const& account) const override;
Expected<int32_t, HostFunctionError>
traceFloat(std::string_view const& msg, Slice const& data) const override;
Expected<int32_t, HostFunctionError>
traceAmount(std::string_view const& msg, STAmount const& amount) const override;
Expected<Bytes, HostFunctionError>
floatFromInt(int64_t x, int32_t mode) const override;
Expected<Bytes, HostFunctionError>
floatFromUint(uint64_t x, int32_t mode) const override;
Expected<Bytes, HostFunctionError>
floatFromSTAmount(STAmount const& x, int32_t mode) const override;
Expected<Bytes, HostFunctionError>
floatFromSTNumber(STNumber const& x, int32_t mode) const override;
Expected<int64_t, HostFunctionError>
floatToInt(Slice const& x, int32_t mode) const override;
Expected<FloatPair, HostFunctionError>
floatToMantExp(Slice const& x) const override;
Expected<Bytes, HostFunctionError>
floatFromMantExp(int64_t mantissa, int32_t exponent, int32_t mode) const override;
Expected<int32_t, HostFunctionError>
floatCompare(Slice const& x, Slice const& y) const override;
Expected<Bytes, HostFunctionError>
floatAdd(Slice const& x, Slice const& y, int32_t mode) const override;
Expected<Bytes, HostFunctionError>
floatSubtract(Slice const& x, Slice const& y, int32_t mode) const override;
Expected<Bytes, HostFunctionError>
floatMultiply(Slice const& x, Slice const& y, int32_t mode) const override;
Expected<Bytes, HostFunctionError>
floatDivide(Slice const& x, Slice const& y, int32_t mode) const override;
Expected<Bytes, HostFunctionError>
floatRoot(Slice const& x, int32_t n, int32_t mode) const override;
Expected<Bytes, HostFunctionError>
floatPower(Slice const& x, int32_t n, int32_t mode) const override;
};
} // namespace xrpl

View File

@@ -1,254 +0,0 @@
#pragma once
#include <xrpl/tx/wasm/WasmImportsHelper.h>
#include <wasm.h>
#include <cstdint>
namespace xrpl {
#define WASM_CB_PARAMS_LIST void *env, wasm_val_vec_t const *params, wasm_val_vec_t *results
#define WASM_SECONDARY_CB_PARAMS_LIST \
HostFunctions &hf, wasm_val_vec_t const *params, wasm_val_vec_t *results
wasm_trap_t* HostFuncMain_wrap(WASM_CB_PARAMS_LIST);
using getLedgerSqn_proto = int32_t(uint8_t*, int32_t);
wasm_trap_t* getLedgerSqn_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using getParentLedgerTime_proto = int32_t(uint8_t*, int32_t);
wasm_trap_t* getParentLedgerTime_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using getParentLedgerHash_proto = int32_t(uint8_t*, int32_t);
wasm_trap_t* getParentLedgerHash_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using getBaseFee_proto = int32_t(uint8_t*, int32_t);
wasm_trap_t* getBaseFee_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using isAmendmentEnabled_proto = int32_t(uint8_t const*, int32_t);
wasm_trap_t* isAmendmentEnabled_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using cacheLedgerObj_proto = int32_t(uint8_t const*, int32_t, int32_t);
wasm_trap_t* cacheLedgerObj_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using getTxField_proto = int32_t(int32_t, uint8_t*, int32_t);
wasm_trap_t* getTxField_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using getCurrentLedgerObjField_proto = int32_t(int32_t, uint8_t*, int32_t);
wasm_trap_t* getCurrentLedgerObjField_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using getLedgerObjField_proto = int32_t(int32_t, int32_t, uint8_t*, int32_t);
wasm_trap_t* getLedgerObjField_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using getTxNestedField_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t);
wasm_trap_t* getTxNestedField_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using getCurrentLedgerObjNestedField_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t);
wasm_trap_t* getCurrentLedgerObjNestedField_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using getLedgerObjNestedField_proto = int32_t(int32_t, uint8_t const*, int32_t, uint8_t*, int32_t);
wasm_trap_t* getLedgerObjNestedField_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using getTxArrayLen_proto = int32_t(int32_t);
wasm_trap_t* getTxArrayLen_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using getCurrentLedgerObjArrayLen_proto = int32_t(int32_t);
wasm_trap_t* getCurrentLedgerObjArrayLen_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using getLedgerObjArrayLen_proto = int32_t(int32_t, int32_t);
wasm_trap_t* getLedgerObjArrayLen_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using getTxNestedArrayLen_proto = int32_t(uint8_t const*, int32_t);
wasm_trap_t* getTxNestedArrayLen_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using getCurrentLedgerObjNestedArrayLen_proto = int32_t(uint8_t const*, int32_t);
wasm_trap_t* getCurrentLedgerObjNestedArrayLen_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using getLedgerObjNestedArrayLen_proto = int32_t(int32_t, uint8_t const*, int32_t);
wasm_trap_t* getLedgerObjNestedArrayLen_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using updateData_proto = int32_t(uint8_t const*, int32_t);
wasm_trap_t* updateData_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using checkSignature_proto =
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t const*, int32_t);
wasm_trap_t* checkSignature_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using computeSha512HalfHash_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t);
wasm_trap_t* computeSha512HalfHash_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using accountKeylet_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t);
wasm_trap_t* accountKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using ammKeylet_proto =
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t);
wasm_trap_t* ammKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using checkKeylet_proto =
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t);
wasm_trap_t* checkKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using credentialKeylet_proto = int32_t(
uint8_t const*,
int32_t,
uint8_t const*,
int32_t,
uint8_t const*,
int32_t,
uint8_t*,
int32_t);
wasm_trap_t* credentialKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using delegateKeylet_proto =
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t);
wasm_trap_t* delegateKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using depositPreauthKeylet_proto =
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t);
wasm_trap_t* depositPreauthKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using didKeylet_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t);
wasm_trap_t* didKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using escrowKeylet_proto =
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t);
wasm_trap_t* escrowKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using lineKeylet_proto = int32_t(
uint8_t const*,
int32_t,
uint8_t const*,
int32_t,
uint8_t const*,
int32_t,
uint8_t*,
int32_t);
wasm_trap_t* lineKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using mptIssuanceKeylet_proto =
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t);
wasm_trap_t* mptIssuanceKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using mptokenKeylet_proto =
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t);
wasm_trap_t* mptokenKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using nftOfferKeylet_proto =
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t);
wasm_trap_t* nftOfferKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using offerKeylet_proto =
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t);
wasm_trap_t* offerKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using oracleKeylet_proto =
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t);
wasm_trap_t* oracleKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using paychanKeylet_proto = int32_t(
uint8_t const*,
int32_t,
uint8_t const*,
int32_t,
uint8_t const*,
int32_t,
uint8_t*,
int32_t);
wasm_trap_t* paychanKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using permissionedDomainKeylet_proto =
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t);
wasm_trap_t* permissionedDomainKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using signersKeylet_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t);
wasm_trap_t* signersKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using ticketKeylet_proto =
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t);
wasm_trap_t* ticketKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using vaultKeylet_proto =
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t);
wasm_trap_t* vaultKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using getNFT_proto = int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t);
wasm_trap_t* getNFT_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using getNFTIssuer_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t);
wasm_trap_t* getNFTIssuer_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using getNFTTaxon_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t);
wasm_trap_t* getNFTTaxon_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using getNFTFlags_proto = int32_t(uint8_t const*, int32_t);
wasm_trap_t* getNFTFlags_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using getNFTTransferFee_proto = int32_t(uint8_t const*, int32_t);
wasm_trap_t* getNFTTransferFee_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using getNFTSerial_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t);
wasm_trap_t* getNFTSerial_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using trace_proto = int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, int32_t);
wasm_trap_t* trace_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using traceNum_proto = int32_t(uint8_t const*, int32_t, int64_t);
wasm_trap_t* traceNum_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using traceAccount_proto = int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t);
wasm_trap_t* traceAccount_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using traceFloat_proto = int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t);
wasm_trap_t* traceFloat_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using traceAmount_proto = int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t);
wasm_trap_t* traceAmount_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using floatFromInt_proto = int32_t(int64_t, uint8_t*, int32_t, int32_t);
wasm_trap_t* floatFromInt_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using floatFromUint_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t, int32_t);
wasm_trap_t* floatFromUint_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using floatFromSTAmount_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t, int32_t);
wasm_trap_t* floatFromSTAmount_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using floatFromSTNumber_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t, int32_t);
wasm_trap_t* floatFromSTNumber_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using floatToInt_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t, int32_t);
wasm_trap_t* floatToInt_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using floatToMantExp_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t, uint8_t*, int32_t);
wasm_trap_t* floatToMantExp_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using floatFromMantExp_proto = int32_t(int64_t, int32_t, uint8_t*, int32_t, int32_t);
wasm_trap_t* floatFromMantExp_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using floatCompare_proto = int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t);
wasm_trap_t* floatCompare_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using floatAdd_proto =
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t, int32_t);
wasm_trap_t* floatAdd_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using floatSubtract_proto =
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t, int32_t);
wasm_trap_t* floatSubtract_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using floatMultiply_proto =
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t, int32_t);
wasm_trap_t* floatMultiply_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using floatDivide_proto =
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t, int32_t);
wasm_trap_t* floatDivide_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using floatRoot_proto = int32_t(uint8_t const*, int32_t, int32_t, uint8_t*, int32_t, int32_t);
wasm_trap_t* floatRoot_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
using floatPower_proto = int32_t(uint8_t const*, int32_t, int32_t, uint8_t*, int32_t, int32_t);
wasm_trap_t* floatPower_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
} // namespace xrpl

View File

@@ -1,189 +0,0 @@
# WASM Module for Programmable Escrows
This module provides WebAssembly (WASM) execution capabilities for programmable
escrows on the XRP Ledger. When an escrow is finished, the WASM code runs to
determine whether the escrow conditions are met, enabling custom programmable
logic for escrow release conditions.
For the full specification, see
[XLS-0102: WASM VM](https://xls.xrpl.org/xls/XLS-0102-wasm-vm.html).
## Architecture
The module follows a layered architecture:
```
┌─────────────────────────────────────────────────────────────┐
│ WasmEngine (WasmVM.h) │
│ runEscrowWasm(), preflightEscrowWasm() │
│ Host function registration │
├─────────────────────────────────────────────────────────────┤
│ WasmiEngine (WasmiVM.h) │
│ Low-level wasmi interpreter integration │
├─────────────────────────────────────────────────────────────┤
│ HostFuncWrapper │ HostFuncImpl │
│ C-style WASM bridges │ C++ implementations │
├─────────────────────────────────────────────────────────────┤
│ HostFunc (Interface) │
│ Abstract base class for host functions │
└─────────────────────────────────────────────────────────────┘
```
### Key Components
- **`WasmVM.h` / `detail/WasmVM.cpp`** - High-level facade providing:
- `WasmEngine` singleton that wraps the underlying WASM interpreter
- `runEscrowWasm()` - Execute WASM code for escrow finish
- `preflightEscrowWasm()` - Validate WASM code during preflight
- `createWasmImport()` - Register all host functions
- **`WasmiVM.h` / `detail/WasmiVM.cpp`** - Low-level integration with the
[wasmi](https://github.com/wasmi-labs/wasmi) WebAssembly interpreter:
- `WasmiEngine` - Manages WASM modules, instances, and execution
- Memory management and gas metering
- Function invocation and result handling
- **`HostFunc.h`** - Abstract `HostFunctions` base class defining the interface
for all callable host functions. Each method returns
`Expected<T, HostFunctionError>`.
- **`HostFuncImpl.h` / `detail/HostFuncImpl*.cpp`** - Concrete
`WasmHostFunctionsImpl` class that implements host functions with access to
`ApplyContext` for ledger state queries. Implementation split across files:
- `HostFuncImpl.cpp` - Core utilities (updateData, checkSignature, etc.)
- `HostFuncImplFloat.cpp` - Float/number arithmetic operations
- `HostFuncImplGetter.cpp` - Field access (transaction, ledger objects)
- `HostFuncImplKeylet.cpp` - Keylet construction functions
- `HostFuncImplLedgerHeader.cpp` - Ledger header info access
- `HostFuncImplNFT.cpp` - NFT-related queries
- `HostFuncImplTrace.cpp` - Debugging/tracing functions
- **`HostFuncWrapper.h` / `detail/HostFuncWrapper.cpp`** - C-style wrapper
functions that bridge WASM calls to C++ `HostFunctions` methods. Each host
function has:
- A `_proto` type alias defining the function signature
- A `_wrap` function that extracts parameters and calls the implementation
- **`ParamsHelper.h`** - Utilities for WASM parameter handling:
- `WASM_IMPORT_FUNC` / `WASM_IMPORT_FUNC2` macros for registration
- `wasmParams()` helper for building parameter vectors
- Type conversion between WASM and C++ types
## Host Functions
Host functions allow WASM code to interact with the XRP Ledger. They are
organized into categories:
- **Ledger Information** - Access ledger sequence, timestamps, hashes, fees
- **Transaction & Ledger Object Access** - Read fields from the transaction
and ledger objects (including the current escrow object)
- **Keylet Construction** - Build keylets to look up various ledger object types
- **Cryptography** - Signature verification and hashing
- **Float Arithmetic** - Mathematical operations for amount calculations
- **NFT Operations** - Query NFT properties
- **Tracing/Debugging** - Log messages for debugging
For the complete list of available host functions, their WASM names, and gas
costs, see the [XLS-0102 specification](https://xls.xrpl.org/xls/XLS-0102-wasm-vm.html)
or `detail/WasmVM.cpp` where they are registered via `WASM_IMPORT_FUNC2` macros.
For method signatures, see `HostFunc.h`.
## Gas Model
Each host function has an associated gas cost. The gas cost is specified when
registering the function in `detail/WasmVM.cpp`:
```cpp
WASM_IMPORT_FUNC2(i, getLedgerSqn, "get_ledger_sqn", hfs, 60);
// ^^ gas cost
```
WASM execution is metered, and if the gas limit is exceeded, execution fails.
## Entry Point
The WASM module must export a function with the name defined by
`ESCROW_FUNCTION_NAME` (currently `"finish"`). This function:
- Takes no parameters (or parameters passed via host function calls)
- Returns an `int32_t`:
- `1` (or positive): Escrow conditions are met, allow finish
- `0` (or negative): Escrow conditions are not met, reject finish
## Adding a New Host Function
To add a new host function, follow these steps:
### 1. Add to HostFunc.h (Base Class)
Add a virtual method declaration with a default implementation that returns an
error:
```cpp
virtual Expected<ReturnType, HostFunctionError>
myNewFunction(ParamType1 param1, ParamType2 param2)
{
return Unexpected(HostFunctionError::INTERNAL);
}
```
### 2. Add to HostFuncImpl.h (Declaration)
Add the method override declaration in `WasmHostFunctionsImpl`:
```cpp
Expected<ReturnType, HostFunctionError>
myNewFunction(ParamType1 param1, ParamType2 param2) override;
```
### 3. Implement in detail/HostFuncImpl\*.cpp
Add the implementation in the appropriate file:
```cpp
Expected<ReturnType, HostFunctionError>
WasmHostFunctionsImpl::myNewFunction(ParamType1 param1, ParamType2 param2)
{
// Implementation using ctx (ApplyContext) for ledger access
return result;
}
```
### 4. Add Wrapper to HostFuncWrapper.h
Add the prototype and wrapper declaration:
```cpp
using myNewFunction_proto = int32_t(uint8_t const*, int32_t, ...);
wasm_trap_t*
myNewFunction_wrap(void* env, wasm_val_vec_t const* params, wasm_val_vec_t* results);
```
### 5. Implement Wrapper in detail/HostFuncWrapper.cpp
Implement the C-style wrapper that bridges WASM to C++:
```cpp
wasm_trap_t*
myNewFunction_wrap(void* env, wasm_val_vec_t const* params, wasm_val_vec_t* results)
{
// Extract parameters from params
// Call hfs->myNewFunction(...)
// Set results and return
}
```
### 6. Register in WasmVM.cpp
Add the function registration in `setCommonHostFunctions()` or
`createWasmImport()`:
```cpp
WASM_IMPORT_FUNC2(i, myNewFunction, "my_new_function", hfs, 100);
// ^^ WASM name ^^ gas cost
```
> [!IMPORTANT]
> New host functions MUST be amendment-gated in `WasmVM.cpp`.
> Wrap the registration in an amendment check to ensure the function is only
> available after the corresponding amendment is enabled on the network.

View File

@@ -1,237 +0,0 @@
#pragma once
#include <xrpl/basics/base_uint.h>
#include <xrpl/basics/contract.h>
#include <xrpl/protocol/TER.h>
#include <functional>
#include <optional>
#include <stdexcept>
#include <string_view>
#include <vector>
namespace xrpl {
using Bytes = std::vector<std::uint8_t>;
using Hash = xrpl::uint256;
using FloatPair = std::pair<int64_t, int32_t>;
// Error signals that cross the wasm boundary as trap messages (the C API has no
// trap code). WasmiEngine::call maps them to TER: hfErrInternal -> tecINTERNAL,
// hfErrOutOfGas / wasmi's OutOfFuel -> tecOUT_OF_GAS, anything else ->
// tecFAILED_PROCESSING.
//
// Matched as substrings, not by equality: the C API returns the Rust Debug form
// of the error, e.g. `Error { kind: Message("HfInternal") }` or
// `Error { kind: TrapCode(OutOfFuel) }`.
std::string_view inline constexpr hfErrInternal = "HfInternal";
std::string_view inline constexpr hfErrOutOfGas = "HfOutOfGas";
std::string_view inline constexpr wasmiTrapOutOfFuel = "OutOfFuel";
enum class HostFunctionError : int32_t {
Unimplemented = -1,
FieldNotFound = -2,
BufferTooSmall = -3,
NoArray = -4,
NotLeafField = -5,
LocatorMalformed = -6,
SlotOutRange = -7,
SlotsFull = -8,
EmptySlot = -9,
LedgerObjNotFound = -10,
OutOfTransferLimit = -11,
DataFieldTooLarge = -12,
PointerOutOfBounds = -13,
NoMemExported = -14,
InvalidParams = -15,
InvalidAccount = -16,
InvalidField = -17,
IndexOutOfBounds = -18,
FloatInputMalformed = -19,
FloatComputationError = -20,
};
enum class WasmTypes { WtI32, WtI64 };
struct Wmem
{
std::uint8_t* p = nullptr;
std::size_t s = 0;
Wmem() = default;
Wmem(void* ptr, std::size_t size) : p(reinterpret_cast<std::uint8_t*>(ptr)), s(size)
{
}
};
template <typename T>
struct WasmResult
{
T result;
int64_t cost;
};
using EscrowResult = WasmResult<int32_t>;
// Engine error when wasm does not run to completion. `cost` is the gas consumed
// when meaningful (tecOUT_OF_GAS / tecFAILED_PROCESSING; caller writes it to tx
// metadata); std::nullopt for tecINTERNAL and malformed input (no gas reported).
struct WasmTER
{
TER ter;
std::optional<int64_t> cost;
};
class FieldLocator
{
int32_t const* ptr_ = nullptr;
uint32_t size_ = 0;
std::vector<int32_t> buf_;
public:
FieldLocator(std::vector<int32_t>&& buf)
: ptr_(&buf[0]), size_(buf.size()), buf_(std::move(buf))
{
}
FieldLocator(int32_t const* ptr, uint32_t const size) : ptr_(ptr), size_(size)
{
}
FieldLocator(FieldLocator const&) = delete;
FieldLocator&
operator=(FieldLocator const&) = delete;
FieldLocator(FieldLocator&&) = default;
FieldLocator&
operator=(FieldLocator&&) = default;
int32_t
operator[](unsigned i) const
{
if (i >= size_)
Throw<std::runtime_error>("index out of bounds");
return ptr_[i];
}
[[nodiscard]] uint32_t
size() const
{
return size_;
}
[[nodiscard]] int32_t const*
data() const
{
return ptr_;
}
[[nodiscard]] bool
empty() const
{
return size_ == 0;
}
};
class WasmRuntimeWrapper
{
public:
virtual ~WasmRuntimeWrapper() = default;
virtual Wmem
getMem() = 0;
virtual std::int64_t
getGas() = 0;
virtual std::int64_t
setGas(std::int64_t gas) = 0;
virtual std::int64_t
getTransferLimit() = 0;
virtual std::int64_t
setTransferLimit(std::int64_t transferLimit) = 0;
};
using RTOptRef = std::optional<std::reference_wrapper<WasmRuntimeWrapper>>;
struct WasmParam
{
// We are not supporting float/double
WasmTypes type = WasmTypes::WtI32;
union
{
std::int32_t i32;
std::int64_t i64 = 0;
} of;
};
template <class... Types>
inline void
wasmParamsHlp(std::vector<WasmParam>& v, std::int32_t p, Types&&... args)
{
v.push_back({.type = WasmTypes::WtI32, .of = {.i32 = p}});
wasmParamsHlp(v, std::forward<Types>(args)...);
}
template <class... Types>
inline void
wasmParamsHlp(std::vector<WasmParam>& v, std::int64_t p, Types&&... args)
{
v.push_back({.type = WasmTypes::WtI64, .of = {.i64 = p}});
wasmParamsHlp(v, std::forward<Types>(args)...);
}
inline void
wasmParamsHlp(std::vector<WasmParam>& v)
{
return;
}
template <class... Types>
inline std::vector<WasmParam>
wasmParams(Types&&... args)
{
std::vector<WasmParam> v;
v.reserve(sizeof...(args));
wasmParamsHlp(v, std::forward<Types>(args)...);
return v;
}
template <typename T, size_t Size = sizeof(T)>
constexpr T
adjustWasmEndianessHlp(T x)
{
static_assert(std::is_integral_v<T>, "Only integral types");
if constexpr (Size > 1)
{
using U = std::make_unsigned_t<T>;
U u = static_cast<U>(x);
U const low = (u & 0xFF) << ((Size - 1) << 3);
u = adjustWasmEndianessHlp<U, Size - 1>(u >> 8);
return static_cast<T>(low | u);
}
return x;
}
template <typename T, size_t Size = sizeof(T)>
constexpr T
adjustWasmEndianess(T x)
{
// LCOV_EXCL_START
static_assert(std::is_integral_v<T>, "Only integral types");
if constexpr (std::endian::native == std::endian::big)
{
return adjustWasmEndianessHlp(x);
}
return x;
// LCOV_EXCL_STOP
}
constexpr int32_t
hfErrorToInt(HostFunctionError e)
{
return static_cast<int32_t>(e);
}
} // namespace xrpl

View File

@@ -1,128 +0,0 @@
#pragma once
#include <xrpl/basics/base_uint.h>
#include <xrpl/tx/wasm/HostFunc.h>
#include <boost/function_types/function_arity.hpp>
#include <boost/function_types/parameter_types.hpp>
#include <boost/function_types/result_type.hpp>
#include <boost/mpl/vector.hpp>
#include <wasm.h>
namespace bft = boost::function_types;
namespace xrpl {
using wasmSecondaryCbFuncType =
wasm_trap_t*(HostFunctions&, wasm_val_vec_t const*, wasm_val_vec_t*);
struct WasmImportFunc
{
std::string_view name;
std::optional<WasmTypes> result;
std::vector<WasmTypes> params;
wasmSecondaryCbFuncType* wrap = nullptr;
uint32_t gas = 0;
};
using WasmUserData = std::pair<HFRef, WasmImportFunc>;
// string - import function name
using ImportVec = std::unordered_map<std::string_view, WasmUserData>;
template <int N, int C, typename Mpl>
void
WasmImpArgs(WasmImportFunc& e)
{
if constexpr (N < C)
{
using at = typename boost::mpl::at_c<Mpl, N>::type;
if constexpr (std::is_pointer_v<at>)
{
e.params.push_back(WasmTypes::WtI32);
}
else if constexpr (std::is_same_v<at, std::int32_t>)
{
e.params.push_back(WasmTypes::WtI32);
}
else if constexpr (std::is_same_v<at, std::int64_t>)
{
e.params.push_back(WasmTypes::WtI64);
}
else
{
static_assert(std::is_pointer_v<at>, "Unsupported argument type");
}
return WasmImpArgs<N + 1, C, Mpl>(e);
}
return;
}
template <typename>
inline constexpr bool wasmDependentFalse = false;
template <typename Rt>
void
WasmImpRet(WasmImportFunc& e)
{
if constexpr (std::is_pointer_v<Rt>)
{
e.result = WasmTypes::WtI32;
}
else if constexpr (std::is_same_v<Rt, std::int32_t>)
{
e.result = WasmTypes::WtI32;
}
else if constexpr (std::is_same_v<Rt, std::int64_t>)
{
e.result = WasmTypes::WtI64;
}
else if constexpr (std::is_void_v<Rt>)
{
e.result.reset();
}
else
{
static_assert(wasmDependentFalse<Rt>, "Unsupported return type");
}
}
template <typename F>
void
WasmImpFuncHelper(WasmImportFunc& e)
{
using rt = typename bft::result_type<F>::type;
using pt = typename bft::parameter_types<F>::type;
// typename boost::mpl::at_c<mpl, N>::type
WasmImpRet<rt>(e);
WasmImpArgs<0, bft::function_arity<F>::value, pt>(e);
// WasmImpWrap(e, std::forward<F>(f));
}
// imp_name - string literal, must have static lifetime
template <typename F>
void
WasmImpFunc(
ImportVec& v,
std::string_view impName,
wasmSecondaryCbFuncType* fWrap,
HostFunctions& hf,
uint32_t gas = 0)
{
WasmImportFunc e;
e.name = impName;
e.wrap = fWrap;
e.gas = gas;
WasmImpFuncHelper<F>(e);
v.emplace(impName, std::make_pair(HFRef(hf), std::move(e)));
}
#define WASM_IMPORT_FUNC(v, f, ...) WasmImpFunc<f##_proto>(v, #f, &f##_wrap, ##__VA_ARGS__)
// n - string literal name, must have static lifetime
#define WASM_IMPORT_FUNC2(v, f, n, ...) WasmImpFunc<f##_proto>(v, n, &f##_wrap, ##__VA_ARGS__)
} // namespace xrpl

View File

@@ -1,89 +0,0 @@
#pragma once
#include <xrpl/tx/wasm/HostFunc.h>
#include <xrpl/tx/wasm/WasmImportsHelper.h>
#include <string_view>
namespace xrpl {
std::string_view inline constexpr wEnv = "env";
std::string_view inline constexpr wHostLib = "host_lib";
std::string_view inline constexpr wMem = "memory";
std::string_view inline constexpr wStore = "store";
std::string_view inline constexpr wLoad = "load";
std::string_view inline constexpr wSize = "size";
std::string_view inline constexpr wAlloc = "allocate";
std::string_view inline constexpr wDealloc = "deallocate";
std::string_view inline constexpr wProcExit = "proc_exit";
std::string_view inline constexpr escrowFunctionName = "finish";
uint32_t inline constexpr maxPages = 128; // 8MB = 64KB*128
class WasmiEngine;
class WasmEngine
{
std::unique_ptr<WasmiEngine> const impl_;
WasmEngine();
public:
WasmEngine(WasmEngine const&) = delete;
WasmEngine(WasmEngine&&) = delete;
WasmEngine&
operator=(WasmEngine const&) = delete;
WasmEngine&
operator=(WasmEngine&&) = delete;
static WasmEngine&
instance();
Expected<WasmResult<int32_t>, WasmTER>
run(Bytes const& wasmCode,
HostFunctions& hfs,
int64_t gasLimit,
std::string_view funcName = {},
std::vector<WasmParam> const& params = {},
ImportVec const& imports = {},
beast::Journal j = beast::Journal{beast::Journal::getNullSink()});
NotTEC
check(
Bytes const& wasmCode,
HostFunctions& hfs,
std::string_view funcName,
std::vector<WasmParam> const& params = {},
ImportVec const& imports = {},
beast::Journal j = beast::Journal{beast::Journal::getNullSink()});
// Host functions helper functionality
void*
newTrap(std::string const& txt = std::string());
[[nodiscard]] beast::Journal
getJournal() const;
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
ImportVec
createWasmImport(HostFunctions& hfs);
Expected<EscrowResult, WasmTER>
runEscrowWasm(
Bytes const& wasmCode,
HostFunctions& hfs,
int64_t gasLimit,
std::string_view funcName = escrowFunctionName,
std::vector<WasmParam> const& params = {});
NotTEC
preflightEscrowWasm(
Bytes const& wasmCode,
HostFunctions& hfs,
std::string_view funcName = escrowFunctionName,
std::vector<WasmParam> const& params = {});
} // namespace xrpl

View File

@@ -1,446 +0,0 @@
#pragma once
#include <xrpl/protocol/Protocol.h>
#include <xrpl/tx/wasm/WasmVM.h>
#include <wasm.h>
#include <wasmi.h>
#include <optional>
namespace xrpl {
template <class T, void (*Create)(T*, size_t), void (*Destroy)(T*)>
class WasmVec
{
using TD = std::remove_pointer_t<decltype(T::data)>;
T vec_;
public:
WasmVec(size_t s = 0) : vec_ WASM_EMPTY_VEC
{
if (s > 0)
Create(&vec_, s); // zeroes memory
}
~WasmVec()
{
clear();
}
WasmVec(WasmVec const&) = delete;
WasmVec&
operator=(WasmVec const&) = delete;
WasmVec(WasmVec&& other) noexcept : vec_ WASM_EMPTY_VEC
{
*this = std::move(other);
}
WasmVec&
operator=(WasmVec&& other) noexcept
{
if (this != &other)
{
clear();
vec_ = other.vec_;
other.vec_ = WASM_EMPTY_VEC;
}
return *this;
}
void
clear()
{
Destroy(&vec_); // call destructor for every elements too
vec_ = WASM_EMPTY_VEC;
}
T
release()
{
T result = vec_;
vec_ = WASM_EMPTY_VEC;
return result;
}
T*
get()
{
return &vec_;
}
[[nodiscard]] T const*
get() const
{
return &vec_;
}
TD&
operator[](size_t i)
{
if (i >= vec_.size)
Throw<std::runtime_error>("Out of bound");
return vec_.data[i];
}
TD const&
operator[](size_t i) const
{
if (i >= vec_.size)
Throw<std::runtime_error>("Out of bound");
return vec_.data[i];
}
[[nodiscard]] size_t
size() const
{
return vec_.size;
}
[[nodiscard]] bool
empty() const
{
return vec_.size == 0u;
}
};
using WasmValtypeVec =
WasmVec<wasm_valtype_vec_t, &wasm_valtype_vec_new_uninitialized, &wasm_valtype_vec_delete>;
using WasmValVec = WasmVec<wasm_val_vec_t, &wasm_val_vec_new_uninitialized, &wasm_val_vec_delete>;
using WasmExternVec =
WasmVec<wasm_extern_vec_t, &wasm_extern_vec_new_uninitialized, &wasm_extern_vec_delete>;
using WasmExporttypeVec = WasmVec<
wasm_exporttype_vec_t,
&wasm_exporttype_vec_new_uninitialized,
&wasm_exporttype_vec_delete>;
using WasmImporttypeVec = WasmVec<
wasm_importtype_vec_t,
&wasm_importtype_vec_new_uninitialized,
&wasm_importtype_vec_delete>;
struct WasmiResult
{
WasmValVec r;
// Set iff the call trapped. Holds the TER the trap was classified into
// (tecINTERNAL / tecOUT_OF_GAS / tecFAILED_PROCESSING); see
// WasmiEngine::call. std::nullopt means the call returned normally.
std::optional<TER> ter;
WasmiResult(unsigned n = 0) : r(n)
{
}
WasmiResult() = delete;
~WasmiResult() = default;
WasmiResult(WasmiResult&& o) = default;
WasmiResult&
operator=(WasmiResult&& o) = default;
};
using ModulePtr = std::unique_ptr<wasm_module_t, decltype(&wasm_module_delete)>;
using InstancePtr = std::unique_ptr<wasm_instance_t, decltype(&wasm_instance_delete)>;
using EnginePtr = std::unique_ptr<wasm_engine_t, decltype(&wasm_engine_delete)>;
using StorePtr = std::unique_ptr<wasm_store_t, decltype(&wasm_store_delete)>;
using FuncInfo = std::pair<wasm_func_t const*, wasm_functype_t const*>;
class InstanceWrapper
{
wasm_store_t* store_ = nullptr;
WasmExternVec exports_;
mutable int memIdx_ = -1;
InstancePtr instance_;
beast::Journal j_ = beast::Journal(beast::Journal::getNullSink());
std::int64_t transferLimit_ = kWasmTransferLimit;
private:
static InstancePtr
init(
StorePtr& s,
ModulePtr& m,
WasmExternVec& expt,
WasmExternVec const& imports,
beast::Journal j);
public:
InstanceWrapper() : instance_(nullptr, &wasm_instance_delete) {};
InstanceWrapper(InstanceWrapper const&) = delete;
InstanceWrapper(InstanceWrapper&& o) : instance_(nullptr, &wasm_instance_delete)
{
*this = std::move(o); // LCOV_EXCL_LINE
}
InstanceWrapper(StorePtr& s, ModulePtr& m, WasmExternVec const& imports, beast::Journal j)
: store_(s.get()), instance_(init(s, m, exports_, imports, j)), j_(j)
{
}
InstanceWrapper&
operator=(InstanceWrapper&& o);
InstanceWrapper&
operator=(InstanceWrapper const&) = delete;
operator bool() const
{
return static_cast<bool>(instance_);
}
FuncInfo
getFunc(std::string_view funcName, WasmExporttypeVec const& exportTypes) const;
Wmem
getMem() const;
std::int64_t
getGas() const;
std::int64_t
setGas(std::int64_t) const;
std::int64_t
getTransferLimit() const;
std::int64_t
setTransferLimit(std::int64_t);
};
class ModuleWrapper
{
ModulePtr module_;
InstanceWrapper instanceWrap_;
WasmExporttypeVec exportTypes_;
beast::Journal j_ = beast::Journal(beast::Journal::getNullSink());
public:
// LCOV_EXCL_START
ModuleWrapper() : module_(nullptr, &wasm_module_delete)
{
}
ModuleWrapper(ModuleWrapper&& o) : module_(nullptr, &wasm_module_delete)
{
*this = std::move(o);
}
// LCOV_EXCL_STOP
ModuleWrapper&
operator=(ModuleWrapper&& o);
ModuleWrapper(
StorePtr& s,
Bytes const& wasmBin,
bool instantiate,
ImportVec const& imports,
beast::Journal j);
~ModuleWrapper() = default;
operator bool() const
{
return instanceWrap_;
}
FuncInfo
getFunc(std::string_view funcName) const
{
return instanceWrap_.getFunc(funcName, exportTypes_);
}
wasm_functype_t*
getFuncType(std::string_view funcName) const;
Wmem
getMem() const
{
return instanceWrap_.getMem();
}
InstanceWrapper&
getInstance(int i = 0)
{
return instanceWrap_;
}
InstanceWrapper const&
getInstance(int i = 0) const
{
return instanceWrap_;
}
int
addInstance(StorePtr& s, WasmExternVec const& imports)
{
instanceWrap_ = {s, module_, imports, j_};
return 0;
}
std::int64_t
getGas() const
{
return instanceWrap_ ? instanceWrap_.getGas() : -1;
}
private:
static ModulePtr
init(StorePtr& s, Bytes const& wasmBin, beast::Journal j);
WasmExternVec
buildImports(StorePtr& s, ImportVec const& imports) const;
};
class WasmiEngine
{
EnginePtr engine_;
StorePtr store_;
std::unique_ptr<ModuleWrapper> moduleWrap_;
beast::Journal j_ = beast::Journal(beast::Journal::getNullSink());
std::mutex m_; // 1 instance mutex
public:
WasmiEngine() : engine_(init()), store_(nullptr, &wasm_store_delete)
{
}
~WasmiEngine() = default;
static EnginePtr
init();
Expected<WasmResult<int32_t>, WasmTER>
run(Bytes const& wasmCode,
HostFunctions& hfs,
int64_t gas,
std::string_view funcName,
std::vector<WasmParam> const& params,
ImportVec const& imports,
beast::Journal j);
NotTEC
check(
Bytes const& wasmCode,
HostFunctions& hfs,
std::string_view funcName,
std::vector<WasmParam> const& params,
ImportVec const& imports,
beast::Journal j);
[[nodiscard]] std::int64_t
getGas() const
{
return moduleWrap_ ? moduleWrap_->getGas() : -1; // LCOV_EXCL_LINE
}
// Host functions helper functionality
wasm_trap_t*
newTrap(std::string const& msg);
// LCOV_EXCL_START
[[nodiscard]] beast::Journal
getJournal() const
{
return j_;
}
// LCOV_EXCL_STOP
private:
[[nodiscard]] InstanceWrapper&
getRT(int m = 0, int i = 0) const
{
if (!moduleWrap_)
Throw<std::runtime_error>("no module");
return moduleWrap_->getInstance(i);
}
[[nodiscard]] Wmem
getMem() const
{
return moduleWrap_ ? moduleWrap_->getMem() : Wmem();
}
Expected<WasmResult<int32_t>, WasmTER>
runHlp(
Bytes const& wasmCode,
HostFunctions& hfs,
int64_t gas,
std::string_view funcName,
std::vector<WasmParam> const& params,
ImportVec const& imports,
beast::Journal j);
NotTEC
checkHlp(
Bytes const& wasmCode,
HostFunctions& hfs,
std::string_view funcName,
std::vector<WasmParam> const& params,
ImportVec const& imports,
beast::Journal j);
int
addModule(Bytes const& wasmCode, bool instantiate, ImportVec const& imports, int64_t gas);
void
clearModules();
// int addInstance();
int32_t
runFunc(std::string_view const funcName, int32_t p);
int32_t
makeModule(Bytes const& wasmCode, WasmExternVec const& imports = {});
[[nodiscard]] FuncInfo
getFunc(std::string_view funcName) const
{
return moduleWrap_->getFunc(funcName);
}
static std::vector<wasm_val_t>
convertParams(std::vector<WasmParam> const& params);
static int
compareParamTypes(wasm_valtype_vec_t const* ftp, std::vector<wasm_val_t> const& p);
static void
addParam(std::vector<wasm_val_t>& in, int32_t p);
static void
addParam(std::vector<wasm_val_t>& in, int64_t p);
template <int NR, class... Types>
inline WasmiResult
call(std::string_view func, Types&&... args);
template <int NR, class... Types>
inline WasmiResult
call(FuncInfo const& f, Types&&... args);
template <int NR, class... Types>
inline WasmiResult
call(FuncInfo const& f, std::vector<wasm_val_t>& in);
template <int NR, class... Types>
inline WasmiResult
call(FuncInfo const& f, std::vector<wasm_val_t>& in, std::int32_t p, Types&&... args);
template <int NR, class... Types>
inline WasmiResult
call(FuncInfo const& f, std::vector<wasm_val_t>& in, std::int64_t p, Types&&... args);
template <int NR, class... Types>
inline WasmiResult
call(
FuncInfo const& f,
std::vector<wasm_val_t>& in,
uint8_t const* d,
int32_t sz,
Types&&... args);
template <int NR, class... Types>
inline WasmiResult
call(FuncInfo const& f, std::vector<wasm_val_t>& in, Bytes const& p, Types&&... args);
};
} // namespace xrpl

View File

@@ -1,145 +0,0 @@
#pragma once
#include <xrpl/basics/Expected.h>
#include <xrpl/tx/wasm/CodecEnvelope.h>
#include <xrpl/tx/wasm/detail/CodecTypeCode.h>
#include <xrpl/tx/wasm/detail/CodecTypeTrait.h>
#include <array>
#include <cstddef>
#include <tuple>
#include <type_traits>
#include <utility>
namespace xrpl::wasm::detail {
// Sentinel that lets the registry's X-macro expansion end with a trailing
// comma: CodecList<Trait0, Trait1, CodecEnd>. Its `void` CodecType never
// matches a real type, so every table builder simply skips it.
struct CodecEnd
{
using CodecType = void;
};
template <typename Trait, typename T>
inline constexpr bool traitIsV = std::is_same_v<typename Trait::CodecType, T>;
template <typename T>
using DecodeFn = Expected<T, CodecError> (*)(CodecEnvelope const&);
template <typename T>
using EncodeFn = Expected<CodecEnvelope, CodecError> (*)(T const&);
// Highest registered version of T within List. Unregistered T ⇒ build error.
template <typename T, typename List, std::size_t... I>
consteval CodecVersion
maxVersionImpl(std::index_sequence<I...>)
{
auto v = CodecVersion{};
auto found = false;
([&] {
using Trait = std::tuple_element_t<I, List>;
if constexpr (traitIsV<Trait, T>)
{
found = true;
v = std::max(v, Trait::kVersion);
}
}(), ...);
if (!found)
{
xrpl::Throw<std::runtime_error>("wasm codec: no codec registered for this type");
}
return v;
}
template <typename T, typename List>
consteval CodecVersion
maxVersion()
{
return maxVersionImpl<T, List>(
std::make_index_sequence<std::tuple_size_v<List>>{});
}
template <typename T, typename List, std::size_t... I>
consteval auto
makeDecoderTableImpl(std::index_sequence<I...>)
{
constexpr auto n = maxVersion<T, List>() + 1;
auto table = std::array<DecodeFn<T>, n>{};
([&] {
using Trait = std::tuple_element_t<I, List>;
if constexpr (traitIsV<Trait, T>)
{
table[Trait::kVersion] = &Trait::decode;
}
}(), ...);
for (const auto& entry : table)
{
if (!entry)
{
xrpl::Throw<std::runtime_error>("wasm codec: decoder versions must be contiguous from 0");
}
}
return table;
}
template <typename T, typename List>
inline constexpr auto decoderTableV = makeDecoderTableImpl<T, List>(
std::make_index_sequence<std::tuple_size_v<List>>{});
template <typename T, typename List, std::size_t... I>
consteval auto
makeEncoderTableImpl(std::index_sequence<I...>)
{
constexpr auto n = maxVersion<T, List>() + 1;
auto table = std::array<EncodeFn<T>, n>{};
([&] {
using Trait = std::tuple_element_t<I, List>;
if constexpr (traitIsV<Trait, T>)
{
table[Trait::kVersion] = &Trait::encode;
}
}(), ...);
for (const auto& entry : table)
{
if (!entry)
{
xrpl::Throw<std::runtime_error>("wasm codec: encoder versions must be contiguous from 0");
}
}
return table;
}
template <typename T, typename List>
inline constexpr auto encoderTableV = makeEncoderTableImpl<T, List>(
std::make_index_sequence<std::tuple_size_v<List>>{});
template <typename T, typename List>
Expected<T, CodecError>
decodeImpl(CodecEnvelope const& env)
{
if (env.header.type_code != codecTypeCodeV<T>)
{
return Unexpected{CodecError::TypeMismatch};
}
auto const& table = decoderTableV<T, List>;
if (env.header.version >= table.size())
{
return Unexpected{CodecError::UnsupportedVersion};
}
return table[env.header.version](env);
}
template <typename T, typename List>
Expected<CodecEnvelope, CodecError>
encodeAt(CodecVersion wireVersion, T const& value)
{
auto const& table = encoderTableV<T, List>;
if (wireVersion >= table.size())
{
return Unexpected{CodecError::UnsupportedVersion};
}
return table[wireVersion](value);
}
} // namespace xrpl::wasm::detail

View File

@@ -1,12 +0,0 @@
#pragma once
#include <tuple>
namespace xrpl::wasm::detail {
template <typename... Traits>
struct CodecList {
using TupleType = std::tuple<Traits...>;
};
} // namespace xrpl::wasm::detail

View File

@@ -1,18 +0,0 @@
#pragma once
#include <xrpl/basics/Expected.h>
#include <xrpl/tx/wasm/CodecEnvelope.h>
namespace xrpl::wasm::detail {
// Maps a contract's declared codec revision to the per-type wire version to
// emit for `code`. This is the revision/amendment POLICY layer, kept separate
// from both the generic dispatch machinery and the concrete value codecs.
//
// Defined in src/libxrpl/tx/wasm/codecs/CodecRevisions.cpp alongside the
// concrete CodecTrait<N> revision maps. (Amendment gating via Rules is a
// deliberate TODO there — see the .cpp.)
Expected<CodecVersion, CodecError>
wireVersionFor(CodecVersion declaredRevision, CodecTypeCode code);
} // namespace xrpl::wasm::detail

View File

@@ -1,18 +0,0 @@
#pragma once
#include <xrpl/tx/wasm/CodecEnvelope.h>
namespace xrpl::wasm::detail {
template <CodecVersion Version>
struct CodecTrait;
// template <>
// struct CodecTrait<0> {
// static constexpr auto kVersion = CodecVersion{0};
// static constexpr auto versions = std::to_array<std::pair<CodecTypeCode, CodecVersion>>({
// {codecTypeCodeV<STNumber>, 0},
// });
// };
} // namespace xrpl::wasm::detail

View File

@@ -1,21 +0,0 @@
#pragma once
#include <xrpl/tx/wasm/CodecEnvelope.h>
namespace xrpl::wasm::detail {
template <typename T>
struct CodecTypeCodeOf;
// Defines a type trait for registering a type code for each
// type in the codec.
template <typename T>
inline constexpr CodecTypeCode codecTypeCodeV = CodecTypeCodeOf<T>::kCodecTypeCode;
#define XRPL_WASM_CODEC_TYPE_CODE(CppType, Code) \
template <> \
struct CodecTypeCodeOf<CppType> { \
static constexpr CodecTypeCode kCodecTypeCode = Code; \
};
} // namespace xrpl::wasm::detail

View File

@@ -1,27 +0,0 @@
#pragma once
#include <xrpl/tx/wasm/CodecEnvelope.h>
#include <limits>
namespace xrpl::wasm::detail {
// Defines a type trait for registering a specific type code and version
// encoding/decoding implementation for each type in the codec.
template <CodecTypeCode TypeCode, CodecVersion Version>
struct CodecTypeTrait;
#define XRPL_WASM_CODEC_TYPE_TRAIT(CppType, Version, PayloadSize) \
template <> \
struct CodecTypeTrait<codecTypeCodeV<CppType>, Version> { \
using CodecType = CppType; \
static constexpr auto kCodecTypeCode = codecTypeCodeV<CppType>; \
static constexpr auto kVersion = Version; \
static constexpr auto kPayloadSize = PayloadSize; \
static Expected<CodecType, CodecError> decode(CodecEnvelope const& env); \
static Expected<CodecEnvelope, CodecError> encode(CodecType const& value); \
};
inline constexpr auto kVariablePayloadSize = std::numeric_limits<CodecLength>::max();
} // namespace xrpl::wasm::detail

View File

@@ -1,48 +0,0 @@
//
// codec_revisions.macro — the SINGLE registration point for codec
// REVISIONS (the "contract-declared codec revision -> per-type wire version"
// pinning). Included multiple times with different macro definitions, so NO
// include guard.
//
// A revision fixes, for every type, which wire version a contract that declared
// that revision receives. It is deliberately SEPARATE from the (type, version)
// registry: adding a codec version does not change any revision — bumping a
// revision is its own act, tied to the amendment that enables it.
//
// CODEC_REVISION_BEGIN(Revision)
// CODEC_REVISION_ENTRY(CppType, Version) // repeated, one per type
// CODEC_REVISION_END(Revision)
//
// HOW TO ADD A REVISION (e.g. revision 1 that emits the widened Number v1):
// 1. Add a block here:
// CODEC_REVISION_BEGIN(1)
// CODEC_REVISION_ENTRY(Number, 1) // widened
// CODEC_REVISION_ENTRY(AccountID, 0) // unchanged
// CODEC_REVISION_END(1)
// 2. Gate it behind its amendment in CodecRevisions.cpp (see the
// amendment-gating TODO in wireVersionFor).
// Both CodecTrait<1> and the wireVersionFor switch case regenerate from this.
//
#ifndef CODEC_REVISION_BEGIN
#define CODEC_REVISION_BEGIN(Revision)
#endif
#ifndef CODEC_REVISION_ENTRY
#define CODEC_REVISION_ENTRY(CppType, Version)
#endif
#ifndef CODEC_REVISION_END
#define CODEC_REVISION_END(Revision)
#endif
// clang-format off
CODEC_REVISION_BEGIN(0)
CODEC_REVISION_ENTRY(Number, 0)
CODEC_REVISION_ENTRY(AccountID, 0)
CODEC_REVISION_END(0)
// clang-format on
#undef CODEC_REVISION_BEGIN
#undef CODEC_REVISION_ENTRY
#undef CODEC_REVISION_END

View File

@@ -1,58 +0,0 @@
//
// codec_types.macro — the SINGLE registration point for wasm codecs.
//
// This file is #included multiple times with different macro definitions, so
// it has NO include guard. Every codec is declared here exactly once, on two
// axes, and everything else (the trait tuple, the dispatch tables, the
// explicit instantiations, the type-code map) is generated from it — so those
// can never drift apart.
//
// CODEC_TYPE(CppType, TypeCode)
// Once per C++ type. Assigns its stable 16-bit wire type code. Drives the
// type-code map and the per-type explicit instantiations of decode/encode.
//
// CODEC_VERSION(CppType, Version, PayloadSize)
// Once per (type, version). Declares a CodecTypeTrait specialization and
// adds it to the registered-codec tuple. Versions per type MUST be
// contiguous from 0 (enforced at compile time).
//
// HOW TO ADD A CODEC
//
// A) A new VERSION of an existing type (e.g. widen Number):
// 1. Add a line here: CODEC_VERSION(Number, 1, 20)
// 2. Define its bodies in the type's .cpp (codecs/NumberCodec.cpp):
// CodecTypeTrait<codecTypeCodeV<Number>, 1>::decode/encode
// 3. If a codec revision should emit it, add an entry in
// codec_revisions.macro.
// (Versions must stay contiguous from 0, or the build fails.)
//
// B) A brand-new TYPE (e.g. STAmount):
// 1. CODEC_TYPE(STAmount, 0x0003) and CODEC_VERSION(STAmount, 0, N) here.
// 2. Add its C++ header include to codecs/CodecTypes.h.
// 3. Create codecs/STAmountCodec.cpp with the decode/encode bodies.
// (GLOB_RECURSE picks up the new .cpp automatically — no CMake edit.)
// 4. Add a CODEC_REVISION_ENTRY(STAmount, 0) to each relevant revision
// block in codec_revisions.macro.
//
#ifndef CODEC_TYPE
#define CODEC_TYPE(CppType, TypeCode)
#endif
#ifndef CODEC_VERSION
#define CODEC_VERSION(CppType, Version, PayloadSize)
#endif
// clang-format off
// C++ type wire type code
CODEC_TYPE(Number, 0x0001)
CODEC_TYPE(AccountID, 0x0002)
// C++ type version payload bytes
CODEC_VERSION(Number, 0, 12) // int64 mantissa + int32 exponent
CODEC_VERSION(AccountID, 0, 20) // 20 raw bytes
// clang-format on
#undef CODEC_TYPE
#undef CODEC_VERSION

View File

@@ -106,7 +106,6 @@ transResults()
MAKE_ERROR(tecLIMIT_EXCEEDED, "Limit exceeded."),
MAKE_ERROR(tecPSEUDO_ACCOUNT, "This operation is not allowed against a pseudo-account."),
MAKE_ERROR(tecPRECISION_LOSS, "The amounts used by the transaction cannot interact."),
MAKE_ERROR(tecOUT_OF_GAS, "The WASM code ran out of gas during execution."),
MAKE_ERROR(tefALREADY, "The exact transaction was already in this ledger."),
MAKE_ERROR(tefBAD_ADD_AUTH, "Not authorized to add account."),
@@ -200,7 +199,6 @@ transResults()
MAKE_ERROR(temARRAY_TOO_LARGE, "Malformed: Array is too large."),
MAKE_ERROR(temBAD_TRANSFER_FEE, "Malformed: Transfer fee is outside valid range."),
MAKE_ERROR(temINVALID_INNER_BATCH, "Malformed: Invalid inner batch transaction."),
MAKE_ERROR(temBAD_WASM, "Malformed: Provided WASM code is invalid."),
MAKE_ERROR(terRETRY, "Retry transaction."),
MAKE_ERROR(terFUNDS_SPENT, "DEPRECATED."),

View File

@@ -7,6 +7,7 @@
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
#include <xrpl/ledger/helpers/TokenHelpers.h>
#include <xrpl/ledger/helpers/VaultHelpers.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/Issue.h>
#include <xrpl/protocol/LedgerFormats.h>
@@ -252,19 +253,26 @@ VaultDeposit::doApply()
!isTesSuccess(ter))
return ter;
// Sanity check
if (accountHolds(
view(),
accountID_,
assetsDeposited.asset(),
FreezeHandling::IgnoreFreeze,
AuthHandling::IgnoreAuth,
j_) < beast::kZero)
// This check is wrong. Disable it with fixCleanup3_2_0.
// For XRP and MPT the predicate is structurally unsatisfiable: xrpLiquid clamps at zero, and
// MPT balances are unsigned. For IOUs it only fires when the deposit drove the depositor's
// trust line into debt the exact case preclaim authorizes via SpendableHandling::FullBalance.
// The check thus converts a preclaim- authorized deposit into tefINTERNAL after the asset
// transfer.
if (!view().rules().enabled(fixCleanup3_2_0))
{
// LCOV_EXCL_START
JLOG(j_.error()) << "VaultDeposit: negative balance of account assets.";
return tefINTERNAL;
// LCOV_EXCL_STOP
// Sanity check
if (accountHolds(
view(),
accountID_,
assetsDeposited.asset(),
FreezeHandling::IgnoreFreeze,
AuthHandling::IgnoreAuth,
j_) < beast::kZero)
{
JLOG(j_.error()) << "VaultDeposit: negative balance of account assets.";
return tefINTERNAL;
}
}
// Transfer shares from vault to depositor.

View File

@@ -1,52 +0,0 @@
#include <xrpl/tx/wasm/HostFuncImpl.h>
#include <xrpl/basics/Expected.h>
#include <xrpl/basics/Slice.h>
#include <xrpl/protocol/Protocol.h>
#include <xrpl/protocol/PublicKey.h>
#include <xrpl/protocol/digest.h>
#include <xrpl/tx/wasm/WasmCommon.h>
#include <cstdint>
namespace xrpl {
// =========================================================
// SECTION: WRITE FUNCTION
// =========================================================
Expected<int32_t, HostFunctionError>
WasmHostFunctionsImpl::updateData(Slice const& data)
{
if (data.size() > kMaxWasmDataLength)
return Unexpected(HostFunctionError::DataFieldTooLarge);
data_ = Bytes(data.begin(), data.end());
return data_->size();
}
// =========================================================
// SECTION: UTILS
// =========================================================
Expected<int32_t, HostFunctionError>
WasmHostFunctionsImpl::checkSignature(
Slice const& message,
Slice const& signature,
Slice const& pubkey) const
{
if (!publicKeyType(pubkey))
return Unexpected(HostFunctionError::InvalidParams);
PublicKey const pk(pubkey);
return verify(pk, message, signature);
}
Expected<Hash, HostFunctionError>
WasmHostFunctionsImpl::computeSha512HalfHash(Slice const& data) const
{
auto const hash = sha512Half(data);
return hash;
}
} // namespace xrpl

View File

@@ -1,594 +0,0 @@
#include <xrpl/basics/Expected.h>
#include <xrpl/basics/Number.h>
#include <xrpl/basics/Slice.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/STNumber.h>
#include <xrpl/protocol/Serializer.h>
#include <xrpl/tx/wasm/HostFunc.h>
#include <xrpl/tx/wasm/HostFuncImpl.h>
#include <xrpl/tx/wasm/WasmCommon.h>
#include <boost/algorithm/hex.hpp>
#include <cstdint>
#include <iterator>
#include <string>
#include <utility>
#ifdef _DEBUG
// #define DEBUG_OUTPUT 1
#endif
namespace xrpl {
namespace wasm_float {
namespace detail {
class WasmNumber : public Number
{
protected:
static unsigned constexpr encodedFloatSize = 12;
bool good_ = false;
public:
WasmNumber(Slice const& data)
{
if (data.size() != encodedFloatSize)
return;
try
{
SerialIter it(data);
Number const x = STNumber(it, sfNumber).value();
*static_cast<Number*>(this) = x;
}
catch (...)
{
return;
}
good_ = true;
}
WasmNumber(Number const& n) : WasmNumber(n.mantissa(), n.exponent()) // ensure Number canonized
{
}
template <class T>
WasmNumber(T mantissa = 0, int32_t exponent = 0)
{
try
{
Number n;
if constexpr (std::is_signed_v<T>)
{
n = Number(static_cast<int64_t>(mantissa), exponent);
}
else
{
n = Number(static_cast<uint64_t>(mantissa), exponent, Number::Normalized{});
}
*static_cast<Number*>(this) = n;
}
catch (...)
{
return;
}
good_ = true;
}
WasmNumber&
operator=(WasmNumber const&) = default;
explicit
operator bool() const
{
return good_;
}
explicit
operator int64_t() const
{
return Number::operator int64_t();
}
Expected<Bytes, HostFunctionError>
toBytes() const
{
Serializer msg;
STNumber(sfNumber, *this).add(msg);
auto data = msg.getData();
#ifdef DEBUG_OUTPUT
std::cout << "m: " << std::setw(20) << mantissa() << ", e: " << std::setw(12) << exponent()
<< ", hex: ";
std::cout << std::hex << std::uppercase << std::setfill('0');
for (auto const& c : data)
std::cout << std::setw(2) << (unsigned)c << " ";
std::cout << std::dec << std::setfill(' ') << std::endl;
#endif
return Expected<Bytes, HostFunctionError>(std::move(data));
}
};
struct FloatState
{
Number::RoundingMode oldMode;
bool good = false;
FloatState(int32_t mode) : oldMode(Number::getround())
{
if (mode < static_cast<int32_t>(Number::RoundingMode::ToNearest) ||
mode > static_cast<int32_t>(Number::RoundingMode::Upward))
return;
Number::setround(static_cast<Number::RoundingMode>(mode));
good = true;
}
~FloatState()
{
Number::setround(oldMode);
}
operator bool() const
{
return good;
}
};
} // namespace detail
std::string
floatToString(Slice const& data)
{
// set default mode as we don't expect it will be used here
detail::FloatState const rm(static_cast<int32_t>(Number::RoundingMode::ToNearest));
detail::WasmNumber const num(data);
if (!num)
{
std::string hex;
hex.reserve(data.size() * 2);
boost::algorithm::hex(data.begin(), data.end(), std::back_inserter(hex));
return "Invalid data: " + hex;
}
auto const s = to_string(num);
return s;
}
Expected<Bytes, HostFunctionError>
floatFromIntImpl(int64_t x, int32_t mode)
{
try
{
detail::FloatState const rm(mode);
if (!rm)
return Unexpected(HostFunctionError::FloatInputMalformed);
detail::WasmNumber const num(x);
if (!num)
return Unexpected(HostFunctionError::FloatInputMalformed); // LCOV_EXCL_LINE
auto const r = num.toBytes();
return r;
}
// LCOV_EXCL_START
catch (...)
{
return Unexpected(HostFunctionError::FloatComputationError);
}
// LCOV_EXCL_STOP
}
Expected<Bytes, HostFunctionError>
floatFromUintImpl(uint64_t x, int32_t mode)
{
try
{
detail::FloatState const rm(mode);
if (!rm)
return Unexpected(HostFunctionError::FloatInputMalformed);
detail::WasmNumber const num(x);
if (!num)
return Unexpected(HostFunctionError::FloatInputMalformed); // LCOV_EXCL_LINE
auto const r = num.toBytes();
return r;
}
// LCOV_EXCL_START
catch (...)
{
return Unexpected(HostFunctionError::FloatComputationError);
}
// LCOV_EXCL_STOP
}
Expected<Bytes, HostFunctionError>
floatFromSTAmountImpl(STAmount const& x, int32_t mode)
{
try
{
detail::FloatState const rm(mode);
if (!rm)
return Unexpected(HostFunctionError::FloatInputMalformed);
detail::WasmNumber const num(static_cast<Number>(x));
if (!num)
return Unexpected(HostFunctionError::FloatInputMalformed); // LCOV_EXCL_LINE
auto const r = num.toBytes();
return r;
}
// LCOV_EXCL_START
catch (...)
{
return Unexpected(HostFunctionError::FloatComputationError);
}
// LCOV_EXCL_STOP
}
Expected<Bytes, HostFunctionError>
floatFromSTNumberImpl(STNumber const& x, int32_t mode)
{
try
{
detail::FloatState const rm(mode);
if (!rm)
return Unexpected(HostFunctionError::FloatInputMalformed);
detail::WasmNumber const num(x.value());
if (!num)
return Unexpected(HostFunctionError::FloatInputMalformed); // LCOV_EXCL_LINE
auto const r = num.toBytes();
return r;
}
// LCOV_EXCL_START
catch (...)
{
return Unexpected(HostFunctionError::FloatComputationError);
}
// LCOV_EXCL_STOP
}
Expected<int64_t, HostFunctionError>
floatToIntImpl(Slice const& x, int32_t mode)
{
try
{
detail::FloatState const rm(mode);
if (!rm)
return Unexpected(HostFunctionError::FloatInputMalformed);
detail::WasmNumber const num(x);
if (!num)
return Unexpected(HostFunctionError::FloatInputMalformed); // LCOV_EXCL_LINE
int64_t const r(num);
return r;
}
// LCOV_EXCL_START
catch (...)
{
return Unexpected(HostFunctionError::FloatComputationError);
}
// LCOV_EXCL_STOP
}
Expected<FloatPair, HostFunctionError>
floatToMantExpImpl(Slice const& x)
{
try
{
detail::FloatState const rm(static_cast<int32_t>(Number::RoundingMode::ToNearest));
if (!rm)
return Unexpected(HostFunctionError::FloatInputMalformed);
detail::WasmNumber const num(x);
if (!num)
return Unexpected(HostFunctionError::FloatInputMalformed); // LCOV_EXCL_LINE
return FloatPair(num.mantissa(), num.exponent());
}
// LCOV_EXCL_START
catch (...)
{
return Unexpected(HostFunctionError::FloatComputationError);
}
// LCOV_EXCL_STOP
}
Expected<Bytes, HostFunctionError>
floatFromMantExpImpl(int64_t mantissa, int32_t exponent, int32_t mode)
{
try
{
detail::FloatState const rm(mode);
if (!rm)
return Unexpected(HostFunctionError::FloatInputMalformed);
detail::WasmNumber const num(mantissa, exponent);
if (!num)
return Unexpected(HostFunctionError::FloatInputMalformed);
return num.toBytes();
}
catch (...)
{
return Unexpected(HostFunctionError::FloatComputationError);
}
}
Expected<int32_t, HostFunctionError>
floatCompareImpl(Slice const& x, Slice const& y)
{
try
{
// set default mode as we don't expect it will be used here
detail::FloatState const rm(static_cast<int32_t>(Number::RoundingMode::ToNearest));
detail::WasmNumber const xx(x);
if (!xx)
return Unexpected(HostFunctionError::FloatInputMalformed);
detail::WasmNumber const yy(y);
if (!yy)
return Unexpected(HostFunctionError::FloatInputMalformed);
if (xx < yy)
return 2;
if (xx == yy)
return 0;
return 1;
}
// LCOV_EXCL_START
catch (...)
{
return Unexpected(HostFunctionError::FloatComputationError);
}
// LCOV_EXCL_STOP
}
Expected<Bytes, HostFunctionError>
floatAddImpl(Slice const& x, Slice const& y, int32_t mode)
{
try
{
detail::FloatState const rm(mode);
if (!rm)
return Unexpected(HostFunctionError::FloatInputMalformed);
detail::WasmNumber const xx(x);
if (!xx)
return Unexpected(HostFunctionError::FloatInputMalformed);
detail::WasmNumber const yy(y);
if (!yy)
return Unexpected(HostFunctionError::FloatInputMalformed);
detail::WasmNumber const res = xx + yy;
return res.toBytes();
}
// LCOV_EXCL_START
catch (...)
{
return Unexpected(HostFunctionError::FloatComputationError);
}
// LCOV_EXCL_STOP
}
Expected<Bytes, HostFunctionError>
floatSubtractImpl(Slice const& x, Slice const& y, int32_t mode)
{
try
{
detail::FloatState const rm(mode);
if (!rm)
return Unexpected(HostFunctionError::FloatInputMalformed);
detail::WasmNumber const xx(x);
if (!xx)
return Unexpected(HostFunctionError::FloatInputMalformed);
detail::WasmNumber const yy(y);
if (!yy)
return Unexpected(HostFunctionError::FloatInputMalformed);
detail::WasmNumber const res = xx - yy;
return res.toBytes();
}
// LCOV_EXCL_START
catch (...)
{
return Unexpected(HostFunctionError::FloatComputationError);
}
// LCOV_EXCL_STOP
}
Expected<Bytes, HostFunctionError>
floatMultiplyImpl(Slice const& x, Slice const& y, int32_t mode)
{
try
{
detail::FloatState const rm(mode);
if (!rm)
return Unexpected(HostFunctionError::FloatInputMalformed);
detail::WasmNumber const xx(x);
if (!xx)
return Unexpected(HostFunctionError::FloatInputMalformed);
detail::WasmNumber const yy(y);
if (!yy)
return Unexpected(HostFunctionError::FloatInputMalformed);
detail::WasmNumber const res = xx * yy;
return res.toBytes();
}
// LCOV_EXCL_START
catch (...)
{
return Unexpected(HostFunctionError::FloatComputationError);
}
// LCOV_EXCL_STOP
}
Expected<Bytes, HostFunctionError>
floatDivideImpl(Slice const& x, Slice const& y, int32_t mode)
{
try
{
detail::FloatState const rm(mode);
if (!rm)
return Unexpected(HostFunctionError::FloatInputMalformed);
detail::WasmNumber const xx(x);
if (!xx)
return Unexpected(HostFunctionError::FloatInputMalformed);
detail::WasmNumber const yy(y);
if (!yy)
return Unexpected(HostFunctionError::FloatInputMalformed);
detail::WasmNumber const res = xx / yy;
return res.toBytes();
}
catch (...)
{
return Unexpected(HostFunctionError::FloatComputationError);
}
}
Expected<Bytes, HostFunctionError>
floatRootImpl(Slice const& x, int32_t n, int32_t mode)
{
try
{
if (n < 1)
return Unexpected(HostFunctionError::FloatInputMalformed);
detail::FloatState const rm(mode);
if (!rm)
return Unexpected(HostFunctionError::FloatInputMalformed);
detail::WasmNumber const xx(x);
if (!xx)
return Unexpected(HostFunctionError::FloatInputMalformed);
detail::WasmNumber const res(root(xx, n));
return res.toBytes();
}
// LCOV_EXCL_START
catch (...)
{
return Unexpected(HostFunctionError::FloatComputationError);
}
// LCOV_EXCL_STOP
}
Expected<Bytes, HostFunctionError>
floatPowerImpl(Slice const& x, int32_t n, int32_t mode)
{
try
{
if ((n < 0) || (n > Number::kMaxExponent))
return Unexpected(HostFunctionError::FloatInputMalformed);
detail::FloatState const rm(mode);
if (!rm)
return Unexpected(HostFunctionError::FloatInputMalformed);
detail::WasmNumber const xx(x);
if (!xx)
return Unexpected(HostFunctionError::FloatInputMalformed);
if (xx == Number() && (n == 0))
return Unexpected(HostFunctionError::InvalidParams);
detail::WasmNumber const res(power(xx, n, 1));
return res.toBytes();
}
// LCOV_EXCL_START
catch (...)
{
return Unexpected(HostFunctionError::FloatComputationError);
}
// LCOV_EXCL_STOP
}
} // namespace wasm_float
// =========================================================
// ACTUAL HOST FUNCTIONS
// =========================================================
Expected<Bytes, HostFunctionError>
WasmHostFunctionsImpl::floatFromInt(int64_t x, int32_t mode) const
{
return wasm_float::floatFromIntImpl(x, mode);
}
Expected<Bytes, HostFunctionError>
WasmHostFunctionsImpl::floatFromUint(uint64_t x, int32_t mode) const
{
return wasm_float::floatFromUintImpl(x, mode);
}
Expected<Bytes, HostFunctionError>
WasmHostFunctionsImpl::floatFromSTAmount(STAmount const& x, int32_t mode) const
{
return wasm_float::floatFromSTAmountImpl(x, mode);
}
Expected<Bytes, HostFunctionError>
WasmHostFunctionsImpl::floatFromSTNumber(STNumber const& x, int32_t mode) const
{
return wasm_float::floatFromSTNumberImpl(x, mode);
}
Expected<int64_t, HostFunctionError>
WasmHostFunctionsImpl::floatToInt(Slice const& x, int32_t mode) const
{
return wasm_float::floatToIntImpl(x, mode);
}
Expected<FloatPair, HostFunctionError>
WasmHostFunctionsImpl::floatToMantExp(Slice const& x) const
{
return wasm_float::floatToMantExpImpl(x);
}
Expected<Bytes, HostFunctionError>
WasmHostFunctionsImpl::floatFromMantExp(int64_t mantissa, int32_t exponent, int32_t mode) const
{
return wasm_float::floatFromMantExpImpl(mantissa, exponent, mode);
}
Expected<int32_t, HostFunctionError>
WasmHostFunctionsImpl::floatCompare(Slice const& x, Slice const& y) const
{
return wasm_float::floatCompareImpl(x, y);
}
Expected<Bytes, HostFunctionError>
WasmHostFunctionsImpl::floatAdd(Slice const& x, Slice const& y, int32_t mode) const
{
return wasm_float::floatAddImpl(x, y, mode);
}
Expected<Bytes, HostFunctionError>
WasmHostFunctionsImpl::floatSubtract(Slice const& x, Slice const& y, int32_t mode) const
{
return wasm_float::floatSubtractImpl(x, y, mode);
}
Expected<Bytes, HostFunctionError>
WasmHostFunctionsImpl::floatMultiply(Slice const& x, Slice const& y, int32_t mode) const
{
return wasm_float::floatMultiplyImpl(x, y, mode);
}
Expected<Bytes, HostFunctionError>
WasmHostFunctionsImpl::floatDivide(Slice const& x, Slice const& y, int32_t mode) const
{
return wasm_float::floatDivideImpl(x, y, mode);
}
Expected<Bytes, HostFunctionError>
WasmHostFunctionsImpl::floatRoot(Slice const& x, int32_t n, int32_t mode) const
{
return wasm_float::floatRootImpl(x, n, mode);
}
Expected<Bytes, HostFunctionError>
WasmHostFunctionsImpl::floatPower(Slice const& x, int32_t n, int32_t mode) const
{
return wasm_float::floatPowerImpl(x, n, mode);
}
} // namespace xrpl

View File

@@ -1,400 +0,0 @@
#include <xrpl/basics/Expected.h>
#include <xrpl/basics/base_uint.h>
#include <xrpl/basics/contract.h>
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/protocol/Asset.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/MPTIssue.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/STBase.h>
#include <xrpl/protocol/STBitString.h>
#include <xrpl/protocol/STObject.h>
#include <xrpl/protocol/Serializer.h>
#include <xrpl/tx/wasm/HostFuncImpl.h>
#include <xrpl/tx/wasm/WasmCommon.h>
#include <cstdint>
#include <stdexcept>
#include <string>
#include <utility>
#include <variant>
namespace xrpl {
using FieldValue = std::variant<STBase const*, uint256 const*>;
template <class T>
Bytes
getIntBytes(STBase const* obj)
{
static_assert(std::is_integral_v<T>, "Only integral types");
XRPL_ASSERT(obj, "getIntBytes null pointer");
auto const* num(static_cast<STInteger<T> const*>(obj)); // NOLINT
T const data = adjustWasmEndianess(num->value());
uint8_t const* b = reinterpret_cast<uint8_t const*>(&data);
return Bytes{b, b + sizeof(T)};
}
static Expected<Bytes, HostFunctionError>
getAnyFieldData(STBase const* obj)
{
if (obj == nullptr)
return Unexpected(HostFunctionError::FieldNotFound);
auto const stype = obj->getSType();
switch (stype)
{
// LCOV_EXCL_START
case STI_UNKNOWN:
case STI_NOTPRESENT:
return Unexpected(HostFunctionError::FieldNotFound);
// LCOV_EXCL_STOP
case STI_OBJECT:
case STI_ARRAY:
case STI_VECTOR256:
return Unexpected(HostFunctionError::NotLeafField);
case STI_ACCOUNT: {
auto const* account(static_cast<STAccount const*>(obj)); // NOLINT
auto const& data = account->value();
return Bytes{data.begin(), data.end()};
}
case STI_ISSUE: {
auto const* issue(static_cast<STIssue const*>(obj)); // NOLINT
Asset const& asset(issue->value());
// XRP and IOU will be processed by serializer
if (asset.holds<MPTIssue>())
{
auto const& mptIssue = asset.get<MPTIssue>();
auto const& mptID = mptIssue.getMptID();
return Bytes{mptID.cbegin(), mptID.cend()};
}
break; // Use serializer
}
case STI_VL: {
auto const* vl(static_cast<STBlob const*>(obj)); // NOLINT
auto const& data = vl->value();
return Bytes{data.begin(), data.end()};
}
case STI_UINT16:
return getIntBytes<std::uint16_t>(obj);
case STI_UINT32:
return getIntBytes<std::uint32_t>(obj);
// LCOV_EXCL_START
case STI_UINT64:
return getIntBytes<std::uint64_t>(obj);
case STI_INT32:
return getIntBytes<std::int32_t>(obj);
case STI_INT64:
return getIntBytes<std::int64_t>(obj);
// LCOV_EXCL_STOP
case STI_UINT256: {
auto const* uint256Obj(static_cast<STUInt256 const*>(obj)); // NOLINT
auto const& data = uint256Obj->value();
return Bytes{data.begin(), data.end()};
}
case STI_AMOUNT:
case STI_NUMBER:
default:
break; // Use serializer
}
Serializer msg;
obj->add(msg);
return msg.getData();
}
static Expected<Bytes, HostFunctionError>
getAnyFieldData(FieldValue const& variantObj)
{
if (STBase const* const* obj = std::get_if<STBase const*>(&variantObj))
return getAnyFieldData(*obj);
if (uint256 const* const* u = std::get_if<uint256 const*>(&variantObj))
return Bytes((*u)->begin(), (*u)->end());
// Unreachable: the variant only holds the two alternatives above. If not,
// it's an xrpld bug -> tecINTERNAL (thrown, caught by HostFuncMain_wrap).
Throw<std::runtime_error>(std::string(hfErrInternal)); // LCOV_EXCL_LINE
}
static inline bool
noField(STBase const* field)
{
return (field == nullptr) || (STI_NOTPRESENT == field->getSType()) ||
(STI_UNKNOWN == field->getSType());
}
static Expected<FieldValue, HostFunctionError>
locateField(STObject const& obj, FieldLocator const& locator)
{
STBase const* field = nullptr;
auto const& knownSFields = SField::getKnownCodeToField();
{
int32_t const sfieldCode = adjustWasmEndianess(locator[0]);
auto const it = knownSFields.find(sfieldCode);
if (it == knownSFields.end())
return Unexpected(HostFunctionError::InvalidField);
auto const& fname(*it->second);
field = obj.peekAtPField(fname);
if (noField(field))
return Unexpected(HostFunctionError::FieldNotFound);
}
for (unsigned i = 1; i < locator.size(); ++i)
{
int32_t const sfieldCode = adjustWasmEndianess(locator[i]);
if (STI_ARRAY == field->getSType())
{
auto const* arr = static_cast<STArray const*>(field); // NOLINT
if (sfieldCode < 0 || std::cmp_greater_equal(sfieldCode, arr->size()))
return Unexpected(HostFunctionError::IndexOutOfBounds);
field = &(arr->operator[](sfieldCode));
}
else if (STI_OBJECT == field->getSType())
{
auto const* o = static_cast<STObject const*>(field); // NOLINT
auto const it = knownSFields.find(sfieldCode);
if (it == knownSFields.end())
return Unexpected(HostFunctionError::InvalidField);
auto const& fname(*it->second);
field = o->peekAtPField(fname);
}
else if (STI_VECTOR256 == field->getSType())
{
auto const* v = static_cast<STVector256 const*>(field); // NOLINT
if (sfieldCode < 0 || std::cmp_greater_equal(sfieldCode, v->size()))
return Unexpected(HostFunctionError::IndexOutOfBounds);
return FieldValue(&(v->operator[](sfieldCode)));
}
else // simple field must be the last one
{
return Unexpected(HostFunctionError::LocatorMalformed);
}
if (noField(field))
return Unexpected(HostFunctionError::FieldNotFound);
}
return FieldValue(field);
}
static inline Expected<int32_t, HostFunctionError>
getArrayLen(FieldValue const& variantField)
{
if (STBase const* const* field = std::get_if<STBase const*>(&variantField))
{
if ((*field)->getSType() == STI_VECTOR256)
return static_cast<STVector256 const*>(*field)->size(); // NOLINT
if ((*field)->getSType() == STI_ARRAY)
return static_cast<STArray const*>(*field)->size(); // NOLINT
}
// uint256 is not an array so that variant should still return NO_ARRAY
return Unexpected(HostFunctionError::NoArray); // LCOV_EXCL_LINE
}
Expected<int32_t, HostFunctionError>
WasmHostFunctionsImpl::cacheLedgerObj(uint256 const& objId, int32_t cacheIdx)
{
auto const& keylet = keylet::unchecked(objId);
if (cacheIdx < 0 || cacheIdx > maxCache)
return Unexpected(HostFunctionError::SlotOutRange);
if (cacheIdx == 0)
{
for (cacheIdx = 0; cacheIdx < maxCache; ++cacheIdx)
{
if (!cache_[cacheIdx])
break;
}
}
else
{
cacheIdx--; // convert to 0-based index
}
if (cacheIdx >= maxCache)
return Unexpected(HostFunctionError::SlotsFull);
cache_[cacheIdx] = ctx_.view().read(keylet);
if (!cache_[cacheIdx])
return Unexpected(HostFunctionError::LedgerObjNotFound);
return cacheIdx + 1; // return 1-based index
}
// Subsection: top level getters
Expected<Bytes, HostFunctionError>
WasmHostFunctionsImpl::getTxField(SField const& fname) const
{
return getAnyFieldData(ctx_.tx.peekAtPField(fname));
}
Expected<Bytes, HostFunctionError>
WasmHostFunctionsImpl::getCurrentLedgerObjField(SField const& fname) const
{
auto const sle = getCurrentLedgerObj();
if (!sle.has_value())
return Unexpected(sle.error());
return getAnyFieldData(sle.value()->peekAtPField(fname));
}
Expected<Bytes, HostFunctionError>
WasmHostFunctionsImpl::getLedgerObjField(int32_t cacheIdx, SField const& fname) const
{
auto const normalizedIdx = normalizeCacheIndex(cacheIdx);
if (!normalizedIdx.has_value())
return Unexpected(normalizedIdx.error());
return getAnyFieldData(cache_[normalizedIdx.value()]->peekAtPField(fname));
}
// Subsection: nested getters
Expected<Bytes, HostFunctionError>
WasmHostFunctionsImpl::getTxNestedField(FieldLocator const& locator) const
{
auto const r = locateField(ctx_.tx, locator);
if (!r)
return Unexpected(r.error());
return getAnyFieldData(r.value());
}
Expected<Bytes, HostFunctionError>
WasmHostFunctionsImpl::getCurrentLedgerObjNestedField(FieldLocator const& locator) const
{
auto const sle = getCurrentLedgerObj();
if (!sle.has_value())
return Unexpected(sle.error());
auto const r = locateField(*sle.value(), locator);
if (!r)
return Unexpected(r.error());
return getAnyFieldData(r.value());
}
Expected<Bytes, HostFunctionError>
WasmHostFunctionsImpl::getLedgerObjNestedField(int32_t cacheIdx, FieldLocator const& locator) const
{
auto const normalizedIdx = normalizeCacheIndex(cacheIdx);
if (!normalizedIdx.has_value())
return Unexpected(normalizedIdx.error());
auto const r = locateField(*cache_[normalizedIdx.value()], locator);
if (!r)
return Unexpected(r.error());
return getAnyFieldData(r.value());
}
// Subsection: array length getters
Expected<int32_t, HostFunctionError>
WasmHostFunctionsImpl::getTxArrayLen(SField const& fname) const
{
if (fname.fieldType != STI_ARRAY && fname.fieldType != STI_VECTOR256)
return Unexpected(HostFunctionError::NoArray);
auto const* field = ctx_.tx.peekAtPField(fname);
if (noField(field))
return Unexpected(HostFunctionError::FieldNotFound);
return getArrayLen(field);
}
Expected<int32_t, HostFunctionError>
WasmHostFunctionsImpl::getCurrentLedgerObjArrayLen(SField const& fname) const
{
if (fname.fieldType != STI_ARRAY && fname.fieldType != STI_VECTOR256)
return Unexpected(HostFunctionError::NoArray);
auto const sle = getCurrentLedgerObj();
if (!sle.has_value())
return Unexpected(sle.error());
auto const* field = sle.value()->peekAtPField(fname);
if (noField(field))
return Unexpected(HostFunctionError::FieldNotFound);
return getArrayLen(field);
}
Expected<int32_t, HostFunctionError>
WasmHostFunctionsImpl::getLedgerObjArrayLen(int32_t cacheIdx, SField const& fname) const
{
if (fname.fieldType != STI_ARRAY && fname.fieldType != STI_VECTOR256)
return Unexpected(HostFunctionError::NoArray);
auto const normalizedIdx = normalizeCacheIndex(cacheIdx);
if (!normalizedIdx.has_value())
return Unexpected(normalizedIdx.error());
auto const* field = cache_[normalizedIdx.value()]->peekAtPField(fname);
if (noField(field))
return Unexpected(HostFunctionError::FieldNotFound);
return getArrayLen(field);
}
// Subsection: nested array length getters
Expected<int32_t, HostFunctionError>
WasmHostFunctionsImpl::getTxNestedArrayLen(FieldLocator const& locator) const
{
auto const r = locateField(ctx_.tx, locator);
if (!r)
return Unexpected(r.error());
auto const& field = r.value();
return getArrayLen(field);
}
Expected<int32_t, HostFunctionError>
WasmHostFunctionsImpl::getCurrentLedgerObjNestedArrayLen(FieldLocator const& locator) const
{
auto const sle = getCurrentLedgerObj();
if (!sle.has_value())
return Unexpected(sle.error());
auto const r = locateField(*sle.value(), locator);
if (!r)
return Unexpected(r.error());
auto const& field = r.value();
return getArrayLen(field);
}
Expected<int32_t, HostFunctionError>
WasmHostFunctionsImpl::getLedgerObjNestedArrayLen(int32_t cacheIdx, FieldLocator const& locator)
const
{
auto const normalizedIdx = normalizeCacheIndex(cacheIdx);
if (!normalizedIdx.has_value())
return Unexpected(normalizedIdx.error());
auto const r = locateField(*cache_[normalizedIdx.value()], locator);
if (!r)
return Unexpected(r.error());
auto const& field = r.value();
return getArrayLen(field);
}
} // namespace xrpl

View File

@@ -1,222 +0,0 @@
#include <xrpl/basics/Expected.h>
#include <xrpl/basics/Slice.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Asset.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/MPTIssue.h>
#include <xrpl/protocol/Protocol.h>
#include <xrpl/protocol/UintTypes.h>
#include <xrpl/tx/wasm/HostFuncImpl.h>
#include <xrpl/tx/wasm/WasmCommon.h>
#include <cstdint>
namespace xrpl {
Expected<Bytes, HostFunctionError>
WasmHostFunctionsImpl::accountKeylet(AccountID const& account) const
{
if (!account)
return Unexpected(HostFunctionError::InvalidAccount);
auto const keylet = keylet::account(account);
return Bytes{keylet.key.begin(), keylet.key.end()};
}
Expected<Bytes, HostFunctionError>
WasmHostFunctionsImpl::ammKeylet(Asset const& issue1, Asset const& issue2) const
{
if (issue1 == issue2)
return Unexpected(HostFunctionError::InvalidParams);
// note: this should be removed with the MPT DEX amendment
if (issue1.holds<MPTIssue>() || issue2.holds<MPTIssue>())
return Unexpected(HostFunctionError::InvalidParams);
auto const keylet = keylet::amm(issue1, issue2);
return Bytes{keylet.key.begin(), keylet.key.end()};
}
Expected<Bytes, HostFunctionError>
WasmHostFunctionsImpl::checkKeylet(AccountID const& account, std::uint32_t seq) const
{
if (!account)
return Unexpected(HostFunctionError::InvalidAccount);
auto const keylet = keylet::check(account, seq);
return Bytes{keylet.key.begin(), keylet.key.end()};
}
Expected<Bytes, HostFunctionError>
WasmHostFunctionsImpl::credentialKeylet(
AccountID const& subject,
AccountID const& issuer,
Slice const& credentialType) const
{
if (!subject || !issuer)
return Unexpected(HostFunctionError::InvalidAccount);
if (credentialType.empty() || credentialType.size() > kMaxCredentialTypeLength)
return Unexpected(HostFunctionError::InvalidParams);
auto const keylet = keylet::credential(subject, issuer, credentialType);
return Bytes{keylet.key.begin(), keylet.key.end()};
}
Expected<Bytes, HostFunctionError>
WasmHostFunctionsImpl::didKeylet(AccountID const& account) const
{
if (!account)
return Unexpected(HostFunctionError::InvalidAccount);
auto const keylet = keylet::did(account);
return Bytes{keylet.key.begin(), keylet.key.end()};
}
Expected<Bytes, HostFunctionError>
WasmHostFunctionsImpl::delegateKeylet(AccountID const& account, AccountID const& authorize) const
{
if (!account || !authorize)
return Unexpected(HostFunctionError::InvalidAccount);
if (account == authorize)
return Unexpected(HostFunctionError::InvalidParams);
auto const keylet = keylet::delegate(account, authorize);
return Bytes{keylet.key.begin(), keylet.key.end()};
}
Expected<Bytes, HostFunctionError>
WasmHostFunctionsImpl::depositPreauthKeylet(AccountID const& account, AccountID const& authorize)
const
{
if (!account || !authorize)
return Unexpected(HostFunctionError::InvalidAccount);
if (account == authorize)
return Unexpected(HostFunctionError::InvalidParams);
auto const keylet = keylet::depositPreauth(account, authorize);
return Bytes{keylet.key.begin(), keylet.key.end()};
}
Expected<Bytes, HostFunctionError>
WasmHostFunctionsImpl::escrowKeylet(AccountID const& account, std::uint32_t seq) const
{
if (!account)
return Unexpected(HostFunctionError::InvalidAccount);
auto const keylet = keylet::escrow(account, seq);
return Bytes{keylet.key.begin(), keylet.key.end()};
}
Expected<Bytes, HostFunctionError>
WasmHostFunctionsImpl::lineKeylet(
AccountID const& account1,
AccountID const& account2,
Currency const& currency) const
{
if (!account1 || !account2)
return Unexpected(HostFunctionError::InvalidAccount);
if (account1 == account2)
return Unexpected(HostFunctionError::InvalidParams);
if (currency.isZero())
return Unexpected(HostFunctionError::InvalidParams);
auto const keylet = keylet::line(account1, account2, currency);
return Bytes{keylet.key.begin(), keylet.key.end()};
}
Expected<Bytes, HostFunctionError>
WasmHostFunctionsImpl::mptIssuanceKeylet(AccountID const& issuer, std::uint32_t seq) const
{
if (!issuer)
return Unexpected(HostFunctionError::InvalidAccount);
auto const keylet = keylet::mptIssuance(seq, issuer);
return Bytes{keylet.key.begin(), keylet.key.end()};
}
Expected<Bytes, HostFunctionError>
WasmHostFunctionsImpl::mptokenKeylet(MPTID const& mptid, AccountID const& holder) const
{
if (!mptid)
return Unexpected(HostFunctionError::InvalidParams);
if (!holder)
return Unexpected(HostFunctionError::InvalidAccount);
auto const keylet = keylet::mptoken(mptid, holder);
return Bytes{keylet.key.begin(), keylet.key.end()};
}
Expected<Bytes, HostFunctionError>
WasmHostFunctionsImpl::nftOfferKeylet(AccountID const& account, std::uint32_t seq) const
{
if (!account)
return Unexpected(HostFunctionError::InvalidAccount);
auto const keylet = keylet::nftoffer(account, seq);
return Bytes{keylet.key.begin(), keylet.key.end()};
}
Expected<Bytes, HostFunctionError>
WasmHostFunctionsImpl::offerKeylet(AccountID const& account, std::uint32_t seq) const
{
if (!account)
return Unexpected(HostFunctionError::InvalidAccount);
auto const keylet = keylet::offer(account, seq);
return Bytes{keylet.key.begin(), keylet.key.end()};
}
Expected<Bytes, HostFunctionError>
WasmHostFunctionsImpl::oracleKeylet(AccountID const& account, std::uint32_t documentId) const
{
if (!account)
return Unexpected(HostFunctionError::InvalidAccount);
auto const keylet = keylet::oracle(account, documentId);
return Bytes{keylet.key.begin(), keylet.key.end()};
}
Expected<Bytes, HostFunctionError>
WasmHostFunctionsImpl::paychanKeylet(
AccountID const& account,
AccountID const& destination,
std::uint32_t seq) const
{
if (!account || !destination)
return Unexpected(HostFunctionError::InvalidAccount);
if (account == destination)
return Unexpected(HostFunctionError::InvalidParams);
auto const keylet = keylet::payChan(account, destination, seq);
return Bytes{keylet.key.begin(), keylet.key.end()};
}
Expected<Bytes, HostFunctionError>
WasmHostFunctionsImpl::permissionedDomainKeylet(AccountID const& account, std::uint32_t seq) const
{
if (!account)
return Unexpected(HostFunctionError::InvalidAccount);
auto const keylet = keylet::permissionedDomain(account, seq);
return Bytes{keylet.key.begin(), keylet.key.end()};
}
Expected<Bytes, HostFunctionError>
WasmHostFunctionsImpl::signersKeylet(AccountID const& account) const
{
if (!account)
return Unexpected(HostFunctionError::InvalidAccount);
auto const keylet = keylet::signers(account);
return Bytes{keylet.key.begin(), keylet.key.end()};
}
Expected<Bytes, HostFunctionError>
WasmHostFunctionsImpl::ticketKeylet(AccountID const& account, std::uint32_t seq) const
{
if (!account)
return Unexpected(HostFunctionError::InvalidAccount);
auto const keylet = keylet::kTicket(account, seq);
return Bytes{keylet.key.begin(), keylet.key.end()};
}
Expected<Bytes, HostFunctionError>
WasmHostFunctionsImpl::vaultKeylet(AccountID const& account, std::uint32_t seq) const
{
if (!account)
return Unexpected(HostFunctionError::InvalidAccount);
auto const keylet = keylet::vault(account, seq);
return Bytes{keylet.key.begin(), keylet.key.end()};
}
} // namespace xrpl

View File

@@ -1,55 +0,0 @@
#include <xrpl/basics/Expected.h>
#include <xrpl/basics/base_uint.h>
#include <xrpl/ledger/AmendmentTable.h>
#include <xrpl/tx/wasm/HostFuncImpl.h>
#include <xrpl/tx/wasm/WasmCommon.h>
#include <cstdint>
#include <string>
#include <string_view>
namespace xrpl {
// =========================================================
// SECTION: LEDGER HEADER FUNCTIONS
// =========================================================
Expected<std::uint32_t, HostFunctionError>
WasmHostFunctionsImpl::getLedgerSqn() const
{
return ctx_.view().seq();
}
Expected<std::uint32_t, HostFunctionError>
WasmHostFunctionsImpl::getParentLedgerTime() const
{
return ctx_.view().parentCloseTime().time_since_epoch().count();
}
Expected<Hash, HostFunctionError>
WasmHostFunctionsImpl::getParentLedgerHash() const
{
return ctx_.view().header().parentHash;
}
Expected<std::uint32_t, HostFunctionError>
WasmHostFunctionsImpl::getBaseFee() const
{
return ctx_.view().fees().base.drops();
}
Expected<int32_t, HostFunctionError>
WasmHostFunctionsImpl::isAmendmentEnabled(uint256 const& amendmentId) const
{
return ctx_.view().rules().enabled(amendmentId);
}
Expected<int32_t, HostFunctionError>
WasmHostFunctionsImpl::isAmendmentEnabled(std::string_view const& amendmentName) const
{
auto const& table = ctx_.registry.get().getAmendmentTable();
auto const amendment = table.find(std::string(amendmentName));
return ctx_.view().rules().enabled(amendment);
}
} // namespace xrpl

View File

@@ -1,74 +0,0 @@
#include <xrpl/basics/Expected.h>
#include <xrpl/basics/Slice.h>
#include <xrpl/basics/base_uint.h>
#include <xrpl/ledger/helpers/NFTokenHelpers.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/nft.h>
#include <xrpl/tx/wasm/HostFuncImpl.h>
#include <xrpl/tx/wasm/WasmCommon.h>
#include <cstdint>
namespace xrpl {
// =========================================================
// SECTION: NFT UTILS
// =========================================================
Expected<Bytes, HostFunctionError>
WasmHostFunctionsImpl::getNFT(AccountID const& account, uint256 const& nftId) const
{
if (!account)
return Unexpected(HostFunctionError::InvalidAccount);
if (!nftId)
return Unexpected(HostFunctionError::InvalidParams);
auto obj = nft::findToken(ctx_.view(), account, nftId);
if (!obj)
return Unexpected(HostFunctionError::LedgerObjNotFound);
auto objUri = obj->at(~sfURI);
if (!objUri)
return Unexpected(HostFunctionError::FieldNotFound);
Slice const s = objUri->value();
return Bytes(s.begin(), s.end());
}
Expected<Bytes, HostFunctionError>
WasmHostFunctionsImpl::getNFTIssuer(uint256 const& nftId) const
{
auto const issuer = nft::getIssuer(nftId);
if (!issuer)
return Unexpected(HostFunctionError::InvalidParams);
return Bytes{issuer.begin(), issuer.end()};
}
Expected<std::uint32_t, HostFunctionError>
WasmHostFunctionsImpl::getNFTTaxon(uint256 const& nftId) const
{
return nft::toUInt32(nft::getTaxon(nftId));
}
Expected<int32_t, HostFunctionError>
WasmHostFunctionsImpl::getNFTFlags(uint256 const& nftId) const
{
return nft::getFlags(nftId);
}
Expected<int32_t, HostFunctionError>
WasmHostFunctionsImpl::getNFTTransferFee(uint256 const& nftId) const
{
return nft::getTransferFee(nftId);
}
Expected<std::uint32_t, HostFunctionError>
WasmHostFunctionsImpl::getNFTSerial(uint256 const& nftId) const
{
return nft::getSerial(nftId);
}
} // namespace xrpl

View File

@@ -1,71 +0,0 @@
#include <xrpl/basics/Expected.h>
#include <xrpl/basics/Slice.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/STAmount.h>
#include <xrpl/tx/wasm/HostFunc.h>
#include <xrpl/tx/wasm/HostFuncImpl.h>
#include <boost/algorithm/hex.hpp>
#include <cstdint>
#include <iterator>
#include <string>
#include <string_view>
#ifdef _DEBUG
// #define DEBUG_OUTPUT 1
#endif
namespace xrpl {
Expected<int32_t, HostFunctionError>
WasmHostFunctionsImpl::trace(std::string_view const& msg, Slice const& data, bool asHex) const
{
if (!asHex)
{
log(msg, [&data] {
return std::string_view(reinterpret_cast<char const*>(data.data()), data.size());
});
}
else
{
log(msg, [&data] {
std::string hex;
hex.reserve(data.size() * 2);
boost::algorithm::hex(data.begin(), data.end(), std::back_inserter(hex));
return hex;
});
}
return 0;
}
Expected<int32_t, HostFunctionError>
WasmHostFunctionsImpl::traceNum(std::string_view const& msg, int64_t data) const
{
log(msg, [data] { return data; });
return 0;
}
Expected<int32_t, HostFunctionError>
WasmHostFunctionsImpl::traceAccount(std::string_view const& msg, AccountID const& account) const
{
log(msg, [&account] { return toBase58(account); });
return 0;
}
Expected<int32_t, HostFunctionError>
WasmHostFunctionsImpl::traceFloat(std::string_view const& msg, Slice const& data) const
{
log(msg, [&data] { return wasm_float::floatToString(data); });
return 0;
}
Expected<int32_t, HostFunctionError>
WasmHostFunctionsImpl::traceAmount(std::string_view const& msg, STAmount const& amount) const
{
log(msg, [&amount] { return amount.getFullText(); });
return 0;
}
} // namespace xrpl

File diff suppressed because it is too large Load Diff

View File

@@ -1,219 +0,0 @@
#include <xrpl/tx/wasm/WasmVM.h>
#include <xrpl/basics/Expected.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/protocol/TER.h>
#include <xrpl/tx/wasm/HostFuncWrapper.h> // IWYU pragma: keep
#include <xrpl/tx/wasm/WasmCommon.h>
#include <xrpl/tx/wasm/WasmImportsHelper.h>
#include <cstdint>
#include <string>
#include <vector>
#ifdef _DEBUG
// #define DEBUG_OUTPUT 1
#endif
#include <xrpl/tx/wasm/HostFunc.h>
#include <xrpl/tx/wasm/WasmiVM.h>
#include <memory>
namespace xrpl {
// WARNING: Per XLS-0102, the host functions registered here form a stable
// ABI. Their name, semantics, parameters, and return types must NEVER be
// changed, as there may always be a program that uses it. New host functions
// may be added and existing gas costs may be adjusted, but every such change
// must be gated by an amendment.
// See XLS-0102 §6.5 (Future-Proofing):
// https://github.com/XRPLF/XRPL-Standards/tree/master/XLS-0102-wasm-vm#65-future-proofing
static void
setCommonHostFunctions(HostFunctions& hfs, ImportVec& i)
{
// clang-format off
WASM_IMPORT_FUNC2(i, getLedgerSqn, "ldgr_index", hfs, 60);
WASM_IMPORT_FUNC2(i, getParentLedgerTime, "parent_ldgr_time", hfs, 60);
WASM_IMPORT_FUNC2(i, getParentLedgerHash, "parent_ldgr_hash", hfs, 60);
WASM_IMPORT_FUNC2(i, getBaseFee, "base_fee", hfs, 60);
WASM_IMPORT_FUNC2(i, isAmendmentEnabled, "amendment_enabled", hfs, 100);
WASM_IMPORT_FUNC2(i, cacheLedgerObj, "cache_le", hfs, 5'000);
WASM_IMPORT_FUNC2(i, getTxField, "tx_field", hfs, 70);
WASM_IMPORT_FUNC2(i, getCurrentLedgerObjField, "home_le_field", hfs, 70);
WASM_IMPORT_FUNC2(i, getLedgerObjField, "le_field", hfs, 70);
WASM_IMPORT_FUNC2(i, getTxNestedField, "tx_inner", hfs, 110);
WASM_IMPORT_FUNC2(i, getCurrentLedgerObjNestedField, "home_le_inner", hfs, 110);
WASM_IMPORT_FUNC2(i, getLedgerObjNestedField, "le_inner", hfs, 110);
WASM_IMPORT_FUNC2(i, getTxArrayLen, "tx_arr_len", hfs, 40);
WASM_IMPORT_FUNC2(i, getCurrentLedgerObjArrayLen, "home_le_arr_len", hfs, 40);
WASM_IMPORT_FUNC2(i, getLedgerObjArrayLen, "le_arr_len", hfs, 40);
WASM_IMPORT_FUNC2(i, getTxNestedArrayLen, "tx_inner_arr_len", hfs, 70);
WASM_IMPORT_FUNC2(i, getCurrentLedgerObjNestedArrayLen, "home_le_inner_arr_len", hfs, 70);
WASM_IMPORT_FUNC2(i, getLedgerObjNestedArrayLen, "le_inner_arr_len", hfs, 70);
WASM_IMPORT_FUNC2(i, checkSignature, "check_sig", hfs, 300);
WASM_IMPORT_FUNC2(i, computeSha512HalfHash, "sha512_half", hfs, 2000);
WASM_IMPORT_FUNC2(i, accountKeylet, "accountroot_id", hfs, 350);
WASM_IMPORT_FUNC2(i, ammKeylet, "amm_id", hfs, 450);
WASM_IMPORT_FUNC2(i, checkKeylet, "check_id", hfs, 350);
WASM_IMPORT_FUNC2(i, credentialKeylet, "credential_id", hfs, 350);
WASM_IMPORT_FUNC2(i, delegateKeylet, "delegate_id", hfs, 350);
WASM_IMPORT_FUNC2(i, depositPreauthKeylet, "deposit_preauth_id", hfs, 350);
WASM_IMPORT_FUNC2(i, didKeylet, "did_id", hfs, 350);
WASM_IMPORT_FUNC2(i, escrowKeylet, "escrow_id", hfs, 350);
WASM_IMPORT_FUNC2(i, lineKeylet, "trustline_id", hfs, 400);
WASM_IMPORT_FUNC2(i, mptIssuanceKeylet, "mpt_issuance_id", hfs, 350);
WASM_IMPORT_FUNC2(i, mptokenKeylet, "mptoken_id", hfs, 500);
WASM_IMPORT_FUNC2(i, nftOfferKeylet, "nft_offer_id", hfs, 350);
WASM_IMPORT_FUNC2(i, offerKeylet, "offer_id", hfs, 350);
WASM_IMPORT_FUNC2(i, oracleKeylet, "oracle_id", hfs, 350);
WASM_IMPORT_FUNC2(i, paychanKeylet, "paychan_id", hfs, 350);
WASM_IMPORT_FUNC2(i, permissionedDomainKeylet, "permissioned_domain_id", hfs, 350);
WASM_IMPORT_FUNC2(i, signersKeylet, "signers_id", hfs, 350);
WASM_IMPORT_FUNC2(i, ticketKeylet, "ticket_id", hfs, 350);
WASM_IMPORT_FUNC2(i, vaultKeylet, "vault_id", hfs, 350);
WASM_IMPORT_FUNC2(i, getNFT, "nft_uri", hfs, 5'000);
WASM_IMPORT_FUNC2(i, getNFTIssuer, "nft_issuer", hfs, 70);
WASM_IMPORT_FUNC2(i, getNFTTaxon, "nft_taxon", hfs, 60);
WASM_IMPORT_FUNC2(i, getNFTFlags, "nft_flags", hfs, 60);
WASM_IMPORT_FUNC2(i, getNFTTransferFee, "nft_xfer_fee", hfs, 60);
WASM_IMPORT_FUNC2(i, getNFTSerial, "nft_serial", hfs, 60);
WASM_IMPORT_FUNC (i, trace, hfs, 500);
WASM_IMPORT_FUNC2(i, traceNum, "trace_num", hfs, 500);
WASM_IMPORT_FUNC2(i, traceAccount, "trace_acct", hfs, 500);
WASM_IMPORT_FUNC2(i, traceFloat, "trace_xfloat", hfs, 500);
WASM_IMPORT_FUNC2(i, traceAmount, "trace_amt", hfs, 500);
WASM_IMPORT_FUNC2(i, floatFromInt, "float_from_int", hfs, 100);
WASM_IMPORT_FUNC2(i, floatFromUint, "float_from_uint", hfs, 130);
WASM_IMPORT_FUNC2(i, floatFromSTAmount, "float_from_stamount", hfs, 150);
WASM_IMPORT_FUNC2(i, floatFromSTNumber, "float_from_stnumber", hfs, 150);
WASM_IMPORT_FUNC2(i, floatToInt, "float_to_int", hfs, 130);
WASM_IMPORT_FUNC2(i, floatToMantExp, "float_to_mant_exp", hfs, 130);
WASM_IMPORT_FUNC2(i, floatFromMantExp, "float_from_mant_exp", hfs, 100);
WASM_IMPORT_FUNC2(i, floatCompare, "float_cmp", hfs, 80);
WASM_IMPORT_FUNC2(i, floatAdd, "float_add", hfs, 160);
WASM_IMPORT_FUNC2(i, floatSubtract, "float_sub", hfs, 160);
WASM_IMPORT_FUNC2(i, floatMultiply, "float_mult", hfs, 300);
WASM_IMPORT_FUNC2(i, floatDivide, "float_div", hfs, 300);
WASM_IMPORT_FUNC2(i, floatRoot, "float_root", hfs, 5'500);
WASM_IMPORT_FUNC2(i, floatPower, "float_pow", hfs, 5'500);
// clang-format on
}
ImportVec
createWasmImport(HostFunctions& hfs)
{
ImportVec i;
setCommonHostFunctions(hfs, i);
WASM_IMPORT_FUNC2(i, updateData, "set_data", hfs, 1000);
return i;
}
Expected<EscrowResult, WasmTER>
runEscrowWasm(
Bytes const& wasmCode,
HostFunctions& hfs,
int64_t gasLimit,
std::string_view funcName,
std::vector<WasmParam> const& params)
{
// create VM and set cost limit
auto& vm = WasmEngine::instance();
// vm.initMaxPages(MAX_PAGES);
auto const ret =
vm.run(wasmCode, hfs, gasLimit, funcName, params, createWasmImport(hfs), hfs.getJournal());
if (!ret)
{
#ifdef DEBUG_OUTPUT
std::cout << ", error: " << ret.error().ter << std::endl;
#endif
// Carries the TER (tecOUT_OF_GAS / tecFAILED_PROCESSING / tecINTERNAL /
// temBAD_AMOUNT) and, when meaningful, the gas consumed. The caller is
// responsible for writing that gas to tx metadata.
return Unexpected(ret.error());
}
#ifdef DEBUG_OUTPUT
std::cout << ", ret: " << ret->result << ", gas spent: " << ret->cost << std::endl;
#endif
return EscrowResult{.result = ret->result, .cost = ret->cost};
}
NotTEC
preflightEscrowWasm(
Bytes const& wasmCode,
HostFunctions& hfs,
std::string_view funcName,
std::vector<WasmParam> const& params)
{
// create VM and set cost limit
auto& vm = WasmEngine::instance();
// vm.initMaxPages(MAX_PAGES);
auto const ret =
vm.check(wasmCode, hfs, funcName, params, createWasmImport(hfs), hfs.getJournal());
return ret;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
WasmEngine::WasmEngine() : impl_(std::make_unique<WasmiEngine>())
{
}
WasmEngine&
WasmEngine::instance()
{
static WasmEngine e;
return e;
}
Expected<WasmResult<int32_t>, WasmTER>
WasmEngine::run(
Bytes const& wasmCode,
HostFunctions& hfs,
int64_t gasLimit,
std::string_view funcName,
std::vector<WasmParam> const& params,
ImportVec const& imports,
beast::Journal j)
{
return impl_->run(wasmCode, hfs, gasLimit, funcName, params, imports, j);
}
NotTEC
WasmEngine::check(
Bytes const& wasmCode,
HostFunctions& hfs,
std::string_view funcName,
std::vector<WasmParam> const& params,
ImportVec const& imports,
beast::Journal j)
{
return impl_->check(wasmCode, hfs, funcName, params, imports, j);
}
void*
WasmEngine::newTrap(std::string const& msg)
{
return impl_->newTrap(msg);
}
// LCOV_EXCL_START
beast::Journal
WasmEngine::getJournal() const
{
return impl_->getJournal();
}
// LCOV_EXCL_STOP
} // namespace xrpl

View File

@@ -1,957 +0,0 @@
#include <xrpl/tx/wasm/WasmiVM.h>
#include <xrpl/basics/Expected.h>
#include <xrpl/basics/contract.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/protocol/TER.h>
#include <xrpl/tx/wasm/HostFunc.h>
#include <xrpl/tx/wasm/WasmCommon.h>
#include <xrpl/tx/wasm/WasmImportsHelper.h>
#include <xrpl/tx/wasm/WasmVM.h>
#include <wasmi/config.h>
#include <wasmi/error.h>
#include <wasm.h>
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <exception>
#include <limits>
#include <memory>
#include <mutex>
#include <optional>
#include <stdexcept>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
#ifdef _DEBUG
// #define DEBUG_OUTPUT 1
#endif
// #define SHOW_CALL_TIME 1
namespace xrpl {
wasm_trap_t*
HostFuncMain_wrap(void* env, wasm_val_vec_t const* params, wasm_val_vec_t* results);
namespace {
void
printWasmError(std::string_view msg, wasm_trap_t* trap, beast::Journal jlog)
{
#ifdef DEBUG_OUTPUT
auto& j = std::cerr;
#else
auto j = jlog.warn();
if (jlog.active(beast::Severity::Warning))
#endif
{
wasm_byte_vec_t errorMessage WASM_EMPTY_VEC;
if (trap != nullptr)
wasm_trap_message(trap, &errorMessage);
if (errorMessage.size != 0u)
{
j << "WASMI Error: " << msg << ", "
<< std::string_view(errorMessage.data, errorMessage.size - 1);
}
else
{
j << "WASMI Error: " << msg;
}
if (errorMessage.size != 0u)
wasm_byte_vec_delete(&errorMessage);
}
if (trap != nullptr)
wasm_trap_delete(trap);
#ifdef DEBUG_OUTPUT
j << std::endl;
#endif
}
// LCOV_EXCL_STOP
// Extract a trap's message into a std::string (the only signal the C API gives
// for classification; see the trap-signal constants in WasmCommon.h). Does not
// take ownership of `trap`.
std::string
trapMessage(wasm_trap_t* trap)
{
if (trap == nullptr)
return {}; // LCOV_EXCL_LINE
wasm_byte_vec_t msg WASM_EMPTY_VEC;
wasm_trap_message(trap, &msg);
std::string out;
if (msg.size != 0u)
{
// wasm_trap_message NUL-terminates, so drop the trailing NUL.
out.assign(msg.data, msg.size - 1);
wasm_byte_vec_delete(&msg);
}
return out;
}
} // namespace
class WasmiRuntimeWrapper : public WasmRuntimeWrapper
{
InstanceWrapper& iw_;
public:
WasmiRuntimeWrapper(InstanceWrapper& iw) : iw_(iw)
{
}
Wmem
getMem() override
{
return iw_.getMem();
}
std::int64_t
getGas() override
{
return iw_.getGas();
}
std::int64_t
setGas(std::int64_t gas) override
{
return iw_.setGas(gas);
}
std::int64_t
getTransferLimit() override
{
return iw_.getTransferLimit();
}
std::int64_t
setTransferLimit(std::int64_t x) override
{
return iw_.setTransferLimit(x);
}
};
InstancePtr
InstanceWrapper::init(
StorePtr& s,
ModulePtr& m,
WasmExternVec& expt,
WasmExternVec const& imports,
beast::Journal j)
{
wasm_trap_t* trap = nullptr;
InstancePtr mi = InstancePtr(
wasm_instance_new(s.get(), m.get(), imports.get(), &trap), &wasm_instance_delete);
if (!mi || (trap != nullptr))
{
printWasmError("can't create instance", trap, j);
Throw<std::runtime_error>("can't create instance");
}
wasm_instance_exports(mi.get(), expt.get());
return mi;
}
InstanceWrapper&
InstanceWrapper::operator=(InstanceWrapper&& o)
{
if (this == &o)
return *this; // LCOV_EXCL_LINE
store_ = o.store_;
o.store_ = nullptr;
exports_ = std::move(o.exports_);
memIdx_ = o.memIdx_;
o.memIdx_ = -1;
instance_ = std::move(o.instance_);
j_ = o.j_;
return *this;
}
FuncInfo
InstanceWrapper::getFunc(std::string_view funcName, WasmExporttypeVec const& exportTypes) const
{
wasm_func_t const* f = nullptr;
wasm_functype_t const* ft = nullptr;
if (!instance_)
Throw<std::runtime_error>("no instance"); // LCOV_EXCL_LINE
if (exportTypes.empty())
Throw<std::runtime_error>("no export"); // LCOV_EXCL_LINE
if (exportTypes.size() != exports_.size())
Throw<std::runtime_error>("invalid export"); // LCOV_EXCL_LINE
for (unsigned i = 0; i < exportTypes.size(); ++i)
{
auto const* expType(exportTypes[i]);
wasm_name_t const* name = wasm_exporttype_name(expType);
wasm_externtype_t const* exnType = wasm_exporttype_type(expType);
if (wasm_externtype_kind(exnType) == WASM_EXTERN_FUNC)
{
if (funcName != std::string_view(name->data, name->size))
continue;
auto const* exn(exports_[i]);
if (wasm_extern_kind(exn) != WASM_EXTERN_FUNC)
Throw<std::runtime_error>("invalid export"); // LCOV_EXCL_LINE
ft = wasm_externtype_as_functype_const(exnType);
f = wasm_extern_as_func_const(exn);
break;
}
}
if ((f == nullptr) || (ft == nullptr))
Throw<std::runtime_error>("can't find function <" + std::string(funcName) + ">");
return {f, ft};
}
Wmem
InstanceWrapper::getMem() const
{
if (memIdx_ >= 0)
{
auto* e(exports_[memIdx_]);
wasm_memory_t* mem = wasm_extern_as_memory(e);
return Wmem(wasm_memory_data(mem), wasm_memory_data_size(mem));
}
wasm_memory_t* mem = nullptr;
for (int i = 0; i < exports_.size(); ++i)
{
auto* e(exports_[i]);
if (wasm_extern_kind(e) == WASM_EXTERN_MEMORY)
{
memIdx_ = i;
mem = wasm_extern_as_memory(e);
break;
}
}
if (mem == nullptr)
return {}; // LCOV_EXCL_LINE
return Wmem(wasm_memory_data(mem), wasm_memory_data_size(mem));
}
std::int64_t
InstanceWrapper::getGas() const
{
if (store_ == nullptr)
return -1; // LCOV_EXCL_LINE
std::uint64_t gas = 0;
wasm_store_get_fuel(store_, &gas);
return static_cast<std::int64_t>(gas);
}
std::int64_t
InstanceWrapper::setGas(std::int64_t gas) const
{
if (store_ == nullptr)
return -1; // LCOV_EXCL_LINE
if (gas < 0)
gas = std::numeric_limits<decltype(gas)>::max();
wasmi_error_t* err = wasm_store_set_fuel(store_, static_cast<std::uint64_t>(gas));
if (err != nullptr)
{
// LCOV_EXCL_START
printWasmError("Can't set instance gas", nullptr, j_);
wasmi_error_delete(err);
return -1;
// LCOV_EXCL_STOP
}
return gas;
}
std::int64_t
InstanceWrapper::getTransferLimit() const
{
if (store_ == nullptr)
return -1; // LCOV_EXCL_LINE
return transferLimit_;
}
std::int64_t
InstanceWrapper::setTransferLimit(std::int64_t x)
{
if (store_ == nullptr)
return -1; // LCOV_EXCL_LINE
if (x < 0)
{
transferLimit_ = std::numeric_limits<decltype(transferLimit_)>::max();
}
else
{
transferLimit_ = x;
}
return transferLimit_;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
ModulePtr
ModuleWrapper::init(StorePtr& s, Bytes const& wasmBin, beast::Journal j)
{
wasm_byte_vec_t const code{.size = wasmBin.size(), .data = (char*)(wasmBin.data())};
ModulePtr m = ModulePtr(wasm_module_new(s.get(), &code), &wasm_module_delete);
if (!m)
throw std::runtime_error("can't create module");
return m;
}
ModuleWrapper::ModuleWrapper(
StorePtr& s,
Bytes const& wasmBin,
bool instantiate,
ImportVec const& imports,
beast::Journal j)
: module_(init(s, wasmBin, j)), j_(j)
{
wasm_module_exports(module_.get(), exportTypes_.get());
auto wimports = buildImports(s, imports);
if (instantiate)
{
addInstance(s, wimports);
}
}
// LCOV_EXCL_START
ModuleWrapper&
ModuleWrapper::operator=(ModuleWrapper&& o)
{
if (this == &o)
return *this;
module_ = std::move(o.module_);
instanceWrap_ = std::move(o.instanceWrap_);
exportTypes_ = std::move(o.exportTypes_);
j_ = o.j_;
return *this;
}
// LCOV_EXCL_STOP
static WasmValtypeVec
makeImpParams(WasmImportFunc const& imp)
{
auto const paramSize = imp.params.size();
if (paramSize == 0u)
return {};
WasmValtypeVec v(paramSize);
for (unsigned i = 0; i < paramSize; ++i)
{
auto const vt = imp.params[i];
switch (vt)
{
case WasmTypes::WtI32:
v[i] = wasm_valtype_new_i32();
break;
case WasmTypes::WtI64:
v[i] = wasm_valtype_new_i64();
break;
// LCOV_EXCL_START
default:
throw std::runtime_error("invalid import type");
// LCOV_EXCL_STOP
}
}
return v;
}
static WasmValtypeVec
makeImpReturn(WasmImportFunc const& imp)
{
if (!imp.result)
return {}; // LCOV_EXCL_LINE
WasmValtypeVec v(1);
switch (*imp.result)
{
case WasmTypes::WtI32:
v[0] = wasm_valtype_new_i32();
break;
// LCOV_EXCL_START
case WasmTypes::WtI64:
v[0] = wasm_valtype_new_i64();
break;
default:
throw std::runtime_error("invalid return type");
// LCOV_EXCL_STOP
}
return v;
}
WasmExternVec
ModuleWrapper::buildImports(StorePtr& s, ImportVec const& imports) const
{
WasmImporttypeVec importTypes;
wasm_module_imports(module_.get(), importTypes.get());
if (importTypes.empty())
return {};
if (imports.empty())
Throw<std::runtime_error>("Empty imports");
WasmExternVec wimports(importTypes.size());
unsigned impCnt = 0;
for (unsigned i = 0; i < importTypes.size(); ++i)
{
wasm_importtype_t const* importType = importTypes[i];
// wasm_name_t const* mn = wasm_importtype_module(importtype);
// auto modName = std::string_view(mn->data, mn->num_elems);
wasm_name_t const* fn = wasm_importtype_name(importType);
auto fieldName = std::string_view(fn->data, fn->size);
wasm_externkind_t const itype = wasm_externtype_kind(wasm_importtype_type(importType));
if ((itype) != WASM_EXTERN_FUNC)
{
Throw<std::runtime_error>(
"Invalid import type " + std::to_string(itype)); // LCOV_EXCL_LINE
}
// for multi-module support
// if ((W_ENV != modName) && (W_HOST_LIB != modName))
// continue;
auto const it = imports.find(fieldName);
if (it == imports.end())
{
printWasmError("Import not found: " + std::string(fieldName), nullptr, j_);
continue; // print all missed import
}
WasmUserData const& obj = it->second;
WasmImportFunc const& imp = obj.second;
WasmValtypeVec params(makeImpParams(imp));
WasmValtypeVec results(makeImpReturn(imp));
std::unique_ptr<wasm_functype_t, decltype(&wasm_functype_delete)> const ftype(
wasm_functype_new(params.get(), results.get()), &wasm_functype_delete);
params.release();
results.release();
wasm_func_t* func =
wasm_func_new_with_env(s.get(), ftype.get(), HostFuncMain_wrap, (void*)&obj, nullptr);
if (func == nullptr)
{
Throw<std::runtime_error>(
"can't create import function " + std::string(imp.name)); // LCOV_EXCL_LINE
}
wimports[i] = wasm_func_as_extern(func);
++impCnt;
}
if (impCnt != importTypes.size())
{
printWasmError(
std::string("Imports not finished: ") + std::to_string(impCnt) + "/" +
std::to_string(importTypes.size()),
nullptr,
j_);
Throw<std::runtime_error>("Missing imports");
}
return wimports;
}
wasm_functype_t*
ModuleWrapper::getFuncType(std::string_view funcName) const
{
for (size_t i = 0; i < exportTypes_.size(); i++)
{
auto const* expType(exportTypes_[i]);
wasm_name_t const* name = wasm_exporttype_name(expType);
wasm_externtype_t const* exnType = wasm_exporttype_type(expType);
if (wasm_externtype_kind(exnType) == WASM_EXTERN_FUNC &&
funcName == std::string_view(name->data, name->size))
{
return wasm_externtype_as_functype(const_cast<wasm_externtype_t*>(exnType));
}
}
throw std::runtime_error("can't find function <" + std::string(funcName) + ">");
}
// int
// my_module_t::delInstance(int i)
// {
// if (i >= mod_inst.size())
// return -1;
// if (!mod_inst[i])
// mod_inst[i] = my_mod_inst_t();
// return i;
// }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
// void
// WasmiEngine::clearModules()
// {
// modules.clear();
// store.reset(); // to free the memory before creating new store
// store = {wasm_store_new(engine.get()), &wasm_store_delete};
// }
std::unique_ptr<wasm_engine_t, decltype(&wasm_engine_delete)>
WasmiEngine::init()
{
wasm_config_t* config = wasm_config_new();
if (config == nullptr)
{
return std::unique_ptr<wasm_engine_t, decltype(&wasm_engine_delete)>{
nullptr, &wasm_engine_delete}; // LCOV_EXCL_LINE
}
wasmi_config_consume_fuel_set(config, true);
wasmi_config_ignore_custom_sections_set(config, true);
wasmi_config_wasm_mutable_globals_set(config, false);
wasmi_config_wasm_multi_value_set(config, false);
wasmi_config_wasm_sign_extension_set(config, false);
wasmi_config_wasm_saturating_float_to_int_set(config, false);
wasmi_config_wasm_bulk_memory_set(config, false);
wasmi_config_wasm_reference_types_set(config, false);
wasmi_config_wasm_tail_call_set(config, false);
wasmi_config_wasm_extended_const_set(config, false);
wasmi_config_floats_set(config, false);
wasmi_config_wasm_multi_memory_set(config, false);
wasmi_config_wasm_custom_page_sizes_set(config, false);
wasmi_config_wasm_memory64_set(config, false);
wasmi_config_wasm_wide_arithmetic_set(config, false);
return std::unique_ptr<wasm_engine_t, decltype(&wasm_engine_delete)>(
wasm_engine_new_with_config(config), &wasm_engine_delete);
}
int
WasmiEngine::addModule(
Bytes const& wasmCode,
bool instantiate,
ImportVec const& imports,
int64_t gas)
{
moduleWrap_.reset();
store_.reset(); // to free the memory before creating new store
store_ = {wasm_store_new_with_memory_max_pages(engine_.get(), maxPages), &wasm_store_delete};
if (gas < 0)
gas = std::numeric_limits<decltype(gas)>::max();
wasmi_error_t* err = wasm_store_set_fuel(store_.get(), static_cast<std::uint64_t>(gas));
if (err != nullptr)
{
// LCOV_EXCL_START
printWasmError("Error setting gas", nullptr, j_);
wasmi_error_delete(err);
throw std::runtime_error("can't set gas");
// LCOV_EXCL_STOP
}
moduleWrap_ = std::make_unique<ModuleWrapper>(store_, wasmCode, instantiate, imports, j_);
if (!moduleWrap_)
throw std::runtime_error("can't create module wrapper"); // LCOV_EXCL_LINE
return moduleWrap_ ? 0 : -1;
}
// int
// WasmiEngine::addInstance()
// {
// return module->addInstance(store.get());
// }
std::vector<wasm_val_t>
WasmiEngine::convertParams(std::vector<WasmParam> const& params)
{
std::vector<wasm_val_t> v;
v.reserve(params.size());
for (auto const& p : params)
{
switch (p.type)
{
case WasmTypes::WtI32:
v.push_back(WASM_I32_VAL(p.of.i32));
break;
// LCOV_EXCL_START
case WasmTypes::WtI64:
v.push_back(WASM_I64_VAL(p.of.i64));
break;
default:
throw std::runtime_error(
"unknown parameter type: " + std::to_string(static_cast<int>(p.type)));
break;
// LCOV_EXCL_STOP
}
}
return v;
}
int
WasmiEngine::compareParamTypes(wasm_valtype_vec_t const* ftp, std::vector<wasm_val_t> const& p)
{
if (ftp->size != p.size())
return std::min(ftp->size, p.size());
for (unsigned i = 0; i < ftp->size; ++i)
{
auto const t1 = wasm_valtype_kind(ftp->data[i]);
auto const t2 = p[i].kind;
if (t1 != t2)
return i;
}
return -1;
}
// LCOV_EXCL_START
void
WasmiEngine::addParam(std::vector<wasm_val_t>& in, int32_t p)
{
in.emplace_back();
auto& el(in.back());
memset(&el, 0, sizeof(el));
el = WASM_I32_VAL(p); // WASM_I32;
}
// LCOV_EXCL_STOP
void
WasmiEngine::addParam(std::vector<wasm_val_t>& in, int64_t p)
{
in.emplace_back();
auto& el(in.back());
el = WASM_I64_VAL(p);
}
template <int NR, class... Types>
WasmiResult
WasmiEngine::call(std::string_view func, Types&&... args)
{
// Lookup our export function
auto f = getFunc(func);
return call<NR>(f, std::forward<Types>(args)...);
}
template <int NR, class... Types>
WasmiResult
WasmiEngine::call(FuncInfo const& f, Types&&... args)
{
std::vector<wasm_val_t> in;
return call<NR>(f, in, std::forward<Types>(args)...);
}
#ifdef SHOW_CALL_TIME
static inline uint64_t
usecs()
{
uint64_t x = std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::high_resolution_clock::now().time_since_epoch())
.count();
return x;
}
#endif
template <int NR, class... Types>
WasmiResult
WasmiEngine::call(FuncInfo const& f, std::vector<wasm_val_t>& in)
{
WasmiResult ret(NR);
wasm_val_vec_t const inv = in.empty() ? wasm_val_vec_t WASM_EMPTY_VEC
: wasm_val_vec_t{.size = in.size(), .data = in.data()};
#ifdef SHOW_CALL_TIME
auto const start = usecs();
#endif
wasm_trap_t* trap = wasm_func_call(f.first, &inv, ret.r.get());
#ifdef SHOW_CALL_TIME
auto const finish = usecs();
auto const delta_ms = (finish - start) / 1000;
std::cout << "wasm_func_call: " << delta_ms << "ms" << std::endl;
#endif
if (trap)
{
// Classify the trap into a TER by matching tokens as substrings of the
// message (see the trap-signal constants in WasmCommon.h for why).
std::string const msg = trapMessage(trap);
auto const has = [&msg](std::string_view token) {
return msg.find(token) != std::string::npos;
};
if (has(hfErrInternal))
{
ret.ter = tecINTERNAL;
}
else if (has(hfErrOutOfGas) || has(wasmiTrapOutOfFuel))
{
ret.ter = tecOUT_OF_GAS;
}
else
{
ret.ter = tecFAILED_PROCESSING;
}
printWasmError("failure to call func", trap, j_);
}
return ret;
}
template <int NR, class... Types>
WasmiResult
WasmiEngine::call(FuncInfo const& f, std::vector<wasm_val_t>& in, std::int32_t p, Types&&... args)
{
addParam(in, p);
return call<NR>(f, in, std::forward<Types>(args)...);
}
template <int NR, class... Types>
WasmiResult
WasmiEngine::call(FuncInfo const& f, std::vector<wasm_val_t>& in, std::int64_t p, Types&&... args)
{
addParam(in, p);
return call<NR>(f, in, std::forward<Types>(args)...);
}
template <int NR, class... Types>
WasmiResult
WasmiEngine::call(FuncInfo const& f, std::vector<wasm_val_t>& in, Bytes const& p, Types&&... args)
{
return call<NR>(f, in, p.data(), p.size(), std::forward<Types>(args)...);
}
static inline void
checkImports(ImportVec const& imports, HostFunctions* hfs)
{
for (auto const& obj : imports)
{
if (hfs != &obj.second.first.get())
Throw<std::runtime_error>("Imports hf unsync");
}
}
Expected<WasmResult<int32_t>, WasmTER>
WasmiEngine::run(
Bytes const& wasmCode,
HostFunctions& hfs,
int64_t gas,
std::string_view funcName,
std::vector<WasmParam> const& params,
ImportVec const& imports,
beast::Journal j)
{
if (gas <= 0)
return Unexpected(WasmTER{.ter = temBAD_AMOUNT, .cost = std::nullopt});
try
{
checkImports(imports, &hfs);
return runHlp(wasmCode, hfs, gas, funcName, params, imports, j);
}
catch (std::exception const& e)
{
printWasmError(std::string("exception: ") + e.what(), nullptr, j);
}
// LCOV_EXCL_START
catch (...)
{
printWasmError(std::string("exception: unknown"), nullptr, j);
}
// LCOV_EXCL_STOP
// An exception escaping the engine is an xrpld-side fault -> tecINTERNAL,
// no gas. Genuine wasm faults don't throw; they surface as traps in runHlp.
return Unexpected(WasmTER{.ter = tecINTERNAL, .cost = std::nullopt});
}
Expected<WasmResult<int32_t>, WasmTER>
WasmiEngine::runHlp(
Bytes const& wasmCode,
HostFunctions& hfs,
int64_t gas,
std::string_view funcName,
std::vector<WasmParam> const& params,
ImportVec const& imports,
beast::Journal j)
{
// currently only 1 module support, possible parallel UT run
std::scoped_lock const lg(m_);
j_ = j;
if (wasmCode.empty())
throw std::runtime_error("empty module");
if (!hfs.checkSelf())
throw std::runtime_error("hfs isn't clean");
// Create and instantiate the module.
[[maybe_unused]] int const m = addModule(wasmCode, true, imports, gas);
if (!moduleWrap_ || !moduleWrap_->getInstance())
throw std::runtime_error("no instance"); // LCOV_EXCL_LINE
auto clearRT = [](HostFunctions* p) { p->resetRT(); };
std::unique_ptr<HostFunctions, decltype(clearRT)> const clearGuard(&hfs, clearRT);
WasmiRuntimeWrapper iw(getRT());
hfs.setRT(iw);
// Call main
auto const f = getFunc(!funcName.empty() ? funcName : "_start");
auto const* ftp = wasm_functype_params(f.second);
// not const because passed directly to VM function (which accept non
// const)
auto p = convertParams(params);
if (int const comp = compareParamTypes(ftp, p); comp >= 0)
throw std::runtime_error("invalid parameter type #" + std::to_string(comp));
auto const res = call<1>(f, p);
if (gas == -1)
gas = std::numeric_limits<decltype(gas)>::max();
if (res.ter.has_value())
{
// call() already classified the trap (see WasmiEngine::call).
// tecINTERNAL is an xrpld-side bug: report no gas.
if (*res.ter == tecINTERNAL)
return Unexpected(WasmTER{.ter = tecINTERNAL, .cost = std::nullopt});
// Out-of-gas / wasm faults report gas (caller writes it to metadata).
// Force fuel to 0 on out-of-gas so cost is the full limit (wasmi leaves
// nonzero leftover fuel on its own out-of-fuel trap).
if (*res.ter == tecOUT_OF_GAS)
iw.setGas(0);
return Unexpected(WasmTER{.ter = *res.ter, .cost = gas - moduleWrap_->getGas()});
}
if (res.r.empty())
{
Throw<std::runtime_error>(
"<" + std::string(funcName) + "> return nothing"); // LCOV_EXCL_LINE
}
if (res.r[0].kind != WASM_I32)
{
Throw<std::runtime_error>(
"<" + std::string(funcName) +
"> return type mismatch, ret: " + std::to_string(static_cast<int>(res.r[0].kind)));
}
WasmResult<int32_t> const ret{.result = res.r[0].of.i32, .cost = gas - moduleWrap_->getGas()};
// #ifdef DEBUG_OUTPUT
// auto& j = std::cerr;
// #else
// auto j = j_.debug();
// #endif
// j << "WASMI Res: " << ret.result << " cost: " << ret.cost << std::endl;
return ret;
}
NotTEC
WasmiEngine::check(
Bytes const& wasmCode,
HostFunctions& hfs,
std::string_view funcName,
std::vector<WasmParam> const& params,
ImportVec const& imports,
beast::Journal j)
{
try
{
checkImports(imports, &hfs);
return checkHlp(wasmCode, hfs, funcName, params, imports, j);
}
catch (std::exception const& e)
{
printWasmError(std::string("exception: ") + e.what(), nullptr, j);
}
// LCOV_EXCL_START
catch (...)
{
printWasmError(std::string("exception: unknown"), nullptr, j);
}
// LCOV_EXCL_STOP
return temBAD_WASM;
}
NotTEC
WasmiEngine::checkHlp(
Bytes const& wasmCode,
HostFunctions& hfs,
std::string_view funcName,
std::vector<WasmParam> const& params,
ImportVec const& imports,
beast::Journal j)
{
// currently only 1 module support, possible parallel UT run
std::scoped_lock const lg(m_);
j_ = j;
// Create and instantiate the module.
if (wasmCode.empty())
throw std::runtime_error("empty module");
int const m = addModule(wasmCode, false, imports, -1);
if ((m < 0) || !moduleWrap_)
throw std::runtime_error("no module"); // LCOV_EXCL_LINE
// Looking for a func and compare parameter types
auto const f = moduleWrap_->getFuncType(!funcName.empty() ? funcName : "_start");
auto const* ftp = wasm_functype_params(f);
auto const p = convertParams(params);
if (int const comp = compareParamTypes(ftp, p); comp >= 0)
throw std::runtime_error("invalid parameter type #" + std::to_string(comp));
return tesSUCCESS;
}
wasm_trap_t*
WasmiEngine::newTrap(std::string const& txt)
{
static char empty[1] = {0};
wasm_message_t msg = {.size = 1, .data = empty};
if (!txt.empty())
wasm_name_new(&msg, txt.size() + 1, txt.c_str()); // include 0
wasm_trap_t* trap = wasm_trap_new(store_.get(), &msg); // NOLINT
if (!txt.empty())
wasm_byte_vec_delete(&msg);
return trap;
}
} // namespace xrpl

View File

@@ -1,38 +0,0 @@
#include "CodecTypes.h"
#include <cstring>
// ───────────────────────────────────────────────────────────────────────────
// Codec bodies for AccountID. One decode/encode pair per registered version.
// ───────────────────────────────────────────────────────────────────────────
namespace xrpl::wasm::detail {
// ── AccountID, version 0 : 20 raw bytes ─────────────────────────────────────
template <>
Expected<AccountID, CodecError>
CodecTypeTrait<codecTypeCodeV<AccountID>, 0>::decode(CodecEnvelope const& env)
{
if (env.header.payload_size != kPayloadSize)
{
return Unexpected{CodecError::Truncated};
}
auto id = AccountID{};
std::memcpy(id.data(), env.payload, id.size());
return id;
}
template <>
Expected<CodecEnvelope, CodecError>
CodecTypeTrait<codecTypeCodeV<AccountID>, 0>::encode(AccountID const& value)
{
// AccountID is fixed-width, so it always fits v0 (no NotRepresentable path).
// TODO(payload-ownership): payload bytes (value.data(), value.size()) must
// be owned by the wire layer; deferred per the current encode signature.
(void)value;
return CodecEnvelope{.header={.type_code=kCodecTypeCode, .version=kVersion, .payload_size=kPayloadSize}, .payload=nullptr};
}
} // namespace xrpl::wasm::detail

View File

@@ -1,60 +0,0 @@
#include <xrpl/tx/wasm/Codec.h>
#include <xrpl/tx/wasm/detail/CodecDispatch.h>
#include <xrpl/tx/wasm/detail/CodecList.h>
#include <xrpl/tx/wasm/detail/CodecRevisions.h>
#include "CodecTypes.h"
//
// The registry translation unit. This is the ONE place that:
// * assembles the complete registered-codec tuple from the .def, and
// * explicitly instantiates decode<T>/encode<T> for every registered type.
//
// Because the definitions live here (not in the public header), callers get the
// codec machinery out of their compiles, and an unregistered decode<T>/encode<T>
// fails at link time rather than with a template error.
//
namespace xrpl::wasm {
namespace {
// The single enumeration of every registered codec, built straight from the
// .def. The trailing detail::CodecEnd absorbs the final comma of the expansion.
using RegisteredCodecs = detail::CodecList<
#define CODEC_VERSION(CppType, Version, PayloadSize) \
detail::CodecTypeTrait<detail::codecTypeCodeV<CppType>, Version>,
#include <xrpl/tx/wasm/detail/codec_types.macro>
detail::CodecEnd>::TupleType;
} // namespace
template <typename T>
Expected<T, CodecError>
decode(CodecEnvelope const& env)
{
return detail::decodeImpl<T, RegisteredCodecs>(env);
}
template <typename T>
Expected<CodecEnvelope, CodecError>
encode(CodecVersion declaredRevision, T const& value)
{
auto const wire =
detail::wireVersionFor(declaredRevision, detail::codecTypeCodeV<T>);
if (!wire)
{
return Unexpected{wire.error()};
}
return detail::encodeAt<T, RegisteredCodecs>(*wire, value);
}
// Explicit instantiation for every registered type — the closed set.
#define CODEC_TYPE(CppType, TypeCode) \
template Expected<CppType, CodecError> decode<CppType>( \
CodecEnvelope const&); \
template Expected<CodecEnvelope, CodecError> encode<CppType>( \
CodecVersion, CppType const&);
#include <xrpl/tx/wasm/detail/codec_types.macro>
} // namespace xrpl::wasm

View File

@@ -1,74 +0,0 @@
#include <xrpl/tx/wasm/detail/CodecRevisions.h>
#include <xrpl/tx/wasm/detail/CodecTrait.h>
#include "CodecTypes.h"
#include <array>
#include <utility>
// ───────────────────────────────────────────────────────────────────────────
// Revision / amendment POLICY.
//
// The CodecTrait<N> revision maps and the wireVersionFor switch are BOTH
// generated from codec_revisions.macro, exactly as the (type, version)
// registry drives the dispatch tables — so the maps and the dispatch can't
// drift from the registration list.
// ───────────────────────────────────────────────────────────────────────────
namespace xrpl::wasm::detail {
// (1) Generate the CodecTrait<N> revision maps.
#define CODEC_REVISION_BEGIN(Revision) \
template <> \
struct CodecTrait<Revision> \
{ \
static constexpr CodecVersion kVersion = Revision; \
static constexpr auto versions = \
std::to_array<std::pair<CodecTypeCode, CodecVersion>>({
#define CODEC_REVISION_ENTRY(CppType, Version) \
{codecTypeCodeV<CppType>, Version},
#define CODEC_REVISION_END(Revision) \
}); \
};
#include <xrpl/tx/wasm/detail/codec_revisions.macro>
namespace {
template <CodecVersion N>
Expected<CodecVersion, CodecError>
versionFromRevision(CodecTypeCode code)
{
for (auto const& [c, v] : CodecTrait<N>::versions)
{
if (c == code)
{
return v;
}
}
return Unexpected{CodecError::TypeNotInRevision};
}
} // namespace
Expected<CodecVersion, CodecError>
wireVersionFor(CodecVersion declaredRevision, CodecTypeCode code)
{
// TODO(amendment-gating): each revision > 0 must additionally be gated
// behind its amendment (via Rules) before a node may emit it, so no node
// emits a wire version its peers can't agree on. Thread Rules in here.
// (2) Generate the runtime-revision -> CodecTrait<N> dispatch.
switch (declaredRevision)
{
#define CODEC_REVISION_BEGIN(Revision) \
case Revision: \
return versionFromRevision<Revision>(code);
#define CODEC_REVISION_ENTRY(CppType, Version)
#define CODEC_REVISION_END(Revision)
#include <xrpl/tx/wasm/detail/codec_revisions.macro>
default:
return Unexpected{CodecError::UnknownCodecVersion};
}
}
} // namespace xrpl::wasm::detail

View File

@@ -1,34 +0,0 @@
#pragma once
//
// Internal aggregation header for the wasm codec registry (NOT public — lives
// under src/). Expands codec_types.macro to declare, in one shared place:
//
// * CODEC_TYPE -> the C++ type -> CodecTypeCode mapping
// * CODEC_VERSION -> each (type, version) CodecTypeTrait specialization
//
// Both the registry TU and every per-type codec .cpp include this, so the trait
// declarations they share are always generated from the same .def and can never
// drift.
//
#include <xrpl/basics/Expected.h> // used by the trait macro's decode/encode
#include <xrpl/tx/wasm/detail/CodecTypeCode.h>
#include <xrpl/tx/wasm/detail/CodecTypeTrait.h>
// One include per registered C++ *type* (not per version):
#include <xrpl/basics/Number.h>
#include <xrpl/protocol/AccountID.h>
namespace xrpl::wasm::detail {
// type -> type code
#define CODEC_TYPE(CppType, TypeCode) XRPL_WASM_CODEC_TYPE_CODE(CppType, TypeCode)
#include <xrpl/tx/wasm/detail/codec_types.macro>
// per-(type, version) trait declarations (bodies live in the type's .cpp)
#define CODEC_VERSION(CppType, Version, PayloadSize) \
XRPL_WASM_CODEC_TYPE_TRAIT(CppType, Version, PayloadSize)
#include <xrpl/tx/wasm/detail/codec_types.macro>
} // namespace xrpl::wasm::detail

View File

@@ -1,54 +0,0 @@
#include "CodecTypes.h"
#include <xrpl/protocol/Serializer.h>
#include <cstdint>
#include <limits>
// ───────────────────────────────────────────────────────────────────────────
// Codec bodies for Number. One decode/encode pair per registered version.
// (GLOB_RECURSE compiles this file automatically; it is wired into the dispatch
// tables by the explicit instantiations in CodecRegistry.cpp.)
// ───────────────────────────────────────────────────────────────────────────
namespace xrpl::wasm::detail {
// ── Number, version 0 : int64 mantissa + int32 exponent = 12 bytes ──────────
// Layout deliberately matches the frozen on-ledger STNumber serialization.
template <>
Expected<Number, CodecError>
CodecTypeTrait<codecTypeCodeV<Number>, 0>::decode(CodecEnvelope const& env)
{
if (env.header.payload_size != kPayloadSize)
{
return Unexpected{CodecError::Truncated};
}
auto sit = SerialIter{env.payload, env.header.payload_size};
auto const mantissa = sit.geti64();
auto const exponent = sit.geti32();
return Number{mantissa, exponent};
}
template <>
Expected<CodecEnvelope, CodecError>
CodecTypeTrait<codecTypeCodeV<Number>, 0>::encode(Number const& value)
{
// v0 carries an int64 mantissa; Number's mantissa is int64 today so it
// always fits. The guard documents the boundary for a future wider Number
// (the "graceful fail" path when a value can't be represented in v0).
if (value.exponent() < std::numeric_limits<std::int32_t>::min() ||
value.exponent() > std::numeric_limits<std::int32_t>::max())
{
return Unexpected{CodecError::NotRepresentable};
}
// TODO(payload-ownership): the returned envelope's payload must reference
// storage that outlives the call; that ownership belongs to the wire layer.
// The encode signature is intentionally left as-is for now, so the actual
// byte production is deferred there.
return CodecEnvelope{.header={.type_code=kCodecTypeCode, .version=kVersion, .payload_size=kPayloadSize}, .payload=nullptr};
}
} // namespace xrpl::wasm::detail

File diff suppressed because it is too large Load Diff

View File

@@ -1,531 +0,0 @@
#pragma once
#include <test/app/wasm_fixtures/fixtures.h>
#include <test/jtx/Env.h>
#include <test/unit_test/SuiteJournal.h>
#include <xrpl/ledger/AmendmentTable.h>
#include <xrpl/ledger/detail/ApplyViewBase.h>
#include <xrpl/ledger/helpers/NFTokenHelpers.h>
#include <xrpl/protocol/digest.h>
#include <xrpl/tx/wasm/HostFunc.h>
#include <xrpl/tx/wasm/WasmVM.h>
#include <boost/algorithm/hex.hpp>
#include <cstdint>
#include <iterator>
#include <string>
#include <string_view>
namespace xrpl::test {
class TestLedgerDataProvider : public HostFunctions
{
jtx::Env& env_;
public:
TestLedgerDataProvider(jtx::Env& env) : HostFunctions(env.journal), env_(env)
{
}
Expected<std::uint32_t, HostFunctionError>
getLedgerSqn() const override
{
return env_.current()->seq();
}
};
class TestHostFunctions : public HostFunctions
{
protected:
test::jtx::Env& env_;
AccountID accountID_;
Bytes data_;
public:
TestHostFunctions(test::jtx::Env& env) : HostFunctions(env.journal), env_(env)
{
accountID_ = env.master.id();
std::string t = "10000";
data_ = Bytes{t.begin(), t.end()};
}
Expected<std::uint32_t, HostFunctionError>
getLedgerSqn() const override
{
return 12345;
}
Expected<std::uint32_t, HostFunctionError>
getParentLedgerTime() const override
{
return 67890;
}
Expected<Hash, HostFunctionError>
getParentLedgerHash() const override
{
return env_.current()->header().parentHash;
}
Expected<std::uint32_t, HostFunctionError>
getBaseFee() const override
{
return 10;
}
Expected<int32_t, HostFunctionError>
isAmendmentEnabled(uint256 const& amendmentId) const override
{
return 1;
}
Expected<int32_t, HostFunctionError>
isAmendmentEnabled(std::string_view const& amendmentName) const override
{
return 1;
}
Expected<int32_t, HostFunctionError>
cacheLedgerObj(uint256 const& objId, int32_t cacheIdx) override
{
return 1;
}
Expected<Bytes, HostFunctionError>
getTxField(SField const& fname) const override
{
if (fname == sfAccount)
return Bytes(accountID_.begin(), accountID_.end());
if (fname == sfFee)
{
int64_t x = 235;
uint8_t const* p = reinterpret_cast<uint8_t const*>(&x);
return Bytes{p, p + sizeof(x)};
}
if (fname == sfSequence)
{
auto const x = getLedgerSqn();
if (!x)
return Unexpected(x.error());
std::uint32_t const data = x.value();
auto const* b = reinterpret_cast<uint8_t const*>(&data);
auto const* e = reinterpret_cast<uint8_t const*>(&data + 1);
return Bytes{b, e};
}
return Bytes();
}
Expected<Bytes, HostFunctionError>
getCurrentLedgerObjField(SField const& fname) const override
{
auto const& sn = fname.getName();
if (sn == "Destination" || sn == "Account")
return Bytes(accountID_.begin(), accountID_.end());
if (sn == "Data")
return data_;
if (sn == "FinishAfter")
{
auto t = env_.current()->parentCloseTime().time_since_epoch().count();
std::string s = std::to_string(t);
return Bytes{s.begin(), s.end()};
}
return Unexpected(HostFunctionError::Unimplemented);
}
Expected<Bytes, HostFunctionError>
getLedgerObjField(int32_t, SField const& fname) const override
{
if (fname == sfBalance)
{
int64_t x = 10'000;
uint8_t const* p = reinterpret_cast<uint8_t const*>(&x);
return Bytes{p, p + sizeof(x)};
}
if (fname == sfAccount)
return Bytes(accountID_.begin(), accountID_.end());
return data_;
}
Expected<Bytes, HostFunctionError>
getTxNestedField(FieldLocator const& locator) const override
{
if (locator.size() == 1)
{
int32_t const* l = locator.data();
int32_t const sfield = l[0];
if (sfield == sfAccount.getCode())
return Bytes(accountID_.begin(), accountID_.end());
}
uint8_t const a[] = {0x2b, 0x6a, 0x23, 0x2a, 0xa4, 0xc4, 0xbe, 0x41, 0xbf, 0x49, 0xd2,
0x45, 0x9f, 0xa4, 0xa0, 0x34, 0x7e, 0x1b, 0x54, 0x3a, 0x4c, 0x92,
0xfc, 0xee, 0x08, 0x21, 0xc0, 0x20, 0x1e, 0x2e, 0x9a, 0x00};
return Bytes(&a[0], &a[sizeof(a)]);
}
Expected<Bytes, HostFunctionError>
getCurrentLedgerObjNestedField(FieldLocator const& locator) const override
{
if (locator.size() == 1)
{
int32_t const* l = locator.data();
int32_t const sfield = l[0];
if (sfield == sfAccount.getCode())
return Bytes(accountID_.begin(), accountID_.end());
}
uint8_t const a[] = {0x2b, 0x6a, 0x23, 0x2a, 0xa4, 0xc4, 0xbe, 0x41, 0xbf, 0x49, 0xd2,
0x45, 0x9f, 0xa4, 0xa0, 0x34, 0x7e, 0x1b, 0x54, 0x3a, 0x4c, 0x92,
0xfc, 0xee, 0x08, 0x21, 0xc0, 0x20, 0x1e, 0x2e, 0x9a, 0x00};
return Bytes(&a[0], &a[sizeof(a)]);
}
Expected<Bytes, HostFunctionError>
getLedgerObjNestedField(int32_t cacheIdx, FieldLocator const& locator) const override
{
if (locator.size() == 1)
{
int32_t const* l = locator.data();
int32_t const sfield = l[0];
if (sfield == sfAccount.getCode())
return Bytes(accountID_.begin(), accountID_.end());
}
uint8_t const a[] = {0x2b, 0x6a, 0x23, 0x2a, 0xa4, 0xc4, 0xbe, 0x41, 0xbf, 0x49, 0xd2,
0x45, 0x9f, 0xa4, 0xa0, 0x34, 0x7e, 0x1b, 0x54, 0x3a, 0x4c, 0x92,
0xfc, 0xee, 0x08, 0x21, 0xc0, 0x20, 0x1e, 0x2e, 0x9a, 0x00};
return Bytes(&a[0], &a[sizeof(a)]);
}
Expected<int32_t, HostFunctionError>
getTxArrayLen(SField const& fname) const override
{
return 32;
}
Expected<int32_t, HostFunctionError>
getCurrentLedgerObjArrayLen(SField const& fname) const override
{
return 32;
}
Expected<int32_t, HostFunctionError>
getLedgerObjArrayLen(int32_t cacheIdx, SField const& fname) const override
{
return 32;
}
Expected<int32_t, HostFunctionError>
getTxNestedArrayLen(FieldLocator const& locator) const override
{
return 32;
}
Expected<int32_t, HostFunctionError>
getCurrentLedgerObjNestedArrayLen(FieldLocator const& locator) const override
{
return 32;
}
Expected<int32_t, HostFunctionError>
getLedgerObjNestedArrayLen(int32_t cacheIdx, FieldLocator const& locator) const override
{
return 32;
}
Expected<int32_t, HostFunctionError>
updateData(Slice const& data) override
{
return data.size();
}
Expected<int32_t, HostFunctionError>
checkSignature(Slice const& message, Slice const& signature, Slice const& pubkey) const override
{
return 1;
}
Expected<Hash, HostFunctionError>
computeSha512HalfHash(Slice const& data) const override
{
return env_.current()->header().parentHash;
}
Expected<Bytes, HostFunctionError>
accountKeylet(AccountID const& account) const override
{
if (!account)
return Unexpected(HostFunctionError::InvalidAccount);
auto const keylet = keylet::account(account);
return Bytes{keylet.key.begin(), keylet.key.end()};
}
Expected<Bytes, HostFunctionError>
ammKeylet(Asset const& issue1, Asset const& issue2) const override
{
if (issue1 == issue2)
return Unexpected(HostFunctionError::InvalidParams);
if (issue1.holds<MPTIssue>() || issue2.holds<MPTIssue>())
return Unexpected(HostFunctionError::InvalidParams);
auto const keylet = keylet::amm(issue1, issue2);
return Bytes{keylet.key.begin(), keylet.key.end()};
}
Expected<Bytes, HostFunctionError>
checkKeylet(AccountID const& account, std::uint32_t seq) const override
{
if (!account)
return Unexpected(HostFunctionError::InvalidAccount);
auto const keylet = keylet::check(account, seq);
return Bytes{keylet.key.begin(), keylet.key.end()};
}
Expected<Bytes, HostFunctionError>
credentialKeylet(AccountID const& subject, AccountID const& issuer, Slice const& credentialType)
const override
{
if (!subject || !issuer || credentialType.empty() ||
credentialType.size() > kMaxCredentialTypeLength)
return Unexpected(HostFunctionError::InvalidAccount);
auto const keylet = keylet::credential(subject, issuer, credentialType);
return Bytes{keylet.key.begin(), keylet.key.end()};
}
Expected<Bytes, HostFunctionError>
escrowKeylet(AccountID const& account, std::uint32_t seq) const override
{
if (!account)
return Unexpected(HostFunctionError::InvalidAccount);
auto const keylet = keylet::escrow(account, seq);
return Bytes{keylet.key.begin(), keylet.key.end()};
}
Expected<Bytes, HostFunctionError>
oracleKeylet(AccountID const& account, std::uint32_t documentId) const override
{
if (!account)
return Unexpected(HostFunctionError::InvalidAccount);
auto const keylet = keylet::oracle(account, documentId);
return Bytes{keylet.key.begin(), keylet.key.end()};
}
Expected<Bytes, HostFunctionError>
getNFT(AccountID const& account, uint256 const& nftId) const override
{
if (!account || !nftId)
return Unexpected(HostFunctionError::InvalidParams);
std::string s = "https://ripple.com";
return Bytes(s.begin(), s.end());
}
Expected<Bytes, HostFunctionError>
getNFTIssuer(uint256 const& nftId) const override
{
return Bytes(accountID_.begin(), accountID_.end());
}
Expected<std::uint32_t, HostFunctionError>
getNFTTaxon(uint256 const& nftId) const override
{
return 4;
}
Expected<int32_t, HostFunctionError>
getNFTFlags(uint256 const& nftId) const override
{
return 8;
}
Expected<int32_t, HostFunctionError>
getNFTTransferFee(uint256 const& nftId) const override
{
return 10;
}
Expected<std::uint32_t, HostFunctionError>
getNFTSerial(uint256 const& nftId) const override
{
return 4;
}
template <typename F>
void
log(std::string_view const& msg, F&& dataFn) const
{
#ifdef DEBUG_OUTPUT
auto& j = std::cerr;
#else
if (!getJournal().active(beast::Severity::Trace))
return;
auto j = getJournal().trace();
#endif
j << "WasmTrace: " << msg << " " << dataFn();
#ifdef DEBUG_OUTPUT
j << std::endl;
#endif
}
Expected<int32_t, HostFunctionError>
trace(std::string_view const& msg, Slice const& data, bool asHex) const override
{
if (!asHex)
{
log(msg, [&data] {
return std::string_view(reinterpret_cast<char const*>(data.data()), data.size());
});
}
else
{
log(msg, [&data] {
std::string hex;
hex.reserve(data.size() * 2);
boost::algorithm::hex(data.begin(), data.end(), std::back_inserter(hex));
return hex;
});
}
return 0;
}
Expected<int32_t, HostFunctionError>
traceNum(std::string_view const& msg, int64_t data) const override
{
log(msg, [data] { return data; });
return 0;
}
Expected<int32_t, HostFunctionError>
traceAccount(std::string_view const& msg, AccountID const& account) const override
{
log(msg, [&account] { return toBase58(account); });
return 0;
}
Expected<int32_t, HostFunctionError>
traceFloat(std::string_view const& msg, Slice const& data) const override
{
log(msg, [&data] { return wasm_float::floatToString(data); });
return 0;
}
Expected<int32_t, HostFunctionError>
traceAmount(std::string_view const& msg, STAmount const& amount) const override
{
log(msg, [&amount] { return amount.getFullText(); });
return 0;
}
Expected<Bytes, HostFunctionError>
floatFromInt(int64_t x, int32_t mode) const override
{
return wasm_float::floatFromIntImpl(x, mode);
}
Expected<Bytes, HostFunctionError>
floatFromUint(uint64_t x, int32_t mode) const override
{
return wasm_float::floatFromUintImpl(x, mode);
}
Expected<Bytes, HostFunctionError>
floatFromSTAmount(STAmount const& x, int32_t mode) const override
{
return wasm_float::floatFromSTAmountImpl(x, mode);
}
Expected<Bytes, HostFunctionError>
floatFromSTNumber(STNumber const& x, int32_t mode) const override
{
return wasm_float::floatFromSTNumberImpl(x, mode);
}
Expected<int64_t, HostFunctionError>
floatToInt(Slice const& x, int32_t mode) const override
{
return wasm_float::floatToIntImpl(x, mode);
}
Expected<FloatPair, HostFunctionError>
floatToMantExp(Slice const& x) const override
{
return wasm_float::floatToMantExpImpl(x);
}
Expected<Bytes, HostFunctionError>
floatFromMantExp(int64_t mantissa, int32_t exponent, int32_t mode) const override
{
return wasm_float::floatFromMantExpImpl(mantissa, exponent, mode);
}
Expected<int32_t, HostFunctionError>
floatCompare(Slice const& x, Slice const& y) const override
{
return wasm_float::floatCompareImpl(x, y);
}
Expected<Bytes, HostFunctionError>
floatAdd(Slice const& x, Slice const& y, int32_t mode) const override
{
return wasm_float::floatAddImpl(x, y, mode);
}
Expected<Bytes, HostFunctionError>
floatSubtract(Slice const& x, Slice const& y, int32_t mode) const override
{
return wasm_float::floatSubtractImpl(x, y, mode);
}
Expected<Bytes, HostFunctionError>
floatMultiply(Slice const& x, Slice const& y, int32_t mode) const override
{
return wasm_float::floatMultiplyImpl(x, y, mode);
}
Expected<Bytes, HostFunctionError>
floatDivide(Slice const& x, Slice const& y, int32_t mode) const override
{
return wasm_float::floatDivideImpl(x, y, mode);
}
Expected<Bytes, HostFunctionError>
floatRoot(Slice const& x, int32_t n, int32_t mode) const override
{
return wasm_float::floatRootImpl(x, n, mode);
}
Expected<Bytes, HostFunctionError>
floatPower(Slice const& x, int32_t n, int32_t mode) const override
{
return wasm_float::floatPowerImpl(x, n, mode);
}
};
class TestHostFunctionsSink : public TestHostFunctions
{
test::StreamSink sink_;
public:
explicit TestHostFunctionsSink(test::jtx::Env& env)
: TestHostFunctions(env), sink_(beast::Severity::Debug)
{
j_ = beast::Journal(sink_);
}
test::StreamSink&
getSink()
{
return sink_;
}
};
} // namespace xrpl::test

View File

@@ -6140,10 +6140,90 @@ class Vault_test : public beast::unit_test::Suite
runTest(amendments);
}
// VaultDeposit::preclaim uses accountHolds(..., SpendableHandling::
// shFULL_BALANCE), which for an IOU asset adds the counterparty's
// LowLimit/HighLimit to the depositor's raw balance (TokenHelpers.cpp:
// getTrustLineBalance with includeOppositeLimit=true). When the
// depositor's raw balance < deposit amount but raw + opposite limit >=
// amount, preclaim is satisfied. doApply then calls
// directSendNoFeeIOU, which unconditionally subtracts saAmount from
// saBalance — driving the trust line negative — and returns tesSUCCESS.
// The post-send sanity check uses the default shSIMPLE_BALANCE (no
// opposite-limit add), sees a negative balance, and returns tefINTERNAL.
void
testVaultDepositNegativeBalanceFromOppositeLimit()
{
auto runTest = [&](FeatureBitset f, TER expected) {
using namespace test::jtx;
using namespace std::literals;
Env env{*this, f};
Account const gw{"gateway"};
Account const owner{"owner"};
Account const depositor{"depositor"};
env.fund(XRP(10000), gw, owner, depositor);
env.close();
// Gateway with DefaultRipple so vault creation on its IOU works.
env(fset(gw, asfDefaultRipple));
env.close();
// Depositor opens a trust line to gateway and receives a small
// balance.
PrettyAsset const usd = gw["USD"];
env.trust(usd(1000), depositor);
env(pay(gw, depositor, usd(100))); // raw trust-line balance: 100
env.close();
// Key precondition: gateway sets a non-zero limit on the same
// RippleState — the "opposite field" from depositor's perspective.
// This is what inflates shFULL_BALANCE in preclaim above the raw
// balance.
env(trust(gw, depositor["USD"](1000)));
env.close();
// Create the IOU vault.
Vault const vault{env};
auto [vaultTx, keylet] = vault.create({.owner = owner, .asset = usd});
env(vaultTx);
env.close();
// Submit a deposit of 500 USD:
// - raw balance: 100 USD
// - opposite limit (gw's side): 1000 USD
// - preclaim sees 100 + 1000 = 1100, passes (>= 500)
// - doApply transfers 500, depositor's trust-line balance
// becomes -400
// - sanity check at VaultDeposit.cpp:256 fires
// - tx returns tefINTERNAL (BUG — should be tesSUCCESS.
auto depositTx =
vault.deposit({.depositor = depositor, .id = keylet.key, .amount = usd(500)});
env(depositTx, Ter(expected));
env.close();
};
{
testcase(
"IOU vault deposit exceeding depositor's balance but "
"within counterparty's trust limit, pre-fixCleanup3_2_0 "
"(tefINTERNAL)");
runTest(test::jtx::testableAmendments() - fixCleanup3_2_0, tefINTERNAL);
}
{
testcase(
"IOU vault deposit exceeding depositor's balance but "
"within counterparty's trust limit, post-fixCleanup3_2_0 "
"(tesSUCCESS)");
runTest(test::jtx::testableAmendments(), tesSUCCESS);
}
}
public:
void
run() override
{
testVaultDepositNegativeBalanceFromOppositeLimit();
testSequences();
testPreflight();
testCreateFailXRP();

View File

@@ -1,469 +0,0 @@
#ifdef _DEBUG
// #define DEBUG_OUTPUT 1
#endif
#include <test/app/TestHostFunctions.h>
#include <test/app/wasm_fixtures/fixtures.h>
#include <test/jtx/Env.h>
#include <xrpl/basics/Expected.h>
#include <xrpl/beast/unit_test/suite.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/TER.h>
#include <xrpl/tx/wasm/HostFunc.h>
#include <xrpl/tx/wasm/HostFuncWrapper.h> // IWYU pragma: keep
#include <xrpl/tx/wasm/WasmCommon.h>
#include <xrpl/tx/wasm/WasmImportsHelper.h>
#include <xrpl/tx/wasm/WasmVM.h>
#include <boost/algorithm/hex.hpp>
#include <wasm.h>
#include <cstdint>
#include <limits>
#include <source_location>
#include <string>
#include <vector>
namespace xrpl::test {
bool
testGetDataIncrement();
using Add_proto = int32_t(int32_t, int32_t);
static wasm_trap_t*
add(HostFunctions&, wasm_val_vec_t const* params, wasm_val_vec_t* results)
{
int32_t const val1 = params->data[0].of.i32;
int32_t const val2 = params->data[1].of.i32;
// printf("Host function \"Add\": %d + %d\n", Val1, Val2);
results->data[0] = WASM_I32_VAL(val1 + val2);
return nullptr;
}
std::vector<uint8_t>
hexToBytes(std::string const& hex)
{
auto const ws = boost::algorithm::unhex(hex);
return Bytes(ws.begin(), ws.end());
}
struct Wasm_test : public beast::unit_test::Suite
{
void
checkResult(
Expected<WasmResult<int32_t>, WasmTER> re,
int32_t expectedResult,
int64_t expectedCost,
std::source_location const location = std::source_location::current())
{
auto const lineStr = " (" + std::to_string(location.line()) + ")";
if (BEAST_EXPECTS(re.has_value(), transToken(re.error().ter) + lineStr))
{
BEAST_EXPECTS(re->result == expectedResult, std::to_string(re->result) + lineStr);
BEAST_EXPECTS(re->cost == expectedCost, std::to_string(re->cost) + lineStr);
}
}
void
testGetDataHelperFunctions()
{
testcase("getData helper functions");
BEAST_EXPECT(testGetDataIncrement());
}
void
testWasmLib()
{
testcase("wasm lib test");
// clang-format off
/* The WASM module buffer. */
Bytes const wasm = {/* WASM header */
0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00,
/* Type section */
0x01, 0x07, 0x01,
/* function type {i32, i32} -> {i32} */
0x60, 0x02, 0x7F, 0x7F, 0x01, 0x7F,
/* Import section */
0x02, 0x13, 0x01,
/* module name: "extern" */
0x06, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6E,
/* extern name: "func-add" */
0x08, 0x66, 0x75, 0x6E, 0x63, 0x2D, 0x61, 0x64, 0x64,
/* import desc: func 0 */
0x00, 0x00,
/* Function section */
0x03, 0x02, 0x01, 0x00,
/* Export section */
0x07, 0x0A, 0x01,
/* export name: "addTwo" */
0x06, 0x61, 0x64, 0x64, 0x54, 0x77, 0x6F,
/* export desc: func 0 */
0x00, 0x01,
/* Code section */
0x0A, 0x0A, 0x01,
/* code body */
0x08, 0x00, 0x20, 0x00, 0x20, 0x01, 0x10, 0x00, 0x0B};
// clang-format on
auto& vm = WasmEngine::instance();
HostFunctions hfs;
ImportVec imports;
WasmImpFunc<Add_proto>(imports, "func-add", add, hfs);
auto re = vm.run(wasm, hfs, 10'000'000, "addTwo", wasmParams(1234, 5678), imports);
// if (res) printf("invokeAdd get the result: %d\n", res.value());
checkResult(re, 6'912, 59);
}
void
testBadWasm()
{
testcase("bad wasm test");
using namespace test::jtx;
Env const env{*this};
HostFunctions hfs(env.journal);
{
auto wasm = hexToBytes("00000000");
std::string const funcName("mock_escrow");
auto re = runEscrowWasm(wasm, hfs, 15, funcName, {});
BEAST_EXPECT(!re);
}
{
auto wasm = hexToBytes("00112233445566778899AA");
std::string const funcName("mock_escrow");
auto const re = preflightEscrowWasm(wasm, hfs, funcName);
BEAST_EXPECT(!isTesSuccess(re));
}
{
// FinishFunction wrong function name
// pub fn bad() -> bool {
// unsafe { host_lib::getLedgerSqn() >= 5 }
// }
auto const badWasm = hexToBytes(
"0061736d010000000105016000017f02190108686f73745f6c69620c6765"
"744c656467657253716e00000302010005030100100611027f00418080c0"
"000b7f00418080c0000b072b04066d656d6f727902000362616400010a5f"
"5f646174615f656e6403000b5f5f686561705f6261736503010a09010700"
"100041044a0b004d0970726f64756365727302086c616e67756167650104"
"52757374000c70726f6365737365642d6279010572757374631d312e3835"
"2e31202834656231363132353020323032352d30332d31352900490f7461"
"726765745f6665617475726573042b0f6d757461626c652d676c6f62616c"
"732b087369676e2d6578742b0f7265666572656e63652d74797065732b0a"
"6d756c746976616c7565");
auto const re = preflightEscrowWasm(badWasm, hfs, escrowFunctionName);
BEAST_EXPECT(!isTesSuccess(re));
}
}
void
testWasmLedgerSqn()
{
testcase("Wasm get ledger sequence");
auto ledgerSqnWasm = hexToBytes(kLedgerSqnWasmHex);
using namespace test::jtx;
Env env{*this};
TestLedgerDataProvider hfs(env);
ImportVec imports;
WASM_IMPORT_FUNC2(imports, getLedgerSqn, "ldgr_index", hfs, 33);
auto& engine = WasmEngine::instance();
auto re =
engine.run(ledgerSqnWasm, hfs, 1'000'000, escrowFunctionName, {}, imports, env.journal);
checkResult(re, 0, 440);
env.close();
env.close();
// empty module, throwing exception
re = engine.run({}, hfs, 1'000'000, escrowFunctionName, {}, imports, env.journal);
BEAST_EXPECT(!re);
env.close();
}
void
testHFCost()
{
testcase("wasm test host functions cost");
using namespace test::jtx;
Env env(*this);
{
auto const allHostFuncWasm = hexToBytes(kAllHostFunctionsWasmHex);
auto& engine = WasmEngine::instance();
TestHostFunctions hfs(env);
auto imp = createWasmImport(hfs);
for (auto& i : imp)
i.second.second.gas = 0;
auto re = engine.run(
allHostFuncWasm, hfs, 1'000'000, escrowFunctionName, {}, imp, env.journal);
checkResult(re, 1, 27'032);
env.close();
}
env.close();
env.close();
env.close();
env.close();
env.close();
{
auto const allHostFuncWasm = hexToBytes(kAllHostFunctionsWasmHex);
auto& engine = WasmEngine::instance();
TestHostFunctions hfs(env);
auto const imp = createWasmImport(hfs);
auto re = engine.run(
allHostFuncWasm, hfs, 1'000'000, escrowFunctionName, {}, imp, env.journal);
checkResult(re, 1, 68'792);
env.close();
}
// not enough gas
{
auto const allHostFuncWasm = hexToBytes(kAllHostFunctionsWasmHex);
auto& engine = WasmEngine::instance();
TestHostFunctions hfs(env);
auto const imp = createWasmImport(hfs);
auto re =
engine.run(allHostFuncWasm, hfs, 200, escrowFunctionName, {}, imp, env.journal);
if (BEAST_EXPECT(!re))
{
// Running out of gas now terminates with tecOUT_OF_GAS (was
// previously collapsed into tecFAILED_PROCESSING).
BEAST_EXPECTS(
re.error().ter == tecOUT_OF_GAS, std::to_string(TERtoInt(re.error().ter)));
}
env.close();
}
}
void
testEscrowWasmDN()
{
testcase("escrow wasm devnet test");
auto const allHFWasm = hexToBytes(kAllHostFunctionsWasmHex);
using namespace test::jtx;
Env env{*this};
{
TestHostFunctions hfs(env);
auto re = runEscrowWasm(allHFWasm, hfs, 100'000, escrowFunctionName, {});
checkResult(re, 1, 68'792);
}
{
// Invalid gas limit (0) should be rejected (boundary condition)
TestHostFunctions hfs(env);
auto re = runEscrowWasm(allHFWasm, hfs, -1, escrowFunctionName, {});
BEAST_EXPECT(!re.has_value());
BEAST_EXPECT(re.error().ter == temBAD_AMOUNT);
}
{
// Invalid gas limit (-1) should be rejected
TestHostFunctions hfs(env);
auto re = runEscrowWasm(allHFWasm, hfs, 0, escrowFunctionName, {});
BEAST_EXPECT(!re.has_value());
BEAST_EXPECT(re.error().ter == temBAD_AMOUNT);
}
{
// max<int64_t>() gas
TestHostFunctions hfs(env);
auto re = runEscrowWasm(
allHFWasm, hfs, std::numeric_limits<int64_t>::max(), escrowFunctionName, {});
checkResult(re, 1, 68'792);
}
{ // fail because trying to access nonexistent field
struct FieldNotFoundHostFunctions : public TestHostFunctions
{
explicit FieldNotFoundHostFunctions(Env& env) : TestHostFunctions(env)
{
}
Expected<Bytes, HostFunctionError>
getTxField(SField const& fname) const override
{
return Unexpected(HostFunctionError::FieldNotFound);
}
};
FieldNotFoundHostFunctions hfs(env);
auto re = runEscrowWasm(allHFWasm, hfs, 100'000, escrowFunctionName, {});
checkResult(re, -201, 28'965);
}
{ // fail because trying to allocate more than MAX_PAGES memory
struct OversizedFieldHostFunctions : public TestHostFunctions
{
explicit OversizedFieldHostFunctions(Env& env) : TestHostFunctions(env)
{
}
Expected<Bytes, HostFunctionError>
getTxField(SField const& fname) const override
{
return Bytes((128 + 1) * 64 * 1024, 1);
}
};
OversizedFieldHostFunctions hfs(env);
auto re = runEscrowWasm(allHFWasm, hfs, 100'000, escrowFunctionName, {});
checkResult(re, -201, 28'965);
}
}
void
testCodecovWasm()
{
testcase("Codecov wasm test");
using namespace test::jtx;
Env env{*this};
auto const codecovWasm = hexToBytes(kCodecovTestsWasmHex);
TestHostFunctions hfs(env);
auto const allowance = 204'624;
auto re = runEscrowWasm(codecovWasm, hfs, allowance, escrowFunctionName, {});
checkResult(re, 1, allowance);
}
void
testBadAlign()
{
testcase("Wasm Bad Align");
// bad_align.c
auto const badAlignWasm = hexToBytes(kBadAlignWasmHex);
using namespace test::jtx;
Env env{*this};
TestHostFunctions hfs(env);
auto imports = createWasmImport(hfs);
{ // Calls float_from_uint with bad alignment.
// Can be checked through codecov
auto& engine = WasmEngine::instance();
auto re = engine.run(badAlignWasm, hfs, 1'000'000, "test", {}, imports, env.journal);
if (BEAST_EXPECTS(re, transToken(re.error().ter)))
{
BEAST_EXPECTS(re->result == 0x47308594, std::to_string(re->result));
}
}
env.close();
}
void
testSwapBytes()
{
testcase("Wasm swap bytes");
uint64_t const swapDataU64 = 0x123456789abcdeffull;
uint64_t const reverseSwapDataU64 = 0xffdebc9a78563412ull;
int64_t const swapDataI64 = 0x123456789abcdeffll;
int64_t const reverseSwapDataI64 = 0xffdebc9a78563412ll;
uint32_t const swapDataU32 = 0x12789aff;
uint32_t const reverseSwapDataU32 = 0xff9a7812;
int32_t const swapDataI32 = 0x12789aff;
int32_t const reverseSwapDataI32 = 0xff9a7812;
uint16_t const swapDataU16 = 0x12ff;
uint16_t const reverseSwapDataU16 = 0xff12;
int16_t const swapDataI16 = 0x12ff;
int16_t const reverseSwapDataI16 = 0xff12;
uint64_t b1 = swapDataU64;
int64_t b2 = swapDataI64;
b1 = adjustWasmEndianessHlp(b1);
b2 = adjustWasmEndianessHlp(b2);
BEAST_EXPECT(b1 == reverseSwapDataU64);
BEAST_EXPECT(b2 == reverseSwapDataI64);
b1 = adjustWasmEndianessHlp(b1);
b2 = adjustWasmEndianessHlp(b2);
BEAST_EXPECT(b1 == swapDataU64);
BEAST_EXPECT(b2 == swapDataI64);
uint32_t b3 = swapDataU32;
int32_t b4 = swapDataI32;
b3 = adjustWasmEndianessHlp(b3);
b4 = adjustWasmEndianessHlp(b4);
BEAST_EXPECT(b3 == reverseSwapDataU32);
BEAST_EXPECT(b4 == reverseSwapDataI32);
b3 = adjustWasmEndianessHlp(b3);
b4 = adjustWasmEndianessHlp(b4);
BEAST_EXPECT(b3 == swapDataU32);
BEAST_EXPECT(b4 == swapDataI32);
uint16_t b5 = swapDataU16;
int16_t b6 = swapDataI16;
b5 = adjustWasmEndianessHlp(b5);
b6 = adjustWasmEndianessHlp(b6);
BEAST_EXPECT(b5 == reverseSwapDataU16);
BEAST_EXPECT(b6 == reverseSwapDataI16);
b5 = adjustWasmEndianessHlp(b5);
b6 = adjustWasmEndianessHlp(b6);
BEAST_EXPECT(b5 == swapDataU16);
BEAST_EXPECT(b6 == swapDataI16);
}
void
run() override
{
using namespace test::jtx;
testGetDataHelperFunctions();
testWasmLib();
testBadWasm();
testWasmLedgerSqn();
testHFCost();
testEscrowWasmDN();
testCodecovWasm();
testBadAlign();
testSwapBytes();
}
};
BEAST_DEFINE_TESTSUITE(Wasm, app, xrpl);
} // namespace xrpl::test

View File

@@ -1,3 +0,0 @@
**/target
**/debug
*.wasm

View File

@@ -1,171 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "all_host_functions"
version = "0.1.0"
dependencies = [
"xrpl-wasm-stdlib",
]
[[package]]
name = "block-buffer"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
dependencies = [
"generic-array",
]
[[package]]
name = "bs58"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4"
dependencies = [
"tinyvec",
]
[[package]]
name = "cfg-if"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
name = "cpufeatures"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
dependencies = [
"libc",
]
[[package]]
name = "crypto-common"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
dependencies = [
"generic-array",
"typenum",
]
[[package]]
name = "digest"
version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"block-buffer",
"crypto-common",
]
[[package]]
name = "generic-array"
version = "0.14.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
dependencies = [
"typenum",
"version_check",
]
[[package]]
name = "libc"
version = "0.2.186"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
[[package]]
name = "proc-macro2"
version = "1.0.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
dependencies = [
"proc-macro2",
]
[[package]]
name = "sha2"
version = "0.10.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
dependencies = [
"cfg-if",
"cpufeatures",
"digest",
]
[[package]]
name = "syn"
version = "2.0.117"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "tinyvec"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3"
dependencies = [
"tinyvec_macros",
]
[[package]]
name = "tinyvec_macros"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "typenum"
version = "1.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de"
[[package]]
name = "unicode-ident"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
[[package]]
name = "version_check"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]]
name = "xrpl-macros"
version = "0.1.0"
source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git?branch=renames#9822d645870908a79d87a57b0244caa6359cb9cf"
dependencies = [
"bs58",
"quote",
"sha2",
"syn",
]
[[package]]
name = "xrpl-wasm-stdlib"
version = "0.8.0"
source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git?branch=renames#9822d645870908a79d87a57b0244caa6359cb9cf"
dependencies = [
"xrpl-macros",
]

View File

@@ -1,21 +0,0 @@
[package]
name = "all_host_functions"
version = "0.1.0"
edition = "2024"
# This empty workspace definition keeps this project independent of the parent workspace
[workspace]
[lib]
crate-type = ["cdylib"]
[dependencies]
xrpl-std = { git = "https://github.com/ripple/xrpl-wasm-stdlib.git", package = "xrpl-wasm-stdlib", branch = "renames" }
[profile.dev]
panic = "abort"
[profile.release]
panic = "abort"
opt-level = "z"
lto = true

View File

@@ -1,791 +0,0 @@
#![cfg_attr(target_arch = "wasm32", no_std)]
#[cfg(not(target_arch = "wasm32"))]
extern crate std;
//
// Host Functions Test
// Tests 26 host functions (across 7 categories)
//
// With craft you can run this test with:
// craft test --project host_functions_test --test-case host_functions_test
//
// Amount Format Update:
// - XRP amounts now return as 8-byte serialized rippled objects
// - IOU and MPT amounts return in variable-length serialized format
// - Format details: https://xrpl.org/docs/references/protocol/binary-format#amount-fields
//
// Error Code Ranges:
// -100 to -199: Ledger Header Functions (3 functions)
// -200 to -299: Transaction Data Functions (5 functions)
// -300 to -399: Current Ledger Object Functions (4 functions)
// -400 to -499: Any Ledger Object Functions (5 functions)
// -500 to -599: Keylet Generation Functions (4 functions)
// -600 to -699: Utility Functions (4 functions)
// -700 to -799: Data Update Functions (1 function)
//
use xrpl_std::core::current_tx::escrow_finish::EscrowFinish;
use xrpl_std::core::current_tx::traits::TransactionCommonFields;
use xrpl_std::host;
use xrpl_std::host::trace::{trace, trace_account_buf, trace_data, trace_num, DataRepr};
use xrpl_std::sfield;
#[unsafe(no_mangle)]
pub extern "C" fn finish() -> i32 {
let _ = trace("=== HOST FUNCTIONS TEST ===");
let _ = trace("Testing 26 host functions");
// Category 1: Ledger Header Data Functions (3 functions)
// Error range: -100 to -199
match test_ledger_header_functions() {
0 => (),
err => return err,
}
// Category 2: Transaction Data Functions (5 functions)
// Error range: -200 to -299
match test_transaction_data_functions() {
0 => (),
err => return err,
}
// Category 3: Current Ledger Object Functions (4 functions)
// Error range: -300 to -399
match test_current_ledger_object_functions() {
0 => (),
err => return err,
}
// Category 4: Any Ledger Object Functions (5 functions)
// Error range: -400 to -499
match test_any_ledger_object_functions() {
0 => (),
err => return err,
}
// Category 5: Keylet Generation Functions (4 functions)
// Error range: -500 to -599
match test_keylet_generation_functions() {
0 => (),
err => return err,
}
// Category 6: Utility Functions (4 functions)
// Error range: -600 to -699
match test_utility_functions() {
0 => (),
err => return err,
}
// Category 7: Data Update Functions (1 function)
// Error range: -700 to -799
match test_data_update_functions() {
0 => (),
err => return err,
}
let _ = trace("SUCCESS: All host function tests passed!");
1 // Success return code for WASM finish function
}
/// Test Category 1: Ledger Header Data Functions (3 functions)
/// - get_ledger_sqn() - Get ledger sequence number
/// - get_parent_ledger_time() - Get parent ledger timestamp
/// - get_parent_ledger_hash() - Get parent ledger hash
fn test_ledger_header_functions() -> i32 {
let _ = trace("--- Category 1: Ledger Header Functions ---");
// Test 1.1: get_ledger_sqn() - should return current ledger sequence number
let mut sqn_buffer = [0u8; 4];
let sqn_result = unsafe { host::ldgr_index(sqn_buffer.as_mut_ptr(), sqn_buffer.len()) };
if sqn_result <= 0 {
let _ = trace_num("ERROR: get_ledger_sqn failed:", sqn_result as i64);
return -101; // Ledger sequence number test failed
}
let ledger_sqn = u32::from_be_bytes(sqn_buffer);
let _ = trace_num("Ledger sequence number:", ledger_sqn as i64);
// Test 1.2: get_parent_ledger_time() - should return parent ledger timestamp
let mut time_buffer = [0u8; 4];
let time_result =
unsafe { host::parent_ldgr_time(time_buffer.as_mut_ptr(), time_buffer.len()) };
if time_result <= 0 {
let _ = trace_num("ERROR: get_parent_ledger_time failed:", time_result as i64);
return -102; // Parent ledger time test failed
}
let parent_ledger_time = u32::from_be_bytes(time_buffer);
let _ = trace_num("Parent ledger time:", parent_ledger_time as i64);
// Test 1.3: get_parent_ledger_hash() - should return parent ledger hash (32 bytes)
let mut hash_buffer = [0u8; 32];
let hash_result =
unsafe { host::parent_ldgr_hash(hash_buffer.as_mut_ptr(), hash_buffer.len()) };
if hash_result != 32 {
let _ = trace_num(
"ERROR: get_parent_ledger_hash wrong length:",
hash_result as i64,
);
return -103; // Parent ledger hash test failed - should be exactly 32 bytes
}
let _ = trace_data("Parent ledger hash:", &hash_buffer, DataRepr::AsHex);
let _ = trace("SUCCESS: Ledger header functions");
0
}
/// Test Category 2: Transaction Data Functions (5 functions)
/// Tests all functions for accessing current transaction data
fn test_transaction_data_functions() -> i32 {
let _ = trace("--- Category 2: Transaction Data Functions ---");
// Test 2.1: get_tx_field() - Basic transaction field access
// Test with Account field (required, 20 bytes)
let mut account_buffer = [0u8; 20];
let account_len = unsafe {
host::tx_field(
sfield::Account.into(),
account_buffer.as_mut_ptr(),
account_buffer.len(),
)
};
if account_len != 20 {
let _ = trace_num(
"ERROR: get_tx_field(Account) wrong length:",
account_len as i64,
);
return -201; // Basic transaction field test failed
}
let _ = trace_account_buf("Transaction Account:", &account_buffer);
// Test with Fee field (XRP amount - 8 bytes in new serialized format)
// New format: XRP amounts are always 8 bytes (positive: value | cPositive flag, negative: just value)
let mut fee_buffer = [0u8; 8];
let fee_len = unsafe {
host::tx_field(
sfield::Fee.into(),
fee_buffer.as_mut_ptr(),
fee_buffer.len(),
)
};
if fee_len != 8 {
let _ = trace_num(
"ERROR: get_tx_field(Fee) wrong length (expected 8 bytes for XRP):",
fee_len as i64,
);
return -202; // Fee field test failed - XRP amounts should be exactly 8 bytes
}
let _ = trace_num("Transaction Fee length:", fee_len as i64);
let _ = trace_data(
"Transaction Fee (serialized XRP amount):",
&fee_buffer,
DataRepr::AsHex,
);
// Test with Sequence field (required, 4 bytes uint32)
let mut seq_buffer = [0u8; 4];
let seq_len = unsafe {
host::tx_field(
sfield::Sequence.into(),
seq_buffer.as_mut_ptr(),
seq_buffer.len(),
)
};
if seq_len != 4 {
let _ = trace_num(
"ERROR: get_tx_field(Sequence) wrong length:",
seq_len as i64,
);
return -203; // Sequence field test failed
}
let _ = trace_data("Transaction Sequence:", &seq_buffer, DataRepr::AsHex);
// NOTE: get_tx_field2() through get_tx_field6() have been deprecated.
// Use get_tx_field() with appropriate parameters for all transaction field access.
// Test 2.2: get_tx_nested_field() - Nested field access with locator
let locator = [0x01_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8]; // Two int32s in little-endian: [1, 0]
let mut nested_buffer = [0u8; 32];
let nested_result = unsafe {
host::tx_inner(
locator.as_ptr(),
locator.len(),
nested_buffer.as_mut_ptr(),
nested_buffer.len(),
)
};
if nested_result < 0 {
let _ = trace_num(
"INFO: get_tx_nested_field not applicable:",
nested_result as i64,
);
// Expected - locator may not match transaction structure
} else {
let _ = trace_num("Nested field length:", nested_result as i64);
let _ = trace_data(
"Nested field:",
&nested_buffer[..nested_result as usize],
DataRepr::AsHex,
);
}
// Test 2.3: get_tx_array_len() - Get array length
let signers_len = unsafe { host::tx_arr_len(sfield::Signers.into()) };
let _ = trace_num("Signers array length:", signers_len as i64);
let memos_len = unsafe { host::tx_arr_len(sfield::Memos.into()) };
let _ = trace_num("Memos array length:", memos_len as i64);
// Test 2.4: get_tx_nested_array_len() - Get nested array length with locator
let nested_array_len = unsafe { host::tx_inner_arr_len(locator.as_ptr(), locator.len()) };
if nested_array_len < 0 {
let _ = trace_num(
"INFO: get_tx_nested_array_len not applicable:",
nested_array_len as i64,
);
} else {
let _ = trace_num("Nested array length:", nested_array_len as i64);
}
let _ = trace("SUCCESS: Transaction data functions");
0
}
/// Test Category 3: Current Ledger Object Functions (4 functions)
/// Tests functions that access the current ledger object being processed
fn test_current_ledger_object_functions() -> i32 {
let _ = trace("--- Category 3: Current Ledger Object Functions ---");
// Test 3.1: get_current_ledger_obj_field() - Access field from current ledger object
// Test with Balance field (XRP amount - 8 bytes in new serialized format)
let mut balance_buffer = [0u8; 8];
let balance_result = unsafe {
host::home_le_field(
sfield::Balance.into(),
balance_buffer.as_mut_ptr(),
balance_buffer.len(),
)
};
if balance_result <= 0 {
let _ = trace_num(
"INFO: get_current_ledger_obj_field(Balance) failed (may be expected):",
balance_result as i64,
);
// This might fail if current ledger object doesn't have balance field
} else if balance_result == 8 {
let _ = trace_num(
"Current object balance length (XRP amount):",
balance_result as i64,
);
let _ = trace_data(
"Current object balance (serialized XRP amount):",
&balance_buffer,
DataRepr::AsHex,
);
} else {
let _ = trace_num(
"Current object balance length (non-XRP amount):",
balance_result as i64,
);
let _ = trace_data(
"Current object balance:",
&balance_buffer[..balance_result as usize],
DataRepr::AsHex,
);
}
// Test with Account field
let mut current_account_buffer = [0u8; 20];
let current_account_result = unsafe {
host::home_le_field(
sfield::Account.into(),
current_account_buffer.as_mut_ptr(),
current_account_buffer.len(),
)
};
if current_account_result <= 0 {
let _ = trace_num(
"INFO: get_current_ledger_obj_field(Account) failed:",
current_account_result as i64,
);
} else {
let _ = trace_account_buf("Current ledger object account:", &current_account_buffer);
}
// Test 3.2: get_current_ledger_obj_nested_field() - Nested field access
let locator = [0x01_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8]; // Two int32s in little-endian: [1, 0]
let mut current_nested_buffer = [0u8; 32];
let current_nested_result = unsafe {
host::home_le_inner(
locator.as_ptr(),
locator.len(),
current_nested_buffer.as_mut_ptr(),
current_nested_buffer.len(),
)
};
if current_nested_result < 0 {
let _ = trace_num(
"INFO: get_current_ledger_obj_nested_field not applicable:",
current_nested_result as i64,
);
} else {
let _ = trace_num("Current nested field length:", current_nested_result as i64);
let _ = trace_data(
"Current nested field:",
&current_nested_buffer[..current_nested_result as usize],
DataRepr::AsHex,
);
}
// Test 3.3: get_current_ledger_obj_array_len() - Array length in current object
let current_array_len = unsafe { host::home_le_arr_len(sfield::Signers.into()) };
let _ = trace_num(
"Current object Signers array length:",
current_array_len as i64,
);
// Test 3.4: get_current_ledger_obj_nested_array_len() - Nested array length
let current_nested_array_len =
unsafe { host::home_le_inner_arr_len(locator.as_ptr(), locator.len()) };
if current_nested_array_len < 0 {
let _ = trace_num(
"INFO: get_current_ledger_obj_nested_array_len not applicable:",
current_nested_array_len as i64,
);
} else {
let _ = trace_num(
"Current nested array length:",
current_nested_array_len as i64,
);
}
let _ = trace("SUCCESS: Current ledger object functions");
0
}
/// Test Category 4: Any Ledger Object Functions (5 functions)
/// Tests functions that work with cached ledger objects
fn test_any_ledger_object_functions() -> i32 {
let _ = trace("--- Category 4: Any Ledger Object Functions ---");
// First we need to cache a ledger object to test the other functions
// Get the account from transaction and generate its keylet
let escrow_finish = EscrowFinish;
let account_id = escrow_finish.get_account().unwrap();
// Test 4.1: cache_ledger_obj() - Cache a ledger object
let mut keylet_buffer = [0u8; 32];
let keylet_result = unsafe {
host::accountroot_id(
account_id.0.as_ptr(),
account_id.0.len(),
keylet_buffer.as_mut_ptr(),
keylet_buffer.len(),
)
};
if keylet_result != 32 {
let _ = trace_num(
"ERROR: accountroot_id failed for caching test:",
keylet_result as i64,
);
return -401; // Keylet generation failed for caching test
}
let cache_result = unsafe { host::cache_le(keylet_buffer.as_ptr(), keylet_result as usize, 0) };
if cache_result <= 0 {
let _ = trace_num(
"INFO: cache_ledger_obj failed (expected with test fixtures):",
cache_result as i64,
);
// Test fixtures may not contain the account object - this is expected
// We'll test the interface but expect failures
// Test 4.2-4.5 with invalid slot (should fail gracefully)
let mut test_buffer = [0u8; 32];
// Test get_ledger_obj_field with invalid slot
let field_result = unsafe {
host::le_field(
1,
sfield::Balance.into(),
test_buffer.as_mut_ptr(),
test_buffer.len(),
)
};
if field_result < 0 {
let _ = trace_num(
"INFO: get_ledger_obj_field failed as expected (no cached object):",
field_result as i64,
);
}
// Test get_ledger_obj_nested_field with invalid slot
let locator = [0x01_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8]; // Two int32s in little-endian: [1, 0]
let nested_result = unsafe {
host::le_inner(
1,
locator.as_ptr(),
locator.len(),
test_buffer.as_mut_ptr(),
test_buffer.len(),
)
};
if nested_result < 0 {
let _ = trace_num(
"INFO: get_ledger_obj_nested_field failed as expected:",
nested_result as i64,
);
}
// Test get_ledger_obj_array_len with invalid slot
let array_result = unsafe { host::le_arr_len(1, sfield::Signers.into()) };
if array_result < 0 {
let _ = trace_num(
"INFO: get_ledger_obj_array_len failed as expected:",
array_result as i64,
);
}
// Test get_ledger_obj_nested_array_len with invalid slot
let nested_array_result =
unsafe { host::le_inner_arr_len(1, locator.as_ptr(), locator.len()) };
if nested_array_result < 0 {
let _ = trace_num(
"INFO: get_ledger_obj_nested_array_len failed as expected:",
nested_array_result as i64,
);
}
let _ = trace("SUCCESS: Any ledger object functions (interface tested)");
return 0;
}
// If we successfully cached an object, test the access functions
let slot = cache_result;
let _ = trace_num("Successfully cached object in slot:", slot as i64);
// Test 4.2: get_ledger_obj_field() - Access field from cached object
let mut cached_balance_buffer = [0u8; 8];
let cached_balance_result = unsafe {
host::le_field(
slot,
sfield::Balance.into(),
cached_balance_buffer.as_mut_ptr(),
cached_balance_buffer.len(),
)
};
if cached_balance_result <= 0 {
let _ = trace_num(
"INFO: get_ledger_obj_field(Balance) failed:",
cached_balance_result as i64,
);
} else if cached_balance_result == 8 {
let _ = trace_num(
"Cached object balance length (XRP amount):",
cached_balance_result as i64,
);
let _ = trace_data(
"Cached object balance (serialized XRP amount):",
&cached_balance_buffer,
DataRepr::AsHex,
);
} else {
let _ = trace_num(
"Cached object balance length (non-XRP amount):",
cached_balance_result as i64,
);
let _ = trace_data(
"Cached object balance:",
&cached_balance_buffer[..cached_balance_result as usize],
DataRepr::AsHex,
);
}
// Test 4.3: get_ledger_obj_nested_field() - Nested field from cached object
let locator = [0x01_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8]; // Two int32s in little-endian: [1, 0]
let mut cached_nested_buffer = [0u8; 32];
let cached_nested_result = unsafe {
host::le_inner(
slot,
locator.as_ptr(),
locator.len(),
cached_nested_buffer.as_mut_ptr(),
cached_nested_buffer.len(),
)
};
if cached_nested_result < 0 {
let _ = trace_num(
"INFO: get_ledger_obj_nested_field not applicable:",
cached_nested_result as i64,
);
} else {
let _ = trace_num("Cached nested field length:", cached_nested_result as i64);
let _ = trace_data(
"Cached nested field:",
&cached_nested_buffer[..cached_nested_result as usize],
DataRepr::AsHex,
);
}
// Test 4.4: get_ledger_obj_array_len() - Array length from cached object
let cached_array_len = unsafe { host::le_arr_len(slot, sfield::Signers.into()) };
let _ = trace_num(
"Cached object Signers array length:",
cached_array_len as i64,
);
// Test 4.5: get_ledger_obj_nested_array_len() - Nested array length from cached object
let cached_nested_array_len =
unsafe { host::le_inner_arr_len(slot, locator.as_ptr(), locator.len()) };
if cached_nested_array_len < 0 {
let _ = trace_num(
"INFO: get_ledger_obj_nested_array_len not applicable:",
cached_nested_array_len as i64,
);
} else {
let _ = trace_num(
"Cached nested array length:",
cached_nested_array_len as i64,
);
}
let _ = trace("SUCCESS: Any ledger object functions");
0
}
/// Test Category 5: Keylet Generation Functions (4 functions)
/// Tests keylet generation functions for different ledger entry types
fn test_keylet_generation_functions() -> i32 {
let _ = trace("--- Category 5: Keylet Generation Functions ---");
let escrow_finish = EscrowFinish;
let account_id = escrow_finish.get_account().unwrap();
// Test 5.1: accountroot_id() - Generate keylet for account
let mut accountroot_id_buffer = [0u8; 32];
let accountroot_id_result = unsafe {
host::accountroot_id(
account_id.0.as_ptr(),
account_id.0.len(),
accountroot_id_buffer.as_mut_ptr(),
accountroot_id_buffer.len(),
)
};
if accountroot_id_result != 32 {
let _ = trace_num(
"ERROR: accountroot_id failed:",
accountroot_id_result as i64,
);
return -501; // Account keylet generation failed
}
let _ = trace_data("Account keylet:", &accountroot_id_buffer, DataRepr::AsHex);
// Test 5.2: credential_keylet() - Generate keylet for credential
let mut credential_keylet_buffer = [0u8; 32];
let credential_keylet_result = unsafe {
host::credential_id(
account_id.0.as_ptr(), // Subject
account_id.0.len(),
account_id.0.as_ptr(), // Issuer - same account for test
account_id.0.len(),
b"TestType".as_ptr(), // Credential type
9usize, // Length of "TestType"
credential_keylet_buffer.as_mut_ptr(),
credential_keylet_buffer.len(),
)
};
if credential_keylet_result <= 0 {
let _ = trace_num(
"INFO: credential_keylet failed (expected - interface issue):",
credential_keylet_result as i64,
);
// This is expected to fail due to unusual parameter types
} else {
let _ = trace_data(
"Credential keylet:",
&credential_keylet_buffer[..credential_keylet_result as usize],
DataRepr::AsHex,
);
}
// Test 5.3: escrow_keylet() - Generate keylet for escrow
let mut escrow_keylet_buffer = [0u8; 32];
let sequence_number: i32 = 1000;
let sequence_number_bytes = sequence_number.to_be_bytes();
let escrow_keylet_result = unsafe {
host::escrow_id(
account_id.0.as_ptr(),
account_id.0.len(),
sequence_number_bytes.as_ptr(),
sequence_number_bytes.len(),
escrow_keylet_buffer.as_mut_ptr(),
escrow_keylet_buffer.len(),
)
};
if escrow_keylet_result != 32 {
let _ = trace_num("ERROR: escrow_keylet failed:", escrow_keylet_result as i64);
return -503; // Escrow keylet generation failed
}
let _ = trace_data("Escrow keylet:", &escrow_keylet_buffer, DataRepr::AsHex);
// Test 5.4: oracle_keylet() - Generate keylet for oracle
let mut oracle_keylet_buffer = [0u8; 32];
let document_id: i32 = 42;
let document_id_bytes = document_id.to_be_bytes();
let oracle_keylet_result = unsafe {
host::oracle_id(
account_id.0.as_ptr(),
account_id.0.len(),
document_id_bytes.as_ptr(),
document_id_bytes.len(),
oracle_keylet_buffer.as_mut_ptr(),
oracle_keylet_buffer.len(),
)
};
if oracle_keylet_result != 32 {
let _ = trace_num("ERROR: oracle_keylet failed:", oracle_keylet_result as i64);
return -504; // Oracle keylet generation failed
}
let _ = trace_data("Oracle keylet:", &oracle_keylet_buffer, DataRepr::AsHex);
let _ = trace("SUCCESS: Keylet generation functions");
0
}
/// Test Category 6: Utility Functions (4 functions)
/// Tests utility functions for hashing, NFT access, and tracing
fn test_utility_functions() -> i32 {
let _ = trace("--- Category 6: Utility Functions ---");
// Test 6.1: compute_sha512_half() - SHA512 hash computation (first 32 bytes)
let test_data = b"Hello, XRPL WASM world!";
let mut hash_output = [0u8; 32];
let hash_result = unsafe {
host::sha512_half(
test_data.as_ptr(),
test_data.len(),
hash_output.as_mut_ptr(),
hash_output.len(),
)
};
if hash_result != 32 {
let _ = trace_num("ERROR: compute_sha512_half failed:", hash_result as i64);
return -601; // SHA512 half computation failed
}
let _ = trace_data("Input data:", test_data, DataRepr::AsHex);
let _ = trace_data("SHA512 half hash:", &hash_output, DataRepr::AsHex);
// Test 6.2: get_nft() - NFT data retrieval
let escrow_finish = EscrowFinish;
let account_id = escrow_finish.get_account().unwrap();
let nft_id = [0u8; 32]; // Dummy NFT ID for testing
let mut nft_buffer = [0u8; 256];
let nft_result = unsafe {
host::nft_uri(
account_id.0.as_ptr(),
account_id.0.len(),
nft_id.as_ptr(),
nft_id.len(),
nft_buffer.as_mut_ptr(),
nft_buffer.len(),
)
};
if nft_result <= 0 {
let _ = trace_num(
"INFO: get_nft failed (expected - no such NFT):",
nft_result as i64,
);
// This is expected - test account likely doesn't own the dummy NFT
} else {
let _ = trace_num("NFT data length:", nft_result as i64);
let _ = trace_data(
"NFT data:",
&nft_buffer[..nft_result as usize],
DataRepr::AsHex,
);
}
// Test 6.3: trace() - Debug logging with data
let trace_message = b"Test trace message";
let trace_data_payload = b"payload";
let trace_result = unsafe {
host::trace(
trace_message.as_ptr(),
trace_message.len(),
trace_data_payload.as_ptr(),
trace_data_payload.len(),
1, // as_hex = true
)
};
if trace_result < 0 {
let _ = trace_num("ERROR: trace() failed:", trace_result as i64);
return -603; // Trace function failed
}
let _ = trace_num("Trace function bytes written:", trace_result as i64);
// Test 6.4: trace_num() - Debug logging with number
let test_number = 42i64;
let trace_num_result = trace_num("Test number trace", test_number);
use xrpl_std::host::Result;
match trace_num_result {
Result::Ok(_) => {
let _ = trace_num("Trace_num function succeeded", 0);
}
Result::Err(_) => {
let _ = trace_num("ERROR: trace_num() failed:", -604);
return -604; // Trace number function failed
}
}
let _ = trace("SUCCESS: Utility functions");
0
}
/// Test Category 7: Data Update Functions (1 function)
/// Tests the function for modifying the current ledger entry
fn test_data_update_functions() -> i32 {
let _ = trace("--- Category 7: Data Update Functions ---");
// Test 7.1: update_data() - Update current ledger entry data
let update_payload = b"Updated ledger entry data from WASM test";
let update_result = unsafe { host::set_data(update_payload.as_ptr(), update_payload.len()) };
if update_result != update_payload.len() as i32 {
let _ = trace_num("ERROR: update_data failed:", update_result as i64);
return -701; // Data update failed
}
let _ = trace_data(
"Successfully updated ledger entry with:",
update_payload,
DataRepr::AsHex,
);
let _ = trace("SUCCESS: Data update functions");
0
}

View File

@@ -1,171 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "all_keylets"
version = "0.0.1"
dependencies = [
"xrpl-wasm-stdlib",
]
[[package]]
name = "block-buffer"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
dependencies = [
"generic-array",
]
[[package]]
name = "bs58"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4"
dependencies = [
"tinyvec",
]
[[package]]
name = "cfg-if"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
name = "cpufeatures"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
dependencies = [
"libc",
]
[[package]]
name = "crypto-common"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
dependencies = [
"generic-array",
"typenum",
]
[[package]]
name = "digest"
version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"block-buffer",
"crypto-common",
]
[[package]]
name = "generic-array"
version = "0.14.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
dependencies = [
"typenum",
"version_check",
]
[[package]]
name = "libc"
version = "0.2.186"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
[[package]]
name = "proc-macro2"
version = "1.0.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
dependencies = [
"proc-macro2",
]
[[package]]
name = "sha2"
version = "0.10.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
dependencies = [
"cfg-if",
"cpufeatures",
"digest",
]
[[package]]
name = "syn"
version = "2.0.117"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "tinyvec"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3"
dependencies = [
"tinyvec_macros",
]
[[package]]
name = "tinyvec_macros"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "typenum"
version = "1.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de"
[[package]]
name = "unicode-ident"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
[[package]]
name = "version_check"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]]
name = "xrpl-macros"
version = "0.1.0"
source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git?branch=renames#21c522f34a24b460297ebb6be1822680459bf37e"
dependencies = [
"bs58",
"quote",
"sha2",
"syn",
]
[[package]]
name = "xrpl-wasm-stdlib"
version = "0.8.0"
source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git?branch=renames#21c522f34a24b460297ebb6be1822680459bf37e"
dependencies = [
"xrpl-macros",
]

View File

@@ -1,21 +0,0 @@
[package]
edition = "2024"
name = "all_keylets"
version = "0.0.1"
# This empty workspace definition keeps this project independent of the parent workspace
[workspace]
[lib]
crate-type = ["cdylib"]
[profile.release]
lto = true
opt-level = 's'
panic = "abort"
[dependencies]
xrpl-std = { git = "https://github.com/ripple/xrpl-wasm-stdlib.git", package = "xrpl-wasm-stdlib", branch = "renames" }
[profile.dev]
panic = "abort"

View File

@@ -1,176 +0,0 @@
#![cfg_attr(target_arch = "wasm32", no_std)]
#[cfg(not(target_arch = "wasm32"))]
extern crate std;
use crate::host::{Error, Result, Result::Err, Result::Ok};
use xrpl_std::core::keylets;
use xrpl_std::core::ledger_objects::current_escrow::get_current_escrow;
use xrpl_std::core::ledger_objects::current_escrow::CurrentEscrow;
use xrpl_std::core::ledger_objects::ledger_object;
use xrpl_std::core::ledger_objects::traits::CurrentEscrowFields;
use xrpl_std::core::ledger_objects::LedgerObjectFieldGetter;
use xrpl_std::core::types::currency::Currency;
use xrpl_std::core::types::issue::{IouIssue, Issue, XrpIssue};
use xrpl_std::core::types::mpt_id::MptId;
use xrpl_std::host;
use xrpl_std::host::trace::{trace, trace_acct, trace_data, trace_num, DataRepr};
use xrpl_std::sfield;
pub fn object_exists<T: LedgerObjectFieldGetter, const CODE: i32>(
keylet_result: Result<keylets::KeyletBytes>,
keylet_type: &str,
sfield: sfield::SField<T, CODE>,
) -> Result<bool> {
let field = CODE;
match keylet_result {
Ok(keylet) => {
let _ = trace_data(keylet_type, &keylet, DataRepr::AsHex);
let slot = unsafe { host::cache_le(keylet.as_ptr(), keylet.len(), 0) };
if slot <= 0 {
let _ = trace_num("Error: ", slot.into());
return Err(Error::from_code(slot));
}
if field == 0 {
let new_field = sfield::PreviousTxnID;
let _ = trace_num("Getting field: ", new_field.clone().into());
match ledger_object::get_field(slot, new_field) {
Ok(data) => {
let _ = trace_data("Field data: ", &data.0, DataRepr::AsHex);
}
Err(result_code) => {
let _ = trace_num("Error getting field: ", result_code.into());
return Err(result_code);
}
}
} else {
let _ = trace_num("Getting field: ", field.into());
match ledger_object::get_field(slot, sfield) {
Ok(_data) => {
let _ = trace("Field data: retrieved");
}
Err(result_code) => {
let _ = trace_num("Error getting field: ", result_code.into());
return Err(result_code);
}
}
}
Ok(true)
}
Err(error) => {
let _ = trace_num("Error getting keylet: ", error.into());
Err(error)
}
}
}
#[unsafe(no_mangle)]
pub extern "C" fn finish() -> i32 {
let _ = trace("$$$$$ STARTING WASM EXECUTION $$$$$");
let escrow: CurrentEscrow = get_current_escrow();
let account = escrow.get_account().unwrap_or_panic();
let _ = trace_acct("Account:", &account);
let destination = escrow.get_destination().unwrap_or_panic();
let _ = trace_acct("Destination:", &destination);
let mut seq = 5;
macro_rules! check_object_exists {
($keylet:expr, $type:expr, $field:expr) => {
match object_exists($keylet, $type, $field) {
Ok(_exists) => {
// false isn't returned
let _ = trace(concat!(
$type,
" object exists, proceeding with escrow finish."
));
}
Err(error) => {
let _ = trace_num("Current seq value:", seq.try_into().unwrap());
return error.code();
}
}
};
}
let accountroot_id = keylets::accountroot_id(&account);
check_object_exists!(accountroot_id, "Account", sfield::Account);
let currency_code: &[u8; 3] = b"USD";
let currency: Currency = Currency::from(*currency_code);
let trustline_id = keylets::trustline_id(&account, &destination, &currency);
check_object_exists!(trustline_id, "Trustline", sfield::Generic);
seq += 1;
let asset1 = Issue::XRP(XrpIssue {});
let asset2 = Issue::IOU(IouIssue::new(destination, currency));
check_object_exists!(keylets::amm_id(&asset1, &asset2), "AMM", sfield::Account);
let check_id = keylets::check_id(&account, seq);
check_object_exists!(check_id, "Check", sfield::Account);
seq += 1;
let cred_type: &[u8] = b"termsandconditions";
let credential_id = keylets::credential_id(&account, &account, cred_type);
check_object_exists!(credential_id, "Credential", sfield::Subject);
seq += 1;
let delegate_id = keylets::delegate_id(&account, &destination);
check_object_exists!(delegate_id, "Delegate", sfield::Account);
seq += 1;
let deposit_preauth_id = keylets::deposit_preauth_id(&account, &destination);
check_object_exists!(deposit_preauth_id, "DepositPreauth", sfield::Account);
seq += 1;
let did_id = keylets::did_id(&account);
check_object_exists!(did_id, "DID", sfield::Account);
seq += 1;
let escrow_id = keylets::escrow_id(&account, seq);
check_object_exists!(escrow_id, "Escrow", sfield::Account);
seq += 1;
let mpt_issuance_id = keylets::mpt_issuance_id(&account, seq);
let mpt_id = MptId::new(seq.try_into().unwrap(), account);
check_object_exists!(mpt_issuance_id, "MPTIssuance", sfield::Issuer);
seq += 1;
let mptoken_id = keylets::mptoken_id(&mpt_id, &destination);
check_object_exists!(mptoken_id, "MPToken", sfield::Account);
let nft_offer_id = keylets::nft_offer_id(&destination, 6);
check_object_exists!(nft_offer_id, "NFTokenOffer", sfield::Owner);
let offer_id = keylets::offer_id(&account, seq);
check_object_exists!(offer_id, "Offer", sfield::Account);
seq += 1;
let paychan_id = keylets::paychan_id(&account, &destination, seq);
check_object_exists!(paychan_id, "PayChannel", sfield::Account);
seq += 1;
let pd_id = keylets::permissioned_domain_id(&account, seq);
check_object_exists!(pd_id, "PermissionedDomain", sfield::Owner);
seq += 1;
let signers_id = keylets::signers_id(&account);
check_object_exists!(signers_id, "SignerList", sfield::Generic);
seq += 1;
seq += 1; // ticket sequence number is one greater
let ticket_id = keylets::ticket_id(&account, seq);
check_object_exists!(ticket_id, "Ticket", sfield::Account);
seq += 1;
let vault_id = keylets::vault_id(&account, seq);
check_object_exists!(vault_id, "Vault", sfield::Account);
// seq += 1;
1 // All keylets exist, finish the escrow.
}

View File

@@ -1,42 +0,0 @@
#include <stdint.h>
int32_t float_from_uint(uint8_t const *, int32_t, uint8_t *, int32_t, int32_t);
int32_t check_id(uint8_t const *, int32_t, uint8_t const *, int32_t, uint8_t *,
int32_t);
uint8_t e_data1[32 * 1024];
uint8_t e_data2[32 * 1024];
int32_t test1()
{
e_data1[1] = 0xFF;
e_data1[2] = 0xFF;
e_data1[3] = 0xFF;
e_data1[4] = 0xFF;
e_data1[5] = 0xFF;
e_data1[6] = 0xFF;
e_data1[7] = 0xFF;
e_data1[8] = 0xFF;
int32_t result = float_from_uint(&e_data1[1], 8, &e_data1[35], 12, 0);
return result >= 0 ? *((int32_t *)(&e_data1[36])) : result;
}
int32_t test2()
{
// Set up misaligned uint32 (seq) at offset 1
e_data2[1] = 0xFF;
e_data2[2] = 0xFF;
e_data2[3] = 0xFF;
e_data2[4] = 0xFF;
// Set up valid non-zero AccountID (20 bytes) at offset 10
for (int i = 0; i < 20; i++)
e_data2[10 + i] = i + 1;
// Call check_id with misaligned uint32 at &e_data2[1] to hit line 72 in
// HostFuncWrapper.cpp
int32_t result = check_id(&e_data2[10], 20, &e_data2[1], 4, &e_data2[35], 32);
// Return the misaligned value directly to validate it was read correctly (-1
// if all 0xFF)
return result >= 0 ? *((int32_t *)(&e_data2[36])) : result;
}
int32_t test() { return test1() + test2(); }

View File

@@ -1,171 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "block-buffer"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
dependencies = [
"generic-array",
]
[[package]]
name = "bs58"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4"
dependencies = [
"tinyvec",
]
[[package]]
name = "cfg-if"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
name = "codecov_tests"
version = "0.0.1"
dependencies = [
"xrpl-wasm-stdlib",
]
[[package]]
name = "cpufeatures"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
dependencies = [
"libc",
]
[[package]]
name = "crypto-common"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
dependencies = [
"generic-array",
"typenum",
]
[[package]]
name = "digest"
version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"block-buffer",
"crypto-common",
]
[[package]]
name = "generic-array"
version = "0.14.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
dependencies = [
"typenum",
"version_check",
]
[[package]]
name = "libc"
version = "0.2.186"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
[[package]]
name = "proc-macro2"
version = "1.0.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
dependencies = [
"proc-macro2",
]
[[package]]
name = "sha2"
version = "0.10.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
dependencies = [
"cfg-if",
"cpufeatures",
"digest",
]
[[package]]
name = "syn"
version = "2.0.117"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "tinyvec"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3"
dependencies = [
"tinyvec_macros",
]
[[package]]
name = "tinyvec_macros"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "typenum"
version = "1.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de"
[[package]]
name = "unicode-ident"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
[[package]]
name = "version_check"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]]
name = "xrpl-macros"
version = "0.1.0"
source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git?branch=renames#9822d645870908a79d87a57b0244caa6359cb9cf"
dependencies = [
"bs58",
"quote",
"sha2",
"syn",
]
[[package]]
name = "xrpl-wasm-stdlib"
version = "0.8.0"
source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git?branch=renames#9822d645870908a79d87a57b0244caa6359cb9cf"
dependencies = [
"xrpl-macros",
]

View File

@@ -1,18 +0,0 @@
[package]
edition = "2024"
name = "codecov_tests"
version = "0.0.1"
# This empty workspace definition keeps this project independent of the parent workspace
[workspace]
[lib]
crate-type = ["cdylib"]
[profile.release]
lto = true
opt-level = 's'
panic = "abort"
[dependencies]
xrpl-std = { git = "https://github.com/ripple/xrpl-wasm-stdlib.git", package = "xrpl-wasm-stdlib", branch = "renames" }

View File

@@ -1,47 +0,0 @@
//TODO add docs after discussing the interface
//Note that Craft currently does not honor the rounding modes
#[allow(unused)]
pub const FLOAT_ROUNDING_MODES_TO_NEAREST: i32 = 0;
#[allow(unused)]
pub const FLOAT_ROUNDING_MODES_TOWARDS_ZERO: i32 = 1;
#[allow(unused)]
pub const FLOAT_ROUNDING_MODES_DOWNWARD: i32 = 2;
#[allow(unused)]
pub const FLOAT_ROUNDING_MODES_UPWARD: i32 = 3;
// pub enum RippledRoundingModes{
// ToNearest = 0,
// TowardsZero = 1,
// DOWNWARD = 2,
// UPWARD = 3
// }
#[allow(unused)]
#[link(wasm_import_module = "host_lib")]
unsafe extern "C" {
pub fn parent_ldgr_hash(out_buff_ptr: i32, out_buff_len: i32) -> i32;
pub fn cache_le(keylet_ptr: i32, keylet_len: i32, cache_num: i32) -> i32;
pub fn tx_inner_arr_len(locator_ptr: i32, locator_len: i32) -> i32;
pub fn accountroot_id(
account_ptr: i32,
account_len: i32,
out_buff_ptr: *mut u8,
out_buff_len: usize,
) -> i32;
pub fn trustline_id(
account1_ptr: *const u8,
account1_len: usize,
account2_ptr: *const u8,
account2_len: usize,
currency_ptr: i32,
currency_len: i32,
out_buff_ptr: *mut u8,
out_buff_len: usize,
) -> i32;
pub fn trace_num(msg_read_ptr: i32, msg_read_len: i32, number: i64) -> i32;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,287 +0,0 @@
# cspell: disable
import os
import re
import shlex
import subprocess
import sys
import tempfile
import zipfile
from difflib import get_close_matches
OPT = "-Oz"
BASE_PATH = os.path.abspath(os.path.dirname(__file__))
def pascal_case(name):
return "".join(word[:1].upper() + word[1:] for word in re.split(r"[_\W]+", name))
def normalize_name(name):
name = re.sub(r"([a-z0-9])([A-Z])", r"\1_\2", name)
return re.sub(r"[^a-z0-9]", "", name.lower())
def fixture_key(name):
name = normalize_name(name).removeprefix("k")
return name.removesuffix("wasmhex").removesuffix("hex")
def declared_fixtures():
h_path = os.path.join(BASE_PATH, "fixtures.h")
with open(h_path, "r", encoding="utf8") as f:
return re.findall(
r"extern std::string const ([A-Za-z_][A-Za-z0-9_]*);", f.read()
)
def find_fixture_name(project_name, suffix):
default = re.sub(r"_([a-z])", lambda m: m.group(1).upper(), project_name) + suffix
k_default = f"k{pascal_case(project_name)}{suffix}"
declarations = declared_fixtures()
normalized = {normalize_name(name): name for name in declarations}
fixture_keys = {fixture_key(name): name for name in declarations}
for name in (default, k_default):
if normalize_name(name) in normalized:
return normalized[normalize_name(name)]
project_key = normalize_name(project_name)
matches = [
name
for key, name in fixture_keys.items()
if key.endswith(project_key)
or key.startswith(project_key)
or project_key.endswith(key)
or project_key.startswith(key)
]
if len(matches) == 1:
return matches[0]
close = get_close_matches(project_key, fixture_keys.keys(), n=1, cutoff=0.82)
if close:
return fixture_keys[close[0]]
return k_default
def fixture_cpp_path(fixture_name):
pattern = rf"extern std::string const {fixture_name} ="
for file_name in os.listdir(BASE_PATH):
if not file_name.endswith(".cpp"):
continue
cpp_path = os.path.join(BASE_PATH, file_name)
with open(cpp_path, "r", encoding="utf8") as f:
if re.search(pattern, f.read()):
return cpp_path
return os.path.join(BASE_PATH, "fixtures.cpp")
def update_fixture(project_name, wasm, suffix="WasmHex"):
fixture_name = find_fixture_name(project_name, suffix)
print(f"Updating fixture: {fixture_name}")
cpp_path = fixture_cpp_path(fixture_name)
h_path = os.path.join(BASE_PATH, "fixtures.h")
with open(cpp_path, "r", encoding="utf8") as f:
cpp_content = f.read()
pattern = rf'extern std::string const {fixture_name} =[ \n]+"[^;]*;'
if re.search(pattern, cpp_content, flags=re.MULTILINE):
updated_cpp_content = re.sub(
pattern,
f'extern std::string const {fixture_name} = "{wasm}";',
cpp_content,
flags=re.MULTILINE,
)
else:
with open(h_path, "r", encoding="utf8") as f:
h_content = f.read()
updated_h_content = (
h_content.rstrip() + f"\n\nextern std::string const {fixture_name};\n"
)
with open(h_path, "w", encoding="utf8") as f:
f.write(updated_h_content)
updated_cpp_content = (
cpp_content.rstrip()
+ f'\n\nextern std::string const {fixture_name} = "{wasm}";\n'
)
with open(cpp_path, "w", encoding="utf8") as f:
f.write(updated_cpp_content)
def read_wasm_hex(path):
with open(path, "rb") as f:
return f.read().hex()
def process_rust(project_name):
project_path = os.path.join(BASE_PATH, project_name)
wasm_location = os.path.join(
project_path, "target", "wasm32v1-none", "release", f"{project_name}.wasm"
)
try:
subprocess.run(
["cargo", "build", "--target", "wasm32v1-none", "--release"],
cwd=project_path,
check=True,
)
subprocess.run(
["wasm-opt", wasm_location, OPT, "-o", wasm_location], check=True
)
print(f"WASM file for {project_name} has been built and optimized.")
except FileNotFoundError as e:
print(f"exec error: {e.filename} is required to build Rust fixtures")
sys.exit(1)
except subprocess.CalledProcessError as e:
print(f"exec error: {e}")
sys.exit(1)
update_fixture(project_name, read_wasm_hex(wasm_location))
def process_c(project_name):
project_path = os.path.join(BASE_PATH, f"{project_name}.c")
wasm_path = os.path.join(BASE_PATH, f"{project_name}.wasm")
cc = os.environ.get("CC")
sysroot = os.environ.get("SYSROOT")
if not cc or not sysroot:
print("exec error: CC and SYSROOT are required to build C fixtures")
sys.exit(1)
build_cmd = [
*shlex.split(cc),
f"--sysroot={sysroot}",
"-O3",
"-ffast-math",
"--target=wasm32",
"-fno-exceptions",
"-fno-threadsafe-statics",
"-fvisibility=default",
"-Wl,--export-all",
"-Wl,--no-entry",
"-Wl,--allow-undefined",
"-DNDEBUG",
"--no-standard-libraries",
"-fno-builtin-memset",
"-o",
wasm_path,
project_path,
]
try:
subprocess.run(build_cmd, check=True)
subprocess.run(["wasm-opt", wasm_path, OPT, "-o", wasm_path], check=True)
print(
f"WASM file for {project_name} has been built with WASI support using clang."
)
except FileNotFoundError as e:
print(f"exec error: {e.filename} is required to build C fixtures")
sys.exit(1)
except subprocess.CalledProcessError as e:
print(f"exec error: {e}")
sys.exit(1)
update_fixture(project_name, read_wasm_hex(wasm_path))
def wat_to_wasm(wat_path, wasm_path):
build_cmd = ["wat2wasm", wat_path, "-o", wasm_path]
try:
subprocess.run(build_cmd, check=True)
print(f"WASM file for {os.path.basename(wat_path)} has been built.")
except FileNotFoundError:
print("exec error: wat2wasm is required to build WAT fixtures")
sys.exit(1)
except subprocess.CalledProcessError as e:
print(f"exec error: {e}")
sys.exit(1)
def process_wat_file(wat_path):
project_name = os.path.splitext(os.path.basename(wat_path))[0]
with open(wat_path, "r", encoding="utf8") as f:
if "(module" not in f.read():
print(f"Skipping WAT fixture without a module: {project_name}")
return
with tempfile.TemporaryDirectory() as tmpdir:
wasm_path = os.path.join(tmpdir, f"{project_name}.wasm")
wat_to_wasm(wat_path, wasm_path)
update_fixture(project_name, read_wasm_hex(wasm_path), "Hex")
def process_wat_zip(zip_path):
project_name = os.path.splitext(os.path.basename(zip_path))[0]
with tempfile.TemporaryDirectory() as tmpdir:
with zipfile.ZipFile(zip_path) as archive:
wat_names = [name for name in archive.namelist() if name.endswith(".wat")]
if len(wat_names) != 1:
print(f"exec error: expected one .wat file in {zip_path}")
sys.exit(1)
archive.extract(wat_names[0], tmpdir)
wasm_path = os.path.join(tmpdir, f"{project_name}.wasm")
wat_to_wasm(os.path.join(tmpdir, wat_names[0]), wasm_path)
update_fixture(project_name, read_wasm_hex(wasm_path), "Hex")
def process_wat(project_name):
candidates = [
os.path.join(BASE_PATH, f"{project_name}.wat"),
os.path.join(BASE_PATH, "wat", f"{project_name}.wat"),
os.path.join(BASE_PATH, "wat", f"{project_name}.zip"),
]
for path in candidates:
if os.path.isfile(path):
if path.endswith(".zip"):
process_wat_zip(path)
else:
process_wat_file(path)
return
print(f"exec error: fixture {project_name} not found")
sys.exit(1)
if __name__ == "__main__":
if len(sys.argv) > 2:
print("Usage: python copyFixtures.py [<project_name>]")
sys.exit(1)
if len(sys.argv) == 2:
project_name = os.path.splitext(os.path.basename(sys.argv[1]))[0]
if os.path.isfile(os.path.join(BASE_PATH, project_name, "Cargo.toml")):
process_rust(project_name)
elif os.path.isfile(os.path.join(BASE_PATH, f"{project_name}.c")):
process_c(project_name)
else:
process_wat(project_name)
print("Fixture has been processed.")
else:
dirs = [
d
for d in os.listdir(BASE_PATH)
if os.path.isfile(os.path.join(BASE_PATH, d, "Cargo.toml"))
]
c_files = [f for f in os.listdir(BASE_PATH) if f.endswith(".c")]
wat_files = [f for f in os.listdir(BASE_PATH) if f.endswith(".wat")]
wat_path = os.path.join(BASE_PATH, "wat")
wat_fixture_files = [
f
for f in (os.listdir(wat_path) if os.path.isdir(wat_path) else [])
if f.endswith((".wat", ".zip"))
]
for d in sorted(dirs):
process_rust(d)
for c in sorted(c_files):
process_c(c[:-2])
for wat in sorted(wat_files):
process_wat_file(os.path.join(BASE_PATH, wat))
for wat_fixture in sorted(wat_fixture_files):
path = os.path.join(wat_path, wat_fixture)
if wat_fixture.endswith(".zip"):
process_wat_zip(path)
else:
process_wat_file(path)
print("All fixtures have been processed.")

View File

@@ -1,650 +0,0 @@
// TODO: consider moving these to separate files (and figure out the build)
#include <test/app/wasm_fixtures/fixtures.h>
#include <string>
extern std::string const kLedgerSqnWasmHex =
"0061736d01000000010e0360027f7f017f6000006000017f02120103656e760a6c6467725f696e6465780000030302"
"01020503010002062b077f01418088040b7f004180080b7f004180080b7f004180080b7f00418088040b7f0041000b"
"7f0041010b07800109066d656d6f72790200115f5f7761736d5f63616c6c5f63746f727300010666696e6973680002"
"0c5f5f64736f5f68616e646c6503010a5f5f646174615f656e6403020d5f5f676c6f62616c5f6261736503030b5f5f"
"686561705f6261736503040d5f5f6d656d6f72795f6261736503050c5f5f7461626c655f6261736503060a3d020200"
"0b3801037f230041106b220024002000410c6a410410002101200028020c2102200041106a24002001410541002002"
"41054f1b20014100481b0b002f0970726f647563657273010c70726f6365737365642d6279010e486f6d6562726577"
"20636c616e670631342e302e36";
extern std::string const kAllHostFunctionsWasmHex =
"0061736d0100000001540c60027f7f017f60037f7f7f017f60047f7f7f7f017f60017f017f60067f7f7f7f7f7f017f"
"60037f7f7f0060057f7f7f7f7f017f60037f7f7e017f60087f7f7f7f7f7f7f7f017f60017f0060027f7f006000017f"
"02dc041a08686f73745f6c69620874785f6669656c64000108686f73745f6c69620974726163655f6e756d00070868"
"6f73745f6c6962057472616365000608686f73745f6c69620a6c6467725f696e646578000008686f73745f6c696210"
"706172656e745f6c6467725f74696d65000008686f73745f6c696210706172656e745f6c6467725f68617368000008"
"686f73745f6c69620874785f696e6e6572000208686f73745f6c69620a74785f6172725f6c656e000308686f73745f"
"6c69621074785f696e6e65725f6172725f6c656e000008686f73745f6c69620d686f6d655f6c655f6669656c640001"
"08686f73745f6c69620d686f6d655f6c655f696e6e6572000208686f73745f6c69620f686f6d655f6c655f6172725f"
"6c656e000308686f73745f6c696215686f6d655f6c655f696e6e65725f6172725f6c656e000008686f73745f6c6962"
"0863616368655f6c65000108686f73745f6c69620d63726564656e7469616c5f6964000808686f73745f6c69620965"
"7363726f775f6964000408686f73745f6c6962096f7261636c655f6964000408686f73745f6c69620b736861353132"
"5f68616c66000208686f73745f6c6962076e66745f757269000408686f73745f6c6962087365745f64617461000008"
"686f73745f6c6962086c655f6669656c64000208686f73745f6c6962086c655f696e6e6572000608686f73745f6c69"
"620a6c655f6172725f6c656e000008686f73745f6c6962106c655f696e6e65725f6172725f6c656e000108686f7374"
"5f6c69620e6163636f756e74726f6f745f6964000208686f73745f6c69620a74726163655f616363740002030c0b09"
"0a05050b05000101030005030100110619037f01418080c0000b7f0041af99c0000b7f0041b099c0000b072e04066d"
"656d6f727902000666696e697368001e0a5f5f646174615f656e6403010b5f5f686561705f6261736503020ac61d0b"
"990101027f230041306b220124002000027f418180202001411c6a4114100022024114470440417f20022002417f4e"
"1b210241010c010b200020012f001c3b0001200041036a2001411e6a2d00003a000020012001290023370308200120"
"0141286a29000037000d200128001f21022000410d6a200129000d3700002000200129030837020841000b3a000020"
"002002360204200141306a24000b460020012d00004101460440418080c000410b20013402041001000b2000200129"
"0001370000200041106a200141116a280000360000200041086a200141096a2900003700000b1900200241094f0440"
"000b20002002360204200020013602000b1900200241214f0440000b20002002360204200020013602000bde1a0109"
"7f230041b0036b22002400418b80c000411b41014100410010021a41a680c000411941014100410010021a41e780c0"
"00412b41014100410010021a2000410036027002400240024002400240024002400240200041f0006a220741041003"
"220141004a0440419281c00041172000280270220141187420014180fe03714108747220014108764180fe03712001"
"4118767272ad10011a200041003602900120004190016a220341041004220141004c0d0141a981c000411320002802"
"9001220141187420014180fe03714108747220014108764180fe037120014118767272ad10011a200041c8016a2202"
"4200370300200041c0016a22054200370300200041b8016a22044200370300200042003703b001200041b0016a2206"
"4120100522014120470d0241bc81c000411320064120410110021a41cf81c000412041014100410010021a41dc82c0"
"00412e41014100410010021a200041a0016a410036020020004198016a420037030020004200370390014181802020"
"034114100022014114470d03418a83c00041142003101f200042003703704188801820074108100022014108470d04"
"419e83c0004117420810011a41b583c000412820074108410110021a2000410036024841848008200041c8006a2203"
"4104100022014104470d0541dd83c000411520034104410110021a200041013b003420024200370300200542003703"
"0020044200370300200042003703b0010240200041346a4102200641201006220141004e044041f283c00041142001"
"ad10011a200041286a20062001101d418684c000410d2000280228200028022c410110021a0c010b419384c0004129"
"2001ac10011a0b41bc84c00041154183803c1007ac10011a41d184c00041134189803c1007ac10011a024020004134"
"6a41021008220141004e044041e484c00041142001ad10011a0c010b41f884c000412d2001ac10011a0b41a585c000"
"412341014100410010021a41de86c000413341014100410010021a2000420037037041828018200041f0006a220141"
"081009220341004c0d0620034108460440419187c000412b420810011a41bc87c000412f20014108410110021a0c08"
"0b41eb87c000412f2003ad10011a200041206a200041f0006a2003101c419a88c00041172000280220200028022441"
"0110021a0c070b41bf82c000411d2001ac10011a419b7f21020c070b419a82c00041252001ac10011a419a7f21020c"
"060b41ef81c000412b2001ac10011a41997f21020c050b41b486c000412a2001ac10011a41b77e21020c040b41f385"
"c00041c1002001ac10011a41b67e21020c030b41c885c000412b2001ac10011a41b57e21020c020b41b188c00041c5"
"002003ac10011a0b200041a0016a410036020020004198016a42003703002000420037039001024041818020200041"
"90016a220341141009220141004a044041f688c000411e2003101f0c010b419489c00041332001ac10011a0b200041"
"013b0048200041c8016a4200370300200041c0016a4200370300200041b8016a4200370300200042003703b0010240"
"200041c8006a4102200041b0016a22014120100a220341004e044041c789c000411c2003ad10011a200041186a2001"
"2003101d41e389c00041152000280218200028021c410110021a0c010b41f889c00041392003ac10011a0b41b18ac0"
"0041244183803c100bac10011a0240200041c8006a4102100c220141004e044041d58ac000411c2001ad10011a0c01"
"0b41f18ac000413d2001ac10011a0b41ae8bc000412841014100410010021a41d68bc000412f41014100410010021a"
"200041b0016a2203101a200041f0006a22012003101b200041a8016a4200370300200041a0016a4200370300200041"
"98016a4200370300200042003703900102400240024002400240200120004190016a22031020220141204604402003"
"41204100100d220441004a044041858cc00041232004ad10011a200042003703482004200041c8006a220141081021"
"220341004c0d022003410846044041a88cc000412a420810011a41d28cc000412e20014108410110021a0c060b4180"
"8dc000412e2003ad10011a200041106a200041c8006a2003101c41ae8dc00041162000280210200028021441011002"
"1a0c050b41e68fc000413c2004ac10011a200041c8016a4200370300200041c0016a4200370300200041b8016a4200"
"370300200042003703b0014101200041b0016a4120102122014100480d020c030b41ba92c000412e2001ac10011a41"
"ef7c21020c050b41c48dc000412b2003ac10011a0c020b41a290c00041c1002001ac10011a0b200041013b00484101"
"200041c8006a200041b0016a10222201410048044041e390c00041352001ac10011a0b410110232201410048044041"
"9891c00041322001ac10011a0b4101200041c8006a10242201410048044041ca91c00041392001ac10011a0b418392"
"c000413741014100410010021a0c010b200041013b0034200041c8016a4200370300200041c0016a42003703002000"
"41b8016a4200370300200042003703b00102402004200041346a200041b0016a22011022220341004e044041ef8dc0"
"00411b2003ad10011a200041086a20012003101d418a8ec00041142000280208200028020c410110021a0c010b419e"
"8ec00041312003ac10011a0b41cf8ec000412320041023ac10011a02402004200041346a1024220141004e044041f2"
"8ec000411b2001ad10011a0c010b418d8fc00041352001ac10011a0b41c28fc000412441014100410010021a0b41e8"
"92c000412f41014100410010021a200041b0016a2201101a200041346a22042001101b200041e0006a420037030020"
"0041d8006a4200370300200041d0006a420037030020004200370348024002400240024002402004200041c8006a22"
"03102022014120460440419793c000410f20034120410110021a20004188016a420037030020004180016a42003703"
"00200041f8006a4200370300200042003703700240200441142004411441a693c0004109200041f0006a2201412010"
"0e220341004a0440200020012003101d41ae93c000411220002802002000280204410110021a0c010b41c093c00041"
"3c2003ac10011a0b200041a8016a22064200370300200041a0016a2202420037030020004198016a22054200370300"
"200042003703900120004180808cc07e360268200041346a22034114200041e8006a410420004190016a2208412010"
"0f22014120470d0141fc93c000410e20084120410110021a200041c8016a4200370300200041c0016a420037030020"
"0041b8016a4200370300200042003703b001200041808080d00236026c20034114200041ec006a4104200041b0016a"
"22044120101022014120470d02418a94c000410e20044120410110021a419894c000412441014100410010021a4191"
"95c000412541014100410010021a20004188016a420037030020004180016a4200370300200041f8006a4200370300"
"2000420037037041b695c0004117200041f0006a22034120101122014120470d0341cd95c000410b41b695c0004117"
"410110021a41d895c000411120034120410110021a2004101a200041c8006a22072004101b20064200370300200242"
"0037030020054200370300200042003703900102404100200422026b410371220320026a220520024d0d0020030440"
"200321010340200241003a0000200241016a2102200141016b22010d000b0b200341016b4107490d00034020024100"
"3a0000200241076a41003a0000200241066a41003a0000200241056a41003a0000200241046a41003a000020024103"
"6a41003a0000200241026a41003a0000200241016a41003a0000200241086a22022005470d000b0b20054180022003"
"6b2201417c716a220220054b0440034020054100360200200541046a22052002490d000b0b02402002200141037122"
"0120026a22034f0d002001220504400340200241003a0000200241016a2102200541016b22050d000b0b200141016b"
"4107490d000340200241003a0000200241076a41003a0000200241066a41003a0000200241056a41003a0000200241"
"046a41003a0000200241036a41003a0000200241026a41003a0000200241016a41003a0000200241086a2202200347"
"0d000b0b0240200741142008412020044180021012220141004a044041e995c00041102001ad10011a20014181024f"
"0d0641f995c000410920042001410110021a0c010b418296c000412e2001ac10011a0b41b096c000411241c296c000"
"41074101100222014100480d0541c996c000411d2001ad10011a41e696c0004111422a1001410048044041ad97c000"
"411a42a47b10011a41a47b21020c070b41f796c000411c420010011a41012102419397c000411a4101410041001002"
"1a41ff97c000412941014100410010021a41a898c000412810132201412846044041d098c000412741a898c0004128"
"410110021a41f798c000411e41014100410010021a41bf80c000412841014100410010021a0c070b419599c000411a"
"2001ac10011a41c37a21020c060b41f494c000411d2001ac10011a418b7c21020c050b41d894c000411c2001ac1001"
"1a41897c21020c040b41bc94c000411c2001ac10011a41887c21020c030b41dd97c00041222001ac10011a41a77b21"
"020c020b000b41c797c00041162001ac10011a41a57b21020b200041b0036a240020020b0d00200020012002411410"
"191a0b0c00200041142001412010180b0e002000418280182001200210140b0e002000200141022002412010150b0a"
"0020004183803c10160b0a0020002001410210170b0bb9190100418080c0000baf196572726f725f636f64653d3d3d"
"3d20484f53542046554e4354494f4e532054455354203d3d3d54657374696e6720323620686f73742066756e637469"
"6f6e73535543434553533a20416c6c20686f73742066756e6374696f6e20746573747320706173736564212d2d2d20"
"43617465676f727920313a204c6564676572204865616465722046756e6374696f6e73202d2d2d4c65646765722073"
"657175656e6365206e756d6265723a506172656e74206c65646765722074696d653a506172656e74206c6564676572"
"20686173683a535543434553533a204c6564676572206865616465722066756e6374696f6e734552524f523a206765"
"745f706172656e745f6c65646765725f686173682077726f6e67206c656e6774683a4552524f523a206765745f7061"
"72656e745f6c65646765725f74696d65206661696c65643a4552524f523a206765745f6c65646765725f73716e2066"
"61696c65643a2d2d2d2043617465676f727920323a205472616e73616374696f6e20446174612046756e6374696f6e"
"73202d2d2d5472616e73616374696f6e204163636f756e743a5472616e73616374696f6e20466565206c656e677468"
"3a5472616e73616374696f6e20466565202873657269616c697a65642058525020616d6f756e74293a5472616e7361"
"6374696f6e2053657175656e63653a4e6573746564206669656c64206c656e6774683a4e6573746564206669656c64"
"3a494e464f3a206765745f74785f6e65737465645f6669656c64206e6f74206170706c696361626c653a5369676e65"
"7273206172726179206c656e6774683a4d656d6f73206172726179206c656e6774683a4e6573746564206172726179"
"206c656e6774683a494e464f3a206765745f74785f6e65737465645f61727261795f6c656e206e6f74206170706c69"
"6361626c653a535543434553533a205472616e73616374696f6e20646174612066756e6374696f6e734552524f523a"
"206765745f74785f6669656c642853657175656e6365292077726f6e67206c656e6774683a4552524f523a20676574"
"5f74785f6669656c6428466565292077726f6e67206c656e6774682028657870656374656420382062797465732066"
"6f7220585250293a4552524f523a206765745f74785f6669656c64284163636f756e74292077726f6e67206c656e67"
"74683a2d2d2d2043617465676f727920333a2043757272656e74204c6564676572204f626a6563742046756e637469"
"6f6e73202d2d2d43757272656e74206f626a6563742062616c616e6365206c656e677468202858525020616d6f756e"
"74293a43757272656e74206f626a6563742062616c616e6365202873657269616c697a65642058525020616d6f756e"
"74293a43757272656e74206f626a6563742062616c616e6365206c656e67746820286e6f6e2d58525020616d6f756e"
"74293a43757272656e74206f626a6563742062616c616e63653a494e464f3a206765745f63757272656e745f6c6564"
"6765725f6f626a5f6669656c642842616c616e636529206661696c656420286d617920626520657870656374656429"
"3a43757272656e74206c6564676572206f626a656374206163636f756e743a494e464f3a206765745f63757272656e"
"745f6c65646765725f6f626a5f6669656c64284163636f756e7429206661696c65643a43757272656e74206e657374"
"6564206669656c64206c656e6774683a43757272656e74206e6573746564206669656c643a494e464f3a206765745f"
"63757272656e745f6c65646765725f6f626a5f6e65737465645f6669656c64206e6f74206170706c696361626c653a"
"43757272656e74206f626a656374205369676e657273206172726179206c656e6774683a43757272656e74206e6573"
"746564206172726179206c656e6774683a494e464f3a206765745f63757272656e745f6c65646765725f6f626a5f6e"
"65737465645f61727261795f6c656e206e6f74206170706c696361626c653a535543434553533a2043757272656e74"
"206c6564676572206f626a6563742066756e6374696f6e732d2d2d2043617465676f727920343a20416e79204c6564"
"676572204f626a6563742046756e6374696f6e73202d2d2d5375636365737366756c6c7920636163686564206f626a"
"65637420696e20736c6f743a436163686564206f626a6563742062616c616e6365206c656e67746820285852502061"
"6d6f756e74293a436163686564206f626a6563742062616c616e6365202873657269616c697a65642058525020616d"
"6f756e74293a436163686564206f626a6563742062616c616e6365206c656e67746820286e6f6e2d58525020616d6f"
"756e74293a436163686564206f626a6563742062616c616e63653a494e464f3a206765745f6c65646765725f6f626a"
"5f6669656c642842616c616e636529206661696c65643a436163686564206e6573746564206669656c64206c656e67"
"74683a436163686564206e6573746564206669656c643a494e464f3a206765745f6c65646765725f6f626a5f6e6573"
"7465645f6669656c64206e6f74206170706c696361626c653a436163686564206f626a656374205369676e65727320"
"6172726179206c656e6774683a436163686564206e6573746564206172726179206c656e6774683a494e464f3a2067"
"65745f6c65646765725f6f626a5f6e65737465645f61727261795f6c656e206e6f74206170706c696361626c653a53"
"5543434553533a20416e79206c6564676572206f626a6563742066756e6374696f6e73494e464f3a2063616368655f"
"6c65646765725f6f626a206661696c6564202865787065637465642077697468207465737420666978747572657329"
"3a494e464f3a206765745f6c65646765725f6f626a5f6669656c64206661696c656420617320657870656374656420"
"286e6f20636163686564206f626a656374293a494e464f3a206765745f6c65646765725f6f626a5f6e65737465645f"
"6669656c64206661696c65642061732065787065637465643a494e464f3a206765745f6c65646765725f6f626a5f61"
"727261795f6c656e206661696c65642061732065787065637465643a494e464f3a206765745f6c65646765725f6f62"
"6a5f6e65737465645f61727261795f6c656e206661696c65642061732065787065637465643a535543434553533a20"
"416e79206c6564676572206f626a6563742066756e6374696f6e732028696e74657266616365207465737465642945"
"52524f523a206163636f756e74726f6f745f6964206661696c656420666f722063616368696e6720746573743a2d2d"
"2d2043617465676f727920353a204b65796c65742047656e65726174696f6e2046756e6374696f6e73202d2d2d4163"
"636f756e74206b65796c65743a546573745479706543726564656e7469616c206b65796c65743a494e464f3a206372"
"6564656e7469616c5f6b65796c6574206661696c656420286578706563746564202d20696e74657266616365206973"
"737565293a457363726f77206b65796c65743a4f7261636c65206b65796c65743a535543434553533a204b65796c65"
"742067656e65726174696f6e2066756e6374696f6e734552524f523a206f7261636c655f6b65796c6574206661696c"
"65643a4552524f523a20657363726f775f6b65796c6574206661696c65643a4552524f523a206163636f756e74726f"
"6f745f6964206661696c65643a2d2d2d2043617465676f727920363a205574696c6974792046756e6374696f6e7320"
"2d2d2d48656c6c6f2c205852504c205741534d20776f726c6421496e70757420646174613a5348413531322068616c"
"6620686173683a4e46542064617461206c656e6774683a4e465420646174613a494e464f3a206765745f6e66742066"
"61696c656420286578706563746564202d206e6f2073756368204e4654293a54657374207472616365206d65737361"
"67657061796c6f616454726163652066756e6374696f6e206279746573207772697474656e3a54657374206e756d62"
"657220747261636554726163655f6e756d2066756e6374696f6e20737563636565646564535543434553533a205574"
"696c6974792066756e6374696f6e734552524f523a2074726163655f6e756d2829206661696c65643a4552524f523a"
"2074726163652829206661696c65643a4552524f523a20636f6d707574655f7368613531325f68616c66206661696c"
"65643a2d2d2d2043617465676f727920373a2044617461205570646174652046756e6374696f6e73202d2d2d557064"
"61746564206c656467657220656e74727920646174612066726f6d205741534d20746573745375636365737366756c"
"6c792075706461746564206c656467657220656e74727920776974683a535543434553533a20446174612075706461"
"74652066756e6374696f6e734552524f523a207570646174655f64617461206661696c65643a004d0970726f647563"
"65727302086c616e6775616765010452757374000c70726f6365737365642d6279010572757374631d312e38372e30"
"202831373036376539616320323032352d30352d303929002c0f7461726765745f6665617475726573022b0f6d7574"
"61626c652d676c6f62616c732b087369676e2d657874";
extern std::string const kAllKeyletsWasmHex =
"0061736d0100000001500a60067f7f7f7f7f7f017f60047f7f7f7f017f60087f7f7f7f7f7f7f7f017f60047f7f7f7f"
"0060037f7f7f017f60037f7f7e017f60057f7f7f7f7f017f6000017f60037f7f7f0060067f7f7f7f7f7e00029f0418"
"08686f73745f6c69620974726163655f6e756d000508686f73745f6c6962057472616365000608686f73745f6c6962"
"0863616368655f6c65000408686f73745f6c6962086c655f6669656c64000108686f73745f6c69620d686f6d655f6c"
"655f6669656c64000408686f73745f6c69620a74726163655f61636374000108686f73745f6c69620e6163636f756e"
"74726f6f745f6964000108686f73745f6c69620c74727573746c696e655f6964000208686f73745f6c696206616d6d"
"5f6964000008686f73745f6c696208636865636b5f6964000008686f73745f6c69620d63726564656e7469616c5f69"
"64000208686f73745f6c69620b64656c65676174655f6964000008686f73745f6c6962126465706f7369745f707265"
"617574685f6964000008686f73745f6c6962066469645f6964000108686f73745f6c696209657363726f775f696400"
"0008686f73745f6c69620f6d70745f69737375616e63655f6964000008686f73745f6c69620a6d70746f6b656e5f69"
"64000008686f73745f6c69620c6e66745f6f666665725f6964000008686f73745f6c6962086f666665725f69640000"
"08686f73745f6c69620a7061796368616e5f6964000208686f73745f6c6962167065726d697373696f6e65645f646f"
"6d61696e5f6964000008686f73745f6c69620a7369676e6572735f6964000108686f73745f6c6962097469636b6574"
"5f6964000008686f73745f6c6962087661756c745f6964000003070603030307080905030100110619037f01418080"
"c0000b7f0041c28ac0000b7f0041d08ac0000b072e04066d656d6f727902000666696e697368001b0a5f5f64617461"
"5f656e6403010b5f5f686561705f6261736503020ae83706140020002001200220034182802042828020101d0b1400"
"20002001200220034181802042818020101d0bd10302017f017e230041a0016b22042400024020012d000041014604"
"4041d780c000411620012802042201ac10001a200041013a0000200020013602040c010b200441186a200141196a29"
"0000370300200441106a200141116a290000370300200441086a200141096a29000037030020042001290001370300"
"2002200320044120410110011a2004412041001002220141004c044041d080c00041072001ac10001a200041013a00"
"00200020013602040c010b418b80c000410f4285801410001a20014185801420044180016a41201003220141204704"
"4041af80c0004115417f20012001417f4e1b2201ac10001a200041013a0000200020013602040c010b200441c2006a"
"20044182016a2d00003a0000200441f0006a20044197016a2900002205370300200441286a22012004418f016a2900"
"00370300200441306a22022005370300200441386a22032004419f016a2d00003a0000200420042f0080013b014020"
"042004290087013703202004200428008301360043200441df006a20032d00003a0000200441d7006a200229030037"
"0000200441cf006a20012903003700002004200429032037004741c480c000410c200441406b4120410110011a2000"
"4180023b01000b200441a0016a24000bd32c02097f027e23004180076b2200240041ed80c000412341014100410010"
"011a02402000027f02404181802020004190016a220741141004220641144604402000410e6a20004192016a22032d"
"00003a000020002000290097013703e80120002000419c016a22012900003700ed01200020002f0090013b010c2000"
"20002903e8013703d806200020002900ed013700dd06200020002800930136000f200041186a20002900dd06370000"
"200020002903d806370013419081c00041082000410c6a2204411410051a4183802020074114100422064114470d03"
"200041226a20032d00003a000020002000290097013703e801200020012900003700ed01200020002f0090013b0120"
"200020002903e8013703d806200020002900ed013700dd0620002000280093013600232000412c6a20002900dd0637"
"0000200020002903d806370027419881c000410c200041206a411410051a200041a8016a22034200370300200041a0"
"016a2201420037030020004198016a420037030020004200370390012004411420074120100622044120460d010240"
"20044100480440200020043602380c010b2000417f3602380b41010c020b0c020b200041cd006a2003290300370000"
"200041c5006a20012903003700002000413d6a20004198016a290300370000200020002903900137003541000b3a00"
"3420004190016a200041346a41a481c00041071019024020002d00900141014604402000280294012106419c8ac000"
"4112420510001a0c010b4100210641ab81c000413541014100410010011a200041e6006a41c4003a0000200041e000"
"6a4100360200200041eb006a41003a0000200041d5a6013b01642000420037035820004100360067200041a8016a22"
"044200370300200041a0016a2203420037030020004198016a22014200370300200042003703900102402000410c6a"
"4114200041206a4114200041d8006a411420004190016a412010072207412047044002402007410048044020002007"
"3602700c010b2000417f3602700b410121060c010b20004185016a2004290300370000200041fd006a200329030037"
"0000200041f5006a2001290300370000200020002903900137006d0b200020063a006c20004190016a200041ec006a"
"41e081c0004109101a20002d00900141014604402000280294012106419c8ac0004112420510001a0c010b41002106"
"41e981c000413741014100410010011a200041f8016a200041306a2204280100360200200041f0016a200041286a22"
"0329010037030020004184026a200041e0006a290300220a3702002000418c026a200041e8006a2802002201360200"
"200020002901203703e8012000200029035822093702fc01200041e8066a22052001360200200041e0066a2207200a"
"370300200020093703d806200041f4066a2003290100370200200041fc066a20042801003602002000200029012037"
"02ec0620004190026a200041d8066a22034128101c20004194016a200041e8016a41d000101c200041013602900120"
"0041f0066a220142003703002005420037030020074200370300200042003703d806024041ae8ac0004114200041bc"
"016a412820034120100822034120470440024020034100480440200020033602ec010c010b2000417f3602ec010b41"
"0121060c010b20004181026a2001290300370000200041f9016a2005290300370000200041f1016a20072903003700"
"00200020002903d8063700e9010b200020063a00e801200041bc026a200041e8016a41a082c0004103101920002d00"
"bc02410146044020002802c0022106419c8ac0004112420610001a0c010b4100210641a382c0004131410141004100"
"10011a200041063602d80620004180026a22044200370300200041f8016a22034200370300200041f0016a22014200"
"370300200042003703e80102402000410c6a4114200041d8066a4104200041e8016a41201009220741204704400240"
"20074100480440200020073602c8020c010b2000417f3602c8020b410121060c010b200041dd026a20042903003700"
"00200041d5026a2003290300370000200041cd026a2001290300370000200020002903e8013700c5020b200020063a"
"00c402200041e8016a200041c4026a41d482c0004105101920002d00e801410146044020002802ec012106419c8ac0"
"004112420610001a0c010b41d982c000413341014100410010011a20004180026a4200370300200041f8016a420037"
"0300200041f0016a4200370300200042003703e801024002402000410c6a2201411420014114418c83c00041122000"
"41e8016a4120100a2201412047044041d780c0004116417f20012001417f4e1b2206ac10001a0c010b200041da066a"
"20002d00ea013a0000200041f0026a200041f7016a290000220a370300200041f8026a200041ff016a290000220937"
"030020004180036a20004187026a2d000022013a0000200041e7066a200a370000200041ef066a2009370000200041"
"f7066a20013a0000200020002f01e8013b01d806200020002900ef0122093703e802200020002800eb013600db0620"
"0020093700df06419e83c000410a200041d8066a22014120410110011a2001412041001002220641004c044041d080"
"c00041072006ac10001a0c010b418b80c000410f4298802010001a200641988020200041e8016a4114100322014114"
"460d0141af80c0004115417f20012001417f4e1b2206ac10001a0b419c8ac0004112420710001a0c010b419a80c000"
"411541014100410010011a41a883c000413841014100410010011a230041206b22082400200841186a220742003703"
"00200841106a22044200370300200841086a220342003703002008420037030020004184036a2201027f2000410c6a"
"22064114200041206a2202411420084120100b22054120470440024020054100480440200120053602040c010b2001"
"417f3602040b41010c010b20012008290300370001200141196a2007290300370000200141116a2004290300370000"
"200141096a200329030037000041000b3a0000200841206a2400200041e8016a2205200141e083c000410810192000"
"2d00e80145044041e883c000413641014100410010011a230041206b22082400200841186a22074200370300200841"
"106a22044200370300200841086a2203420037030020084200370300200041a8036a2201027f200641142002411420"
"084120100c22024120470440024020024100480440200120023602040c010b2001417f3602040b41010c010b200120"
"08290300370001200141196a2007290300370000200141116a2004290300370000200141096a200329030037000041"
"000b3a0000200841206a240020052001419e84c000410e101920002d00e801410146044020002802ec012106419c8a"
"c0004112420910001a0c020b41ac84c000413c41014100410010011a230041206b22022400200241186a2207420037"
"0300200241106a22044200370300200241086a2203420037030020024200370300200041cc036a2201027f2000410c"
"6a411420024120100d22054120470440024020054100480440200120053602040c010b2001417f3602040b41010c01"
"0b20012002290300370001200141196a2007290300370000200141116a2004290300370000200141096a2003290300"
"37000041000b3a0000200241206a2400200041e8016a200141e884c0004103101920002d00e8014101460440200028"
"02ec012106419c8ac0004112420a10001a0c020b41eb84c000413141014100410010011a230041306b220224002002"
"410b36020c200241286a22074200370300200241206a22044200370300200241186a22034200370300200242003703"
"10200041f0036a2201027f2000410c6a41142002410c6a4104200241106a4120100e22054120470440024020054100"
"480440200120053602040c010b2001417f3602040b41010c010b20012002290310370001200141196a200729030037"
"0000200141116a2004290300370000200141096a200329030037000041000b3a0000200241306a2400200041e8016a"
"2001419c85c0004106101920002d00e801410146044020002802ec012106419c8ac0004112420b10001a0c020b41a2"
"85c000413441014100410010011a230041306b220224002002410c36020c200241286a22074200370300200241206a"
"22044200370300200241186a220342003703002002420037031020004194046a2201027f2000410c6a41142002410c"
"6a4104200241106a4120100f22054120470440024020054100480440200120053602040c010b2001417f3602040b41"
"010c010b20012002290310370001200141196a2007290300370000200141116a2004290300370000200141096a2003"
"29030037000041000b3a0000200241306a2400200041fc016a2000411c6a280100360200200041f4016a200041146a"
"2901003702002000200029010c3702ec01200041808080e0003602e801200041d8066a2103230041406a2204240002"
"4020012d0000410146044041d780c000411620012802042201ac10001a200341013a0000200320013602040c010b20"
"0441206a200141196a290000370300200441186a200141116a290000370300200441106a200141096a290000370300"
"2004200129000137030841d685c000410b200441086a22014120410110011a02400240200141204100100222014100"
"4c044041d080c00041072001ac10001a0c010b418b80c000410f4284802010001a2001418480202004412c6a411410"
"0322014114460d0141af80c0004115417f20012001417f4e1b2201ac10001a0b200341013a0000200320013602040c"
"010b419a80c000411541014100410010011a20034180023b01000b200441406b240020002d00d80641014604402000"
"2802dc062106419c8ac0004112420c10001a0c020b41e185c000413941014100410010011a230041206b2202240020"
"0241186a22074200370300200241106a22044200370300200241086a2203420037030020024200370300200041b804"
"6a2201027f200041e8016a4118200041206a4114200241201010220541204704400240200541004804402001200536"
"02040c010b2001417f3602040b41010c010b20012002290300370001200141196a2007290300370000200141116a20"
"04290300370000200141096a200329030037000041000b3a0000200241206a2400200041d8066a2001419a86c00041"
"07101920002d00d806410146044020002802dc062106419c8ac0004112420d10001a0c020b41a186c0004135410141"
"00410010011a230041306b220224002002410636020c200241286a22074200370300200241206a2204420037030020"
"0241186a2203420037030020024200370310200041dc046a2201027f200041206a41142002410c6a4104200241106a"
"4120101122054120470440024020054100480440200120053602040c010b2001417f3602040b41010c010b20012002"
"290310370001200141196a2007290300370000200141116a2004290300370000200141096a20032903003700004100"
"0b3a0000200241306a2400200041d8066a200141d686c000410c101820002d00d806410146044020002802dc062106"
"419c8ac0004112420d10001a0c020b41e286c000413a41014100410010011a230041306b220224002002410d36020c"
"200241286a22074200370300200241206a22044200370300200241186a220342003703002002420037031020004180"
"056a2201027f2000410c6a41142002410c6a4104200241106a41201012220541204704400240200541004804402001"
"20053602040c010b2001417f3602040b41010c010b20012002290310370001200141196a2007290300370000200141"
"116a2004290300370000200141096a200329030037000041000b3a0000200241306a2400200041d8066a2001419c87"
"c0004105101920002d00d806410146044020002802dc062106419c8ac0004112420d10001a0c020b41a187c0004133"
"41014100410010011a230041306b220224002002410e36020c200241286a22074200370300200241206a2204420037"
"0300200241186a2203420037030020024200370310200041a4056a2201027f2000410c6a4114200041206a41142002"
"410c6a4104200241106a4120101322054120470440024020054100480440200120053602040c010b2001417f360204"
"0b41010c010b20012002290310370001200141196a2007290300370000200141116a2004290300370000200141096a"
"200329030037000041000b3a0000200241306a2400200041d8066a200141d487c000410a101920002d00d806410146"
"044020002802dc062106419c8ac0004112420e10001a0c020b41de87c000413841014100410010011a230041306b22"
"0224002002410f36020c200241286a22074200370300200241206a22044200370300200241186a2203420037030020"
"024200370310200041c8056a2201027f2000410c6a41142002410c6a4104200241106a412010142205412047044002"
"4020054100480440200120053602040c010b2001417f3602040b41010c010b20012002290310370001200141196a20"
"07290300370000200141116a2004290300370000200141096a200329030037000041000b3a0000200241306a240020"
"0041d8066a2001419688c0004112101820002d00d806410146044020002802dc062106419c8ac0004112420f10001a"
"0c020b41a888c00041c00041014100410010011a230041206b22022400200241186a22074200370300200241106a22"
"044200370300200241086a2203420037030020024200370300200041ec056a2201027f2000410c6a41142002412010"
"1522054120470440024020054100480440200120053602040c010b2001417f3602040b41010c010b20012002290300"
"370001200141196a2007290300370000200141116a2004290300370000200141096a200329030037000041000b3a00"
"00200241206a2400200041d8066a200141e888c000410a101a20002d00d806410146044020002802dc062106419c8a"
"c0004112421010001a0c020b41f288c000413841014100410010011a230041306b220224002002411236020c200241"
"286a22074200370300200241206a22044200370300200241186a220342003703002002420037031020004190066a22"
"01027f2000410c6a41142002410c6a4104200241106a41201016220541204704400240200541004804402001200536"
"02040c010b2001417f3602040b41010c010b20012002290310370001200141196a2007290300370000200141116a20"
"04290300370000200141096a200329030037000041000b3a0000200241306a2400200041d8066a200141aa89c00041"
"06101920002d00d806410146044020002802dc062106419c8ac0004112421210001a0c020b4101210641b089c00041"
"3441014100410010011a230041306b220224002002411336020c200241286a22074200370300200241206a22044200"
"370300200241186a2203420037030020024200370310200041b4066a2201027f2000410c6a41142002410c6a410420"
"0241106a4120101722054120470440024020054100480440200120053602040c010b2001417f3602040b41010c010b"
"20012002290310370001200141196a2007290300370000200141116a2004290300370000200141096a200329030037"
"000041000b3a0000200241306a2400200041d8066a200141e489c0004105101920002d00d806410146044020002802"
"dc062106419c8ac0004112421310001a0c020b41e989c000413341014100410010011a0c010b20002802ec01210641"
"9c8ac0004112420810001a0b20004180076a240020060f0b418080c000410b417f20062006417f4e1bac1000000bfd"
"0401067f200241104f0440024020002000410020006b41037122056a22044f0d002001210320050440200521060340"
"200020032d00003a0000200341016a2103200041016a2100200641016b22060d000b0b200541016b4107490d000340"
"200020032d00003a0000200041016a200341016a2d00003a0000200041026a200341026a2d00003a0000200041036a"
"200341036a2d00003a0000200041046a200341046a2d00003a0000200041056a200341056a2d00003a000020004106"
"6a200341066a2d00003a0000200041076a200341076a2d00003a0000200341086a2103200041086a22002004470d00"
"0b0b2004200220056b2207417c7122086a21000240200120056a2206410371450440200020044d0d01200621010340"
"20042001280200360200200141046a2101200441046a22042000490d000b0c010b200020044d0d0020064103742205"
"41187121032006417c71220241046a2101410020056b41187121052002280200210203402004200220037620012802"
"00220220057472360200200141046a2101200441046a22042000490d000b0b20074103712102200620086a21010b02"
"402000200020026a22064f0d002002410771220304400340200020012d00003a0000200141016a2101200041016a21"
"00200341016b22030d000b0b200241016b4107490d000340200020012d00003a0000200041016a200141016a2d0000"
"3a0000200041026a200141026a2d00003a0000200041036a200141036a2d00003a0000200041046a200141046a2d00"
"003a0000200041056a200141056a2d00003a0000200041066a200141066a2d00003a0000200041076a200141076a2d"
"00003a0000200141086a2101200041086a22002006470d000b0b0b940201017f230041406a22062400024020012d00"
"00410146044041d780c000411620012802042201ac10001a200041013a0000200020013602040c010b200641206a20"
"0141196a290000370300200641186a200141116a290000370300200641106a200141096a2900003703002006200129"
"000137030820022003200641086a22014120410110011a024002402001412041001002220141004c044041d080c000"
"41072001ac10001a0c010b418b80c000410f200510001a200120042006412c6a4114100322014114460d0141af80c0"
"004115417f20012001417f4e1b2201ac10001a0b200041013a0000200020013602040c010b419a80c0004115410141"
"00410010011a20004180023b01000b200641406b24000b0bb80a0100418080c0000bae0a6572726f725f636f64653d"
"47657474696e67206669656c643a204669656c6420646174613a207265747269657665644572726f72206765747469"
"6e67206669656c643a204669656c6420646174613a204572726f723a204572726f722067657474696e67206b65796c"
"65743a202424242424205354415254494e47205741534d20455845435554494f4e2024242424244163636f756e743a"
"44657374696e6174696f6e3a4163636f756e744163636f756e74206f626a656374206578697374732c2070726f6365"
"6564696e67207769746820657363726f772066696e6973682e54727573746c696e6554727573746c696e65206f626a"
"656374206578697374732c2070726f63656564696e67207769746820657363726f772066696e6973682e414d4d414d"
"4d206f626a656374206578697374732c2070726f63656564696e67207769746820657363726f772066696e6973682e"
"436865636b436865636b206f626a656374206578697374732c2070726f63656564696e67207769746820657363726f"
"772066696e6973682e7465726d73616e64636f6e646974696f6e7343726564656e7469616c43726564656e7469616c"
"206f626a656374206578697374732c2070726f63656564696e67207769746820657363726f772066696e6973682e44"
"656c656761746544656c6567617465206f626a656374206578697374732c2070726f63656564696e67207769746820"
"657363726f772066696e6973682e4465706f736974507265617574684465706f73697450726561757468206f626a65"
"6374206578697374732c2070726f63656564696e67207769746820657363726f772066696e6973682e444944444944"
"206f626a656374206578697374732c2070726f63656564696e67207769746820657363726f772066696e6973682e45"
"7363726f77457363726f77206f626a656374206578697374732c2070726f63656564696e6720776974682065736372"
"6f772066696e6973682e4d505449737375616e63654d505449737375616e6365206f626a656374206578697374732c"
"2070726f63656564696e67207769746820657363726f772066696e6973682e4d50546f6b656e4d50546f6b656e206f"
"626a656374206578697374732c2070726f63656564696e67207769746820657363726f772066696e6973682e4e4654"
"6f6b656e4f666665724e46546f6b656e4f66666572206f626a656374206578697374732c2070726f63656564696e67"
"207769746820657363726f772066696e6973682e4f666665724f66666572206f626a656374206578697374732c2070"
"726f63656564696e67207769746820657363726f772066696e6973682e5061794368616e6e656c5061794368616e6e"
"656c206f626a656374206578697374732c2070726f63656564696e67207769746820657363726f772066696e697368"
"2e5065726d697373696f6e6564446f6d61696e5065726d697373696f6e6564446f6d61696e206f626a656374206578"
"697374732c2070726f63656564696e67207769746820657363726f772066696e6973682e5369676e65724c69737453"
"69676e65724c697374206f626a656374206578697374732c2070726f63656564696e67207769746820657363726f77"
"2066696e6973682e5469636b65745469636b6574206f626a656374206578697374732c2070726f63656564696e6720"
"7769746820657363726f772066696e6973682e5661756c745661756c74206f626a656374206578697374732c207072"
"6f63656564696e67207769746820657363726f772066696e6973682e43757272656e74207365712076616c75653a00"
"4d0970726f64756365727302086c616e6775616765010452757374000c70726f6365737365642d6279010572757374"
"631d312e38372e30202831373036376539616320323032352d30352d303929002c0f7461726765745f666561747572"
"6573022b0f6d757461626c652d676c6f62616c732b087369676e2d657874";
extern std::string const kCodecovTestsWasmHex =
"0061736d0100000001570b60067f7f7f7f7f7f017f60047f7f7f7f017f60027f7f017f60037f7f7f017f60077f7f7f"
"7f7f7f7f017f60057f7f7f7f7f017f60087f7f7f7f7f7f7f7f017f60017f017f60037f7f7e017f60047f7f7f7f0060"
"00017f02c60a3b08686f73745f6c6962057472616365000508686f73745f6c69620974726163655f6e756d00080868"
"6f73745f6c69620a6c6467725f696e646578000208686f73745f6c696210706172656e745f6c6467725f74696d6500"
"0208686f73745f6c696210706172656e745f6c6467725f68617368000208686f73745f6c696208626173655f666565"
"000208686f73745f6c696211616d656e646d656e745f656e61626c6564000208686f73745f6c69620874785f666965"
"6c64000308686f73745f6c69620e6163636f756e74726f6f745f6964000108686f73745f6c69620863616368655f6c"
"65000308686f73745f6c69620d686f6d655f6c655f6669656c64000308686f73745f6c6962086c655f6669656c6400"
"0108686f73745f6c69620874785f696e6e6572000108686f73745f6c69620d686f6d655f6c655f696e6e6572000108"
"686f73745f6c6962086c655f696e6e6572000508686f73745f6c69620a74785f6172725f6c656e000708686f73745f"
"6c69620f686f6d655f6c655f6172725f6c656e000708686f73745f6c69620a6c655f6172725f6c656e000208686f73"
"745f6c69621074785f696e6e65725f6172725f6c656e000208686f73745f6c696215686f6d655f6c655f696e6e6572"
"5f6172725f6c656e000208686f73745f6c6962106c655f696e6e65725f6172725f6c656e000308686f73745f6c6962"
"087365745f64617461000208686f73745f6c69620b7368613531325f68616c66000108686f73745f6c696209636865"
"636b5f736967000008686f73745f6c6962076e66745f757269000008686f73745f6c69620a6e66745f697373756572"
"000108686f73745f6c6962096e66745f7461786f6e000108686f73745f6c6962096e66745f666c616773000208686f"
"73745f6c69620c6e66745f786665725f666565000208686f73745f6c69620a6e66745f73657269616c000108686f73"
"745f6c69620a74726163655f61636374000108686f73745f6c69620974726163655f616d74000108686f73745f6c69"
"6208636865636b5f6964000008686f73745f6c69620f666c6f61745f66726f6d5f75696e74000508686f73745f6c69"
"620c74727573746c696e655f6964000608686f73745f6c696206616d6d5f6964000008686f73745f6c69620d637265"
"64656e7469616c5f6964000608686f73745f6c69620a6d70746f6b656e5f6964000008686f73745f6c69620c747261"
"63655f78666c6f6174000108686f73745f6c696209666c6f61745f636d70000108686f73745f6c696209666c6f6174"
"5f616464000408686f73745f6c696209666c6f61745f737562000408686f73745f6c69620a666c6f61745f6d756c74"
"000408686f73745f6c696209666c6f61745f646976000408686f73745f6c69620a666c6f61745f726f6f7400000868"
"6f73745f6c696209666c6f61745f706f77000008686f73745f6c696209657363726f775f6964000008686f73745f6c"
"69620f6d70745f69737375616e63655f6964000008686f73745f6c69620c6e66745f6f666665725f6964000008686f"
"73745f6c6962086f666665725f6964000008686f73745f6c6962096f7261636c655f6964000008686f73745f6c6962"
"0a7061796368616e5f6964000608686f73745f6c6962167065726d697373696f6e65645f646f6d61696e5f69640000"
"08686f73745f6c6962097469636b65745f6964000008686f73745f6c6962087661756c745f6964000008686f73745f"
"6c69620b64656c65676174655f6964000008686f73745f6c6962126465706f7369745f707265617574685f69640000"
"08686f73745f6c6962066469645f6964000108686f73745f6c69620a7369676e6572735f69640001030302090a0503"
"0100110619037f01418080c0000b7f0041cf9bc0000b7f0041d09bc0000b072e04066d656d6f727902000666696e69"
"7368003c0a5f5f646174615f656e6403010b5f5f686561705f6261736503020a8c2f02460002402000200147044020"
"02200341014100410010001a20004100480d01418b80c000410b2000ad1001000b200220032000ac10011a0f0b418b"
"80c000410b2000ac1001000bc22e020b7f017e23004190026b22002400419680c000412341014100410010001a2000"
"4100360260200041e0006a220241041002410441888ac000410a103b20004100360260200241041003410441928ac0"
"004110103b200041f8006a22054200370300200041f0006a22014200370300200041e8006a22064200370300200042"
"00370360200241201004412041a28ac0004110103b20004100360260200241041005410441b28ac0004108103b2000"
"41106a2208428182848890a0c08001370300200041186a2209428182848890a0c08001370300200041206a220a4281"
"82848890a0c080013703002000428182848890a0c0800137030841b980c000410e1006410141c780c0004111103b20"
"0041086a41201006410141c780c0004111103b418180202002411410072203411446044002402000412e6a200041e2"
"006a2d00003a0000200020002900673703e8012000200041ec006a2900003700ed01200020002f00603b012c200020"
"002903e8013703a801200020002900ed013700ad012000200028006336002f200041386a20002900ad013700002000"
"20002903a801370033200542003703002001420037030020064200370300200042003703602000412c6a2205411420"
"024120100822034120470d00200041c2006a20002d00623a0000200041f0016a2207200041ef006a290000220b3703"
"00200041cf006a200b370000200041d7006a200041f7006a290000370000200041df006a200041ff006a2d00003a00"
"00200020002f01603b01402000200028006336004320002000290067370047200041406b412041001009410141d880"
"c0004108103b2001410036020020064200370300200042003703604181802020024114100a411441ba8ac000410d10"
"3b20014100360200200642003703002000420037036041014181802020024114100b411441c78ac0004108103b0240"
"4100200041e4006a22046b410371220320046a220120044d0d0020030440200321060340200441003a000020044101"
"6a2104200641016b22060d000b0b200341016b4107490d000340200441003a0000200441076a41003a000020044106"
"6a41003a0000200441056a41003a0000200441046a41003a0000200441036a41003a0000200441026a41003a000020"
"0441016a41003a0000200441086a22042001470d000b0b2001413c20036b2203417c716a220420014b044003402001"
"4100360200200141046a22012004490d000b0b024020042003410371220320046a22064f0d00200322010440034020"
"0441003a0000200441016a2104200141016b22010d000b0b200341016b4107490d000340200441003a000020044107"
"6a41003a0000200441066a41003a0000200441056a41003a0000200441046a41003a0000200441036a41003a000020"
"0441026a41003a0000200441016a41003a0000200441086a22042006470d000b0b200041043602a001200041818020"
"360260200041f8016a2203410036020020074200370300200042003703e80120024104200041e8016a22014114100c"
"411441cf8ac0004108103b2003410036020020074200370300200042003703e801200220002802a00120014114100d"
"411441d78ac000410d103b2003410036020020074200370300200042003703e8014101200220002802a00120014114"
"100e411441e48ac0004108103b4189803c100f412041e080c000410a103b4189803c1010412041ea80c000410f103b"
"41014189803c1011412041f980c000410a103b200220002802a00110124120418381c0004110103b200220002802a0"
"0110134120419381c0004115103b4101200220002802a0011014412041a881c0004110103b200541141015411441b8"
"81c0004108103b20004180026a220642003703002003420037030020074200370300200042003703e8012002200028"
"02a001200141201016412041ec8ac000410b103b41c081c000410c41cc81c000410b41d781c000410e1017410141e5"
"81c0004109103b200041c0016a200a290300370300200041b8016a2009290300370300200041b0016a200829030037"
"0300200020002903083703a801200341003b010020074200370300200042003703e80120054114200041a8016a2204"
"4120200141121018411241f78ac0004107103b2003410036020020074200370300200042003703e801200441202001"
"41141019411441fe8ac000410a103b200041003602e8012004412020014104101a410441888bc0004109103b200441"
"20101b410841ee81c0004109103b20044120101c410a41f781c000410c103b200041003602e8012004412020014104"
"101d410441918bc000410a103b418382c000410d20054114101e4100419082c000410a103b418382c000410d419a82"
"c0004108101f410041a282c0004109103b418382c000410d41ab82c0004108101f410041b382c000410e103b417f41"
"041004417141c182c0004118103b200041003602e8012001417f10044171419b8bc0004118103b200041ea016a4100"
"3a0000200041003b01e801200141031004417d41b38bc000411e103b200041003602e8012001418094ebdc03100441"
"7341d18bc000411d103b4102100f416f41d982c0004119103b417f20002802a0011012417141f282c0004118103b20"
"02417f10124171418a83c0004118103b20024181081012417441a283c0004119103b200041e094ebdc036a22082000"
"2802a0011012417341bb83c0004118103b200642003703002003420037030020074200370300200042003703e80120"
"05411420084108200141201020417341ee8bc0004114103b2006420037030020034200370300200742003703002000"
"42003703e8012005411420054114200141201020417141828cc0004116103b20064200370300200342003703002007"
"4200370300200042003703e801200841082001412041001021417341988cc0004117103b2006420037030020034200"
"37030020074200370300200042003703e801200220002802a0012001412041001021417141af8cc0004120103b2008"
"20002802a00141011009417341d383c0004110103b200220002802a00141011009417141e383c0004112103b200642"
"003703002003420037030020074200370300200042003703e801200820002802a001200141201008417341cf8cc000"
"4116103b200642003703002003420037030020074200370300200042003703e801200220002802a001200141201008"
"417141e58cc0004118103b200642003703002003420037030020074200370300200042003703e80120054114200541"
"14200820002802a001200141201022417341fd8cc000411d103b200642003703002003420037030020074200370300"
"200042003703e8012005411420054114200220002802a0012001412010224171419a8dc000411f103b200642003703"
"002003420037030020074200370300200042003703e80141bb9bc0004114200820002802a001200141201023417341"
"b98dc0004115103b200642003703002003420037030020074200370300200042003703e80141bb9bc0004114200220"
"002802a001200141201023417141ce8dc000411b103b20064200370300200342003703002007420037030020004200"
"3703e80141bb9bc000411441f583c0004114200141201023417141e98dc0004125103b200642003703002003420037"
"030020074200370300200042003703e801418984c000412841bb9bc00041142001412010234171418e8ec000412110"
"3b200041dc016a2000413c6a280100360200200041d4016a200041346a2901003702002000200029012c3702cc0120"
"0041808080083602c801200041003b01e801200041c8016a2209411841bb9bc0004114200141021023417141af8ec0"
"00410a103b200820002802a001422a1001417341b184c0004111103b200041003b01e8014102200141021007416f41"
"b98ec0004117103b200041003b01e801410220014102100a416f41d08ec000411c103b200041003b01e80141014102"
"20014102100b416f41ec8ec0004117103b4102100f416f41d982c0004119103b41021010416f41c284c000411e103b"
"410141021011416f41e084c0004119103b41b980c0004181081006417441f984c000411f103b41b980c00041c10010"
"064174419885c000411a103b200041003b01e801200241810820014102100c417441838fc0004116103b200041003b"
"01e801200241810820014102100d417441998fc000411b103b200041003b01e8014101200241810820014102100e41"
"7441b48fc0004116103b20024181081012417441b285c000411e103b20024181081013417441d085c0004123103b41"
"0120024181081014417441f385c000411e103b200241812010154174419186c0004116103b418382c00041810841cc"
"81c000410b41d781c000410e1017417441e581c0004109103b418382c000410d41cc81c00041810841d781c000410e"
"1017417441e581c0004109103b418382c000410d41cc81c000410b41d781c0004181081017417441e581c000410910"
"3b200041003b01e8012002418108200141021016417441ca8fc0004119103b200041003b01e80141bb9bc000418108"
"41bb9bc0004114200141021023417441e38fc0004114103b200041003b01e801200541142005411420024181082001"
"41021024417441f78fc000411b103b200041003b01e8012009418108200541142001410210254174419290c000411e"
"103b418382c000410d200820002802a00141001000417341a786c000410f103b200042d487b6f4c7d4b1c0003700e0"
"01418382c000410d200041e095ebdc036a220441081026417341b686c0004116103b418382c000410d200820002802"
"a001101f417341cc86c0004113103b20044108200041e0016a220841081027417341df86c0004114103b2008410820"
"0441081027417341f386c0004114103b200041003b01e80120044108200841082001410241001028417341b090c000"
"4114103b200041003b01e80120084108200441082001410241001028417341c490c0004114103b200041003b01e801"
"20044108200841082001410241001029417341d890c0004114103b200041003b01e801200841082004410820014102"
"41001029417341ec90c0004114103b200041003b01e8012004410820084108200141024100102a4173418091c00041"
"15103b200041003b01e8012008410820044108200141024100102a4173419591c0004115103b200041003b01e80120"
"04410820084108200141024100102b417341aa91c0004114103b200041003b01e80120084108200441082001410241"
"00102b417341be91c0004114103b200041003b01e801200441084103200141024100102c417341d291c0004114103b"
"200041003b01e801200441084103200141024100102d417341e691c0004113103b2006420037030020034200370300"
"20074200370300200042003703e801200541142005411420014120102e417141f991c000411b103b20064200370300"
"2003420037030020074200370300200042003703e801200541142005411420014120102f4171419492c0004121103b"
"200642003703002003420037030020074200370300200042003703e8012005411420054114200141201030417141b5"
"92c000411e103b200642003703002003420037030020074200370300200042003703e8012005411420054114200141"
"201031417141d392c000411a103b200642003703002003420037030020074200370300200042003703e80120054114"
"20054114200141201032417141ed92c000411b103b2006420037030020034200370300200742003703002000420037"
"03e8012005411420054114200541142001412010334171418893c000411c103b200642003703002003420037030020"
"074200370300200042003703e8012005411420054114200141201034417141a493c0004128103b2006420037030020"
"03420037030020074200370300200042003703e8012005411420054114200141201035417141cc93c000411b103b20"
"0642003703002003420037030020074200370300200042003703e8012005411420054114200141201036417141e793"
"c000411a103b200220002802a001410010094171418787c000411b103b200041003b01e80120054114200220002802"
"a0012001410210184171418194c000411a103b200041003b01e801200220002802a0012001410210194171419b94c0"
"00411d103b200041003b01e801200220002802a00120014102101a417141b894c000411c103b200220002802a00110"
"1b417141a287c000411c103b200220002802a001101c417141be87c000411f103b200041003602e801200220002802"
"a00120014104101d417141d494c000411d103b200041003b01e801200220002802a001200141021008417141f194c0"
"004124103b200041808080083602e801200041003b018e02200220002802a001200141042000418e026a2203410210"
"204171419595c000411e103b200041003b018e02200220002802a00122062005411420022006200341021024417141"
"b395c0004124103b200041003b018e0220054114200220002802a001220620022006200341021024417141d795c000"
"4124103b200041003b018e02200220002802a00120054114200341021037417141fb95c0004122103b200041003b01"
"8e0220054114200220002802a0012003410210374171419d96c0004122103b200041003b018e02200220002802a001"
"20054114200341021038417141bf96c0004129103b200041003b018e0220054114200220002802a001200341021038"
"417141e896c0004129103b200041003b018e02200220002802a0012003410210394171419197c000411c103b200041"
"003b018e02200220002802a0012001410420034102102e417141ad97c000411f103b200041003b018e022002200028"
"02a0012005411441f583c0004114200341021022417141cc97c0004123103b200041003b018e022005411420022000"
"2802a00141f583c0004114200341021022417141ef97c0004123103b200041003b018e02200220002802a001200141"
"0420034102102f4171419298c0004125103b200041003b018e0220094118200220002802a001200341021025417141"
"b798c0004120103b200041003b018e02200220002802a00120014104200341021030417141d798c0004122103b2000"
"41003b018e02200220002802a00120014104200341021031417141f998c000411e103b200041003b018e0220022000"
"2802a001200141042003410210324171419799c000411f103b200041003b018e02200220002802a001200541142001"
"4104200341021033417141b699c0004121103b200041003b018e0220054114200220002802a0012001410420034102"
"1033417141d799c0004121103b200041003b018e02200220002802a00120014104200341021034417141f899c00041"
"2c103b200041003b018e02200220002802a00120034102103a417141a49ac0004120103b200041003b018e02200220"
"002802a00120014104200341021035417141c49ac000411f103b200041003b018e02200220002802a0012001410420"
"0341021036417141e39ac000411e103b200041003b018e02200220002802a00141dd87c00041202003410210184171"
"41819bc000411d103b418382c000410d200220002802a001101e417141fd87c0004120103b418396abdd03410d41dd"
"87c0004120410010004173419d88c0004110103b418396abdd03410d200841081026417341ad88c0004117103b4183"
"96abdd03410d20054114101e417341c488c0004115103b418396abdd03410d41ab82c0004108101f417341d988c000"
"4114103b200220002802a001200241810841001000417441ed88c000410e103b200241810842011001417441fb88c0"
"004112103b418382c0004181082008410810264174418d89c0004115103b418382c00041810820054114101e417441"
"a289c0004113103b418382c00041810841ab82c0004108101f417441b589c0004112103b418382c000410d20022000"
"2802a001101f417141c789c0004116103b200041003b018e02200220002802a001200541142003410210254171419e"
"9bc000411d103b418382c000410d200220002802a00141021000417141dd89c0004114103b4101410020054114101e"
"410041f189c0004117103b20004190026a240041010f0b0b418080c000410b417f20032003417f4e1bac1001000b0b"
"a61b0200418080c0000b89046572726f725f636f64653d54455354204641494c45442424242424205354415254494e"
"47205741534d20455845435554494f4e202424242424746573745f616d656e646d656e74616d656e646d656e745f65"
"6e61626c656463616368655f6c6574785f6172725f6c656e686f6d655f6c655f6172725f6c656e6c655f6172725f6c"
"656e74785f696e6e65725f6172725f6c656e686f6d655f6c655f696e6e65725f6172725f6c656e6c655f696e6e6572"
"5f6172725f6c656e7365745f6461746174657374206d65737361676574657374207075626b65797465737420736967"
"6e6174757265636865636b5f7369676e66745f666c6167736e66745f786665725f66656574657374696e6720747261"
"636574726163655f61636374400000000000005f74726163655f616d74400000000000000074726163655f616d745f"
"7a65726f706172656e745f6c6467725f686173685f6e65675f70747274785f6172725f6c656e5f696e76616c69645f"
"736669656c6474785f696e6e65725f6172725f6c656e5f6e65675f70747274785f696e6e65725f6172725f6c656e5f"
"6e65675f6c656e74785f696e6e65725f6172725f6c656e5f746f6f5f6c6f6e6774785f696e6e65725f6172725f6c65"
"6e5f7074725f6f6f6263616368655f6c655f7074725f6f6f6263616368655f6c655f77726f6e675f6c656e55534430"
"303030303030303030303030303030300041b184c0000b8a1774726163655f6e756d5f6f6f625f737472686f6d655f"
"6c655f6172725f6c656e5f696e76616c69645f736669656c646c655f6172725f6c656e5f696e76616c69645f736669"
"656c64616d656e646d656e745f656e61626c65645f746f6f5f6269675f736c696365616d656e646d656e745f656e61"
"626c65645f746f6f5f6c6f6e6774785f696e6e65725f6172725f6c656e5f746f6f5f6269675f736c696365686f6d65"
"5f6c655f696e6e65725f6172725f6c656e5f746f6f5f6269675f736c6963656c655f696e6e65725f6172725f6c656e"
"5f746f6f5f6269675f736c6963657365745f646174615f746f6f5f6269675f736c69636574726163655f6f6f625f73"
"6c69636574726163655f78666c6f61745f6f6f625f736c69636574726163655f616d745f6f6f625f736c696365666c"
"6f61745f636d705f6f6f625f736c69636531666c6f61745f636d705f6f6f625f736c6963653263616368655f6c655f"
"77726f6e675f73697a655f75696e743235366e66745f666c6167735f77726f6e675f73697a655f75696e743235366e"
"66745f786665725f6665655f77726f6e675f73697a655f75696e743235363030303030303030303030303030303030"
"30303030303030303030303030303174726163655f616363745f77726f6e675f73697a655f6163636f756e745f6964"
"74726163655f6f6f625f737472696e6774726163655f78666c6f61745f6f6f625f737472696e6774726163655f6163"
"63745f6f6f625f737472696e6774726163655f616d745f6f6f625f737472696e6774726163655f746f6f5f6c6f6e67"
"74726163655f6e756d5f746f6f5f6c6f6e6774726163655f78666c6f61745f746f6f5f6c6f6e6774726163655f6163"
"63745f746f6f5f6c6f6e6774726163655f616d745f746f6f5f6c6f6e6774726163655f616d745f77726f6e675f6c65"
"6e67746874726163655f696e76616c69645f61735f68657874726163655f616363745f636865636b5f646573796e63"
"6c6467725f696e646578706172656e745f6c6467725f74696d65706172656e745f6c6467725f68617368626173655f"
"666565686f6d655f6c655f6669656c646c655f6669656c6474785f696e6e6572686f6d655f6c655f696e6e65726c65"
"5f696e6e65727368613531325f68616c666e66745f7572696e66745f6973737565726e66745f7461786f6e6e66745f"
"73657269616c706172656e745f6c6467725f686173685f6e65675f6c656e706172656e745f6c6467725f686173685f"
"6275665f746f6f5f736d616c6c706172656e745f6c6467725f686173685f6c656e5f746f6f5f6c6f6e67636865636b"
"5f69645f6f6f625f6c656e5f753332636865636b5f69645f77726f6e675f6c656e5f753332666c6f61745f66726f6d"
"5f75696e745f6c656e5f6f6f62666c6f61745f66726f6d5f75696e745f77726f6e675f6c656e5f75696e7436346163"
"636f756e74726f6f745f69645f6c656e5f6f6f626163636f756e74726f6f745f69645f77726f6e675f6c656e747275"
"73746c696e655f69645f6c656e5f6f6f625f63757272656e637974727573746c696e655f69645f77726f6e675f6c65"
"6e5f63757272656e6379616d6d5f69645f6c656e5f6f6f625f617373657432616d6d5f69645f6c656e5f77726f6e67"
"5f6c656e5f617373657432616d6d5f69645f6c656e5f77726f6e675f6e6f6e5f7872705f63757272656e63795f6c65"
"6e616d6d5f69645f6c656e5f77726f6e675f7872705f63757272656e63795f6c656e616d6d5f69645f6d707474785f"
"6669656c645f696e76616c69645f736669656c64686f6d655f6c655f6669656c645f696e76616c69645f736669656c"
"646c655f6669656c645f696e76616c69645f736669656c6474785f696e6e65725f746f6f5f6269675f736c69636568"
"6f6d655f6c655f696e6e65725f746f6f5f6269675f736c6963656c655f696e6e65725f746f6f5f6269675f736c6963"
"657368613531325f68616c665f746f6f5f6269675f736c696365616d6d5f69645f746f6f5f6269675f736c69636563"
"726564656e7469616c5f69645f746f6f5f6269675f736c6963656d70746f6b656e5f69645f746f6f5f6269675f736c"
"6963655f6d70746964666c6f61745f6164645f6f6f625f736c69636531666c6f61745f6164645f6f6f625f736c6963"
"6532666c6f61745f7375625f6f6f625f736c69636531666c6f61745f7375625f6f6f625f736c69636532666c6f6174"
"5f6d756c745f6f6f625f736c69636531666c6f61745f6d756c745f6f6f625f736c69636532666c6f61745f6469765f"
"6f6f625f736c69636531666c6f61745f6469765f6f6f625f736c69636532666c6f61745f726f6f745f6f6f625f736c"
"696365666c6f61745f706f775f6f6f625f736c696365657363726f775f69645f77726f6e675f73697a655f75696e74"
"33326d70745f69737375616e63655f69645f77726f6e675f73697a655f75696e7433326e66745f6f666665725f6964"
"5f77726f6e675f73697a655f75696e7433326f666665725f69645f77726f6e675f73697a655f75696e7433326f7261"
"636c655f69645f77726f6e675f73697a655f75696e7433327061796368616e5f69645f77726f6e675f73697a655f75"
"696e7433327065726d697373696f6e65645f646f6d61696e5f69645f77726f6e675f73697a655f75696e7433327469"
"636b65745f69645f77726f6e675f73697a655f75696e7433327661756c745f69645f77726f6e675f73697a655f7569"
"6e7433326e66745f7572695f77726f6e675f73697a655f75696e743235366e66745f6973737565725f77726f6e675f"
"73697a655f75696e743235366e66745f7461786f6e5f77726f6e675f73697a655f75696e743235366e66745f736572"
"69616c5f77726f6e675f73697a655f75696e743235366163636f756e74726f6f745f69645f77726f6e675f73697a65"
"5f6163636f756e745f6964636865636b5f69645f77726f6e675f73697a655f6163636f756e745f696463726564656e"
"7469616c5f69645f77726f6e675f73697a655f6163636f756e745f69643163726564656e7469616c5f69645f77726f"
"6e675f73697a655f6163636f756e745f69643264656c65676174655f69645f77726f6e675f73697a655f6163636f75"
"6e745f69643164656c65676174655f69645f77726f6e675f73697a655f6163636f756e745f6964326465706f736974"
"5f707265617574685f69645f77726f6e675f73697a655f6163636f756e745f6964316465706f7369745f7072656175"
"74685f69645f77726f6e675f73697a655f6163636f756e745f6964326469645f69645f77726f6e675f73697a655f61"
"63636f756e745f6964657363726f775f69645f77726f6e675f73697a655f6163636f756e745f696474727573746c69"
"6e655f69645f77726f6e675f73697a655f6163636f756e745f69643174727573746c696e655f69645f77726f6e675f"
"73697a655f6163636f756e745f6964326d70745f69737375616e63655f69645f77726f6e675f73697a655f6163636f"
"756e745f69646d70746f6b656e5f69645f77726f6e675f73697a655f6163636f756e745f69646e66745f6f66666572"
"5f69645f77726f6e675f73697a655f6163636f756e745f69646f666665725f69645f77726f6e675f73697a655f6163"
"636f756e745f69646f7261636c655f69645f77726f6e675f73697a655f6163636f756e745f69647061796368616e5f"
"69645f77726f6e675f73697a655f6163636f756e745f6964317061796368616e5f69645f77726f6e675f73697a655f"
"6163636f756e745f6964327065726d697373696f6e65645f646f6d61696e5f69645f77726f6e675f73697a655f6163"
"636f756e745f69647369676e6572735f69645f77726f6e675f73697a655f6163636f756e745f69647469636b65745f"
"69645f77726f6e675f73697a655f6163636f756e745f69647661756c745f69645f77726f6e675f73697a655f616363"
"6f756e745f69646e66745f7572695f77726f6e675f73697a655f6163636f756e745f69646d70746f6b656e5f69645f"
"6d707469645f77726f6e675f6c656e677468004d0970726f64756365727302086c616e677561676501045275737400"
"0c70726f6365737365642d6279010572757374631d312e38372e30202831373036376539616320323032352d30352d"
"303929002c0f7461726765745f6665617475726573022b0f6d757461626c652d676c6f62616c732b087369676e2d65"
"7874";
extern std::string const kBadAlignWasmHex =
"0061736d01000000011b046000017f60057f7f7f7f7f017f60067f7f7f7f7f7f017f60000002260203656e760f666c"
"6f61745f66726f6d5f75696e74000103656e7608636865636b5f6964000203050403000000050301000306470b7f00"
"4180080b7f00418088020b7f004180080b7f00418088040b7f00418088040b7f00418088080b7f004180080b7f0041"
"8088080b7f004180800c0b7f0041000b7f0041010b07cc0110066d656d6f72790200115f5f7761736d5f63616c6c"
"5f63746f72730002057465737431000307655f64617461310300057465737432000407655f64617461320301047465"
"737400050c5f5f64736f5f68616e646c6503020a5f5f646174615f656e6403030b5f5f737461636b5f6c6f770304"
"0c5f5f737461636b5f6869676803050d5f5f676c6f62616c5f6261736503060b5f5f686561705f6261736503070a"
"5f5f686561705f656e6403080d5f5f6d656d6f72795f6261736503090c5f5f7461626c655f62617365030a0a9902"
"0402000b2801017f418108427f370000418108410841a308410c41001000220041a40828020020004100481b0b5f01"
"017f419a88024191a4cca00136010041928802428994ace0d0c1c38710370100418a88024281848ca0d0c0c1830837"
"010041818802417f360000418a8802411441818802410441a3880241201001220041a4880228020020004100481b0b"
"8a0101037f418108427f370000418108410841a308410c410010002100419a88024191a4cca0013601004192880242"
"8994ace0d0c1c38710370100418a88024281848ca0d0c0c1830837010041818802417f36000041a408280200210141"
"8a8802411441818802410441a3880241201001220241a4880228020020024100481b2000200120004100481b6a0b00"
"7f0970726f647563657273010c70726f6365737365642d62790105636c616e675f31392e312e352d776173692d7364"
"6b202868747470733a2f2f6769746875622e636f6d2f6c6c766d2f6c6c766d2d70726f6a6563742061623462356132"
"6462353832393538616631656533303861373930636664623432626432343732302900490f7461726765745f666561"
"7475726573042b0f6d757461626c652d676c6f62616c732b087369676e2d6578742b0f7265666572656e63652d7479"
"7065732b0a6d756c746976616c7565";

View File

@@ -1,12 +0,0 @@
#pragma once
// TODO: consider moving these to separate files (and figure out the build)
#include <string>
extern std::string const kLedgerSqnWasmHex;
extern std::string const kAllHostFunctionsWasmHex;
extern std::string const kAllKeyletsWasmHex;
extern std::string const kCodecovTestsWasmHex;
extern std::string const kBadAlignWasmHex;

View File

@@ -1,14 +0,0 @@
#include <stdint.h>
int32_t ldgr_index(uint8_t *, int32_t);
int finish()
{
uint32_t sqn;
int32_t result = ldgr_index((uint8_t *)&sqn, sizeof(sqn));
if (result < 0)
return result;
return sqn >= 5 ? 5 : 0;
}