rippled
LedgerRequest.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012-2014 Ripple Labs Inc.
5 
6  Permission to use, copy, modify, and/or distribute this software for any
7  purpose with or without fee is hereby granted, provided that the above
8  copyright notice and this permission notice appear in all copies.
9 
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 //==============================================================================
19 
20 #include <ripple/app/ledger/InboundLedgers.h>
21 #include <ripple/app/ledger/LedgerMaster.h>
22 #include <ripple/app/ledger/LedgerToJson.h>
23 #include <ripple/app/main/Application.h>
24 #include <ripple/net/RPCErr.h>
25 #include <ripple/protocol/ErrorCodes.h>
26 #include <ripple/protocol/jss.h>
27 #include <ripple/resource/Fees.h>
28 #include <ripple/rpc/Context.h>
29 #include <ripple/rpc/impl/Tuning.h>
30 
31 namespace ripple {
32 
33 // {
34 // ledger_hash : <ledger>
35 // ledger_index : <ledger_index>
36 // }
39 {
40  auto const hasHash = context.params.isMember(jss::ledger_hash);
41  auto const hasIndex = context.params.isMember(jss::ledger_index);
42  std::uint32_t ledgerIndex = 0;
43 
44  auto& ledgerMaster = context.app.getLedgerMaster();
45  LedgerHash ledgerHash;
46 
47  if ((hasHash && hasIndex) || !(hasHash || hasIndex))
48  {
49  return RPC::make_param_error(
50  "Exactly one of ledger_hash and ledger_index can be set.");
51  }
52 
54 
55  if (hasHash)
56  {
57  auto const& jsonHash = context.params[jss::ledger_hash];
58  if (!jsonHash.isString() || !ledgerHash.parseHex(jsonHash.asString()))
59  return RPC::invalid_field_error(jss::ledger_hash);
60  }
61  else
62  {
63  auto const& jsonIndex = context.params[jss::ledger_index];
64  if (!jsonIndex.isInt())
65  return RPC::invalid_field_error(jss::ledger_index);
66 
67  // We need a validated ledger to get the hash from the sequence
68  if (ledgerMaster.getValidatedLedgerAge() >
70  {
71  if (context.apiVersion == 1)
72  return rpcError(rpcNO_CURRENT);
73  return rpcError(rpcNOT_SYNCED);
74  }
75 
76  ledgerIndex = jsonIndex.asInt();
77  auto ledger = ledgerMaster.getValidatedLedger();
78 
79  if (ledgerIndex >= ledger->info().seq)
80  return RPC::make_param_error("Ledger index too large");
81  if (ledgerIndex <= 0)
82  return RPC::make_param_error("Ledger index too small");
83 
84  auto const j = context.app.journal("RPCHandler");
85  // Try to get the hash of the desired ledger from the validated ledger
86  auto neededHash = hashOfSeq(*ledger, ledgerIndex, j);
87  if (!neededHash)
88  {
89  // Find a ledger more likely to have the hash of the desired ledger
90  auto const refIndex = getCandidateLedger(ledgerIndex);
91  auto refHash = hashOfSeq(*ledger, refIndex, j);
92  assert(refHash);
93 
94  ledger = ledgerMaster.getLedgerByHash(*refHash);
95  if (!ledger)
96  {
97  // We don't have the ledger we need to figure out which ledger
98  // they want. Try to get it.
99 
100  if (auto il = context.app.getInboundLedgers().acquire(
101  *refHash, refIndex, InboundLedger::Reason::GENERIC))
102  {
103  Json::Value jvResult = RPC::make_error(
105  "acquiring ledger containing requested index");
106  jvResult[jss::acquiring] = getJson(LedgerFill(*il));
107  return jvResult;
108  }
109 
110  if (auto il = context.app.getInboundLedgers().find(*refHash))
111  {
112  Json::Value jvResult = RPC::make_error(
114  "acquiring ledger containing requested index");
115  jvResult[jss::acquiring] = il->getJson(0);
116  return jvResult;
117  }
118 
119  // Likely the app is shutting down
120  return Json::Value();
121  }
122 
123  neededHash = hashOfSeq(*ledger, ledgerIndex, j);
124  }
125  assert(neededHash);
126  ledgerHash = neededHash ? *neededHash : beast::zero; // kludge
127  }
128 
129  // Try to get the desired ledger
130  // Verify all nodes even if we think we have it
131  auto ledger = context.app.getInboundLedgers().acquire(
132  ledgerHash, ledgerIndex, InboundLedger::Reason::GENERIC);
133 
134  // In standalone mode, accept the ledger from the ledger cache
135  if (!ledger && context.app.config().standalone())
136  ledger = ledgerMaster.getLedgerByHash(ledgerHash);
137 
138  if (ledger)
139  {
140  // We already had the entire ledger verified/acquired
141  Json::Value jvResult;
142  jvResult[jss::ledger_index] = ledger->info().seq;
143  addJson(jvResult, {*ledger, 0});
144  return jvResult;
145  }
146 
147  if (auto il = context.app.getInboundLedgers().find(ledgerHash))
148  return il->getJson(0);
149 
150  return RPC::make_error(
151  rpcNOT_READY, "findCreate failed to return an inbound ledger");
152 }
153 
154 } // namespace ripple
ripple::RPC::JsonContext
Definition: Context.h:53
ripple::HashPrefix::ledgerMaster
@ ledgerMaster
ledger master data for signing
ripple::RPC::Context::loadType
Resource::Charge & loadType
Definition: Context.h:43
ripple::InboundLedger::Reason::GENERIC
@ GENERIC
ripple::rpcNOT_READY
@ rpcNOT_READY
Definition: ErrorCodes.h:60
ripple::rpcLGR_NOT_FOUND
@ rpcLGR_NOT_FOUND
Definition: ErrorCodes.h:72
ripple::Application::getInboundLedgers
virtual InboundLedgers & getInboundLedgers()=0
ripple::base_uint< 256 >
ripple::Application::getLedgerMaster
virtual LedgerMaster & getLedgerMaster()=0
ripple::InboundLedgers::acquire
virtual std::shared_ptr< Ledger const > acquire(uint256 const &hash, std::uint32_t seq, InboundLedger::Reason)=0
ripple::doLedgerRequest
Json::Value doLedgerRequest(RPC::JsonContext &)
Definition: LedgerRequest.cpp:38
ripple::Application::config
virtual Config & config()=0
ripple::Config::standalone
bool standalone() const
Definition: Config.h:249
ripple::RPC::Context::app
Application & app
Definition: Context.h:42
Json::Value::isMember
bool isMember(const char *key) const
Return true if the object has a member named key.
Definition: json_value.cpp:932
ripple::rpcNO_CURRENT
@ rpcNO_CURRENT
Definition: ErrorCodes.h:65
std::uint32_t
ripple::rpcError
Json::Value rpcError(int iError, Json::Value jvResult)
Definition: RPCErr.cpp:29
ripple::getJson
Json::Value getJson(LedgerFill const &fill)
Return a new Json::Value representing the ledger with given options.
Definition: LedgerToJson.cpp:280
ripple::hashOfSeq
boost::optional< uint256 > hashOfSeq(ReadView const &ledger, LedgerIndex seq, beast::Journal journal)
Return the hash of a ledger by sequence.
Definition: View.cpp:573
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::Application::journal
virtual beast::Journal journal(std::string const &name)=0
ripple::base_uint::parseHex
bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Definition: base_uint.h:384
ripple::RPC::Context::apiVersion
unsigned int apiVersion
Definition: Context.h:50
ripple::addJson
void addJson(Json::Value &json, LedgerFill const &fill)
Given a Ledger and options, fill a Json::Object or Json::Value with a description of the ledger.
Definition: LedgerToJson.cpp:270
ripple::getCandidateLedger
LedgerIndex getCandidateLedger(LedgerIndex requested)
Find a ledger index from which we could easily get the requested ledger.
Definition: View.h:187
ripple::RPC::make_param_error
Json::Value make_param_error(std::string const &message)
Returns a new json object that indicates invalid parameters.
Definition: ErrorCodes.h:224
ripple::LedgerFill
Definition: LedgerToJson.h:32
ripple::RPC::JsonContext::params
Json::Value params
Definition: Context.h:64
ripple::RPC::invalid_field_error
Json::Value invalid_field_error(std::string const &name)
Definition: ErrorCodes.h:278
ripple::Resource::feeHighBurdenRPC
const Charge feeHighBurdenRPC
ripple::RPC::make_error
Json::Value make_error(error_code_i code)
Returns a new json object that reflects the error code.
Definition: ErrorCodes.cpp:202
ripple::RPC::Tuning::maxValidatedLedgerAge
constexpr auto maxValidatedLedgerAge
Definition: rpc/impl/Tuning.h:59
ripple::rpcNOT_SYNCED
@ rpcNOT_SYNCED
Definition: ErrorCodes.h:67
Json::Value
Represents a JSON value.
Definition: json_value.h:145
ripple::InboundLedgers::find
virtual std::shared_ptr< InboundLedger > find(LedgerHash const &hash)=0