rippled
Loading...
Searching...
No Matches
ValidatorRPC_test.cpp
1#include <test/jtx.h>
2#include <test/jtx/TrustedPublisherServer.h>
3
4#include <xrpld/app/main/BasicApp.h>
5#include <xrpld/app/misc/ValidatorSite.h>
6#include <xrpld/core/ConfigSections.h>
7
8#include <xrpl/beast/unit_test.h>
9#include <xrpl/json/json_value.h>
10#include <xrpl/protocol/jss.h>
11
12#include <set>
13
14namespace ripple {
15
16namespace test {
17
19{
21
22public:
23 void
25 {
26 using namespace test::jtx;
27
28 for (bool const isAdmin : {true, false})
29 {
30 for (std::string cmd : {"validators", "validator_list_sites"})
31 {
32 Env env{*this, isAdmin ? envconfig() : envconfig(no_admin)};
33 env.set_retries(isAdmin ? 5 : 0);
34 auto const jrr = env.rpc(cmd)[jss::result];
35 if (isAdmin)
36 {
37 BEAST_EXPECT(!jrr.isMember(jss::error));
38 BEAST_EXPECT(jrr[jss::status] == "success");
39 }
40 else
41 {
42 // The current HTTP/S ServerHandler returns an HTTP 403
43 // error code here rather than a noPermission JSON error.
44 // The JSONRPCClient just eats that error and returns null
45 // result.
46 BEAST_EXPECT(jrr.isNull());
47 }
48 }
49
50 {
51 Env env{*this, isAdmin ? envconfig() : envconfig(no_admin)};
52 auto const jrr = env.rpc("server_info")[jss::result];
53 BEAST_EXPECT(jrr[jss::status] == "success");
54 BEAST_EXPECT(
55 jrr[jss::info].isMember(jss::validator_list) == isAdmin);
56 }
57
58 {
59 Env env{*this, isAdmin ? envconfig() : envconfig(no_admin)};
60 auto const jrr = env.rpc("server_state")[jss::result];
61 BEAST_EXPECT(jrr[jss::status] == "success");
62 BEAST_EXPECT(
63 jrr[jss::state].isMember(jss::validator_list_expires) ==
64 isAdmin);
65 }
66 }
67 }
68
69 void
71 {
72 using namespace test::jtx;
73
74 std::set<std::string> const keys = {
75 "n949f75evCHwgyP4fPVgaHqNHxUVN15PsJEZ3B3HnXPcPjcZAoy7",
76 "n9MD5h24qrQqiyBC8aeqqCWvpiBiYQ3jxSr91uiDvmrkyHRdYLUj"};
77 Env env{
78 *this,
80 for (auto const& key : keys)
81 cfg->section(SECTION_VALIDATORS).append(key);
82 return cfg;
83 }),
84 };
85
86 // Server info reports maximum expiration since not dynamic
87 {
88 auto const jrr = env.rpc("server_info")[jss::result];
89 BEAST_EXPECT(
90 jrr[jss::info][jss::validator_list][jss::expiration] ==
91 "never");
92 }
93 {
94 auto const jrr = env.rpc("server_state")[jss::result];
95 BEAST_EXPECT(
96 jrr[jss::state][jss::validator_list_expires].asUInt() ==
97 NetClock::time_point::max().time_since_epoch().count());
98 }
99 // All our keys are in the response
100 {
101 auto const jrr = env.rpc("validators")[jss::result];
102 BEAST_EXPECT(jrr[jss::validator_list][jss::expiration] == "never");
103 BEAST_EXPECT(jrr[jss::validation_quorum].asUInt() == keys.size());
104 BEAST_EXPECT(
105 jrr[jss::trusted_validator_keys].size() == keys.size());
106 BEAST_EXPECT(jrr[jss::publisher_lists].size() == 0);
107 BEAST_EXPECT(jrr[jss::local_static_keys].size() == keys.size());
108 for (auto const& jKey : jrr[jss::local_static_keys])
109 {
110 BEAST_EXPECT(keys.count(jKey.asString()) == 1);
111 }
112 BEAST_EXPECT(jrr[jss::signing_keys].size() == 0);
113 }
114 // No validator sites configured
115 {
116 auto const jrr = env.rpc("validator_list_sites")[jss::result];
117 BEAST_EXPECT(jrr[jss::validator_sites].size() == 0);
118 }
119 // Negative UNL empty
120 {
121 auto const jrr = env.rpc("validators")[jss::result];
122 BEAST_EXPECT(jrr[jss::NegativeUNL].isNull());
123 }
124 // Negative UNL update
125 {
126 hash_set<PublicKey> disabledKeys;
127 auto k1 = randomKeyPair(KeyType::ed25519).first;
128 auto k2 = randomKeyPair(KeyType::ed25519).first;
129 disabledKeys.insert(k1);
130 disabledKeys.insert(k2);
131 env.app().validators().setNegativeUNL(disabledKeys);
132
133 auto const jrr = env.rpc("validators")[jss::result];
134 auto& jrrnUnl = jrr[jss::NegativeUNL];
135 auto jrrnUnlSize = jrrnUnl.size();
136 BEAST_EXPECT(jrrnUnlSize == 2);
137 for (std::uint32_t x = 0; x < jrrnUnlSize; ++x)
138 {
139 auto parsedKey = parseBase58<PublicKey>(
140 TokenType::NodePublic, jrrnUnl[x].asString());
141 BEAST_EXPECT(parsedKey);
142 if (parsedKey)
143 BEAST_EXPECT(
144 disabledKeys.find(*parsedKey) != disabledKeys.end());
145 }
146
147 disabledKeys.clear();
148 env.app().validators().setNegativeUNL(disabledKeys);
149 auto const jrrUpdated = env.rpc("validators")[jss::result];
150 BEAST_EXPECT(jrrUpdated[jss::NegativeUNL].isNull());
151 }
152 }
153
154 void
156 {
157 using namespace test::jtx;
158
159 auto toStr = [](PublicKey const& publicKey) {
160 return toBase58(TokenType::NodePublic, publicKey);
161 };
162
163 // Validator keys that will be in the published list
164 std::vector<Validator> validators = {
167 std::set<std::string> expectedKeys;
168 for (auto const& val : validators)
169 expectedKeys.insert(toStr(val.masterPublic));
170
171 // Manage single-thread io_context for server.
172 BasicApp worker{1};
173 using namespace std::chrono_literals;
174 NetClock::time_point const validUntil{3600s};
175 NetClock::time_point const validFrom2{validUntil - 60s};
176 NetClock::time_point const validUntil2{validFrom2 + 3600s};
177 auto server = make_TrustedPublisherServer(
178 worker.get_io_context(),
179 validators,
180 validUntil,
181 {{validFrom2, validUntil2}},
182 false,
183 1,
184 false);
185
186 //----------------------------------------------------------------------
187 // Publisher list site unavailable v1
188 {
189 // Publisher site information
190 using namespace std::string_literals;
191 std::string siteURI =
192 "http://"s + getEnvLocalhostAddr() + ":1234/validators";
193
194 Env env{
195 *this,
197 cfg->section(SECTION_VALIDATOR_LIST_SITES).append(siteURI);
198 cfg->section(SECTION_VALIDATOR_LIST_KEYS)
199 .append(strHex(server->publisherPublic()));
200 return cfg;
201 }),
202 };
203
204 env.app().validatorSites().start();
205 env.app().validatorSites().join();
206
207 {
208 auto const jrr = env.rpc("server_info")[jss::result];
209 BEAST_EXPECT(
210 jrr[jss::info][jss::validator_list][jss::expiration] ==
211 "unknown");
212 }
213 {
214 auto const jrr = env.rpc("server_state")[jss::result];
215 BEAST_EXPECT(
216 jrr[jss::state][jss::validator_list_expires].asInt() == 0);
217 }
218 {
219 auto const jrr = env.rpc("validators")[jss::result];
220 BEAST_EXPECT(
221 jrr[jss::validation_quorum].asUInt() ==
223 BEAST_EXPECT(jrr[jss::local_static_keys].size() == 0);
224 BEAST_EXPECT(jrr[jss::trusted_validator_keys].size() == 0);
225 BEAST_EXPECT(
226 jrr[jss::validator_list][jss::expiration] == "unknown");
227
228 if (BEAST_EXPECT(jrr[jss::publisher_lists].size() == 1))
229 {
230 auto jp = jrr[jss::publisher_lists][0u];
231 BEAST_EXPECT(jp[jss::available] == false);
232 BEAST_EXPECT(jp[jss::list].size() == 0);
233 BEAST_EXPECT(!jp.isMember(jss::seq));
234 BEAST_EXPECT(!jp.isMember(jss::expiration));
235 BEAST_EXPECT(!jp.isMember(jss::version));
236 BEAST_EXPECT(
237 jp[jss::pubkey_publisher] ==
238 strHex(server->publisherPublic()));
239 }
240 BEAST_EXPECT(jrr[jss::signing_keys].size() == 0);
241 }
242 {
243 auto const jrr = env.rpc("validator_list_sites")[jss::result];
244 if (BEAST_EXPECT(jrr[jss::validator_sites].size() == 1))
245 {
246 auto js = jrr[jss::validator_sites][0u];
247 BEAST_EXPECT(js[jss::refresh_interval_min].asUInt() == 5);
248 BEAST_EXPECT(js[jss::uri] == siteURI);
249 BEAST_EXPECT(js.isMember(jss::last_refresh_time));
250 BEAST_EXPECT(js[jss::last_refresh_status] == "invalid");
251 }
252 }
253 }
254 // Publisher list site unavailable v2
255 {
256 // Publisher site information
257 using namespace std::string_literals;
258 std::string siteURI =
259 "http://"s + getEnvLocalhostAddr() + ":1234/validators2";
260
261 Env env{
262 *this,
264 cfg->section(SECTION_VALIDATOR_LIST_SITES).append(siteURI);
265 cfg->section(SECTION_VALIDATOR_LIST_KEYS)
266 .append(strHex(server->publisherPublic()));
267 return cfg;
268 }),
269 };
270
271 env.app().validatorSites().start();
272 env.app().validatorSites().join();
273
274 {
275 auto const jrr = env.rpc("server_info")[jss::result];
276 BEAST_EXPECT(
277 jrr[jss::info][jss::validator_list][jss::expiration] ==
278 "unknown");
279 }
280 {
281 auto const jrr = env.rpc("server_state")[jss::result];
282 BEAST_EXPECT(
283 jrr[jss::state][jss::validator_list_expires].asInt() == 0);
284 }
285 {
286 auto const jrr = env.rpc("validators")[jss::result];
287 BEAST_EXPECT(
288 jrr[jss::validation_quorum].asUInt() ==
290 BEAST_EXPECT(jrr[jss::local_static_keys].size() == 0);
291 BEAST_EXPECT(jrr[jss::trusted_validator_keys].size() == 0);
292 BEAST_EXPECT(
293 jrr[jss::validator_list][jss::expiration] == "unknown");
294
295 if (BEAST_EXPECT(jrr[jss::publisher_lists].size() == 1))
296 {
297 auto jp = jrr[jss::publisher_lists][0u];
298 BEAST_EXPECT(jp[jss::available] == false);
299 BEAST_EXPECT(jp[jss::list].size() == 0);
300 BEAST_EXPECT(!jp.isMember(jss::seq));
301 BEAST_EXPECT(!jp.isMember(jss::expiration));
302 BEAST_EXPECT(!jp.isMember(jss::version));
303 BEAST_EXPECT(
304 jp[jss::pubkey_publisher] ==
305 strHex(server->publisherPublic()));
306 }
307 BEAST_EXPECT(jrr[jss::signing_keys].size() == 0);
308 }
309 {
310 auto const jrr = env.rpc("validator_list_sites")[jss::result];
311 if (BEAST_EXPECT(jrr[jss::validator_sites].size() == 1))
312 {
313 auto js = jrr[jss::validator_sites][0u];
314 BEAST_EXPECT(js[jss::refresh_interval_min].asUInt() == 5);
315 BEAST_EXPECT(js[jss::uri] == siteURI);
316 BEAST_EXPECT(js.isMember(jss::last_refresh_time));
317 BEAST_EXPECT(js[jss::last_refresh_status] == "invalid");
318 }
319 }
320 }
321 //----------------------------------------------------------------------
322 // Publisher list site available
323 server->start();
324 // Publisher list site available v1
325 {
327 uri << "http://" << server->local_endpoint() << "/validators";
328 auto siteURI = uri.str();
329
330 Env env{
331 *this,
333 cfg->section(SECTION_VALIDATOR_LIST_SITES).append(siteURI);
334 cfg->section(SECTION_VALIDATOR_LIST_KEYS)
335 .append(strHex(server->publisherPublic()));
336 return cfg;
337 }),
338 };
339
340 env.app().validatorSites().start();
341 env.app().validatorSites().join();
342 hash_set<NodeID> startKeys;
343 for (auto const& val : validators)
344 startKeys.insert(calcNodeID(val.masterPublic));
345
346 env.app().validators().updateTrusted(
347 startKeys,
348 env.timeKeeper().now(),
349 env.app().getOPs(),
350 env.app().overlay(),
351 env.app().getHashRouter());
352
353 {
354 auto const jrr = env.rpc("server_info")[jss::result];
355 BEAST_EXPECT(
356 jrr[jss::info][jss::validator_list][jss::expiration] ==
357 to_string(validUntil));
358 }
359 {
360 auto const jrr = env.rpc("server_state")[jss::result];
361 BEAST_EXPECT(
362 jrr[jss::state][jss::validator_list_expires].asUInt() ==
363 validUntil.time_since_epoch().count());
364 }
365 {
366 auto const jrr = env.rpc("validators")[jss::result];
367 BEAST_EXPECT(jrr[jss::validation_quorum].asUInt() == 2);
368 BEAST_EXPECT(
369 jrr[jss::validator_list][jss::expiration] ==
370 to_string(validUntil));
371 BEAST_EXPECT(jrr[jss::local_static_keys].size() == 0);
372
373 BEAST_EXPECT(
374 jrr[jss::trusted_validator_keys].size() ==
375 expectedKeys.size());
376 for (auto const& jKey : jrr[jss::trusted_validator_keys])
377 {
378 BEAST_EXPECT(expectedKeys.count(jKey.asString()) == 1);
379 }
380
381 if (BEAST_EXPECT(jrr[jss::publisher_lists].size() == 1))
382 {
383 auto jp = jrr[jss::publisher_lists][0u];
384 BEAST_EXPECT(jp[jss::available] == true);
385 if (BEAST_EXPECT(jp[jss::list].size() == 2))
386 {
387 // check entries
388 std::set<std::string> foundKeys;
389 for (auto const& k : jp[jss::list])
390 {
391 foundKeys.insert(k.asString());
392 }
393 BEAST_EXPECT(foundKeys == expectedKeys);
394 }
395 BEAST_EXPECT(jp[jss::seq].asUInt() == 1);
396 BEAST_EXPECT(
397 jp[jss::pubkey_publisher] ==
398 strHex(server->publisherPublic()));
399 BEAST_EXPECT(jp[jss::expiration] == to_string(validUntil));
400 BEAST_EXPECT(jp[jss::version] == 1);
401 }
402 auto jsk = jrr[jss::signing_keys];
403 BEAST_EXPECT(jsk.size() == 2);
404 for (auto const& val : validators)
405 {
406 BEAST_EXPECT(jsk.isMember(toStr(val.masterPublic)));
407 BEAST_EXPECT(
408 jsk[toStr(val.masterPublic)] ==
409 toStr(val.signingPublic));
410 }
411 }
412 {
413 auto const jrr = env.rpc("validator_list_sites")[jss::result];
414 if (BEAST_EXPECT(jrr[jss::validator_sites].size() == 1))
415 {
416 auto js = jrr[jss::validator_sites][0u];
417 BEAST_EXPECT(js[jss::refresh_interval_min].asUInt() == 5);
418 BEAST_EXPECT(js[jss::uri] == siteURI);
419 BEAST_EXPECT(js[jss::last_refresh_status] == "accepted");
420 // The actual time of the update will vary run to run, so
421 // just verify the time is there
422 BEAST_EXPECT(js.isMember(jss::last_refresh_time));
423 }
424 }
425 }
426 // Publisher list site available v2
427 {
429 uri << "http://" << server->local_endpoint() << "/validators2";
430 auto siteURI = uri.str();
431
432 Env env{
433 *this,
435 cfg->section(SECTION_VALIDATOR_LIST_SITES).append(siteURI);
436 cfg->section(SECTION_VALIDATOR_LIST_KEYS)
437 .append(strHex(server->publisherPublic()));
438 return cfg;
439 }),
440 };
441
442 env.app().validatorSites().start();
443 env.app().validatorSites().join();
444 hash_set<NodeID> startKeys;
445 for (auto const& val : validators)
446 startKeys.insert(calcNodeID(val.masterPublic));
447
448 env.app().validators().updateTrusted(
449 startKeys,
450 env.timeKeeper().now(),
451 env.app().getOPs(),
452 env.app().overlay(),
453 env.app().getHashRouter());
454
455 {
456 auto const jrr = env.rpc("server_info")[jss::result];
457 BEAST_EXPECT(
458 jrr[jss::info][jss::validator_list][jss::expiration] ==
459 to_string(validUntil2));
460 }
461 {
462 auto const jrr = env.rpc("server_state")[jss::result];
463 BEAST_EXPECT(
464 jrr[jss::state][jss::validator_list_expires].asUInt() ==
465 validUntil2.time_since_epoch().count());
466 }
467 {
468 auto const jrr = env.rpc("validators")[jss::result];
469 BEAST_EXPECT(jrr[jss::validation_quorum].asUInt() == 2);
470 BEAST_EXPECT(
471 jrr[jss::validator_list][jss::expiration] ==
472 to_string(validUntil2));
473 BEAST_EXPECT(jrr[jss::local_static_keys].size() == 0);
474
475 BEAST_EXPECT(
476 jrr[jss::trusted_validator_keys].size() ==
477 expectedKeys.size());
478 for (auto const& jKey : jrr[jss::trusted_validator_keys])
479 {
480 BEAST_EXPECT(expectedKeys.count(jKey.asString()) == 1);
481 }
482
483 if (BEAST_EXPECT(jrr[jss::publisher_lists].size() == 1))
484 {
485 auto jp = jrr[jss::publisher_lists][0u];
486 BEAST_EXPECT(jp[jss::available] == true);
487 if (BEAST_EXPECT(jp[jss::list].size() == 2))
488 {
489 // check entries
490 std::set<std::string> foundKeys;
491 for (auto const& k : jp[jss::list])
492 {
493 foundKeys.insert(k.asString());
494 }
495 BEAST_EXPECT(foundKeys == expectedKeys);
496 }
497 BEAST_EXPECT(jp[jss::seq].asUInt() == 1);
498 BEAST_EXPECT(
499 jp[jss::pubkey_publisher] ==
500 strHex(server->publisherPublic()));
501 BEAST_EXPECT(jp[jss::expiration] == to_string(validUntil));
502 BEAST_EXPECT(jp[jss::version] == 2);
503 if (BEAST_EXPECT(jp.isMember(jss::remaining)) &&
504 BEAST_EXPECT(jp[jss::remaining].isArray()) &&
505 BEAST_EXPECT(jp[jss::remaining].size() == 1))
506 {
507 auto const& r = jp[jss::remaining][0u];
508 if (BEAST_EXPECT(r[jss::list].size() == 2))
509 {
510 // check entries
511 std::set<std::string> foundKeys;
512 for (auto const& k : r[jss::list])
513 {
514 foundKeys.insert(k.asString());
515 }
516 BEAST_EXPECT(foundKeys == expectedKeys);
517 }
518 BEAST_EXPECT(r[jss::seq].asUInt() == 2);
519 BEAST_EXPECT(
520 r[jss::effective] == to_string(validFrom2));
521 BEAST_EXPECT(
522 r[jss::expiration] == to_string(validUntil2));
523 }
524 }
525 auto jsk = jrr[jss::signing_keys];
526 BEAST_EXPECT(jsk.size() == 2);
527 for (auto const& val : validators)
528 {
529 BEAST_EXPECT(jsk.isMember(toStr(val.masterPublic)));
530 BEAST_EXPECT(
531 jsk[toStr(val.masterPublic)] ==
532 toStr(val.signingPublic));
533 }
534 }
535 {
536 auto const jrr = env.rpc("validator_list_sites")[jss::result];
537 if (BEAST_EXPECT(jrr[jss::validator_sites].size() == 1))
538 {
539 auto js = jrr[jss::validator_sites][0u];
540 BEAST_EXPECT(js[jss::refresh_interval_min].asUInt() == 5);
541 BEAST_EXPECT(js[jss::uri] == siteURI);
542 BEAST_EXPECT(js[jss::last_refresh_status] == "accepted");
543 // The actual time of the update will vary run to run, so
544 // just verify the time is there
545 BEAST_EXPECT(js.isMember(jss::last_refresh_time));
546 }
547 }
548 }
549 }
550
551 void
553 {
554 using namespace test::jtx;
555 Env env{*this};
556 auto result = env.rpc("validation_create");
557 BEAST_EXPECT(
558 result.isMember(jss::result) &&
559 result[jss::result][jss::status] == "success");
560 result = env.rpc(
561 "validation_create",
562 "BAWL MAN JADE MOON DOVE GEM SON NOW HAD ADEN GLOW TIRE");
563 BEAST_EXPECT(
564 result.isMember(jss::result) &&
565 result[jss::result][jss::status] == "success");
566 }
567
568 void
569 run() override
570 {
571 testPrivileges();
572 testStaticUNL();
573 testDynamicUNL();
574 test_validation_create();
575 }
576};
577
578BEAST_DEFINE_TESTSUITE(ValidatorRPC, rpc, ripple);
579
580} // namespace test
581} // namespace ripple
A testsuite class.
Definition suite.h:52
virtual ValidatorSite & validatorSites()=0
A public key.
Definition PublicKey.h:43
void start()
Start fetching lists from sites.
void run() override
Runs the suite.
A transaction testing environment.
Definition Env.h:102
Application & app()
Definition Env.h:242
Json::Value rpc(unsigned apiVersion, std::unordered_map< std::string, std::string > const &headers, std::string const &cmd, Args &&... args)
Execute an RPC command.
Definition Env.h:772
Set the expected result code for a JTx The test will fail if the code doesn't match.
Definition rpc.h:16
T clear(T... args)
T count(T... args)
T end(T... args)
T find(T... args)
T insert(T... args)
std::uint32_t asUInt(AnyValue const &v)
Definition Oracle.cpp:334
std::unique_ptr< Config > no_admin(std::unique_ptr< Config >)
adjust config so no admin ports are enabled
Definition envconfig.cpp:57
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
Definition envconfig.h:35
std::shared_ptr< TrustedPublisherServer > make_TrustedPublisherServer(boost::asio::io_context &ioc, std::vector< TrustedPublisherServer::Validator > const &validators, NetClock::time_point validUntil, std::vector< std::pair< NetClock::time_point, NetClock::time_point > > const &futures, bool useSSL=false, int version=1, bool immediateStart=true, int sequence=1)
char const * getEnvLocalhostAddr()
Definition envconfig.h:17
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:6
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition AccountID.cpp:95
bool isAdmin(Port const &port, Json::Value const &params, beast::IP::Address const &remoteIp)
Definition Role.cpp:66
std::string strHex(FwdIt begin, FwdIt end)
Definition strHex.h:11
NodeID calcNodeID(PublicKey const &)
Calculate the 160-bit node ID from a node public key.
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:611
std::pair< PublicKey, SecretKey > randomKeyPair(KeyType type)
Create a key pair using secure random numbers.
T size(T... args)
T str(T... args)