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>
44 for (
auto const& jo : jv)
47 !jo.isMember(jss::issuer) || !jo[jss::issuer].isString() ||
48 !jo.isMember(jss::credential_type) ||
49 !jo[jss::credential_type].isString())
52 auto const issuer = parseBase58<AccountID>(jo[jss::issuer].asString());
53 if (!issuer || !*issuer)
56 auto const credentialType =
57 strUnHex(jo[jss::credential_type].asString());
58 if (!credentialType || credentialType->empty() ||
64 credential.setFieldVL(sfCredentialType, *credentialType);
77 jvResult[jss::error] =
"malformedRequest";
87 auto const account = parseBase58<AccountID>(params.
asString());
88 if (!account || account->
isZero())
90 jvResult[jss::error] =
"malformedAddress";
103 jvResult[jss::error] =
"malformedRequest";
118 jvResult[jss::error] =
"malformedRequest";
127 (dp.
isMember(jss::authorized) == dp.
isMember(jss::authorized_credentials)) ||
129 (dp.
isMember(jss::authorized_credentials) && !dp[jss::authorized_credentials].
isArray())
133 jvResult[jss::error] =
"malformedRequest";
137 auto const owner = parseBase58<AccountID>(dp[jss::owner].asString());
140 jvResult[jss::error] =
"malformedOwner";
147 parseBase58<AccountID>(dp[jss::authorized].asString());
150 jvResult[jss::error] =
"malformedAuthorized";
156 auto const& ac(dp[jss::authorized_credentials]);
161 jvResult[jss::error] =
"malformedAuthorizedCredentials";
168 jvResult[jss::error] =
"malformedAuthorizedCredentials";
180 jvResult[jss::error] =
"malformedRequest";
189 jvResult[jss::error] =
"malformedRequest";
197 jvResult[jss::error] =
"malformedRequest";
202 params.
isMember(jss::sub_index) ? params[jss::sub_index].
asUInt() : 0;
211 jvResult[jss::error] =
"malformedRequest";
217 jvResult[jss::error] =
"malformedRequest";
226 parseBase58<AccountID>(params[jss::owner].asString());
230 jvResult[jss::error] =
"malformedAddress";
237 jvResult[jss::error] =
"malformedRequest";
249 jvResult[jss::error] =
"malformedRequest";
259 jvResult[jss::error] =
"malformedRequest";
263 auto const id = parseBase58<AccountID>(params[jss::owner].asString());
267 jvResult[jss::error] =
"malformedOwner";
282 jvResult[jss::error] =
"malformedRequest";
291 jvResult[jss::error] =
"malformedRequest";
295 auto const id = parseBase58<AccountID>(params[jss::account].asString());
298 jvResult[jss::error] =
"malformedAddress";
311 jvResult[jss::error] =
"malformedRequest";
324 !jvRippleState.
isMember(jss::accounts) ||
325 !jvRippleState[jss::accounts].
isArray() ||
326 2 != jvRippleState[jss::accounts].
size() ||
327 !jvRippleState[jss::accounts][0u].
isString() ||
328 !jvRippleState[jss::accounts][1u].
isString() ||
329 (jvRippleState[jss::accounts][0u].
asString() ==
330 jvRippleState[jss::accounts][1u].
asString()))
332 jvResult[jss::error] =
"malformedRequest";
337 parseBase58<AccountID>(jvRippleState[jss::accounts][0u].asString());
339 parseBase58<AccountID>(jvRippleState[jss::accounts][1u].asString());
342 jvResult[jss::error] =
"malformedAddress";
346 if (!
to_currency(uCurrency, jvRippleState[jss::currency].asString()))
348 jvResult[jss::error] =
"malformedCurrency";
363 jvResult[jss::error] =
"malformedRequest";
372 jvResult[jss::error] =
"malformedRequest";
376 auto const id = parseBase58<AccountID>(params[jss::account].asString());
379 jvResult[jss::error] =
"malformedAddress";
394 jvResult[jss::error] =
"malformedRequest";
400 jvResult[jss::error] =
"malformedRequest";
412 jvResult[jss::error] =
"malformedRequest";
420 jvResult[jss::error] =
"malformedRequest";
432 jvResult[jss::error] =
"malformedRequest";
445 if (!params.
isMember(jss::bridge_account))
448 auto const& jsBridgeAccount = params[jss::bridge_account];
449 if (!jsBridgeAccount.isString())
455 parseBase58<AccountID>(jsBridgeAccount.asString());
456 if (!account || account->
isZero())
468 if (account != bridge.door(chainType))
481 return maybeKeylet->key;
484 jvResult[jss::error] =
"malformedRequest";
497 jvResult[jss::error] =
"malformedRequest";
504 !(claim_id.
isMember(sfIssuingChainDoor.getJsonName()) &&
505 claim_id[sfIssuingChainDoor.getJsonName()].
isString()) ||
506 !(claim_id.
isMember(sfLockingChainDoor.getJsonName()) &&
507 claim_id[sfLockingChainDoor.getJsonName()].
isString()) ||
508 !claim_id.
isMember(sfIssuingChainIssue.getJsonName()) ||
509 !claim_id.
isMember(sfLockingChainIssue.getJsonName()) ||
510 !claim_id.
isMember(jss::xchain_owned_claim_id))
512 jvResult[jss::error] =
"malformedRequest";
520 auto const lockingChainDoor = parseBase58<AccountID>(
521 claim_id[sfLockingChainDoor.getJsonName()].
asString());
522 auto const issuingChainDoor = parseBase58<AccountID>(
523 claim_id[sfIssuingChainDoor.getJsonName()].
asString());
524 Issue lockingChainIssue, issuingChainIssue;
525 bool valid = lockingChainDoor && issuingChainDoor;
538 jvResult[jss::error] =
"malformedRequest";
543 if (
valid && claim_id[jss::xchain_owned_claim_id].isIntegral())
545 auto const seq = claim_id[jss::xchain_owned_claim_id].
asUInt();
556 jvResult[jss::error] =
"malformedRequest";
572 jvResult[jss::error] =
"malformedRequest";
579 !(claim_id.
isMember(sfIssuingChainDoor.getJsonName()) &&
580 claim_id[sfIssuingChainDoor.getJsonName()].
isString()) ||
581 !(claim_id.
isMember(sfLockingChainDoor.getJsonName()) &&
582 claim_id[sfLockingChainDoor.getJsonName()].
isString()) ||
583 !claim_id.
isMember(sfIssuingChainIssue.getJsonName()) ||
584 !claim_id.
isMember(sfLockingChainIssue.getJsonName()) ||
585 !claim_id.
isMember(jss::xchain_owned_create_account_claim_id))
587 jvResult[jss::error] =
"malformedRequest";
596 auto const lockingChainDoor = parseBase58<AccountID>(
597 claim_id[sfLockingChainDoor.getJsonName()].
asString());
598 auto const issuingChainDoor = parseBase58<AccountID>(
599 claim_id[sfIssuingChainDoor.getJsonName()].
asString());
600 Issue lockingChainIssue, issuingChainIssue;
601 bool valid = lockingChainDoor && issuingChainDoor;
614 jvResult[jss::error] =
"malformedRequest";
619 claim_id[jss::xchain_owned_create_account_claim_id].isIntegral())
622 claim_id[jss::xchain_owned_create_account_claim_id].
asUInt();
639 auto const account = parseBase58<AccountID>(params.
asString());
640 if (!account || account->
isZero())
642 jvResult[jss::error] =
"malformedAddress";
657 jvResult[jss::error] =
"malformedRequest";
663 if (!params.
isMember(jss::oracle_document_id) ||
666 jvResult[jss::error] =
"malformedRequest";
670 auto const& oracle = params;
672 auto const id = oracle[jss::oracle_document_id];
673 if (
id.isUInt() || (
id.isInt() &&
id.asInt() >= 0))
687 parseBase58<AccountID>(oracle[jss::account].asString());
688 if (!account || account->
isZero())
690 jvResult[jss::error] =
"malformedAddress";
696 jvResult[jss::error] =
"malformedDocumentID";
711 jvResult[jss::error] =
"malformedRequest";
719 (!cred.
isMember(jss::credential_type) ||
720 !cred[jss::credential_type].
isString()))
722 jvResult[jss::error] =
"malformedRequest";
726 auto const subject = parseBase58<AccountID>(cred[jss::subject].asString());
727 auto const issuer = parseBase58<AccountID>(cred[jss::issuer].asString());
728 auto const credType =
strUnHex(cred[jss::credential_type].asString());
730 if (!subject || subject->isZero() || !issuer || issuer->isZero() ||
731 !credType || credType->empty())
733 jvResult[jss::error] =
"malformedRequest";
738 *subject, *issuer,
Slice(credType->data(), credType->size()))
747 if (unparsedMPTIssuanceID.
isString())
752 jvResult[jss::error] =
"malformedRequest";
759 jvResult[jss::error] =
"malformedRequest";
771 jvResult[jss::error] =
"malformedRequest";
777 if (!mptJson.
isMember(jss::mpt_issuance_id) ||
780 jvResult[jss::error] =
"malformedRequest";
786 auto const mptIssuanceIdStr = mptJson[jss::mpt_issuance_id].
asString();
789 if (!mptIssuanceID.
parseHex(mptIssuanceIdStr))
790 Throw<std::runtime_error>(
"Cannot parse mpt_issuance_id");
793 parseBase58<AccountID>(mptJson[jss::account].asString());
795 if (!account || account->
isZero())
797 jvResult[jss::error] =
"malformedAddress";
805 jvResult[jss::error] =
"malformedRequest";
821 jvResult[jss::error] =
"malformedRequest";
827 jvResult[jss::error] =
"malformedRequest";
831 if (!pd[jss::account].isString())
833 jvResult[jss::error] =
"malformedAddress";
838 (pd[jss::seq].
isInt() && pd[jss::seq].
asInt() < 0) ||
841 jvResult[jss::error] =
"malformedRequest";
845 auto const account = parseBase58<AccountID>(pd[jss::account].asString());
848 jvResult[jss::error] =
"malformedAddress";
879 static auto ledgerEntryParsers = std::to_array<LedgerEntry>({
900 {jss::permissioned_domain,
902 ltPERMISSIONED_DOMAIN},
907 {jss::xchain_owned_claim_id,
909 ltXCHAIN_OWNED_CLAIM_ID},
910 {jss::xchain_owned_create_account_claim_id,
912 ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID},
921 for (
const auto& ledgerEntry : ledgerEntryParsers)
925 expectedType = ledgerEntry.expectedType;
930 Json::Value const& params = ledgerEntry.fieldName == jss::bridge
932 : context.
params[ledgerEntry.fieldName];
933 uNodeIndex = ledgerEntry.parseFunction(params, jvResult)
934 .value_or(beast::zero);
935 if (jvResult.isMember(jss::error))
947 jvResult[jss::error] =
"unknownOption";
949 jvResult[jss::error] =
"invalidParams";
959 jvResult[jss::error] =
"invalidParams";
966 if (uNodeIndex.isZero())
968 jvResult[jss::error] =
"entryNotFound";
974 bool bNodeBinary =
false;
981 jvResult[jss::error] =
"entryNotFound";
985 if ((expectedType !=
ltANY) && (expectedType != sleNode->getType()))
987 jvResult[jss::error] =
"unexpectedLedgerType";
998 jvResult[jss::index] =
to_string(uNodeIndex);
1003 jvResult[jss::index] =
to_string(uNodeIndex);
1013 org::xrpl::rpc::v1::GetLedgerEntryRequest& request = context.
params;
1014 org::xrpl::rpc::v1::GetLedgerEntryResponse response;
1015 grpc::Status status = grpc::Status::OK;
1020 grpc::Status errorStatus;
1023 errorStatus = grpc::Status(
1024 grpc::StatusCode::INVALID_ARGUMENT, status.message());
1029 grpc::Status(grpc::StatusCode::NOT_FOUND, status.message());
1031 return {response, errorStatus};
1037 grpc::Status errorStatus{
1038 grpc::StatusCode::INVALID_ARGUMENT,
"index malformed"};
1039 return {response, errorStatus};
1045 grpc::Status errorStatus{
1046 grpc::StatusCode::NOT_FOUND,
"object not found"};
1047 return {response, errorStatus};
1053 auto& stateObject = *response.mutable_ledger_object();
1055 stateObject.set_key(request.key());
1056 *(response.mutable_ledger()) = request.ledger();
1057 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