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