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 xrpl {
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(jrr[jss::info].isMember(jss::validator_list) == isAdmin);
55 }
56
57 {
58 Env env{*this, isAdmin ? envconfig() : envconfig(no_admin)};
59 auto const jrr = env.rpc("server_state")[jss::result];
60 BEAST_EXPECT(jrr[jss::status] == "success");
61 BEAST_EXPECT(jrr[jss::state].isMember(jss::validator_list_expires) == isAdmin);
62 }
63 }
64 }
65
66 void
68 {
69 using namespace test::jtx;
70
71 std::set<std::string> const keys = {
72 "n949f75evCHwgyP4fPVgaHqNHxUVN15PsJEZ3B3HnXPcPjcZAoy7",
73 "n9MD5h24qrQqiyBC8aeqqCWvpiBiYQ3jxSr91uiDvmrkyHRdYLUj"};
74 Env env{
75 *this,
77 for (auto const& key : keys)
78 cfg->section(SECTION_VALIDATORS).append(key);
79 return cfg;
80 }),
81 };
82
83 // Server info reports maximum expiration since not dynamic
84 {
85 auto const jrr = env.rpc("server_info")[jss::result];
86 BEAST_EXPECT(jrr[jss::info][jss::validator_list][jss::expiration] == "never");
87 }
88 {
89 auto const jrr = env.rpc("server_state")[jss::result];
90 BEAST_EXPECT(
91 jrr[jss::state][jss::validator_list_expires].asUInt() ==
92 NetClock::time_point::max().time_since_epoch().count());
93 }
94 // All our keys are in the response
95 {
96 auto const jrr = env.rpc("validators")[jss::result];
97 BEAST_EXPECT(jrr[jss::validator_list][jss::expiration] == "never");
98 BEAST_EXPECT(jrr[jss::validation_quorum].asUInt() == keys.size());
99 BEAST_EXPECT(jrr[jss::trusted_validator_keys].size() == keys.size());
100 BEAST_EXPECT(jrr[jss::publisher_lists].size() == 0);
101 BEAST_EXPECT(jrr[jss::local_static_keys].size() == keys.size());
102 for (auto const& jKey : jrr[jss::local_static_keys])
103 {
104 BEAST_EXPECT(keys.count(jKey.asString()) == 1);
105 }
106 BEAST_EXPECT(jrr[jss::signing_keys].size() == 0);
107 }
108 // No validator sites configured
109 {
110 auto const jrr = env.rpc("validator_list_sites")[jss::result];
111 BEAST_EXPECT(jrr[jss::validator_sites].size() == 0);
112 }
113 // Negative UNL empty
114 {
115 auto const jrr = env.rpc("validators")[jss::result];
116 BEAST_EXPECT(jrr[jss::NegativeUNL].isNull());
117 }
118 // Negative UNL update
119 {
120 hash_set<PublicKey> disabledKeys;
121 auto k1 = randomKeyPair(KeyType::ed25519).first;
122 auto k2 = randomKeyPair(KeyType::ed25519).first;
123 disabledKeys.insert(k1);
124 disabledKeys.insert(k2);
125 env.app().validators().setNegativeUNL(disabledKeys);
126
127 auto const jrr = env.rpc("validators")[jss::result];
128 auto& jrrnUnl = jrr[jss::NegativeUNL];
129 auto jrrnUnlSize = jrrnUnl.size();
130 BEAST_EXPECT(jrrnUnlSize == 2);
131 for (std::uint32_t x = 0; x < jrrnUnlSize; ++x)
132 {
133 auto parsedKey = parseBase58<PublicKey>(TokenType::NodePublic, jrrnUnl[x].asString());
134 BEAST_EXPECT(parsedKey);
135 if (parsedKey)
136 BEAST_EXPECT(disabledKeys.find(*parsedKey) != disabledKeys.end());
137 }
138
139 disabledKeys.clear();
140 env.app().validators().setNegativeUNL(disabledKeys);
141 auto const jrrUpdated = env.rpc("validators")[jss::result];
142 BEAST_EXPECT(jrrUpdated[jss::NegativeUNL].isNull());
143 }
144 }
145
146 void
148 {
149 using namespace test::jtx;
150
151 auto toStr = [](PublicKey const& publicKey) { return toBase58(TokenType::NodePublic, publicKey); };
152
153 // Validator keys that will be in the published list
154 std::vector<Validator> validators = {
156 std::set<std::string> expectedKeys;
157 for (auto const& val : validators)
158 expectedKeys.insert(toStr(val.masterPublic));
159
160 // Manage single-thread io_context for server.
161 BasicApp worker{1};
162 using namespace std::chrono_literals;
163 NetClock::time_point const validUntil{3600s};
164 NetClock::time_point const validFrom2{validUntil - 60s};
165 NetClock::time_point const validUntil2{validFrom2 + 3600s};
166 auto server = make_TrustedPublisherServer(
167 worker.get_io_context(), validators, validUntil, {{validFrom2, validUntil2}}, false, 1, false);
168
169 //----------------------------------------------------------------------
170 // Publisher list site unavailable v1
171 {
172 // Publisher site information
173 using namespace std::string_literals;
174 std::string siteURI = "http://"s + getEnvLocalhostAddr() + ":1234/validators";
175
176 Env env{
177 *this,
179 cfg->section(SECTION_VALIDATOR_LIST_SITES).append(siteURI);
180 cfg->section(SECTION_VALIDATOR_LIST_KEYS).append(strHex(server->publisherPublic()));
181 return cfg;
182 }),
183 };
184
185 env.app().validatorSites().start();
186 env.app().validatorSites().join();
187
188 {
189 auto const jrr = env.rpc("server_info")[jss::result];
190 BEAST_EXPECT(jrr[jss::info][jss::validator_list][jss::expiration] == "unknown");
191 }
192 {
193 auto const jrr = env.rpc("server_state")[jss::result];
194 BEAST_EXPECT(jrr[jss::state][jss::validator_list_expires].asInt() == 0);
195 }
196 {
197 auto const jrr = env.rpc("validators")[jss::result];
198 BEAST_EXPECT(jrr[jss::validation_quorum].asUInt() == std::numeric_limits<std::uint32_t>::max());
199 BEAST_EXPECT(jrr[jss::local_static_keys].size() == 0);
200 BEAST_EXPECT(jrr[jss::trusted_validator_keys].size() == 0);
201 BEAST_EXPECT(jrr[jss::validator_list][jss::expiration] == "unknown");
202
203 if (BEAST_EXPECT(jrr[jss::publisher_lists].size() == 1))
204 {
205 auto jp = jrr[jss::publisher_lists][0u];
206 BEAST_EXPECT(jp[jss::available] == false);
207 BEAST_EXPECT(jp[jss::list].size() == 0);
208 BEAST_EXPECT(!jp.isMember(jss::seq));
209 BEAST_EXPECT(!jp.isMember(jss::expiration));
210 BEAST_EXPECT(!jp.isMember(jss::version));
211 BEAST_EXPECT(jp[jss::pubkey_publisher] == strHex(server->publisherPublic()));
212 }
213 BEAST_EXPECT(jrr[jss::signing_keys].size() == 0);
214 }
215 {
216 auto const jrr = env.rpc("validator_list_sites")[jss::result];
217 if (BEAST_EXPECT(jrr[jss::validator_sites].size() == 1))
218 {
219 auto js = jrr[jss::validator_sites][0u];
220 BEAST_EXPECT(js[jss::refresh_interval_min].asUInt() == 5);
221 BEAST_EXPECT(js[jss::uri] == siteURI);
222 BEAST_EXPECT(js.isMember(jss::last_refresh_time));
223 BEAST_EXPECT(js[jss::last_refresh_status] == "invalid");
224 }
225 }
226 }
227 // Publisher list site unavailable v2
228 {
229 // Publisher site information
230 using namespace std::string_literals;
231 std::string siteURI = "http://"s + getEnvLocalhostAddr() + ":1234/validators2";
232
233 Env env{
234 *this,
236 cfg->section(SECTION_VALIDATOR_LIST_SITES).append(siteURI);
237 cfg->section(SECTION_VALIDATOR_LIST_KEYS).append(strHex(server->publisherPublic()));
238 return cfg;
239 }),
240 };
241
242 env.app().validatorSites().start();
243 env.app().validatorSites().join();
244
245 {
246 auto const jrr = env.rpc("server_info")[jss::result];
247 BEAST_EXPECT(jrr[jss::info][jss::validator_list][jss::expiration] == "unknown");
248 }
249 {
250 auto const jrr = env.rpc("server_state")[jss::result];
251 BEAST_EXPECT(jrr[jss::state][jss::validator_list_expires].asInt() == 0);
252 }
253 {
254 auto const jrr = env.rpc("validators")[jss::result];
255 BEAST_EXPECT(jrr[jss::validation_quorum].asUInt() == std::numeric_limits<std::uint32_t>::max());
256 BEAST_EXPECT(jrr[jss::local_static_keys].size() == 0);
257 BEAST_EXPECT(jrr[jss::trusted_validator_keys].size() == 0);
258 BEAST_EXPECT(jrr[jss::validator_list][jss::expiration] == "unknown");
259
260 if (BEAST_EXPECT(jrr[jss::publisher_lists].size() == 1))
261 {
262 auto jp = jrr[jss::publisher_lists][0u];
263 BEAST_EXPECT(jp[jss::available] == false);
264 BEAST_EXPECT(jp[jss::list].size() == 0);
265 BEAST_EXPECT(!jp.isMember(jss::seq));
266 BEAST_EXPECT(!jp.isMember(jss::expiration));
267 BEAST_EXPECT(!jp.isMember(jss::version));
268 BEAST_EXPECT(jp[jss::pubkey_publisher] == strHex(server->publisherPublic()));
269 }
270 BEAST_EXPECT(jrr[jss::signing_keys].size() == 0);
271 }
272 {
273 auto const jrr = env.rpc("validator_list_sites")[jss::result];
274 if (BEAST_EXPECT(jrr[jss::validator_sites].size() == 1))
275 {
276 auto js = jrr[jss::validator_sites][0u];
277 BEAST_EXPECT(js[jss::refresh_interval_min].asUInt() == 5);
278 BEAST_EXPECT(js[jss::uri] == siteURI);
279 BEAST_EXPECT(js.isMember(jss::last_refresh_time));
280 BEAST_EXPECT(js[jss::last_refresh_status] == "invalid");
281 }
282 }
283 }
284 //----------------------------------------------------------------------
285 // Publisher list site available
286 server->start();
287 // Publisher list site available v1
288 {
290 uri << "http://" << server->local_endpoint() << "/validators";
291 auto siteURI = uri.str();
292
293 Env env{
294 *this,
296 cfg->section(SECTION_VALIDATOR_LIST_SITES).append(siteURI);
297 cfg->section(SECTION_VALIDATOR_LIST_KEYS).append(strHex(server->publisherPublic()));
298 return cfg;
299 }),
300 };
301
302 env.app().validatorSites().start();
303 env.app().validatorSites().join();
304 hash_set<NodeID> startKeys;
305 for (auto const& val : validators)
306 startKeys.insert(calcNodeID(val.masterPublic));
307
308 env.app().validators().updateTrusted(
309 startKeys, env.timeKeeper().now(), env.app().getOPs(), env.app().overlay(), env.app().getHashRouter());
310
311 {
312 auto const jrr = env.rpc("server_info")[jss::result];
313 BEAST_EXPECT(jrr[jss::info][jss::validator_list][jss::expiration] == to_string(validUntil));
314 }
315 {
316 auto const jrr = env.rpc("server_state")[jss::result];
317 BEAST_EXPECT(
318 jrr[jss::state][jss::validator_list_expires].asUInt() == validUntil.time_since_epoch().count());
319 }
320 {
321 auto const jrr = env.rpc("validators")[jss::result];
322 BEAST_EXPECT(jrr[jss::validation_quorum].asUInt() == 2);
323 BEAST_EXPECT(jrr[jss::validator_list][jss::expiration] == to_string(validUntil));
324 BEAST_EXPECT(jrr[jss::local_static_keys].size() == 0);
325
326 BEAST_EXPECT(jrr[jss::trusted_validator_keys].size() == expectedKeys.size());
327 for (auto const& jKey : jrr[jss::trusted_validator_keys])
328 {
329 BEAST_EXPECT(expectedKeys.count(jKey.asString()) == 1);
330 }
331
332 if (BEAST_EXPECT(jrr[jss::publisher_lists].size() == 1))
333 {
334 auto jp = jrr[jss::publisher_lists][0u];
335 BEAST_EXPECT(jp[jss::available] == true);
336 if (BEAST_EXPECT(jp[jss::list].size() == 2))
337 {
338 // check entries
339 std::set<std::string> foundKeys;
340 for (auto const& k : jp[jss::list])
341 {
342 foundKeys.insert(k.asString());
343 }
344 BEAST_EXPECT(foundKeys == expectedKeys);
345 }
346 BEAST_EXPECT(jp[jss::seq].asUInt() == 1);
347 BEAST_EXPECT(jp[jss::pubkey_publisher] == strHex(server->publisherPublic()));
348 BEAST_EXPECT(jp[jss::expiration] == to_string(validUntil));
349 BEAST_EXPECT(jp[jss::version] == 1);
350 }
351 auto jsk = jrr[jss::signing_keys];
352 BEAST_EXPECT(jsk.size() == 2);
353 for (auto const& val : validators)
354 {
355 BEAST_EXPECT(jsk.isMember(toStr(val.masterPublic)));
356 BEAST_EXPECT(jsk[toStr(val.masterPublic)] == toStr(val.signingPublic));
357 }
358 }
359 {
360 auto const jrr = env.rpc("validator_list_sites")[jss::result];
361 if (BEAST_EXPECT(jrr[jss::validator_sites].size() == 1))
362 {
363 auto js = jrr[jss::validator_sites][0u];
364 BEAST_EXPECT(js[jss::refresh_interval_min].asUInt() == 5);
365 BEAST_EXPECT(js[jss::uri] == siteURI);
366 BEAST_EXPECT(js[jss::last_refresh_status] == "accepted");
367 // The actual time of the update will vary run to run, so
368 // just verify the time is there
369 BEAST_EXPECT(js.isMember(jss::last_refresh_time));
370 }
371 }
372 }
373 // Publisher list site available v2
374 {
376 uri << "http://" << server->local_endpoint() << "/validators2";
377 auto siteURI = uri.str();
378
379 Env env{
380 *this,
382 cfg->section(SECTION_VALIDATOR_LIST_SITES).append(siteURI);
383 cfg->section(SECTION_VALIDATOR_LIST_KEYS).append(strHex(server->publisherPublic()));
384 return cfg;
385 }),
386 };
387
388 env.app().validatorSites().start();
389 env.app().validatorSites().join();
390 hash_set<NodeID> startKeys;
391 for (auto const& val : validators)
392 startKeys.insert(calcNodeID(val.masterPublic));
393
394 env.app().validators().updateTrusted(
395 startKeys, env.timeKeeper().now(), env.app().getOPs(), env.app().overlay(), env.app().getHashRouter());
396
397 {
398 auto const jrr = env.rpc("server_info")[jss::result];
399 BEAST_EXPECT(jrr[jss::info][jss::validator_list][jss::expiration] == to_string(validUntil2));
400 }
401 {
402 auto const jrr = env.rpc("server_state")[jss::result];
403 BEAST_EXPECT(
404 jrr[jss::state][jss::validator_list_expires].asUInt() == validUntil2.time_since_epoch().count());
405 }
406 {
407 auto const jrr = env.rpc("validators")[jss::result];
408 BEAST_EXPECT(jrr[jss::validation_quorum].asUInt() == 2);
409 BEAST_EXPECT(jrr[jss::validator_list][jss::expiration] == to_string(validUntil2));
410 BEAST_EXPECT(jrr[jss::local_static_keys].size() == 0);
411
412 BEAST_EXPECT(jrr[jss::trusted_validator_keys].size() == expectedKeys.size());
413 for (auto const& jKey : jrr[jss::trusted_validator_keys])
414 {
415 BEAST_EXPECT(expectedKeys.count(jKey.asString()) == 1);
416 }
417
418 if (BEAST_EXPECT(jrr[jss::publisher_lists].size() == 1))
419 {
420 auto jp = jrr[jss::publisher_lists][0u];
421 BEAST_EXPECT(jp[jss::available] == true);
422 if (BEAST_EXPECT(jp[jss::list].size() == 2))
423 {
424 // check entries
425 std::set<std::string> foundKeys;
426 for (auto const& k : jp[jss::list])
427 {
428 foundKeys.insert(k.asString());
429 }
430 BEAST_EXPECT(foundKeys == expectedKeys);
431 }
432 BEAST_EXPECT(jp[jss::seq].asUInt() == 1);
433 BEAST_EXPECT(jp[jss::pubkey_publisher] == strHex(server->publisherPublic()));
434 BEAST_EXPECT(jp[jss::expiration] == to_string(validUntil));
435 BEAST_EXPECT(jp[jss::version] == 2);
436 if (BEAST_EXPECT(jp.isMember(jss::remaining)) && BEAST_EXPECT(jp[jss::remaining].isArray()) &&
437 BEAST_EXPECT(jp[jss::remaining].size() == 1))
438 {
439 auto const& r = jp[jss::remaining][0u];
440 if (BEAST_EXPECT(r[jss::list].size() == 2))
441 {
442 // check entries
443 std::set<std::string> foundKeys;
444 for (auto const& k : r[jss::list])
445 {
446 foundKeys.insert(k.asString());
447 }
448 BEAST_EXPECT(foundKeys == expectedKeys);
449 }
450 BEAST_EXPECT(r[jss::seq].asUInt() == 2);
451 BEAST_EXPECT(r[jss::effective] == to_string(validFrom2));
452 BEAST_EXPECT(r[jss::expiration] == to_string(validUntil2));
453 }
454 }
455 auto jsk = jrr[jss::signing_keys];
456 BEAST_EXPECT(jsk.size() == 2);
457 for (auto const& val : validators)
458 {
459 BEAST_EXPECT(jsk.isMember(toStr(val.masterPublic)));
460 BEAST_EXPECT(jsk[toStr(val.masterPublic)] == toStr(val.signingPublic));
461 }
462 }
463 {
464 auto const jrr = env.rpc("validator_list_sites")[jss::result];
465 if (BEAST_EXPECT(jrr[jss::validator_sites].size() == 1))
466 {
467 auto js = jrr[jss::validator_sites][0u];
468 BEAST_EXPECT(js[jss::refresh_interval_min].asUInt() == 5);
469 BEAST_EXPECT(js[jss::uri] == siteURI);
470 BEAST_EXPECT(js[jss::last_refresh_status] == "accepted");
471 // The actual time of the update will vary run to run, so
472 // just verify the time is there
473 BEAST_EXPECT(js.isMember(jss::last_refresh_time));
474 }
475 }
476 }
477 }
478
479 void
481 {
482 using namespace test::jtx;
483 Env env{*this};
484 auto result = env.rpc("validation_create");
485 BEAST_EXPECT(result.isMember(jss::result) && result[jss::result][jss::status] == "success");
486 result = env.rpc("validation_create", "BAWL MAN JADE MOON DOVE GEM SON NOW HAD ADEN GLOW TIRE");
487 BEAST_EXPECT(result.isMember(jss::result) && result[jss::result][jss::status] == "success");
488 }
489
490 void
491 run() override
492 {
493 testPrivileges();
494 testStaticUNL();
495 testDynamicUNL();
496 test_validation_create();
497 }
498};
499
500BEAST_DEFINE_TESTSUITE(ValidatorRPC, rpc, xrpl);
501
502} // namespace test
503} // namespace xrpl
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:98
Application & app()
Definition Env.h:230
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:749
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:320
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
Definition envconfig.h:35
std::unique_ptr< Config > no_admin(std::unique_ptr< Config >)
adjust config so no admin ports are enabled
Definition envconfig.cpp:57
char const * getEnvLocalhostAddr()
Definition envconfig.h:17
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)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:6
std::pair< PublicKey, SecretKey > randomKeyPair(KeyType type)
Create a key pair using secure random numbers.
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:598
std::string strHex(FwdIt begin, FwdIt end)
Definition strHex.h:11
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition AccountID.cpp:92
bool isAdmin(Port const &port, Json::Value const &params, beast::IP::Address const &remoteIp)
Definition Role.cpp:63
NodeID calcNodeID(PublicKey const &)
Calculate the 160-bit node ID from a node public key.
T size(T... args)
T str(T... args)