fix: Port WASM host function tests to new WASM design

This commit is contained in:
TimothyBanks
2026-08-17 14:24:34 -04:00
parent e863db5061
commit c5524e4881
66 changed files with 2713 additions and 6006 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,56 @@
#pragma once
#include <xrpl/basics/Slice.h>
#include <xrpl/tx/wasm/WasmCommon.h>
#include <tx/wasm/RealHostFixture.h>
#include <cstdint>
#include <limits>
#include <string>
namespace xrpl::test {
// Known float bit patterns (12-byte `wasm_float` regions) — inputs / expected values for
// the float host functions. `kNormalExp` is the exponent offset the encoding uses.
namespace floats {
inline constexpr int kNormalExp = 18;
// clang-format off
inline Bytes const kIntMin = {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00}; // -2^63 (rounds to -(2^63-1))
inline Bytes const kIntZero = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00}; // 0
inline Bytes const kIntMax = {0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00}; // 2^63-1
inline Bytes const kUintMax = {0x19, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9A, 0x00, 0x00, 0x00, 0x01}; // 2^64-1
inline Bytes const kMaxExp = {0x0D, 0xE0, 0xB6, 0xB3, 0xA7, 0x64, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00}; // 1e(kMaxExponent + kNormalExp)
inline Bytes const kPreMaxExp = {0x0D, 0xE0, 0xB6, 0xB3, 0xA7, 0x64, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF}; // 1e(kMaxExponent + kNormalExp - 1)
inline Bytes const kMinusMaxExp = {0xF2, 0x1F, 0x49, 0x4C, 0x58, 0x9C, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00}; // -1e(kMaxExponent + kNormalExp)
inline Bytes const kMinExp = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00}; // 1e(kMinExponent - kNormalExp)
inline Bytes const kMax = {0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x80, 0x00}; // kMaxRep e(kMaxExponent - kNormalExp)
inline Bytes const kMaxIOU = {0x0D, 0xE0, 0xB6, 0xB3, 0xA7, 0x63, 0xFF, 0x9C, 0x00, 0x00, 0x00, 0x4E}; // 9999999999999999e(96)
inline Bytes const kMinIOU = {0x0D, 0xE0, 0xB6, 0xB3, 0xA7, 0x64, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x9D}; // 1e(-81)
inline Bytes const kOne = {0x0D, 0xE0, 0xB6, 0xB3, 0xA7, 0x64, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xEE}; // 1
inline Bytes const kMinusOne = {0xF2, 0x1F, 0x49, 0x4C, 0x58, 0x9C, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xEE}; // -1
inline Bytes const kOneMore = {0x0D, 0xE0, 0xB6, 0xB3, 0xA7, 0x64, 0x03, 0xE8, 0xFF, 0xFF, 0xFF, 0xEE}; // 1.000000000000001
inline Bytes const kTwo = {0x1B, 0xC1, 0x6D, 0x67, 0x4E, 0xC8, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xEE}; // 2
inline Bytes const kTen = {0x0D, 0xE0, 0xB6, 0xB3, 0xA7, 0x64, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xEF}; // 10
inline Bytes const kPi = {0x2B, 0x99, 0x2D, 0xDF, 0xA2, 0x32, 0x48, 0xE8, 0xFF, 0xFF, 0xFF, 0xEE}; // 3.141592653589793
inline Bytes const kInvalidZero = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00}; // non-canonical zero
inline Bytes const kMinusThree = {0xD6, 0x5D, 0xDB, 0xE5, 0x09, 0xD4, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xEE}; // -3
// clang-format on
inline std::string const kInvalidData = "invalid_data";
} // namespace floats
struct FloatTest : WasmImplTest
{
static constexpr std::int64_t kMin64 = std::numeric_limits<std::int64_t>::min();
static constexpr std::int64_t kMax64 = std::numeric_limits<std::int64_t>::max();
static Slice
slice(Bytes const& b)
{
return Slice{b.data(), b.size()};
}
};
} // namespace xrpl::test

View File

@@ -0,0 +1,69 @@
#pragma once
#include <xrpl/basics/Slice.h>
#include <xrpl/basics/base_uint.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/Keylet.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/STArray.h>
#include <xrpl/protocol/TER.h>
#include <xrpl/protocol/nft.h>
#include <xrpl/protocol_autogen/transactions/NFTokenMint.h>
#include <xrpl/tx/transactors/nft/NFTokenMint.h>
#include <gtest/gtest.h>
#include <helpers/Account.h>
#include <helpers/TxTest.h>
#include <tx/wasm/RealHostFixture.h>
#include <cstdint>
#include <optional>
#include <string_view>
namespace xrpl::test {
struct NFTTest : WasmImplTest
{
static constexpr std::uint16_t kFlags = nft::kFlagTransferable | nft::kFlagBurnable;
static constexpr std::uint16_t kFee = 314;
static constexpr std::uint32_t kTaxon = 12345;
static constexpr std::uint32_t kSequence = 7;
static uint256
makeNftId(AccountID const& issuer)
{
return NFTokenMint::createNFTokenID(kFlags, kFee, issuer, nft::toTaxon(kTaxon), kSequence);
}
// Mint a real NFToken owned by `issuer` (taxon 0) and return its id, read back from the
// owner's NFTokenPage. TxTest applies to the open ledger, which produces no metadata, so
// the id is recovered from ledger state rather than from the mint's metadata.
uint256
mintNFT(Account const& issuer, std::optional<std::string_view> uri = std::nullopt)
{
auto builder = transactions::NFTokenMintBuilder{issuer.id(), 0u};
if (uri)
builder.setURI(Slice{uri->data(), uri->size()});
auto const r = ledger.submit(builder, issuer);
EXPECT_EQ(r.ter, tesSUCCESS) << transToken(r.ter);
ledger.close();
// The single minted token lives in the owner's first NFTokenPage.
auto const& view = ledger.getOpenLedger();
auto const first = keylet::nftokenPageMin(issuer.id()).key;
auto const last = keylet::nftokenPageMax(issuer.id()).key;
auto const pageKey = view.succ(first, last.next());
EXPECT_TRUE(pageKey.has_value());
auto const page = pageKey ? view.read(Keylet{ltNFTOKEN_PAGE, *pageKey}) : nullptr;
EXPECT_NE(page, nullptr);
if (!page)
return uint256{};
auto const& tokens = page->getFieldArray(sfNFTokens);
EXPECT_FALSE(tokens.empty());
return tokens.empty() ? uint256{} : tokens[0].getFieldH256(sfNFTokenID);
}
};
} // namespace xrpl::test

View File

@@ -1,85 +1,108 @@
#pragma once
// Base for the "impl" wasm tests: a *real* `WasmHostFunctionsImpl` over a *real* ledger,
// built with no Application / jtx / beast::unit_test::Suite. The ledger is a `TxTest`
// (genesis ledger + OpenView + real transactor dispatch); the host is constructed from
// its `ServiceRegistry` and `OpenView` through an `ApplyContext`.
//
// This is the counterpart to `HostContextFixture` (mock host, interop): here the host
// really computes, so a test asserts a value against the ledger's own source of truth
// (`keylet::escrow`, a real field's bytes, `wasm_float`), rather than what a mock was
// asked. Pure-computation host functions (keylets, floats, check_sig, sha512_half, nft
// decoders) ignore the ledger; the reading getters read the object `leKey` points at.
#include <xrpl/basics/Slice.h>
#include <xrpl/basics/base_uint.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h> // TapNone
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Asset.h>
#include <xrpl/protocol/Fees.h>
#include <xrpl/protocol/Indexes.h> // keylet::account
#include <xrpl/protocol/Issue.h>
#include <xrpl/protocol/KeyType.h>
#include <xrpl/protocol/Keylet.h>
#include <xrpl/protocol/MPTIssue.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/STAmount.h>
#include <xrpl/protocol/STArray.h>
#include <xrpl/protocol/STNumber.h>
#include <xrpl/protocol/STObject.h>
#include <xrpl/protocol/STTx.h>
#include <xrpl/protocol/SecretKey.h>
#include <xrpl/protocol/Serializer.h>
#include <xrpl/protocol/TER.h>
#include <xrpl/protocol/TxFormats.h>
#include <xrpl/protocol/UintTypes.h>
#include <xrpl/protocol/XRPAmount.h>
#include <xrpl/protocol_autogen/transactions/SignerListSet.h>
#include <xrpl/tx/ApplyContext.h>
#include <xrpl/tx/wasm/HostFuncImpl.h>
#include <xrpl/tx/wasm/WasmCommon.h>
#include <gtest/gtest.h>
#include <helpers/Account.h>
#include <helpers/CaptureSink.h>
#include <helpers/TxTest.h>
#include <cstdint>
#include <expected>
#include <functional>
#include <memory>
#include <optional>
#include <span>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
namespace xrpl::test {
static Bytes
inline Bytes
toBytes(std::uint8_t value)
{
return {value};
}
static Bytes
inline Bytes
toBytes(std::uint16_t value)
{
auto const* b = reinterpret_cast<uint8_t const*>(&value);
auto const* e = reinterpret_cast<uint8_t const*>(&value + 1);
return Bytes{b, e};
return {static_cast<std::uint8_t>(value), static_cast<std::uint8_t>(value >> 8)};
}
static Bytes
inline Bytes
toBytes(std::uint32_t value)
{
auto const* b = reinterpret_cast<uint8_t const*>(&value);
auto const* e = reinterpret_cast<uint8_t const*>(&value + 1);
return Bytes{b, e};
return {
static_cast<std::uint8_t>(value),
static_cast<std::uint8_t>(value >> 8),
static_cast<std::uint8_t>(value >> 16),
static_cast<std::uint8_t>(value >> 24)};
}
static Bytes
inline Bytes
toBytes(uint256 const& value)
{
return Bytes{value.begin(), value.end()};
return Bytes{std::begin(value), std::end(value)};
}
static Bytes
inline Bytes
toBytes(std::string_view value)
{
return Bytes{std::begin(value), std::end(value)};
}
inline Bytes
toBytes(std::span<std::uint8_t const> value)
{
return Bytes{std::begin(value), std::end(value)};
}
inline Bytes
toBytes(AccountID const& account)
{
return Bytes{std::begin(account), std::end(account)};
}
inline Bytes
toBytes(Issue const& issue)
{
Serializer s;
auto s = Serializer{};
s.addBitString(issue.currency);
if (!isXRP(issue.currency))
s.addBitString(issue.account);
auto const data = s.getData();
return data;
return s.getData();
}
static Bytes
inline Bytes
toBytes(Asset const& asset)
{
if (asset.holds<Issue>())
@@ -90,61 +113,247 @@ toBytes(Asset const& asset)
return Bytes{mptID.cbegin(), mptID.cend()};
}
static Bytes
inline Bytes
toBytes(STAmount const& amount)
{
Serializer msg;
auto msg = Serializer{};
amount.add(msg);
auto const data = msg.getData();
return data;
return msg.getData();
}
static Bytes
inline Bytes
toBytes(STNumber const& number)
{
Serializer msg;
auto msg = Serializer{};
number.add(msg);
auto const data = msg.getData();
return data;
return msg.getData();
}
class WasmImplTest : public testing::Test
template <typename T, typename U>
void
expectValue(std::expected<T, HostFunctionError> const& result, U const& expected)
{
ASSERT_TRUE(result.has_value())
<< "expected a value, got error " << static_cast<int>(result.error());
EXPECT_EQ(*result, expected);
}
template <typename T>
void
expectError(std::expected<T, HostFunctionError> const& result, HostFunctionError expected)
{
ASSERT_FALSE(result.has_value()) << "expected error, got a value";
EXPECT_EQ(result.error(), expected);
}
inline void
expectKeyletMatches(std::expected<Bytes, HostFunctionError> const& result, Keylet const& expected)
{
expectValue(result, toBytes(expected.key));
}
struct SignedMessage
{
Bytes message;
Bytes signature;
Bytes publicKey;
};
inline SignedMessage
signMessage(std::string_view message, KeyType keyType = KeyType::Secp256k1)
{
auto const [pk, sk] = randomKeyPair(keyType);
auto const msg = Bytes{std::begin(message), std::end(message)};
auto const sig = sign(pk, sk, Slice{msg.data(), msg.size()});
return {
.message = msg,
.signature = Bytes{sig.data(), sig.data() + sig.size()},
.publicKey = Bytes{pk.data(), pk.data() + pk.size()}};
}
inline uint256
credentialId(
std::string_view hex = "0011223344556677889900112233445566778899001122334455667788990011")
{
auto id = uint256{};
EXPECT_TRUE(id.parseHex(std::string{hex}));
return id;
}
inline STObject
makeMemo(Bytes const& data)
{
auto memo = STObject::makeInnerObject(sfMemo);
memo.setFieldVL(sfMemoData, data);
return memo;
}
struct TxAssembler
{
TxType type;
std::function<void(STObject&)> build;
};
inline TxAssembler
bareTx(TxType type = ttESCROW_FINISH)
{
return {.type = type, .build = [](STObject&) {}};
}
inline TxAssembler
escrowFinishTx(TxTest& ledger, Account const& acct)
{
return {.type = ttESCROW_FINISH, .build = [&ledger, acct](STObject& obj) {
auto credId = uint256{};
EXPECT_TRUE(credId.parseHex(
"0011223344556677889900112233445566778899001122334455667788990011"));
obj.setAccountID(sfAccount, acct.id());
obj.setAccountID(sfOwner, acct.id());
obj.setFieldU32(sfOfferSequence, ledger.getAccountRoot(acct.id()).getSequence());
obj.setFieldArray(sfMemos, STArray{});
auto credIds = STVector256{};
credIds.pushBack(credId);
obj.setFieldV256(sfCredentialIDs, credIds);
}};
}
inline TxAssembler
ammDepositTx(Account const& acct, Asset const& asset1, Asset const& asset2)
{
return {.type = ttAMM_DEPOSIT, .build = [acct, asset1, asset2](STObject& obj) {
obj.setAccountID(sfAccount, acct.id());
obj.setFieldIssue(sfAsset, STIssue{sfAsset, asset1});
obj.setFieldIssue(sfAsset2, STIssue{sfAsset2, asset2});
}};
}
inline TxAssembler
mptIssuanceCreateTx(Account const& acct, std::uint8_t scale)
{
return {.type = ttMPTOKEN_ISSUANCE_CREATE, .build = [acct, scale](STObject& obj) {
obj.setAccountID(sfAccount, acct.id());
obj.setFieldU8(sfAssetScale, scale);
}};
}
class WasmHost
{
public:
// The real ledger. Tests populate it with `ledger.createAccount()` / `submit()` /
// `close()` before reading through the host.
TxTest ledger;
// A real host bound to `leKey` — the "current"/home object the `*_field` and
// `*_arr_len` getters read. Defaults to a throwaway keylet for the many functions
// (keylets, floats, sig, hash, nft decoders) that never touch the current object.
//
// Returns a reference into a fixture-owned host so its `ApplyContext&` outlives it;
// call once per test.
WasmHostFunctionsImpl&
host(Keylet const& leKey = keylet::account(AccountID{}))
WasmHost(
std::shared_ptr<STTx const> tx,
std::unique_ptr<ApplyContext> context,
std::unique_ptr<WasmHostFunctionsImpl> host)
: tx_{std::move(tx)}, context_{std::move(context)}, host_{std::move(host)}
{
}
WasmHostFunctionsImpl*
operator->() const
{
return host_.get();
}
WasmHostFunctionsImpl&
operator*() const
{
// The finish tx the host runs under. Its contents are irrelevant to the
// functions these tests exercise; it only has to be a well-formed shell.
finishTx_ = std::make_shared<STTx>(ttESCROW_FINISH, [](STObject&) {});
context_.emplace(
ledger.getServiceRegistry(),
ledger.getOpenLedger(),
*finishTx_,
tesSUCCESS,
ledger.getOpenLedger().fees().base,
TapNone,
beast::Journal{beast::Journal::getNullSink()});
host_.emplace(*context_, leKey);
return *host_;
}
private:
std::shared_ptr<STTx const> finishTx_;
std::optional<ApplyContext> context_;
std::optional<WasmHostFunctionsImpl> host_;
std::shared_ptr<STTx const> tx_;
std::unique_ptr<ApplyContext> context_;
std::unique_ptr<WasmHostFunctionsImpl> host_;
};
class WasmImplTest : public testing::Test
{
public:
TxTest ledger;
Account
fund(char const* name, XRPAmount amount = XRP(1000))
{
auto const account = Account{name};
ledger.createAccount(account, amount);
return account;
}
WasmHost
makeHost(
beast::Journal journal,
Keylet const& leKey = keylet::account(AccountID{}),
TxType txType = ttESCROW_FINISH,
std::function<void(STObject&)> assembler = [](STObject&) {})
{
auto tx = std::make_shared<STTx>(
txType, [assembler = std::move(assembler)](STObject& obj) { assembler(obj); });
auto context = std::make_unique<ApplyContext>(
ledger.getServiceRegistry(),
ledger.getOpenLedger(),
*tx,
tesSUCCESS,
ledger.getOpenLedger().fees().base,
TapNone,
journal);
auto host = std::make_unique<WasmHostFunctionsImpl>(*context, leKey);
return WasmHost{std::move(tx), std::move(context), std::move(host)};
}
// The common case: a host that discards its log output.
WasmHost
makeHost(
Keylet const& leKey = keylet::account(AccountID{}),
TxType txType = ttESCROW_FINISH,
std::function<void(STObject&)> assembler = [](STObject&) {})
{
return makeHost(
beast::Journal{beast::Journal::getNullSink()}, leKey, txType, std::move(assembler));
}
// A host whose `trace` output is captured, so a test can read it back with `logged()`.
// The sink is a fixture member, so it outlives the host and accumulates across a test.
WasmHost
makeTracingHost(
Keylet const& leKey = keylet::account(AccountID{}),
TxType txType = ttESCROW_FINISH,
std::function<void(STObject&)> assembler = [](STObject&) {})
{
return makeHost(beast::Journal{traceSink_}, leKey, txType, std::move(assembler));
}
// Everything `trace` has written to the tracing host so far.
[[nodiscard]] std::string
logged() const
{
return traceSink_.messages();
}
// Submit a real SignerListSet so `keylet::signerList(owner)` exists — the object the
// signer-list nested-field / array-length getters read. `signers` pairs each signer
// account with its weight.
void
makeSignerList(
Account const& owner,
std::uint32_t quorum,
std::vector<std::pair<Account, std::uint16_t>> const& signers)
{
auto entries = STArray{};
for (auto const& [signer, weight] : signers)
{
auto entry = STObject::makeInnerObject(sfSignerEntry);
entry.setAccountID(sfAccount, signer.id());
entry.setFieldU16(sfSignerWeight, weight);
entries.push_back(std::move(entry));
}
auto const r = ledger.submit(
transactions::SignerListSetBuilder{owner.id(), quorum}.setSignerEntries(entries),
owner);
EXPECT_EQ(r.ter, tesSUCCESS) << transToken(r.ter);
ledger.close();
}
private:
CaptureSink traceSink_{beast::Severity::Trace};
};
} // namespace xrpl::test

View File

@@ -4,12 +4,8 @@
#include <gtest/gtest.h>
#include <helpers/Account.h>
#include <helpers/TxTest.h>
#include <tx/wasm/RealHostFixture.h>
#include <expected>
#include <iterator>
namespace xrpl::test {
struct AccountKeyletImpl : WasmImplTest
@@ -18,22 +14,14 @@ struct AccountKeyletImpl : WasmImplTest
TEST_F(AccountKeyletImpl, MatchesAccountKeyletFunction)
{
auto const owner = Account{"owner"};
ledger.createAccount(owner, XRP(1000));
auto const owner = fund("owner");
auto const expected = keylet::account(owner.id());
auto const expectedBytes = Bytes{std::begin(expected.key), std::end(expected.key)};
auto const result = host().accountKeylet(owner);
ASSERT_TRUE(result.has_value());
EXPECT_EQ(*result, expectedBytes);
expectKeyletMatches(makeHost()->accountKeylet(owner), keylet::account(owner.id()));
}
TEST_F(AccountKeyletImpl, UnsetAccountIsInvalidAccount)
{
auto const result = host().accountKeylet(AccountID{});
ASSERT_FALSE(result.has_value());
EXPECT_EQ(result.error(), HostFunctionError::InvalidAccount);
expectError(makeHost()->accountKeylet(AccountID{}), HostFunctionError::InvalidAccount);
}
} // namespace xrpl::test

View File

@@ -5,12 +5,8 @@
#include <gtest/gtest.h>
#include <helpers/Account.h>
#include <helpers/TxTest.h>
#include <tx/wasm/RealHostFixture.h>
#include <expected>
#include <iterator>
namespace xrpl::test {
struct AmmKeyletImpl : WasmImplTest
@@ -19,35 +15,26 @@ struct AmmKeyletImpl : WasmImplTest
TEST_F(AmmKeyletImpl, MatchesAmmKeyletFunction)
{
auto const owner = Account{"owner"};
ledger.createAccount(owner, XRP(1000));
auto const owner = fund("owner");
auto usdIssue = Issue{toCurrency("USD"), owner.id()};
auto const expected = keylet::amm(xrpIssue(), usdIssue);
auto const expectedBytes = Bytes{std::begin(expected.key), std::end(expected.key)};
auto const result = host().ammKeylet(usdIssue, xrpIssue());
ASSERT_TRUE(result.has_value());
EXPECT_EQ(*result, expectedBytes);
expectKeyletMatches(
makeHost()->ammKeylet(usdIssue, xrpIssue()), keylet::amm(xrpIssue(), usdIssue));
}
TEST_F(AmmKeyletImpl, InvalidIssue1)
{
auto const result = host().ammKeylet(xrpIssue(), xrpIssue());
ASSERT_TRUE(!result.has_value());
EXPECT_EQ(result.error(), HostFunctionError::InvalidParams);
expectError(makeHost()->ammKeylet(xrpIssue(), xrpIssue()), HostFunctionError::InvalidParams);
}
TEST_F(AmmKeyletImpl, InvalidIssue2)
{
auto const owner = Account{"owner"};
ledger.createAccount(owner, XRP(1000));
auto const owner = fund("owner");
auto baseMpt = makeMptID(1, owner.id());
auto const result = host().ammKeylet(baseMpt, xrpIssue());
ASSERT_TRUE(!result.has_value());
EXPECT_EQ(result.error(), HostFunctionError::InvalidParams);
expectError(makeHost()->ammKeylet(baseMpt, xrpIssue()), HostFunctionError::InvalidParams);
}
} // namespace xrpl::test

View File

@@ -1,8 +1,6 @@
#include <gtest/gtest.h>
#include <tx/wasm/RealHostFixture.h>
#include <expected>
namespace xrpl::test {
struct BaseFeeImpl : WasmImplTest
@@ -11,9 +9,7 @@ struct BaseFeeImpl : WasmImplTest
TEST_F(BaseFeeImpl, MatchesLedger)
{
auto const result = host().getBaseFee();
ASSERT_TRUE(result.has_value());
EXPECT_EQ(*result, ledger.getOpenLedger().fees().base.drops());
expectValue(makeHost()->getBaseFee(), ledger.getOpenLedger().fees().base.drops());
}
} // namespace xrpl::test

View File

@@ -9,7 +9,6 @@
#include <tx/wasm/RealHostFixture.h>
#include <cstdint>
#include <expected>
namespace xrpl::test {
@@ -21,16 +20,16 @@ struct CacheLedgerObjImpl : WasmImplTest
auto const owner = Account{"owner"};
ledger.createAccount(owner, XRP(1000));
auto& h = host();
auto h = makeHost();
auto const key = keylet::account(owner.id()).key;
for (auto i = int32_t{1}; i < 257; ++i)
{
auto const slot = h.cacheLedgerObj(key, i);
auto const slot = h->cacheLedgerObj(key, i);
ASSERT_TRUE(slot.has_value()) << "cacheLedgerObj should find the created account";
EXPECT_EQ(*slot, i);
auto const account = h.getLedgerObjField(*slot, sfAccount);
auto const account = h->getLedgerObjField(*slot, sfAccount);
ASSERT_TRUE(account.has_value());
Bytes const ownerBytes{owner.id().begin(), owner.id().end()};
EXPECT_EQ(*account, ownerBytes);
@@ -43,7 +42,7 @@ struct CacheLedgerObjImpl : WasmImplTest
// Every slot is now occupied, so asking to auto-allocate (cacheIdx == 0) has nowhere
// to put the object.
auto const result = h.cacheLedgerObj(key, 0);
auto const result = h->cacheLedgerObj(key, 0);
ASSERT_FALSE(result.has_value());
EXPECT_EQ(result.error(), HostFunctionError::SlotsFull);
}
@@ -61,11 +60,11 @@ TEST_F(CacheLedgerObjImpl, MatchesLedgerImplicitIndices)
TEST_F(CacheLedgerObjImpl, OutOfRange)
{
auto result = host().cacheLedgerObj(uint256{}, -1);
auto result = makeHost()->cacheLedgerObj(uint256{}, -1);
ASSERT_FALSE(result.has_value());
EXPECT_EQ(result.error(), HostFunctionError::SlotOutRange);
result = host().cacheLedgerObj(uint256{}, 257);
result = makeHost()->cacheLedgerObj(uint256{}, 257);
ASSERT_FALSE(result.has_value());
EXPECT_EQ(result.error(), HostFunctionError::SlotOutRange);
}
@@ -73,9 +72,26 @@ TEST_F(CacheLedgerObjImpl, OutOfRange)
TEST_F(CacheLedgerObjImpl, LedgerObjNotFound)
{
auto const ghost = keylet::account(Account{"ghost"}.id()).key;
auto result = host().cacheLedgerObj(ghost, 0);
auto result = makeHost()->cacheLedgerObj(ghost, 0);
ASSERT_FALSE(result.has_value());
EXPECT_EQ(result.error(), HostFunctionError::LedgerObjNotFound);
}
// Two hosts built from the same fixture are fully independent: each owns its own slot
// table, so caching into one leaves the other's slots empty. (This is what the `WasmHost`
// handle buys over the old shared-fixture-state design.)
TEST_F(CacheLedgerObjImpl, IndependentHostsDoNotShareSlots)
{
auto const owner = fund("owner");
auto const key = keylet::account(owner.id()).key;
auto a = makeHost();
auto b = makeHost();
ASSERT_TRUE(a->cacheLedgerObj(key, 1).has_value());
expectValue(a->getLedgerObjField(1, sfAccount), toBytes(owner.id()));
// `b` never cached anything, so its slot 1 is still empty.
expectError(b->getLedgerObjField(1, sfAccount), HostFunctionError::EmptySlot);
}
} // namespace xrpl::test

View File

@@ -5,12 +5,8 @@
#include <gtest/gtest.h>
#include <helpers/Account.h>
#include <helpers/TxTest.h>
#include <tx/wasm/RealHostFixture.h>
#include <expected>
#include <iterator>
namespace xrpl::test {
struct CheckKeyletImpl : WasmImplTest
@@ -19,22 +15,16 @@ struct CheckKeyletImpl : WasmImplTest
TEST_F(CheckKeyletImpl, MatchesCheckKeyletFunction)
{
auto const owner = Account{"owner"};
ledger.createAccount(owner, XRP(1000));
auto const owner = fund("owner");
auto const expected = keylet::check(owner.id(), SeqProxy::rawSequence(1u));
auto const expectedBytes = Bytes{std::begin(expected.key), std::end(expected.key)};
auto const result = host().checkKeylet(owner.id(), 1u);
ASSERT_TRUE(result.has_value());
EXPECT_EQ(*result, expectedBytes);
expectKeyletMatches(
makeHost()->checkKeylet(owner.id(), 1u),
keylet::check(owner.id(), SeqProxy::rawSequence(1u)));
}
TEST_F(CheckKeyletImpl, UnsetAccountIsInvalidAccount)
{
auto const result = host().checkKeylet(AccountID{}, 1u);
ASSERT_FALSE(result.has_value());
EXPECT_EQ(result.error(), HostFunctionError::InvalidAccount);
expectError(makeHost()->checkKeylet(AccountID{}, 1u), HostFunctionError::InvalidAccount);
}
} // namespace xrpl::test

View File

@@ -0,0 +1,80 @@
#include <xrpl/protocol/KeyType.h>
#include <xrpl/protocol/SecretKey.h>
#include <xrpl/protocol/Seed.h>
#include <gtest/gtest.h>
#include <tx/wasm/RealHostFixture.h>
#include <cstdint>
namespace xrpl::test {
struct CheckSignatureImpl : WasmImplTest
{
};
TEST_F(CheckSignatureImpl, ValidSignature)
{
auto const kp = generateKeyPair(KeyType::Secp256k1, randomSeed());
auto const& pk = kp.first;
auto const& sk = kp.second;
auto const& message = std::string{"hello signature"};
auto const sig = sign(pk, sk, Slice(message.data(), message.size()));
auto const result = makeHost()->checkSignature(
Slice{message.data(), message.size()}, Slice{sig.data(), sig.size()}, pk);
expectValue(result, std::int32_t{1});
}
TEST_F(CheckSignatureImpl, InvalidSignature)
{
auto const kp = generateKeyPair(KeyType::Secp256k1, randomSeed());
auto const& pk = kp.first;
auto const& sk = kp.second;
auto const& message = std::string{"hello signature"};
auto const sig = sign(pk, sk, Slice(message.data(), message.size()));
auto const badSignature = std::string(sig.size(), 0xFF);
auto const result = makeHost()->checkSignature(
Slice{message.data(), message.size()}, Slice{badSignature.data(), badSignature.size()}, pk);
expectValue(result, std::int32_t{0});
}
TEST_F(CheckSignatureImpl, InvalidPublicKey)
{
auto const kp = generateKeyPair(KeyType::Secp256k1, randomSeed());
auto const kp2 = generateKeyPair(KeyType::Secp256k1, randomSeed());
auto const& pk = kp.first;
auto const& sk = kp.second;
auto const& message = std::string{"hello signature"};
auto const sig = sign(pk, sk, Slice(message.data(), message.size()));
auto const result = makeHost()->checkSignature(
Slice{message.data(), message.size()}, Slice{sig.data(), sig.size()}, kp2.first);
expectValue(result, std::int32_t{0});
}
TEST_F(CheckSignatureImpl, EmptySignature)
{
auto const kp = generateKeyPair(KeyType::Secp256k1, randomSeed());
auto const& pk = kp.first;
auto const& message = std::string{"hello signature"};
auto const result =
makeHost()->checkSignature(Slice{message.data(), message.size()}, Slice{}, pk);
expectValue(result, std::int32_t{0});
}
TEST_F(CheckSignatureImpl, EmptyMessage)
{
auto const kp = generateKeyPair(KeyType::Secp256k1, randomSeed());
auto const& pk = kp.first;
auto const& sk = kp.second;
auto const& message = std::string{"hello signature"};
auto const sig = sign(pk, sk, Slice(message.data(), message.size()));
auto const result = makeHost()->checkSignature(Slice{}, Slice{sig.data(), sig.size()}, pk);
expectValue(result, std::int32_t{0});
}
} // namespace xrpl::test

View File

@@ -6,12 +6,8 @@
#include <gtest/gtest.h>
#include <helpers/Account.h>
#include <helpers/TxTest.h>
#include <tx/wasm/RealHostFixture.h>
#include <expected>
#include <iterator>
namespace xrpl::test {
struct CredentialKeyletImpl : WasmImplTest
@@ -20,23 +16,19 @@ struct CredentialKeyletImpl : WasmImplTest
TEST_F(CredentialKeyletImpl, MatchesCredentialKeyletFunction)
{
auto const owner = Account{"owner"};
ledger.createAccount(owner, XRP(1000));
auto const owner = fund("owner");
auto const credTypeStr = std::string{"test"};
auto const credType = Slice{credTypeStr.data(), credTypeStr.size()};
auto const expected = keylet::credential(owner.id(), owner.id(), credType);
auto const expectedBytes = Bytes{std::begin(expected.key), std::end(expected.key)};
auto const result = host().credentialKeylet(owner.id(), owner.id(), credType);
ASSERT_TRUE(result.has_value());
EXPECT_EQ(*result, expectedBytes);
expectKeyletMatches(
makeHost()->credentialKeylet(owner.id(), owner.id(), credType),
keylet::credential(owner.id(), owner.id(), credType));
}
TEST_F(CredentialKeyletImpl, CredentialTypeStringTooLong)
{
auto const owner = Account{"owner"};
ledger.createAccount(owner, XRP(1000));
auto const owner = fund("owner");
auto constexpr credTypeStr = std::string_view{
"abcdefghijklmnopqrstuvwxyz01234567890qwertyuiop[]"
@@ -44,26 +36,25 @@ TEST_F(CredentialKeyletImpl, CredentialTypeStringTooLong)
static_assert(credTypeStr.size() > kMaxCredentialTypeLength);
auto const credType = Slice{credTypeStr.data(), credTypeStr.size()};
auto const result = host().credentialKeylet(owner.id(), owner.id(), credType);
ASSERT_TRUE(!result.has_value());
EXPECT_EQ(result.error(), HostFunctionError::InvalidParams);
expectError(
makeHost()->credentialKeylet(owner.id(), owner.id(), credType),
HostFunctionError::InvalidParams);
}
TEST_F(CredentialKeyletImpl, InvalidAccount)
{
auto const owner = Account{"owner"};
ledger.createAccount(owner, XRP(1000));
auto const owner = fund("owner");
auto const credTypeStr = std::string{"test"};
auto const credType = Slice{credTypeStr.data(), credTypeStr.size()};
auto result = host().credentialKeylet(AccountID{}, owner.id(), credType);
ASSERT_TRUE(!result.has_value());
EXPECT_EQ(result.error(), HostFunctionError::InvalidAccount);
expectError(
makeHost()->credentialKeylet(AccountID{}, owner.id(), credType),
HostFunctionError::InvalidAccount);
result = host().credentialKeylet(owner.id(), AccountID{}, credType);
ASSERT_TRUE(!result.has_value());
EXPECT_EQ(result.error(), HostFunctionError::InvalidAccount);
expectError(
makeHost()->credentialKeylet(owner.id(), AccountID{}, credType),
HostFunctionError::InvalidAccount);
}
} // namespace xrpl::test

View File

@@ -0,0 +1,56 @@
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/tx/wasm/WasmCommon.h>
#include <gtest/gtest.h>
#include <helpers/Account.h>
#include <tx/wasm/RealHostFixture.h>
#include <utility>
namespace xrpl::test {
struct CurrentLedgerObjArrayLenImpl : WasmImplTest
{
using WasmImplTest::makeHost;
WasmHost
makeHost(Account const& acct)
{
makeSignerList(acct, 2, {{Account{"alice"}, 1}, {Account{"becky"}, 1}});
auto assembler = bareTx();
return makeHost(keylet::signerList(acct.id()), assembler.type, std::move(assembler.build));
}
};
TEST_F(CurrentLedgerObjArrayLenImpl, SignerEntriesLength)
{
auto const owner = fund("owner");
auto h = makeHost(owner);
expectValue(h->getCurrentLedgerObjArrayLen(sfSignerEntries), 2);
}
TEST_F(CurrentLedgerObjArrayLenImpl, NonArrayFieldNoArray)
{
auto const owner = fund("owner");
auto h = makeHost(owner);
expectError(h->getCurrentLedgerObjArrayLen(sfAccount), HostFunctionError::NoArray);
}
TEST_F(CurrentLedgerObjArrayLenImpl, MissingArrayFieldNotFound)
{
auto const owner = fund("owner");
auto h = makeHost(owner);
expectError(h->getCurrentLedgerObjArrayLen(sfMemos), HostFunctionError::FieldNotFound);
}
TEST_F(CurrentLedgerObjArrayLenImpl, MissingCurrentObjectNotFound)
{
auto const owner = fund("owner");
auto assembler = bareTx();
auto h = makeHost(keylet::signerList(owner.id()), assembler.type, std::move(assembler.build));
expectError(
h->getCurrentLedgerObjArrayLen(sfSignerEntries), HostFunctionError::LedgerObjNotFound);
}
} // namespace xrpl::test

View File

@@ -12,9 +12,6 @@
#include <helpers/TxTest.h>
#include <tx/wasm/RealHostFixture.h>
#include <expected>
#include <iterator>
namespace xrpl::test {
struct CurrentLedgerObjFieldImpl : WasmImplTest
@@ -49,11 +46,7 @@ TEST_F(CurrentLedgerObjFieldImpl, ReadsfAccount)
auto const escrow = makeEscrow(owner, Account{"dest"});
ASSERT_NE(ledger.getOpenLedger().read(escrow), nullptr) << "escrow object should exist";
auto const account = host(escrow).getCurrentLedgerObjField(sfAccount);
ASSERT_TRUE(account.has_value());
auto const ownerBytes = Bytes{std::begin(owner.id()), std::end(owner.id())};
EXPECT_EQ(*account, ownerBytes);
expectValue(makeHost(escrow)->getCurrentLedgerObjField(sfAccount), toBytes(owner.id()));
}
TEST_F(CurrentLedgerObjFieldImpl, ReadsfAccountDummyEscrow)
@@ -63,10 +56,9 @@ TEST_F(CurrentLedgerObjFieldImpl, ReadsfAccountDummyEscrow)
auto const ownerSeq = ledger.getAccountRoot(owner.id()).getSequence();
auto const escrow = keylet::escrow(owner.id(), SeqProxy::rawSequence(ownerSeq));
auto const account = host(escrow).getCurrentLedgerObjField(sfAccount);
ASSERT_TRUE(!account.has_value());
ASSERT_TRUE(account.error() == HostFunctionError::LedgerObjNotFound);
expectError(
makeHost(escrow)->getCurrentLedgerObjField(sfAccount),
HostFunctionError::LedgerObjNotFound);
}
TEST_F(CurrentLedgerObjFieldImpl, ReadAmount)
@@ -75,9 +67,7 @@ TEST_F(CurrentLedgerObjFieldImpl, ReadAmount)
auto const escrow = makeEscrow(owner, Account{"dest"});
ASSERT_NE(ledger.getOpenLedger().read(escrow), nullptr) << "escrow object should exist";
auto const amount = host(escrow).getCurrentLedgerObjField(sfAmount);
ASSERT_TRUE(amount.has_value());
EXPECT_EQ(*amount, toBytes(XRP(100)));
expectValue(makeHost(escrow)->getCurrentLedgerObjField(sfAmount), toBytes(XRP(100)));
}
TEST_F(CurrentLedgerObjFieldImpl, ReadPreviousTxnID)
@@ -87,10 +77,8 @@ TEST_F(CurrentLedgerObjFieldImpl, ReadPreviousTxnID)
auto const escrow = makeEscrow(owner, Account{"dest"}, &transactionId);
ASSERT_NE(ledger.getOpenLedger().read(escrow), nullptr) << "escrow object should exist";
auto const previousTxnId = host(escrow).getCurrentLedgerObjField(sfPreviousTxnID);
ASSERT_TRUE(previousTxnId.has_value());
EXPECT_EQ(*previousTxnId, toBytes(transactionId));
expectValue(
makeHost(escrow)->getCurrentLedgerObjField(sfPreviousTxnID), toBytes(transactionId));
}
TEST_F(CurrentLedgerObjFieldImpl, ReadOwner)
@@ -99,10 +87,8 @@ TEST_F(CurrentLedgerObjFieldImpl, ReadOwner)
auto const escrow = makeEscrow(owner, Account{"dest"});
ASSERT_NE(ledger.getOpenLedger().read(escrow), nullptr) << "escrow object should exist";
auto const ownerField = host(escrow).getCurrentLedgerObjField(sfOwner);
ASSERT_TRUE(!ownerField.has_value());
ASSERT_TRUE(ownerField.error() == HostFunctionError::FieldNotFound);
expectError(
makeHost(escrow)->getCurrentLedgerObjField(sfOwner), HostFunctionError::FieldNotFound);
}
} // namespace xrpl::test

View File

@@ -0,0 +1,61 @@
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/tx/wasm/WasmCommon.h>
#include <gtest/gtest.h>
#include <helpers/Account.h>
#include <tx/wasm/RealHostFixture.h>
#include <utility>
namespace xrpl::test {
struct CurrentLedgerObjNestedArrayLenImpl : WasmImplTest
{
using WasmImplTest::makeHost;
WasmHost
makeHost(Account const& acct)
{
makeSignerList(acct, 2, {{Account{"alice"}, 1}, {Account{"becky"}, 1}});
auto assembler = bareTx();
return makeHost(keylet::signerList(acct.id()), assembler.type, std::move(assembler.build));
}
};
TEST_F(CurrentLedgerObjNestedArrayLenImpl, SignerEntriesLength)
{
auto const owner = fund("owner");
auto h = makeHost(owner);
expectValue(h->getCurrentLedgerObjNestedArrayLen(FieldLocator{{sfSignerEntries.getCode()}}), 2);
}
TEST_F(CurrentLedgerObjNestedArrayLenImpl, NonArrayFieldNoArray)
{
auto const owner = fund("owner");
auto h = makeHost(owner);
expectError(
h->getCurrentLedgerObjNestedArrayLen(FieldLocator{{sfSignerQuorum.getCode()}}),
HostFunctionError::NoArray);
}
TEST_F(CurrentLedgerObjNestedArrayLenImpl, MissingFieldNotFound)
{
auto const owner = fund("owner");
auto h = makeHost(owner);
expectError(
h->getCurrentLedgerObjNestedArrayLen(FieldLocator{{sfSigners.getCode()}}),
HostFunctionError::FieldNotFound);
}
TEST_F(CurrentLedgerObjNestedArrayLenImpl, MissingCurrentObjectNotFound)
{
auto const owner = fund("owner");
auto assembler = bareTx();
auto h = makeHost(keylet::signerList(owner.id()), assembler.type, std::move(assembler.build));
expectError(
h->getCurrentLedgerObjNestedArrayLen(FieldLocator{{sfSignerEntries.getCode()}}),
HostFunctionError::LedgerObjNotFound);
}
} // namespace xrpl::test

View File

@@ -0,0 +1,122 @@
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/STArray.h>
#include <xrpl/protocol/STObject.h>
#include <xrpl/tx/wasm/WasmCommon.h>
#include <gtest/gtest.h>
#include <helpers/Account.h>
#include <tx/wasm/RealHostFixture.h>
#include <cstdint>
#include <utility>
namespace xrpl::test {
struct CurrentLedgerObjNestedFieldImpl : WasmImplTest
{
using WasmImplTest::makeHost;
WasmHost
makeHost(Account const& acct)
{
makeSignerList(acct, 2, {{Account{"alice"}, 1}, {Account{"becky"}, 1}});
auto assembler = bareTx();
return makeHost(keylet::signerList(acct.id()), assembler.type, std::move(assembler.build));
}
};
TEST_F(CurrentLedgerObjNestedFieldImpl, MatchesNestedSignerQuorum)
{
auto const owner = fund("owner");
auto h = makeHost(owner);
expectValue(
h->getCurrentLedgerObjNestedField(FieldLocator{{sfSignerQuorum.getCode()}}),
toBytes(static_cast<std::uint32_t>(2)));
}
TEST_F(CurrentLedgerObjNestedFieldImpl, MatchesNestedSignerWeight)
{
auto const owner = fund("owner");
auto h = makeHost(owner);
expectValue(
h->getCurrentLedgerObjNestedField(
FieldLocator{{sfSignerEntries.getCode(), 0, sfSignerWeight.getCode()}}),
toBytes(static_cast<std::uint16_t>(1)));
}
TEST_F(CurrentLedgerObjNestedFieldImpl, MatchesNestedSignerAccount)
{
auto const owner = fund("owner");
auto h = makeHost(owner);
auto const sle = ledger.getOpenLedger().read(keylet::signerList(owner.id()));
ASSERT_NE(sle, nullptr);
auto const& entry0 = sle->getFieldArray(sfSignerEntries)[0];
expectValue(
h->getCurrentLedgerObjNestedField(
FieldLocator{{sfSignerEntries.getCode(), 0, sfAccount.getCode()}}),
toBytes(entry0.getAccountID(sfAccount)));
}
TEST_F(CurrentLedgerObjNestedFieldImpl, MissingFieldNotFound)
{
auto const owner = fund("owner");
auto h = makeHost(owner);
expectError(
h->getCurrentLedgerObjNestedField(
FieldLocator{{sfSigners.getCode(), 0, sfAccount.getCode()}}),
HostFunctionError::FieldNotFound);
}
TEST_F(CurrentLedgerObjNestedFieldImpl, IndexOutOfBounds)
{
auto const owner = fund("owner");
auto h = makeHost(owner);
auto const err = HostFunctionError::IndexOutOfBounds;
expectError(
h->getCurrentLedgerObjNestedField(
FieldLocator{{sfSignerEntries.getCode(), 2, sfAccount.getCode()}}),
err);
expectError(
h->getCurrentLedgerObjNestedField(
FieldLocator{{sfSignerEntries.getCode(), -1, sfAccount.getCode()}}),
err);
}
TEST_F(CurrentLedgerObjNestedFieldImpl, UnknownFieldCodeInvalidField)
{
auto const owner = fund("owner");
auto h = makeHost(owner);
auto const err = HostFunctionError::InvalidField;
expectError(h->getCurrentLedgerObjNestedField(FieldLocator{{fieldCode(20000, 20000)}}), err);
expectError(
h->getCurrentLedgerObjNestedField(
FieldLocator{{sfSignerEntries.getCode(), 0, fieldCode(20000, 20000)}}),
err);
}
TEST_F(CurrentLedgerObjNestedFieldImpl, NestIntoNonContainerMalformed)
{
auto const owner = fund("owner");
auto h = makeHost(owner);
expectError(
h->getCurrentLedgerObjNestedField(
FieldLocator{{sfSignerQuorum.getCode(), 0, sfAccount.getCode()}}),
HostFunctionError::LocatorMalformed);
}
TEST_F(CurrentLedgerObjNestedFieldImpl, MissingCurrentObjectNotFound)
{
auto const owner = fund("owner");
auto assembler = bareTx();
auto h = makeHost(keylet::signerList(owner.id()), assembler.type, std::move(assembler.build));
expectError(
h->getCurrentLedgerObjNestedField(FieldLocator{{sfSignerQuorum.getCode()}}),
HostFunctionError::LedgerObjNotFound);
}
} // namespace xrpl::test

View File

@@ -4,12 +4,8 @@
#include <gtest/gtest.h>
#include <helpers/Account.h>
#include <helpers/TxTest.h>
#include <tx/wasm/RealHostFixture.h>
#include <expected>
#include <iterator>
namespace xrpl::test {
struct DelegateKeyletImpl : WasmImplTest
@@ -18,40 +14,31 @@ struct DelegateKeyletImpl : WasmImplTest
TEST_F(DelegateKeyletImpl, MatchesDelegateKeyletFunction)
{
auto const owner = Account{"owner"};
ledger.createAccount(owner, XRP(1000));
auto const delegate = Account{"delegate"};
ledger.createAccount(delegate, XRP(1000));
auto const owner = fund("owner");
auto const delegate = fund("delegate");
auto const expected = keylet::delegate(owner.id(), delegate.id());
auto const expectedBytes = Bytes{std::begin(expected.key), std::end(expected.key)};
auto const result = host().delegateKeylet(owner.id(), delegate.id());
ASSERT_TRUE(result.has_value());
EXPECT_EQ(*result, expectedBytes);
expectKeyletMatches(
makeHost()->delegateKeylet(owner.id(), delegate.id()),
keylet::delegate(owner.id(), delegate.id()));
}
TEST_F(DelegateKeyletImpl, CantDelegateToSelf)
{
auto const owner = Account{"owner"};
ledger.createAccount(owner, XRP(1000));
auto const owner = fund("owner");
auto const result = host().delegateKeylet(owner.id(), owner.id());
ASSERT_TRUE(!result.has_value());
EXPECT_EQ(result.error(), HostFunctionError::InvalidParams);
expectError(
makeHost()->delegateKeylet(owner.id(), owner.id()), HostFunctionError::InvalidParams);
}
TEST_F(DelegateKeyletImpl, InvalidAccount)
{
auto const owner = Account{"owner"};
ledger.createAccount(owner, XRP(1000));
auto const owner = fund("owner");
auto result = host().delegateKeylet(AccountID{}, owner.id());
ASSERT_TRUE(!result.has_value());
EXPECT_EQ(result.error(), HostFunctionError::InvalidAccount);
expectError(
makeHost()->delegateKeylet(AccountID{}, owner.id()), HostFunctionError::InvalidAccount);
result = host().delegateKeylet(owner.id(), AccountID{});
ASSERT_TRUE(!result.has_value());
EXPECT_EQ(result.error(), HostFunctionError::InvalidAccount);
expectError(
makeHost()->delegateKeylet(owner.id(), AccountID{}), HostFunctionError::InvalidAccount);
}
} // namespace xrpl::test

View File

@@ -4,12 +4,8 @@
#include <gtest/gtest.h>
#include <helpers/Account.h>
#include <helpers/TxTest.h>
#include <tx/wasm/RealHostFixture.h>
#include <expected>
#include <iterator>
namespace xrpl::test {
struct DepositPreauthKeyletImpl : WasmImplTest
@@ -18,40 +14,33 @@ struct DepositPreauthKeyletImpl : WasmImplTest
TEST_F(DepositPreauthKeyletImpl, MatchesDepositPreauthKeyletFunction)
{
auto const owner = Account{"owner"};
ledger.createAccount(owner, XRP(1000));
auto const destination = Account{"destination"};
ledger.createAccount(destination, XRP(1000));
auto const owner = fund("owner");
auto const destination = fund("destination");
auto const expected = keylet::depositPreauth(owner.id(), destination.id());
auto const expectedBytes = Bytes{std::begin(expected.key), std::end(expected.key)};
auto const result = host().depositPreauthKeylet(owner.id(), destination.id());
ASSERT_TRUE(result.has_value());
EXPECT_EQ(*result, expectedBytes);
expectKeyletMatches(
makeHost()->depositPreauthKeylet(owner.id(), destination.id()),
keylet::depositPreauth(owner.id(), destination.id()));
}
TEST_F(DepositPreauthKeyletImpl, CantPreauthToSelf)
{
auto const owner = Account{"owner"};
ledger.createAccount(owner, XRP(1000));
auto const owner = fund("owner");
auto const result = host().depositPreauthKeylet(owner.id(), owner.id());
ASSERT_TRUE(!result.has_value());
EXPECT_EQ(result.error(), HostFunctionError::InvalidParams);
expectError(
makeHost()->depositPreauthKeylet(owner.id(), owner.id()), HostFunctionError::InvalidParams);
}
TEST_F(DepositPreauthKeyletImpl, InvalidAccount)
{
auto const owner = Account{"owner"};
ledger.createAccount(owner, XRP(1000));
auto const owner = fund("owner");
auto result = host().depositPreauthKeylet(AccountID{}, owner.id());
ASSERT_TRUE(!result.has_value());
EXPECT_EQ(result.error(), HostFunctionError::InvalidAccount);
expectError(
makeHost()->depositPreauthKeylet(AccountID{}, owner.id()),
HostFunctionError::InvalidAccount);
result = host().depositPreauthKeylet(owner.id(), AccountID{});
ASSERT_TRUE(!result.has_value());
EXPECT_EQ(result.error(), HostFunctionError::InvalidAccount);
expectError(
makeHost()->depositPreauthKeylet(owner.id(), AccountID{}),
HostFunctionError::InvalidAccount);
}
} // namespace xrpl::test

View File

@@ -4,12 +4,8 @@
#include <gtest/gtest.h>
#include <helpers/Account.h>
#include <helpers/TxTest.h>
#include <tx/wasm/RealHostFixture.h>
#include <expected>
#include <iterator>
namespace xrpl::test {
struct DidKeyletImpl : WasmImplTest
@@ -18,21 +14,14 @@ struct DidKeyletImpl : WasmImplTest
TEST_F(DidKeyletImpl, MatchesDidKeyletFunction)
{
auto const owner = Account{"owner"};
ledger.createAccount(owner, XRP(1000));
auto const owner = fund("owner");
auto const expected = keylet::did(owner.id());
auto const expectedBytes = Bytes{std::begin(expected.key), std::end(expected.key)};
auto const result = host().didKeylet(owner.id());
ASSERT_TRUE(result.has_value());
EXPECT_EQ(*result, expectedBytes);
expectKeyletMatches(makeHost()->didKeylet(owner.id()), keylet::did(owner.id()));
}
TEST_F(DidKeyletImpl, InvalidAccount)
{
auto result = host().didKeylet(AccountID{});
ASSERT_TRUE(!result.has_value());
EXPECT_EQ(result.error(), HostFunctionError::InvalidAccount);
expectError(makeHost()->didKeylet(AccountID{}), HostFunctionError::InvalidAccount);
}
} // namespace xrpl::test

View File

@@ -8,8 +8,6 @@
#include <tx/wasm/RealHostFixture.h>
#include <cstdint>
#include <expected>
#include <iterator>
namespace xrpl::test {
@@ -22,18 +20,15 @@ TEST_F(EscrowKeyletImpl, MatchesLedgerKeyletFunction)
auto const owner = Account{"owner"};
auto const seq = std::uint32_t{42};
auto const result = host().escrowKeylet(owner.id(), seq);
ASSERT_TRUE(result.has_value());
auto const expected = keylet::escrow(owner.id(), SeqProxy::rawSequence(seq)).key;
auto const expectedBytes = Bytes{std::begin(expected), std::end(expected)};
EXPECT_EQ(*result, expectedBytes);
expectKeyletMatches(
makeHost()->escrowKeylet(owner.id(), seq),
keylet::escrow(owner.id(), SeqProxy::rawSequence(seq)));
}
TEST_F(EscrowKeyletImpl, DifferentAccountsGiveDifferentKeylets)
{
auto const a = host().escrowKeylet(Account{"alice"}.id(), 7);
auto const b = host().escrowKeylet(Account{"becky"}.id(), 7);
auto const a = makeHost()->escrowKeylet(Account{"alice"}.id(), 7);
auto const b = makeHost()->escrowKeylet(Account{"becky"}.id(), 7);
ASSERT_TRUE(a.has_value() && b.has_value());
EXPECT_NE(*a, *b);
@@ -41,10 +36,7 @@ TEST_F(EscrowKeyletImpl, DifferentAccountsGiveDifferentKeylets)
TEST_F(EscrowKeyletImpl, UnsetAccountIsInvalidAccount)
{
auto const result = host().escrowKeylet(AccountID{}, 1);
ASSERT_FALSE(result.has_value());
EXPECT_EQ(result.error(), HostFunctionError::InvalidAccount);
expectError(makeHost()->escrowKeylet(AccountID{}, 1), HostFunctionError::InvalidAccount);
}
} // namespace xrpl::test

View File

@@ -0,0 +1,46 @@
#include <xrpl/basics/Slice.h>
#include <xrpl/tx/wasm/WasmCommon.h>
#include <gtest/gtest.h>
#include <tx/wasm/FloatFixture.h>
#include <tx/wasm/RealHostFixture.h>
namespace xrpl::test {
struct FloatAddImpl : FloatTest
{
};
TEST_F(FloatAddImpl, BadModeIsMalformed)
{
expectError(
makeHost()->floatAdd(slice(floats::kOne), slice(floats::kOne), -1),
HostFunctionError::FloatInputMalformed);
}
TEST_F(FloatAddImpl, MalformedInput)
{
expectError(
makeHost()->floatAdd(slice(floats::kOne), Slice{}, 0),
HostFunctionError::FloatInputMalformed);
}
TEST_F(FloatAddImpl, MaxIouPlusMaxExpIsMaxExp)
{
expectValue(
makeHost()->floatAdd(slice(floats::kMaxIOU), slice(floats::kMaxExp), 0), floats::kMaxExp);
}
TEST_F(FloatAddImpl, MinPlusZeroIsMin)
{
expectValue(
makeHost()->floatAdd(slice(floats::kIntMin), slice(floats::kIntZero), 0), floats::kIntMin);
}
TEST_F(FloatAddImpl, MaxPlusMinIsZero)
{
expectValue(
makeHost()->floatAdd(slice(floats::kIntMax), slice(floats::kIntMin), 0), floats::kIntZero);
}
} // namespace xrpl::test

View File

@@ -0,0 +1,48 @@
#include <xrpl/basics/Slice.h>
#include <xrpl/tx/wasm/WasmCommon.h>
#include <gtest/gtest.h>
#include <tx/wasm/FloatFixture.h>
#include <tx/wasm/RealHostFixture.h>
namespace xrpl::test {
struct FloatCompareImpl : FloatTest
{
};
TEST_F(FloatCompareImpl, MalformedInputs)
{
// A wrong-size (here empty) buffer is malformed; the impl normalizes any well-formed
// 12-byte buffer, so size is the only rejection.
expectError(makeHost()->floatCompare(Slice{}, Slice{}), HostFunctionError::FloatInputMalformed);
expectError(
makeHost()->floatCompare(slice(floats::kOne), Slice{}),
HostFunctionError::FloatInputMalformed);
}
TEST_F(FloatCompareImpl, Less)
{
expectValue(makeHost()->floatCompare(slice(floats::kIntMin), slice(floats::kIntZero)), 2);
}
TEST_F(FloatCompareImpl, Greater)
{
expectValue(makeHost()->floatCompare(slice(floats::kIntMax), slice(floats::kIntZero)), 1);
}
TEST_F(FloatCompareImpl, Equal)
{
expectValue(makeHost()->floatCompare(slice(floats::kOne), slice(floats::kOne)), 0);
}
// A non-canonical encoding of 10 (mantissa 100000, exponent -4) is normalized on decode, so
// it compares equal to the canonical 10 — the impl accepts any well-formed 12-byte buffer.
TEST_F(FloatCompareImpl, NonCanonicalNormalizes)
{
Bytes const nonCanonicalTen{
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x86, 0xA0, 0xFF, 0xFF, 0xFF, 0xFC};
expectValue(makeHost()->floatCompare(slice(nonCanonicalTen), slice(floats::kTen)), 0);
}
} // namespace xrpl::test

View File

@@ -0,0 +1,70 @@
#include <xrpl/basics/Slice.h>
#include <xrpl/protocol/STAmount.h>
#include <xrpl/tx/wasm/WasmCommon.h>
#include <gtest/gtest.h>
#include <tx/wasm/FloatFixture.h>
#include <tx/wasm/RealHostFixture.h>
namespace xrpl::test {
struct FloatDivideImpl : FloatTest
{
};
TEST_F(FloatDivideImpl, BadModeIsMalformed)
{
expectError(
makeHost()->floatDivide(slice(floats::kOne), slice(floats::kOne), -1),
HostFunctionError::FloatInputMalformed);
}
TEST_F(FloatDivideImpl, MalformedInput)
{
expectError(
makeHost()->floatDivide(slice(floats::kOne), Slice{}, 0),
HostFunctionError::FloatInputMalformed);
}
TEST_F(FloatDivideImpl, DivideByZeroIsComputationError)
{
expectError(
makeHost()->floatDivide(slice(floats::kOne), slice(floats::kIntZero), 0),
HostFunctionError::FloatComputationError);
}
TEST_F(FloatDivideImpl, OverflowIsComputationError)
{
// A divisor just below 1, so max / it overflows.
auto const y = makeHost()->floatFromMantExp(STAmount::kMaxValue, -floats::kNormalExp - 1, 0);
ASSERT_TRUE(y.has_value());
expectError(
makeHost()->floatDivide(slice(floats::kMax), slice(*y), 0),
HostFunctionError::FloatComputationError);
}
TEST_F(FloatDivideImpl, ZeroDividedByOneIsZero)
{
expectValue(
makeHost()->floatDivide(slice(floats::kIntZero), slice(floats::kOne), 0), floats::kIntZero);
}
TEST_F(FloatDivideImpl, MaxExpDividedByTenIsPreMaxExp)
{
expectValue(
makeHost()->floatDivide(slice(floats::kMaxExp), slice(floats::kTen), 0),
floats::kPreMaxExp);
}
// The rounding mode changes an inexact result: 1/3 rounded Downward differs from Upward.
TEST_F(FloatDivideImpl, RoundingModeAffectsInexactResult)
{
auto const three = makeHost()->floatFromInt(3, 0);
ASSERT_TRUE(three.has_value());
auto const down = makeHost()->floatDivide(slice(floats::kOne), slice(*three), 2);
auto const up = makeHost()->floatDivide(slice(floats::kOne), slice(*three), 3);
ASSERT_TRUE(down.has_value() && up.has_value());
EXPECT_NE(*down, *up);
}
} // namespace xrpl::test

View File

@@ -0,0 +1,34 @@
#include <xrpl/tx/wasm/WasmCommon.h>
#include <gtest/gtest.h>
#include <tx/wasm/FloatFixture.h>
#include <tx/wasm/RealHostFixture.h>
namespace xrpl::test {
struct FloatFromIntImpl : FloatTest
{
};
TEST_F(FloatFromIntImpl, BadModeIsMalformed)
{
expectError(makeHost()->floatFromInt(kMin64, -1), HostFunctionError::FloatInputMalformed);
expectError(makeHost()->floatFromInt(kMin64, 4), HostFunctionError::FloatInputMalformed);
}
TEST_F(FloatFromIntImpl, MinInt)
{
expectValue(makeHost()->floatFromInt(kMin64, 0), floats::kIntMin);
}
TEST_F(FloatFromIntImpl, Zero)
{
expectValue(makeHost()->floatFromInt(0, 0), floats::kIntZero);
}
TEST_F(FloatFromIntImpl, MaxInt)
{
expectValue(makeHost()->floatFromInt(kMax64, 0), floats::kIntMax);
}
} // namespace xrpl::test

View File

@@ -0,0 +1,68 @@
#include <xrpl/basics/Number.h>
#include <xrpl/protocol/STAmount.h>
#include <xrpl/tx/wasm/WasmCommon.h>
#include <gtest/gtest.h>
#include <tx/wasm/FloatFixture.h>
#include <tx/wasm/RealHostFixture.h>
namespace xrpl::test {
struct FloatFromMantExpImpl : FloatTest
{
static constexpr int kMaxRawExp = Number::kMaxExponent + floats::kNormalExp;
static constexpr int kMinRawExp = Number::kMinExponent + floats::kNormalExp;
};
TEST_F(FloatFromMantExpImpl, BadModeIsMalformed)
{
expectError(makeHost()->floatFromMantExp(1, 0, -1), HostFunctionError::FloatInputMalformed);
expectError(makeHost()->floatFromMantExp(1, 0, 4), HostFunctionError::FloatInputMalformed);
}
TEST_F(FloatFromMantExpImpl, ExponentTooHighIsMalformed)
{
expectError(
makeHost()->floatFromMantExp(1, kMaxRawExp + 1, 0), HostFunctionError::FloatInputMalformed);
}
TEST_F(FloatFromMantExpImpl, UnderflowIsZero)
{
expectValue(makeHost()->floatFromMantExp(1, kMinRawExp - 1, 0), floats::kIntZero);
}
TEST_F(FloatFromMantExpImpl, MaxExponent)
{
expectValue(makeHost()->floatFromMantExp(1, kMaxRawExp, 0), floats::kMaxExp);
}
TEST_F(FloatFromMantExpImpl, MinusMaxExponent)
{
expectValue(makeHost()->floatFromMantExp(-1, kMaxRawExp, 0), floats::kMinusMaxExp);
}
TEST_F(FloatFromMantExpImpl, PreMaxExponent)
{
expectValue(makeHost()->floatFromMantExp(1, kMaxRawExp - 1, 0), floats::kPreMaxExp);
}
TEST_F(FloatFromMantExpImpl, MaxIou)
{
expectValue(
makeHost()->floatFromMantExp(STAmount::kMaxValue, STAmount::kMaxOffset, 0),
floats::kMaxIOU);
}
TEST_F(FloatFromMantExpImpl, MinExponent)
{
expectValue(
makeHost()->floatFromMantExp(1, Number::kMinExponent - floats::kNormalExp, 0),
floats::kMinExp);
}
TEST_F(FloatFromMantExpImpl, TenTimesTenthIsOne)
{
expectValue(makeHost()->floatFromMantExp(10, -1, 0), floats::kOne);
}
} // namespace xrpl::test

View File

@@ -0,0 +1,67 @@
#include <xrpl/protocol/IOUAmount.h>
#include <xrpl/protocol/Issue.h>
#include <xrpl/protocol/STAmount.h>
#include <xrpl/protocol/UintTypes.h>
#include <xrpl/tx/wasm/WasmCommon.h>
#include <gtest/gtest.h>
#include <helpers/Account.h>
#include <helpers/TxTest.h>
#include <tx/wasm/FloatFixture.h>
#include <tx/wasm/RealHostFixture.h>
#include <cstdint>
namespace xrpl::test {
struct FloatFromStAmountImpl : FloatTest
{
static Issue
usd()
{
return Issue{toCurrency("USD"), Account{"gw"}.id()};
}
};
TEST_F(FloatFromStAmountImpl, BadModeIsMalformed)
{
auto const amount = STAmount{XRP(100)};
expectError(makeHost()->floatFromSTAmount(amount, -1), HostFunctionError::FloatInputMalformed);
expectError(makeHost()->floatFromSTAmount(amount, 4), HostFunctionError::FloatInputMalformed);
}
TEST_F(FloatFromStAmountImpl, ZeroXrp)
{
expectValue(makeHost()->floatFromSTAmount(STAmount{XRP(0)}, 0), floats::kIntZero);
}
TEST_F(FloatFromStAmountImpl, MinusOneXrp)
{
// -1 XRP == -1'000'000 drops.
auto const expected = makeHost()->floatFromMantExp(-1'000'000, 0, 0);
ASSERT_TRUE(expected.has_value());
expectValue(makeHost()->floatFromSTAmount(STAmount{XRP(-1)}, 0), *expected);
}
TEST_F(FloatFromStAmountImpl, MaxDrops)
{
auto const expected = makeHost()->floatFromMantExp(9'223'372'036'854'776, 3, 0);
ASSERT_TRUE(expected.has_value());
expectValue(makeHost()->floatFromSTAmount(STAmount{noIssue(), kMax64}, 0), *expected);
}
TEST_F(FloatFromStAmountImpl, MinIou)
{
auto const amount = STAmount{
IOUAmount{static_cast<std::int64_t>(STAmount::kMinValue), STAmount::kMinOffset}, usd()};
expectValue(makeHost()->floatFromSTAmount(amount, 0), floats::kMinIOU);
}
TEST_F(FloatFromStAmountImpl, MaxIou)
{
auto const amount = STAmount{
IOUAmount{static_cast<std::int64_t>(STAmount::kMaxValue), STAmount::kMaxOffset}, usd()};
expectValue(makeHost()->floatFromSTAmount(amount, 0), floats::kMaxIOU);
}
} // namespace xrpl::test

View File

@@ -0,0 +1,39 @@
#include <xrpl/basics/Number.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/STNumber.h>
#include <xrpl/tx/wasm/WasmCommon.h>
#include <gtest/gtest.h>
#include <tx/wasm/FloatFixture.h>
#include <tx/wasm/RealHostFixture.h>
#include <cstdint>
#include <limits>
namespace xrpl::test {
struct FloatFromStNumberImpl : FloatTest
{
};
TEST_F(FloatFromStNumberImpl, BadModeIsMalformed)
{
auto const n = STNumber{sfNumber, Number(123, 0)};
expectError(makeHost()->floatFromSTNumber(n, -1), HostFunctionError::FloatInputMalformed);
expectError(makeHost()->floatFromSTNumber(n, 4), HostFunctionError::FloatInputMalformed);
}
TEST_F(FloatFromStNumberImpl, MaxUint)
{
auto const n = STNumber{
sfNumber, Number(std::numeric_limits<std::uint64_t>::max(), 0, Number::Normalized{})};
expectValue(makeHost()->floatFromSTNumber(n, 0), floats::kUintMax);
}
TEST_F(FloatFromStNumberImpl, MinusMaxExponent)
{
auto const n = STNumber{sfNumber, Number(-1, Number::kMaxExponent + floats::kNormalExp)};
expectValue(makeHost()->floatFromSTNumber(n, 0), floats::kMinusMaxExp);
}
} // namespace xrpl::test

View File

@@ -0,0 +1,33 @@
#include <xrpl/tx/wasm/WasmCommon.h>
#include <gtest/gtest.h>
#include <tx/wasm/FloatFixture.h>
#include <tx/wasm/RealHostFixture.h>
#include <cstdint>
#include <limits>
namespace xrpl::test {
struct FloatFromUintImpl : FloatTest
{
static constexpr std::uint64_t kMaxU64 = std::numeric_limits<std::uint64_t>::max();
};
TEST_F(FloatFromUintImpl, BadModeIsMalformed)
{
expectError(makeHost()->floatFromUint(0, -1), HostFunctionError::FloatInputMalformed);
expectError(makeHost()->floatFromUint(0, 4), HostFunctionError::FloatInputMalformed);
}
TEST_F(FloatFromUintImpl, Zero)
{
expectValue(makeHost()->floatFromUint(0, 0), floats::kIntZero);
}
TEST_F(FloatFromUintImpl, MaxUint)
{
expectValue(makeHost()->floatFromUint(kMaxU64, 0), floats::kUintMax);
}
} // namespace xrpl::test

View File

@@ -0,0 +1,55 @@
#include <xrpl/basics/Slice.h>
#include <xrpl/tx/wasm/WasmCommon.h>
#include <gtest/gtest.h>
#include <tx/wasm/FloatFixture.h>
#include <tx/wasm/RealHostFixture.h>
namespace xrpl::test {
struct FloatMultiplyImpl : FloatTest
{
};
TEST_F(FloatMultiplyImpl, BadModeIsMalformed)
{
expectError(
makeHost()->floatMultiply(slice(floats::kOne), slice(floats::kOne), -1),
HostFunctionError::FloatInputMalformed);
}
TEST_F(FloatMultiplyImpl, MalformedInput)
{
expectError(
makeHost()->floatMultiply(slice(floats::kOne), Slice{}, 0),
HostFunctionError::FloatInputMalformed);
}
TEST_F(FloatMultiplyImpl, OverflowIsComputationError)
{
expectError(
makeHost()->floatMultiply(slice(floats::kMax), slice(floats::kOneMore), 0),
HostFunctionError::FloatComputationError);
}
TEST_F(FloatMultiplyImpl, OneTimesOneIsOne)
{
expectValue(
makeHost()->floatMultiply(slice(floats::kOne), slice(floats::kOne), 0), floats::kOne);
}
TEST_F(FloatMultiplyImpl, ZeroTimesMaxIouIsZero)
{
expectValue(
makeHost()->floatMultiply(slice(floats::kIntZero), slice(floats::kMaxIOU), 0),
floats::kIntZero);
}
TEST_F(FloatMultiplyImpl, TenTimesPreMaxExpIsMaxExp)
{
expectValue(
makeHost()->floatMultiply(slice(floats::kTen), slice(floats::kPreMaxExp), 0),
floats::kMaxExp);
}
} // namespace xrpl::test

View File

@@ -0,0 +1,71 @@
#include <xrpl/basics/Number.h>
#include <xrpl/basics/Slice.h>
#include <xrpl/tx/wasm/WasmCommon.h>
#include <gtest/gtest.h>
#include <tx/wasm/FloatFixture.h>
#include <tx/wasm/RealHostFixture.h>
namespace xrpl::test {
struct FloatPowerImpl : FloatTest
{
};
TEST_F(FloatPowerImpl, BadModeIsMalformed)
{
expectError(
makeHost()->floatPower(slice(floats::kOne), 2, -1), HostFunctionError::FloatInputMalformed);
}
TEST_F(FloatPowerImpl, MalformedInput)
{
expectError(makeHost()->floatPower(Slice{}, 3, 0), HostFunctionError::FloatInputMalformed);
}
TEST_F(FloatPowerImpl, NegativeDegreeIsMalformed)
{
expectError(
makeHost()->floatPower(slice(floats::kOne), -2, 0), HostFunctionError::FloatInputMalformed);
}
TEST_F(FloatPowerImpl, OverflowIsComputationError)
{
expectError(
makeHost()->floatPower(slice(floats::kMax), 2, 0),
HostFunctionError::FloatComputationError);
}
TEST_F(FloatPowerImpl, DegreeTooLargeIsMalformed)
{
expectError(
makeHost()->floatPower(slice(floats::kMax), Number::kMaxExponent + 1, 0),
HostFunctionError::FloatInputMalformed);
}
TEST_F(FloatPowerImpl, DegreeZeroIsOne)
{
expectValue(makeHost()->floatPower(slice(floats::kMaxIOU), 0, 0), floats::kOne);
}
TEST_F(FloatPowerImpl, DegreeOneIsIdentity)
{
expectValue(makeHost()->floatPower(slice(floats::kMaxIOU), 1, 0), floats::kMaxIOU);
}
TEST_F(FloatPowerImpl, TenSquaredIsHundred)
{
auto const hundred = makeHost()->floatFromMantExp(100, 0, 0);
ASSERT_TRUE(hundred.has_value());
expectValue(makeHost()->floatPower(slice(floats::kTen), 2, 0), *hundred);
}
TEST_F(FloatPowerImpl, TenthSquaredIsHundredth)
{
auto const tenth = makeHost()->floatFromMantExp(1, -1, 0);
auto const hundredth = makeHost()->floatFromMantExp(1, -2, 0);
ASSERT_TRUE(tenth.has_value() && hundredth.has_value());
expectValue(makeHost()->floatPower(slice(*tenth), 2, 0), *hundredth);
}
} // namespace xrpl::test

View File

@@ -0,0 +1,63 @@
#include <xrpl/basics/Slice.h>
#include <xrpl/tx/wasm/WasmCommon.h>
#include <gtest/gtest.h>
#include <tx/wasm/FloatFixture.h>
#include <tx/wasm/RealHostFixture.h>
namespace xrpl::test {
struct FloatRootImpl : FloatTest
{
};
TEST_F(FloatRootImpl, BadModeIsMalformed)
{
expectError(
makeHost()->floatRoot(slice(floats::kOne), 2, -1), HostFunctionError::FloatInputMalformed);
}
TEST_F(FloatRootImpl, MalformedInput)
{
expectError(makeHost()->floatRoot(Slice{}, 3, 0), HostFunctionError::FloatInputMalformed);
}
TEST_F(FloatRootImpl, NegativeDegreeIsMalformed)
{
expectError(
makeHost()->floatRoot(slice(floats::kOne), -2, 0), HostFunctionError::FloatInputMalformed);
}
TEST_F(FloatRootImpl, RootOfZeroIsZero)
{
expectValue(makeHost()->floatRoot(slice(floats::kIntZero), 2, 0), floats::kIntZero);
}
TEST_F(FloatRootImpl, FirstRootIsIdentity)
{
expectValue(makeHost()->floatRoot(slice(floats::kMaxIOU), 1, 0), floats::kMaxIOU);
}
TEST_F(FloatRootImpl, SquareRootOfHundredIsTen)
{
auto const hundred = makeHost()->floatFromMantExp(100, 0, 0);
ASSERT_TRUE(hundred.has_value());
expectValue(makeHost()->floatRoot(slice(*hundred), 2, 0), floats::kTen);
}
TEST_F(FloatRootImpl, CubeRootOfThousandIsTen)
{
auto const thousand = makeHost()->floatFromMantExp(1000, 0, 0);
ASSERT_TRUE(thousand.has_value());
expectValue(makeHost()->floatRoot(slice(*thousand), 3, 0), floats::kTen);
}
TEST_F(FloatRootImpl, SquareRootOfHundredthIsTenth)
{
auto const hundredth = makeHost()->floatFromMantExp(1, -2, 0);
auto const tenth = makeHost()->floatFromMantExp(1, -1, 0);
ASSERT_TRUE(hundredth.has_value() && tenth.has_value());
expectValue(makeHost()->floatRoot(slice(*hundredth), 2, 0), *tenth);
}
} // namespace xrpl::test

View File

@@ -0,0 +1,49 @@
#include <xrpl/basics/Slice.h>
#include <xrpl/tx/wasm/WasmCommon.h>
#include <gtest/gtest.h>
#include <tx/wasm/FloatFixture.h>
#include <tx/wasm/RealHostFixture.h>
namespace xrpl::test {
struct FloatSubtractImpl : FloatTest
{
};
TEST_F(FloatSubtractImpl, BadModeIsMalformed)
{
expectError(
makeHost()->floatSubtract(slice(floats::kOne), slice(floats::kOne), -1),
HostFunctionError::FloatInputMalformed);
}
TEST_F(FloatSubtractImpl, MalformedInput)
{
expectError(
makeHost()->floatSubtract(slice(floats::kOne), Slice{}, 0),
HostFunctionError::FloatInputMalformed);
}
TEST_F(FloatSubtractImpl, MinusMaxExpMinusMaxIouIsMinusMaxExp)
{
expectValue(
makeHost()->floatSubtract(slice(floats::kMinusMaxExp), slice(floats::kMaxIOU), 0),
floats::kMinusMaxExp);
}
TEST_F(FloatSubtractImpl, MinMinusZeroIsMin)
{
expectValue(
makeHost()->floatSubtract(slice(floats::kIntMin), slice(floats::kIntZero), 0),
floats::kIntMin);
}
TEST_F(FloatSubtractImpl, ZeroMinusOneIsMinusOne)
{
expectValue(
makeHost()->floatSubtract(slice(floats::kIntZero), slice(floats::kOne), 0),
floats::kMinusOne);
}
} // namespace xrpl::test

View File

@@ -0,0 +1,70 @@
#include <xrpl/basics/Slice.h>
#include <xrpl/tx/wasm/WasmCommon.h>
#include <gtest/gtest.h>
#include <tx/wasm/FloatFixture.h>
#include <tx/wasm/RealHostFixture.h>
#include <cstdint>
namespace xrpl::test {
struct FloatToIntImpl : FloatTest
{
};
TEST_F(FloatToIntImpl, BadModeIsMalformed)
{
expectError(
makeHost()->floatToInt(slice(floats::kOne), -1), HostFunctionError::FloatInputMalformed);
expectError(
makeHost()->floatToInt(slice(floats::kOne), 4), HostFunctionError::FloatInputMalformed);
}
TEST_F(FloatToIntImpl, MalformedInputs)
{
expectError(makeHost()->floatToInt(Slice{}, 0), HostFunctionError::FloatInputMalformed);
}
TEST_F(FloatToIntImpl, Zero)
{
expectValue(makeHost()->floatToInt(slice(floats::kIntZero), 0), std::int64_t{0});
}
TEST_F(FloatToIntImpl, One)
{
expectValue(makeHost()->floatToInt(slice(floats::kOne), 0), std::int64_t{1});
}
TEST_F(FloatToIntImpl, MinusOne)
{
expectValue(makeHost()->floatToInt(slice(floats::kMinusOne), 0), std::int64_t{-1});
}
TEST_F(FloatToIntImpl, Max)
{
expectValue(makeHost()->floatToInt(slice(floats::kIntMax), 0), kMax64);
}
TEST_F(FloatToIntImpl, Min)
{
// floatIntMin rounds to -(2^63-1), i.e. -kMax64.
expectValue(makeHost()->floatToInt(slice(floats::kIntMin), 0), -kMax64);
}
TEST_F(FloatToIntImpl, OverflowsInt64IsComputationError)
{
expectError(
makeHost()->floatToInt(slice(floats::kUintMax), 0),
HostFunctionError::FloatComputationError);
}
TEST_F(FloatToIntImpl, PiRoundsByMode)
{
expectValue(makeHost()->floatToInt(slice(floats::kPi), 0), std::int64_t{3}); // ToNearest
expectValue(makeHost()->floatToInt(slice(floats::kPi), 1), std::int64_t{3}); // TowardsZero
expectValue(makeHost()->floatToInt(slice(floats::kPi), 2), std::int64_t{3}); // Downward
expectValue(makeHost()->floatToInt(slice(floats::kPi), 3), std::int64_t{4}); // Upward
}
} // namespace xrpl::test

View File

@@ -0,0 +1,80 @@
#include <xrpl/basics/Number.h>
#include <xrpl/basics/Slice.h>
#include <xrpl/tx/wasm/WasmCommon.h>
#include <gtest/gtest.h>
#include <tx/wasm/FloatFixture.h>
#include <tx/wasm/RealHostFixture.h>
#include <cstdint>
#include <limits>
namespace xrpl::test {
struct FloatToMantExpImpl : FloatTest
{
static constexpr std::int32_t kExpMin = std::numeric_limits<std::int32_t>::min();
static FloatPair
pair(std::int64_t mantissa, std::int32_t exponent)
{
return FloatPair{mantissa, exponent};
}
};
TEST_F(FloatToMantExpImpl, MalformedInput)
{
expectError(makeHost()->floatToMantExp(Slice{}), HostFunctionError::FloatInputMalformed);
}
TEST_F(FloatToMantExpImpl, Zero)
{
expectValue(makeHost()->floatToMantExp(slice(floats::kIntZero)), pair(0, kExpMin));
}
TEST_F(FloatToMantExpImpl, One)
{
expectValue(
makeHost()->floatToMantExp(slice(floats::kOne)),
pair(1'000'000'000'000'000'000, -floats::kNormalExp));
}
TEST_F(FloatToMantExpImpl, MinusOne)
{
expectValue(
makeHost()->floatToMantExp(slice(floats::kMinusOne)),
pair(-1'000'000'000'000'000'000, -floats::kNormalExp));
}
TEST_F(FloatToMantExpImpl, Ten)
{
expectValue(
makeHost()->floatToMantExp(slice(floats::kTen)),
pair(1'000'000'000'000'000'000, -floats::kNormalExp + 1));
}
TEST_F(FloatToMantExpImpl, Pi)
{
expectValue(
makeHost()->floatToMantExp(slice(floats::kPi)),
pair(3'141'592'653'589'793'000, -floats::kNormalExp));
}
TEST_F(FloatToMantExpImpl, IntMax)
{
expectValue(makeHost()->floatToMantExp(slice(floats::kIntMax)), pair(kMax64, 0));
}
TEST_F(FloatToMantExpImpl, IntMin)
{
expectValue(makeHost()->floatToMantExp(slice(floats::kIntMin)), pair(-kMax64, 0));
}
TEST_F(FloatToMantExpImpl, Max)
{
expectValue(
makeHost()->floatToMantExp(slice(floats::kMax)),
pair(Number::kMaxRep, Number::kMaxExponent));
}
} // namespace xrpl::test

View File

@@ -0,0 +1,54 @@
#include <xrpl/basics/base_uint.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/tx/wasm/WasmCommon.h>
#include <gtest/gtest.h>
#include <helpers/Account.h>
#include <tx/wasm/NFTFixture.h>
#include <tx/wasm/RealHostFixture.h>
#include <string_view>
namespace xrpl::test {
struct GetNFTImpl : NFTTest
{
};
TEST_F(GetNFTImpl, UnsetAccountIsInvalidAccount)
{
auto const issuer = Account{"issuer"};
expectError(
makeHost()->getNFT(AccountID{}, makeNftId(issuer.id())), HostFunctionError::InvalidAccount);
}
TEST_F(GetNFTImpl, ZeroIdIsInvalidParams)
{
auto const owner = fund("owner");
expectError(makeHost()->getNFT(owner.id(), uint256{}), HostFunctionError::InvalidParams);
}
TEST_F(GetNFTImpl, MissingTokenIsNotFound)
{
auto const owner = fund("owner");
expectError(
makeHost()->getNFT(owner.id(), makeNftId(owner.id())),
HostFunctionError::LedgerObjNotFound);
}
TEST_F(GetNFTImpl, ReturnsUri)
{
auto const owner = fund("owner");
auto const uri = std::string_view{"https://example.com/nft"};
auto const id = mintNFT(owner, uri);
expectValue(makeHost()->getNFT(owner.id(), id), toBytes(uri));
}
TEST_F(GetNFTImpl, WithoutUriFieldNotFound)
{
auto const owner = fund("owner");
auto const id = mintNFT(owner);
expectError(makeHost()->getNFT(owner.id(), id), HostFunctionError::FieldNotFound);
}
} // namespace xrpl::test

View File

@@ -4,7 +4,6 @@
#include <gtest/gtest.h>
#include <tx/wasm/RealHostFixture.h>
#include <expected>
#include <string_view>
namespace xrpl::test {
@@ -17,34 +16,30 @@ TEST_F(IsAmendmentEnabledImpl, EnabledAmendmentByIdReadsOne)
{
auto const id = getRegisteredFeature("TokenEscrow");
ASSERT_TRUE(id.has_value());
auto const result = host().isAmendmentEnabled(id.value_or(uint256{}));
ASSERT_TRUE(result.has_value());
EXPECT_EQ(*result, 1);
auto const result = makeHost()->isAmendmentEnabled(id.value_or(uint256{}));
expectValue(result, 1);
}
TEST_F(IsAmendmentEnabledImpl, EnabledAmendmentByNameReadsOne)
{
auto const result = host().isAmendmentEnabled(std::string_view{"TokenEscrow"});
auto const result = makeHost()->isAmendmentEnabled(std::string_view{"TokenEscrow"});
ASSERT_TRUE(result.has_value());
EXPECT_EQ(*result, 1);
expectValue(result, 1);
}
TEST_F(IsAmendmentEnabledImpl, UnknownAmendmentByIdReadsZero)
{
auto const result = host().isAmendmentEnabled(
auto const result = makeHost()->isAmendmentEnabled(
uint256{"DEADBEEF00000000000000000000000000000000000000000000000000000000"});
ASSERT_TRUE(result.has_value());
EXPECT_EQ(*result, 0);
expectValue(result, 0);
}
TEST_F(IsAmendmentEnabledImpl, UnknownAmendmentNameReadsZero)
{
auto const result = host().isAmendmentEnabled(std::string_view{"DEADBEEF"});
auto const result = makeHost()->isAmendmentEnabled(std::string_view{"DEADBEEF"});
ASSERT_TRUE(result.has_value());
EXPECT_EQ(*result, 0);
expectValue(result, 0);
}
} // namespace xrpl::test

View File

@@ -0,0 +1,59 @@
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/tx/wasm/WasmCommon.h>
#include <gtest/gtest.h>
#include <helpers/Account.h>
#include <tx/wasm/RealHostFixture.h>
#include <utility>
namespace xrpl::test {
struct LedgerObjArrayLenImpl : WasmImplTest
{
using WasmImplTest::makeHost;
WasmHost
makeHost(Account const& acct)
{
makeSignerList(acct, 2, {{Account{"alice"}, 1}, {Account{"becky"}, 1}});
auto assembler = bareTx();
auto h = makeHost(keylet::account(AccountID{}), assembler.type, std::move(assembler.build));
h->cacheLedgerObj(keylet::signerList(acct.id()).key, 1);
return h;
}
};
TEST_F(LedgerObjArrayLenImpl, SignerEntriesLength)
{
auto const owner = fund("owner");
auto h = makeHost(owner);
expectValue(h->getLedgerObjArrayLen(1, sfSignerEntries), 2);
}
TEST_F(LedgerObjArrayLenImpl, NonArrayFieldNoArray)
{
auto const owner = fund("owner");
auto h = makeHost(owner);
expectError(h->getLedgerObjArrayLen(1, sfAccount), HostFunctionError::NoArray);
}
TEST_F(LedgerObjArrayLenImpl, MissingArrayFieldNotFound)
{
auto const owner = fund("owner");
auto h = makeHost(owner);
expectError(h->getLedgerObjArrayLen(1, sfMemos), HostFunctionError::FieldNotFound);
}
TEST_F(LedgerObjArrayLenImpl, SlotErrors)
{
auto const owner = fund("owner");
auto h = makeHost(owner);
expectError(h->getLedgerObjArrayLen(0, sfSignerEntries), HostFunctionError::SlotOutRange);
expectError(h->getLedgerObjArrayLen(257, sfSignerEntries), HostFunctionError::SlotOutRange);
expectError(h->getLedgerObjArrayLen(2, sfSignerEntries), HostFunctionError::EmptySlot);
}
} // namespace xrpl::test

View File

@@ -0,0 +1,80 @@
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/tx/wasm/WasmCommon.h>
#include <gtest/gtest.h>
#include <helpers/Account.h>
#include <helpers/TxTest.h>
#include <tx/wasm/RealHostFixture.h>
#include <cstdint>
#include <utility>
namespace xrpl::test {
struct LedgerObjFieldImpl : WasmImplTest
{
template <typename Functor>
void
checkCachedField(
Account const& acct,
std::uint32_t index,
SField const& field,
TxAssembler assembler,
Functor&& f)
{
auto const accountKeylet = keylet::account(acct.id());
auto h = makeHost(accountKeylet, assembler.type, std::move(assembler.build));
h->cacheLedgerObj(accountKeylet.key, 1);
expectValue(h->getLedgerObjField(index, field), f());
}
void
checkCachedFieldError(
Account const& acct,
std::uint32_t index,
SField const& field,
TxAssembler assembler,
HostFunctionError error)
{
auto const accountKeylet = keylet::account(acct.id());
auto h = makeHost(accountKeylet, assembler.type, std::move(assembler.build));
h->cacheLedgerObj(accountKeylet.key, 1);
expectError(h->getLedgerObjField(index, field), error);
}
};
TEST_F(LedgerObjFieldImpl, MatchesAccount)
{
auto const owner = fund("owner");
checkCachedField(owner, 1, sfAccount, bareTx(), [&] { return toBytes(owner.id()); });
}
TEST_F(LedgerObjFieldImpl, MatchesBalance)
{
auto const owner = fund("owner");
auto const root = ledger.getOpenLedger().read(keylet::account(owner.id()));
checkCachedField(
owner, 1, sfBalance, bareTx(), [&] { return toBytes(root->getFieldAmount(sfBalance)); });
}
TEST_F(LedgerObjFieldImpl, MatchesAccountSlotOutOfRange)
{
auto const owner = fund("owner");
checkCachedFieldError(owner, 0, sfAccount, bareTx(), HostFunctionError::SlotOutRange);
checkCachedFieldError(owner, 257, sfAccount, bareTx(), HostFunctionError::SlotOutRange);
}
TEST_F(LedgerObjFieldImpl, MatchesAccountEmptySlot)
{
auto const owner = fund("owner");
checkCachedFieldError(owner, 2, sfAccount, bareTx(), HostFunctionError::EmptySlot);
}
TEST_F(LedgerObjFieldImpl, MatchesOwnerFieldNotFound)
{
auto const owner = fund("owner");
checkCachedFieldError(owner, 1, sfOwner, bareTx(), HostFunctionError::FieldNotFound);
}
} // namespace xrpl::test

View File

@@ -0,0 +1,79 @@
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/tx/wasm/WasmCommon.h>
#include <gtest/gtest.h>
#include <helpers/Account.h>
#include <tx/wasm/RealHostFixture.h>
#include <utility>
namespace xrpl::test {
struct LedgerObjNestedArrayLenImpl : WasmImplTest
{
using WasmImplTest::makeHost;
WasmHost
makeHost(Account const& acct)
{
makeSignerList(acct, 2, {{Account{"alice"}, 1}, {Account{"becky"}, 1}});
auto assembler = bareTx();
auto h = makeHost(keylet::account(AccountID{}), assembler.type, std::move(assembler.build));
h->cacheLedgerObj(keylet::signerList(acct.id()).key, 1);
return h;
}
};
TEST_F(LedgerObjNestedArrayLenImpl, SignerEntriesLength)
{
auto const owner = fund("owner");
auto h = makeHost(owner);
expectValue(h->getLedgerObjNestedArrayLen(1, FieldLocator{{sfSignerEntries.getCode()}}), 2);
}
TEST_F(LedgerObjNestedArrayLenImpl, NonArrayFieldNoArray)
{
auto const owner = fund("owner");
auto h = makeHost(owner);
expectError(
h->getLedgerObjNestedArrayLen(1, FieldLocator{{sfSignerQuorum.getCode()}}),
HostFunctionError::NoArray);
}
TEST_F(LedgerObjNestedArrayLenImpl, MissingFieldNotFound)
{
auto const owner = fund("owner");
auto h = makeHost(owner);
expectError(
h->getLedgerObjNestedArrayLen(1, FieldLocator{{sfSigners.getCode()}}),
HostFunctionError::FieldNotFound);
}
TEST_F(LedgerObjNestedArrayLenImpl, SlotErrors)
{
auto const owner = fund("owner");
auto h = makeHost(owner);
expectError(
h->getLedgerObjNestedArrayLen(0, FieldLocator{{sfSignerEntries.getCode()}}),
HostFunctionError::SlotOutRange);
expectError(
h->getLedgerObjNestedArrayLen(257, FieldLocator{{sfSignerEntries.getCode()}}),
HostFunctionError::SlotOutRange);
expectError(
h->getLedgerObjNestedArrayLen(2, FieldLocator{{sfSignerEntries.getCode()}}),
HostFunctionError::EmptySlot);
}
TEST_F(LedgerObjNestedArrayLenImpl, NestIntoNonContainerMalformed)
{
auto const owner = fund("owner");
auto h = makeHost(owner);
expectError(
h->getLedgerObjNestedArrayLen(
1, FieldLocator{{sfSignerQuorum.getCode(), 0, sfAccount.getCode()}}),
HostFunctionError::LocatorMalformed);
}
} // namespace xrpl::test

View File

@@ -0,0 +1,155 @@
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/STArray.h>
#include <xrpl/protocol/STObject.h>
#include <xrpl/tx/wasm/WasmCommon.h>
#include <gtest/gtest.h>
#include <helpers/Account.h>
#include <tx/wasm/RealHostFixture.h>
#include <cstdint>
#include <utility>
namespace xrpl::test {
struct LedgerObjNestedFieldImpl : WasmImplTest
{
using WasmImplTest::makeHost;
WasmHost
makeHost(Account const& acct)
{
makeSignerList(acct, 2, {{Account{"alice"}, 1}, {Account{"becky"}, 1}});
auto assembler = bareTx();
auto h = makeHost(keylet::account(AccountID{}), assembler.type, std::move(assembler.build));
h->cacheLedgerObj(keylet::signerList(acct.id()).key, 1);
return h;
}
};
TEST_F(LedgerObjNestedFieldImpl, MatchesNestedSignerAccountsByIndex)
{
auto const owner = fund("owner");
auto h = makeHost(owner);
auto const sle = ledger.getOpenLedger().read(keylet::signerList(owner.id()));
ASSERT_NE(sle, nullptr);
auto const& entries = sle->getFieldArray(sfSignerEntries);
expectValue(
h->getLedgerObjNestedField(
1, FieldLocator{{sfSignerEntries.getCode(), 0, sfAccount.getCode()}}),
toBytes(entries[0].getAccountID(sfAccount)));
expectValue(
h->getLedgerObjNestedField(
1, FieldLocator{{sfSignerEntries.getCode(), 1, sfAccount.getCode()}}),
toBytes(entries[1].getAccountID(sfAccount)));
EXPECT_NE(entries[0].getAccountID(sfAccount), entries[1].getAccountID(sfAccount));
}
TEST_F(LedgerObjNestedFieldImpl, MatchesNestedSignerWeight)
{
auto const owner = fund("owner");
auto h = makeHost(owner);
expectValue(
h->getLedgerObjNestedField(
1, FieldLocator{{sfSignerEntries.getCode(), 0, sfSignerWeight.getCode()}}),
toBytes(static_cast<std::uint16_t>(1)));
}
TEST_F(LedgerObjNestedFieldImpl, MatchesBaseSignerQuorum)
{
auto const owner = fund("owner");
auto h = makeHost(owner);
expectValue(
h->getLedgerObjNestedField(1, FieldLocator{{sfSignerQuorum.getCode()}}),
toBytes(static_cast<std::uint32_t>(2)));
}
TEST_F(LedgerObjNestedFieldImpl, MissingFieldNotFound)
{
auto const owner = fund("owner");
auto h = makeHost(owner);
auto const err = HostFunctionError::FieldNotFound;
expectError(
h->getLedgerObjNestedField(1, FieldLocator{{sfSigners.getCode(), 0, sfAccount.getCode()}}),
err);
expectError(
h->getLedgerObjNestedField(
1, FieldLocator{{sfSignerEntries.getCode(), 0, sfDestination.getCode()}}),
err);
}
TEST_F(LedgerObjNestedFieldImpl, IndexOutOfBounds)
{
auto const owner = fund("owner");
auto h = makeHost(owner);
auto const err = HostFunctionError::IndexOutOfBounds;
expectError(
h->getLedgerObjNestedField(
1, FieldLocator{{sfSignerEntries.getCode(), 2, sfAccount.getCode()}}),
err);
expectError(
h->getLedgerObjNestedField(
1, FieldLocator{{sfSignerEntries.getCode(), -1, sfAccount.getCode()}}),
err);
}
TEST_F(LedgerObjNestedFieldImpl, UnknownFieldCodeInvalidField)
{
auto const owner = fund("owner");
auto h = makeHost(owner);
auto const err = HostFunctionError::InvalidField;
expectError(
h->getLedgerObjNestedField(
1, FieldLocator{{fieldCode(99999, 99999), 0, sfAccount.getCode()}}),
err);
expectError(
h->getLedgerObjNestedField(
1, FieldLocator{{sfSignerEntries.getCode(), 0, fieldCode(99999, 99999)}}),
err);
}
TEST_F(LedgerObjNestedFieldImpl, SlotErrors)
{
auto const owner = fund("owner");
auto h = makeHost(owner);
// 0 and 257 are outside the 1..256 slot range.
expectError(
h->getLedgerObjNestedField(0, FieldLocator{{sfSignerQuorum.getCode()}}),
HostFunctionError::SlotOutRange);
expectError(
h->getLedgerObjNestedField(257, FieldLocator{{sfSignerQuorum.getCode()}}),
HostFunctionError::SlotOutRange);
// Slot 2 is in range but nothing was cached there.
expectError(
h->getLedgerObjNestedField(2, FieldLocator{{sfSignerQuorum.getCode()}}),
HostFunctionError::EmptySlot);
}
TEST_F(LedgerObjNestedFieldImpl, ContainerWithoutIndexNotLeaf)
{
auto const owner = fund("owner");
auto h = makeHost(owner);
expectError(
h->getLedgerObjNestedField(1, FieldLocator{{sfSignerEntries.getCode()}}),
HostFunctionError::NotLeafField);
}
TEST_F(LedgerObjNestedFieldImpl, NestIntoNonContainerMalformed)
{
auto const owner = fund("owner");
auto h = makeHost(owner);
expectError(
h->getLedgerObjNestedField(
1, FieldLocator{{sfSignerQuorum.getCode(), 0, sfAccount.getCode()}}),
HostFunctionError::LocatorMalformed);
}
} // namespace xrpl::test

View File

@@ -1,8 +1,6 @@
#include <gtest/gtest.h>
#include <tx/wasm/RealHostFixture.h>
#include <expected>
namespace xrpl::test {
struct LedgerSqnImpl : WasmImplTest
@@ -11,9 +9,7 @@ struct LedgerSqnImpl : WasmImplTest
TEST_F(LedgerSqnImpl, MatchesLedger)
{
auto const result = host().getLedgerSqn();
ASSERT_TRUE(result.has_value());
EXPECT_EQ(*result, ledger.getOpenLedger().header().seq);
expectValue(makeHost()->getLedgerSqn(), ledger.getOpenLedger().header().seq);
}
} // namespace xrpl::test

View File

@@ -4,12 +4,8 @@
#include <gtest/gtest.h>
#include <helpers/Account.h>
#include <helpers/TxTest.h>
#include <tx/wasm/RealHostFixture.h>
#include <expected>
#include <iterator>
namespace xrpl::test {
struct MptokenIssuanceKeyletImpl : WasmImplTest
@@ -18,21 +14,17 @@ struct MptokenIssuanceKeyletImpl : WasmImplTest
TEST_F(MptokenIssuanceKeyletImpl, MatchesMptokenIssuanceKeyletFunction)
{
auto const owner = Account{"owner"};
ledger.createAccount(owner, XRP(1000));
auto const owner = fund("owner");
auto const expected = keylet::mptokenIssuance(makeMptID(1u, owner.id()));
auto const expectedBytes = Bytes{std::begin(expected.key), std::end(expected.key)};
auto const result = host().mptokenIssuanceKeylet(owner.id(), 1u);
ASSERT_TRUE(result.has_value());
EXPECT_EQ(*result, expectedBytes);
expectKeyletMatches(
makeHost()->mptokenIssuanceKeylet(owner.id(), 1u),
keylet::mptokenIssuance(makeMptID(1u, owner.id())));
}
TEST_F(MptokenIssuanceKeyletImpl, InvalidAccount)
{
auto result = host().mptokenIssuanceKeylet(AccountID{}, 1u);
ASSERT_TRUE(!result.has_value());
EXPECT_EQ(result.error(), HostFunctionError::InvalidAccount);
expectError(
makeHost()->mptokenIssuanceKeylet(AccountID{}, 1u), HostFunctionError::InvalidAccount);
}
} // namespace xrpl::test

View File

@@ -4,12 +4,8 @@
#include <gtest/gtest.h>
#include <helpers/Account.h>
#include <helpers/TxTest.h>
#include <tx/wasm/RealHostFixture.h>
#include <expected>
#include <iterator>
namespace xrpl::test {
struct MptokenKeyletImpl : WasmImplTest
@@ -18,37 +14,27 @@ struct MptokenKeyletImpl : WasmImplTest
TEST_F(MptokenKeyletImpl, MatchesMptokenKeyletFunction)
{
auto const owner = Account{"owner"};
ledger.createAccount(owner, XRP(1000));
auto const anotherAccount = Account{"account"};
ledger.createAccount(anotherAccount, XRP(1000));
auto const owner = fund("owner");
auto const anotherAccount = fund("account");
auto const mpt = makeMptID(1u, owner.id());
auto const expected = keylet::mptoken(mpt, anotherAccount.id());
auto const expectedBytes = Bytes{std::begin(expected.key), std::end(expected.key)};
auto const result = host().mptokenKeylet(mpt, anotherAccount.id());
ASSERT_TRUE(result.has_value());
EXPECT_EQ(*result, expectedBytes);
expectKeyletMatches(
makeHost()->mptokenKeylet(mpt, anotherAccount.id()),
keylet::mptoken(mpt, anotherAccount.id()));
}
TEST_F(MptokenKeyletImpl, InvalidMpt)
{
auto const owner = Account{"owner"};
ledger.createAccount(owner, XRP(1000));
auto result = host().mptokenKeylet(MPTID{}, owner.id());
ASSERT_TRUE(!result.has_value());
EXPECT_EQ(result.error(), HostFunctionError::InvalidParams);
auto const owner = fund("owner");
expectError(makeHost()->mptokenKeylet(MPTID{}, owner.id()), HostFunctionError::InvalidParams);
}
TEST_F(MptokenKeyletImpl, InvalidAccount)
{
auto const owner = Account{"owner"};
ledger.createAccount(owner, XRP(1000));
auto const owner = fund("owner");
auto const mpt = makeMptID(1u, owner.id());
auto result = host().mptokenKeylet(mpt, AccountID{});
ASSERT_TRUE(!result.has_value());
EXPECT_EQ(result.error(), HostFunctionError::InvalidAccount);
expectError(makeHost()->mptokenKeylet(mpt, AccountID{}), HostFunctionError::InvalidAccount);
}
} // namespace xrpl::test

View File

@@ -1,39 +0,0 @@
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/SeqProxy.h>
#include <xrpl/tx/wasm/WasmCommon.h>
#include <gtest/gtest.h>
#include <helpers/Account.h>
#include <helpers/TxTest.h>
#include <tx/wasm/RealHostFixture.h>
#include <expected>
#include <iterator>
namespace xrpl::test {
struct NFTImpl : WasmImplTest
{
};
TEST_F(NFTImpl, MatchesVaultFunction)
{
auto const owner = Account{"owner"};
ledger.createAccount(owner, XRP(1000));
auto const expected = keylet::vault(owner.id(), SeqProxy::rawSequence(1u));
auto const expectedBytes = Bytes{std::begin(expected.key), std::end(expected.key)};
auto const result = host().vaultKeylet(owner.id(), 1u);
ASSERT_TRUE(result.has_value());
EXPECT_EQ(*result, expectedBytes);
}
TEST_F(NFTImpl, InvalidAccount)
{
auto result = host().vaultKeylet(AccountID{}, 1u);
ASSERT_TRUE(!result.has_value());
EXPECT_EQ(result.error(), HostFunctionError::InvalidAccount);
}
} // namespace xrpl::test

View File

@@ -0,0 +1,26 @@
#include <gtest/gtest.h>
#include <helpers/Account.h>
#include <tx/wasm/NFTFixture.h>
#include <tx/wasm/RealHostFixture.h>
#include <cstdint>
namespace xrpl::test {
struct NFTFlagsImpl : NFTTest
{
};
TEST_F(NFTFlagsImpl, FlagsDecodeFromId)
{
auto const issuer = Account{"issuer"};
expectValue(makeHost()->getNFTFlags(makeNftId(issuer.id())), std::int32_t{kFlags});
}
TEST_F(NFTFlagsImpl, FlagsShouldBeZeroWithZeroNftId)
{
expectValue(makeHost()->getNFTFlags(uint256{}), std::int32_t{});
}
} // namespace xrpl::test

View File

@@ -0,0 +1,28 @@
#include <xrpl/protocol/AccountID.h>
#include <xrpl/tx/wasm/WasmCommon.h>
#include <gtest/gtest.h>
#include <helpers/Account.h>
#include <tx/wasm/NFTFixture.h>
#include <tx/wasm/RealHostFixture.h>
#include <string_view>
namespace xrpl::test {
struct NFTIssuerImpl : NFTTest
{
};
TEST_F(NFTIssuerImpl, IssuerDecodesFromId)
{
auto const issuer = Account{"issuer"};
expectValue(makeHost()->getNFTIssuer(makeNftId(issuer.id())), toBytes(issuer.id()));
}
TEST_F(NFTIssuerImpl, IssuerZeroIsInvalidParams)
{
expectError(makeHost()->getNFTIssuer(makeNftId(AccountID{})), HostFunctionError::InvalidParams);
}
} // namespace xrpl::test

View File

@@ -0,0 +1,26 @@
#include <gtest/gtest.h>
#include <helpers/Account.h>
#include <tx/wasm/NFTFixture.h>
#include <tx/wasm/RealHostFixture.h>
#include <cstdint>
namespace xrpl::test {
struct NFTSequenceImpl : NFTTest
{
};
TEST_F(NFTSequenceImpl, SequenceDecodesFromId)
{
auto const issuer = Account{"issuer"};
expectValue(makeHost()->getNFTSequence(makeNftId(issuer.id())), kSequence);
}
TEST_F(NFTSequenceImpl, SequenceShouldBeZeroWithZeroNftId)
{
expectValue(makeHost()->getNFTSequence(uint256{}), std::int32_t{});
}
} // namespace xrpl::test

View File

@@ -0,0 +1,19 @@
#include <gtest/gtest.h>
#include <helpers/Account.h>
#include <tx/wasm/NFTFixture.h>
#include <tx/wasm/RealHostFixture.h>
namespace xrpl::test {
struct NFTTaxonImpl : NFTTest
{
};
TEST_F(NFTTaxonImpl, TaxonDecodesFromId)
{
auto const issuer = Account{"issuer"};
expectValue(makeHost()->getNFTTaxon(makeNftId(issuer.id())), kTaxon);
}
} // namespace xrpl::test

View File

@@ -0,0 +1,26 @@
#include <gtest/gtest.h>
#include <helpers/Account.h>
#include <tx/wasm/NFTFixture.h>
#include <tx/wasm/RealHostFixture.h>
#include <cstdint>
namespace xrpl::test {
struct NFTTransferFeeImpl : NFTTest
{
};
TEST_F(NFTTransferFeeImpl, TransferFeeDecodesFromId)
{
auto const issuer = Account{"issuer"};
expectValue(makeHost()->getNFTTransferFee(makeNftId(issuer.id())), std::int32_t{kFee});
}
TEST_F(NFTTransferFeeImpl, TransferFeeShouldBeZeroWithZeroNftId)
{
expectValue(makeHost()->getNFTTransferFee(uint256{}), std::int32_t{});
}
} // namespace xrpl::test

View File

@@ -5,12 +5,8 @@
#include <gtest/gtest.h>
#include <helpers/Account.h>
#include <helpers/TxTest.h>
#include <tx/wasm/RealHostFixture.h>
#include <expected>
#include <iterator>
namespace xrpl::test {
struct NftokenOfferKeyletImpl : WasmImplTest
@@ -19,21 +15,16 @@ struct NftokenOfferKeyletImpl : WasmImplTest
TEST_F(NftokenOfferKeyletImpl, MatchesNftokenOfferFunction)
{
auto const owner = Account{"owner"};
ledger.createAccount(owner, XRP(1000));
auto const owner = fund("owner");
auto const expected = keylet::nftokenOffer(owner.id(), SeqProxy::rawSequence(1u));
auto const expectedBytes = Bytes{std::begin(expected.key), std::end(expected.key)};
auto const result = host().nftokenOfferKeylet(owner.id(), 1u);
ASSERT_TRUE(result.has_value());
EXPECT_EQ(*result, expectedBytes);
expectKeyletMatches(
makeHost()->nftokenOfferKeylet(owner.id(), 1u),
keylet::nftokenOffer(owner.id(), SeqProxy::rawSequence(1u)));
}
TEST_F(NftokenOfferKeyletImpl, InvalidAccount)
{
auto result = host().nftokenOfferKeylet(AccountID{}, 1u);
ASSERT_TRUE(!result.has_value());
EXPECT_EQ(result.error(), HostFunctionError::InvalidAccount);
expectError(makeHost()->nftokenOfferKeylet(AccountID{}, 1u), HostFunctionError::InvalidAccount);
}
} // namespace xrpl::test

View File

@@ -5,12 +5,8 @@
#include <gtest/gtest.h>
#include <helpers/Account.h>
#include <helpers/TxTest.h>
#include <tx/wasm/RealHostFixture.h>
#include <expected>
#include <iterator>
namespace xrpl::test {
struct OfferKeyletImpl : WasmImplTest
@@ -19,21 +15,16 @@ struct OfferKeyletImpl : WasmImplTest
TEST_F(OfferKeyletImpl, MatchesOfferFunction)
{
auto const owner = Account{"owner"};
ledger.createAccount(owner, XRP(1000));
auto const owner = fund("owner");
auto const expected = keylet::offer(owner.id(), SeqProxy::rawSequence(1u));
auto const expectedBytes = Bytes{std::begin(expected.key), std::end(expected.key)};
auto const result = host().offerKeylet(owner.id(), 1u);
ASSERT_TRUE(result.has_value());
EXPECT_EQ(*result, expectedBytes);
expectKeyletMatches(
makeHost()->offerKeylet(owner.id(), 1u),
keylet::offer(owner.id(), SeqProxy::rawSequence(1u)));
}
TEST_F(OfferKeyletImpl, InvalidAccount)
{
auto result = host().offerKeylet(AccountID{}, 1u);
ASSERT_TRUE(!result.has_value());
EXPECT_EQ(result.error(), HostFunctionError::InvalidAccount);
expectError(makeHost()->offerKeylet(AccountID{}, 1u), HostFunctionError::InvalidAccount);
}
} // namespace xrpl::test

View File

@@ -4,12 +4,8 @@
#include <gtest/gtest.h>
#include <helpers/Account.h>
#include <helpers/TxTest.h>
#include <tx/wasm/RealHostFixture.h>
#include <expected>
#include <iterator>
namespace xrpl::test {
struct OracleKeyletImpl : WasmImplTest
@@ -18,21 +14,14 @@ struct OracleKeyletImpl : WasmImplTest
TEST_F(OracleKeyletImpl, MatchesOracleFunction)
{
auto const owner = Account{"owner"};
ledger.createAccount(owner, XRP(1000));
auto const owner = fund("owner");
auto const expected = keylet::oracle(owner.id(), 1u);
auto const expectedBytes = Bytes{std::begin(expected.key), std::end(expected.key)};
auto const result = host().oracleKeylet(owner.id(), 1u);
ASSERT_TRUE(result.has_value());
EXPECT_EQ(*result, expectedBytes);
expectKeyletMatches(makeHost()->oracleKeylet(owner.id(), 1u), keylet::oracle(owner.id(), 1u));
}
TEST_F(OracleKeyletImpl, InvalidAccount)
{
auto result = host().oracleKeylet(AccountID{}, 1u);
ASSERT_TRUE(!result.has_value());
EXPECT_EQ(result.error(), HostFunctionError::InvalidAccount);
expectError(makeHost()->oracleKeylet(AccountID{}, 1u), HostFunctionError::InvalidAccount);
}
} // namespace xrpl::test

View File

@@ -1,8 +1,6 @@
#include <gtest/gtest.h>
#include <tx/wasm/RealHostFixture.h>
#include <expected>
namespace xrpl::test {
struct ParentLedgerHashImpl : WasmImplTest
@@ -11,9 +9,7 @@ struct ParentLedgerHashImpl : WasmImplTest
TEST_F(ParentLedgerHashImpl, MatchesLedger)
{
auto const result = host().getParentLedgerHash();
ASSERT_TRUE(result.has_value());
EXPECT_EQ(*result, ledger.getOpenLedger().header().parentHash);
expectValue(makeHost()->getParentLedgerHash(), ledger.getOpenLedger().header().parentHash);
}
} // namespace xrpl::test

View File

@@ -1,8 +1,6 @@
#include <gtest/gtest.h>
#include <tx/wasm/RealHostFixture.h>
#include <expected>
namespace xrpl::test {
struct ParentLedgerTimeImpl : WasmImplTest
@@ -11,9 +9,9 @@ struct ParentLedgerTimeImpl : WasmImplTest
TEST_F(ParentLedgerTimeImpl, MatchesLedger)
{
auto const result = host().getParentLedgerTime();
ASSERT_TRUE(result.has_value());
EXPECT_EQ(*result, ledger.getOpenLedger().parentCloseTime().time_since_epoch().count());
expectValue(
makeHost()->getParentLedgerTime(),
ledger.getOpenLedger().parentCloseTime().time_since_epoch().count());
}
} // namespace xrpl::test

View File

@@ -5,12 +5,8 @@
#include <gtest/gtest.h>
#include <helpers/Account.h>
#include <helpers/TxTest.h>
#include <tx/wasm/RealHostFixture.h>
#include <expected>
#include <iterator>
namespace xrpl::test {
struct PaychannelKeyletImpl : WasmImplTest
@@ -19,41 +15,33 @@ struct PaychannelKeyletImpl : WasmImplTest
TEST_F(PaychannelKeyletImpl, MatchesPaychannelFunction)
{
auto const owner = Account{"owner"};
ledger.createAccount(owner, XRP(1000));
auto const destination = Account{"destination"};
ledger.createAccount(destination, XRP(1000));
auto const owner = fund("owner");
auto const destination = fund("destination");
auto const expected =
keylet::payChannel(owner.id(), destination.id(), SeqProxy::rawSequence(1u));
auto const expectedBytes = Bytes{std::begin(expected.key), std::end(expected.key)};
auto const result = host().paychannelKeylet(owner.id(), destination.id(), 1u);
ASSERT_TRUE(result.has_value());
EXPECT_EQ(*result, expectedBytes);
expectKeyletMatches(
makeHost()->paychannelKeylet(owner.id(), destination.id(), 1u),
keylet::payChannel(owner.id(), destination.id(), SeqProxy::rawSequence(1u)));
}
TEST_F(PaychannelKeyletImpl, CantUseSelf)
{
auto const owner = Account{"owner"};
ledger.createAccount(owner, XRP(1000));
auto const owner = fund("owner");
auto result = host().paychannelKeylet(owner.id(), owner.id(), 1u);
ASSERT_TRUE(!result.has_value());
EXPECT_EQ(result.error(), HostFunctionError::InvalidParams);
expectError(
makeHost()->paychannelKeylet(owner.id(), owner.id(), 1u), HostFunctionError::InvalidParams);
}
TEST_F(PaychannelKeyletImpl, InvalidAccount)
{
auto const owner = Account{"owner"};
ledger.createAccount(owner, XRP(1000));
auto const owner = fund("owner");
auto result = host().paychannelKeylet(AccountID{}, owner.id(), 1u);
ASSERT_TRUE(!result.has_value());
EXPECT_EQ(result.error(), HostFunctionError::InvalidAccount);
expectError(
makeHost()->paychannelKeylet(AccountID{}, owner.id(), 1u),
HostFunctionError::InvalidAccount);
result = host().paychannelKeylet(owner.id(), AccountID{}, 1u);
ASSERT_TRUE(!result.has_value());
EXPECT_EQ(result.error(), HostFunctionError::InvalidAccount);
expectError(
makeHost()->paychannelKeylet(owner.id(), AccountID{}, 1u),
HostFunctionError::InvalidAccount);
}
} // namespace xrpl::test

View File

@@ -5,12 +5,8 @@
#include <gtest/gtest.h>
#include <helpers/Account.h>
#include <helpers/TxTest.h>
#include <tx/wasm/RealHostFixture.h>
#include <expected>
#include <iterator>
namespace xrpl::test {
struct PermissionedDomainKeyletImpl : WasmImplTest
@@ -19,21 +15,17 @@ struct PermissionedDomainKeyletImpl : WasmImplTest
TEST_F(PermissionedDomainKeyletImpl, MatchesPermissionedDomainFunction)
{
auto const owner = Account{"owner"};
ledger.createAccount(owner, XRP(1000));
auto const owner = fund("owner");
auto const expected = keylet::permissionedDomain(owner.id(), SeqProxy::rawSequence(1u));
auto const expectedBytes = Bytes{std::begin(expected.key), std::end(expected.key)};
auto const result = host().permissionedDomainKeylet(owner.id(), 1u);
ASSERT_TRUE(result.has_value());
EXPECT_EQ(*result, expectedBytes);
expectKeyletMatches(
makeHost()->permissionedDomainKeylet(owner.id(), 1u),
keylet::permissionedDomain(owner.id(), SeqProxy::rawSequence(1u)));
}
TEST_F(PermissionedDomainKeyletImpl, InvalidAccount)
{
auto result = host().permissionedDomainKeylet(AccountID{}, 1u);
ASSERT_TRUE(!result.has_value());
EXPECT_EQ(result.error(), HostFunctionError::InvalidAccount);
expectError(
makeHost()->permissionedDomainKeylet(AccountID{}, 1u), HostFunctionError::InvalidAccount);
}
} // namespace xrpl::test

View File

@@ -0,0 +1,21 @@
#include <xrpl/protocol/digest.h>
#include <gtest/gtest.h>
#include <tx/wasm/RealHostFixture.h>
#include <string>
namespace xrpl::test {
struct Sha512HalfImpl : WasmImplTest
{
};
TEST_F(Sha512HalfImpl, LogsMessageAndData)
{
static constexpr auto data = std::string_view{"hello world"};
auto const result = makeHost()->computeSha512HalfHash({data.data(), data.size()});
expectValue(result, sha512Half(Slice{data.data(), data.size()}));
}
} // namespace xrpl::test

View File

@@ -4,12 +4,8 @@
#include <gtest/gtest.h>
#include <helpers/Account.h>
#include <helpers/TxTest.h>
#include <tx/wasm/RealHostFixture.h>
#include <expected>
#include <iterator>
namespace xrpl::test {
struct SignerListKeyletImpl : WasmImplTest
@@ -18,21 +14,14 @@ struct SignerListKeyletImpl : WasmImplTest
TEST_F(SignerListKeyletImpl, MatchesSignerListFunction)
{
auto const owner = Account{"owner"};
ledger.createAccount(owner, XRP(1000));
auto const owner = fund("owner");
auto const expected = keylet::signerList(owner.id());
auto const expectedBytes = Bytes{std::begin(expected.key), std::end(expected.key)};
auto const result = host().signerListKeylet(owner.id());
ASSERT_TRUE(result.has_value());
EXPECT_EQ(*result, expectedBytes);
expectKeyletMatches(makeHost()->signerListKeylet(owner.id()), keylet::signerList(owner.id()));
}
TEST_F(SignerListKeyletImpl, InvalidAccount)
{
auto result = host().signerListKeylet(AccountID{});
ASSERT_TRUE(!result.has_value());
EXPECT_EQ(result.error(), HostFunctionError::InvalidAccount);
expectError(makeHost()->signerListKeylet(AccountID{}), HostFunctionError::InvalidAccount);
}
} // namespace xrpl::test

View File

@@ -5,12 +5,8 @@
#include <gtest/gtest.h>
#include <helpers/Account.h>
#include <helpers/TxTest.h>
#include <tx/wasm/RealHostFixture.h>
#include <expected>
#include <iterator>
namespace xrpl::test {
struct TicketKeyletImpl : WasmImplTest
@@ -19,21 +15,16 @@ struct TicketKeyletImpl : WasmImplTest
TEST_F(TicketKeyletImpl, MatchesTicketFunction)
{
auto const owner = Account{"owner"};
ledger.createAccount(owner, XRP(1000));
auto const owner = fund("owner");
auto const expected = keylet::ticket(owner.id(), SeqProxy::rawTicket(1u));
auto const expectedBytes = Bytes{std::begin(expected.key), std::end(expected.key)};
auto const result = host().ticketKeylet(owner.id(), 1u);
ASSERT_TRUE(result.has_value());
EXPECT_EQ(*result, expectedBytes);
expectKeyletMatches(
makeHost()->ticketKeylet(owner.id(), 1u),
keylet::ticket(owner.id(), SeqProxy::rawTicket(1u)));
}
TEST_F(TicketKeyletImpl, InvalidAccount)
{
auto result = host().ticketKeylet(AccountID{}, 1u);
ASSERT_TRUE(!result.has_value());
EXPECT_EQ(result.error(), HostFunctionError::InvalidAccount);
expectError(makeHost()->ticketKeylet(AccountID{}, 1u), HostFunctionError::InvalidAccount);
}
} // namespace xrpl::test

View File

@@ -0,0 +1,30 @@
#include <xrpl/beast/utility/Journal.h>
#include <gtest/gtest.h>
#include <helpers/CaptureSink.h>
#include <tx/wasm/RealHostFixture.h>
#include <string>
namespace xrpl::test {
struct TraceImpl : WasmImplTest
{
};
TEST_F(TraceImpl, LogsMessageAndData)
{
auto h = makeTracingHost();
h->trace("hello", "world");
EXPECT_NE(logged().find("hello world"), std::string::npos) << logged();
}
TEST_F(TraceImpl, NothingLoggedBelowTraceSeverity)
{
CaptureSink sink{beast::Severity::Error};
auto h = makeHost(beast::Journal{sink});
h->trace("hello", "world");
EXPECT_TRUE(sink.messages().empty()) << sink.messages();
}
} // namespace xrpl::test

View File

@@ -5,12 +5,8 @@
#include <gtest/gtest.h>
#include <helpers/Account.h>
#include <helpers/TxTest.h>
#include <tx/wasm/RealHostFixture.h>
#include <expected>
#include <iterator>
namespace xrpl::test {
struct TrustlineKeyletImpl : WasmImplTest
@@ -19,58 +15,49 @@ struct TrustlineKeyletImpl : WasmImplTest
TEST_F(TrustlineKeyletImpl, MatchesTrustlineKeyletFunction)
{
auto const owner = Account{"owner"};
ledger.createAccount(owner, XRP(1000));
auto const destination = Account{"destination"};
ledger.createAccount(destination, XRP(1000));
auto const owner = fund("owner");
auto const destination = fund("destination");
auto const usd = toCurrency("USD");
auto const expected = keylet::trustLine(owner.id(), destination.id(), usd);
auto const expectedBytes = Bytes{std::begin(expected.key), std::end(expected.key)};
auto const result = host().trustLineKeylet(owner.id(), destination.id(), usd);
ASSERT_TRUE(result.has_value());
EXPECT_EQ(*result, expectedBytes);
expectKeyletMatches(
makeHost()->trustLineKeylet(owner.id(), destination.id(), usd),
keylet::trustLine(owner.id(), destination.id(), usd));
}
TEST_F(TrustlineKeyletImpl, InvalidCurrency)
{
auto const owner = Account{"owner"};
ledger.createAccount(owner, XRP(1000));
auto const destination = Account{"destination"};
ledger.createAccount(destination, XRP(1000));
auto const owner = fund("owner");
auto const destination = fund("destination");
auto const result = host().trustLineKeylet(owner.id(), destination.id(), toCurrency(""));
ASSERT_TRUE(!result.has_value());
EXPECT_EQ(result.error(), HostFunctionError::InvalidParams);
expectError(
makeHost()->trustLineKeylet(owner.id(), destination.id(), toCurrency("")),
HostFunctionError::InvalidParams);
}
TEST_F(TrustlineKeyletImpl, CantTrustlineToSelf)
{
auto const owner = Account{"owner"};
ledger.createAccount(owner, XRP(1000));
auto const owner = fund("owner");
auto const usd = toCurrency("USD");
auto const result = host().trustLineKeylet(owner.id(), owner.id(), usd);
ASSERT_TRUE(!result.has_value());
EXPECT_EQ(result.error(), HostFunctionError::InvalidParams);
expectError(
makeHost()->trustLineKeylet(owner.id(), owner.id(), usd), HostFunctionError::InvalidParams);
}
TEST_F(TrustlineKeyletImpl, InvalidAccount)
{
auto const owner = Account{"owner"};
ledger.createAccount(owner, XRP(1000));
auto const owner = fund("owner");
auto const usd = toCurrency("USD");
auto result = host().trustLineKeylet(AccountID{}, owner.id(), usd);
ASSERT_TRUE(!result.has_value());
EXPECT_EQ(result.error(), HostFunctionError::InvalidAccount);
expectError(
makeHost()->trustLineKeylet(AccountID{}, owner.id(), usd),
HostFunctionError::InvalidAccount);
result = host().trustLineKeylet(owner.id(), AccountID{}, usd);
ASSERT_TRUE(!result.has_value());
EXPECT_EQ(result.error(), HostFunctionError::InvalidAccount);
expectError(
makeHost()->trustLineKeylet(owner.id(), AccountID{}, usd),
HostFunctionError::InvalidAccount);
}
} // namespace xrpl::test

View File

@@ -0,0 +1,62 @@
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/STArray.h>
#include <xrpl/protocol/STObject.h>
#include <xrpl/tx/wasm/WasmCommon.h>
#include <gtest/gtest.h>
#include <helpers/Account.h>
#include <tx/wasm/RealHostFixture.h>
#include <utility>
namespace xrpl::test {
struct TxArrayLenImpl : WasmImplTest
{
using WasmImplTest::makeHost;
WasmHost
makeHost(Account const& acct)
{
auto assembler = escrowFinishTx(ledger, acct);
assembler.build = [inner = std::move(assembler.build)](STObject& obj) {
inner(obj);
auto memos = STArray{};
memos.push_back(makeMemo(toBytes("hello")));
memos.push_back(makeMemo(toBytes("world")));
obj.setFieldArray(sfMemos, memos);
};
return makeHost(keylet::account(acct.id()), assembler.type, std::move(assembler.build));
}
};
TEST_F(TxArrayLenImpl, MemosLength)
{
auto const owner = fund("owner");
auto h = makeHost(owner);
expectValue(h->getTxArrayLen(sfMemos), 2);
}
TEST_F(TxArrayLenImpl, CredentialIdsLength)
{
auto const owner = fund("owner");
auto h = makeHost(owner);
expectValue(h->getTxArrayLen(sfCredentialIDs), 1);
}
TEST_F(TxArrayLenImpl, NonArrayFieldNoArray)
{
auto const owner = fund("owner");
auto h = makeHost(owner);
expectError(h->getTxArrayLen(sfAccount), HostFunctionError::NoArray);
}
TEST_F(TxArrayLenImpl, MissingArrayFieldNotFound)
{
auto const owner = fund("owner");
auto h = makeHost(owner);
expectError(h->getTxArrayLen(sfSigners), HostFunctionError::FieldNotFound);
}
} // namespace xrpl::test

View File

@@ -1,7 +1,9 @@
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/Issue.h>
#include <xrpl/protocol/MPTIssue.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/SeqProxy.h>
#include <xrpl/protocol/TxFormats.h>
#include <xrpl/protocol/UintTypes.h>
#include <xrpl/tx/wasm/WasmCommon.h>
#include <gtest/gtest.h>
@@ -10,73 +12,160 @@
#include <tx/wasm/RealHostFixture.h>
#include <cstdint>
#include <expected>
#include <iterator>
#include <utility>
namespace xrpl::test {
struct CacheLedgerObjImpl : WasmImplTest
struct TxFieldImpl : WasmImplTest
{
template <typename Functor>
void
runMatchesLedger(bool implicit)
checkTxField(Account const& acct, SField const& field, TxAssembler assembler, Functor&& f)
{
auto const owner = Account{"owner"};
ledger.createAccount(owner, XRP(1000));
auto h = makeHost(keylet::account(acct.id()), assembler.type, std::move(assembler.build));
expectValue(h->getTxField(field), f());
}
auto& h = host();
auto const key = keylet::account(owner.id()).key;
for (auto i = int32_t{1}; i < 257; ++i)
{
auto const slot = h.cacheLedgerObj(key, i);
ASSERT_TRUE(slot.has_value()) << "cacheLedgerObj should find the created account";
EXPECT_EQ(*slot, i);
auto const account = h.getLedgerObjField(*slot, sfAccount);
ASSERT_TRUE(account.has_value());
Bytes const ownerBytes{owner.id().begin(), owner.id().end()};
EXPECT_EQ(*account, ownerBytes);
auto const sle = ledger.getOpenLedger().read(keylet::account(owner.id()));
ASSERT_NE(sle, nullptr);
auto const& ledgerAccount = sle->getAccountID(sfAccount);
EXPECT_EQ(*account, (Bytes{ledgerAccount.begin(), ledgerAccount.end()}));
}
// Every slot is now occupied, so asking to auto-allocate (cacheIdx == 0) has nowhere
// to put the object.
auto const result = h.cacheLedgerObj(key, 0);
ASSERT_FALSE(result.has_value());
EXPECT_EQ(result.error(), HostFunctionError::SlotsFull);
void
checkTxFieldError(
Account const& acct,
SField const& field,
TxAssembler assembler,
HostFunctionError error)
{
auto h = makeHost(keylet::account(acct.id()), assembler.type, std::move(assembler.build));
expectError(h->getTxField(field), error);
}
};
TEST_F(CacheLedgerObjImpl, MatchesLedgerExplicitIndices)
TEST_F(TxFieldImpl, MPTokenIssuanceCreateTxMatchesScale)
{
runMatchesLedger(false);
auto const owner = Account{"owner"};
ledger.createAccount(owner, XRP(1000));
auto const expectedScale = std::uint8_t{8};
checkTxField(owner, sfAssetScale, mptIssuanceCreateTx(owner, expectedScale), [&] {
return toBytes(expectedScale);
});
}
TEST_F(CacheLedgerObjImpl, MatchesLedgerImplicitIndices)
TEST_F(TxFieldImpl, AmmDepositTxUSDMatchesAsset)
{
runMatchesLedger(true);
auto const owner = Account{"owner"};
ledger.createAccount(owner, XRP(1000));
auto usdIssue = Issue{toCurrency("USD"), owner.id()};
checkTxField(
owner, sfAsset, ammDepositTx(owner, xrpIssue(), usdIssue), [&] { return Bytes(20, 0); });
}
TEST_F(CacheLedgerObjImpl, OutOfRange)
TEST_F(TxFieldImpl, AmmDepositTxUSDMatchesAsset2)
{
auto result = host().cacheLedgerObj(uint256{}, -1);
ASSERT_FALSE(result.has_value());
EXPECT_EQ(result.error(), HostFunctionError::SlotOutRange);
result = host().cacheLedgerObj(uint256{}, 257);
ASSERT_FALSE(result.has_value());
EXPECT_EQ(result.error(), HostFunctionError::SlotOutRange);
auto const owner = Account{"owner"};
ledger.createAccount(owner, XRP(1000));
auto usdIssue = Issue{toCurrency("USD"), owner.id()};
checkTxField(owner, sfAsset2, ammDepositTx(owner, xrpIssue(), usdIssue), [&] {
return toBytes(Asset{usdIssue});
});
}
TEST_F(CacheLedgerObjImpl, LedgerObjNotFound)
TEST_F(TxFieldImpl, AmmDepositTxGBPMatchesAsset)
{
auto const ghost = keylet::account(Account{"ghost"}.id()).key;
auto result = host().cacheLedgerObj(ghost, 0);
ASSERT_FALSE(result.has_value());
EXPECT_EQ(result.error(), HostFunctionError::LedgerObjNotFound);
auto const owner = Account{"owner"};
ledger.createAccount(owner, XRP(1000));
auto gbpIssue = Issue{toCurrency("GBP"), owner.id()};
auto mptId = makeMptID(1, owner);
auto mptIssue = MPTIssue{mptId};
checkTxField(owner, sfAsset, ammDepositTx(owner, gbpIssue, mptIssue), [&] {
return toBytes(Asset{gbpIssue});
});
}
TEST_F(TxFieldImpl, AmmDepositTxGBPMatchesAsset2)
{
auto const owner = Account{"owner"};
ledger.createAccount(owner, XRP(1000));
auto gbpIssue = Issue{toCurrency("GBP"), owner.id()};
auto mptId = makeMptID(1, owner);
auto mptIssue = MPTIssue{mptId};
checkTxField(owner, sfAsset2, ammDepositTx(owner, gbpIssue, mptIssue), [&] {
return toBytes(Asset{mptId});
});
}
TEST_F(TxFieldImpl, EscrowTxMatchesAccount)
{
auto const owner = Account{"owner"};
ledger.createAccount(owner, XRP(1000));
checkTxField(owner, sfAccount, escrowFinishTx(ledger, owner), [&] {
return Bytes{std::begin(owner.id()), std::end(owner.id())};
});
}
TEST_F(TxFieldImpl, EscrowTxMatchesOwner)
{
auto const owner = Account{"owner"};
ledger.createAccount(owner, XRP(1000));
checkTxField(owner, sfOwner, escrowFinishTx(ledger, owner), [&] {
return Bytes{std::begin(owner.id()), std::end(owner.id())};
});
}
TEST_F(TxFieldImpl, EscrowTxMatchesTransactionType)
{
auto const owner = Account{"owner"};
ledger.createAccount(owner, XRP(1000));
checkTxField(owner, sfTransactionType, escrowFinishTx(ledger, owner), [] {
return toBytes(ttESCROW_FINISH);
});
}
TEST_F(TxFieldImpl, EscrowTxMatchesOfferSequence)
{
auto const owner = Account{"owner"};
ledger.createAccount(owner, XRP(1000));
checkTxField(owner, sfOfferSequence, escrowFinishTx(ledger, owner), [&] {
return toBytes(ledger.getAccountRoot(owner.id()).getSequence());
});
}
TEST_F(TxFieldImpl, EscrowTxMatchesDestination)
{
auto const owner = Account{"owner"};
ledger.createAccount(owner, XRP(1000));
checkTxFieldError(
owner, sfDestination, escrowFinishTx(ledger, owner), HostFunctionError::FieldNotFound);
}
TEST_F(TxFieldImpl, EscrowTxMatchesMemos)
{
auto const owner = Account{"owner"};
ledger.createAccount(owner, XRP(1000));
checkTxFieldError(
owner, sfMemos, escrowFinishTx(ledger, owner), HostFunctionError::NotLeafField);
}
TEST_F(TxFieldImpl, EscrowTxMatchesCredentialIDs)
{
auto const owner = Account{"owner"};
ledger.createAccount(owner, XRP(1000));
checkTxFieldError(
owner, sfCredentialIDs, escrowFinishTx(ledger, owner), HostFunctionError::NotLeafField);
}
TEST_F(TxFieldImpl, EscrowTxMatchesInvalid)
{
auto const owner = Account{"owner"};
ledger.createAccount(owner, XRP(1000));
checkTxFieldError(
owner, sfInvalid, escrowFinishTx(ledger, owner), HostFunctionError::FieldNotFound);
}
TEST_F(TxFieldImpl, EscrowTxMatchesGeneric)
{
auto const owner = Account{"owner"};
ledger.createAccount(owner, XRP(1000));
checkTxFieldError(
owner, sfGeneric, escrowFinishTx(ledger, owner), HostFunctionError::FieldNotFound);
}
} // namespace xrpl::test

View File

@@ -0,0 +1,64 @@
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/STArray.h>
#include <xrpl/protocol/STObject.h>
#include <xrpl/tx/wasm/WasmCommon.h>
#include <gtest/gtest.h>
#include <helpers/Account.h>
#include <tx/wasm/RealHostFixture.h>
#include <utility>
namespace xrpl::test {
struct TxNestedArrayLenImpl : WasmImplTest
{
using WasmImplTest::makeHost;
WasmHost
makeHost(Account const& acct)
{
auto assembler = escrowFinishTx(ledger, acct);
assembler.build = [inner = std::move(assembler.build)](STObject& obj) {
inner(obj);
auto memos = STArray{};
memos.push_back(makeMemo(toBytes("hello")));
obj.setFieldArray(sfMemos, memos);
};
return makeHost(keylet::account(acct.id()), assembler.type, std::move(assembler.build));
}
};
TEST_F(TxNestedArrayLenImpl, MemosLength)
{
auto const owner = fund("owner");
auto h = makeHost(owner);
expectValue(h->getTxNestedArrayLen(FieldLocator{{sfMemos.getCode()}}), 1);
}
TEST_F(TxNestedArrayLenImpl, CredentialIdsLength)
{
auto const owner = fund("owner");
auto h = makeHost(owner);
expectValue(h->getTxNestedArrayLen(FieldLocator{{sfCredentialIDs.getCode()}}), 1);
}
TEST_F(TxNestedArrayLenImpl, NonArrayFieldNoArray)
{
auto const owner = fund("owner");
auto h = makeHost(owner);
expectError(
h->getTxNestedArrayLen(FieldLocator{{sfAccount.getCode()}}), HostFunctionError::NoArray);
}
TEST_F(TxNestedArrayLenImpl, MissingFieldNotFound)
{
auto const owner = fund("owner");
auto h = makeHost(owner);
expectError(
h->getTxNestedArrayLen(FieldLocator{{sfSigners.getCode()}}),
HostFunctionError::FieldNotFound);
}
} // namespace xrpl::test

View File

@@ -0,0 +1,133 @@
#include <xrpl/basics/Slice.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/STArray.h>
#include <xrpl/protocol/STObject.h>
#include <xrpl/tx/wasm/WasmCommon.h>
#include <gtest/gtest.h>
#include <helpers/Account.h>
#include <tx/wasm/RealHostFixture.h>
#include <cstdint>
#include <limits>
#include <utility>
namespace xrpl::test {
struct TxNestedFieldImpl : WasmImplTest
{
TxAssembler
assemble(Account const& acct)
{
auto assembler = escrowFinishTx(ledger, acct);
assembler.build = [inner = std::move(assembler.build)](STObject& obj) {
inner(obj);
auto memos = STArray{};
auto memo = STObject::makeInnerObject(sfMemo);
memo.setFieldVL(sfMemoData, Slice{"hello", 5});
memos.push_back(std::move(memo));
obj.setFieldArray(sfMemos, memos);
};
return assembler;
}
using WasmImplTest::makeHost;
WasmHost
makeHost(Account const& acct)
{
auto assembler = assemble(acct);
return makeHost(keylet::account(acct.id()), assembler.type, std::move(assembler.build));
}
};
TEST_F(TxNestedFieldImpl, MatchesNestedMemo)
{
auto const owner = fund("owner");
auto h = makeHost(owner);
expectValue(
h->getTxNestedField(FieldLocator{{sfMemos.getCode(), 0, sfMemoData.getCode()}}),
toBytes("hello"));
}
TEST_F(TxNestedFieldImpl, MatchesCredId)
{
auto const owner = fund("owner");
auto h = makeHost(owner);
expectValue(
h->getTxNestedField(FieldLocator{{sfCredentialIDs.getCode(), 0}}), toBytes(credentialId()));
}
TEST_F(TxNestedFieldImpl, MatchesBaseFieldViaNestedLocator)
{
auto const owner = fund("owner");
auto h = makeHost(owner);
expectValue(h->getTxNestedField(FieldLocator{{sfAccount.getCode()}}), toBytes(owner.id()));
}
TEST_F(TxNestedFieldImpl, MissingFieldNotFound)
{
auto const owner = fund("owner");
auto h = makeHost(owner);
auto const err = HostFunctionError::FieldNotFound;
expectError(
h->getTxNestedField(FieldLocator{{sfSigners.getCode(), 0, sfAccount.getCode()}}), err);
expectError(h->getTxNestedField(FieldLocator{{sfMemos.getCode(), 0, sfURI.getCode()}}), err);
expectError(h->getTxNestedField(FieldLocator{{sfMemos.getCode(), 0, -1}}), err);
expectError(h->getTxNestedField(FieldLocator{{-1, 0, sfAccount.getCode()}}), err);
expectError(h->getTxNestedField(FieldLocator{{0, 0, sfAccount.getCode()}}), err);
}
TEST_F(TxNestedFieldImpl, IndexOutOfBounds)
{
auto const owner = fund("owner");
auto h = makeHost(owner);
auto const err = HostFunctionError::IndexOutOfBounds;
expectError(
h->getTxNestedField(FieldLocator{{sfMemos.getCode(), 1, sfMemoData.getCode()}}), err);
expectError(h->getTxNestedField(FieldLocator{{sfCredentialIDs.getCode(), 1}}), err);
expectError(
h->getTxNestedField(FieldLocator{{sfMemos.getCode(), -1, sfMemoData.getCode()}}), err);
expectError(h->getTxNestedField(FieldLocator{{sfCredentialIDs.getCode(), -1}}), err);
}
TEST_F(TxNestedFieldImpl, UnknownFieldCodeInvalidField)
{
auto const owner = fund("owner");
auto h = makeHost(owner);
auto const err = HostFunctionError::InvalidField;
expectError(
h->getTxNestedField(FieldLocator{{fieldCode(20000, 20000), 0, sfAccount.getCode()}}), err);
expectError(
h->getTxNestedField(FieldLocator{{sfMemos.getCode(), 0, fieldCode(20000, 20000)}}), err);
// Far-negative code: not in the SField map at all.
expectError(
h->getTxNestedField(
FieldLocator{{std::numeric_limits<std::int32_t>::min(), 0, sfAccount.getCode()}}),
err);
}
TEST_F(TxNestedFieldImpl, ContainerWithoutIndexNotLeaf)
{
auto const owner = fund("owner");
auto h = makeHost(owner);
auto const err = HostFunctionError::NotLeafField;
expectError(h->getTxNestedField(FieldLocator{{sfMemos.getCode()}}), err);
expectError(h->getTxNestedField(FieldLocator{{sfCredentialIDs.getCode()}}), err);
}
TEST_F(TxNestedFieldImpl, NestIntoNonContainerMalformed)
{
auto const owner = fund("owner");
auto h = makeHost(owner);
expectError(
h->getTxNestedField(FieldLocator{{sfAccount.getCode(), 0, sfAccount.getCode()}}),
HostFunctionError::LocatorMalformed);
}
} // namespace xrpl::test

View File

@@ -4,8 +4,6 @@
#include <gtest/gtest.h>
#include <tx/wasm/RealHostFixture.h>
#include <expected>
namespace xrpl::test {
struct UpdateDataImpl : WasmImplTest
@@ -14,22 +12,19 @@ struct UpdateDataImpl : WasmImplTest
TEST_F(UpdateDataImpl, SmallData)
{
auto& h = host();
auto h = makeHost();
auto data = Bytes(10, 0x42);
auto result = h.updateData(Slice{data.data(), data.size()});
ASSERT_TRUE(result.has_value());
EXPECT_EQ(*result, data.size());
expectValue(h->updateData(Slice{data.data(), data.size()}), data.size());
// TODO: getData() does not seem to be called when the smart escrow finishes.
EXPECT_EQ(h.getData(), data);
EXPECT_EQ(h->getData(), data);
}
TEST_F(UpdateDataImpl, LargeData)
{
auto& h = host();
auto h = makeHost();
auto data = Bytes(kMaxWasmDataLength + 1, 0x42);
auto result = h.updateData(Slice{data.data(), data.size()});
ASSERT_TRUE(!result.has_value());
EXPECT_EQ(result.error(), HostFunctionError::DataFieldTooLarge);
expectError(
h->updateData(Slice{data.data(), data.size()}), HostFunctionError::DataFieldTooLarge);
}
} // namespace xrpl::test

View File

@@ -5,12 +5,8 @@
#include <gtest/gtest.h>
#include <helpers/Account.h>
#include <helpers/TxTest.h>
#include <tx/wasm/RealHostFixture.h>
#include <expected>
#include <iterator>
namespace xrpl::test {
struct VaultKeyletImpl : WasmImplTest
@@ -19,21 +15,16 @@ struct VaultKeyletImpl : WasmImplTest
TEST_F(VaultKeyletImpl, MatchesVaultFunction)
{
auto const owner = Account{"owner"};
ledger.createAccount(owner, XRP(1000));
auto const owner = fund("owner");
auto const expected = keylet::vault(owner.id(), SeqProxy::rawSequence(1u));
auto const expectedBytes = Bytes{std::begin(expected.key), std::end(expected.key)};
auto const result = host().vaultKeylet(owner.id(), 1u);
ASSERT_TRUE(result.has_value());
EXPECT_EQ(*result, expectedBytes);
expectKeyletMatches(
makeHost()->vaultKeylet(owner.id(), 1u),
keylet::vault(owner.id(), SeqProxy::rawSequence(1u)));
}
TEST_F(VaultKeyletImpl, InvalidAccount)
{
auto result = host().vaultKeylet(AccountID{}, 1u);
ASSERT_TRUE(!result.has_value());
EXPECT_EQ(result.error(), HostFunctionError::InvalidAccount);
expectError(makeHost()->vaultKeylet(AccountID{}, 1u), HostFunctionError::InvalidAccount);
}
} // namespace xrpl::test