20#include <xrpld/app/main/Application.h>
21#include <xrpld/app/misc/CredentialHelpers.h>
22#include <xrpld/ledger/ReadView.h>
23#include <xrpld/rpc/Context.h>
24#include <xrpld/rpc/GRPCHandlers.h>
25#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>
43 for (
auto const& jo : jv)
46 !jo.isMember(jss::issuer) || !jo[jss::issuer].isString() ||
47 !jo.isMember(jss::credential_type) ||
48 !jo[jss::credential_type].isString())
51 auto const issuer = parseBase58<AccountID>(jo[jss::issuer].asString());
52 if (!issuer || !*issuer)
55 auto const credentialType =
56 strUnHex(jo[jss::credential_type].asString());
57 if (!credentialType || credentialType->empty() ||
63 credential.setFieldVL(sfCredentialType, *credentialType);
76 jvResult[jss::error] =
"malformedRequest";
86 auto const account = parseBase58<AccountID>(params.
asString());
87 if (!account || account->
isZero())
89 jvResult[jss::error] =
"malformedAddress";
102 jvResult[jss::error] =
"malformedRequest";
117 jvResult[jss::error] =
"malformedRequest";
126 (dp.
isMember(jss::authorized) == dp.
isMember(jss::authorized_credentials)) ||
128 (dp.
isMember(jss::authorized_credentials) && !dp[jss::authorized_credentials].
isArray())
132 jvResult[jss::error] =
"malformedRequest";
136 auto const owner = parseBase58<AccountID>(dp[jss::owner].asString());
139 jvResult[jss::error] =
"malformedOwner";
146 parseBase58<AccountID>(dp[jss::authorized].asString());
149 jvResult[jss::error] =
"malformedAuthorized";
155 auto const& ac(dp[jss::authorized_credentials]);
160 jvResult[jss::error] =
"malformedAuthorizedCredentials";
167 jvResult[jss::error] =
"malformedAuthorizedCredentials";
179 jvResult[jss::error] =
"malformedRequest";
188 jvResult[jss::error] =
"malformedRequest";
196 jvResult[jss::error] =
"malformedRequest";
201 params.
isMember(jss::sub_index) ? params[jss::sub_index].
asUInt() : 0;
210 jvResult[jss::error] =
"malformedRequest";
216 jvResult[jss::error] =
"malformedRequest";
225 parseBase58<AccountID>(params[jss::owner].asString());
229 jvResult[jss::error] =
"malformedAddress";
236 jvResult[jss::error] =
"malformedRequest";
248 jvResult[jss::error] =
"malformedRequest";
258 jvResult[jss::error] =
"malformedRequest";
262 auto const id = parseBase58<AccountID>(params[jss::owner].asString());
266 jvResult[jss::error] =
"malformedOwner";
281 jvResult[jss::error] =
"malformedRequest";
290 jvResult[jss::error] =
"malformedRequest";
294 auto const id = parseBase58<AccountID>(params[jss::account].asString());
297 jvResult[jss::error] =
"malformedAddress";
310 jvResult[jss::error] =
"malformedRequest";
323 !jvRippleState.
isMember(jss::accounts) ||
324 !jvRippleState[jss::accounts].
isArray() ||
325 2 != jvRippleState[jss::accounts].
size() ||
326 !jvRippleState[jss::accounts][0u].
isString() ||
327 !jvRippleState[jss::accounts][1u].
isString() ||
328 (jvRippleState[jss::accounts][0u].
asString() ==
329 jvRippleState[jss::accounts][1u].
asString()))
331 jvResult[jss::error] =
"malformedRequest";
336 parseBase58<AccountID>(jvRippleState[jss::accounts][0u].asString());
338 parseBase58<AccountID>(jvRippleState[jss::accounts][1u].asString());
341 jvResult[jss::error] =
"malformedAddress";
345 if (!
to_currency(uCurrency, jvRippleState[jss::currency].asString()))
347 jvResult[jss::error] =
"malformedCurrency";
362 jvResult[jss::error] =
"malformedRequest";
371 jvResult[jss::error] =
"malformedRequest";
375 auto const id = parseBase58<AccountID>(params[jss::account].asString());
378 jvResult[jss::error] =
"malformedAddress";
393 jvResult[jss::error] =
"malformedRequest";
399 jvResult[jss::error] =
"malformedRequest";
411 jvResult[jss::error] =
"malformedRequest";
419 jvResult[jss::error] =
"malformedRequest";
431 jvResult[jss::error] =
"malformedRequest";
444 if (!params.
isMember(jss::bridge_account))
447 auto const& jsBridgeAccount = params[jss::bridge_account];
448 if (!jsBridgeAccount.isString())
454 parseBase58<AccountID>(jsBridgeAccount.asString());
455 if (!account || account->
isZero())
467 if (account != bridge.door(chainType))
480 return maybeKeylet->key;
483 jvResult[jss::error] =
"malformedRequest";
496 jvResult[jss::error] =
"malformedRequest";
503 !(claim_id.
isMember(sfIssuingChainDoor.getJsonName()) &&
504 claim_id[sfIssuingChainDoor.getJsonName()].
isString()) ||
505 !(claim_id.
isMember(sfLockingChainDoor.getJsonName()) &&
506 claim_id[sfLockingChainDoor.getJsonName()].
isString()) ||
507 !claim_id.
isMember(sfIssuingChainIssue.getJsonName()) ||
508 !claim_id.
isMember(sfLockingChainIssue.getJsonName()) ||
509 !claim_id.
isMember(jss::xchain_owned_claim_id))
511 jvResult[jss::error] =
"malformedRequest";
519 auto const lockingChainDoor = parseBase58<AccountID>(
520 claim_id[sfLockingChainDoor.getJsonName()].
asString());
521 auto const issuingChainDoor = parseBase58<AccountID>(
522 claim_id[sfIssuingChainDoor.getJsonName()].
asString());
523 Issue lockingChainIssue, issuingChainIssue;
524 bool valid = lockingChainDoor && issuingChainDoor;
537 jvResult[jss::error] =
"malformedRequest";
542 if (
valid && claim_id[jss::xchain_owned_claim_id].isIntegral())
544 auto const seq = claim_id[jss::xchain_owned_claim_id].
asUInt();
555 jvResult[jss::error] =
"malformedRequest";
571 jvResult[jss::error] =
"malformedRequest";
578 !(claim_id.
isMember(sfIssuingChainDoor.getJsonName()) &&
579 claim_id[sfIssuingChainDoor.getJsonName()].
isString()) ||
580 !(claim_id.
isMember(sfLockingChainDoor.getJsonName()) &&
581 claim_id[sfLockingChainDoor.getJsonName()].
isString()) ||
582 !claim_id.
isMember(sfIssuingChainIssue.getJsonName()) ||
583 !claim_id.
isMember(sfLockingChainIssue.getJsonName()) ||
584 !claim_id.
isMember(jss::xchain_owned_create_account_claim_id))
586 jvResult[jss::error] =
"malformedRequest";
595 auto const lockingChainDoor = parseBase58<AccountID>(
596 claim_id[sfLockingChainDoor.getJsonName()].
asString());
597 auto const issuingChainDoor = parseBase58<AccountID>(
598 claim_id[sfIssuingChainDoor.getJsonName()].
asString());
599 Issue lockingChainIssue, issuingChainIssue;
600 bool valid = lockingChainDoor && issuingChainDoor;
613 jvResult[jss::error] =
"malformedRequest";
618 claim_id[jss::xchain_owned_create_account_claim_id].isIntegral())
621 claim_id[jss::xchain_owned_create_account_claim_id].
asUInt();
638 auto const account = parseBase58<AccountID>(params.
asString());
639 if (!account || account->
isZero())
641 jvResult[jss::error] =
"malformedAddress";
656 jvResult[jss::error] =
"malformedRequest";
662 if (!params.
isMember(jss::oracle_document_id) ||
665 jvResult[jss::error] =
"malformedRequest";
669 auto const& oracle = params;
671 auto const id = oracle[jss::oracle_document_id];
672 if (
id.isUInt() || (
id.isInt() &&
id.asInt() >= 0))
686 parseBase58<AccountID>(oracle[jss::account].asString());
687 if (!account || account->
isZero())
689 jvResult[jss::error] =
"malformedAddress";
695 jvResult[jss::error] =
"malformedDocumentID";
710 jvResult[jss::error] =
"malformedRequest";
718 (!cred.
isMember(jss::credential_type) ||
719 !cred[jss::credential_type].
isString()))
721 jvResult[jss::error] =
"malformedRequest";
725 auto const subject = parseBase58<AccountID>(cred[jss::subject].asString());
726 auto const issuer = parseBase58<AccountID>(cred[jss::issuer].asString());
727 auto const credType =
strUnHex(cred[jss::credential_type].asString());
729 if (!subject || subject->isZero() || !issuer || issuer->isZero() ||
730 !credType || credType->empty())
732 jvResult[jss::error] =
"malformedRequest";
737 *subject, *issuer,
Slice(credType->data(), credType->size()))
746 if (unparsedMPTIssuanceID.
isString())
751 jvResult[jss::error] =
"malformedRequest";
758 jvResult[jss::error] =
"malformedRequest";
770 jvResult[jss::error] =
"malformedRequest";
776 if (!mptJson.
isMember(jss::mpt_issuance_id) ||
779 jvResult[jss::error] =
"malformedRequest";
785 auto const mptIssuanceIdStr = mptJson[jss::mpt_issuance_id].
asString();
788 if (!mptIssuanceID.
parseHex(mptIssuanceIdStr))
789 Throw<std::runtime_error>(
"Cannot parse mpt_issuance_id");
792 parseBase58<AccountID>(mptJson[jss::account].asString());
794 if (!account || account->
isZero())
796 jvResult[jss::error] =
"malformedAddress";
804 jvResult[jss::error] =
"malformedRequest";
820 jvResult[jss::error] =
"malformedRequest";
826 jvResult[jss::error] =
"malformedRequest";
831 (pd[jss::seq].
isInt() && pd[jss::seq].
asInt() < 0) ||
834 jvResult[jss::error] =
"malformedRequest";
838 auto const account = parseBase58<AccountID>(pd[jss::account].asString());
841 jvResult[jss::error] =
"malformedAddress";
872 static auto ledgerEntryParsers = std::to_array<LedgerEntry>({
893 {jss::permissioned_domain,
895 ltPERMISSIONED_DOMAIN},
900 {jss::xchain_owned_claim_id,
902 ltXCHAIN_OWNED_CLAIM_ID},
903 {jss::xchain_owned_create_account_claim_id,
905 ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID},
914 for (
const auto& ledgerEntry : ledgerEntryParsers)
918 expectedType = ledgerEntry.expectedType;
923 Json::Value const& params = ledgerEntry.fieldName == jss::bridge
925 : context.
params[ledgerEntry.fieldName];
926 uNodeIndex = ledgerEntry.parseFunction(params, jvResult)
927 .value_or(beast::zero);
928 if (jvResult.isMember(jss::error))
940 jvResult[jss::error] =
"unknownOption";
942 jvResult[jss::error] =
"invalidParams";
952 jvResult[jss::error] =
"invalidParams";
959 if (uNodeIndex.isZero())
961 jvResult[jss::error] =
"entryNotFound";
967 bool bNodeBinary =
false;
974 jvResult[jss::error] =
"entryNotFound";
978 if ((expectedType !=
ltANY) && (expectedType != sleNode->getType()))
980 jvResult[jss::error] =
"unexpectedLedgerType";
991 jvResult[jss::index] =
to_string(uNodeIndex);
996 jvResult[jss::index] =
to_string(uNodeIndex);
1006 org::xrpl::rpc::v1::GetLedgerEntryRequest& request = context.
params;
1007 org::xrpl::rpc::v1::GetLedgerEntryResponse response;
1008 grpc::Status status = grpc::Status::OK;
1013 grpc::Status errorStatus;
1016 errorStatus = grpc::Status(
1017 grpc::StatusCode::INVALID_ARGUMENT, status.message());
1022 grpc::Status(grpc::StatusCode::NOT_FOUND, status.message());
1024 return {response, errorStatus};
1030 grpc::Status errorStatus{
1031 grpc::StatusCode::INVALID_ARGUMENT,
"index malformed"};
1032 return {response, errorStatus};
1038 grpc::Status errorStatus{
1039 grpc::StatusCode::NOT_FOUND,
"object not found"};
1040 return {response, errorStatus};
1046 auto& stateObject = *response.mutable_ledger_object();
1048 stateObject.set_key(request.key());
1049 *(response.mutable_ledger()) = request.ledger();
1050 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 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 > 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