1#include <xrpld/app/ledger/LedgerMaster.h> 
    2#include <xrpld/app/ledger/LedgerToJson.h> 
    3#include <xrpld/app/ledger/OpenLedger.h> 
    4#include <xrpld/app/misc/Transaction.h> 
    5#include <xrpld/app/paths/TrustLine.h> 
    6#include <xrpld/app/rdb/RelationalDatabase.h> 
    7#include <xrpld/app/tx/detail/NFTokenUtils.h> 
    8#include <xrpld/rpc/Context.h> 
    9#include <xrpld/rpc/DeliveredAmount.h> 
   10#include <xrpld/rpc/detail/RPCHelpers.h> 
   12#include <xrpl/ledger/View.h> 
   13#include <xrpl/protocol/AccountID.h> 
   14#include <xrpl/protocol/RPCErr.h> 
   15#include <xrpl/protocol/nftPageMask.h> 
   16#include <xrpl/resource/Fees.h> 
   18#include <boost/algorithm/string/case_conv.hpp> 
   19#include <boost/algorithm/string/predicate.hpp> 
   29    auto const publicKey =
 
   35        result = parseBase58<AccountID>(account);
 
 
   81    if (sle->getType() == ltRIPPLE_STATE)
 
   83        if (sle->getFieldAmount(sfLowLimit).getIssuer() == accountID)
 
   84            return sle->getFieldU64(sfLowNode);
 
   85        else if (sle->getFieldAmount(sfHighLimit).getIssuer() == accountID)
 
   86            return sle->getFieldU64(sfHighNode);
 
   89    if (!sle->isFieldPresent(sfOwnerNode))
 
   92    return sle->getFieldU64(sfOwnerNode);
 
 
  101    if (sle->getType() == ltRIPPLE_STATE)
 
  103        return (sle->getFieldAmount(sfLowLimit).getIssuer() == accountID) ||
 
  104            (sle->getFieldAmount(sfHighLimit).getIssuer() == accountID);
 
  106    else if (sle->isFieldPresent(sfAccount))
 
  114        return sle->getAccountID(sfAccount) == accountID ||
 
  115            (sle->isFieldPresent(sfDestination) &&
 
  116             sle->getAccountID(sfDestination) == accountID);
 
  118    else if (sle->getType() == ltSIGNER_LIST)
 
  121        return sle->key() == accountSignerList.
key;
 
  123    else if (sle->getType() == ltNFTOKEN_OFFER)
 
  127        return sle->getAccountID(sfOwner) == accountID;
 
 
  144    if (!dirIndex.
isZero() && !ledger.
read({ltDIR_NODE, dirIndex}))
 
  150        return it != typeFilter.
end();
 
  155    bool iterateNFTPages =
 
  156        (!typeFilter.has_value() ||
 
  157         typeMatchesFilter(typeFilter.value(), ltNFTOKEN_PAGE)) &&
 
  158        dirIndex == beast::zero;
 
  163    if (iterateNFTPages && entryIndex != beast::zero)
 
  169            iterateNFTPages = 
false;
 
  176    uint32_t mlimit = limit;
 
  181        Keylet const first = entryIndex == beast::zero
 
  183            : 
Keylet{ltNFTOKEN_PAGE, entryIndex};
 
  191        auto cp = ledger.
read(
Keylet{ltNFTOKEN_PAGE, ck});
 
  196            auto const npm = (*cp)[~sfNextPageMin];
 
  198                cp = ledger.
read(
Keylet(ltNFTOKEN_PAGE, *npm));
 
  206                    jvResult[jss::limit] = limit;
 
  222        entryIndex = beast::zero;
 
  234    auto dir = ledger.
read({ltDIR_NODE, dirIndex});
 
  255        auto const& entries = dir->getFieldV256(sfIndexes);
 
  256        auto iter = entries.begin();
 
  260            iter = 
std::find(iter, entries.end(), entryIndex);
 
  261            if (iter == entries.end())
 
  269        if (i == mlimit && mlimit < limit)
 
  271            jvResult[jss::limit] = limit;
 
  272            jvResult[jss::marker] =
 
  277        for (; iter != entries.end(); ++iter)
 
  281            if (!typeFilter.has_value() ||
 
  282                typeMatchesFilter(typeFilter.value(), sleNode->getType()))
 
  289                if (++iter != entries.end())
 
  291                    jvResult[jss::limit] = limit;
 
  292                    jvResult[jss::marker] =
 
  301        auto const nodeIndex = dir->getFieldU64(sfIndexNext);
 
  306        dir = ledger.
read({ltDIR_NODE, dirIndex});
 
  312            auto const& e = dir->getFieldV256(sfIndexes);
 
  315                jvResult[jss::limit] = limit;
 
  316                jvResult[jss::marker] =
 
 
  342    auto& params = context.params;
 
  344    auto indexValue = params[jss::ledger_index];
 
  345    auto hashValue = params[jss::ledger_hash];
 
  348    auto& legacyLedger = params[jss::ledger];
 
  351        if (legacyLedger.asString().size() > 12)
 
  352            hashValue = legacyLedger;
 
  354            indexValue = legacyLedger;
 
  357    if (!hashValue.isNull())
 
  359        if (!hashValue.isString())
 
  363        if (!ledgerHash.parseHex(hashValue.asString()))
 
  365        return getLedger(ledger, ledgerHash, context);
 
  371    auto const index = indexValue.asString();
 
  373    if (index == 
"current" || index.empty())
 
  374        return getLedger(ledger, LedgerShortcut::CURRENT, context);
 
  376    if (index == 
"validated")
 
  377        return getLedger(ledger, LedgerShortcut::VALIDATED, context);
 
  379    if (index == 
"closed")
 
  380        return getLedger(ledger, LedgerShortcut::CLOSED, context);
 
  390template <
class T, 
class R>
 
  394    R& request = context.
params;
 
 
  420    org::xrpl::rpc::v1::LedgerSpecifier 
const& specifier,
 
  425    using LedgerCase = org::xrpl::rpc::v1::LedgerSpecifier::LedgerCase;
 
  426    LedgerCase ledgerCase = specifier.ledger_case();
 
  429        case LedgerCase::kHash: {
 
  432                return getLedger(ledger, *hash, context);
 
  436        case LedgerCase::kSequence:
 
  437            return getLedger(ledger, specifier.sequence(), context);
 
  438        case LedgerCase::kShortcut:
 
  440        case LedgerCase::LEDGER_NOT_SET: {
 
  441            auto const shortcut = specifier.shortcut();
 
  443                org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_VALIDATED)
 
  445                return getLedger(ledger, LedgerShortcut::VALIDATED, context);
 
  450                        org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_CURRENT ||
 
  452                        org::xrpl::rpc::v1::LedgerSpecifier::
 
  453                            SHORTCUT_UNSPECIFIED)
 
  455                    return getLedger(ledger, LedgerShortcut::CURRENT, context);
 
  459                    org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_CLOSED)
 
  461                    return getLedger(ledger, LedgerShortcut::CLOSED, context);
 
 
  475    if (ledger == 
nullptr)
 
 
  485    if (ledger == 
nullptr)
 
  488        if (cur->info().seq == ledgerIndex)
 
  494    if (ledger == 
nullptr)
 
 
  520    if (shortcut == LedgerShortcut::VALIDATED)
 
  523        if (ledger == 
nullptr)
 
  531            !ledger->open(), 
"ripple::RPC::getLedger : validated is not open");
 
  535        if (shortcut == LedgerShortcut::CURRENT)
 
  539                ledger->open(), 
"ripple::RPC::getLedger : current is open");
 
  541        else if (shortcut == LedgerShortcut::CLOSED)
 
  545                !ledger->open(), 
"ripple::RPC::getLedger : closed is not open");
 
  552        if (ledger == 
nullptr)
 
  559        static auto const minSequenceGap = 10;
 
  561        if (ledger->info().seq + minSequenceGap <
 
 
  614    auto& info = ledger->info();
 
  618        result[jss::ledger_hash] = 
to_string(info.hash);
 
  619        result[jss::ledger_index] = info.seq;
 
  623        result[jss::ledger_current_index] = info.seq;
 
 
  634    if (
auto status = 
lookupLedger(ledger, context, result))
 
  635        status.inject(result);
 
 
  644    for (
auto const& jv : jvArray)
 
  648        auto const id = parseBase58<AccountID>(jv.asString());
 
 
  660    if (sle.
getType() == ltACCOUNT_ROOT)
 
  665            Blob const b(hash.begin(), hash.end());
 
  667            boost::to_lower(md5);
 
  671            jv[jss::urlgravatar] =
 
  672                str(boost::format(
"http://www.gravatar.com/avatar/%s") % md5);
 
  677        jv[jss::Invalid] = 
true;
 
 
  687    limit = 
range.rdefault;
 
  692    auto const& jvLimit = context.
params[jss::limit];
 
  693    if (!(jvLimit.isUInt() || (jvLimit.isInt() && jvLimit.asInt() >= 0)))
 
  696    limit = jvLimit.asUInt();
 
 
  717    if (result.size() == 18 &&
 
 
  728    using string_to_seed_t =
 
  732    static seed_match_t 
const seedTypes[]{
 
  733        {jss::passphrase.c_str(),
 
  736         [](
std::string const& s) { 
return parseBase58<Seed>(s); }},
 
  745    seed_match_t 
const* seedType = 
nullptr;
 
  747    for (
auto const& t : seedTypes)
 
  759            "Exactly one of the following must be specified: " +
 
  766    auto const& param = params[seedType->first];
 
  767    if (!param.isString())
 
  773    auto const fieldContents = param.asString();
 
 
  790    bool const has_key_type = params.
isMember(jss::key_type);
 
  793    static char const* 
const secretTypes[]{
 
  794        jss::passphrase.c_str(),
 
  797        jss::seed_hex.c_str()};
 
  800    char const* secretType = 
nullptr;
 
  802    for (
auto t : secretTypes)
 
  811    if (count == 0 || secretType == 
nullptr)
 
  820            "Exactly one of the following must be specified: " +
 
  832        if (!params[jss::key_type].isString())
 
  851        if (strcmp(secretType, jss::secret.c_str()) == 0)
 
  854                "The secret field is not allowed if " +
 
  865    if (strcmp(secretType, jss::seed_hex.c_str()) != 0)
 
  876                    rpcBAD_SEED, 
"Specified seed is for an Ed25519 wallet.");
 
  893            if (!params[jss::secret].isString())
 
  915        LogicError(
"keypairForSignature: invalid key type");
 
 
  926        static constexpr auto types = std::to_array<
 
  928#pragma push_macro("LEDGER_ENTRY") 
  931#define LEDGER_ENTRY(tag, value, name, rpcName, ...) \ 
  932    {jss::name, jss::rpcName, tag}, 
  934#include <xrpl/protocol/detail/ledger_entries.macro> 
  937#pragma pop_macro("LEDGER_ENTRY") 
  940        auto const& p = params[jss::type];
 
  947                "ripple::RPC::chooseLedgerEntryType : first valid result type");
 
  954        auto const filter = p.asString();
 
  957                return boost::iequals(std::get<0>(t), filter) ||
 
  958                    std::get<1>(t) == filter;
 
  960        if (iter == types.end())
 
  966                "ripple::RPC::chooseLedgerEntryType : second valid result " 
 
  980        case LedgerEntryType::ltAMENDMENTS:
 
  981        case LedgerEntryType::ltDIR_NODE:
 
  982        case LedgerEntryType::ltFEE_SETTINGS:
 
  983        case LedgerEntryType::ltLEDGER_HASHES:
 
  984        case LedgerEntryType::ltNEGATIVE_UNL:
 
 
 1001    if ((hasHash && hasIndex) || !(hasHash || hasIndex))
 
 1004            "Exactly one of ledger_hash and ledger_index can be set.");
 
 1011        auto const& jsonHash = context.
params[jss::ledger_hash];
 
 1012        if (!jsonHash.isString() || !ledgerHash.
parseHex(jsonHash.asString()))
 
 1017        auto const& jsonIndex = context.
params[jss::ledger_index];
 
 1018        if (!jsonIndex.isInt())
 
 1030        ledgerIndex = jsonIndex.asInt();
 
 1033        if (ledgerIndex >= ledger->info().seq)
 
 1035        if (ledgerIndex <= 0)
 
 1038        auto const j = context.
app.
journal(
"RPCHandler");
 
 1041        auto neededHash = 
hashOfSeq(*ledger, ledgerIndex, j);
 
 1047            auto refHash = 
hashOfSeq(*ledger, refIndex, j);
 
 1050                "ripple::RPC::getLedgerByContext : nonzero ledger hash");
 
 1063                        "acquiring ledger containing requested index");
 
 1064                    jvResult[jss::acquiring] =
 
 1073                        "acquiring ledger containing requested index");
 
 1074                    jvResult[jss::acquiring] = il->getJson(0);
 
 1082            neededHash = 
hashOfSeq(*ledger, ledgerIndex, j);
 
 1086            "ripple::RPC::getLedgerByContext : nonzero needed hash");
 
 1087        ledgerHash = neededHash ? *neededHash : beast::zero;  
 
 1103        return il->getJson(0);
 
 1106        rpcNOT_READY, 
"findCreate failed to return an inbound ledger");
 
 
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.
 
virtual Config & config()=0
 
virtual beast::Journal journal(std::string const &name)=0
 
virtual InboundLedgers & getInboundLedgers()=0
 
virtual LedgerMaster & getLedgerMaster()=0
 
virtual std::shared_ptr< Ledger const > acquire(uint256 const &hash, std::uint32_t seq, InboundLedger::Reason)=0
 
virtual std::shared_ptr< InboundLedger > find(LedgerHash const &hash)=0
 
std::shared_ptr< Ledger const > getValidatedLedger()
 
std::shared_ptr< ReadView const > getCurrentLedger()
 
bool isValidated(ReadView const &ledger)
 
std::shared_ptr< Ledger const > getClosedLedger()
 
std::shared_ptr< Ledger const > getLedgerBySeq(std::uint32_t index)
 
std::shared_ptr< Ledger const > getLedgerByHash(uint256 const &hash)
 
LedgerIndex getValidLedgerIndex()
 
virtual std::shared_ptr< SLE const > read(Keylet const &k) const =0
Return the state item associated with a key.
 
virtual std::optional< key_type > succ(key_type const &key, std::optional< key_type > const &last=std::nullopt) const =0
Return the key of the next state item.
 
LedgerEntryType getType() const
 
Json::Value getJson(JsonOptions options=JsonOptions::none) const override
 
bool isFieldPresent(SField const &field) const
 
uint128 getFieldH128(SField const &field) const
 
Seeds are used to generate deterministic secret keys.
 
An immutable linear range of bytes.
 
static std::optional< base_uint > fromVoidChecked(T const &from)
 
static constexpr std::size_t size()
 
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
 
@ stringValue
UTF-8 string value.
 
@ arrayValue
array value (ordered list)
 
@ objectValue
object value (collection of name/value pairs).
 
bool lexicalCastChecked(Out &out, In in)
Intelligently convert from one type to another.
 
Status
Return codes from Backend operations.
 
auto constexpr maxValidatedLedgerAge
 
Status ledgerFromRequest(T &ledger, GRPCContext< R > &context)
 
error_code_i accountFromStringWithCode(AccountID &result, std::string const &strIdent, bool bStrict)
Decode account ID from string.
 
bool contains_error(Json::Value const &json)
Returns true if the json contains an rpc error specification.
 
std::optional< Seed > getSeedFromRPC(Json::Value const ¶ms, Json::Value &error)
 
Json::Value make_error(error_code_i code)
Returns a new json object that reflects the error code.
 
std::variant< std::shared_ptr< Ledger const >, Json::Value > getLedgerByContext(RPC::JsonContext &context)
Return a ledger based on ledger_hash or ledger_index, or an RPC error.
 
Json::Value invalid_field_error(std::string const &name)
 
bool isAccountObjectsValidType(LedgerEntryType const &type)
Check if the type is a valid filtering type for account_objects method.
 
static constexpr std::integral_constant< unsigned, Version > apiVersion
 
bool isRelatedToAccount(ReadView const &ledger, std::shared_ptr< SLE const > const &sle, AccountID const &accountID)
Tests if a SLE is owned by accountID.
 
void injectSLE(Json::Value &jv, SLE const &sle)
Inject JSON describing ledger entry.
 
Json::Value make_param_error(std::string const &message)
Returns a new json object that indicates invalid parameters.
 
Status getLedger(T &ledger, uint256 const &ledgerHash, Context &context)
Get ledger by hash If there is no error in the return value, the ledger pointer will have been filled...
 
std::pair< RPC::Status, LedgerEntryType > chooseLedgerEntryType(Json::Value const ¶ms)
 
std::string invalid_field_message(std::string const &name)
 
bool getAccountObjects(ReadView const &ledger, AccountID const &account, std::optional< std::vector< LedgerEntryType > > const &typeFilter, uint256 dirIndex, uint256 entryIndex, std::uint32_t const limit, Json::Value &jvResult)
Gathers all objects for an account in a ledger.
 
std::optional< Json::Value > readLimitField(unsigned int &limit, Tuning::LimitRange const &range, JsonContext const &context)
Retrieve the limit value from a JsonContext, or set a default - then restrict the limit by max and mi...
 
Json::Value accountFromString(AccountID &result, std::string const &strIdent, bool bStrict)
 
Json::Value expected_field_error(std::string const &name, std::string const &type)
 
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.
 
Status ledgerFromSpecifier(T &ledger, org::xrpl::rpc::v1::LedgerSpecifier const &specifier, Context &context)
 
std::optional< AccountID > accountFromStringStrict(std::string const &account)
Get an AccountID from an account ID or public key.
 
hash_set< AccountID > parseAccountIds(Json::Value const &jvArray)
 
std::uint64_t getStartHint(std::shared_ptr< SLE const > const &sle, AccountID const &accountID)
Gets the start hint for traversing account objects.
 
Json::Value missing_field_error(std::string const &name)
 
std::optional< Seed > parseRippleLibSeed(Json::Value const &value)
 
std::optional< std::pair< PublicKey, SecretKey > > keypairForSignature(Json::Value const ¶ms, Json::Value &error, unsigned int apiVersion)
 
Charge const feeHeavyBurdenRPC
 
Keylet child(uint256 const &key) noexcept
Any item that can be in an owner dir.
 
Keylet page(uint256 const &root, std::uint64_t index=0) noexcept
A page in a directory.
 
Keylet nftpage_min(AccountID const &owner)
NFT page keylets.
 
Keylet nftpage_max(AccountID const &owner)
A keylet for the owner's last possible NFT page.
 
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
 
Keylet signers(AccountID const &account) noexcept
A SignerList.
 
uint256 constexpr pageMask(std::string_view("0000000000000000000000000000000000000000ffffffffffffffffffffffff"))
 
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
 
std::optional< KeyType > keyTypeFromString(std::string const &s)
 
LedgerIndex getCandidateLedger(LedgerIndex requested)
Find a ledger index from which we could easily get the requested ledger.
 
std::pair< PublicKey, SecretKey > generateKeyPair(KeyType type, Seed const &seed)
Generate a key pair deterministically.
 
std::optional< uint256 > hashOfSeq(ReadView const &ledger, LedgerIndex seq, beast::Journal journal)
Return the hash of a ledger by sequence.
 
AccountID calcAccountID(PublicKey const &pk)
 
Json::Value rpcError(int iError)
 
bool isUnlimited(Role const &role)
ADMIN and IDENTIFIED roles shall have unlimited resources.
 
std::string decodeBase58Token(std::string const &s, TokenType type)
 
std::string strHex(FwdIt begin, FwdIt end)
 
std::enable_if_t< std::is_same< T, char >::value||std::is_same< T, unsigned char >::value, Slice > makeSlice(std::array< T, N > const &a)
 
std::string to_string(base_uint< Bits, Tag > const &a)
 
ClosedInterval< T > range(T low, T high)
Create a closed range interval.
 
LedgerEntryType
Identifiers for on-ledger objects.
 
@ ltANY
A special type, matching any ledger entry type.
 
Number root(Number f, unsigned d)
 
Json::Value getJson(LedgerFill const &fill)
Return a new Json::Value representing the ledger with given options.
 
@ ledgerMaster
ledger master data for signing
 
std::optional< Seed > parseGenericSeed(std::string const &str, bool rfc1751=true)
Attempt to parse a string as a seed.
 
void LogicError(std::string const &how) noexcept
Called when faulty logic causes a broken invariant.
 
A pair of SHAMap key and LedgerEntryType.
 
The context of information needed to call an RPC.
 
Resource::Charge & loadType
 
LedgerMaster & ledgerMaster
 
Status represents the results of an operation that might fail.
 
Represents RPC limit parameter values that have a min, default and max.