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";
250 (dp.
isMember(jss::authorized) == dp.
isMember(jss::authorized_credentials)) ||
252 (dp.
isMember(jss::authorized_credentials) && !dp[jss::authorized_credentials].
isArray())
256 jvResult[jss::error] =
"malformedRequest";
260 auto const owner = parseBase58<AccountID>(dp[jss::owner].asString());
263 jvResult[jss::error] =
"malformedOwner";
270 parseBase58<AccountID>(dp[jss::authorized].asString());
273 jvResult[jss::error] =
"malformedAuthorized";
279 auto const& ac(dp[jss::authorized_credentials]);
284 jvResult[jss::error] =
"malformedAuthorizedCredentials";
291 jvResult[jss::error] =
"malformedAuthorizedCredentials";
301 auto const account = parseBase58<AccountID>(params.
asString());
302 if (!account || account->
isZero())
304 jvResult[jss::error] =
"malformedAddress";
316 jvResult[jss::error] =
"malformedRequest";
325 jvResult[jss::error] =
"malformedRequest";
333 jvResult[jss::error] =
"malformedRequest";
338 params.
isMember(jss::sub_index) ? params[jss::sub_index].
asUInt() : 0;
347 jvResult[jss::error] =
"malformedRequest";
353 jvResult[jss::error] =
"malformedRequest";
362 parseBase58<AccountID>(params[jss::owner].asString());
366 jvResult[jss::error] =
"malformedAddress";
373 jvResult[jss::error] =
"malformedRequest";
385 jvResult[jss::error] =
"malformedRequest";
395 jvResult[jss::error] =
"malformedRequest";
399 auto const id = parseBase58<AccountID>(params[jss::owner].asString());
403 jvResult[jss::error] =
"malformedOwner";
418 jvResult[jss::error] =
"malformedRequest";
424 if (!mptJson.
isMember(jss::mpt_issuance_id) ||
427 jvResult[jss::error] =
"malformedRequest";
433 auto const mptIssuanceIdStr = mptJson[jss::mpt_issuance_id].
asString();
436 if (!mptIssuanceID.
parseHex(mptIssuanceIdStr))
437 Throw<std::runtime_error>(
"Cannot parse mpt_issuance_id");
440 parseBase58<AccountID>(mptJson[jss::account].asString());
442 if (!account || account->
isZero())
444 jvResult[jss::error] =
"malformedAddress";
452 jvResult[jss::error] =
"malformedRequest";
462 if (unparsedMPTIssuanceID.
isString())
467 jvResult[jss::error] =
"malformedRequest";
474 jvResult[jss::error] =
"malformedRequest";
486 jvResult[jss::error] =
"malformedRequest";
492 jvResult[jss::error] =
"malformedRequest";
504 jvResult[jss::error] =
"malformedRequest";
513 jvResult[jss::error] =
"malformedRequest";
517 auto const id = parseBase58<AccountID>(params[jss::account].asString());
520 jvResult[jss::error] =
"malformedAddress";
535 jvResult[jss::error] =
"malformedRequest";
541 if (!params.
isMember(jss::oracle_document_id) ||
544 jvResult[jss::error] =
"malformedRequest";
548 auto const& oracle = params;
550 auto const id = oracle[jss::oracle_document_id];
551 if (
id.isUInt() || (
id.isInt() &&
id.asInt() >= 0))
565 parseBase58<AccountID>(oracle[jss::account].asString());
566 if (!account || account->
isZero())
568 jvResult[jss::error] =
"malformedAddress";
574 jvResult[jss::error] =
"malformedDocumentID";
587 jvResult[jss::error] =
"malformedRequest";
605 jvResult[jss::error] =
"malformedRequest";
611 jvResult[jss::error] =
"malformedRequest";
615 if (!pd[jss::account].isString())
617 jvResult[jss::error] =
"malformedAddress";
622 (pd[jss::seq].
isInt() && pd[jss::seq].
asInt() < 0) ||
625 jvResult[jss::error] =
"malformedRequest";
629 auto const account = parseBase58<AccountID>(pd[jss::account].asString());
632 jvResult[jss::error] =
"malformedAddress";
645 !jvRippleState.
isMember(jss::accounts) ||
646 !jvRippleState[jss::accounts].
isArray() ||
647 2 != jvRippleState[jss::accounts].
size() ||
648 !jvRippleState[jss::accounts][0u].
isString() ||
649 !jvRippleState[jss::accounts][1u].
isString() ||
650 (jvRippleState[jss::accounts][0u].
asString() ==
651 jvRippleState[jss::accounts][1u].
asString()))
653 jvResult[jss::error] =
"malformedRequest";
658 parseBase58<AccountID>(jvRippleState[jss::accounts][0u].asString());
660 parseBase58<AccountID>(jvRippleState[jss::accounts][1u].asString());
663 jvResult[jss::error] =
"malformedAddress";
667 if (!
to_currency(uCurrency, jvRippleState[jss::currency].asString()))
669 jvResult[jss::error] =
"malformedCurrency";
684 jvResult[jss::error] =
"malformedRequest";
693 jvResult[jss::error] =
"malformedRequest";
697 auto const id = parseBase58<AccountID>(params[jss::account].asString());
700 jvResult[jss::error] =
"malformedAddress";
716 jvResult[jss::error] =
"malformedRequest";
723 !(claim_id.
isMember(sfIssuingChainDoor.getJsonName()) &&
724 claim_id[sfIssuingChainDoor.getJsonName()].
isString()) ||
725 !(claim_id.
isMember(sfLockingChainDoor.getJsonName()) &&
726 claim_id[sfLockingChainDoor.getJsonName()].
isString()) ||
727 !claim_id.
isMember(sfIssuingChainIssue.getJsonName()) ||
728 !claim_id.
isMember(sfLockingChainIssue.getJsonName()) ||
729 !claim_id.
isMember(jss::xchain_owned_claim_id))
731 jvResult[jss::error] =
"malformedRequest";
739 auto const lockingChainDoor = parseBase58<AccountID>(
740 claim_id[sfLockingChainDoor.getJsonName()].
asString());
741 auto const issuingChainDoor = parseBase58<AccountID>(
742 claim_id[sfIssuingChainDoor.getJsonName()].
asString());
743 Issue lockingChainIssue, issuingChainIssue;
744 bool valid = lockingChainDoor && issuingChainDoor;
757 jvResult[jss::error] =
"malformedRequest";
762 if (
valid && claim_id[jss::xchain_owned_claim_id].isIntegral())
764 auto const seq = claim_id[jss::xchain_owned_claim_id].
asUInt();
775 jvResult[jss::error] =
"malformedRequest";
791 jvResult[jss::error] =
"malformedRequest";
798 !(claim_id.
isMember(sfIssuingChainDoor.getJsonName()) &&
799 claim_id[sfIssuingChainDoor.getJsonName()].
isString()) ||
800 !(claim_id.
isMember(sfLockingChainDoor.getJsonName()) &&
801 claim_id[sfLockingChainDoor.getJsonName()].
isString()) ||
802 !claim_id.
isMember(sfIssuingChainIssue.getJsonName()) ||
803 !claim_id.
isMember(sfLockingChainIssue.getJsonName()) ||
804 !claim_id.
isMember(jss::xchain_owned_create_account_claim_id))
806 jvResult[jss::error] =
"malformedRequest";
815 auto const lockingChainDoor = parseBase58<AccountID>(
816 claim_id[sfLockingChainDoor.getJsonName()].
asString());
817 auto const issuingChainDoor = parseBase58<AccountID>(
818 claim_id[sfIssuingChainDoor.getJsonName()].
asString());
819 Issue lockingChainIssue, issuingChainIssue;
820 bool valid = lockingChainDoor && issuingChainDoor;
833 jvResult[jss::error] =
"malformedRequest";
838 claim_id[jss::xchain_owned_create_account_claim_id].isIntegral())
841 claim_id[jss::xchain_owned_create_account_claim_id].
asUInt();
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