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