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/LedgerToJson.h>
22 #include <ripple/app/ledger/LedgerMaster.h>
23 #include <ripple/app/main/Application.h>
24 #include <ripple/net/RPCErr.h>
25 #include <ripple/resource/Fees.h>
26 #include <ripple/rpc/Context.h>
27 #include <ripple/protocol/ErrorCodes.h>
28 #include <ripple/protocol/jss.h>
29 #include <ripple/rpc/impl/Tuning.h>
30 
31 namespace ripple {
32 
33 // {
34 // ledger_hash : <ledger>
35 // ledger_index : <ledger_index>
36 // }
38 {
39  auto const hasHash = context.params.isMember (jss::ledger_hash);
40  auto const hasIndex = context.params.isMember (jss::ledger_index);
41  std::uint32_t ledgerIndex = 0;
42 
43  auto& ledgerMaster = context.app.getLedgerMaster();
44  LedgerHash ledgerHash;
45 
46  if ((hasHash && hasIndex) || !(hasHash || hasIndex))
47  {
48  return RPC::make_param_error(
49  "Exactly one of ledger_hash and ledger_index can be set.");
50  }
51 
53 
54  if (hasHash)
55  {
56  auto const& jsonHash = context.params[jss::ledger_hash];
57  if (!jsonHash.isString() || !ledgerHash.SetHex (jsonHash.asString ()))
58  return RPC::invalid_field_error (jss::ledger_hash);
59  }
60  else
61  {
62  auto const& jsonIndex = context.params[jss::ledger_index];
63  if (!jsonIndex.isInt())
64  return RPC::invalid_field_error (jss::ledger_index);
65 
66  // We need a validated ledger to get the hash from the sequence
67  if (ledgerMaster.getValidatedLedgerAge() >
69  return rpcError (rpcNO_CURRENT);
70 
71  ledgerIndex = jsonIndex.asInt();
72  auto ledger = ledgerMaster.getValidatedLedger();
73 
74  if (ledgerIndex >= ledger->info().seq)
75  return RPC::make_param_error("Ledger index too large");
76  if (ledgerIndex <= 0)
77  return RPC::make_param_error("Ledger index too small");
78 
79  auto const j = context.app.journal("RPCHandler");
80  // Try to get the hash of the desired ledger from the validated ledger
81  auto neededHash = hashOfSeq(*ledger, ledgerIndex, j);
82  if (! neededHash)
83  {
84  // Find a ledger more likely to have the hash of the desired ledger
85  auto const refIndex = getCandidateLedger(ledgerIndex);
86  auto refHash = hashOfSeq(*ledger, refIndex, j);
87  assert(refHash);
88 
89  ledger = ledgerMaster.getLedgerByHash (*refHash);
90  if (! ledger)
91  {
92  // We don't have the ledger we need to figure out which ledger
93  // they want. Try to get it.
94 
95  if (auto il = context.app.getInboundLedgers().acquire (
96  *refHash, refIndex, InboundLedger::Reason::GENERIC))
97  {
98  Json::Value jvResult = RPC::make_error(
100  "acquiring ledger containing requested index");
101  jvResult[jss::acquiring] = getJson (LedgerFill (*il));
102  return jvResult;
103  }
104 
105  if (auto il = context.app.getInboundLedgers().find (*refHash))
106  {
107  Json::Value jvResult = RPC::make_error(
109  "acquiring ledger containing requested index");
110  jvResult[jss::acquiring] = il->getJson (0);
111  return jvResult;
112  }
113 
114  // Likely the app is shutting down
115  return Json::Value();
116  }
117 
118  neededHash = hashOfSeq(*ledger, ledgerIndex, j);
119  }
120  assert (neededHash);
121  ledgerHash = neededHash ? *neededHash : beast::zero; // kludge
122  }
123 
124  // Try to get the desired ledger
125  // Verify all nodes even if we think we have it
126  auto ledger = context.app.getInboundLedgers().acquire (
127  ledgerHash, ledgerIndex, InboundLedger::Reason::GENERIC);
128 
129  // In standalone mode, accept the ledger from the ledger cache
130  if (! ledger && context.app.config().standalone())
131  ledger = ledgerMaster.getLedgerByHash (ledgerHash);
132 
133  if (ledger)
134  {
135  // We already had the entire ledger verified/acquired
136  Json::Value jvResult;
137  jvResult[jss::ledger_index] = ledger->info().seq;
138  addJson (jvResult, {*ledger, 0});
139  return jvResult;
140  }
141 
142  if (auto il = context.app.getInboundLedgers().find (ledgerHash))
143  return il->getJson (0);
144 
145  return RPC::make_error (
146  rpcNOT_READY, "findCreate failed to return an inbound ledger");
147 }
148 
149 } // 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:61
ripple::rpcLGR_NOT_FOUND
@ rpcLGR_NOT_FOUND
Definition: ErrorCodes.h:73
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:37
ripple::Application::config
virtual Config & config()=0
ripple::Config::standalone
bool standalone() const
Definition: Config.h:204
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:362
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:961
ripple::rpcNO_CURRENT
@ rpcNO_CURRENT
Definition: ErrorCodes.h:66
std::uint32_t
ripple::rpcError
Json::Value rpcError(int iError, Json::Value jvResult)
Definition: RPCErr.cpp:28
ripple::getJson
Json::Value getJson(LedgerFill const &fill)
Return a new Json::Value representing the ledger with given options.
Definition: LedgerToJson.cpp:272
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:553
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:263
ripple::getCandidateLedger
LedgerIndex getCandidateLedger(LedgerIndex requested)
Find a ledger index from which we could easily get the requested ledger.
Definition: View.h:177
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:219
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:264
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:182
ripple::RPC::Tuning::maxValidatedLedgerAge
constexpr auto maxValidatedLedgerAge
Definition: rpc/impl/Tuning.h:58
Json::Value
Represents a JSON value.
Definition: json_value.h:141
ripple::InboundLedgers::find
virtual std::shared_ptr< InboundLedger > find(LedgerHash const &hash)=0