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  // Negative UNL empty
138  {
139  auto const jrr = env.rpc("validators")[jss::result];
140  BEAST_EXPECT(jrr[jss::NegativeUNL].isNull());
141  }
142  // Negative UNL update
143  {
144  hash_set<PublicKey> disabledKeys;
145  auto k1 = randomKeyPair(KeyType::ed25519).first;
146  auto k2 = randomKeyPair(KeyType::ed25519).first;
147  disabledKeys.insert(k1);
148  disabledKeys.insert(k2);
149  env.app().validators().setNegativeUNL(disabledKeys);
150 
151  auto const jrr = env.rpc("validators")[jss::result];
152  auto& jrrnUnl = jrr[jss::NegativeUNL];
153  auto jrrnUnlSize = jrrnUnl.size();
154  BEAST_EXPECT(jrrnUnlSize == 2);
155  for (std::uint32_t x = 0; x < jrrnUnlSize; ++x)
156  {
157  auto parsedKey = parseBase58<PublicKey>(
158  TokenType::NodePublic, jrrnUnl[x].asString());
159  BEAST_EXPECT(parsedKey);
160  if (parsedKey)
161  BEAST_EXPECT(
162  disabledKeys.find(*parsedKey) != disabledKeys.end());
163  }
164 
165  disabledKeys.clear();
166  env.app().validators().setNegativeUNL(disabledKeys);
167  auto const jrrUpdated = env.rpc("validators")[jss::result];
168  BEAST_EXPECT(jrrUpdated[jss::NegativeUNL].isNull());
169  }
170  }
171 
172  void
174  {
175  using namespace test::jtx;
176 
177  auto toStr = [](PublicKey const& publicKey) {
178  return toBase58(TokenType::NodePublic, publicKey);
179  };
180 
181  // Validator keys that will be in the published list
182  std::vector<Validator> validators = {
185  std::set<std::string> expectedKeys;
186  for (auto const& val : validators)
187  expectedKeys.insert(toStr(val.masterPublic));
188 
189  // Manage single-thread io_service for server.
190  BasicApp worker{1};
191  using namespace std::chrono_literals;
192  NetClock::time_point const expiration{3600s};
193  auto server = make_TrustedPublisherServer(
194  worker.get_io_service(), validators, expiration, false, 1, false);
195 
196  //----------------------------------------------------------------------
197  // Publisher list site unavailable
198  {
199  // Publisher site information
200  using namespace std::string_literals;
201  std::string siteURI =
202  "http://"s + getEnvLocalhostAddr() + ":1234/validators";
203 
204  Env env{
205  *this,
207  cfg->section(SECTION_VALIDATOR_LIST_SITES).append(siteURI);
208  cfg->section(SECTION_VALIDATOR_LIST_KEYS)
209  .append(strHex(server->publisherPublic()));
210  return cfg;
211  }),
212  };
213 
214  env.app().validatorSites().start();
215  env.app().validatorSites().join();
216 
217  {
218  auto const jrr = env.rpc("server_info")[jss::result];
219  BEAST_EXPECT(
220  jrr[jss::info][jss::validator_list][jss::expiration] ==
221  "unknown");
222  }
223  {
224  auto const jrr = env.rpc("server_state")[jss::result];
225  BEAST_EXPECT(
226  jrr[jss::state][jss::validator_list_expires].asInt() == 0);
227  }
228  {
229  auto const jrr = env.rpc("validators")[jss::result];
230  BEAST_EXPECT(
231  jrr[jss::validation_quorum].asUInt() ==
233  BEAST_EXPECT(jrr[jss::local_static_keys].size() == 0);
234  BEAST_EXPECT(jrr[jss::trusted_validator_keys].size() == 0);
235  BEAST_EXPECT(
236  jrr[jss::validator_list][jss::expiration] == "unknown");
237 
238  if (BEAST_EXPECT(jrr[jss::publisher_lists].size() == 1))
239  {
240  auto jp = jrr[jss::publisher_lists][0u];
241  BEAST_EXPECT(jp[jss::available] == false);
242  BEAST_EXPECT(jp[jss::list].size() == 0);
243  BEAST_EXPECT(!jp.isMember(jss::seq));
244  BEAST_EXPECT(!jp.isMember(jss::expiration));
245  BEAST_EXPECT(!jp.isMember(jss::version));
246  BEAST_EXPECT(
247  jp[jss::pubkey_publisher] ==
248  strHex(server->publisherPublic()));
249  }
250  BEAST_EXPECT(jrr[jss::signing_keys].size() == 0);
251  }
252  {
253  auto const jrr = env.rpc("validator_list_sites")[jss::result];
254  if (BEAST_EXPECT(jrr[jss::validator_sites].size() == 1))
255  {
256  auto js = jrr[jss::validator_sites][0u];
257  BEAST_EXPECT(js[jss::refresh_interval_min].asUInt() == 5);
258  BEAST_EXPECT(js[jss::uri] == siteURI);
259  BEAST_EXPECT(js.isMember(jss::last_refresh_time));
260  BEAST_EXPECT(js[jss::last_refresh_status] == "invalid");
261  }
262  }
263  }
264  //----------------------------------------------------------------------
265  // Publisher list site available
266  {
267  server->start();
268 
269  std::stringstream uri;
270  uri << "http://" << server->local_endpoint() << "/validators";
271  auto siteURI = uri.str();
272 
273  Env env{
274  *this,
276  cfg->section(SECTION_VALIDATOR_LIST_SITES).append(siteURI);
277  cfg->section(SECTION_VALIDATOR_LIST_KEYS)
278  .append(strHex(server->publisherPublic()));
279  return cfg;
280  }),
281  };
282 
283  env.app().validatorSites().start();
284  env.app().validatorSites().join();
285  hash_set<NodeID> startKeys;
286  for (auto const& val : validators)
287  startKeys.insert(calcNodeID(val.masterPublic));
288 
289  env.app().validators().updateTrusted(startKeys);
290 
291  {
292  auto const jrr = env.rpc("server_info")[jss::result];
293  BEAST_EXPECT(
294  jrr[jss::info][jss::validator_list][jss::expiration] ==
296  }
297  {
298  auto const jrr = env.rpc("server_state")[jss::result];
299  BEAST_EXPECT(
300  jrr[jss::state][jss::validator_list_expires].asUInt() ==
301  expiration.time_since_epoch().count());
302  }
303  {
304  auto const jrr = env.rpc("validators")[jss::result];
305  BEAST_EXPECT(jrr[jss::validation_quorum].asUInt() == 2);
306  BEAST_EXPECT(
307  jrr[jss::validator_list][jss::expiration] ==
309  BEAST_EXPECT(jrr[jss::local_static_keys].size() == 0);
310 
311  BEAST_EXPECT(
312  jrr[jss::trusted_validator_keys].size() ==
313  expectedKeys.size());
314  for (auto const& jKey : jrr[jss::trusted_validator_keys])
315  {
316  BEAST_EXPECT(expectedKeys.count(jKey.asString()) == 1);
317  }
318 
319  if (BEAST_EXPECT(jrr[jss::publisher_lists].size() == 1))
320  {
321  auto jp = jrr[jss::publisher_lists][0u];
322  BEAST_EXPECT(jp[jss::available] == true);
323  if (BEAST_EXPECT(jp[jss::list].size() == 2))
324  {
325  // check entries
326  std::set<std::string> foundKeys;
327  for (auto const& k : jp[jss::list])
328  {
329  foundKeys.insert(k.asString());
330  }
331  BEAST_EXPECT(foundKeys == expectedKeys);
332  }
333  BEAST_EXPECT(jp[jss::seq].asUInt() == 1);
334  BEAST_EXPECT(
335  jp[jss::pubkey_publisher] ==
336  strHex(server->publisherPublic()));
337  BEAST_EXPECT(jp[jss::expiration] == to_string(expiration));
338  BEAST_EXPECT(jp[jss::version] == 1);
339  }
340  auto jsk = jrr[jss::signing_keys];
341  BEAST_EXPECT(jsk.size() == 2);
342  for (auto const& val : validators)
343  {
344  BEAST_EXPECT(jsk.isMember(toStr(val.masterPublic)));
345  BEAST_EXPECT(
346  jsk[toStr(val.masterPublic)] ==
347  toStr(val.signingPublic));
348  }
349  }
350  {
351  auto const jrr = env.rpc("validator_list_sites")[jss::result];
352  if (BEAST_EXPECT(jrr[jss::validator_sites].size() == 1))
353  {
354  auto js = jrr[jss::validator_sites][0u];
355  BEAST_EXPECT(js[jss::refresh_interval_min].asUInt() == 5);
356  BEAST_EXPECT(js[jss::uri] == siteURI);
357  BEAST_EXPECT(js[jss::last_refresh_status] == "accepted");
358  // The actual time of the update will vary run to run, so
359  // just verify the time is there
360  BEAST_EXPECT(js.isMember(jss::last_refresh_time));
361  }
362  }
363  }
364  }
365 
366  void
368  {
369  using namespace test::jtx;
370  Env env{*this};
371  auto result = env.rpc("validation_create");
372  BEAST_EXPECT(
373  result.isMember(jss::result) &&
374  result[jss::result][jss::status] == "success");
375  result = env.rpc(
376  "validation_create",
377  "BAWL MAN JADE MOON DOVE GEM SON NOW HAD ADEN GLOW TIRE");
378  BEAST_EXPECT(
379  result.isMember(jss::result) &&
380  result[jss::result][jss::status] == "success");
381  }
382 
383  void
384  run() override
385  {
386  testPrivileges();
387  testStaticUNL();
388  testDynamicUNL();
390  }
391 };
392 
393 BEAST_DEFINE_TESTSUITE(ValidatorRPC, app, ripple);
394 
395 } // namespace test
396 } // 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:173
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::unordered_set::find
T find(T... args)
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:42
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:384
std::unordered_set::clear
T clear(T... args)
ripple::KeyType::ed25519
@ ed25519
ripple::test::jtx::expiration
Set Expiration on a JTx.
Definition: Check_test.cpp:29
ripple::test::make_TrustedPublisherServer
std::shared_ptr< TrustedPublisherServer > make_TrustedPublisherServer(boost::asio::io_context &ioc, std::vector< TrustedPublisherServer::Validator > const &validators, NetClock::time_point expiration, bool useSSL=false, int version=1, bool immediateStart=true, int sequence=1)
Definition: TrustedPublisherServer.h:618
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:95
std::chrono::time_point
ripple::test::ValidatorRPC_test::testStaticUNL
void testStaticUNL()
Definition: ValidatorRPC_test.cpp:88
std::uint32_t
ripple::test::TrustedPublisherServer::randomValidator
static Validator randomValidator()
Definition: TrustedPublisherServer.h:131
ripple::randomKeyPair
std::pair< PublicKey, SecretKey > randomKeyPair(KeyType type)
Create a key pair using secure random numbers.
Definition: SecretKey.cpp:260
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::unordered_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:45
ripple::test::ValidatorRPC_test::test_validation_create
void test_validation_create()
Definition: ValidatorRPC_test.cpp:367
std::unordered_set::end
T end(T... args)
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:115
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:684