mirror of
https://github.com/XRPLF/rippled.git
synced 2026-07-06 23:00:20 +00:00
Compare commits
3 Commits
ripple/se/
...
ripple/was
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8022fc33cf | ||
|
|
9767d86de4 | ||
|
|
ca2d999618 |
@@ -329,6 +329,7 @@ words:
|
||||
- wthread
|
||||
- xbridge
|
||||
- xchain
|
||||
- xfloat
|
||||
- ximinez
|
||||
- XMACRO
|
||||
- xrpkuwait
|
||||
|
||||
@@ -254,6 +254,9 @@ 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;
|
||||
|
||||
|
||||
@@ -360,6 +360,7 @@ enum TECcodes : TERUnderlyingType {
|
||||
tecLIMIT_EXCEEDED = 195,
|
||||
tecPSEUDO_ACCOUNT = 196,
|
||||
tecPRECISION_LOSS = 197,
|
||||
tecOUT_OF_GAS = 200,
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -113,398 +113,398 @@ public:
|
||||
virtual Expected<std::uint32_t, HostFunctionError>
|
||||
getLedgerSqn() const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<std::uint32_t, HostFunctionError>
|
||||
getParentLedgerTime() const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<Hash, HostFunctionError>
|
||||
getParentLedgerHash() const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<uint32_t, HostFunctionError>
|
||||
getBaseFee() const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<int32_t, HostFunctionError>
|
||||
isAmendmentEnabled(uint256 const& amendmentId) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<int32_t, HostFunctionError>
|
||||
isAmendmentEnabled(std::string_view const& amendmentName) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<int32_t, HostFunctionError>
|
||||
cacheLedgerObj(uint256 const& objId, int32_t cacheIdx)
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
getTxField(SField const& fname) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
getCurrentLedgerObjField(SField const& fname) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
getLedgerObjField(int32_t cacheIdx, SField const& fname) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
getTxNestedField(FieldLocator const& locator) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
getCurrentLedgerObjNestedField(FieldLocator const& locator) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
getLedgerObjNestedField(int32_t cacheIdx, FieldLocator const& locator) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<int32_t, HostFunctionError>
|
||||
getTxArrayLen(SField const& fname) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<int32_t, HostFunctionError>
|
||||
getCurrentLedgerObjArrayLen(SField const& fname) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<int32_t, HostFunctionError>
|
||||
getLedgerObjArrayLen(int32_t cacheIdx, SField const& fname) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<int32_t, HostFunctionError>
|
||||
getTxNestedArrayLen(FieldLocator const& locator) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<int32_t, HostFunctionError>
|
||||
getCurrentLedgerObjNestedArrayLen(FieldLocator const& locator) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<int32_t, HostFunctionError>
|
||||
getLedgerObjNestedArrayLen(int32_t cacheIdx, FieldLocator const& locator) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<int32_t, HostFunctionError>
|
||||
updateData(Slice const& data)
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<int32_t, HostFunctionError>
|
||||
checkSignature(Slice const& message, Slice const& signature, Slice const& pubkey) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<Hash, HostFunctionError>
|
||||
computeSha512HalfHash(Slice const& data) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
accountKeylet(AccountID const& account) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
ammKeylet(Asset const& issue1, Asset const& issue2) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
checkKeylet(AccountID const& account, std::uint32_t seq) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
credentialKeylet(AccountID const& subject, AccountID const& issuer, Slice const& credentialType)
|
||||
const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
didKeylet(AccountID const& account) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
delegateKeylet(AccountID const& account, AccountID const& authorize) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
depositPreauthKeylet(AccountID const& account, AccountID const& authorize) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
escrowKeylet(AccountID const& account, std::uint32_t seq) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
lineKeylet(AccountID const& account1, AccountID const& account2, Currency const& currency) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
mptIssuanceKeylet(AccountID const& issuer, std::uint32_t seq) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
mptokenKeylet(MPTID const& mptid, AccountID const& holder) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
nftOfferKeylet(AccountID const& account, std::uint32_t seq) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
offerKeylet(AccountID const& account, std::uint32_t seq) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
oracleKeylet(AccountID const& account, std::uint32_t docId) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
paychanKeylet(AccountID const& account, AccountID const& destination, std::uint32_t seq) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
permissionedDomainKeylet(AccountID const& account, std::uint32_t seq) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
signersKeylet(AccountID const& account) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
ticketKeylet(AccountID const& account, std::uint32_t seq) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
vaultKeylet(AccountID const& account, std::uint32_t seq) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
getNFT(AccountID const& account, uint256 const& nftId) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
getNFTIssuer(uint256 const& nftId) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<std::uint32_t, HostFunctionError>
|
||||
getNFTTaxon(uint256 const& nftId) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<int32_t, HostFunctionError>
|
||||
getNFTFlags(uint256 const& nftId) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<int32_t, HostFunctionError>
|
||||
getNFTTransferFee(uint256 const& nftId) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<std::uint32_t, HostFunctionError>
|
||||
getNFTSerial(uint256 const& nftId) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<int32_t, HostFunctionError>
|
||||
trace(std::string_view const& msg, Slice const& data, bool asHex) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<int32_t, HostFunctionError>
|
||||
traceNum(std::string_view const& msg, int64_t data) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<int32_t, HostFunctionError>
|
||||
traceAccount(std::string_view const& msg, AccountID const& account) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<int32_t, HostFunctionError>
|
||||
traceFloat(std::string_view const& msg, Slice const& data) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<int32_t, HostFunctionError>
|
||||
traceAmount(std::string_view const& msg, STAmount const& amount) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
floatFromInt(int64_t x, int32_t mode) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
floatFromUint(uint64_t x, int32_t mode) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
floatFromSTAmount(STAmount const& x, int32_t mode) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
floatFromSTNumber(STNumber const& x, int32_t mode) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<int64_t, HostFunctionError>
|
||||
floatToInt(Slice const& x, int32_t mode) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<FloatPair, HostFunctionError>
|
||||
floatToMantExp(Slice const& x) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
floatFromMantExp(int64_t mantissa, int32_t exponent, int32_t mode) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<int32_t, HostFunctionError>
|
||||
floatCompare(Slice const& x, Slice const& y) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
floatAdd(Slice const& x, Slice const& y, int32_t mode) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
floatSubtract(Slice const& x, Slice const& y, int32_t mode) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
floatMultiply(Slice const& x, Slice const& y, int32_t mode) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
floatDivide(Slice const& x, Slice const& y, int32_t mode) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
floatRoot(Slice const& x, int32_t n, int32_t mode) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual Expected<Bytes, HostFunctionError>
|
||||
floatPower(Slice const& x, int32_t n, int32_t mode) const
|
||||
{
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual ~HostFunctions() = default;
|
||||
|
||||
@@ -2,10 +2,12 @@
|
||||
|
||||
#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 {
|
||||
@@ -14,8 +16,20 @@ 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 {
|
||||
Internal = -1,
|
||||
Unimplemented = -1,
|
||||
FieldNotFound = -2,
|
||||
BufferTooSmall = -3,
|
||||
NoArray = -4,
|
||||
@@ -25,7 +39,7 @@ enum class HostFunctionError : int32_t {
|
||||
SlotsFull = -8,
|
||||
EmptySlot = -9,
|
||||
LedgerObjNotFound = -10,
|
||||
Decoding = -11,
|
||||
OutOfTransferLimit = -11,
|
||||
DataFieldTooLarge = -12,
|
||||
PointerOutOfBounds = -13,
|
||||
NoMemExported = -14,
|
||||
@@ -35,9 +49,6 @@ enum class HostFunctionError : int32_t {
|
||||
IndexOutOfBounds = -18,
|
||||
FloatInputMalformed = -19,
|
||||
FloatComputationError = -20,
|
||||
NoRuntime = -21,
|
||||
OutOfGas = -22,
|
||||
OutOfTransferLimit = -23,
|
||||
};
|
||||
|
||||
enum class WasmTypes { WtI32, WtI64 };
|
||||
@@ -61,6 +72,15 @@ struct WasmResult
|
||||
};
|
||||
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;
|
||||
@@ -124,6 +144,12 @@ public:
|
||||
|
||||
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>>;
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ public:
|
||||
static WasmEngine&
|
||||
instance();
|
||||
|
||||
Expected<WasmResult<int32_t>, TER>
|
||||
Expected<WasmResult<int32_t>, WasmTER>
|
||||
run(Bytes const& wasmCode,
|
||||
HostFunctions& hfs,
|
||||
int64_t gasLimit,
|
||||
@@ -71,7 +71,7 @@ public:
|
||||
ImportVec
|
||||
createWasmImport(HostFunctions& hfs);
|
||||
|
||||
Expected<EscrowResult, TER>
|
||||
Expected<EscrowResult, WasmTER>
|
||||
runEscrowWasm(
|
||||
Bytes const& wasmCode,
|
||||
HostFunctions& hfs,
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
#include <wasm.h>
|
||||
#include <wasmi.h>
|
||||
|
||||
#include <optional>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
template <class T, void (*Create)(T*, size_t), void (*Destroy)(T*)>
|
||||
@@ -120,7 +122,10 @@ using WasmImporttypeVec = WasmVec<
|
||||
struct WasmiResult
|
||||
{
|
||||
WasmValVec r;
|
||||
bool f{false}; // failure flag
|
||||
// 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)
|
||||
{
|
||||
@@ -147,6 +152,7 @@ class InstanceWrapper
|
||||
mutable int memIdx_ = -1;
|
||||
InstancePtr instance_;
|
||||
beast::Journal j_ = beast::Journal(beast::Journal::getNullSink());
|
||||
std::int64_t transferLimit_ = kWasmTransferLimit;
|
||||
|
||||
private:
|
||||
static InstancePtr
|
||||
@@ -194,6 +200,12 @@ public:
|
||||
|
||||
std::int64_t
|
||||
setGas(std::int64_t) const;
|
||||
|
||||
std::int64_t
|
||||
getTransferLimit() const;
|
||||
|
||||
std::int64_t
|
||||
setTransferLimit(std::int64_t);
|
||||
};
|
||||
|
||||
class ModuleWrapper
|
||||
@@ -297,7 +309,7 @@ public:
|
||||
static EnginePtr
|
||||
init();
|
||||
|
||||
Expected<WasmResult<int32_t>, TER>
|
||||
Expected<WasmResult<int32_t>, WasmTER>
|
||||
run(Bytes const& wasmCode,
|
||||
HostFunctions& hfs,
|
||||
int64_t gas,
|
||||
@@ -348,7 +360,7 @@ private:
|
||||
return moduleWrap_ ? moduleWrap_->getMem() : Wmem();
|
||||
}
|
||||
|
||||
Expected<WasmResult<int32_t>, TER>
|
||||
Expected<WasmResult<int32_t>, WasmTER>
|
||||
runHlp(
|
||||
Bytes const& wasmCode,
|
||||
HostFunctions& hfs,
|
||||
|
||||
@@ -106,6 +106,7 @@ 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."),
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#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>
|
||||
@@ -13,6 +14,8 @@
|
||||
#include <xrpl/tx/wasm/WasmCommon.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <variant>
|
||||
|
||||
@@ -121,7 +124,9 @@ getAnyFieldData(FieldValue const& variantObj)
|
||||
if (uint256 const* const* u = std::get_if<uint256 const*>(&variantObj))
|
||||
return Bytes((*u)->begin(), (*u)->end());
|
||||
|
||||
return Unexpected(HostFunctionError::Internal); // LCOV_EXCL_LINE
|
||||
// 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
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <xrpl/basics/Expected.h>
|
||||
#include <xrpl/basics/Slice.h>
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/basics/contract.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/Asset.h>
|
||||
#include <xrpl/protocol/Issue.h>
|
||||
@@ -31,6 +32,8 @@
|
||||
#include <exception>
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
@@ -41,7 +44,12 @@ namespace xrpl {
|
||||
|
||||
using SFieldCRef = std::reference_wrapper<SField const>;
|
||||
|
||||
static inline Expected<std::int64_t, HostFunctionError>
|
||||
constexpr int64_t unalignedGas = 50;
|
||||
|
||||
// Charge `delta` gas; returns the remaining gas. Out-of-gas throws hfErrOutOfGas
|
||||
// (-> tecOUT_OF_GAS); a failed setGas is an xrpld bug, throws hfErrInternal
|
||||
// (-> tecINTERNAL). HostFuncMain_wrap turns both into traps.
|
||||
static inline std::int64_t
|
||||
checkGas(WasmRuntimeWrapper& rt, int64_t delta)
|
||||
{
|
||||
int64_t const gas = rt.getGas();
|
||||
@@ -51,67 +59,52 @@ checkGas(WasmRuntimeWrapper& rt, int64_t delta)
|
||||
int64_t const x = gas >= delta ? gas - delta : 0;
|
||||
|
||||
if (rt.setGas(x) < 0)
|
||||
return Unexpected(HostFunctionError::Internal); // LCOV_EXCL_LINE
|
||||
Throw<std::runtime_error>(std::string(hfErrInternal)); // LCOV_EXCL_LINE
|
||||
|
||||
if (gas < delta)
|
||||
return Unexpected(HostFunctionError::OutOfGas);
|
||||
Throw<std::runtime_error>(std::string(hfErrOutOfGas));
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline Expected<std::int64_t, wasm_trap_t*>
|
||||
checkGas(WasmRuntimeWrapper& rt, WasmImportFunc const& impFunc)
|
||||
// Transfer limit is a separate soft budget: exceeding it is a normal guest-facing
|
||||
// return code, not a trap. Only a failed setTransferLimit (an xrpld bug) throws.
|
||||
static inline Expected<std::int64_t, HostFunctionError>
|
||||
checkTransfer(WasmRuntimeWrapper& rt, int64_t delta)
|
||||
{
|
||||
auto g = checkGas(rt, impFunc.gas);
|
||||
auto const transLimit = rt.getTransferLimit();
|
||||
int64_t const x = transLimit >= delta ? transLimit - delta : 0;
|
||||
|
||||
if (!g)
|
||||
{
|
||||
if (g.error() == HostFunctionError::OutOfGas)
|
||||
{
|
||||
wasm_trap_t* const trap = // NOLINT
|
||||
reinterpret_cast<wasm_trap_t*>(WasmEngine::instance().newTrap("hf out of gas"));
|
||||
return Unexpected(trap);
|
||||
}
|
||||
if (rt.setTransferLimit(x) < 0)
|
||||
Throw<std::runtime_error>(std::string(hfErrInternal)); // LCOV_EXCL_LINE
|
||||
|
||||
wasm_trap_t* trap = reinterpret_cast<wasm_trap_t*>( // NOLINT
|
||||
WasmEngine::instance().newTrap("can't set gas")); // LCOV_EXCL_LINE
|
||||
return Unexpected(trap); // LCOV_EXCL_LINE
|
||||
}
|
||||
if (transLimit < delta)
|
||||
return Unexpected(HostFunctionError::OutOfTransferLimit);
|
||||
|
||||
return *g;
|
||||
return x;
|
||||
}
|
||||
|
||||
static Expected<std::tuple<HostFunctions&, WasmImportFunc const&>, wasm_trap_t*>
|
||||
// On any failure here a C++ exception is thrown; HostFuncMain_wrap's catch-all
|
||||
// turns it into tecINTERNAL. These conditions are all xrpld-side invariants.
|
||||
static std::tuple<HostFunctions&, WasmImportFunc const&>
|
||||
mainCheck(void* env, wasm_val_vec_t const* params, wasm_val_vec_t* results)
|
||||
{
|
||||
if (env == nullptr)
|
||||
{
|
||||
wasm_trap_t* trap = reinterpret_cast<wasm_trap_t*>( // NOLINT
|
||||
WasmEngine::instance().newTrap("no environment")); // LCOV_EXCL_LINE
|
||||
return Unexpected(trap); // LCOV_EXCL_LINE
|
||||
}
|
||||
Throw<std::runtime_error>(std::string(hfErrInternal)); // LCOV_EXCL_LINE
|
||||
|
||||
if (params == nullptr)
|
||||
{
|
||||
wasm_trap_t* trap = reinterpret_cast<wasm_trap_t*>( // NOLINT
|
||||
WasmEngine::instance().newTrap("no params")); // LCOV_EXCL_LINE
|
||||
return Unexpected(trap); // LCOV_EXCL_LINE
|
||||
}
|
||||
Throw<std::runtime_error>(std::string(hfErrInternal)); // LCOV_EXCL_LINE
|
||||
|
||||
if (results == nullptr)
|
||||
{
|
||||
wasm_trap_t* trap = reinterpret_cast<wasm_trap_t*>( // NOLINT
|
||||
WasmEngine::instance().newTrap("no results")); // LCOV_EXCL_LINE
|
||||
return Unexpected(trap); // LCOV_EXCL_LINE
|
||||
}
|
||||
Throw<std::runtime_error>(std::string(hfErrInternal)); // LCOV_EXCL_LINE
|
||||
|
||||
WasmUserData const* udata = reinterpret_cast<WasmUserData*>(env);
|
||||
HostFunctions& hf = udata->first;
|
||||
WasmRuntimeWrapper& rt = hf.getRT();
|
||||
WasmImportFunc const& impFunc = udata->second;
|
||||
|
||||
if (auto g = checkGas(rt, impFunc); !g)
|
||||
return Unexpected(g.error()); // LCOV_EXCL_LINE
|
||||
// Charge the per-call gas. Throws (and terminates) if out of gas.
|
||||
checkGas(rt, impFunc.gas);
|
||||
|
||||
return std::tie(hf, impFunc);
|
||||
}
|
||||
@@ -146,6 +139,9 @@ setData(
|
||||
if (srcSize > dstSize)
|
||||
return hfErrorToInt(HostFunctionError::BufferTooSmall);
|
||||
|
||||
if (auto t = checkTransfer(runtime, srcSize); !t)
|
||||
return hfErrorToInt(t.error());
|
||||
|
||||
memcpy(memory.p + dst, src, srcSize);
|
||||
|
||||
return srcSize;
|
||||
@@ -255,6 +251,9 @@ getDataUInt256(WasmRuntimeWrapper& runtime, wasm_val_vec_t const* params, int32_
|
||||
if (slice->size() != uint256::size())
|
||||
return Unexpected(HostFunctionError::InvalidParams);
|
||||
|
||||
if (auto t = checkTransfer(runtime, uint256::size()); !t)
|
||||
return Unexpected(t.error());
|
||||
|
||||
return uint256::fromVoid(slice->data());
|
||||
}
|
||||
|
||||
@@ -268,6 +267,9 @@ getDataAccountID(WasmRuntimeWrapper& runtime, wasm_val_vec_t const* params, int3
|
||||
if (slice->size() != AccountID::size())
|
||||
return Unexpected(HostFunctionError::InvalidParams);
|
||||
|
||||
if (auto t = checkTransfer(runtime, AccountID::size()); !t)
|
||||
return Unexpected(t.error());
|
||||
|
||||
return AccountID::fromVoid(slice->data());
|
||||
}
|
||||
|
||||
@@ -281,6 +283,9 @@ getDataCurrency(WasmRuntimeWrapper& runtime, wasm_val_vec_t const* params, int32
|
||||
if (slice->size() != Currency::size())
|
||||
return Unexpected(HostFunctionError::InvalidParams);
|
||||
|
||||
if (auto t = checkTransfer(runtime, Currency::size()); !t)
|
||||
return Unexpected(t.error());
|
||||
|
||||
return Currency::fromVoid(slice->data());
|
||||
}
|
||||
|
||||
@@ -293,12 +298,18 @@ getDataAsset(WasmRuntimeWrapper& runtime, wasm_val_vec_t const* params, int32_t&
|
||||
|
||||
if (slice->size() == MPTID::size())
|
||||
{
|
||||
if (auto t = checkTransfer(runtime, slice->size()); !t)
|
||||
return Unexpected(t.error());
|
||||
|
||||
auto const mptid = MPTID::fromVoid(slice->data());
|
||||
return Asset{mptid};
|
||||
}
|
||||
|
||||
if (slice->size() == Currency::size())
|
||||
{
|
||||
if (auto t = checkTransfer(runtime, slice->size()); !t)
|
||||
return Unexpected(t.error());
|
||||
|
||||
auto const currency = Currency::fromVoid(slice->data());
|
||||
auto const issue = Issue{currency, xrpAccount()};
|
||||
if (!issue.native())
|
||||
@@ -309,6 +320,9 @@ getDataAsset(WasmRuntimeWrapper& runtime, wasm_val_vec_t const* params, int32_t&
|
||||
|
||||
if (slice->size() == (Currency::size() + AccountID::size()))
|
||||
{
|
||||
if (auto t = checkTransfer(runtime, slice->size()); !t)
|
||||
return Unexpected(t.error());
|
||||
|
||||
auto const issue = Issue(
|
||||
Currency::fromVoid(slice->data()),
|
||||
AccountID::fromVoid(slice->data() + Currency::size()));
|
||||
@@ -349,6 +363,13 @@ getDataLocator(WasmRuntimeWrapper& runtime, wasm_val_vec_t const* params, int32_
|
||||
if ((p & (alignof(int32_t) - 1)) != 0u)
|
||||
{ // unaligned
|
||||
|
||||
// Use gas and transfer limit for copying. checkGas throws (and
|
||||
// terminates execution) if out of gas; checkTransfer keeps returning a
|
||||
// guest-facing code when the transfer limit is exceeded.
|
||||
checkGas(runtime, unalignedGas);
|
||||
if (auto t = checkTransfer(runtime, slice->size()); !t)
|
||||
return Unexpected(t.error());
|
||||
|
||||
std::vector<int32_t> locBuf(locSize);
|
||||
memcpy(&locBuf[0], slice->data(), slice->size());
|
||||
FieldLocator locator(std::move(locBuf));
|
||||
@@ -391,7 +412,7 @@ returnResult(
|
||||
if constexpr (std::is_same_v<T, Bytes>)
|
||||
{
|
||||
if (index < 0 || index + 1 >= params->size)
|
||||
return hfResult(results, HostFunctionError::Internal); // LCOV_EXCL_LINE
|
||||
Throw<std::runtime_error>(std::string(hfErrInternal)); // LCOV_EXCL_LINE
|
||||
|
||||
auto const dataResult = setData(
|
||||
runtime,
|
||||
@@ -404,7 +425,7 @@ returnResult(
|
||||
else if constexpr (std::is_same_v<T, Hash>)
|
||||
{
|
||||
if (index < 0 || index + 1 >= params->size)
|
||||
return hfResult(results, HostFunctionError::Internal); // LCOV_EXCL_LINE
|
||||
Throw<std::runtime_error>(std::string(hfErrInternal)); // LCOV_EXCL_LINE
|
||||
|
||||
auto const dataResult = setData(
|
||||
runtime,
|
||||
@@ -421,7 +442,7 @@ returnResult(
|
||||
else if constexpr (std::is_same_v<T, std::uint32_t>)
|
||||
{
|
||||
if (index < 0 || index + 1 >= params->size)
|
||||
return hfResult(results, HostFunctionError::Internal); // LCOV_EXCL_LINE
|
||||
Throw<std::runtime_error>(std::string(hfErrInternal)); // LCOV_EXCL_LINE
|
||||
|
||||
auto const resultValue = adjustWasmEndianess(res.value());
|
||||
auto const dataResult = setData(
|
||||
@@ -435,7 +456,7 @@ returnResult(
|
||||
else if constexpr (std::is_same_v<T, int64_t>)
|
||||
{
|
||||
if (index < 0 || index + 1 >= params->size)
|
||||
return hfResult(results, HostFunctionError::Internal); // LCOV_EXCL_LINE
|
||||
Throw<std::runtime_error>(std::string(hfErrInternal)); // LCOV_EXCL_LINE
|
||||
|
||||
auto const resultValue = adjustWasmEndianess(res.value());
|
||||
auto const dataResult = setData(
|
||||
@@ -449,7 +470,7 @@ returnResult(
|
||||
else if constexpr (std::is_same_v<T, FloatPair>)
|
||||
{
|
||||
if (index < 0 || index + 3 >= params->size)
|
||||
return hfResult(results, HostFunctionError::Internal); // LCOV_EXCL_LINE
|
||||
Throw<std::runtime_error>(std::string(hfErrInternal)); // LCOV_EXCL_LINE
|
||||
|
||||
auto const mantissa = adjustWasmEndianess(res->first);
|
||||
auto const r1 = setData(
|
||||
@@ -481,6 +502,7 @@ returnResult(
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
wasm_trap_t*
|
||||
HostFuncMain_wrap(WASM_CB_PARAMS_LIST)
|
||||
{
|
||||
@@ -488,11 +510,7 @@ HostFuncMain_wrap(WASM_CB_PARAMS_LIST)
|
||||
|
||||
try
|
||||
{
|
||||
auto const mc = mainCheck(env, params, results);
|
||||
if (!mc)
|
||||
return mc.error(); // LCOV_EXCL_LINE
|
||||
auto& [hf, impFunc] = *mc;
|
||||
|
||||
auto [hf, impFunc] = mainCheck(env, params, results);
|
||||
hfName = impFunc.name;
|
||||
auto* fWrap = reinterpret_cast<wasmSecondaryCbFuncType*>(impFunc.wrap);
|
||||
return fWrap(hf, params, results);
|
||||
@@ -502,8 +520,11 @@ HostFuncMain_wrap(WASM_CB_PARAMS_LIST)
|
||||
#ifdef DEBUG_OUTPUT
|
||||
std::cerr << "Hostfunction " << hfName << " exception: " << e.what() << std::endl;
|
||||
#endif
|
||||
// Normalize to the two boundary signals: explicit out-of-gas, else any
|
||||
// exception (including stray ones from helpers) is an internal fault.
|
||||
bool const oog = std::string_view(e.what()) == hfErrOutOfGas;
|
||||
wasm_trap_t* trap = reinterpret_cast<wasm_trap_t*>( // NOLINT
|
||||
WasmEngine::instance().newTrap(e.what())); // LCOV_EXCL_LINE
|
||||
WasmEngine::instance().newTrap(std::string(oog ? hfErrOutOfGas : hfErrInternal)));
|
||||
return trap;
|
||||
}
|
||||
catch (...)
|
||||
@@ -511,12 +532,12 @@ HostFuncMain_wrap(WASM_CB_PARAMS_LIST)
|
||||
#ifdef DEBUG_OUTPUT
|
||||
std::cerr << "Hostfunction " << hfName << " unknown exception." << std::endl;
|
||||
#endif
|
||||
wasm_trap_t* trap = reinterpret_cast<wasm_trap_t*>( // NOLINT
|
||||
WasmEngine::instance().newTrap("Unknown exception")); // LCOV_EXCL_LINE
|
||||
wasm_trap_t* trap = reinterpret_cast<wasm_trap_t*>( // NOLINT
|
||||
WasmEngine::instance().newTrap(std::string(hfErrInternal))); // LCOV_EXCL_LINE
|
||||
return trap;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
return nullptr; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
@@ -1677,6 +1698,7 @@ class MockWasmRuntimeWrapper : public WasmRuntimeWrapper
|
||||
Wmem mem_;
|
||||
|
||||
std::int64_t gas_ = 1'000'000;
|
||||
std::int64_t transferLimit_ = kWasmTransferLimit;
|
||||
|
||||
public:
|
||||
MockWasmRuntimeWrapper(Wmem memory) : mem_(memory)
|
||||
@@ -1702,6 +1724,19 @@ public:
|
||||
gas_ = gas;
|
||||
return gas_;
|
||||
}
|
||||
|
||||
std::int64_t
|
||||
getTransferLimit() override
|
||||
{
|
||||
return transferLimit_;
|
||||
}
|
||||
|
||||
std::int64_t
|
||||
setTransferLimit(std::int64_t x) override
|
||||
{
|
||||
transferLimit_ = x;
|
||||
return transferLimit_;
|
||||
}
|
||||
};
|
||||
|
||||
bool
|
||||
|
||||
@@ -31,76 +31,76 @@ static void
|
||||
setCommonHostFunctions(HostFunctions& hfs, ImportVec& i)
|
||||
{
|
||||
// clang-format off
|
||||
WASM_IMPORT_FUNC2(i, getLedgerSqn, "get_ledger_sqn", hfs, 60);
|
||||
WASM_IMPORT_FUNC2(i, getParentLedgerTime, "get_parent_ledger_time", hfs, 60);
|
||||
WASM_IMPORT_FUNC2(i, getParentLedgerHash, "get_parent_ledger_hash", hfs, 60);
|
||||
WASM_IMPORT_FUNC2(i, getBaseFee, "get_base_fee", hfs, 60);
|
||||
WASM_IMPORT_FUNC2(i, isAmendmentEnabled, "amendment_enabled", hfs, 100);
|
||||
WASM_IMPORT_FUNC2(i, 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_ledger_obj", hfs, 5'000);
|
||||
WASM_IMPORT_FUNC2(i, getTxField, "get_tx_field", hfs, 70);
|
||||
WASM_IMPORT_FUNC2(i, getCurrentLedgerObjField, "get_current_ledger_obj_field", hfs, 70);
|
||||
WASM_IMPORT_FUNC2(i, getLedgerObjField, "get_ledger_obj_field", hfs, 70);
|
||||
WASM_IMPORT_FUNC2(i, getTxNestedField, "get_tx_nested_field", hfs, 110);
|
||||
WASM_IMPORT_FUNC2(i, getCurrentLedgerObjNestedField, "get_current_ledger_obj_nested_field", hfs, 110);
|
||||
WASM_IMPORT_FUNC2(i, getLedgerObjNestedField, "get_ledger_obj_nested_field", hfs, 110);
|
||||
WASM_IMPORT_FUNC2(i, getTxArrayLen, "get_tx_array_len", hfs, 40);
|
||||
WASM_IMPORT_FUNC2(i, getCurrentLedgerObjArrayLen, "get_current_ledger_obj_array_len", hfs, 40);
|
||||
WASM_IMPORT_FUNC2(i, getLedgerObjArrayLen, "get_ledger_obj_array_len", hfs, 40);
|
||||
WASM_IMPORT_FUNC2(i, getTxNestedArrayLen, "get_tx_nested_array_len", hfs, 70);
|
||||
WASM_IMPORT_FUNC2(i, getCurrentLedgerObjNestedArrayLen, "get_current_ledger_obj_nested_array_len", hfs, 70);
|
||||
WASM_IMPORT_FUNC2(i, getLedgerObjNestedArrayLen, "get_ledger_obj_nested_array_len", hfs, 70);
|
||||
WASM_IMPORT_FUNC2(i, 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, "compute_sha512_half", hfs, 2000);
|
||||
WASM_IMPORT_FUNC2(i, checkSignature, "check_sig", hfs, 300);
|
||||
WASM_IMPORT_FUNC2(i, computeSha512HalfHash, "sha512_half", hfs, 2000);
|
||||
|
||||
WASM_IMPORT_FUNC2(i, accountKeylet, "account_keylet", hfs, 350);
|
||||
WASM_IMPORT_FUNC2(i, ammKeylet, "amm_keylet", hfs, 450);
|
||||
WASM_IMPORT_FUNC2(i, checkKeylet, "check_keylet", hfs, 350);
|
||||
WASM_IMPORT_FUNC2(i, credentialKeylet, "credential_keylet", hfs, 350);
|
||||
WASM_IMPORT_FUNC2(i, delegateKeylet, "delegate_keylet", hfs, 350);
|
||||
WASM_IMPORT_FUNC2(i, depositPreauthKeylet, "deposit_preauth_keylet", hfs, 350);
|
||||
WASM_IMPORT_FUNC2(i, didKeylet, "did_keylet", hfs, 350);
|
||||
WASM_IMPORT_FUNC2(i, escrowKeylet, "escrow_keylet", hfs, 350);
|
||||
WASM_IMPORT_FUNC2(i, lineKeylet, "line_keylet", hfs, 400);
|
||||
WASM_IMPORT_FUNC2(i, mptIssuanceKeylet, "mpt_issuance_keylet", hfs, 350);
|
||||
WASM_IMPORT_FUNC2(i, mptokenKeylet, "mptoken_keylet", hfs, 500);
|
||||
WASM_IMPORT_FUNC2(i, nftOfferKeylet, "nft_offer_keylet", hfs, 350);
|
||||
WASM_IMPORT_FUNC2(i, offerKeylet, "offer_keylet", hfs, 350);
|
||||
WASM_IMPORT_FUNC2(i, oracleKeylet, "oracle_keylet", hfs, 350);
|
||||
WASM_IMPORT_FUNC2(i, paychanKeylet, "paychan_keylet", hfs, 350);
|
||||
WASM_IMPORT_FUNC2(i, permissionedDomainKeylet, "permissioned_domain_keylet", hfs, 350);
|
||||
WASM_IMPORT_FUNC2(i, signersKeylet, "signers_keylet", hfs, 350);
|
||||
WASM_IMPORT_FUNC2(i, ticketKeylet, "ticket_keylet", hfs, 350);
|
||||
WASM_IMPORT_FUNC2(i, vaultKeylet, "vault_keylet", hfs, 350);
|
||||
WASM_IMPORT_FUNC2(i, 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, "get_nft", hfs, 5'000);
|
||||
WASM_IMPORT_FUNC2(i, getNFTIssuer, "get_nft_issuer", hfs, 70);
|
||||
WASM_IMPORT_FUNC2(i, getNFTTaxon, "get_nft_taxon", hfs, 60);
|
||||
WASM_IMPORT_FUNC2(i, getNFTFlags, "get_nft_flags", hfs, 60);
|
||||
WASM_IMPORT_FUNC2(i, getNFTTransferFee, "get_nft_transfer_fee", hfs, 60);
|
||||
WASM_IMPORT_FUNC2(i, getNFTSerial, "get_nft_serial", hfs, 60);
|
||||
WASM_IMPORT_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_account", hfs, 500);
|
||||
WASM_IMPORT_FUNC2(i, traceFloat, "trace_opaque_float", hfs, 500);
|
||||
WASM_IMPORT_FUNC2(i, traceAmount, "trace_amount", hfs, 500);
|
||||
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_compare", hfs, 80);
|
||||
WASM_IMPORT_FUNC2(i, floatAdd, "float_add", hfs, 160);
|
||||
WASM_IMPORT_FUNC2(i, floatSubtract, "float_subtract", hfs, 160);
|
||||
WASM_IMPORT_FUNC2(i, floatMultiply, "float_multiply", hfs, 300);
|
||||
WASM_IMPORT_FUNC2(i, floatDivide, "float_divide", hfs, 300);
|
||||
WASM_IMPORT_FUNC2(i, floatRoot, "float_root", hfs, 5'500);
|
||||
WASM_IMPORT_FUNC2(i, floatPower, "float_pow", hfs, 5'500);
|
||||
WASM_IMPORT_FUNC2(i, 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
|
||||
}
|
||||
|
||||
@@ -110,12 +110,12 @@ createWasmImport(HostFunctions& hfs)
|
||||
ImportVec i;
|
||||
|
||||
setCommonHostFunctions(hfs, i);
|
||||
WASM_IMPORT_FUNC2(i, updateData, "update_data", hfs, 1000);
|
||||
WASM_IMPORT_FUNC2(i, updateData, "set_data", hfs, 1000);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
Expected<EscrowResult, TER>
|
||||
Expected<EscrowResult, WasmTER>
|
||||
runEscrowWasm(
|
||||
Bytes const& wasmCode,
|
||||
HostFunctions& hfs,
|
||||
@@ -133,9 +133,12 @@ runEscrowWasm(
|
||||
if (!ret)
|
||||
{
|
||||
#ifdef DEBUG_OUTPUT
|
||||
std::cout << ", error: " << ret.error() << std::endl;
|
||||
std::cout << ", error: " << ret.error().ter << std::endl;
|
||||
#endif
|
||||
return Unexpected<TER>(ret.error());
|
||||
// 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
|
||||
@@ -174,7 +177,7 @@ WasmEngine::instance()
|
||||
return e;
|
||||
}
|
||||
|
||||
Expected<WasmResult<int32_t>, TER>
|
||||
Expected<WasmResult<int32_t>, WasmTER>
|
||||
WasmEngine::run(
|
||||
Bytes const& wasmCode,
|
||||
HostFunctions& hfs,
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
@@ -78,6 +79,26 @@ printWasmError(std::string_view msg, wasm_trap_t* trap, beast::Journal jlog)
|
||||
}
|
||||
// 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
|
||||
@@ -106,6 +127,18 @@ public:
|
||||
{
|
||||
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
|
||||
@@ -247,6 +280,32 @@ InstanceWrapper::setGas(std::int64_t gas) const
|
||||
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
|
||||
@@ -641,7 +700,24 @@ WasmiEngine::call(FuncInfo const& f, std::vector<wasm_val_t>& in)
|
||||
|
||||
if (trap)
|
||||
{
|
||||
ret.f = true;
|
||||
// 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_);
|
||||
}
|
||||
|
||||
@@ -681,7 +757,7 @@ checkImports(ImportVec const& imports, HostFunctions* hfs)
|
||||
}
|
||||
}
|
||||
|
||||
Expected<WasmResult<int32_t>, TER>
|
||||
Expected<WasmResult<int32_t>, WasmTER>
|
||||
WasmiEngine::run(
|
||||
Bytes const& wasmCode,
|
||||
HostFunctions& hfs,
|
||||
@@ -692,7 +768,7 @@ WasmiEngine::run(
|
||||
beast::Journal j)
|
||||
{
|
||||
if (gas <= 0)
|
||||
return Unexpected<TER>(temBAD_AMOUNT);
|
||||
return Unexpected(WasmTER{.ter = temBAD_AMOUNT, .cost = std::nullopt});
|
||||
|
||||
try
|
||||
{
|
||||
@@ -709,10 +785,12 @@ WasmiEngine::run(
|
||||
printWasmError(std::string("exception: unknown"), nullptr, j);
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
return Unexpected<TER>(tecFAILED_PROCESSING);
|
||||
// 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>, TER>
|
||||
Expected<WasmResult<int32_t>, WasmTER>
|
||||
WasmiEngine::runHlp(
|
||||
Bytes const& wasmCode,
|
||||
HostFunctions& hfs,
|
||||
@@ -755,8 +833,24 @@ WasmiEngine::runHlp(
|
||||
|
||||
auto const res = call<1>(f, p);
|
||||
|
||||
if (res.f)
|
||||
Throw<std::runtime_error>("<" + std::string(funcName) + "> failure");
|
||||
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())
|
||||
{
|
||||
@@ -771,8 +865,6 @@ WasmiEngine::runHlp(
|
||||
"> return type mismatch, ret: " + std::to_string(static_cast<int>(res.r[0].kind)));
|
||||
}
|
||||
|
||||
if (gas == -1)
|
||||
gas = std::numeric_limits<decltype(gas)>::max();
|
||||
WasmResult<int32_t> const ret{.result = res.r[0].of.i32, .cost = gas - moduleWrap_->getGas()};
|
||||
|
||||
// #ifdef DEBUG_OUTPUT
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -135,7 +135,7 @@ public:
|
||||
return Bytes{s.begin(), s.end()};
|
||||
}
|
||||
|
||||
return Unexpected(HostFunctionError::Internal);
|
||||
return Unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
Expected<Bytes, HostFunctionError>
|
||||
|
||||
@@ -53,13 +53,13 @@ struct Wasm_test : public beast::unit_test::Suite
|
||||
{
|
||||
void
|
||||
checkResult(
|
||||
Expected<WasmResult<int32_t>, TER> re,
|
||||
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()) + lineStr))
|
||||
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);
|
||||
@@ -179,7 +179,7 @@ struct Wasm_test : public beast::unit_test::Suite
|
||||
Env env{*this};
|
||||
TestLedgerDataProvider hfs(env);
|
||||
ImportVec imports;
|
||||
WASM_IMPORT_FUNC2(imports, getLedgerSqn, "get_ledger_sqn", hfs, 33);
|
||||
WASM_IMPORT_FUNC2(imports, getLedgerSqn, "ldgr_index", hfs, 33);
|
||||
auto& engine = WasmEngine::instance();
|
||||
|
||||
auto re =
|
||||
@@ -217,7 +217,7 @@ struct Wasm_test : public beast::unit_test::Suite
|
||||
auto re = engine.run(
|
||||
allHostFuncWasm, hfs, 1'000'000, escrowFunctionName, {}, imp, env.journal);
|
||||
|
||||
checkResult(re, 1, 27'617);
|
||||
checkResult(re, 1, 27'032);
|
||||
|
||||
env.close();
|
||||
}
|
||||
@@ -239,7 +239,7 @@ struct Wasm_test : public beast::unit_test::Suite
|
||||
auto re = engine.run(
|
||||
allHostFuncWasm, hfs, 1'000'000, escrowFunctionName, {}, imp, env.journal);
|
||||
|
||||
checkResult(re, 1, 70'877);
|
||||
checkResult(re, 1, 68'792);
|
||||
|
||||
env.close();
|
||||
}
|
||||
@@ -258,8 +258,10 @@ struct Wasm_test : public beast::unit_test::Suite
|
||||
|
||||
if (BEAST_EXPECT(!re))
|
||||
{
|
||||
// Running out of gas now terminates with tecOUT_OF_GAS (was
|
||||
// previously collapsed into tecFAILED_PROCESSING).
|
||||
BEAST_EXPECTS(
|
||||
re.error() == tecFAILED_PROCESSING, std::to_string(TERtoInt(re.error())));
|
||||
re.error().ter == tecOUT_OF_GAS, std::to_string(TERtoInt(re.error().ter)));
|
||||
}
|
||||
|
||||
env.close();
|
||||
@@ -278,7 +280,7 @@ struct Wasm_test : public beast::unit_test::Suite
|
||||
{
|
||||
TestHostFunctions hfs(env);
|
||||
auto re = runEscrowWasm(allHFWasm, hfs, 100'000, escrowFunctionName, {});
|
||||
checkResult(re, 1, 70'877);
|
||||
checkResult(re, 1, 68'792);
|
||||
}
|
||||
|
||||
{
|
||||
@@ -286,7 +288,7 @@ struct Wasm_test : public beast::unit_test::Suite
|
||||
TestHostFunctions hfs(env);
|
||||
auto re = runEscrowWasm(allHFWasm, hfs, -1, escrowFunctionName, {});
|
||||
BEAST_EXPECT(!re.has_value());
|
||||
BEAST_EXPECT(re.error() == temBAD_AMOUNT);
|
||||
BEAST_EXPECT(re.error().ter == temBAD_AMOUNT);
|
||||
}
|
||||
|
||||
{
|
||||
@@ -294,7 +296,7 @@ struct Wasm_test : public beast::unit_test::Suite
|
||||
TestHostFunctions hfs(env);
|
||||
auto re = runEscrowWasm(allHFWasm, hfs, 0, escrowFunctionName, {});
|
||||
BEAST_EXPECT(!re.has_value());
|
||||
BEAST_EXPECT(re.error() == temBAD_AMOUNT);
|
||||
BEAST_EXPECT(re.error().ter == temBAD_AMOUNT);
|
||||
}
|
||||
|
||||
{
|
||||
@@ -302,7 +304,7 @@ struct Wasm_test : public beast::unit_test::Suite
|
||||
TestHostFunctions hfs(env);
|
||||
auto re = runEscrowWasm(
|
||||
allHFWasm, hfs, std::numeric_limits<int64_t>::max(), escrowFunctionName, {});
|
||||
checkResult(re, 1, 70'877);
|
||||
checkResult(re, 1, 68'792);
|
||||
}
|
||||
|
||||
{ // fail because trying to access nonexistent field
|
||||
@@ -320,7 +322,7 @@ struct Wasm_test : public beast::unit_test::Suite
|
||||
|
||||
FieldNotFoundHostFunctions hfs(env);
|
||||
auto re = runEscrowWasm(allHFWasm, hfs, 100'000, escrowFunctionName, {});
|
||||
checkResult(re, -201, 29'502);
|
||||
checkResult(re, -201, 28'965);
|
||||
}
|
||||
|
||||
{ // fail because trying to allocate more than MAX_PAGES memory
|
||||
@@ -338,7 +340,7 @@ struct Wasm_test : public beast::unit_test::Suite
|
||||
|
||||
OversizedFieldHostFunctions hfs(env);
|
||||
auto re = runEscrowWasm(allHFWasm, hfs, 100'000, escrowFunctionName, {});
|
||||
checkResult(re, -201, 29'502);
|
||||
checkResult(re, -201, 28'965);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -354,7 +356,7 @@ struct Wasm_test : public beast::unit_test::Suite
|
||||
auto const codecovWasm = hexToBytes(kCodecovTestsWasmHex);
|
||||
TestHostFunctions hfs(env);
|
||||
|
||||
auto const allowance = 220'169;
|
||||
auto const allowance = 204'624;
|
||||
auto re = runEscrowWasm(codecovWasm, hfs, allowance, escrowFunctionName, {});
|
||||
|
||||
checkResult(re, 1, allowance);
|
||||
@@ -379,7 +381,7 @@ struct Wasm_test : public beast::unit_test::Suite
|
||||
auto& engine = WasmEngine::instance();
|
||||
|
||||
auto re = engine.run(badAlignWasm, hfs, 1'000'000, "test", {}, imports, env.journal);
|
||||
if (BEAST_EXPECTS(re, transToken(re.error())))
|
||||
if (BEAST_EXPECTS(re, transToken(re.error().ter)))
|
||||
{
|
||||
BEAST_EXPECTS(re->result == 0x47308594, std::to_string(re->result));
|
||||
}
|
||||
|
||||
@@ -44,9 +44,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.6"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||
checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"typenum",
|
||||
@@ -64,9 +64,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.9"
|
||||
version = "0.14.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2"
|
||||
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
"version_check",
|
||||
@@ -74,24 +74,24 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.177"
|
||||
version = "0.2.186"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
|
||||
checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.103"
|
||||
version = "1.0.106"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8"
|
||||
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.41"
|
||||
version = "1.0.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1"
|
||||
checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
@@ -109,9 +109,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.108"
|
||||
version = "2.0.117"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917"
|
||||
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -120,9 +120,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec"
|
||||
version = "1.10.0"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa"
|
||||
checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3"
|
||||
dependencies = [
|
||||
"tinyvec_macros",
|
||||
]
|
||||
@@ -135,15 +135,15 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.19.0"
|
||||
version = "1.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb"
|
||||
checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.22"
|
||||
version = "1.0.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
|
||||
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
@@ -152,9 +152,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
|
||||
[[package]]
|
||||
name = "xrpl-address-macro"
|
||||
version = "0.7.1"
|
||||
source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git?branch=u32-buffer#1e5d096f46742ef7fcf1cb6f28a2526a72ed59d8"
|
||||
name = "xrpl-macros"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git?branch=renames#9822d645870908a79d87a57b0244caa6359cb9cf"
|
||||
dependencies = [
|
||||
"bs58",
|
||||
"quote",
|
||||
@@ -164,8 +164,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "xrpl-wasm-stdlib"
|
||||
version = "0.7.1"
|
||||
source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git?branch=u32-buffer#1e5d096f46742ef7fcf1cb6f28a2526a72ed59d8"
|
||||
version = "0.8.0"
|
||||
source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git?branch=renames#9822d645870908a79d87a57b0244caa6359cb9cf"
|
||||
dependencies = [
|
||||
"xrpl-address-macro",
|
||||
"xrpl-macros",
|
||||
]
|
||||
|
||||
@@ -10,7 +10,7 @@ edition = "2024"
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
xrpl-std = { git = "https://github.com/ripple/xrpl-wasm-stdlib.git", package = "xrpl-wasm-stdlib", branch = "u32-buffer" }
|
||||
xrpl-std = { git = "https://github.com/ripple/xrpl-wasm-stdlib.git", package = "xrpl-wasm-stdlib", branch = "renames" }
|
||||
|
||||
[profile.dev]
|
||||
panic = "abort"
|
||||
|
||||
@@ -98,7 +98,7 @@ fn test_ledger_header_functions() -> i32 {
|
||||
|
||||
// Test 1.1: get_ledger_sqn() - should return current ledger sequence number
|
||||
let mut sqn_buffer = [0u8; 4];
|
||||
let sqn_result = unsafe { host::get_ledger_sqn(sqn_buffer.as_mut_ptr(), sqn_buffer.len()) };
|
||||
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);
|
||||
@@ -110,7 +110,7 @@ fn test_ledger_header_functions() -> i32 {
|
||||
// Test 1.2: get_parent_ledger_time() - should return parent ledger timestamp
|
||||
let mut time_buffer = [0u8; 4];
|
||||
let time_result =
|
||||
unsafe { host::get_parent_ledger_time(time_buffer.as_mut_ptr(), time_buffer.len()) };
|
||||
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);
|
||||
@@ -122,7 +122,7 @@ fn test_ledger_header_functions() -> i32 {
|
||||
// Test 1.3: get_parent_ledger_hash() - should return parent ledger hash (32 bytes)
|
||||
let mut hash_buffer = [0u8; 32];
|
||||
let hash_result =
|
||||
unsafe { host::get_parent_ledger_hash(hash_buffer.as_mut_ptr(), hash_buffer.len()) };
|
||||
unsafe { host::parent_ldgr_hash(hash_buffer.as_mut_ptr(), hash_buffer.len()) };
|
||||
|
||||
if hash_result != 32 {
|
||||
let _ = trace_num(
|
||||
@@ -146,8 +146,8 @@ fn test_transaction_data_functions() -> i32 {
|
||||
// Test with Account field (required, 20 bytes)
|
||||
let mut account_buffer = [0u8; 20];
|
||||
let account_len = unsafe {
|
||||
host::get_tx_field(
|
||||
sfield::Account,
|
||||
host::tx_field(
|
||||
sfield::Account.into(),
|
||||
account_buffer.as_mut_ptr(),
|
||||
account_buffer.len(),
|
||||
)
|
||||
@@ -165,8 +165,13 @@ fn test_transaction_data_functions() -> i32 {
|
||||
// Test with Fee field (XRP amount - 8 bytes in new serialized format)
|
||||
// New format: XRP amounts are always 8 bytes (positive: value | cPositive flag, negative: just value)
|
||||
let mut fee_buffer = [0u8; 8];
|
||||
let fee_len =
|
||||
unsafe { host::get_tx_field(sfield::Fee, fee_buffer.as_mut_ptr(), fee_buffer.len()) };
|
||||
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(
|
||||
@@ -184,8 +189,13 @@ fn test_transaction_data_functions() -> i32 {
|
||||
|
||||
// Test with Sequence field (required, 4 bytes uint32)
|
||||
let mut seq_buffer = [0u8; 4];
|
||||
let seq_len =
|
||||
unsafe { host::get_tx_field(sfield::Sequence, seq_buffer.as_mut_ptr(), seq_buffer.len()) };
|
||||
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(
|
||||
@@ -203,7 +213,7 @@ fn test_transaction_data_functions() -> i32 {
|
||||
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::get_tx_nested_field(
|
||||
host::tx_inner(
|
||||
locator.as_ptr(),
|
||||
locator.len(),
|
||||
nested_buffer.as_mut_ptr(),
|
||||
@@ -227,15 +237,14 @@ fn test_transaction_data_functions() -> i32 {
|
||||
}
|
||||
|
||||
// Test 2.3: get_tx_array_len() - Get array length
|
||||
let signers_len = unsafe { host::get_tx_array_len(sfield::Signers) };
|
||||
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::get_tx_array_len(sfield::Memos) };
|
||||
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::get_tx_nested_array_len(locator.as_ptr(), locator.len()) };
|
||||
let nested_array_len = unsafe { host::tx_inner_arr_len(locator.as_ptr(), locator.len()) };
|
||||
|
||||
if nested_array_len < 0 {
|
||||
let _ = trace_num(
|
||||
@@ -259,8 +268,8 @@ fn test_current_ledger_object_functions() -> i32 {
|
||||
// Test with Balance field (XRP amount - 8 bytes in new serialized format)
|
||||
let mut balance_buffer = [0u8; 8];
|
||||
let balance_result = unsafe {
|
||||
host::get_current_ledger_obj_field(
|
||||
sfield::Balance,
|
||||
host::home_le_field(
|
||||
sfield::Balance.into(),
|
||||
balance_buffer.as_mut_ptr(),
|
||||
balance_buffer.len(),
|
||||
)
|
||||
@@ -297,8 +306,8 @@ fn test_current_ledger_object_functions() -> i32 {
|
||||
// Test with Account field
|
||||
let mut current_account_buffer = [0u8; 20];
|
||||
let current_account_result = unsafe {
|
||||
host::get_current_ledger_obj_field(
|
||||
sfield::Account,
|
||||
host::home_le_field(
|
||||
sfield::Account.into(),
|
||||
current_account_buffer.as_mut_ptr(),
|
||||
current_account_buffer.len(),
|
||||
)
|
||||
@@ -317,7 +326,7 @@ fn test_current_ledger_object_functions() -> i32 {
|
||||
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::get_current_ledger_obj_nested_field(
|
||||
host::home_le_inner(
|
||||
locator.as_ptr(),
|
||||
locator.len(),
|
||||
current_nested_buffer.as_mut_ptr(),
|
||||
@@ -340,7 +349,7 @@ fn test_current_ledger_object_functions() -> i32 {
|
||||
}
|
||||
|
||||
// Test 3.3: get_current_ledger_obj_array_len() - Array length in current object
|
||||
let current_array_len = unsafe { host::get_current_ledger_obj_array_len(sfield::Signers) };
|
||||
let 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,
|
||||
@@ -348,7 +357,7 @@ fn test_current_ledger_object_functions() -> i32 {
|
||||
|
||||
// Test 3.4: get_current_ledger_obj_nested_array_len() - Nested array length
|
||||
let current_nested_array_len =
|
||||
unsafe { host::get_current_ledger_obj_nested_array_len(locator.as_ptr(), locator.len()) };
|
||||
unsafe { host::home_le_inner_arr_len(locator.as_ptr(), locator.len()) };
|
||||
|
||||
if current_nested_array_len < 0 {
|
||||
let _ = trace_num(
|
||||
@@ -379,7 +388,7 @@ fn test_any_ledger_object_functions() -> i32 {
|
||||
// Test 4.1: cache_ledger_obj() - Cache a ledger object
|
||||
let mut keylet_buffer = [0u8; 32];
|
||||
let keylet_result = unsafe {
|
||||
host::account_keylet(
|
||||
host::accountroot_id(
|
||||
account_id.0.as_ptr(),
|
||||
account_id.0.len(),
|
||||
keylet_buffer.as_mut_ptr(),
|
||||
@@ -389,14 +398,13 @@ fn test_any_ledger_object_functions() -> i32 {
|
||||
|
||||
if keylet_result != 32 {
|
||||
let _ = trace_num(
|
||||
"ERROR: account_keylet failed for caching test:",
|
||||
"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_ledger_obj(keylet_buffer.as_ptr(), keylet_result as usize, 0) };
|
||||
let cache_result = unsafe { host::cache_le(keylet_buffer.as_ptr(), keylet_result as usize, 0) };
|
||||
|
||||
if cache_result <= 0 {
|
||||
let _ = trace_num(
|
||||
@@ -411,9 +419,9 @@ fn test_any_ledger_object_functions() -> i32 {
|
||||
|
||||
// Test get_ledger_obj_field with invalid slot
|
||||
let field_result = unsafe {
|
||||
host::get_ledger_obj_field(
|
||||
host::le_field(
|
||||
1,
|
||||
sfield::Balance,
|
||||
sfield::Balance.into(),
|
||||
test_buffer.as_mut_ptr(),
|
||||
test_buffer.len(),
|
||||
)
|
||||
@@ -428,7 +436,7 @@ fn test_any_ledger_object_functions() -> i32 {
|
||||
// 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::get_ledger_obj_nested_field(
|
||||
host::le_inner(
|
||||
1,
|
||||
locator.as_ptr(),
|
||||
locator.len(),
|
||||
@@ -444,7 +452,7 @@ fn test_any_ledger_object_functions() -> i32 {
|
||||
}
|
||||
|
||||
// Test get_ledger_obj_array_len with invalid slot
|
||||
let array_result = unsafe { host::get_ledger_obj_array_len(1, sfield::Signers) };
|
||||
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:",
|
||||
@@ -454,7 +462,7 @@ fn test_any_ledger_object_functions() -> i32 {
|
||||
|
||||
// Test get_ledger_obj_nested_array_len with invalid slot
|
||||
let nested_array_result =
|
||||
unsafe { host::get_ledger_obj_nested_array_len(1, locator.as_ptr(), locator.len()) };
|
||||
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:",
|
||||
@@ -473,9 +481,9 @@ fn test_any_ledger_object_functions() -> i32 {
|
||||
// Test 4.2: get_ledger_obj_field() - Access field from cached object
|
||||
let mut cached_balance_buffer = [0u8; 8];
|
||||
let cached_balance_result = unsafe {
|
||||
host::get_ledger_obj_field(
|
||||
host::le_field(
|
||||
slot,
|
||||
sfield::Balance,
|
||||
sfield::Balance.into(),
|
||||
cached_balance_buffer.as_mut_ptr(),
|
||||
cached_balance_buffer.len(),
|
||||
)
|
||||
@@ -512,7 +520,7 @@ fn test_any_ledger_object_functions() -> i32 {
|
||||
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::get_ledger_obj_nested_field(
|
||||
host::le_inner(
|
||||
slot,
|
||||
locator.as_ptr(),
|
||||
locator.len(),
|
||||
@@ -536,7 +544,7 @@ fn test_any_ledger_object_functions() -> i32 {
|
||||
}
|
||||
|
||||
// Test 4.4: get_ledger_obj_array_len() - Array length from cached object
|
||||
let cached_array_len = unsafe { host::get_ledger_obj_array_len(slot, sfield::Signers) };
|
||||
let 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,
|
||||
@@ -544,7 +552,7 @@ fn test_any_ledger_object_functions() -> i32 {
|
||||
|
||||
// Test 4.5: get_ledger_obj_nested_array_len() - Nested array length from cached object
|
||||
let cached_nested_array_len =
|
||||
unsafe { host::get_ledger_obj_nested_array_len(slot, locator.as_ptr(), locator.len()) };
|
||||
unsafe { host::le_inner_arr_len(slot, locator.as_ptr(), locator.len()) };
|
||||
|
||||
if cached_nested_array_len < 0 {
|
||||
let _ = trace_num(
|
||||
@@ -570,30 +578,30 @@ fn test_keylet_generation_functions() -> i32 {
|
||||
let escrow_finish = EscrowFinish;
|
||||
let account_id = escrow_finish.get_account().unwrap();
|
||||
|
||||
// Test 5.1: account_keylet() - Generate keylet for account
|
||||
let mut account_keylet_buffer = [0u8; 32];
|
||||
let account_keylet_result = unsafe {
|
||||
host::account_keylet(
|
||||
// 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(),
|
||||
account_keylet_buffer.as_mut_ptr(),
|
||||
account_keylet_buffer.len(),
|
||||
accountroot_id_buffer.as_mut_ptr(),
|
||||
accountroot_id_buffer.len(),
|
||||
)
|
||||
};
|
||||
|
||||
if account_keylet_result != 32 {
|
||||
if accountroot_id_result != 32 {
|
||||
let _ = trace_num(
|
||||
"ERROR: account_keylet failed:",
|
||||
account_keylet_result as i64,
|
||||
"ERROR: accountroot_id failed:",
|
||||
accountroot_id_result as i64,
|
||||
);
|
||||
return -501; // Account keylet generation failed
|
||||
}
|
||||
let _ = trace_data("Account keylet:", &account_keylet_buffer, DataRepr::AsHex);
|
||||
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_keylet(
|
||||
host::credential_id(
|
||||
account_id.0.as_ptr(), // Subject
|
||||
account_id.0.len(),
|
||||
account_id.0.as_ptr(), // Issuer - same account for test
|
||||
@@ -624,7 +632,7 @@ fn test_keylet_generation_functions() -> i32 {
|
||||
let sequence_number: i32 = 1000;
|
||||
let sequence_number_bytes = sequence_number.to_be_bytes();
|
||||
let escrow_keylet_result = unsafe {
|
||||
host::escrow_keylet(
|
||||
host::escrow_id(
|
||||
account_id.0.as_ptr(),
|
||||
account_id.0.len(),
|
||||
sequence_number_bytes.as_ptr(),
|
||||
@@ -645,7 +653,7 @@ fn test_keylet_generation_functions() -> i32 {
|
||||
let document_id: i32 = 42;
|
||||
let document_id_bytes = document_id.to_be_bytes();
|
||||
let oracle_keylet_result = unsafe {
|
||||
host::oracle_keylet(
|
||||
host::oracle_id(
|
||||
account_id.0.as_ptr(),
|
||||
account_id.0.len(),
|
||||
document_id_bytes.as_ptr(),
|
||||
@@ -674,7 +682,7 @@ fn test_utility_functions() -> i32 {
|
||||
let test_data = b"Hello, XRPL WASM world!";
|
||||
let mut hash_output = [0u8; 32];
|
||||
let hash_result = unsafe {
|
||||
host::compute_sha512_half(
|
||||
host::sha512_half(
|
||||
test_data.as_ptr(),
|
||||
test_data.len(),
|
||||
hash_output.as_mut_ptr(),
|
||||
@@ -695,7 +703,7 @@ fn test_utility_functions() -> i32 {
|
||||
let nft_id = [0u8; 32]; // Dummy NFT ID for testing
|
||||
let mut nft_buffer = [0u8; 256];
|
||||
let nft_result = unsafe {
|
||||
host::get_nft(
|
||||
host::nft_uri(
|
||||
account_id.0.as_ptr(),
|
||||
account_id.0.len(),
|
||||
nft_id.as_ptr(),
|
||||
@@ -766,7 +774,7 @@ fn test_data_update_functions() -> i32 {
|
||||
// Test 7.1: update_data() - Update current ledger entry data
|
||||
let update_payload = b"Updated ledger entry data from WASM test";
|
||||
|
||||
let update_result = unsafe { host::update_data(update_payload.as_ptr(), update_payload.len()) };
|
||||
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);
|
||||
|
||||
48
src/test/app/wasm_fixtures/all_keylets/Cargo.lock
generated
48
src/test/app/wasm_fixtures/all_keylets/Cargo.lock
generated
@@ -44,9 +44,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.6"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||
checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"typenum",
|
||||
@@ -64,9 +64,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.9"
|
||||
version = "0.14.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2"
|
||||
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
"version_check",
|
||||
@@ -74,24 +74,24 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.177"
|
||||
version = "0.2.186"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
|
||||
checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.103"
|
||||
version = "1.0.106"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8"
|
||||
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.41"
|
||||
version = "1.0.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1"
|
||||
checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
@@ -109,9 +109,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.108"
|
||||
version = "2.0.117"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917"
|
||||
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -120,9 +120,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec"
|
||||
version = "1.10.0"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa"
|
||||
checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3"
|
||||
dependencies = [
|
||||
"tinyvec_macros",
|
||||
]
|
||||
@@ -135,15 +135,15 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.19.0"
|
||||
version = "1.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb"
|
||||
checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.22"
|
||||
version = "1.0.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
|
||||
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
@@ -152,9 +152,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
|
||||
[[package]]
|
||||
name = "xrpl-address-macro"
|
||||
version = "0.7.1"
|
||||
source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git?branch=u32-buffer#1e5d096f46742ef7fcf1cb6f28a2526a72ed59d8"
|
||||
name = "xrpl-macros"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git?branch=renames#21c522f34a24b460297ebb6be1822680459bf37e"
|
||||
dependencies = [
|
||||
"bs58",
|
||||
"quote",
|
||||
@@ -164,8 +164,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "xrpl-wasm-stdlib"
|
||||
version = "0.7.1"
|
||||
source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git?branch=u32-buffer#1e5d096f46742ef7fcf1cb6f28a2526a72ed59d8"
|
||||
version = "0.8.0"
|
||||
source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git?branch=renames#21c522f34a24b460297ebb6be1822680459bf37e"
|
||||
dependencies = [
|
||||
"xrpl-address-macro",
|
||||
"xrpl-macros",
|
||||
]
|
||||
|
||||
@@ -15,7 +15,7 @@ opt-level = 's'
|
||||
panic = "abort"
|
||||
|
||||
[dependencies]
|
||||
xrpl-std = { git = "https://github.com/ripple/xrpl-wasm-stdlib.git", package = "xrpl-wasm-stdlib", branch = "u32-buffer" }
|
||||
xrpl-std = { git = "https://github.com/ripple/xrpl-wasm-stdlib.git", package = "xrpl-wasm-stdlib", branch = "renames" }
|
||||
|
||||
[profile.dev]
|
||||
panic = "abort"
|
||||
|
||||
@@ -4,39 +4,38 @@
|
||||
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::types::account_id::AccountID;
|
||||
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::keylets;
|
||||
use xrpl_std::core::types::mpt_id::MptId;
|
||||
use xrpl_std::core::types::uint::Hash256;
|
||||
use xrpl_std::host;
|
||||
use xrpl_std::host::trace::{trace, trace_account, trace_data, trace_num, DataRepr};
|
||||
use xrpl_std::host::trace::{trace, trace_acct, trace_data, trace_num, DataRepr};
|
||||
use xrpl_std::sfield;
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub fn object_exists(
|
||||
pub fn object_exists<T: LedgerObjectFieldGetter, const CODE: i32>(
|
||||
keylet_result: Result<keylets::KeyletBytes>,
|
||||
keylet_type: &str,
|
||||
field: i32,
|
||||
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_ledger_obj(keylet.as_ptr(), keylet.len(), 0) };
|
||||
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.into());
|
||||
match ledger_object::get_field::<Hash256>(slot, new_field) {
|
||||
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);
|
||||
}
|
||||
@@ -47,9 +46,9 @@ pub fn object_exists(
|
||||
}
|
||||
} else {
|
||||
let _ = trace_num("Getting field: ", field.into());
|
||||
match ledger_object::get_field::<AccountID>(slot, field) {
|
||||
Ok(data) => {
|
||||
let _ = trace_data("Field data: ", &data.0, DataRepr::AsHex);
|
||||
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());
|
||||
@@ -74,10 +73,10 @@ pub extern "C" fn finish() -> i32 {
|
||||
let escrow: CurrentEscrow = get_current_escrow();
|
||||
|
||||
let account = escrow.get_account().unwrap_or_panic();
|
||||
let _ = trace_account("Account:", &account);
|
||||
let _ = trace_acct("Account:", &account);
|
||||
|
||||
let destination = escrow.get_destination().unwrap_or_panic();
|
||||
let _ = trace_account("Destination:", &destination);
|
||||
let _ = trace_acct("Destination:", &destination);
|
||||
|
||||
let mut seq = 5;
|
||||
|
||||
@@ -99,82 +98,78 @@ pub extern "C" fn finish() -> i32 {
|
||||
};
|
||||
}
|
||||
|
||||
let account_keylet = keylets::account_keylet(&account);
|
||||
check_object_exists!(account_keylet, "Account", sfield::Account);
|
||||
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 line_keylet = keylets::line_keylet(&account, &destination, ¤cy);
|
||||
check_object_exists!(line_keylet, "Trustline", sfield::Generic);
|
||||
let trustline_id = keylets::trustline_id(&account, &destination, ¤cy);
|
||||
check_object_exists!(trustline_id, "Trustline", sfield::Generic);
|
||||
seq += 1;
|
||||
|
||||
let asset1 = Issue::XRP(XrpIssue {});
|
||||
let asset2 = Issue::IOU(IouIssue::new(destination, currency));
|
||||
check_object_exists!(
|
||||
keylets::amm_keylet(&asset1, &asset2),
|
||||
"AMM",
|
||||
sfield::Account
|
||||
);
|
||||
check_object_exists!(keylets::amm_id(&asset1, &asset2), "AMM", sfield::Account);
|
||||
|
||||
let check_keylet = keylets::check_keylet(&account, seq);
|
||||
check_object_exists!(check_keylet, "Check", 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_keylet = keylets::credential_keylet(&account, &account, cred_type);
|
||||
check_object_exists!(credential_keylet, "Credential", sfield::Subject);
|
||||
let credential_id = keylets::credential_id(&account, &account, cred_type);
|
||||
check_object_exists!(credential_id, "Credential", sfield::Subject);
|
||||
seq += 1;
|
||||
|
||||
let delegate_keylet = keylets::delegate_keylet(&account, &destination);
|
||||
check_object_exists!(delegate_keylet, "Delegate", sfield::Account);
|
||||
let delegate_id = keylets::delegate_id(&account, &destination);
|
||||
check_object_exists!(delegate_id, "Delegate", sfield::Account);
|
||||
seq += 1;
|
||||
|
||||
let deposit_preauth_keylet = keylets::deposit_preauth_keylet(&account, &destination);
|
||||
check_object_exists!(deposit_preauth_keylet, "DepositPreauth", sfield::Account);
|
||||
let deposit_preauth_id = keylets::deposit_preauth_id(&account, &destination);
|
||||
check_object_exists!(deposit_preauth_id, "DepositPreauth", sfield::Account);
|
||||
seq += 1;
|
||||
|
||||
let did_keylet = keylets::did_keylet(&account);
|
||||
check_object_exists!(did_keylet, "DID", sfield::Account);
|
||||
let did_id = keylets::did_id(&account);
|
||||
check_object_exists!(did_id, "DID", sfield::Account);
|
||||
seq += 1;
|
||||
|
||||
let escrow_keylet = keylets::escrow_keylet(&account, seq);
|
||||
check_object_exists!(escrow_keylet, "Escrow", sfield::Account);
|
||||
let escrow_id = keylets::escrow_id(&account, seq);
|
||||
check_object_exists!(escrow_id, "Escrow", sfield::Account);
|
||||
seq += 1;
|
||||
|
||||
let mpt_issuance_keylet = keylets::mpt_issuance_keylet(&account, seq);
|
||||
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_keylet, "MPTIssuance", sfield::Issuer);
|
||||
check_object_exists!(mpt_issuance_id, "MPTIssuance", sfield::Issuer);
|
||||
seq += 1;
|
||||
|
||||
let mptoken_keylet = keylets::mptoken_keylet(&mpt_id, &destination);
|
||||
check_object_exists!(mptoken_keylet, "MPToken", sfield::Account);
|
||||
let mptoken_id = keylets::mptoken_id(&mpt_id, &destination);
|
||||
check_object_exists!(mptoken_id, "MPToken", sfield::Account);
|
||||
|
||||
let nft_offer_keylet = keylets::nft_offer_keylet(&destination, 6);
|
||||
check_object_exists!(nft_offer_keylet, "NFTokenOffer", sfield::Owner);
|
||||
let nft_offer_id = keylets::nft_offer_id(&destination, 6);
|
||||
check_object_exists!(nft_offer_id, "NFTokenOffer", sfield::Owner);
|
||||
|
||||
let offer_keylet = keylets::offer_keylet(&account, seq);
|
||||
check_object_exists!(offer_keylet, "Offer", sfield::Account);
|
||||
let offer_id = keylets::offer_id(&account, seq);
|
||||
check_object_exists!(offer_id, "Offer", sfield::Account);
|
||||
seq += 1;
|
||||
|
||||
let paychan_keylet = keylets::paychan_keylet(&account, &destination, seq);
|
||||
check_object_exists!(paychan_keylet, "PayChannel", sfield::Account);
|
||||
let paychan_id = keylets::paychan_id(&account, &destination, seq);
|
||||
check_object_exists!(paychan_id, "PayChannel", sfield::Account);
|
||||
seq += 1;
|
||||
|
||||
let pd_keylet = keylets::permissioned_domain_keylet(&account, seq);
|
||||
check_object_exists!(pd_keylet, "PermissionedDomain", sfield::Owner);
|
||||
let pd_id = keylets::permissioned_domain_id(&account, seq);
|
||||
check_object_exists!(pd_id, "PermissionedDomain", sfield::Owner);
|
||||
seq += 1;
|
||||
|
||||
let signers_keylet = keylets::signers_keylet(&account);
|
||||
check_object_exists!(signers_keylet, "SignerList", sfield::Generic);
|
||||
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_keylet = keylets::ticket_keylet(&account, seq);
|
||||
check_object_exists!(ticket_keylet, "Ticket", sfield::Account);
|
||||
let ticket_id = keylets::ticket_id(&account, seq);
|
||||
check_object_exists!(ticket_id, "Ticket", sfield::Account);
|
||||
seq += 1;
|
||||
|
||||
let vault_keylet = keylets::vault_keylet(&account, seq);
|
||||
check_object_exists!(vault_keylet, "Vault", sfield::Account);
|
||||
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.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#include <stdint.h>
|
||||
|
||||
int32_t float_from_uint(uint8_t const *, int32_t, uint8_t *, int32_t, int32_t);
|
||||
int32_t check_keylet(uint8_t const *, int32_t, uint8_t const *, int32_t,
|
||||
uint8_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];
|
||||
@@ -31,10 +31,9 @@ int32_t test2()
|
||||
// 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_keylet with misaligned uint32 at &e_data2[1] to hit line 72 in
|
||||
// Call check_id with misaligned uint32 at &e_data2[1] to hit line 72 in
|
||||
// HostFuncWrapper.cpp
|
||||
int32_t result =
|
||||
check_keylet(&e_data2[10], 20, &e_data2[1], 4, &e_data2[35], 32);
|
||||
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;
|
||||
|
||||
48
src/test/app/wasm_fixtures/codecov_tests/Cargo.lock
generated
48
src/test/app/wasm_fixtures/codecov_tests/Cargo.lock
generated
@@ -44,9 +44,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.6"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||
checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"typenum",
|
||||
@@ -64,9 +64,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.9"
|
||||
version = "0.14.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2"
|
||||
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
"version_check",
|
||||
@@ -74,24 +74,24 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.177"
|
||||
version = "0.2.186"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
|
||||
checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.103"
|
||||
version = "1.0.106"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8"
|
||||
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.41"
|
||||
version = "1.0.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1"
|
||||
checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
@@ -109,9 +109,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.108"
|
||||
version = "2.0.117"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917"
|
||||
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -120,9 +120,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec"
|
||||
version = "1.10.0"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa"
|
||||
checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3"
|
||||
dependencies = [
|
||||
"tinyvec_macros",
|
||||
]
|
||||
@@ -135,15 +135,15 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.19.0"
|
||||
version = "1.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb"
|
||||
checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.22"
|
||||
version = "1.0.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
|
||||
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
@@ -152,9 +152,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
|
||||
[[package]]
|
||||
name = "xrpl-address-macro"
|
||||
version = "0.7.1"
|
||||
source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git?branch=u32-buffer#1e5d096f46742ef7fcf1cb6f28a2526a72ed59d8"
|
||||
name = "xrpl-macros"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git?branch=renames#9822d645870908a79d87a57b0244caa6359cb9cf"
|
||||
dependencies = [
|
||||
"bs58",
|
||||
"quote",
|
||||
@@ -164,8 +164,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "xrpl-wasm-stdlib"
|
||||
version = "0.7.1"
|
||||
source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git?branch=u32-buffer#1e5d096f46742ef7fcf1cb6f28a2526a72ed59d8"
|
||||
version = "0.8.0"
|
||||
source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git?branch=renames#9822d645870908a79d87a57b0244caa6359cb9cf"
|
||||
dependencies = [
|
||||
"xrpl-address-macro",
|
||||
"xrpl-macros",
|
||||
]
|
||||
|
||||
@@ -15,4 +15,4 @@ opt-level = 's'
|
||||
panic = "abort"
|
||||
|
||||
[dependencies]
|
||||
xrpl-std = { git = "https://github.com/ripple/xrpl-wasm-stdlib.git", package = "xrpl-wasm-stdlib", branch = "u32-buffer" }
|
||||
xrpl-std = { git = "https://github.com/ripple/xrpl-wasm-stdlib.git", package = "xrpl-wasm-stdlib", branch = "renames" }
|
||||
|
||||
@@ -19,20 +19,20 @@ pub const FLOAT_ROUNDING_MODES_UPWARD: i32 = 3;
|
||||
#[allow(unused)]
|
||||
#[link(wasm_import_module = "host_lib")]
|
||||
unsafe extern "C" {
|
||||
pub fn get_parent_ledger_hash(out_buff_ptr: i32, out_buff_len: i32) -> i32;
|
||||
pub fn parent_ldgr_hash(out_buff_ptr: i32, out_buff_len: i32) -> i32;
|
||||
|
||||
pub fn cache_ledger_obj(keylet_ptr: i32, keylet_len: i32, cache_num: i32) -> i32;
|
||||
pub fn cache_le(keylet_ptr: i32, keylet_len: i32, cache_num: i32) -> i32;
|
||||
|
||||
pub fn get_tx_nested_array_len(locator_ptr: i32, locator_len: i32) -> i32;
|
||||
pub fn tx_inner_arr_len(locator_ptr: i32, locator_len: i32) -> i32;
|
||||
|
||||
pub fn account_keylet(
|
||||
pub fn accountroot_id(
|
||||
account_ptr: i32,
|
||||
account_len: i32,
|
||||
out_buff_ptr: *mut u8,
|
||||
out_buff_len: usize,
|
||||
) -> i32;
|
||||
|
||||
pub fn line_keylet(
|
||||
pub fn trustline_id(
|
||||
account1_ptr: *const u8,
|
||||
account1_len: usize,
|
||||
account2_ptr: *const u8,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,20 +1,87 @@
|
||||
# cspell: disable
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
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 update_fixture(project_name, wasm):
|
||||
fixture_name = (
|
||||
re.sub(r"_([a-z])", lambda m: m.group(1).upper(), project_name) + "WasmHex"
|
||||
)
|
||||
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 = os.path.abspath(os.path.join(os.path.dirname(__file__), "fixtures.cpp"))
|
||||
h_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "fixtures.h"))
|
||||
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()
|
||||
|
||||
@@ -30,7 +97,7 @@ def update_fixture(project_name, wasm):
|
||||
with open(h_path, "r", encoding="utf8") as f:
|
||||
h_content = f.read()
|
||||
updated_h_content = (
|
||||
h_content.rstrip() + f"\n\n extern std::string const {fixture_name};\n"
|
||||
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)
|
||||
@@ -43,83 +110,178 @@ def update_fixture(project_name, wasm):
|
||||
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.abspath(
|
||||
os.path.join(os.path.dirname(__file__), project_name)
|
||||
)
|
||||
wasm_location = f"target/wasm32v1-none/release/{project_name}.wasm"
|
||||
build_cmd = (
|
||||
f"(cd {project_path} "
|
||||
f"&& cargo build --target wasm32v1-none --release "
|
||||
f"&& wasm-opt {wasm_location} {OPT} -o {wasm_location}"
|
||||
")"
|
||||
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(build_cmd, shell=True, check=True)
|
||||
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)
|
||||
|
||||
src_path = os.path.abspath(
|
||||
os.path.join(
|
||||
os.path.dirname(__file__),
|
||||
f"{project_name}/target/wasm32v1-none/release/{project_name}.wasm",
|
||||
)
|
||||
)
|
||||
with open(src_path, "rb") as f:
|
||||
data = f.read()
|
||||
wasm = data.hex()
|
||||
update_fixture(project_name, wasm)
|
||||
update_fixture(project_name, read_wasm_hex(wasm_location))
|
||||
|
||||
|
||||
def process_c(project_name):
|
||||
project_path = os.path.abspath(
|
||||
os.path.join(os.path.dirname(__file__), f"{project_name}.c")
|
||||
)
|
||||
wasm_path = os.path.abspath(
|
||||
os.path.join(os.path.dirname(__file__), f"{project_name}.wasm")
|
||||
)
|
||||
build_cmd = (
|
||||
f"$CC --sysroot=$SYSROOT "
|
||||
f"-O3 -ffast-math --target=wasm32 -fno-exceptions -fno-threadsafe-statics -fvisibility=default -Wl,--export-all -Wl,--no-entry -Wl,--allow-undefined -DNDEBUG --no-standard-libraries -fno-builtin-memset "
|
||||
f"-o {wasm_path} {project_path}"
|
||||
f"&& wasm-opt {wasm_path} {OPT} -o {wasm_path}"
|
||||
)
|
||||
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, shell=True, check=True)
|
||||
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)
|
||||
|
||||
with open(wasm_path, "rb") as f:
|
||||
data = f.read()
|
||||
wasm = data.hex()
|
||||
update_fixture(project_name, wasm)
|
||||
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:
|
||||
if os.path.isdir(os.path.join(os.path.dirname(__file__), sys.argv[1])):
|
||||
process_rust(sys.argv[1])
|
||||
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_c(sys.argv[1])
|
||||
process_wat(project_name)
|
||||
print("Fixture has been processed.")
|
||||
else:
|
||||
dirs = [
|
||||
d
|
||||
for d in os.listdir(os.path.dirname(__file__))
|
||||
if os.path.isdir(os.path.join(os.path.dirname(__file__), d))
|
||||
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(os.path.dirname(__file__)) if f.endswith(".c")]
|
||||
for d in dirs:
|
||||
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 c_files:
|
||||
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.")
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,11 +1,11 @@
|
||||
#include <stdint.h>
|
||||
|
||||
int32_t get_ledger_sqn(uint8_t *, int32_t);
|
||||
int32_t ldgr_index(uint8_t *, int32_t);
|
||||
|
||||
int finish()
|
||||
{
|
||||
uint32_t sqn;
|
||||
int32_t result = get_ledger_sqn((uint8_t *)&sqn, sizeof(sqn));
|
||||
int32_t result = ldgr_index((uint8_t *)&sqn, sizeof(sqn));
|
||||
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
||||
Reference in New Issue
Block a user