rippled
ServerInfo.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/main/Application.h>
21 #include <ripple/app/misc/NetworkOPs.h>
22 #include <ripple/app/reporting/P2pProxy.h>
23 #include <ripple/json/json_value.h>
24 #include <ripple/net/RPCErr.h>
25 #include <ripple/protocol/LedgerFormats.h>
26 #include <ripple/protocol/SField.h>
27 #include <ripple/protocol/TER.h>
28 #include <ripple/protocol/TxFormats.h>
29 #include <ripple/protocol/digest.h>
30 #include <ripple/protocol/jss.h>
31 #include <ripple/rpc/Context.h>
32 #include <ripple/rpc/Role.h>
33 
34 #include <boost/algorithm/string.hpp>
35 
36 #include <unordered_map>
37 
38 namespace ripple {
39 
40 namespace detail {
41 
43 {
44 private:
46  // translate e.g. STI_LEDGERENTRY to LedgerEntry
47  translate(std::string const& inp);
48 
51 
52 public:
54 
55  bool
56  hashMatches(uint256 hash) const
57  {
58  return defsHash_ == hash;
59  }
60 
61  Json::Value const&
62  get() const
63  {
64  return defs_;
65  }
66 };
67 
70 {
71  auto replace = [&](char const* oldStr, char const* newStr) -> std::string {
72  std::string out = inp;
73  boost::replace_all(out, oldStr, newStr);
74  return out;
75  };
76 
77  auto contains = [&](char const* s) -> bool {
78  return inp.find(s) != std::string::npos;
79  };
80 
81  if (contains("UINT"))
82  {
83  if (contains("256") || contains("160") || contains("128"))
84  return replace("UINT", "Hash");
85  else
86  return replace("UINT", "UInt");
87  }
88 
90  {"OBJECT", "STObject"},
91  {"ARRAY", "STArray"},
92  {"ACCOUNT", "AccountID"},
93  {"LEDGERENTRY", "LedgerEntry"},
94  {"NOTPRESENT", "NotPresent"},
95  {"PATHSET", "PathSet"},
96  {"VL", "Blob"},
97  {"XCHAIN_BRIDGE", "XChainBridge"},
98  };
99 
100  if (auto const& it = replacements.find(inp); it != replacements.end())
101  {
102  return it->second;
103  }
104 
106  size_t pos = 0;
107  std::string inpToProcess = inp;
108 
109  // convert snake_case to CamelCase
110  for (;;)
111  {
112  pos = inpToProcess.find("_");
113  if (pos == std::string::npos)
114  pos = inpToProcess.size();
115  std::string token = inpToProcess.substr(0, pos);
116  if (token.size() > 1)
117  {
118  boost::algorithm::to_lower(token);
119  token.data()[0] -= ('a' - 'A');
120  out += token;
121  }
122  else
123  out += token;
124  if (pos == inpToProcess.size())
125  break;
126  inpToProcess = inpToProcess.substr(pos + 1);
127  }
128  return out;
129 };
130 
132 {
133  // populate SerializedTypeID names and values
134  defs_[jss::TYPES] = Json::objectValue;
135 
136  defs_[jss::TYPES]["Done"] = -1;
137  std::map<int32_t, std::string> typeMap{{-1, "Done"}};
138  for (auto const& [rawName, typeValue] : sTypeMap)
139  {
140  std::string typeName =
141  translate(std::string(rawName).substr(4) /* remove STI_ */);
142  defs_[jss::TYPES][typeName] = typeValue;
143  typeMap[typeValue] = typeName;
144  }
145 
146  // populate LedgerEntryType names and values
147  defs_[jss::LEDGER_ENTRY_TYPES] = Json::objectValue;
148  defs_[jss::LEDGER_ENTRY_TYPES][jss::Invalid] = -1;
149 
150  for (auto const& f : LedgerFormats::getInstance())
151  {
152  defs_[jss::LEDGER_ENTRY_TYPES][f.getName()] = f.getType();
153  }
154 
155  // populate SField serialization data
156  defs_[jss::FIELDS] = Json::arrayValue;
157 
158  uint32_t i = 0;
159  {
161  a[0U] = "Generic";
163  v[jss::nth] = 0;
164  v[jss::isVLEncoded] = false;
165  v[jss::isSerialized] = false;
166  v[jss::isSigningField] = false;
167  v[jss::type] = "Unknown";
168  a[1U] = v;
169  defs_[jss::FIELDS][i++] = a;
170  }
171 
172  {
174  a[0U] = "Invalid";
176  v[jss::nth] = -1;
177  v[jss::isVLEncoded] = false;
178  v[jss::isSerialized] = false;
179  v[jss::isSigningField] = false;
180  v[jss::type] = "Unknown";
181  a[1U] = v;
182  defs_[jss::FIELDS][i++] = a;
183  }
184 
185  {
187  a[0U] = "ObjectEndMarker";
189  v[jss::nth] = 1;
190  v[jss::isVLEncoded] = false;
191  v[jss::isSerialized] = true;
192  v[jss::isSigningField] = true;
193  v[jss::type] = "STObject";
194  a[1U] = v;
195  defs_[jss::FIELDS][i++] = a;
196  }
197 
198  {
200  a[0U] = "ArrayEndMarker";
202  v[jss::nth] = 1;
203  v[jss::isVLEncoded] = false;
204  v[jss::isSerialized] = true;
205  v[jss::isSigningField] = true;
206  v[jss::type] = "STArray";
207  a[1U] = v;
208  defs_[jss::FIELDS][i++] = a;
209  }
210 
211  {
213  a[0U] = "taker_gets_funded";
215  v[jss::nth] = 258;
216  v[jss::isVLEncoded] = false;
217  v[jss::isSerialized] = false;
218  v[jss::isSigningField] = false;
219  v[jss::type] = "Amount";
220  a[1U] = v;
221  defs_[jss::FIELDS][i++] = a;
222  }
223 
224  {
226  a[0U] = "taker_pays_funded";
228  v[jss::nth] = 259;
229  v[jss::isVLEncoded] = false;
230  v[jss::isSerialized] = false;
231  v[jss::isSigningField] = false;
232  v[jss::type] = "Amount";
233  a[1U] = v;
234  defs_[jss::FIELDS][i++] = a;
235  }
236 
237  for (auto const& [code, f] : ripple::SField::getKnownCodeToField())
238  {
239  if (f->fieldName == "")
240  continue;
241 
242  Json::Value innerObj = Json::objectValue;
243 
244  uint32_t type = f->fieldType;
245 
246  innerObj[jss::nth] = f->fieldValue;
247 
248  // whether the field is variable-length encoded
249  // this means that the length is included before the content
250  innerObj[jss::isVLEncoded] =
251  (type == 7U /* Blob */ || type == 8U /* AccountID */ ||
252  type == 19U /* Vector256 */);
253 
254  // whether the field is included in serialization
255  innerObj[jss::isSerialized] =
256  (type < 10000 && f->fieldName != "hash" &&
257  f->fieldName != "index"); /* hash, index, TRANSACTION,
258  LEDGER_ENTRY, VALIDATION, METADATA */
259 
260  // whether the field is included in serialization when signing
261  innerObj[jss::isSigningField] = f->shouldInclude(false);
262 
263  innerObj[jss::type] = typeMap[type];
264 
265  Json::Value innerArray = Json::arrayValue;
266  innerArray[0U] = f->fieldName;
267  innerArray[1U] = innerObj;
268 
269  defs_[jss::FIELDS][i++] = innerArray;
270  }
271 
272  // populate TER code names and values
273  defs_[jss::TRANSACTION_RESULTS] = Json::objectValue;
274 
275  for (auto const& [code, terInfo] : transResults())
276  {
277  defs_[jss::TRANSACTION_RESULTS][terInfo.first] = code;
278  }
279 
280  // populate TxType names and values
281  defs_[jss::TRANSACTION_TYPES] = Json::objectValue;
282  defs_[jss::TRANSACTION_TYPES][jss::Invalid] = -1;
283  for (auto const& f : TxFormats::getInstance())
284  {
285  defs_[jss::TRANSACTION_TYPES][f.getName()] = f.getType();
286  }
287 
288  // generate hash
289  {
290  const std::string out = Json::FastWriter().write(defs_);
291  defsHash_ = ripple::sha512Half(ripple::Slice{out.data(), out.size()});
292  defs_[jss::hash] = to_string(defsHash_);
293  }
294 }
295 
296 } // namespace detail
297 
300 {
301  auto& params = context.params;
302 
303  uint256 hash;
304  if (params.isMember(jss::hash))
305  {
306  if (!params[jss::hash].isString() ||
307  !hash.parseHex(params[jss::hash].asString()))
308  return RPC::invalid_field_error(jss::hash);
309  }
310 
311  static const detail::ServerDefinitions defs{};
312  if (defs.hashMatches(hash))
313  {
315  jv[jss::hash] = to_string(hash);
316  return jv;
317  }
318  return defs.get();
319 }
320 
323 {
325 
326  ret[jss::info] = context.netOps.getServerInfo(
327  true,
328  context.role == Role::ADMIN,
329  context.params.isMember(jss::counters) &&
330  context.params[jss::counters].asBool());
331 
332  if (context.app.config().reporting())
333  {
334  Json::Value const proxied = forwardToP2p(context);
335  auto const lf = proxied[jss::result][jss::info][jss::load_factor];
336  auto const vq = proxied[jss::result][jss::info][jss::validation_quorum];
337  ret[jss::info][jss::validation_quorum] = vq.isNull() ? 1 : vq;
338  ret[jss::info][jss::load_factor] = lf.isNull() ? 1 : lf;
339  }
340  return ret;
341 }
342 
343 } // namespace ripple
ripple::RPC::JsonContext
Definition: Context.h:53
ripple::NetworkOPs::getServerInfo
virtual Json::Value getServerInfo(bool human, bool admin, bool counters)=0
std::string
STL class.
ripple::sTypeMap
static const std::map< std::string, int > sTypeMap
Definition: SField.h:106
ripple::Slice
An immutable linear range of bytes.
Definition: Slice.h:44
Json::arrayValue
@ arrayValue
array value (ordered list)
Definition: json_value.h:42
ripple::detail::to_string
static std::string to_string(TableType type)
to_string Returns the name of a table according to its TableType.
Definition: Node.cpp:46
Json::Value::get
Value get(UInt index, const Value &defaultValue) const
If the array contains at least index+1 elements, returns the element value, otherwise returns default...
Definition: json_value.cpp:834
ripple::transResults
std::unordered_map< TERUnderlyingType, std::pair< char const *const, char const *const > > const & transResults()
Definition: TER.cpp:29
std::string::find
T find(T... args)
ripple::doServerDefinitions
Json::Value doServerDefinitions(RPC::JsonContext &)
Definition: ServerInfo.cpp:299
std::string::size
T size(T... args)
ripple::SField::getKnownCodeToField
static std::map< int, SField const * > const & getKnownCodeToField()
Definition: SField.h:292
ripple::detail::ServerDefinitions
Definition: ServerInfo.cpp:42
ripple::detail::ServerDefinitions::defsHash_
uint256 defsHash_
Definition: ServerInfo.cpp:49
Json::Value::isNull
bool isNull() const
isNull() tests to see if this field is null.
Definition: json_value.cpp:967
ripple::RPC::Context::role
Role role
Definition: Context.h:47
ripple::detail::ServerDefinitions::ServerDefinitions
ServerDefinitions()
Definition: ServerInfo.cpp:131
Json::Value::asBool
bool asBool() const
Definition: json_value.cpp:619
ripple::detail::ServerDefinitions::get
Json::Value const & get() const
Definition: ServerInfo.cpp:62
ripple::base_uint< 256 >
ripple::Config::reporting
bool reporting() const
Definition: Config.h:351
ripple::QualityDirection::out
@ out
ripple::Role::ADMIN
@ ADMIN
Json::objectValue
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:43
ripple::detail::ServerDefinitions::hashMatches
bool hashMatches(uint256 hash) const
Definition: ServerInfo.cpp:56
ripple::TxFormats::getInstance
static TxFormats const & getInstance()
Definition: TxFormats.cpp:489
ripple::Application::config
virtual Config & config()=0
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
std::map
STL class.
Json::FastWriter::write
std::string write(const Value &root) override
Definition: json_writer.cpp:193
ripple::LedgerFormats::getInstance
static LedgerFormats const & getInstance()
Definition: LedgerFormats.cpp:346
ripple::RPC::Context::netOps
NetworkOPs & netOps
Definition: Context.h:44
ripple::forwardToP2p
Json::Value forwardToP2p(RPC::JsonContext &context)
Forward a JSON request to a p2p node and return the response.
Definition: P2pProxy.cpp:28
std::string::substr
T substr(T... args)
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::detail::ServerDefinitions::defs_
Json::Value defs_
Definition: ServerInfo.cpp:50
ripple::sha512Half
sha512_half_hasher::result_type sha512Half(Args const &... args)
Returns the SHA512-Half of a series of objects.
Definition: digest.h:216
Json::FastWriter
Outputs a Value in JSON format without formatting (not human friendly).
Definition: json_writer.h:52
ripple::to_string
std::string to_string(Manifest const &m)
Format the specified manifest to a string for debugging purposes.
Definition: app/misc/impl/Manifest.cpp:41
ripple::doServerInfo
Json::Value doServerInfo(RPC::JsonContext &)
Definition: ServerInfo.cpp:322
ripple::base_uint::parseHex
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Definition: base_uint.h:496
unordered_map
ripple::RPC::JsonContext::params
Json::Value params
Definition: Context.h:64
std::string::data
T data(T... args)
ripple::RPC::invalid_field_error
Json::Value invalid_field_error(std::string const &name)
Definition: ErrorCodes.h:306
ripple::detail::ServerDefinitions::translate
std::string translate(std::string const &inp)
Definition: ServerInfo.cpp:69
Json::Value
Represents a JSON value.
Definition: json_value.h:145