From f03b5883bd87440bdc4d2996d8e3bcc5a84e8dad Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Tue, 29 Apr 2025 12:39:12 -0400 Subject: [PATCH] More host functions (#5411) * getNFT * escrow keylet * account keylet * credential keylet * oracle keylet * hook everything in * fix stuff --- src/xrpld/app/misc/WasmHostFuncImpl.cpp | 115 +++++++++++ src/xrpld/app/misc/WasmHostFuncImpl.h | 19 ++ src/xrpld/app/misc/WasmVM.cpp | 241 ++++++++++++++++++++++++ src/xrpld/app/misc/WasmVM.h | 33 ++++ 4 files changed, 408 insertions(+) diff --git a/src/xrpld/app/misc/WasmHostFuncImpl.cpp b/src/xrpld/app/misc/WasmHostFuncImpl.cpp index fe1b02a53b..0383b15662 100644 --- a/src/xrpld/app/misc/WasmHostFuncImpl.cpp +++ b/src/xrpld/app/misc/WasmHostFuncImpl.cpp @@ -18,6 +18,7 @@ //============================================================================== #include +#include #include @@ -98,6 +99,33 @@ WasmHostFunctionsImpl::getCurrentLedgerEntryField(const std::string& fname) return std::nullopt; } +std::optional +WasmHostFunctionsImpl::getNFT( + const std::string& account, + const std::string& nftId) +{ + auto const accountId = parseBase58(account); + if (!accountId || accountId->isZero()) + { + return std::nullopt; + } + + uint256 nftHash; + if (!nftHash.parseHex(nftId)) + { + return std::nullopt; + } + + auto jv = nft::findToken(ctx.view(), accountId.value(), nftHash); + if (!jv) + { + return std::nullopt; + } + + Slice const s = (*jv)[sfURI]; + return Bytes{s.begin(), s.end()}; +} + bool WasmHostFunctionsImpl::updateData(const Bytes& data) { @@ -115,4 +143,91 @@ WasmHostFunctionsImpl::computeSha512HalfHash(const Bytes& data) auto const hash = sha512Half(data); return uint256::fromVoid(hash.data()); } + +std::optional +WasmHostFunctionsImpl::accountKeylet(const std::string& account) +{ + auto const accountId = parseBase58(account); + if (!accountId || accountId->isZero()) + { + return std::nullopt; + } + + auto keylet = keylet::account(*accountId).key; + if (!keylet) + { + return std::nullopt; + } + + return Bytes{keylet.begin(), keylet.end()}; +} + +std::optional +WasmHostFunctionsImpl::credentialKeylet( + const std::string& subject, + const std::string& issuer, + const std::string& credentialType) +{ + auto const subjectId = parseBase58(subject); + if (!subjectId || subjectId->isZero()) + { + return std::nullopt; + } + + auto const issuerId = parseBase58(issuer); + if (!issuerId || issuerId->isZero()) + { + return std::nullopt; + } + + auto keylet = + keylet::credential(*subjectId, *issuerId, makeSlice(credentialType)) + .key; + if (!keylet) + { + return std::nullopt; + } + + return Bytes{keylet.begin(), keylet.end()}; +} + +std::optional +WasmHostFunctionsImpl::escrowKeylet( + const std::string& account, + const std::uint32_t& seq) +{ + auto const accountId = parseBase58(account); + if (!accountId || accountId->isZero()) + { + return std::nullopt; + } + + auto keylet = keylet::escrow(*accountId, seq).key; + if (!keylet) + { + return std::nullopt; + } + + return Bytes{keylet.begin(), keylet.end()}; +} + +std::optional +WasmHostFunctionsImpl::oracleKeylet( + const std::string& account, + const std::uint32_t& documentId) +{ + auto const accountId = parseBase58(account); + if (!accountId || accountId->isZero()) + { + return std::nullopt; + } + + auto keylet = keylet::oracle(*accountId, documentId).key; + if (!keylet) + { + return std::nullopt; + } + + return Bytes{keylet.begin(), keylet.end()}; +} } // namespace ripple diff --git a/src/xrpld/app/misc/WasmHostFuncImpl.h b/src/xrpld/app/misc/WasmHostFuncImpl.h index a311073d7b..aa42f79ff6 100644 --- a/src/xrpld/app/misc/WasmHostFuncImpl.h +++ b/src/xrpld/app/misc/WasmHostFuncImpl.h @@ -54,12 +54,31 @@ public: std::optional getCurrentLedgerEntryField(std::string const& fname) override; + std::optional + getNFT(std::string const& account, std::string const& nftId) override; + bool updateData(Bytes const& data) override; Hash computeSha512HalfHash(Bytes const& data) override; + std::optional + accountKeylet(std::string const& account) override; + + std::optional + credentialKeylet( + std::string const& subject, + std::string const& issuer, + std::string const& credentialType) override; + + std::optional + escrowKeylet(std::string const& account, std::uint32_t const& seq) override; + + std::optional + oracleKeylet(std::string const& account, std::uint32_t const& documentId) + override; + private: ApplyContext& ctx; Keylet leKey; diff --git a/src/xrpld/app/misc/WasmVM.cpp b/src/xrpld/app/misc/WasmVM.cpp index 22ac65479f..1764734db3 100644 --- a/src/xrpld/app/misc/WasmVM.cpp +++ b/src/xrpld/app/misc/WasmVM.cpp @@ -220,6 +220,148 @@ getCurrentLedgerEntryField( return WasmEdge_Result_Success; } +WasmEdge_Result +getNFT( + void* data, + const WasmEdge_CallingFrameContext* fm, + const WasmEdge_Value* in, + WasmEdge_Value* out) +{ + auto account = getFieldName(fm, in, 0); + if (!account) + return account.error(); + + auto nftId = getFieldName(fm, in, 2); + if (!nftId) + return nftId.error(); + + auto nftURI = + ((HostFunctions*)data)->getNFT(account.value(), nftId.value()); + if (!nftURI) + return WasmEdge_Result_Fail; + + auto pointer = setData(fm, nftURI.value()); + if (!pointer) + return pointer.error(); + + out[0] = pointer.value(); + // out[1] = WasmEdge_ValueGenI32((int)nftURI.value().size()); + return WasmEdge_Result_Success; +} + +WasmEdge_Result +accountKeylet( + void* data, + const WasmEdge_CallingFrameContext* fm, + const WasmEdge_Value* in, + WasmEdge_Value* out) +{ + auto account = getFieldName(fm, in, 0); + if (!account) + return account.error(); + + auto keylet = ((HostFunctions*)data)->accountKeylet(account.value()); + if (!keylet) + return WasmEdge_Result_Fail; + + auto pointer = setData(fm, keylet.value()); + if (!pointer) + return pointer.error(); + + out[0] = pointer.value(); + // out[1] = WasmEdge_ValueGenI32((int)nftURI.value().size()); + return WasmEdge_Result_Success; +} + +WasmEdge_Result +credentialKeylet( + void* data, + const WasmEdge_CallingFrameContext* fm, + const WasmEdge_Value* in, + WasmEdge_Value* out) +{ + auto subject = getFieldName(fm, in, 0); + if (!subject) + return subject.error(); + + auto issuer = getFieldName(fm, in, 2); + if (!issuer) + return issuer.error(); + + auto credentialType = getFieldName(fm, in, 4); + if (!credentialType) + return credentialType.error(); + + auto keylet = + ((HostFunctions*)data) + ->credentialKeylet( + subject.value(), issuer.value(), credentialType.value()); + if (!keylet) + return WasmEdge_Result_Fail; + + auto pointer = setData(fm, keylet.value()); + if (!pointer) + return pointer.error(); + + out[0] = pointer.value(); + // out[1] = WasmEdge_ValueGenI32((int)nftURI.value().size()); + return WasmEdge_Result_Success; +} + +WasmEdge_Result +escrowKeylet( + void* data, + const WasmEdge_CallingFrameContext* fm, + const WasmEdge_Value* in, + WasmEdge_Value* out) +{ + auto account = getFieldName(fm, in, 0); + if (!account) + return account.error(); + + auto sequence = WasmEdge_ValueGetI32(in[2]); + + auto keylet = + ((HostFunctions*)data)->escrowKeylet(account.value(), sequence); + if (!keylet) + return WasmEdge_Result_Fail; + + auto pointer = setData(fm, keylet.value()); + if (!pointer) + return pointer.error(); + + out[0] = pointer.value(); + // out[1] = WasmEdge_ValueGenI32((int)nftURI.value().size()); + return WasmEdge_Result_Success; +} + +WasmEdge_Result +oracleKeylet( + void* data, + const WasmEdge_CallingFrameContext* fm, + const WasmEdge_Value* in, + WasmEdge_Value* out) +{ + auto account = getFieldName(fm, in, 0); + if (!account) + return account.error(); + + auto documentId = WasmEdge_ValueGetI32(in[2]); + + auto keylet = + ((HostFunctions*)data)->escrowKeylet(account.value(), documentId); + if (!keylet) + return WasmEdge_Result_Fail; + + auto pointer = setData(fm, keylet.value()); + if (!pointer) + return pointer.error(); + + out[0] = pointer.value(); + // out[1] = WasmEdge_ValueGenI32((int)nftURI.value().size()); + return WasmEdge_Result_Success; +} + WasmEdge_Result updateData( void* data, @@ -393,6 +535,25 @@ runEscrowWasm( WasmEdge_ModuleInstanceAddFunction(hostMod, fName, hostFunc); // WasmEdge_StringDelete(fName); } + // getNFT + { + WasmEdge_ValType inputList[4] = { + WasmEdge_ValTypeGenI32(), + WasmEdge_ValTypeGenI32(), + WasmEdge_ValTypeGenI32(), + WasmEdge_ValTypeGenI32()}; + WasmEdge_ValType returnList[1] = {WasmEdge_ValTypeGenI32()}; + WasmEdge_FunctionTypeContext* hostFuncType = + WasmEdge_FunctionTypeCreate(inputList, 2, returnList, 1); + WasmEdge_FunctionInstanceContext* hostFunc = + WasmEdge_FunctionInstanceCreate(hostFuncType, getNFT, hfs, 100); + // WasmEdge_FunctionTypeDelete(hostFuncType); + // WasmEdge_FunctionInstanceDelete(hostFunc); + + WasmEdge_String fName = WasmEdge_StringCreateByCString("getNFT"); + WasmEdge_ModuleInstanceAddFunction(hostMod, fName, hostFunc); + // WasmEdge_StringDelete(fName); + } // updateData { WasmEdge_ValType inputList[2] = { @@ -428,6 +589,86 @@ runEscrowWasm( WasmEdge_ModuleInstanceAddFunction(hostMod, fName, hostFunc); // WasmEdge_StringDelete(fName); } + // accountKeylet + { + WasmEdge_ValType inputList[2] = { + WasmEdge_ValTypeGenI32(), WasmEdge_ValTypeGenI32()}; + WasmEdge_ValType returnList[1] = {WasmEdge_ValTypeGenI32()}; + WasmEdge_FunctionTypeContext* hostFuncType = + WasmEdge_FunctionTypeCreate(inputList, 2, returnList, 1); + WasmEdge_FunctionInstanceContext* hostFunc = + WasmEdge_FunctionInstanceCreate( + hostFuncType, accountKeylet, hfs, 100); + // WasmEdge_FunctionTypeDelete(hostFuncType); + // WasmEdge_FunctionInstanceDelete(hostFunc); + + WasmEdge_String fName = + WasmEdge_StringCreateByCString("accountKeylet"); + WasmEdge_ModuleInstanceAddFunction(hostMod, fName, hostFunc); + // WasmEdge_StringDelete(fName); + } + // credentialKeylet + { + WasmEdge_ValType inputList[6] = { + WasmEdge_ValTypeGenI32(), + WasmEdge_ValTypeGenI32(), + WasmEdge_ValTypeGenI32(), + WasmEdge_ValTypeGenI32(), + WasmEdge_ValTypeGenI32(), + WasmEdge_ValTypeGenI32()}; + WasmEdge_ValType returnList[1] = {WasmEdge_ValTypeGenI32()}; + WasmEdge_FunctionTypeContext* hostFuncType = + WasmEdge_FunctionTypeCreate(inputList, 6, returnList, 1); + WasmEdge_FunctionInstanceContext* hostFunc = + WasmEdge_FunctionInstanceCreate( + hostFuncType, credentialKeylet, hfs, 100); + // WasmEdge_FunctionTypeDelete(hostFuncType); + // WasmEdge_FunctionInstanceDelete(hostFunc); + WasmEdge_String fName = + WasmEdge_StringCreateByCString("credentialKeylet"); + WasmEdge_ModuleInstanceAddFunction(hostMod, fName, hostFunc); + // WasmEdge_StringDelete(fName); + } + // escrowKeylet + { + WasmEdge_ValType inputList[3] = { + WasmEdge_ValTypeGenI32(), + WasmEdge_ValTypeGenI32(), + WasmEdge_ValTypeGenI32()}; + WasmEdge_ValType returnList[1] = {WasmEdge_ValTypeGenI32()}; + WasmEdge_FunctionTypeContext* hostFuncType = + WasmEdge_FunctionTypeCreate(inputList, 3, returnList, 1); + WasmEdge_FunctionInstanceContext* hostFunc = + WasmEdge_FunctionInstanceCreate( + hostFuncType, escrowKeylet, hfs, 100); + // WasmEdge_FunctionTypeDelete(hostFuncType); + // WasmEdge_FunctionInstanceDelete(hostFunc); + + WasmEdge_String fName = + WasmEdge_StringCreateByCString("escrowKeylet"); + WasmEdge_ModuleInstanceAddFunction(hostMod, fName, hostFunc); + // WasmEdge_StringDelete(fName); + } + // oracleKeylet + { + WasmEdge_ValType inputList[3] = { + WasmEdge_ValTypeGenI32(), + WasmEdge_ValTypeGenI32(), + WasmEdge_ValTypeGenI32()}; + WasmEdge_ValType returnList[1] = {WasmEdge_ValTypeGenI32()}; + WasmEdge_FunctionTypeContext* hostFuncType = + WasmEdge_FunctionTypeCreate(inputList, 3, returnList, 1); + WasmEdge_FunctionInstanceContext* hostFunc = + WasmEdge_FunctionInstanceCreate( + hostFuncType, oracleKeylet, hfs, 100); + // WasmEdge_FunctionTypeDelete(hostFuncType); + // WasmEdge_FunctionInstanceDelete(hostFunc); + + WasmEdge_String fName = + WasmEdge_StringCreateByCString("oracleKeylet"); + WasmEdge_ModuleInstanceAddFunction(hostMod, fName, hostFunc); + // WasmEdge_StringDelete(fName); + } // print { WasmEdge_ValType inputList[2] = { diff --git a/src/xrpld/app/misc/WasmVM.h b/src/xrpld/app/misc/WasmVM.h index 796c1ee6bb..b0839dc76d 100644 --- a/src/xrpld/app/misc/WasmVM.h +++ b/src/xrpld/app/misc/WasmVM.h @@ -74,6 +74,12 @@ struct HostFunctions return Bytes{}; } + virtual std::optional + getNFT(std::string const& account, std::string const& nftId) + { + return Bytes{}; + } + virtual bool updateData(Bytes const& data) { @@ -86,6 +92,33 @@ struct HostFunctions return Hash{}; } + virtual std::optional + accountKeylet(std::string const& account) + { + return Bytes{}; + } + + virtual std::optional + credentialKeylet( + std::string const& subject, + std::string const& issuer, + std::string const& credentialType) + { + return Bytes{}; + } + + virtual std::optional + escrowKeylet(std::string const& account, std::uint32_t const& seq) + { + return Bytes{}; + } + + virtual std::optional + oracleKeylet(std::string const& account, std::uint32_t const& docId) + { + return Bytes{}; + } + virtual ~HostFunctions() = default; };