20#include <xrpld/app/misc/CredentialHelpers.h>
21#include <xrpld/ledger/ReadView.h>
22#include <xrpld/rpc/Context.h>
23#include <xrpld/rpc/GRPCHandlers.h>
24#include <xrpld/rpc/detail/RPCHelpers.h>
26#include <xrpl/basics/StringUtilities.h>
27#include <xrpl/basics/strHex.h>
28#include <xrpl/beast/core/LexicalCast.h>
29#include <xrpl/json/json_errors.h>
30#include <xrpl/protocol/ErrorCodes.h>
31#include <xrpl/protocol/Indexes.h>
32#include <xrpl/protocol/RPCErr.h>
33#include <xrpl/protocol/STXChainBridge.h>
34#include <xrpl/protocol/jss.h>
46 jvResult[jss::error] =
"malformedRequest";
56 auto const account = parseBase58<AccountID>(params.
asString());
57 if (!account || account->
isZero())
59 jvResult[jss::error] =
"malformedAddress";
74 jvResult[jss::error] =
"malformedRequest";
82 jvResult[jss::error] =
"malformedRequest";
94 jvResult[jss::error] =
"malformedRequest";
107 if (!params.
isMember(jss::bridge_account))
110 auto const& jsBridgeAccount = params[jss::bridge_account];
111 if (!jsBridgeAccount.isString())
117 parseBase58<AccountID>(jsBridgeAccount.asString());
118 if (!account || account->
isZero())
130 if (account != bridge.door(chainType))
143 return maybeKeylet->key;
146 jvResult[jss::error] =
"malformedRequest";
156 jvResult[jss::error] =
"malformedRequest";
171 jvResult[jss::error] =
"malformedRequest";
179 (!cred.
isMember(jss::credential_type) ||
180 !cred[jss::credential_type].
isString()))
182 jvResult[jss::error] =
"malformedRequest";
186 auto const subject = parseBase58<AccountID>(cred[jss::subject].asString());
187 auto const issuer = parseBase58<AccountID>(cred[jss::issuer].asString());
188 auto const credType =
strUnHex(cred[jss::credential_type].asString());
190 if (!subject || subject->isZero() || !issuer || issuer->isZero() ||
191 !credType || credType->empty())
193 jvResult[jss::error] =
"malformedRequest";
198 *subject, *issuer,
Slice(credType->data(), credType->size()))
206 for (
auto const& jo : jv)
208 if (!jo.isObject() ||
209 !jo.isMember(jss::issuer) || !jo[jss::issuer].isString() ||
210 !jo.isMember(jss::credential_type) ||
211 !jo[jss::credential_type].isString())
214 auto const issuer = parseBase58<AccountID>(jo[jss::issuer].asString());
215 if (!issuer || !*issuer)
218 auto const credentialType =
219 strUnHex(jo[jss::credential_type].asString());
220 if (!credentialType || credentialType->empty() ||
226 credential.setFieldVL(sfCredentialType, *credentialType);
241 jvResult[jss::error] =
"malformedRequest";
248 jvResult[jss::error] =
"malformedRequest";
251 if (!params[jss::account].isString() || !params[jss::authorize].isString())
253 jvResult[jss::error] =
"malformedAddress";
257 parseBase58<AccountID>(params[jss::account].asString());
260 jvResult[jss::error] =
"malformedAddress";
263 auto const authorize =
264 parseBase58<AccountID>(params[jss::authorize].asString());
267 jvResult[jss::error] =
"malformedAddress";
281 jvResult[jss::error] =
"malformedRequest";
290 (dp.
isMember(jss::authorized) == dp.
isMember(jss::authorized_credentials)) ||
292 (dp.
isMember(jss::authorized_credentials) && !dp[jss::authorized_credentials].
isArray())
296 jvResult[jss::error] =
"malformedRequest";
300 auto const owner = parseBase58<AccountID>(dp[jss::owner].asString());
303 jvResult[jss::error] =
"malformedOwner";
310 parseBase58<AccountID>(dp[jss::authorized].asString());
313 jvResult[jss::error] =
"malformedAuthorized";
319 auto const& ac(dp[jss::authorized_credentials]);
324 jvResult[jss::error] =
"malformedAuthorizedCredentials";
331 jvResult[jss::error] =
"malformedAuthorizedCredentials";
341 auto const account = parseBase58<AccountID>(params.
asString());
342 if (!account || account->
isZero())
344 jvResult[jss::error] =
"malformedAddress";
356 jvResult[jss::error] =
"malformedRequest";
365 jvResult[jss::error] =
"malformedRequest";
373 jvResult[jss::error] =
"malformedRequest";
378 params.
isMember(jss::sub_index) ? params[jss::sub_index].
asUInt() : 0;
387 jvResult[jss::error] =
"malformedRequest";
393 jvResult[jss::error] =
"malformedRequest";
402 parseBase58<AccountID>(params[jss::owner].asString());
406 jvResult[jss::error] =
"malformedAddress";
413 jvResult[jss::error] =
"malformedRequest";
425 jvResult[jss::error] =
"malformedRequest";
435 jvResult[jss::error] =
"malformedRequest";
439 auto const id = parseBase58<AccountID>(params[jss::owner].asString());
443 jvResult[jss::error] =
"malformedOwner";
458 jvResult[jss::error] =
"malformedRequest";
464 if (!mptJson.
isMember(jss::mpt_issuance_id) ||
467 jvResult[jss::error] =
"malformedRequest";
473 auto const mptIssuanceIdStr = mptJson[jss::mpt_issuance_id].
asString();
476 if (!mptIssuanceID.
parseHex(mptIssuanceIdStr))
477 Throw<std::runtime_error>(
"Cannot parse mpt_issuance_id");
480 parseBase58<AccountID>(mptJson[jss::account].asString());
482 if (!account || account->
isZero())
484 jvResult[jss::error] =
"malformedAddress";
492 jvResult[jss::error] =
"malformedRequest";
502 if (unparsedMPTIssuanceID.
isString())
507 jvResult[jss::error] =
"malformedRequest";
514 jvResult[jss::error] =
"malformedRequest";
526 jvResult[jss::error] =
"malformedRequest";
532 jvResult[jss::error] =
"malformedRequest";
544 jvResult[jss::error] =
"malformedRequest";
553 jvResult[jss::error] =
"malformedRequest";
557 auto const id = parseBase58<AccountID>(params[jss::account].asString());
560 jvResult[jss::error] =
"malformedAddress";
575 jvResult[jss::error] =
"malformedRequest";
581 if (!params.
isMember(jss::oracle_document_id) ||
584 jvResult[jss::error] =
"malformedRequest";
588 auto const& oracle = params;
590 auto const id = oracle[jss::oracle_document_id];
591 if (
id.isUInt() || (
id.isInt() &&
id.asInt() >= 0))
605 parseBase58<AccountID>(oracle[jss::account].asString());
606 if (!account || account->
isZero())
608 jvResult[jss::error] =
"malformedAddress";
614 jvResult[jss::error] =
"malformedDocumentID";
627 jvResult[jss::error] =
"malformedRequest";
645 jvResult[jss::error] =
"malformedRequest";
651 jvResult[jss::error] =
"malformedRequest";
655 if (!pd[jss::account].isString())
657 jvResult[jss::error] =
"malformedAddress";
662 (pd[jss::seq].
isInt() && pd[jss::seq].
asInt() < 0) ||
665 jvResult[jss::error] =
"malformedRequest";
669 auto const account = parseBase58<AccountID>(pd[jss::account].asString());
672 jvResult[jss::error] =
"malformedAddress";
685 !jvRippleState.
isMember(jss::accounts) ||
686 !jvRippleState[jss::accounts].
isArray() ||
687 2 != jvRippleState[jss::accounts].
size() ||
688 !jvRippleState[jss::accounts][0u].
isString() ||
689 !jvRippleState[jss::accounts][1u].
isString() ||
690 (jvRippleState[jss::accounts][0u].
asString() ==
691 jvRippleState[jss::accounts][1u].
asString()))
693 jvResult[jss::error] =
"malformedRequest";
698 parseBase58<AccountID>(jvRippleState[jss::accounts][0u].asString());
700 parseBase58<AccountID>(jvRippleState[jss::accounts][1u].asString());
703 jvResult[jss::error] =
"malformedAddress";
707 if (!
to_currency(uCurrency, jvRippleState[jss::currency].asString()))
709 jvResult[jss::error] =
"malformedCurrency";
724 jvResult[jss::error] =
"malformedRequest";
733 jvResult[jss::error] =
"malformedRequest";
737 auto const id = parseBase58<AccountID>(params[jss::account].asString());
740 jvResult[jss::error] =
"malformedAddress";
756 jvResult[jss::error] =
"malformedRequest";
763 !(claim_id.
isMember(sfIssuingChainDoor.getJsonName()) &&
764 claim_id[sfIssuingChainDoor.getJsonName()].
isString()) ||
765 !(claim_id.
isMember(sfLockingChainDoor.getJsonName()) &&
766 claim_id[sfLockingChainDoor.getJsonName()].
isString()) ||
767 !claim_id.
isMember(sfIssuingChainIssue.getJsonName()) ||
768 !claim_id.
isMember(sfLockingChainIssue.getJsonName()) ||
769 !claim_id.
isMember(jss::xchain_owned_claim_id))
771 jvResult[jss::error] =
"malformedRequest";
779 auto const lockingChainDoor = parseBase58<AccountID>(
780 claim_id[sfLockingChainDoor.getJsonName()].
asString());
781 auto const issuingChainDoor = parseBase58<AccountID>(
782 claim_id[sfIssuingChainDoor.getJsonName()].
asString());
783 Issue lockingChainIssue, issuingChainIssue;
784 bool valid = lockingChainDoor && issuingChainDoor;
797 jvResult[jss::error] =
"malformedRequest";
802 if (
valid && claim_id[jss::xchain_owned_claim_id].isIntegral())
804 auto const seq = claim_id[jss::xchain_owned_claim_id].
asUInt();
815 jvResult[jss::error] =
"malformedRequest";
831 jvResult[jss::error] =
"malformedRequest";
838 !(claim_id.
isMember(sfIssuingChainDoor.getJsonName()) &&
839 claim_id[sfIssuingChainDoor.getJsonName()].
isString()) ||
840 !(claim_id.
isMember(sfLockingChainDoor.getJsonName()) &&
841 claim_id[sfLockingChainDoor.getJsonName()].
isString()) ||
842 !claim_id.
isMember(sfIssuingChainIssue.getJsonName()) ||
843 !claim_id.
isMember(sfLockingChainIssue.getJsonName()) ||
844 !claim_id.
isMember(jss::xchain_owned_create_account_claim_id))
846 jvResult[jss::error] =
"malformedRequest";
855 auto const lockingChainDoor = parseBase58<AccountID>(
856 claim_id[sfLockingChainDoor.getJsonName()].
asString());
857 auto const issuingChainDoor = parseBase58<AccountID>(
858 claim_id[sfIssuingChainDoor.getJsonName()].
asString());
859 Issue lockingChainIssue, issuingChainIssue;
860 bool valid = lockingChainDoor && issuingChainDoor;
873 jvResult[jss::error] =
"malformedRequest";
878 claim_id[jss::xchain_owned_create_account_claim_id].isIntegral())
881 claim_id[jss::xchain_owned_create_account_claim_id].
asUInt();
919 static auto ledgerEntryParsers = std::to_array<LedgerEntry>({
941 {jss::permissioned_domain,
943 ltPERMISSIONED_DOMAIN},
948 {jss::xchain_owned_claim_id,
950 ltXCHAIN_OWNED_CLAIM_ID},
951 {jss::xchain_owned_create_account_claim_id,
953 ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID},
962 for (
const auto& ledgerEntry : ledgerEntryParsers)
966 expectedType = ledgerEntry.expectedType;
971 Json::Value const& params = ledgerEntry.fieldName == jss::bridge
973 : context.
params[ledgerEntry.fieldName];
974 uNodeIndex = ledgerEntry.parseFunction(params, jvResult)
975 .value_or(beast::zero);
976 if (jvResult.isMember(jss::error))
988 jvResult[jss::error] =
"unknownOption";
990 jvResult[jss::error] =
"invalidParams";
1000 jvResult[jss::error] =
"invalidParams";
1007 if (uNodeIndex.isZero())
1009 jvResult[jss::error] =
"entryNotFound";
1015 bool bNodeBinary =
false;
1022 jvResult[jss::error] =
"entryNotFound";
1026 if ((expectedType !=
ltANY) && (expectedType != sleNode->getType()))
1028 jvResult[jss::error] =
"unexpectedLedgerType";
1039 jvResult[jss::index] =
to_string(uNodeIndex);
1044 jvResult[jss::index] =
to_string(uNodeIndex);
1054 org::xrpl::rpc::v1::GetLedgerEntryRequest& request = context.
params;
1055 org::xrpl::rpc::v1::GetLedgerEntryResponse response;
1056 grpc::Status status = grpc::Status::OK;
1061 grpc::Status errorStatus;
1064 errorStatus = grpc::Status(
1065 grpc::StatusCode::INVALID_ARGUMENT, status.message());
1070 grpc::Status(grpc::StatusCode::NOT_FOUND, status.message());
1072 return {response, errorStatus};
1078 grpc::Status errorStatus{
1079 grpc::StatusCode::INVALID_ARGUMENT,
"index malformed"};
1080 return {response, errorStatus};
1086 grpc::Status errorStatus{
1087 grpc::StatusCode::NOT_FOUND,
"object not found"};
1088 return {response, errorStatus};
1094 auto& stateObject = *response.mutable_ledger_object();
1096 stateObject.set_key(request.key());
1097 *(response.mutable_ledger()) = request.ledger();
1098 return {response, status};
Lightweight wrapper to tag static string.
UInt size() const
Number of values in array or object.
std::string asString() const
Returns the unquoted string value.
bool isNull() const
isNull() tests to see if this field is null.
bool isMember(const char *key) const
Return true if the object has a member named key.
A currency issued by an account.
void push_back(STObject const &object)
static STObject makeInnerObject(SField const &name)
static ChainType srcChain(bool wasLockingChainSend)
Blob const & peekData() const
An immutable linear range of bytes.
static std::optional< base_uint > fromVoidChecked(T const &from)
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
T make_optional(T... args)
bool lexicalCastChecked(Out &out, In in)
Intelligently convert from one type to another.
Status ledgerFromRequest(T &ledger, GRPCContext< R > &context)
Status lookupLedger(std::shared_ptr< ReadView const > &ledger, JsonContext &context, Json::Value &result)
Look up a ledger from a request and fill a Json::Result with the data representing a ledger.
TER authorized(ApplyContext const &ctx, AccountID const &dst)
TER valid(PreclaimContext const &ctx, AccountID const &src)
std::set< std::pair< AccountID, Slice > > makeSorted(STArray const &credentials)
Keylet mptoken(MPTID const &issuanceID, AccountID const &holder) noexcept
Keylet oracle(AccountID const &account, std::uint32_t const &documentID) noexcept
Keylet delegate(AccountID const &account, AccountID const &authorizedAccount) noexcept
A keylet for Delegate object.
Keylet permissionedDomain(AccountID const &account, std::uint32_t seq) noexcept
Keylet amm(Asset const &issue1, Asset const &issue2) noexcept
AMM entry.
Keylet line(AccountID const &id0, AccountID const &id1, Currency const ¤cy) noexcept
The index of a trust line for a given currency.
Keylet mptIssuance(std::uint32_t seq, AccountID const &issuer) noexcept
Keylet xChainClaimID(STXChainBridge const &bridge, std::uint64_t seq)
Keylet did(AccountID const &account) noexcept
Keylet credential(AccountID const &subject, AccountID const &issuer, Slice const &credType) noexcept
Keylet account(AccountID const &id) noexcept
AccountID root.
Keylet page(uint256 const &root, std::uint64_t index=0) noexcept
A page in a directory.
Keylet unchecked(uint256 const &key) noexcept
Any ledger entry.
Keylet escrow(AccountID const &src, std::uint32_t seq) noexcept
An escrow entry.
Keylet bridge(STXChainBridge const &bridge, STXChainBridge::ChainType chainType)
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Keylet xChainCreateAccountClaimID(STXChainBridge const &bridge, std::uint64_t seq)
Keylet offer(AccountID const &id, std::uint32_t seq) noexcept
An offer from an account.
Keylet depositPreauth(AccountID const &owner, AccountID const &preauthorized) noexcept
A DepositPreauth.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
static std::optional< uint256 > parseMPToken(Json::Value const &mptJson, Json::Value &jvResult)
static std::optional< uint256 > parseIndex(Json::Value const ¶ms, Json::Value &jvResult)
static STArray parseAuthorizeCredentials(Json::Value const &jv)
std::optional< Blob > strUnHex(std::size_t strSize, Iterator begin, Iterator end)
Json::Value doLedgerEntry(RPC::JsonContext &)
static std::optional< uint256 > parsePaymentChannel(Json::Value const ¶ms, Json::Value &jvResult)
static std::optional< uint256 > parseAMM(Json::Value const ¶ms, Json::Value &jvResult)
static std::optional< uint256 > parseMPTokenIssuance(Json::Value const &unparsedMPTIssuanceID, Json::Value &jvResult)
static std::optional< uint256 > parseBridge(Json::Value const ¶ms, Json::Value &jvResult)
static std::optional< uint256 > parseDepositPreauth(Json::Value const &dp, Json::Value &jvResult)
static std::optional< uint256 > parseNFTokenPage(Json::Value const ¶ms, Json::Value &jvResult)
static std::optional< uint256 > parseCheck(Json::Value const ¶ms, Json::Value &jvResult)
static std::optional< uint256 > parseTicket(Json::Value const ¶ms, Json::Value &jvResult)
static std::optional< uint256 > parseCredential(Json::Value const &cred, Json::Value &jvResult)
static std::optional< uint256 > parseOracle(Json::Value const ¶ms, Json::Value &jvResult)
Issue issueFromJson(Json::Value const &v)
std::string strHex(FwdIt begin, FwdIt end)
static std::optional< uint256 > parseEscrow(Json::Value const ¶ms, Json::Value &jvResult)
std::size_t constexpr maxCredentialsArraySize
The maximum number of credentials can be passed in array.
std::pair< org::xrpl::rpc::v1::GetLedgerEntryResponse, grpc::Status > doLedgerEntryGrpc(RPC::GRPCContext< org::xrpl::rpc::v1::GetLedgerEntryRequest > &context)
static std::optional< uint256 > parseXChainOwnedCreateAccountClaimID(Json::Value const &claim_id, Json::Value &jvResult)
std::size_t constexpr maxCredentialTypeLength
The maximum length of a CredentialType inside a Credential.
uint256 getTicketIndex(AccountID const &account, std::uint32_t uSequence)
static std::optional< uint256 > parseOffer(Json::Value const ¶ms, Json::Value &jvResult)
std::string to_string(base_uint< Bits, Tag > const &a)
LedgerEntryType
Identifiers for on-ledger objects.
@ ltANY
A special type, matching any ledger entry type.
static std::optional< uint256 > parseDelegate(Json::Value const ¶ms, Json::Value &jvResult)
static std::optional< uint256 > parseAccountRoot(Json::Value const ¶ms, Json::Value &jvResult)
static std::optional< uint256 > parseRippleState(Json::Value const &jvRippleState, Json::Value &jvResult)
@ credential
Credentials signature.
static std::optional< uint256 > parseXChainOwnedClaimID(Json::Value const &claim_id, Json::Value &jvResult)
static std::optional< uint256 > parseDirectory(Json::Value const ¶ms, Json::Value &jvResult)
static std::optional< uint256 > parseDID(Json::Value const ¶ms, Json::Value &jvResult)
static std::optional< uint256 > parsePermissionedDomains(Json::Value const &pd, Json::Value &jvResult)
bool to_currency(Currency &, std::string const &)
Tries to convert a string to a Currency, returns true on success.
A pair of SHAMap key and LedgerEntryType.
LedgerEntryType expectedType
Json::StaticString fieldName
FunctionType parseFunction