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/LedgerFormats.h>
33#include <xrpl/protocol/RPCErr.h>
34#include <xrpl/protocol/STXChainBridge.h>
35#include <xrpl/protocol/jss.h>
47 jvResult[jss::error] =
"malformedRequest";
57 auto const account = parseBase58<AccountID>(params.
asString());
58 if (!account || account->
isZero())
60 jvResult[jss::error] =
"malformedAddress";
75 jvResult[jss::error] =
"malformedRequest";
83 jvResult[jss::error] =
"malformedRequest";
95 jvResult[jss::error] =
"malformedRequest";
108 if (!params.
isMember(jss::bridge_account))
111 auto const& jsBridgeAccount = params[jss::bridge_account];
112 if (!jsBridgeAccount.isString())
118 parseBase58<AccountID>(jsBridgeAccount.asString());
119 if (!account || account->
isZero())
131 if (account !=
bridge.door(chainType))
144 return maybeKeylet->key;
147 jvResult[jss::error] =
"malformedRequest";
157 jvResult[jss::error] =
"malformedRequest";
172 jvResult[jss::error] =
"malformedRequest";
180 (!cred.
isMember(jss::credential_type) ||
181 !cred[jss::credential_type].
isString()))
183 jvResult[jss::error] =
"malformedRequest";
187 auto const subject = parseBase58<AccountID>(cred[jss::subject].asString());
188 auto const issuer = parseBase58<AccountID>(cred[jss::issuer].asString());
189 auto const credType =
strUnHex(cred[jss::credential_type].asString());
191 if (!subject || subject->isZero() || !issuer || issuer->isZero() ||
192 !credType || credType->empty())
194 jvResult[jss::error] =
"malformedRequest";
199 *subject, *issuer,
Slice(credType->data(), credType->size()))
207 for (
auto const& jo : jv)
209 if (!jo.isObject() ||
210 !jo.isMember(jss::issuer) || !jo[jss::issuer].isString() ||
211 !jo.isMember(jss::credential_type) ||
212 !jo[jss::credential_type].isString())
215 auto const issuer = parseBase58<AccountID>(jo[jss::issuer].asString());
216 if (!issuer || !*issuer)
219 auto const credentialType =
220 strUnHex(jo[jss::credential_type].asString());
221 if (!credentialType || credentialType->empty() ||
227 credential.setFieldVL(sfCredentialType, *credentialType);
242 jvResult[jss::error] =
"malformedRequest";
249 jvResult[jss::error] =
"malformedRequest";
252 if (!params[jss::account].isString() || !params[jss::authorize].isString())
254 jvResult[jss::error] =
"malformedAddress";
258 parseBase58<AccountID>(params[jss::account].asString());
261 jvResult[jss::error] =
"malformedAddress";
264 auto const authorize =
265 parseBase58<AccountID>(params[jss::authorize].asString());
268 jvResult[jss::error] =
"malformedAddress";
282 jvResult[jss::error] =
"malformedRequest";
291 (dp.
isMember(jss::authorized) == dp.
isMember(jss::authorized_credentials)) ||
293 (dp.
isMember(jss::authorized_credentials) && !dp[jss::authorized_credentials].
isArray())
297 jvResult[jss::error] =
"malformedRequest";
301 auto const owner = parseBase58<AccountID>(dp[jss::owner].asString());
304 jvResult[jss::error] =
"malformedOwner";
311 parseBase58<AccountID>(dp[jss::authorized].asString());
314 jvResult[jss::error] =
"malformedAuthorized";
320 auto const& ac(dp[jss::authorized_credentials]);
325 jvResult[jss::error] =
"malformedAuthorizedCredentials";
332 jvResult[jss::error] =
"malformedAuthorizedCredentials";
342 auto const account = parseBase58<AccountID>(params.
asString());
343 if (!account || account->
isZero())
345 jvResult[jss::error] =
"malformedAddress";
357 jvResult[jss::error] =
"malformedRequest";
366 jvResult[jss::error] =
"malformedRequest";
374 jvResult[jss::error] =
"malformedRequest";
379 params.
isMember(jss::sub_index) ? params[jss::sub_index].
asUInt() : 0;
388 jvResult[jss::error] =
"malformedRequest";
394 jvResult[jss::error] =
"malformedRequest";
403 parseBase58<AccountID>(params[jss::owner].asString());
407 jvResult[jss::error] =
"malformedAddress";
414 jvResult[jss::error] =
"malformedRequest";
426 jvResult[jss::error] =
"malformedRequest";
436 jvResult[jss::error] =
"malformedRequest";
440 auto const id = parseBase58<AccountID>(params[jss::owner].asString());
444 jvResult[jss::error] =
"malformedOwner";
459 jvResult[jss::error] =
"malformedRequest";
465 if (!mptJson.
isMember(jss::mpt_issuance_id) ||
468 jvResult[jss::error] =
"malformedRequest";
474 auto const mptIssuanceIdStr = mptJson[jss::mpt_issuance_id].
asString();
477 if (!mptIssuanceID.
parseHex(mptIssuanceIdStr))
478 Throw<std::runtime_error>(
"Cannot parse mpt_issuance_id");
481 parseBase58<AccountID>(mptJson[jss::account].asString());
483 if (!account || account->
isZero())
485 jvResult[jss::error] =
"malformedAddress";
493 jvResult[jss::error] =
"malformedRequest";
503 if (unparsedMPTIssuanceID.
isString())
508 jvResult[jss::error] =
"malformedRequest";
515 jvResult[jss::error] =
"malformedRequest";
527 jvResult[jss::error] =
"malformedRequest";
533 jvResult[jss::error] =
"malformedRequest";
545 jvResult[jss::error] =
"malformedRequest";
554 jvResult[jss::error] =
"malformedRequest";
558 auto const id = parseBase58<AccountID>(params[jss::account].asString());
561 jvResult[jss::error] =
"malformedAddress";
576 jvResult[jss::error] =
"malformedRequest";
582 if (!params.
isMember(jss::oracle_document_id) ||
585 jvResult[jss::error] =
"malformedRequest";
589 auto const& oracle = params;
591 auto const id = oracle[jss::oracle_document_id];
592 if (
id.isUInt() || (
id.isInt() &&
id.asInt() >= 0))
606 parseBase58<AccountID>(oracle[jss::account].asString());
607 if (!account || account->
isZero())
609 jvResult[jss::error] =
"malformedAddress";
615 jvResult[jss::error] =
"malformedDocumentID";
628 jvResult[jss::error] =
"malformedRequest";
646 jvResult[jss::error] =
"malformedRequest";
652 jvResult[jss::error] =
"malformedRequest";
656 if (!pd[jss::account].isString())
658 jvResult[jss::error] =
"malformedAddress";
663 (pd[jss::seq].
isInt() && pd[jss::seq].
asInt() < 0) ||
666 jvResult[jss::error] =
"malformedRequest";
670 auto const account = parseBase58<AccountID>(pd[jss::account].asString());
673 jvResult[jss::error] =
"malformedAddress";
686 !jvRippleState.
isMember(jss::accounts) ||
687 !jvRippleState[jss::accounts].
isArray() ||
688 2 != jvRippleState[jss::accounts].
size() ||
689 !jvRippleState[jss::accounts][0u].
isString() ||
690 !jvRippleState[jss::accounts][1u].
isString() ||
691 (jvRippleState[jss::accounts][0u].
asString() ==
692 jvRippleState[jss::accounts][1u].
asString()))
694 jvResult[jss::error] =
"malformedRequest";
699 parseBase58<AccountID>(jvRippleState[jss::accounts][0u].asString());
701 parseBase58<AccountID>(jvRippleState[jss::accounts][1u].asString());
704 jvResult[jss::error] =
"malformedAddress";
708 if (!
to_currency(uCurrency, jvRippleState[jss::currency].asString()))
710 jvResult[jss::error] =
"malformedCurrency";
725 jvResult[jss::error] =
"malformedRequest";
734 jvResult[jss::error] =
"malformedRequest";
738 auto const id = parseBase58<AccountID>(params[jss::account].asString());
741 jvResult[jss::error] =
"malformedAddress";
756 jvResult[jss::error] =
"malformedRequest";
763 !(params[jss::seq].
isInt() || params[jss::seq].
isUInt()) ||
764 params[jss::seq].
asDouble() <= 0.0 ||
767 jvResult[jss::error] =
"malformedRequest";
771 auto const id = parseBase58<AccountID>(params[jss::owner].asString());
774 jvResult[jss::error] =
"malformedOwner";
790 jvResult[jss::error] =
"malformedRequest";
797 !(claim_id.
isMember(sfIssuingChainDoor.getJsonName()) &&
798 claim_id[sfIssuingChainDoor.getJsonName()].
isString()) ||
799 !(claim_id.
isMember(sfLockingChainDoor.getJsonName()) &&
800 claim_id[sfLockingChainDoor.getJsonName()].
isString()) ||
801 !claim_id.
isMember(sfIssuingChainIssue.getJsonName()) ||
802 !claim_id.
isMember(sfLockingChainIssue.getJsonName()) ||
803 !claim_id.
isMember(jss::xchain_owned_claim_id))
805 jvResult[jss::error] =
"malformedRequest";
813 auto const lockingChainDoor = parseBase58<AccountID>(
814 claim_id[sfLockingChainDoor.getJsonName()].
asString());
815 auto const issuingChainDoor = parseBase58<AccountID>(
816 claim_id[sfIssuingChainDoor.getJsonName()].
asString());
817 Issue lockingChainIssue, issuingChainIssue;
818 bool valid = lockingChainDoor && issuingChainDoor;
831 jvResult[jss::error] =
"malformedRequest";
836 if (
valid && claim_id[jss::xchain_owned_claim_id].isIntegral())
838 auto const seq = claim_id[jss::xchain_owned_claim_id].
asUInt();
849 jvResult[jss::error] =
"malformedRequest";
865 jvResult[jss::error] =
"malformedRequest";
872 !(claim_id.
isMember(sfIssuingChainDoor.getJsonName()) &&
873 claim_id[sfIssuingChainDoor.getJsonName()].
isString()) ||
874 !(claim_id.
isMember(sfLockingChainDoor.getJsonName()) &&
875 claim_id[sfLockingChainDoor.getJsonName()].
isString()) ||
876 !claim_id.
isMember(sfIssuingChainIssue.getJsonName()) ||
877 !claim_id.
isMember(sfLockingChainIssue.getJsonName()) ||
878 !claim_id.
isMember(jss::xchain_owned_create_account_claim_id))
880 jvResult[jss::error] =
"malformedRequest";
889 auto const lockingChainDoor = parseBase58<AccountID>(
890 claim_id[sfLockingChainDoor.getJsonName()].
asString());
891 auto const issuingChainDoor = parseBase58<AccountID>(
892 claim_id[sfIssuingChainDoor.getJsonName()].
asString());
893 Issue lockingChainIssue, issuingChainIssue;
894 bool valid = lockingChainDoor && issuingChainDoor;
907 jvResult[jss::error] =
"malformedRequest";
912 claim_id[jss::xchain_owned_create_account_claim_id].isIntegral())
915 claim_id[jss::xchain_owned_create_account_claim_id].
asUInt();
953 static auto ledgerEntryParsers = std::to_array<LedgerEntry>({
975 {jss::permissioned_domain,
977 ltPERMISSIONED_DOMAIN},
982 {jss::xchain_owned_claim_id,
984 ltXCHAIN_OWNED_CLAIM_ID},
985 {jss::xchain_owned_create_account_claim_id,
987 ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID},
997 for (
auto const& ledgerEntry : ledgerEntryParsers)
1001 expectedType = ledgerEntry.expectedType;
1006 Json::Value const& params = ledgerEntry.fieldName == jss::bridge
1008 : context.
params[ledgerEntry.fieldName];
1009 uNodeIndex = ledgerEntry.parseFunction(params, jvResult)
1010 .value_or(beast::zero);
1011 if (jvResult.isMember(jss::error))
1023 jvResult[jss::error] =
"unknownOption";
1025 jvResult[jss::error] =
"invalidParams";
1035 jvResult[jss::error] =
"invalidParams";
1042 if (uNodeIndex.isZero())
1044 jvResult[jss::error] =
"entryNotFound";
1050 bool bNodeBinary =
false;
1057 jvResult[jss::error] =
"entryNotFound";
1061 if ((expectedType !=
ltANY) && (expectedType != sleNode->getType()))
1063 jvResult[jss::error] =
"unexpectedLedgerType";
1074 jvResult[jss::index] =
to_string(uNodeIndex);
1079 jvResult[jss::index] =
to_string(uNodeIndex);
1089 org::xrpl::rpc::v1::GetLedgerEntryRequest& request = context.
params;
1090 org::xrpl::rpc::v1::GetLedgerEntryResponse response;
1091 grpc::Status status = grpc::Status::OK;
1096 grpc::Status errorStatus;
1099 errorStatus = grpc::Status(
1100 grpc::StatusCode::INVALID_ARGUMENT, status.message());
1105 grpc::Status(grpc::StatusCode::NOT_FOUND, status.message());
1107 return {response, errorStatus};
1113 grpc::Status errorStatus{
1114 grpc::StatusCode::INVALID_ARGUMENT,
"index malformed"};
1115 return {response, errorStatus};
1121 grpc::Status errorStatus{
1122 grpc::StatusCode::NOT_FOUND,
"object not found"};
1123 return {response, errorStatus};
1129 auto& stateObject = *response.mutable_ledger_object();
1131 stateObject.set_key(request.key());
1132 *(response.mutable_ledger()) = request.ledger();
1133 return {response, status};
Lightweight wrapper to tag static string.
UInt size() const
Number of values in array or object.
static UInt const maxUInt
std::string asString() const
Returns the unquoted string value.
bool isNull() const
isNull() tests to see if this field is null.
bool isMember(char const *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 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 vault(AccountID const &owner, std::uint32_t seq) 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.
Json::Value bridge(Account const &lockingChainDoor, Issue const &lockingChainIssue, Account const &issuingChainDoor, Issue const &issuingChainIssue)
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 > parseVault(Json::Value const ¶ms, 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 bool authorized(Port const &port, std::map< std::string, std::string > const &h)
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
Set the sequence number on a JTx.