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  BasicApp worker{1};
158  using namespace std::chrono_literals;
159  NetClock::time_point const expiration{3600s};
160  TrustedPublisherServer server{
161  worker.get_io_service(), validators, expiration, false, 1, false};
162 
163  //----------------------------------------------------------------------
164  // Publisher list site unavailable
165  {
166  // Publisher site information
167  using namespace std::string_literals;
168  std::string siteURI =
169  "http://"s + getEnvLocalhostAddr() + ":1234/validators";
170 
171  Env env{
172  *this,
174  cfg->section(SECTION_VALIDATOR_LIST_SITES).append(siteURI);
175  cfg->section(SECTION_VALIDATOR_LIST_KEYS)
176  .append(strHex(server.publisherPublic()));
177  return cfg;
178  }),
179  };
180 
181  env.app().validatorSites().start();
182  env.app().validatorSites().join();
183 
184  {
185  auto const jrr = env.rpc("server_info")[jss::result];
186  BEAST_EXPECT(
187  jrr[jss::info][jss::validator_list][jss::expiration] ==
188  "unknown");
189  }
190  {
191  auto const jrr = env.rpc("server_state")[jss::result];
192  BEAST_EXPECT(
193  jrr[jss::state][jss::validator_list_expires].asInt() == 0);
194  }
195  {
196  auto const jrr = env.rpc("validators")[jss::result];
197  BEAST_EXPECT(
198  jrr[jss::validation_quorum].asUInt() ==
200  BEAST_EXPECT(jrr[jss::local_static_keys].size() == 0);
201  BEAST_EXPECT(jrr[jss::trusted_validator_keys].size() == 0);
202  BEAST_EXPECT(
203  jrr[jss::validator_list][jss::expiration] == "unknown");
204 
205  if (BEAST_EXPECT(jrr[jss::publisher_lists].size() == 1))
206  {
207  auto jp = jrr[jss::publisher_lists][0u];
208  BEAST_EXPECT(jp[jss::available] == false);
209  BEAST_EXPECT(jp[jss::list].size() == 0);
210  BEAST_EXPECT(!jp.isMember(jss::seq));
211  BEAST_EXPECT(!jp.isMember(jss::expiration));
212  BEAST_EXPECT(!jp.isMember(jss::version));
213  BEAST_EXPECT(
214  jp[jss::pubkey_publisher] ==
215  strHex(server.publisherPublic()));
216  }
217  BEAST_EXPECT(jrr[jss::signing_keys].size() == 0);
218  }
219  {
220  auto const jrr = env.rpc("validator_list_sites")[jss::result];
221  if (BEAST_EXPECT(jrr[jss::validator_sites].size() == 1))
222  {
223  auto js = jrr[jss::validator_sites][0u];
224  BEAST_EXPECT(js[jss::refresh_interval_min].asUInt() == 5);
225  BEAST_EXPECT(js[jss::uri] == siteURI);
226  BEAST_EXPECT(js.isMember(jss::last_refresh_time));
227  BEAST_EXPECT(js[jss::last_refresh_status] == "invalid");
228  }
229  }
230  }
231  //----------------------------------------------------------------------
232  // Publisher list site available
233  {
234  server.start();
235 
236  std::stringstream uri;
237  uri << "http://" << server.local_endpoint() << "/validators";
238  auto siteURI = uri.str();
239 
240  Env env{
241  *this,
243  cfg->section(SECTION_VALIDATOR_LIST_SITES).append(siteURI);
244  cfg->section(SECTION_VALIDATOR_LIST_KEYS)
245  .append(strHex(server.publisherPublic()));
246  return cfg;
247  }),
248  };
249 
250  env.app().validatorSites().start();
251  env.app().validatorSites().join();
252  hash_set<NodeID> startKeys;
253  for (auto const& val : validators)
254  startKeys.insert(calcNodeID(val.masterPublic));
255 
256  env.app().validators().updateTrusted(startKeys);
257 
258  {
259  auto const jrr = env.rpc("server_info")[jss::result];
260  BEAST_EXPECT(
261  jrr[jss::info][jss::validator_list][jss::expiration] ==
263  }
264  {
265  auto const jrr = env.rpc("server_state")[jss::result];
266  BEAST_EXPECT(
267  jrr[jss::state][jss::validator_list_expires].asUInt() ==
268  expiration.time_since_epoch().count());
269  }
270  {
271  auto const jrr = env.rpc("validators")[jss::result];
272  BEAST_EXPECT(jrr[jss::validation_quorum].asUInt() == 2);
273  BEAST_EXPECT(
274  jrr[jss::validator_list][jss::expiration] ==
276  BEAST_EXPECT(jrr[jss::local_static_keys].size() == 0);
277 
278  BEAST_EXPECT(
279  jrr[jss::trusted_validator_keys].size() ==
280  expectedKeys.size());
281  for (auto const& jKey : jrr[jss::trusted_validator_keys])
282  {
283  BEAST_EXPECT(expectedKeys.count(jKey.asString()) == 1);
284  }
285 
286  if (BEAST_EXPECT(jrr[jss::publisher_lists].size() == 1))
287  {
288  auto jp = jrr[jss::publisher_lists][0u];
289  BEAST_EXPECT(jp[jss::available] == true);
290  if (BEAST_EXPECT(jp[jss::list].size() == 2))
291  {
292  // check entries
293  std::set<std::string> foundKeys;
294  for (auto const& k : jp[jss::list])
295  {
296  foundKeys.insert(k.asString());
297  }
298  BEAST_EXPECT(foundKeys == expectedKeys);
299  }
300  BEAST_EXPECT(jp[jss::seq].asUInt() == 1);
301  BEAST_EXPECT(
302  jp[jss::pubkey_publisher] ==
303  strHex(server.publisherPublic()));
304  BEAST_EXPECT(jp[jss::expiration] == to_string(expiration));
305  BEAST_EXPECT(jp[jss::version] == 1);
306  }
307  auto jsk = jrr[jss::signing_keys];
308  BEAST_EXPECT(jsk.size() == 2);
309  for (auto const& val : validators)
310  {
311  BEAST_EXPECT(jsk.isMember(toStr(val.masterPublic)));
312  BEAST_EXPECT(
313  jsk[toStr(val.masterPublic)] ==
314  toStr(val.signingPublic));
315  }
316  }
317  {
318  auto const jrr = env.rpc("validator_list_sites")[jss::result];
319  if (BEAST_EXPECT(jrr[jss::validator_sites].size() == 1))
320  {
321  auto js = jrr[jss::validator_sites][0u];
322  BEAST_EXPECT(js[jss::refresh_interval_min].asUInt() == 5);
323  BEAST_EXPECT(js[jss::uri] == siteURI);
324  BEAST_EXPECT(js[jss::last_refresh_status] == "accepted");
325  // The actual time of the update will vary run to run, so
326  // just verify the time is there
327  BEAST_EXPECT(js.isMember(jss::last_refresh_time));
328  }
329  }
330  }
331  }
332 
333  void
335  {
336  using namespace test::jtx;
337  Env env{*this};
338  auto result = env.rpc("validation_create");
339  BEAST_EXPECT(
340  result.isMember(jss::result) &&
341  result[jss::result][jss::status] == "success");
342  result = env.rpc(
343  "validation_create",
344  "BAWL MAN JADE MOON DOVE GEM SON NOW HAD ADEN GLOW TIRE");
345  BEAST_EXPECT(
346  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: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:351
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:334
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