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/basics/base64.h>
26#include <xrpl/beast/unit_test.h>
27#include <xrpl/json/json_value.h>
28#include <xrpl/protocol/Sign.h>
29#include <xrpl/protocol/jss.h>
30
31#include <set>
32
33namespace ripple {
34
35namespace test {
36
38{
40
41public:
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,
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 validUntil{3600s};
193 NetClock::time_point const validFrom2{validUntil - 60s};
194 NetClock::time_point const validUntil2{validFrom2 + 3600s};
195 auto server = make_TrustedPublisherServer(
196 worker.get_io_service(),
197 validators,
198 validUntil,
199 {{validFrom2, validUntil2}},
200 false,
201 1,
202 false);
203
204 //----------------------------------------------------------------------
205 // Publisher list site unavailable v1
206 {
207 // Publisher site information
208 using namespace std::string_literals;
209 std::string siteURI =
210 "http://"s + getEnvLocalhostAddr() + ":1234/validators";
211
212 Env env{
213 *this,
215 cfg->section(SECTION_VALIDATOR_LIST_SITES).append(siteURI);
216 cfg->section(SECTION_VALIDATOR_LIST_KEYS)
217 .append(strHex(server->publisherPublic()));
218 return cfg;
219 }),
220 };
221
222 env.app().validatorSites().start();
223 env.app().validatorSites().join();
224
225 {
226 auto const jrr = env.rpc("server_info")[jss::result];
227 BEAST_EXPECT(
228 jrr[jss::info][jss::validator_list][jss::expiration] ==
229 "unknown");
230 }
231 {
232 auto const jrr = env.rpc("server_state")[jss::result];
233 BEAST_EXPECT(
234 jrr[jss::state][jss::validator_list_expires].asInt() == 0);
235 }
236 {
237 auto const jrr = env.rpc("validators")[jss::result];
238 BEAST_EXPECT(
239 jrr[jss::validation_quorum].asUInt() ==
241 BEAST_EXPECT(jrr[jss::local_static_keys].size() == 0);
242 BEAST_EXPECT(jrr[jss::trusted_validator_keys].size() == 0);
243 BEAST_EXPECT(
244 jrr[jss::validator_list][jss::expiration] == "unknown");
245
246 if (BEAST_EXPECT(jrr[jss::publisher_lists].size() == 1))
247 {
248 auto jp = jrr[jss::publisher_lists][0u];
249 BEAST_EXPECT(jp[jss::available] == false);
250 BEAST_EXPECT(jp[jss::list].size() == 0);
251 BEAST_EXPECT(!jp.isMember(jss::seq));
252 BEAST_EXPECT(!jp.isMember(jss::expiration));
253 BEAST_EXPECT(!jp.isMember(jss::version));
254 BEAST_EXPECT(
255 jp[jss::pubkey_publisher] ==
256 strHex(server->publisherPublic()));
257 }
258 BEAST_EXPECT(jrr[jss::signing_keys].size() == 0);
259 }
260 {
261 auto const jrr = env.rpc("validator_list_sites")[jss::result];
262 if (BEAST_EXPECT(jrr[jss::validator_sites].size() == 1))
263 {
264 auto js = jrr[jss::validator_sites][0u];
265 BEAST_EXPECT(js[jss::refresh_interval_min].asUInt() == 5);
266 BEAST_EXPECT(js[jss::uri] == siteURI);
267 BEAST_EXPECT(js.isMember(jss::last_refresh_time));
268 BEAST_EXPECT(js[jss::last_refresh_status] == "invalid");
269 }
270 }
271 }
272 // Publisher list site unavailable v2
273 {
274 // Publisher site information
275 using namespace std::string_literals;
276 std::string siteURI =
277 "http://"s + getEnvLocalhostAddr() + ":1234/validators2";
278
279 Env env{
280 *this,
282 cfg->section(SECTION_VALIDATOR_LIST_SITES).append(siteURI);
283 cfg->section(SECTION_VALIDATOR_LIST_KEYS)
284 .append(strHex(server->publisherPublic()));
285 return cfg;
286 }),
287 };
288
289 env.app().validatorSites().start();
290 env.app().validatorSites().join();
291
292 {
293 auto const jrr = env.rpc("server_info")[jss::result];
294 BEAST_EXPECT(
295 jrr[jss::info][jss::validator_list][jss::expiration] ==
296 "unknown");
297 }
298 {
299 auto const jrr = env.rpc("server_state")[jss::result];
300 BEAST_EXPECT(
301 jrr[jss::state][jss::validator_list_expires].asInt() == 0);
302 }
303 {
304 auto const jrr = env.rpc("validators")[jss::result];
305 BEAST_EXPECT(
306 jrr[jss::validation_quorum].asUInt() ==
308 BEAST_EXPECT(jrr[jss::local_static_keys].size() == 0);
309 BEAST_EXPECT(jrr[jss::trusted_validator_keys].size() == 0);
310 BEAST_EXPECT(
311 jrr[jss::validator_list][jss::expiration] == "unknown");
312
313 if (BEAST_EXPECT(jrr[jss::publisher_lists].size() == 1))
314 {
315 auto jp = jrr[jss::publisher_lists][0u];
316 BEAST_EXPECT(jp[jss::available] == false);
317 BEAST_EXPECT(jp[jss::list].size() == 0);
318 BEAST_EXPECT(!jp.isMember(jss::seq));
319 BEAST_EXPECT(!jp.isMember(jss::expiration));
320 BEAST_EXPECT(!jp.isMember(jss::version));
321 BEAST_EXPECT(
322 jp[jss::pubkey_publisher] ==
323 strHex(server->publisherPublic()));
324 }
325 BEAST_EXPECT(jrr[jss::signing_keys].size() == 0);
326 }
327 {
328 auto const jrr = env.rpc("validator_list_sites")[jss::result];
329 if (BEAST_EXPECT(jrr[jss::validator_sites].size() == 1))
330 {
331 auto js = jrr[jss::validator_sites][0u];
332 BEAST_EXPECT(js[jss::refresh_interval_min].asUInt() == 5);
333 BEAST_EXPECT(js[jss::uri] == siteURI);
334 BEAST_EXPECT(js.isMember(jss::last_refresh_time));
335 BEAST_EXPECT(js[jss::last_refresh_status] == "invalid");
336 }
337 }
338 }
339 //----------------------------------------------------------------------
340 // Publisher list site available
341 server->start();
342 // Publisher list site available v1
343 {
345 uri << "http://" << server->local_endpoint() << "/validators";
346 auto siteURI = uri.str();
347
348 Env env{
349 *this,
351 cfg->section(SECTION_VALIDATOR_LIST_SITES).append(siteURI);
352 cfg->section(SECTION_VALIDATOR_LIST_KEYS)
353 .append(strHex(server->publisherPublic()));
354 return cfg;
355 }),
356 };
357
358 env.app().validatorSites().start();
359 env.app().validatorSites().join();
360 hash_set<NodeID> startKeys;
361 for (auto const& val : validators)
362 startKeys.insert(calcNodeID(val.masterPublic));
363
364 env.app().validators().updateTrusted(
365 startKeys,
366 env.timeKeeper().now(),
367 env.app().getOPs(),
368 env.app().overlay(),
369 env.app().getHashRouter());
370
371 {
372 auto const jrr = env.rpc("server_info")[jss::result];
373 BEAST_EXPECT(
374 jrr[jss::info][jss::validator_list][jss::expiration] ==
375 to_string(validUntil));
376 }
377 {
378 auto const jrr = env.rpc("server_state")[jss::result];
379 BEAST_EXPECT(
380 jrr[jss::state][jss::validator_list_expires].asUInt() ==
381 validUntil.time_since_epoch().count());
382 }
383 {
384 auto const jrr = env.rpc("validators")[jss::result];
385 BEAST_EXPECT(jrr[jss::validation_quorum].asUInt() == 2);
386 BEAST_EXPECT(
387 jrr[jss::validator_list][jss::expiration] ==
388 to_string(validUntil));
389 BEAST_EXPECT(jrr[jss::local_static_keys].size() == 0);
390
391 BEAST_EXPECT(
392 jrr[jss::trusted_validator_keys].size() ==
393 expectedKeys.size());
394 for (auto const& jKey : jrr[jss::trusted_validator_keys])
395 {
396 BEAST_EXPECT(expectedKeys.count(jKey.asString()) == 1);
397 }
398
399 if (BEAST_EXPECT(jrr[jss::publisher_lists].size() == 1))
400 {
401 auto jp = jrr[jss::publisher_lists][0u];
402 BEAST_EXPECT(jp[jss::available] == true);
403 if (BEAST_EXPECT(jp[jss::list].size() == 2))
404 {
405 // check entries
406 std::set<std::string> foundKeys;
407 for (auto const& k : jp[jss::list])
408 {
409 foundKeys.insert(k.asString());
410 }
411 BEAST_EXPECT(foundKeys == expectedKeys);
412 }
413 BEAST_EXPECT(jp[jss::seq].asUInt() == 1);
414 BEAST_EXPECT(
415 jp[jss::pubkey_publisher] ==
416 strHex(server->publisherPublic()));
417 BEAST_EXPECT(jp[jss::expiration] == to_string(validUntil));
418 BEAST_EXPECT(jp[jss::version] == 1);
419 }
420 auto jsk = jrr[jss::signing_keys];
421 BEAST_EXPECT(jsk.size() == 2);
422 for (auto const& val : validators)
423 {
424 BEAST_EXPECT(jsk.isMember(toStr(val.masterPublic)));
425 BEAST_EXPECT(
426 jsk[toStr(val.masterPublic)] ==
427 toStr(val.signingPublic));
428 }
429 }
430 {
431 auto const jrr = env.rpc("validator_list_sites")[jss::result];
432 if (BEAST_EXPECT(jrr[jss::validator_sites].size() == 1))
433 {
434 auto js = jrr[jss::validator_sites][0u];
435 BEAST_EXPECT(js[jss::refresh_interval_min].asUInt() == 5);
436 BEAST_EXPECT(js[jss::uri] == siteURI);
437 BEAST_EXPECT(js[jss::last_refresh_status] == "accepted");
438 // The actual time of the update will vary run to run, so
439 // just verify the time is there
440 BEAST_EXPECT(js.isMember(jss::last_refresh_time));
441 }
442 }
443 }
444 // Publisher list site available v2
445 {
447 uri << "http://" << server->local_endpoint() << "/validators2";
448 auto siteURI = uri.str();
449
450 Env env{
451 *this,
453 cfg->section(SECTION_VALIDATOR_LIST_SITES).append(siteURI);
454 cfg->section(SECTION_VALIDATOR_LIST_KEYS)
455 .append(strHex(server->publisherPublic()));
456 return cfg;
457 }),
458 };
459
460 env.app().validatorSites().start();
461 env.app().validatorSites().join();
462 hash_set<NodeID> startKeys;
463 for (auto const& val : validators)
464 startKeys.insert(calcNodeID(val.masterPublic));
465
466 env.app().validators().updateTrusted(
467 startKeys,
468 env.timeKeeper().now(),
469 env.app().getOPs(),
470 env.app().overlay(),
471 env.app().getHashRouter());
472
473 {
474 auto const jrr = env.rpc("server_info")[jss::result];
475 BEAST_EXPECT(
476 jrr[jss::info][jss::validator_list][jss::expiration] ==
477 to_string(validUntil2));
478 }
479 {
480 auto const jrr = env.rpc("server_state")[jss::result];
481 BEAST_EXPECT(
482 jrr[jss::state][jss::validator_list_expires].asUInt() ==
483 validUntil2.time_since_epoch().count());
484 }
485 {
486 auto const jrr = env.rpc("validators")[jss::result];
487 BEAST_EXPECT(jrr[jss::validation_quorum].asUInt() == 2);
488 BEAST_EXPECT(
489 jrr[jss::validator_list][jss::expiration] ==
490 to_string(validUntil2));
491 BEAST_EXPECT(jrr[jss::local_static_keys].size() == 0);
492
493 BEAST_EXPECT(
494 jrr[jss::trusted_validator_keys].size() ==
495 expectedKeys.size());
496 for (auto const& jKey : jrr[jss::trusted_validator_keys])
497 {
498 BEAST_EXPECT(expectedKeys.count(jKey.asString()) == 1);
499 }
500
501 if (BEAST_EXPECT(jrr[jss::publisher_lists].size() == 1))
502 {
503 auto jp = jrr[jss::publisher_lists][0u];
504 BEAST_EXPECT(jp[jss::available] == true);
505 if (BEAST_EXPECT(jp[jss::list].size() == 2))
506 {
507 // check entries
508 std::set<std::string> foundKeys;
509 for (auto const& k : jp[jss::list])
510 {
511 foundKeys.insert(k.asString());
512 }
513 BEAST_EXPECT(foundKeys == expectedKeys);
514 }
515 BEAST_EXPECT(jp[jss::seq].asUInt() == 1);
516 BEAST_EXPECT(
517 jp[jss::pubkey_publisher] ==
518 strHex(server->publisherPublic()));
519 BEAST_EXPECT(jp[jss::expiration] == to_string(validUntil));
520 BEAST_EXPECT(jp[jss::version] == 2);
521 if (BEAST_EXPECT(jp.isMember(jss::remaining)) &&
522 BEAST_EXPECT(jp[jss::remaining].isArray()) &&
523 BEAST_EXPECT(jp[jss::remaining].size() == 1))
524 {
525 auto const& r = jp[jss::remaining][0u];
526 if (BEAST_EXPECT(r[jss::list].size() == 2))
527 {
528 // check entries
529 std::set<std::string> foundKeys;
530 for (auto const& k : r[jss::list])
531 {
532 foundKeys.insert(k.asString());
533 }
534 BEAST_EXPECT(foundKeys == expectedKeys);
535 }
536 BEAST_EXPECT(r[jss::seq].asUInt() == 2);
537 BEAST_EXPECT(
538 r[jss::effective] == to_string(validFrom2));
539 BEAST_EXPECT(
540 r[jss::expiration] == to_string(validUntil2));
541 }
542 }
543 auto jsk = jrr[jss::signing_keys];
544 BEAST_EXPECT(jsk.size() == 2);
545 for (auto const& val : validators)
546 {
547 BEAST_EXPECT(jsk.isMember(toStr(val.masterPublic)));
548 BEAST_EXPECT(
549 jsk[toStr(val.masterPublic)] ==
550 toStr(val.signingPublic));
551 }
552 }
553 {
554 auto const jrr = env.rpc("validator_list_sites")[jss::result];
555 if (BEAST_EXPECT(jrr[jss::validator_sites].size() == 1))
556 {
557 auto js = jrr[jss::validator_sites][0u];
558 BEAST_EXPECT(js[jss::refresh_interval_min].asUInt() == 5);
559 BEAST_EXPECT(js[jss::uri] == siteURI);
560 BEAST_EXPECT(js[jss::last_refresh_status] == "accepted");
561 // The actual time of the update will vary run to run, so
562 // just verify the time is there
563 BEAST_EXPECT(js.isMember(jss::last_refresh_time));
564 }
565 }
566 }
567 }
568
569 void
571 {
572 using namespace test::jtx;
573 Env env{*this};
574 auto result = env.rpc("validation_create");
575 BEAST_EXPECT(
576 result.isMember(jss::result) &&
577 result[jss::result][jss::status] == "success");
578 result = env.rpc(
579 "validation_create",
580 "BAWL MAN JADE MOON DOVE GEM SON NOW HAD ADEN GLOW TIRE");
581 BEAST_EXPECT(
582 result.isMember(jss::result) &&
583 result[jss::result][jss::status] == "success");
584 }
585
586 void
587 run() override
588 {
589 testPrivileges();
590 testStaticUNL();
591 testDynamicUNL();
592 test_validation_create();
593 }
594};
595
596BEAST_DEFINE_TESTSUITE(ValidatorRPC, app, ripple);
597
598} // namespace test
599} // namespace ripple
A testsuite class.
Definition: suite.h:53
A public key.
Definition: PublicKey.h:62
void run() override
Runs the suite.
A transaction testing environment.
Definition: Env.h:117
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
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:353
std::unique_ptr< Config > no_admin(std::unique_ptr< Config >)
adjust config so no admin ports are enabled
Definition: envconfig.cpp:81
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:106
bool isAdmin(Port const &port, Json::Value const &params, beast::IP::Address const &remoteIp)
Definition: Role.cpp:84
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:303
std::string to_string(base_uint< Bits, Tag > const &a)
Definition: base_uint.h:629
std::pair< PublicKey, SecretKey > randomKeyPair(KeyType type)
Create a key pair using secure random numbers.
Definition: SecretKey.cpp:368
T size(T... args)
T str(T... args)