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/Sign.h>
27 #include <ripple/protocol/jss.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(
73  jrr[jss::info].isMember(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(
81  jrr[jss::state].isMember(jss::validator_list_expires) ==
82  isAdmin);
83  }
84  }
85  }
86 
87  void
89  {
90  using namespace test::jtx;
91 
92  std::set<std::string> const keys = {
93  "n949f75evCHwgyP4fPVgaHqNHxUVN15PsJEZ3B3HnXPcPjcZAoy7",
94  "n9MD5h24qrQqiyBC8aeqqCWvpiBiYQ3jxSr91uiDvmrkyHRdYLUj"};
95  Env env{
96  *this,
97  envconfig([&keys](std::unique_ptr<Config> cfg) {
98  for (auto const& key : keys)
99  cfg->section(SECTION_VALIDATORS).append(key);
100  return cfg;
101  }),
102  };
103 
104  // Server info reports maximum expiration since not dynamic
105  {
106  auto const jrr = env.rpc("server_info")[jss::result];
107  BEAST_EXPECT(
108  jrr[jss::info][jss::validator_list][jss::expiration] ==
109  "never");
110  }
111  {
112  auto const jrr = env.rpc("server_state")[jss::result];
113  BEAST_EXPECT(
114  jrr[jss::state][jss::validator_list_expires].asUInt() ==
115  NetClock::time_point::max().time_since_epoch().count());
116  }
117  // All our keys are in the response
118  {
119  auto const jrr = env.rpc("validators")[jss::result];
120  BEAST_EXPECT(jrr[jss::validator_list][jss::expiration] == "never");
121  BEAST_EXPECT(jrr[jss::validation_quorum].asUInt() == keys.size());
122  BEAST_EXPECT(
123  jrr[jss::trusted_validator_keys].size() == keys.size());
124  BEAST_EXPECT(jrr[jss::publisher_lists].size() == 0);
125  BEAST_EXPECT(jrr[jss::local_static_keys].size() == keys.size());
126  for (auto const& jKey : jrr[jss::local_static_keys])
127  {
128  BEAST_EXPECT(keys.count(jKey.asString()) == 1);
129  }
130  BEAST_EXPECT(jrr[jss::signing_keys].size() == 0);
131  }
132  // No validator sites configured
133  {
134  auto const jrr = env.rpc("validator_list_sites")[jss::result];
135  BEAST_EXPECT(jrr[jss::validator_sites].size() == 0);
136  }
137  }
138 
139  void
141  {
142  using namespace test::jtx;
143 
144  auto toStr = [](PublicKey const& publicKey) {
145  return toBase58(TokenType::NodePublic, publicKey);
146  };
147 
148  // Validator keys that will be in the published list
149  std::vector<Validator> validators = {
152  std::set<std::string> expectedKeys;
153  for (auto const& val : validators)
154  expectedKeys.insert(toStr(val.masterPublic));
155 
156  // Manage single thread io_service for server
157  struct Worker : BasicApp
158  {
159  Worker() : BasicApp(1)
160  {
161  }
162  };
163  Worker w;
164  using namespace std::chrono_literals;
165  NetClock::time_point const expiration{3600s};
166  TrustedPublisherServer server{
167  w.get_io_service(), validators, expiration, false, 1, false};
168 
169  //----------------------------------------------------------------------
170  // Publisher list site unavailable
171  {
172  // Publisher site information
173  using namespace std::string_literals;
174  std::string siteURI =
175  "http://"s + getEnvLocalhostAddr() + ":1234/validators";
176 
177  Env env{
178  *this,
180  cfg->section(SECTION_VALIDATOR_LIST_SITES).append(siteURI);
181  cfg->section(SECTION_VALIDATOR_LIST_KEYS)
182  .append(strHex(server.publisherPublic()));
183  return cfg;
184  }),
185  };
186 
187  env.app().validatorSites().start();
188  env.app().validatorSites().join();
189 
190  {
191  auto const jrr = env.rpc("server_info")[jss::result];
192  BEAST_EXPECT(
193  jrr[jss::info][jss::validator_list][jss::expiration] ==
194  "unknown");
195  }
196  {
197  auto const jrr = env.rpc("server_state")[jss::result];
198  BEAST_EXPECT(
199  jrr[jss::state][jss::validator_list_expires].asInt() == 0);
200  }
201  {
202  auto const jrr = env.rpc("validators")[jss::result];
203  BEAST_EXPECT(
204  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] ==
221  strHex(server.publisherPublic()));
222  }
223  BEAST_EXPECT(jrr[jss::signing_keys].size() == 0);
224  }
225  {
226  auto const jrr = env.rpc("validator_list_sites")[jss::result];
227  if (BEAST_EXPECT(jrr[jss::validator_sites].size() == 1))
228  {
229  auto js = jrr[jss::validator_sites][0u];
230  BEAST_EXPECT(js[jss::refresh_interval_min].asUInt() == 5);
231  BEAST_EXPECT(js[jss::uri] == siteURI);
232  BEAST_EXPECT(js.isMember(jss::last_refresh_time));
233  BEAST_EXPECT(js[jss::last_refresh_status] == "invalid");
234  }
235  }
236  }
237  //----------------------------------------------------------------------
238  // Publisher list site available
239  {
240  server.start();
241 
242  std::stringstream uri;
243  uri << "http://" << server.local_endpoint() << "/validators";
244  auto siteURI = uri.str();
245 
246  Env env{
247  *this,
249  cfg->section(SECTION_VALIDATOR_LIST_SITES).append(siteURI);
250  cfg->section(SECTION_VALIDATOR_LIST_KEYS)
251  .append(strHex(server.publisherPublic()));
252  return cfg;
253  }),
254  };
255 
256  env.app().validatorSites().start();
257  env.app().validatorSites().join();
258  hash_set<NodeID> startKeys;
259  for (auto const& val : validators)
260  startKeys.insert(calcNodeID(val.masterPublic));
261 
262  env.app().validators().updateTrusted(startKeys);
263 
264  {
265  auto const jrr = env.rpc("server_info")[jss::result];
266  BEAST_EXPECT(
267  jrr[jss::info][jss::validator_list][jss::expiration] ==
269  }
270  {
271  auto const jrr = env.rpc("server_state")[jss::result];
272  BEAST_EXPECT(
273  jrr[jss::state][jss::validator_list_expires].asUInt() ==
274  expiration.time_since_epoch().count());
275  }
276  {
277  auto const jrr = env.rpc("validators")[jss::result];
278  BEAST_EXPECT(jrr[jss::validation_quorum].asUInt() == 2);
279  BEAST_EXPECT(
280  jrr[jss::validator_list][jss::expiration] ==
282  BEAST_EXPECT(jrr[jss::local_static_keys].size() == 0);
283 
284  BEAST_EXPECT(
285  jrr[jss::trusted_validator_keys].size() ==
286  expectedKeys.size());
287  for (auto const& jKey : jrr[jss::trusted_validator_keys])
288  {
289  BEAST_EXPECT(expectedKeys.count(jKey.asString()) == 1);
290  }
291 
292  if (BEAST_EXPECT(jrr[jss::publisher_lists].size() == 1))
293  {
294  auto jp = jrr[jss::publisher_lists][0u];
295  BEAST_EXPECT(jp[jss::available] == true);
296  if (BEAST_EXPECT(jp[jss::list].size() == 2))
297  {
298  // check entries
299  std::set<std::string> foundKeys;
300  for (auto const& k : jp[jss::list])
301  {
302  foundKeys.insert(k.asString());
303  }
304  BEAST_EXPECT(foundKeys == expectedKeys);
305  }
306  BEAST_EXPECT(jp[jss::seq].asUInt() == 1);
307  BEAST_EXPECT(
308  jp[jss::pubkey_publisher] ==
309  strHex(server.publisherPublic()));
310  BEAST_EXPECT(jp[jss::expiration] == to_string(expiration));
311  BEAST_EXPECT(jp[jss::version] == 1);
312  }
313  auto jsk = jrr[jss::signing_keys];
314  BEAST_EXPECT(jsk.size() == 2);
315  for (auto const& val : validators)
316  {
317  BEAST_EXPECT(jsk.isMember(toStr(val.masterPublic)));
318  BEAST_EXPECT(
319  jsk[toStr(val.masterPublic)] ==
320  toStr(val.signingPublic));
321  }
322  }
323  {
324  auto const jrr = env.rpc("validator_list_sites")[jss::result];
325  if (BEAST_EXPECT(jrr[jss::validator_sites].size() == 1))
326  {
327  auto js = jrr[jss::validator_sites][0u];
328  BEAST_EXPECT(js[jss::refresh_interval_min].asUInt() == 5);
329  BEAST_EXPECT(js[jss::uri] == siteURI);
330  BEAST_EXPECT(js[jss::last_refresh_status] == "accepted");
331  // The actual time of the update will vary run to run, so
332  // just verify the time is there
333  BEAST_EXPECT(js.isMember(jss::last_refresh_time));
334  }
335  }
336  }
337  }
338 
339  void
341  {
342  using namespace test::jtx;
343  Env env{*this};
344  auto result = env.rpc("validation_create");
345  BEAST_EXPECT(
346  result.isMember(jss::result) &&
347  result[jss::result][jss::status] == "success");
348  result = env.rpc(
349  "validation_create",
350  "BAWL MAN JADE MOON DOVE GEM SON NOW HAD ADEN GLOW TIRE");
351  BEAST_EXPECT(
352  result.isMember(jss::result) &&
353  result[jss::result][jss::status] == "success");
354  }
355 
356  void
357  run() override
358  {
359  testPrivileges();
360  testStaticUNL();
361  testDynamicUNL();
363  }
364 };
365 
366 BEAST_DEFINE_TESTSUITE(ValidatorRPC, app, ripple);
367 
368 } // namespace test
369 } // namespace ripple
ripple::isAdmin
bool isAdmin(Port const &port, Json::Value const &params, beast::IP::Address const &remoteIp)
Definition: Role.cpp:57
ripple::test::ValidatorRPC_test::testDynamicUNL
void testDynamicUNL()
Definition: ValidatorRPC_test.cpp:140
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:299
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:49
ripple::test::ValidatorRPC_test::run
void run() override
Definition: ValidatorRPC_test.cpp:357
ripple::test::jtx::expiration
Set Expiration on a JTx.
Definition: Check_test.cpp:29
ripple::test::getEnvLocalhostAddr
const char * getEnvLocalhostAddr()
Definition: envconfig.h:31
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:70
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:92
std::chrono::time_point
ripple::test::TrustedPublisherServer
Definition: TrustedPublisherServer.h:42
ripple::test::ValidatorRPC_test::testStaticUNL
void testStaticUNL()
Definition: ValidatorRPC_test.cpp:88
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:67
ripple::test::ValidatorRPC_test::test_validation_create
void test_validation_create()
Definition: ValidatorRPC_test.cpp:340
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:114
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:676