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  if (context.app.config().reporting())
42 
43  auto const hasHash = context.params.isMember(jss::ledger_hash);
44  auto const hasIndex = context.params.isMember(jss::ledger_index);
45  std::uint32_t ledgerIndex = 0;
46 
47  auto& ledgerMaster = context.app.getLedgerMaster();
48  LedgerHash ledgerHash;
49 
50  if ((hasHash && hasIndex) || !(hasHash || hasIndex))
51  {
52  return RPC::make_param_error(
53  "Exactly one of ledger_hash and ledger_index can be set.");
54  }
55 
57 
58  if (hasHash)
59  {
60  auto const& jsonHash = context.params[jss::ledger_hash];
61  if (!jsonHash.isString() || !ledgerHash.parseHex(jsonHash.asString()))
62  return RPC::invalid_field_error(jss::ledger_hash);
63  }
64  else
65  {
66  auto const& jsonIndex = context.params[jss::ledger_index];
67  if (!jsonIndex.isInt())
68  return RPC::invalid_field_error(jss::ledger_index);
69 
70  // We need a validated ledger to get the hash from the sequence
71  if (ledgerMaster.getValidatedLedgerAge() >
73  {
74  if (context.apiVersion == 1)
75  return rpcError(rpcNO_CURRENT);
76  return rpcError(rpcNOT_SYNCED);
77  }
78 
79  ledgerIndex = jsonIndex.asInt();
80  auto ledger = ledgerMaster.getValidatedLedger();
81 
82  if (ledgerIndex >= ledger->info().seq)
83  return RPC::make_param_error("Ledger index too large");
84  if (ledgerIndex <= 0)
85  return RPC::make_param_error("Ledger index too small");
86 
87  auto const j = context.app.journal("RPCHandler");
88  // Try to get the hash of the desired ledger from the validated ledger
89  auto neededHash = hashOfSeq(*ledger, ledgerIndex, j);
90  if (!neededHash)
91  {
92  // Find a ledger more likely to have the hash of the desired ledger
93  auto const refIndex = getCandidateLedger(ledgerIndex);
94  auto refHash = hashOfSeq(*ledger, refIndex, j);
95  assert(refHash);
96 
97  ledger = ledgerMaster.getLedgerByHash(*refHash);
98  if (!ledger)
99  {
100  // We don't have the ledger we need to figure out which ledger
101  // they want. Try to get it.
102 
103  if (auto il = context.app.getInboundLedgers().acquire(
104  *refHash, refIndex, InboundLedger::Reason::GENERIC))
105  {
106  Json::Value jvResult = RPC::make_error(
108  "acquiring ledger containing requested index");
109  jvResult[jss::acquiring] =
110  getJson(LedgerFill(*il, &context));
111  return jvResult;
112  }
113 
114  if (auto il = context.app.getInboundLedgers().find(*refHash))
115  {
116  Json::Value jvResult = RPC::make_error(
118  "acquiring ledger containing requested index");
119  jvResult[jss::acquiring] = il->getJson(0);
120  return jvResult;
121  }
122 
123  // Likely the app is shutting down
124  return Json::Value();
125  }
126 
127  neededHash = hashOfSeq(*ledger, ledgerIndex, j);
128  }
129  assert(neededHash);
130  ledgerHash = neededHash ? *neededHash : beast::zero; // kludge
131  }
132 
133  // Try to get the desired ledger
134  // Verify all nodes even if we think we have it
135  auto ledger = context.app.getInboundLedgers().acquire(
136  ledgerHash, ledgerIndex, InboundLedger::Reason::GENERIC);
137 
138  // In standalone mode, accept the ledger from the ledger cache
139  if (!ledger && context.app.config().standalone())
140  ledger = ledgerMaster.getLedgerByHash(ledgerHash);
141 
142  if (ledger)
143  {
144  // We already had the entire ledger verified/acquired
145  Json::Value jvResult;
146  jvResult[jss::ledger_index] = ledger->info().seq;
147  addJson(jvResult, {*ledger, &context, 0});
148  return jvResult;
149  }
150 
151  if (auto il = context.app.getInboundLedgers().find(ledgerHash))
152  return il->getJson(0);
153 
154  return RPC::make_error(
155  rpcNOT_READY, "findCreate failed to return an inbound ledger");
156 }
157 
158 } // 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::rpcREPORTING_UNSUPPORTED
@ rpcREPORTING_UNSUPPORTED
Definition: ErrorCodes.h:141
ripple::Application::getInboundLedgers
virtual InboundLedgers & getInboundLedgers()=0
ripple::base_uint< 256 >
ripple::Config::reporting
bool reporting() const
Definition: Config.h:267
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:262
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:293
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:576
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:283
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:231
ripple::LedgerFill
Definition: LedgerToJson.h:33
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:285
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:209
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