rippled
ValidatorRPC_test.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012-2016 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/BasicApp.h>
21 #include <ripple/app/misc/ValidatorSite.h>
22 #include <ripple/basics/base64.h>
23 #include <ripple/beast/unit_test.h>
24 #include <ripple/core/ConfigSections.h>
25 #include <ripple/json/json_value.h>
26 #include <ripple/protocol/jss.h>
27 #include <ripple/protocol/Sign.h>
28 #include <test/jtx.h>
29 #include <test/jtx/TrustedPublisherServer.h>
30 
31 #include <set>
32 
33 namespace ripple {
34 
35 namespace test {
36 
37 class ValidatorRPC_test : public beast::unit_test::suite
38 {
40 
41 public:
42  void
44  {
45  using namespace test::jtx;
46 
47  for (bool const isAdmin : {true, false})
48  {
49  for (std::string cmd : {"validators", "validator_list_sites"})
50  {
51  Env env{*this, isAdmin ? envconfig() : envconfig(no_admin)};
52  auto const jrr = env.rpc(cmd)[jss::result];
53  if (isAdmin)
54  {
55  BEAST_EXPECT(!jrr.isMember(jss::error));
56  BEAST_EXPECT(jrr[jss::status] == "success");
57  }
58  else
59  {
60  // The current HTTP/S ServerHandler returns an HTTP 403
61  // error code here rather than a noPermission JSON error.
62  // The JSONRPCClient just eats that error and returns null
63  // result.
64  BEAST_EXPECT(jrr.isNull());
65  }
66  }
67 
68  {
69  Env env{*this, isAdmin ? envconfig() : envconfig(no_admin)};
70  auto const jrr = env.rpc("server_info")[jss::result];
71  BEAST_EXPECT(jrr[jss::status] == "success");
72  BEAST_EXPECT(jrr[jss::info].isMember(
73  jss::validator_list) == isAdmin);
74  }
75 
76  {
77  Env env{*this, isAdmin ? envconfig() : envconfig(no_admin)};
78  auto const jrr = env.rpc("server_state")[jss::result];
79  BEAST_EXPECT(jrr[jss::status] == "success");
80  BEAST_EXPECT(jrr[jss::state].isMember(
81  jss::validator_list_expires) == isAdmin);
82  }
83  }
84  }
85 
86  void
88  {
89  using namespace test::jtx;
90 
91  std::set<std::string> const keys = {
92  "n949f75evCHwgyP4fPVgaHqNHxUVN15PsJEZ3B3HnXPcPjcZAoy7",
93  "n9MD5h24qrQqiyBC8aeqqCWvpiBiYQ3jxSr91uiDvmrkyHRdYLUj"};
94  Env env{
95  *this,
96  envconfig([&keys](std::unique_ptr<Config> cfg) {
97  for (auto const& key : keys)
98  cfg->section(SECTION_VALIDATORS).append(key);
99  return cfg;
100  }),
101  };
102 
103  // Server info reports maximum expiration since not dynamic
104  {
105  auto const jrr = env.rpc("server_info")[jss::result];
106  BEAST_EXPECT(
107  jrr[jss::info][jss::validator_list][jss::expiration] ==
108  "never");
109  }
110  {
111  auto const jrr = env.rpc("server_state")[jss::result];
112  BEAST_EXPECT(
113  jrr[jss::state][jss::validator_list_expires].asUInt() ==
114  NetClock::time_point::max().time_since_epoch().count());
115  }
116  // All our keys are in the response
117  {
118  auto const jrr = env.rpc("validators")[jss::result];
119  BEAST_EXPECT(jrr[jss::validator_list][jss::expiration] == "never");
120  BEAST_EXPECT(jrr[jss::validation_quorum].asUInt() == keys.size());
121  BEAST_EXPECT(jrr[jss::trusted_validator_keys].size() == keys.size());
122  BEAST_EXPECT(jrr[jss::publisher_lists].size() == 0);
123  BEAST_EXPECT(jrr[jss::local_static_keys].size() == keys.size());
124  for (auto const& jKey : jrr[jss::local_static_keys])
125  {
126  BEAST_EXPECT(keys.count(jKey.asString())== 1);
127  }
128  BEAST_EXPECT(jrr[jss::signing_keys].size() == 0);
129  }
130  // No validator sites configured
131  {
132  auto const jrr = env.rpc("validator_list_sites")[jss::result];
133  BEAST_EXPECT(jrr[jss::validator_sites].size() == 0);
134  }
135  }
136 
137  void
139  {
140  using namespace test::jtx;
141 
142  auto toStr = [](PublicKey const& publicKey) {
143  return toBase58(TokenType::NodePublic, publicKey);
144  };
145 
146  // Validator keys that will be in the published list
147  std::vector<Validator> validators = {
150  std::set<std::string> expectedKeys;
151  for (auto const& val : validators)
152  expectedKeys.insert(toStr(val.masterPublic));
153 
154  // Manage single thread io_service for server
155  struct Worker : BasicApp
156  {
157  Worker() : BasicApp(1) {}
158  };
159  Worker w;
160  using namespace std::chrono_literals;
161  NetClock::time_point const expiration{3600s};
162  TrustedPublisherServer server{
163  w.get_io_service(),
164  validators,
165  expiration,
166  false,
167  1,
168  false};
169 
170  //----------------------------------------------------------------------
171  // Publisher list site unavailable
172  {
173  // Publisher site information
174  using namespace std::string_literals;
175  std::string siteURI =
176  "http://"s + getEnvLocalhostAddr() + ":1234/validators";
177 
178  Env env{
179  *this,
181  cfg->section(SECTION_VALIDATOR_LIST_SITES).append(siteURI);
182  cfg->section(SECTION_VALIDATOR_LIST_KEYS)
183  .append(strHex(server.publisherPublic()));
184  return cfg;
185  }),
186  };
187 
188  env.app().validatorSites().start();
189  env.app().validatorSites().join();
190 
191  {
192  auto const jrr = env.rpc("server_info")[jss::result];
193  BEAST_EXPECT(
194  jrr[jss::info][jss::validator_list][jss::expiration] ==
195  "unknown");
196  }
197  {
198  auto const jrr = env.rpc("server_state")[jss::result];
199  BEAST_EXPECT(
200  jrr[jss::state][jss::validator_list_expires].asInt() == 0);
201  }
202  {
203  auto const jrr = env.rpc("validators")[jss::result];
204  BEAST_EXPECT(jrr[jss::validation_quorum].asUInt() ==
206  BEAST_EXPECT(jrr[jss::local_static_keys].size() == 0);
207  BEAST_EXPECT(jrr[jss::trusted_validator_keys].size() == 0);
208  BEAST_EXPECT(
209  jrr[jss::validator_list][jss::expiration] == "unknown");
210 
211  if (BEAST_EXPECT(jrr[jss::publisher_lists].size() == 1))
212  {
213  auto jp = jrr[jss::publisher_lists][0u];
214  BEAST_EXPECT(jp[jss::available] == false);
215  BEAST_EXPECT(jp[jss::list].size() == 0);
216  BEAST_EXPECT(!jp.isMember(jss::seq));
217  BEAST_EXPECT(!jp.isMember(jss::expiration));
218  BEAST_EXPECT(!jp.isMember(jss::version));
219  BEAST_EXPECT(
220  jp[jss::pubkey_publisher] == strHex(server.publisherPublic()));
221  }
222  BEAST_EXPECT(jrr[jss::signing_keys].size() == 0);
223  }
224  {
225  auto const jrr = env.rpc("validator_list_sites")[jss::result];
226  if (BEAST_EXPECT(jrr[jss::validator_sites].size() == 1))
227  {
228  auto js = jrr[jss::validator_sites][0u];
229  BEAST_EXPECT(js[jss::refresh_interval_min].asUInt() == 5);
230  BEAST_EXPECT(js[jss::uri] == siteURI);
231  BEAST_EXPECT(js.isMember(jss::last_refresh_time));
232  BEAST_EXPECT(js[jss::last_refresh_status] == "invalid");
233  }
234  }
235  }
236  //----------------------------------------------------------------------
237  // Publisher list site available
238  {
239  server.start();
240 
241  std::stringstream uri;
242  uri << "http://" << server.local_endpoint() << "/validators";
243  auto siteURI = uri.str();
244 
245  Env env{
246  *this,
248  cfg->section(SECTION_VALIDATOR_LIST_SITES).append(siteURI);
249  cfg->section(SECTION_VALIDATOR_LIST_KEYS)
250  .append(strHex(server.publisherPublic()));
251  return cfg;
252  }),
253  };
254 
255  env.app().validatorSites().start();
256  env.app().validatorSites().join();
257  hash_set<NodeID> startKeys;
258  for (auto const& val : validators)
259  startKeys.insert(calcNodeID(val.masterPublic));
260 
261  env.app().validators().updateTrusted(startKeys);
262 
263  {
264  auto const jrr = env.rpc("server_info")[jss::result];
265  BEAST_EXPECT(
266  jrr[jss::info][jss::validator_list][jss::expiration] ==
268  }
269  {
270  auto const jrr = env.rpc("server_state")[jss::result];
271  BEAST_EXPECT(
272  jrr[jss::state][jss::validator_list_expires].asUInt() ==
273  expiration.time_since_epoch().count());
274  }
275  {
276  auto const jrr = env.rpc("validators")[jss::result];
277  BEAST_EXPECT(jrr[jss::validation_quorum].asUInt() == 2);
278  BEAST_EXPECT(
279  jrr[jss::validator_list][jss::expiration] ==
281  BEAST_EXPECT(jrr[jss::local_static_keys].size() == 0);
282 
283  BEAST_EXPECT(jrr[jss::trusted_validator_keys].size() ==
284  expectedKeys.size());
285  for (auto const& jKey : jrr[jss::trusted_validator_keys])
286  {
287  BEAST_EXPECT(expectedKeys.count(jKey.asString()) == 1);
288  }
289 
290  if (BEAST_EXPECT(jrr[jss::publisher_lists].size() == 1))
291  {
292  auto jp = jrr[jss::publisher_lists][0u];
293  BEAST_EXPECT(jp[jss::available] == true);
294  if (BEAST_EXPECT(jp[jss::list].size() == 2))
295  {
296  // check entries
297  std::set<std::string> foundKeys;
298  for (auto const& k : jp[jss::list])
299  {
300  foundKeys.insert(k.asString());
301  }
302  BEAST_EXPECT(foundKeys == expectedKeys);
303  }
304  BEAST_EXPECT(jp[jss::seq].asUInt() == 1);
305  BEAST_EXPECT(
306  jp[jss::pubkey_publisher] == strHex(server.publisherPublic()));
307  BEAST_EXPECT(jp[jss::expiration] == to_string(expiration));
308  BEAST_EXPECT(jp[jss::version] == 1);
309  }
310  auto jsk = jrr[jss::signing_keys];
311  BEAST_EXPECT(jsk.size() == 2);
312  for (auto const& val : validators)
313  {
314  BEAST_EXPECT(jsk.isMember(toStr(val.masterPublic)));
315  BEAST_EXPECT(
316  jsk[toStr(val.masterPublic)] ==
317  toStr(val.signingPublic));
318  }
319  }
320  {
321  auto const jrr = env.rpc("validator_list_sites")[jss::result];
322  if (BEAST_EXPECT(jrr[jss::validator_sites].size() == 1))
323  {
324  auto js = jrr[jss::validator_sites][0u];
325  BEAST_EXPECT(js[jss::refresh_interval_min].asUInt() == 5);
326  BEAST_EXPECT(js[jss::uri] == siteURI);
327  BEAST_EXPECT(js[jss::last_refresh_status] == "accepted");
328  // The actual time of the update will vary run to run, so
329  // just verify the time is there
330  BEAST_EXPECT(js.isMember(jss::last_refresh_time));
331  }
332  }
333  }
334  }
335 
336  void
338  {
339  using namespace test::jtx;
340  Env env{*this};
341  auto result = env.rpc("validation_create");
342  BEAST_EXPECT(result.isMember(jss::result) &&
343  result[jss::result][jss::status] == "success");
344  result = env.rpc("validation_create",
345  "BAWL MAN JADE MOON DOVE GEM SON NOW HAD ADEN GLOW TIRE");
346  BEAST_EXPECT(result.isMember(jss::result) &&
347  result[jss::result][jss::status] == "success");
348  }
349 
350  void
351  run() override
352  {
353  testPrivileges();
354  testStaticUNL();
355  testDynamicUNL();
357  }
358 };
359 
360 BEAST_DEFINE_TESTSUITE(ValidatorRPC, app, ripple);
361 
362 } // namespace test
363 } // namespace ripple
ripple::isAdmin
bool isAdmin(Port const &port, Json::Value const &params, beast::IP::Address const &remoteIp)
Definition: Role.cpp:54
ripple::test::ValidatorRPC_test::testDynamicUNL
void testDynamicUNL()
Definition: ValidatorRPC_test.cpp:138
ripple::test::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(AccountDelete, app, ripple)
std::string
STL class.
ripple::calcNodeID
NodeID calcNodeID(PublicKey const &pk)
Calculate the 160-bit node ID from a node public key.
Definition: PublicKey.cpp:307
std::unordered_set
STL class.
std::vector
STL class.
std::set::size
T size(T... args)
ripple::toBase58
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition: AccountID.cpp:29
std::stringstream
STL class.
ripple::to_string
std::string to_string(ListDisposition disposition)
Definition: ValidatorList.cpp:41
ripple::test::jtx::envconfig
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
Definition: envconfig.h:52
ripple::test::ValidatorRPC_test::run
void run() override
Definition: ValidatorRPC_test.cpp:351
ripple::test::jtx::expiration
Set Expiration on a JTx.
Definition: Check_test.cpp:29
ripple::test::getEnvLocalhostAddr
const char * getEnvLocalhostAddr()
Definition: envconfig.h:32
ripple::test::jtx::no_admin
std::unique_ptr< Config > no_admin(std::unique_ptr< Config >)
adjust config so no admin ports are enabled
Definition: envconfig.cpp:69
ripple::test::ValidatorRPC_test::testPrivileges
void testPrivileges()
Definition: ValidatorRPC_test.cpp:43
ripple::PublicKey
A public key.
Definition: PublicKey.h:59
ripple::test::TrustedPublisherServer::Validator
Definition: TrustedPublisherServer.h:94
std::chrono::time_point
ripple::test::TrustedPublisherServer
Definition: TrustedPublisherServer.h:42
ripple::test::ValidatorRPC_test::testStaticUNL
void testStaticUNL()
Definition: ValidatorRPC_test.cpp:87
ripple::test::TrustedPublisherServer::randomValidator
static Validator randomValidator()
Definition: TrustedPublisherServer.h:128
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::test::ValidatorRPC_test
Definition: ValidatorRPC_test.cpp:37
std::set::insert
T insert(T... args)
std::set::count
T count(T... args)
ripple::TokenType::NodePublic
@ NodePublic
std::stringstream::str
T str(T... args)
BasicApp
Definition: BasicApp.h:29
ripple::strHex
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:70
ripple::test::ValidatorRPC_test::test_validation_create
void test_validation_create()
Definition: ValidatorRPC_test.cpp:337
std::chrono::time_point::max
T max(T... args)
std::unique_ptr
STL class.
std::numeric_limits
set
ripple::test::jtx::Env
A transaction testing environment.
Definition: Env.h:117
ripple::test::jtx::Env::rpc
Json::Value rpc(std::unordered_map< std::string, std::string > const &headers, std::string const &cmd, Args &&... args)
Execute an RPC command.
Definition: Env.h:688