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/json/json_writer.h>
25 #include <ripple/net/RPCErr.h>
26 #include <ripple/protocol/LedgerFormats.h>
27 #include <ripple/protocol/SField.h>
28 #include <ripple/protocol/TER.h>
29 #include <ripple/protocol/TxFormats.h>
30 #include <ripple/protocol/digest.h>
31 #include <ripple/protocol/jss.h>
32 #include <ripple/rpc/Context.h>
33 #include <ripple/rpc/Role.h>
34 
35 #include <boost/algorithm/string.hpp>
36 
37 #include <unordered_map>
38 
39 namespace ripple {
40 
41 namespace detail {
42 
44 {
45 private:
47  // translate e.g. STI_LEDGERENTRY to LedgerEntry
48  translate(std::string const& inp);
49 
52 
53 public:
55 
56  bool
57  hashMatches(uint256 hash) const
58  {
59  return defsHash_ == hash;
60  }
61 
62  Json::Value const&
63  get() const
64  {
65  return defs_;
66  }
67 };
68 
71 {
72  auto replace = [&](char const* oldStr, char const* newStr) -> std::string {
73  std::string out = inp;
74  boost::replace_all(out, oldStr, newStr);
75  return out;
76  };
77 
78  auto contains = [&](char const* s) -> bool {
79  return inp.find(s) != std::string::npos;
80  };
81 
82  if (contains("UINT"))
83  {
84  if (contains("256") || contains("160") || contains("128"))
85  return replace("UINT", "Hash");
86  else
87  return replace("UINT", "UInt");
88  }
89 
91  {"OBJECT", "STObject"},
92  {"ARRAY", "STArray"},
93  {"ACCOUNT", "AccountID"},
94  {"LEDGERENTRY", "LedgerEntry"},
95  {"NOTPRESENT", "NotPresent"},
96  {"PATHSET", "PathSet"},
97  {"VL", "Blob"},
98  {"XCHAIN_BRIDGE", "XChainBridge"},
99  };
100 
101  if (auto const& it = replacements.find(inp); it != replacements.end())
102  {
103  return it->second;
104  }
105 
107  size_t pos = 0;
108  std::string inpToProcess = inp;
109 
110  // convert snake_case to CamelCase
111  for (;;)
112  {
113  pos = inpToProcess.find("_");
114  if (pos == std::string::npos)
115  pos = inpToProcess.size();
116  std::string token = inpToProcess.substr(0, pos);
117  if (token.size() > 1)
118  {
119  boost::algorithm::to_lower(token);
120  token.data()[0] -= ('a' - 'A');
121  out += token;
122  }
123  else
124  out += token;
125  if (pos == inpToProcess.size())
126  break;
127  inpToProcess = inpToProcess.substr(pos + 1);
128  }
129  return out;
130 };
131 
133 {
134  // populate SerializedTypeID names and values
135  defs_[jss::TYPES] = Json::objectValue;
136 
137  defs_[jss::TYPES]["Done"] = -1;
138  std::map<int32_t, std::string> typeMap{{-1, "Done"}};
139  for (auto const& [rawName, typeValue] : sTypeMap)
140  {
141  std::string typeName =
142  translate(std::string(rawName).substr(4) /* remove STI_ */);
143  defs_[jss::TYPES][typeName] = typeValue;
144  typeMap[typeValue] = typeName;
145  }
146 
147  // populate LedgerEntryType names and values
148  defs_[jss::LEDGER_ENTRY_TYPES] = Json::objectValue;
149  defs_[jss::LEDGER_ENTRY_TYPES][jss::Invalid] = -1;
150 
151  for (auto const& f : LedgerFormats::getInstance())
152  {
153  defs_[jss::LEDGER_ENTRY_TYPES][f.getName()] = f.getType();
154  }
155 
156  // populate SField serialization data
157  defs_[jss::FIELDS] = Json::arrayValue;
158 
159  uint32_t i = 0;
160  {
162  a[0U] = "Generic";
164  v[jss::nth] = 0;
165  v[jss::isVLEncoded] = false;
166  v[jss::isSerialized] = false;
167  v[jss::isSigningField] = false;
168  v[jss::type] = "Unknown";
169  a[1U] = v;
170  defs_[jss::FIELDS][i++] = a;
171  }
172 
173  {
175  a[0U] = "Invalid";
177  v[jss::nth] = -1;
178  v[jss::isVLEncoded] = false;
179  v[jss::isSerialized] = false;
180  v[jss::isSigningField] = false;
181  v[jss::type] = "Unknown";
182  a[1U] = v;
183  defs_[jss::FIELDS][i++] = a;
184  }
185 
186  {
188  a[0U] = "ObjectEndMarker";
190  v[jss::nth] = 1;
191  v[jss::isVLEncoded] = false;
192  v[jss::isSerialized] = true;
193  v[jss::isSigningField] = true;
194  v[jss::type] = "STObject";
195  a[1U] = v;
196  defs_[jss::FIELDS][i++] = a;
197  }
198 
199  {
201  a[0U] = "ArrayEndMarker";
203  v[jss::nth] = 1;
204  v[jss::isVLEncoded] = false;
205  v[jss::isSerialized] = true;
206  v[jss::isSigningField] = true;
207  v[jss::type] = "STArray";
208  a[1U] = v;
209  defs_[jss::FIELDS][i++] = a;
210  }
211 
212  {
214  a[0U] = "taker_gets_funded";
216  v[jss::nth] = 258;
217  v[jss::isVLEncoded] = false;
218  v[jss::isSerialized] = false;
219  v[jss::isSigningField] = false;
220  v[jss::type] = "Amount";
221  a[1U] = v;
222  defs_[jss::FIELDS][i++] = a;
223  }
224 
225  {
227  a[0U] = "taker_pays_funded";
229  v[jss::nth] = 259;
230  v[jss::isVLEncoded] = false;
231  v[jss::isSerialized] = false;
232  v[jss::isSigningField] = false;
233  v[jss::type] = "Amount";
234  a[1U] = v;
235  defs_[jss::FIELDS][i++] = a;
236  }
237 
238  for (auto const& [code, f] : ripple::SField::getKnownCodeToField())
239  {
240  if (f->fieldName == "")
241  continue;
242 
243  Json::Value innerObj = Json::objectValue;
244 
245  uint32_t type = f->fieldType;
246 
247  innerObj[jss::nth] = f->fieldValue;
248 
249  // whether the field is variable-length encoded
250  // this means that the length is included before the content
251  innerObj[jss::isVLEncoded] =
252  (type == 7U /* Blob */ || type == 8U /* AccountID */ ||
253  type == 19U /* Vector256 */);
254 
255  // whether the field is included in serialization
256  innerObj[jss::isSerialized] =
257  (type < 10000 && f->fieldName != "hash" &&
258  f->fieldName != "index"); /* hash, index, TRANSACTION,
259  LEDGER_ENTRY, VALIDATION, METADATA */
260 
261  // whether the field is included in serialization when signing
262  innerObj[jss::isSigningField] = f->shouldInclude(false);
263 
264  innerObj[jss::type] = typeMap[type];
265 
266  Json::Value innerArray = Json::arrayValue;
267  innerArray[0U] = f->fieldName;
268  innerArray[1U] = innerObj;
269 
270  defs_[jss::FIELDS][i++] = innerArray;
271  }
272 
273  // populate TER code names and values
274  defs_[jss::TRANSACTION_RESULTS] = Json::objectValue;
275 
276  for (auto const& [code, terInfo] : transResults())
277  {
278  defs_[jss::TRANSACTION_RESULTS][terInfo.first] = code;
279  }
280 
281  // populate TxType names and values
282  defs_[jss::TRANSACTION_TYPES] = Json::objectValue;
283  defs_[jss::TRANSACTION_TYPES][jss::Invalid] = -1;
284  for (auto const& f : TxFormats::getInstance())
285  {
286  defs_[jss::TRANSACTION_TYPES][f.getName()] = f.getType();
287  }
288 
289  // generate hash
290  {
291  const std::string out = Json::FastWriter().write(defs_);
292  defsHash_ = ripple::sha512Half(ripple::Slice{out.data(), out.size()});
293  defs_[jss::hash] = to_string(defsHash_);
294  }
295 }
296 
297 } // namespace detail
298 
301 {
302  auto& params = context.params;
303 
304  uint256 hash;
305  if (params.isMember(jss::hash))
306  {
307  if (!params[jss::hash].isString() ||
308  !hash.parseHex(params[jss::hash].asString()))
309  return RPC::invalid_field_error(jss::hash);
310  }
311 
312  static const detail::ServerDefinitions defs{};
313  if (defs.hashMatches(hash))
314  {
316  jv[jss::hash] = to_string(hash);
317  return jv;
318  }
319  return defs.get();
320 }
321 
324 {
326 
327  ret[jss::info] = context.netOps.getServerInfo(
328  true,
329  context.role == Role::ADMIN,
330  context.params.isMember(jss::counters) &&
331  context.params[jss::counters].asBool());
332 
333  if (context.app.config().reporting())
334  {
335  Json::Value const proxied = forwardToP2p(context);
336  auto const lf = proxied[jss::result][jss::info][jss::load_factor];
337  auto const vq = proxied[jss::result][jss::info][jss::validation_quorum];
338  ret[jss::info][jss::validation_quorum] = vq.isNull() ? 1 : vq;
339  ret[jss::info][jss::load_factor] = lf.isNull() ? 1 : lf;
340  }
341  return ret;
342 }
343 
344 } // 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:108
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:300
std::string::size
T size(T... args)
ripple::SField::getKnownCodeToField
static std::map< int, SField const * > const & getKnownCodeToField()
Definition: SField.h:294
ripple::detail::ServerDefinitions
Definition: ServerInfo.cpp:43
ripple::detail::ServerDefinitions::defsHash_
uint256 defsHash_
Definition: ServerInfo.cpp:50
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:132
Json::Value::asBool
bool asBool() const
Definition: json_value.cpp:619
ripple::detail::ServerDefinitions::get
Json::Value const & get() const
Definition: ServerInfo.cpp:63
ripple::base_uint< 256 >
ripple::Config::reporting
bool reporting() const
Definition: Config.h:350
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:57
ripple::TxFormats::getInstance
static TxFormats const & getInstance()
Definition: TxFormats.cpp:508
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:362
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:51
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:323
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:310
ripple::detail::ServerDefinitions::translate
std::string translate(std::string const &inp)
Definition: ServerInfo.cpp:70
Json::Value
Represents a JSON value.
Definition: json_value.h:145