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.SetHex(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  return rpcError(rpcNO_CURRENT);
71 
72  ledgerIndex = jsonIndex.asInt();
73  auto ledger = ledgerMaster.getValidatedLedger();
74 
75  if (ledgerIndex >= ledger->info().seq)
76  return RPC::make_param_error("Ledger index too large");
77  if (ledgerIndex <= 0)
78  return RPC::make_param_error("Ledger index too small");
79 
80  auto const j = context.app.journal("RPCHandler");
81  // Try to get the hash of the desired ledger from the validated ledger
82  auto neededHash = hashOfSeq(*ledger, ledgerIndex, j);
83  if (!neededHash)
84  {
85  // Find a ledger more likely to have the hash of the desired ledger
86  auto const refIndex = getCandidateLedger(ledgerIndex);
87  auto refHash = hashOfSeq(*ledger, refIndex, j);
88  assert(refHash);
89 
90  ledger = ledgerMaster.getLedgerByHash(*refHash);
91  if (!ledger)
92  {
93  // We don't have the ledger we need to figure out which ledger
94  // they want. Try to get it.
95 
96  if (auto il = context.app.getInboundLedgers().acquire(
97  *refHash, refIndex, InboundLedger::Reason::GENERIC))
98  {
99  Json::Value jvResult = RPC::make_error(
101  "acquiring ledger containing requested index");
102  jvResult[jss::acquiring] = getJson(LedgerFill(*il));
103  return jvResult;
104  }
105 
106  if (auto il = context.app.getInboundLedgers().find(*refHash))
107  {
108  Json::Value jvResult = RPC::make_error(
110  "acquiring ledger containing requested index");
111  jvResult[jss::acquiring] = il->getJson(0);
112  return jvResult;
113  }
114 
115  // Likely the app is shutting down
116  return Json::Value();
117  }
118 
119  neededHash = hashOfSeq(*ledger, ledgerIndex, j);
120  }
121  assert(neededHash);
122  ledgerHash = neededHash ? *neededHash : beast::zero; // kludge
123  }
124 
125  // Try to get the desired ledger
126  // Verify all nodes even if we think we have it
127  auto ledger = context.app.getInboundLedgers().acquire(
128  ledgerHash, ledgerIndex, InboundLedger::Reason::GENERIC);
129 
130  // In standalone mode, accept the ledger from the ledger cache
131  if (!ledger && context.app.config().standalone())
132  ledger = ledgerMaster.getLedgerByHash(ledgerHash);
133 
134  if (ledger)
135  {
136  // We already had the entire ledger verified/acquired
137  Json::Value jvResult;
138  jvResult[jss::ledger_index] = ledger->info().seq;
139  addJson(jvResult, {*ledger, 0});
140  return jvResult;
141  }
142 
143  if (auto il = context.app.getInboundLedgers().find(ledgerHash))
144  return il->getJson(0);
145 
146  return RPC::make_error(
147  rpcNOT_READY, "findCreate failed to return an inbound ledger");
148 }
149 
150 } // namespace ripple
ripple::RPC::JsonContext
Definition: Context.h:52
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:216
ripple::base_uint::SetHex
bool SetHex(const char *psz, bool bStrict=false)
Parse a hex string into a base_uint The input can be:
Definition: base_uint.h:406
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:283
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::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:273
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:63
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
Json::Value
Represents a JSON value.
Definition: json_value.h:145
ripple::InboundLedgers::find
virtual std::shared_ptr< InboundLedger > find(LedgerHash const &hash)=0