rippled
Loading...
Searching...
No Matches
ValidatorList_test.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright 2015 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
22#include <xrpld/app/misc/ValidatorList.h>
23#include <xrpld/overlay/detail/ProtocolMessage.h>
24
25#include <xrpl/basics/Slice.h>
26#include <xrpl/basics/base64.h>
27#include <xrpl/basics/strHex.h>
28#include <xrpl/protocol/HashPrefix.h>
29#include <xrpl/protocol/PublicKey.h>
30#include <xrpl/protocol/SecretKey.h>
31#include <xrpl/protocol/Sign.h>
32#include <xrpl/protocol/digest.h>
33#include <xrpl/protocol/jss.h>
34#include <xrpl/protocol/messages.h>
35
36#include <boost/beast/core/multi_buffer.hpp>
37
38namespace ripple {
39namespace test {
40
42{
43private:
50
51 static PublicKey
56
57 static PublicKey
62
63 static std::string
65 PublicKey const& pk,
66 SecretKey const& sk,
67 PublicKey const& spk,
68 SecretKey const& ssk,
69 int seq)
70 {
72 st[sfSequence] = seq;
73 st[sfPublicKey] = pk;
74
76 {
77 st[sfSigningPubKey] = spk;
79 }
80
81 sign(
82 st,
84 *publicKeyType(pk),
85 sk,
86 sfMasterSignature);
87
88 Serializer s;
89 st.add(s);
90
91 return std::string(static_cast<char const*>(s.data()), s.size());
92 }
93
94 static std::string
96 {
99 st[sfPublicKey] = pk;
100
101 sign(
102 st,
104 *publicKeyType(pk),
105 sk,
106 sfMasterSignature);
107
108 Serializer s;
109 st.add(s);
110
111 return std::string(static_cast<char const*>(s.data()), s.size());
112 }
113
114 static Validator
116 {
117 auto const secret = randomSecretKey();
118 auto const masterPublic = derivePublicKey(KeyType::ed25519, secret);
119 auto const signingKeys = randomKeyPair(KeyType::secp256k1);
120 return {
121 masterPublic,
122 signingKeys.first,
124 masterPublic,
125 secret,
126 signingKeys.first,
127 signingKeys.second,
128 1))};
129 }
130
133 std::vector<Validator> const& validators,
134 std::size_t sequence,
135 std::size_t validUntil,
136 std::optional<std::size_t> validFrom = {})
137 {
138 std::string data = "{\"sequence\":" + std::to_string(sequence) +
139 ",\"expiration\":" + std::to_string(validUntil);
140 if (validFrom)
141 data += ",\"effective\":" + std::to_string(*validFrom);
142 data += ",\"validators\":[";
143
144 for (auto const& val : validators)
145 {
146 data += "{\"validation_public_key\":\"" + strHex(val.masterPublic) +
147 "\",\"manifest\":\"" + val.manifest + "\"},";
148 }
149
150 data.pop_back();
151 data += "]}";
152 return base64_encode(data);
153 }
154
157 std::string const& blob,
159 {
160 auto const data = base64_decode(blob);
161 return strHex(sign(keys.first, keys.second, makeSlice(data)));
162 }
163
164 static hash_set<NodeID>
166 {
168 res.reserve(pks.size());
169 for (auto const& pk : pks)
170 res.insert(calcNodeID(pk));
171 return res;
172 }
173
174 void
177 PublicKey pubKey,
178 ListDisposition expectedWorst,
179 ListDisposition expectedBest)
180 {
181 BEAST_EXPECT(
183 (result.publisherKey && *result.publisherKey == pubKey));
184 BEAST_EXPECT(result.bestDisposition() == expectedBest);
185 BEAST_EXPECT(result.worstDisposition() == expectedWorst);
186 }
187
188 void
190 {
191 testcase("Genesis Quorum");
192
193 ManifestCache manifests;
194 jtx::Env env(*this);
195 auto& app = env.app();
196 {
197 auto trustedKeys = std::make_unique<ValidatorList>(
198 manifests,
199 manifests,
200 env.timeKeeper(),
201 app.config().legacy("database_path"),
202 env.journal);
203 BEAST_EXPECT(trustedKeys->quorum() == 1);
204 }
205 {
206 std::size_t minQuorum = 0;
207 auto trustedKeys = std::make_unique<ValidatorList>(
208 manifests,
209 manifests,
210 env.timeKeeper(),
211 app.config().legacy("database_path"),
212 env.journal,
213 minQuorum);
214 BEAST_EXPECT(trustedKeys->quorum() == minQuorum);
215 }
216 }
217
218 void
220 {
221 testcase("Config Load");
222
223 jtx::Env env(
225 auto& app = env.app();
226 std::vector<std::string> const emptyCfgKeys;
227 std::vector<std::string> const emptyCfgPublishers;
228
229 auto const localSigningKeys = randomKeyPair(KeyType::secp256k1);
230 auto const localSigningPublicOuter = localSigningKeys.first;
231 auto const localSigningSecret = localSigningKeys.second;
232 auto const localMasterSecret = randomSecretKey();
233 auto const localMasterPublic =
234 derivePublicKey(KeyType::ed25519, localMasterSecret);
235
236 std::string const cfgManifest(makeManifestString(
237 localMasterPublic,
238 localMasterSecret,
239 localSigningPublicOuter,
240 localSigningSecret,
241 1));
242
243 auto format = [](PublicKey const& publicKey,
244 char const* comment = nullptr) {
245 auto ret = toBase58(TokenType::NodePublic, publicKey);
246
247 if (comment)
248 ret += comment;
249
250 return ret;
251 };
252
253 std::vector<PublicKey> configList;
254 configList.reserve(8);
255
256 while (configList.size() != 8)
257 configList.push_back(randomNode());
258
259 // Correct configuration
261 {format(configList[0]),
262 format(configList[1], " Comment"),
263 format(configList[2], " Multi Word Comment"),
264 format(configList[3], " Leading Whitespace"),
265 format(configList[4], " Trailing Whitespace "),
266 format(configList[5], " Leading & Trailing Whitespace "),
267 format(
268 configList[6],
269 " Leading, Trailing & Internal Whitespace "),
270 format(configList[7], " ")});
271
272 {
273 ManifestCache manifests;
274 auto trustedKeys = std::make_unique<ValidatorList>(
275 manifests,
276 manifests,
277 env.timeKeeper(),
278 app.config().legacy("database_path"),
279 env.journal);
280
281 // Correct (empty) configuration
282 BEAST_EXPECT(
283 trustedKeys->load({}, emptyCfgKeys, emptyCfgPublishers));
284
285 // load local validator key with or without manifest
286 BEAST_EXPECT(trustedKeys->load(
287 localSigningPublicOuter, emptyCfgKeys, emptyCfgPublishers));
288 BEAST_EXPECT(trustedKeys->listed(localSigningPublicOuter));
289
290 manifests.applyManifest(*deserializeManifest(cfgManifest));
291 BEAST_EXPECT(trustedKeys->load(
292 localSigningPublicOuter, emptyCfgKeys, emptyCfgPublishers));
293
294 BEAST_EXPECT(trustedKeys->listed(localMasterPublic));
295 BEAST_EXPECT(trustedKeys->listed(localSigningPublicOuter));
296 }
297 {
298 // load should add validator keys from config
299 ManifestCache manifests;
300 auto trustedKeys = std::make_unique<ValidatorList>(
301 manifests,
302 manifests,
303 env.timeKeeper(),
304 app.config().legacy("database_path"),
305 env.journal);
306
307 BEAST_EXPECT(trustedKeys->load({}, cfgKeys, emptyCfgPublishers));
308
309 for (auto const& n : configList)
310 BEAST_EXPECT(trustedKeys->listed(n));
311
312 // load should accept Ed25519 master public keys
313 auto const masterNode1 = randomMasterKey();
314 auto const masterNode2 = randomMasterKey();
315
316 std::vector<std::string> cfgMasterKeys(
317 {format(masterNode1), format(masterNode2, " Comment")});
318 BEAST_EXPECT(
319 trustedKeys->load({}, cfgMasterKeys, emptyCfgPublishers));
320 BEAST_EXPECT(trustedKeys->listed(masterNode1));
321 BEAST_EXPECT(trustedKeys->listed(masterNode2));
322
323 // load should reject invalid config keys
324 BEAST_EXPECT(
325 !trustedKeys->load({}, {"NotAPublicKey"}, emptyCfgPublishers));
326 BEAST_EXPECT(!trustedKeys->load(
327 {}, {format(randomNode(), "!")}, emptyCfgPublishers));
328
329 // load terminates when encountering an invalid entry
330 auto const goodKey = randomNode();
331 BEAST_EXPECT(!trustedKeys->load(
332 {},
333 {format(randomNode(), "!"), format(goodKey)},
334 emptyCfgPublishers));
335 BEAST_EXPECT(!trustedKeys->listed(goodKey));
336 }
337 {
338 // local validator key on config list
339 ManifestCache manifests;
340 auto trustedKeys = std::make_unique<ValidatorList>(
341 manifests,
342 manifests,
343 env.timeKeeper(),
344 app.config().legacy("database_path"),
345 env.journal);
346
347 auto const localSigningPublic =
348 parseBase58<PublicKey>(TokenType::NodePublic, cfgKeys.front());
349
350 BEAST_EXPECT(trustedKeys->load(
351 *localSigningPublic, cfgKeys, emptyCfgPublishers));
352
353 BEAST_EXPECT(trustedKeys->localPublicKey() == localSigningPublic);
354 BEAST_EXPECT(trustedKeys->listed(*localSigningPublic));
355 for (auto const& n : configList)
356 BEAST_EXPECT(trustedKeys->listed(n));
357 }
358 {
359 // local validator key not on config list
360 ManifestCache manifests;
361 auto trustedKeys = std::make_unique<ValidatorList>(
362 manifests,
363 manifests,
364 env.timeKeeper(),
365 app.config().legacy("database_path"),
366 env.journal);
367
368 auto const localSigningPublic = randomNode();
369 BEAST_EXPECT(trustedKeys->load(
370 localSigningPublic, cfgKeys, emptyCfgPublishers));
371
372 BEAST_EXPECT(trustedKeys->localPublicKey() == localSigningPublic);
373 BEAST_EXPECT(trustedKeys->listed(localSigningPublic));
374 for (auto const& n : configList)
375 BEAST_EXPECT(trustedKeys->listed(n));
376 }
377 {
378 // local validator key (with manifest) not on config list
379 ManifestCache manifests;
380 auto trustedKeys = std::make_unique<ValidatorList>(
381 manifests,
382 manifests,
383 env.timeKeeper(),
384 app.config().legacy("database_path"),
385 env.journal);
386
387 manifests.applyManifest(*deserializeManifest(cfgManifest));
388
389 BEAST_EXPECT(trustedKeys->load(
390 localSigningPublicOuter, cfgKeys, emptyCfgPublishers));
391
392 BEAST_EXPECT(trustedKeys->localPublicKey() == localMasterPublic);
393 BEAST_EXPECT(trustedKeys->listed(localSigningPublicOuter));
394 BEAST_EXPECT(trustedKeys->listed(localMasterPublic));
395 for (auto const& n : configList)
396 BEAST_EXPECT(trustedKeys->listed(n));
397 }
398 {
399 ManifestCache manifests;
400 auto trustedKeys = std::make_unique<ValidatorList>(
401 manifests,
402 manifests,
403 env.timeKeeper(),
404 app.config().legacy("database_path"),
405 env.journal);
406
407 // load should reject invalid validator list signing keys
408 std::vector<std::string> badPublishers({"NotASigningKey"});
409 BEAST_EXPECT(!trustedKeys->load({}, emptyCfgKeys, badPublishers));
410
411 // load should reject validator list signing keys with invalid
412 // encoding
415 badPublishers.clear();
416 for (auto const& key : keys)
417 badPublishers.push_back(toBase58(TokenType::NodePublic, key));
418
419 BEAST_EXPECT(!trustedKeys->load({}, emptyCfgKeys, badPublishers));
420 for (auto const& key : keys)
421 BEAST_EXPECT(!trustedKeys->trustedPublisher(key));
422
423 // load should accept valid validator list publisher keys
424 std::vector<std::string> cfgPublishers;
425 for (auto const& key : keys)
426 cfgPublishers.push_back(strHex(key));
427
428 BEAST_EXPECT(trustedKeys->load({}, emptyCfgKeys, cfgPublishers));
429 for (auto const& key : keys)
430 BEAST_EXPECT(trustedKeys->trustedPublisher(key));
431 BEAST_EXPECT(
432 trustedKeys->getListThreshold() == keys.size() / 2 + 1);
433 }
434 {
435 ManifestCache manifests;
436 auto trustedKeys = std::make_unique<ValidatorList>(
437 manifests,
438 manifests,
439 env.timeKeeper(),
440 app.config().legacy("database_path"),
441 env.journal);
442
447 randomMasterKey()});
448 std::vector<std::string> cfgPublishers;
449 for (auto const& key : keys)
450 cfgPublishers.push_back(strHex(key));
451
452 // explicitly set the list threshold
453 BEAST_EXPECT(trustedKeys->load(
454 {}, emptyCfgKeys, cfgPublishers, std::size_t(2)));
455 for (auto const& key : keys)
456 BEAST_EXPECT(trustedKeys->trustedPublisher(key));
457 BEAST_EXPECT(trustedKeys->getListThreshold() == 2);
458 }
459 {
460 // Attempt to load a publisher key that has been revoked.
461 // Should fail
462 ManifestCache valManifests;
463 ManifestCache pubManifests;
464 auto trustedKeys = std::make_unique<ValidatorList>(
465 valManifests,
466 pubManifests,
467 env.timeKeeper(),
468 app.config().legacy("database_path"),
469 env.journal);
470
471 auto const pubRevokedSecret = randomSecretKey();
472 auto const pubRevokedPublic =
473 derivePublicKey(KeyType::ed25519, pubRevokedSecret);
474 auto const pubRevokedSigning = randomKeyPair(KeyType::secp256k1);
475 // make this manifest revoked (seq num = max)
476 // -- thus should not be loaded
478 pubRevokedPublic,
479 pubRevokedSecret,
480 pubRevokedSigning.first,
481 pubRevokedSigning.second,
483
484 // these two are not revoked (and not in the manifest cache at all.)
485 auto legitKey1 = randomMasterKey();
486 auto legitKey2 = randomMasterKey();
487
488 std::vector<std::string> cfgPublishers = {
489 strHex(pubRevokedPublic), strHex(legitKey1), strHex(legitKey2)};
490 BEAST_EXPECT(trustedKeys->load({}, emptyCfgKeys, cfgPublishers));
491
492 BEAST_EXPECT(!trustedKeys->trustedPublisher(pubRevokedPublic));
493 BEAST_EXPECT(trustedKeys->trustedPublisher(legitKey1));
494 BEAST_EXPECT(trustedKeys->trustedPublisher(legitKey2));
495 // 2 is the threshold for 3 publishers (even though 1 is revoked)
496 BEAST_EXPECT(trustedKeys->getListThreshold() == 2);
497 }
498 {
499 // One (of two) publisher keys has been revoked, the user had
500 // explicitly set validator list threshold to 2.
501 ManifestCache valManifests;
502 ManifestCache pubManifests;
503 auto trustedKeys = std::make_unique<ValidatorList>(
504 valManifests,
505 pubManifests,
506 env.timeKeeper(),
507 app.config().legacy("database_path"),
508 env.journal);
509
510 auto const pubRevokedSecret = randomSecretKey();
511 auto const pubRevokedPublic =
512 derivePublicKey(KeyType::ed25519, pubRevokedSecret);
513 auto const pubRevokedSigning = randomKeyPair(KeyType::secp256k1);
514 // make this manifest revoked (seq num = max)
515 // -- thus should not be loaded
517 pubRevokedPublic,
518 pubRevokedSecret,
519 pubRevokedSigning.first,
520 pubRevokedSigning.second,
522
523 // this one is not revoked (and not in the manifest cache at all.)
524 auto legitKey = randomMasterKey();
525
526 std::vector<std::string> cfgPublishers = {
527 strHex(pubRevokedPublic), strHex(legitKey)};
528 BEAST_EXPECT(trustedKeys->load(
529 {}, emptyCfgKeys, cfgPublishers, std::size_t(2)));
530
531 BEAST_EXPECT(!trustedKeys->trustedPublisher(pubRevokedPublic));
532 BEAST_EXPECT(trustedKeys->trustedPublisher(legitKey));
533 // 2 is the threshold, as requested in configuration
534 BEAST_EXPECT(trustedKeys->getListThreshold() == 2);
535 }
536 }
537
538 void
540 {
541 testcase("Apply list");
542 using namespace std::chrono_literals;
543
544 std::string const siteUri = "testApplyList.test";
545
546 auto checkAvailable =
547 [this](
548 auto const& trustedKeys,
549 auto const& hexPublic,
550 auto const& manifest,
551 auto const version,
553 expected) {
554 auto const available = trustedKeys->getAvailable(hexPublic);
555
556 BEAST_EXPECT(!version || available);
557 if (available)
558 {
559 auto const& a = *available;
560 BEAST_EXPECT(a[jss::public_key] == hexPublic);
561 BEAST_EXPECT(a[jss::manifest] == manifest);
562 // Because multiple lists were processed, the version was
563 // overridden
564 BEAST_EXPECT(a[jss::version] == version);
565 if (version == 1)
566 {
567 BEAST_EXPECT(expected.size() == 1);
568 BEAST_EXPECT(a[jss::blob] == expected[0].first);
569 BEAST_EXPECT(a[jss::signature] == expected[0].second);
570 BEAST_EXPECT(!a.isMember(jss::blobs_v2));
571 }
572 else if (BEAST_EXPECT(a.isMember(jss::blobs_v2)))
573 {
574 BEAST_EXPECT(!a.isMember(jss::blob));
575 BEAST_EXPECT(!a.isMember(jss::signature));
576 auto const& blobs_v2 = a[jss::blobs_v2];
577 BEAST_EXPECT(
578 blobs_v2.isArray() &&
579 blobs_v2.size() == expected.size());
580
581 for (unsigned int i = 0; i < expected.size(); ++i)
582 {
583 BEAST_EXPECT(
584 blobs_v2[i][jss::blob] == expected[i].first);
585 BEAST_EXPECT(
586 blobs_v2[i][jss::signature] ==
587 expected[i].second);
588 }
589 }
590 }
591 };
592
593 ManifestCache manifests;
594 jtx::Env env(*this);
595 auto& app = env.app();
596 auto trustedKeys = std::make_unique<ValidatorList>(
597 manifests,
598 manifests,
599 env.app().timeKeeper(),
600 app.config().legacy("database_path"),
601 env.journal);
602
603 auto expectTrusted =
604 [this, &trustedKeys](std::vector<Validator> const& list) {
605 for (auto const& val : list)
606 {
607 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
608 BEAST_EXPECT(trustedKeys->listed(val.signingPublic));
609 }
610 };
611
612 auto expectUntrusted =
613 [this, &trustedKeys](std::vector<Validator> const& list) {
614 for (auto const& val : list)
615 {
616 BEAST_EXPECT(!trustedKeys->listed(val.masterPublic));
617 BEAST_EXPECT(!trustedKeys->listed(val.signingPublic));
618 }
619 };
620
621 auto const publisherSecret = randomSecretKey();
622 auto const publisherPublic =
623 derivePublicKey(KeyType::ed25519, publisherSecret);
624 auto const hexPublic =
625 strHex(publisherPublic.begin(), publisherPublic.end());
626 auto const pubSigningKeys1 = randomKeyPair(KeyType::secp256k1);
627 auto const manifest1 = base64_encode(makeManifestString(
628 publisherPublic,
629 publisherSecret,
630 pubSigningKeys1.first,
631 pubSigningKeys1.second,
632 1));
633
634 std::vector<std::string> cfgKeys1({strHex(publisherPublic)});
635 std::vector<std::string> emptyCfgKeys;
636
637 BEAST_EXPECT(trustedKeys->load({}, emptyCfgKeys, cfgKeys1));
638
640 auto constexpr listSize = 20;
641 auto constexpr numLists = 9;
643 // 1-based to correspond with the individually named blobs below.
644 for (auto i = 1; i <= numLists; ++i)
645 {
646 auto& list = lists[i];
647 list.reserve(listSize);
648 while (list.size() < listSize)
649 list.push_back(randomValidator());
650 }
651 return lists;
652 }();
653
654 // Attempt an expired list (fail) and a single list (succeed)
655 env.timeKeeper().set(env.timeKeeper().now() + 1s);
656 auto const version = 1;
657 auto const sequence1 = 1;
658 auto const expiredblob = makeList(
659 lists.at(1),
660 sequence1,
661 env.timeKeeper().now().time_since_epoch().count());
662 auto const expiredSig = signList(expiredblob, pubSigningKeys1);
663
664 NetClock::time_point const validUntil = env.timeKeeper().now() + 3600s;
665 auto const sequence2 = 2;
666 auto const blob2 = makeList(
667 lists.at(2), sequence2, validUntil.time_since_epoch().count());
668 auto const sig2 = signList(blob2, pubSigningKeys1);
669
671 trustedKeys->applyLists(
672 manifest1,
673 version,
674 {{expiredblob, expiredSig, {}}, {blob2, sig2, {}}},
675 siteUri),
676 publisherPublic,
679
680 expectTrusted(lists.at(2));
681
682 checkAvailable(
683 trustedKeys, hexPublic, manifest1, version, {{blob2, sig2}});
684
685 // Do not apply future lists, but process them
686 auto const version2 = 2;
687 auto const sequence7 = 7;
688 auto const effective7 = validUntil - 60s;
689 auto const expiration7 = effective7 + 3600s;
690 auto const blob7 = makeList(
691 lists.at(7),
692 sequence7,
693 expiration7.time_since_epoch().count(),
694 effective7.time_since_epoch().count());
695 auto const sig7 = signList(blob7, pubSigningKeys1);
696
697 auto const sequence8 = 8;
698 auto const effective8 = expiration7 - 60s;
699 auto const expiration8 = effective8 + 3600s;
700 auto const blob8 = makeList(
701 lists.at(8),
702 sequence8,
703 expiration8.time_since_epoch().count(),
704 effective8.time_since_epoch().count());
705 auto const sig8 = signList(blob8, pubSigningKeys1);
706
707 checkResult(
708 trustedKeys->applyLists(
709 manifest1,
710 version2,
711 {{blob7, sig7, {}}, {blob8, sig8, {}}},
712 siteUri),
713 publisherPublic,
714 ListDisposition::pending,
715 ListDisposition::pending);
716
717 expectUntrusted(lists.at(7));
718 expectUntrusted(lists.at(8));
719
720 // Do not apply out-of-order future list, but process it
721 auto const sequence6 = 6;
722 auto const effective6 = effective7 - 60s;
723 auto const expiration6 = effective6 + 3600s;
724 auto const blob6 = makeList(
725 lists.at(6),
726 sequence6,
727 expiration6.time_since_epoch().count(),
728 effective6.time_since_epoch().count());
729 auto const sig6 = signList(blob6, pubSigningKeys1);
730
731 // Process future list that is overridden by a later list
732 auto const sequence6a = 5;
733 auto const effective6a = effective6 + 60s;
734 auto const expiration6a = effective6a + 3600s;
735 auto const blob6a = makeList(
736 lists.at(5),
737 sequence6a,
738 expiration6a.time_since_epoch().count(),
739 effective6a.time_since_epoch().count());
740 auto const sig6a = signList(blob6a, pubSigningKeys1);
741
742 checkResult(
743 trustedKeys->applyLists(
744 manifest1,
745 version,
746 {{blob6a, sig6a, {}}, {blob6, sig6, {}}},
747 siteUri),
748 publisherPublic,
749 ListDisposition::pending,
750 ListDisposition::pending);
751
752 expectUntrusted(lists.at(6));
753 expectTrusted(lists.at(2));
754
755 // Do not apply re-process lists known future sequence numbers
756
757 checkResult(
758 trustedKeys->applyLists(
759 manifest1,
760 version,
761 {{blob7, sig7, {}}, {blob6, sig6, {}}},
762 siteUri),
763 publisherPublic,
764 ListDisposition::known_sequence,
765 ListDisposition::known_sequence);
766
767 expectUntrusted(lists.at(6));
768 expectUntrusted(lists.at(7));
769 expectTrusted(lists.at(2));
770
771 // do not use list from untrusted publisher
772 auto const untrustedManifest = base64_encode(makeManifestString(
773 randomMasterKey(),
774 publisherSecret,
775 pubSigningKeys1.first,
776 pubSigningKeys1.second,
777 1));
778
779 checkResult(
780 trustedKeys->applyLists(
781 untrustedManifest, version, {{blob2, sig2, {}}}, siteUri),
782 publisherPublic,
783 ListDisposition::untrusted,
784 ListDisposition::untrusted);
785
786 // do not use list with unhandled version
787 auto const badVersion = 666;
788 checkResult(
789 trustedKeys->applyLists(
790 manifest1, badVersion, {{blob2, sig2, {}}}, siteUri),
791 publisherPublic,
792 ListDisposition::unsupported_version,
793 ListDisposition::unsupported_version);
794
795 // apply list with highest sequence number
796 auto const sequence3 = 3;
797 auto const blob3 = makeList(
798 lists.at(3), sequence3, validUntil.time_since_epoch().count());
799 auto const sig3 = signList(blob3, pubSigningKeys1);
800
801 checkResult(
802 trustedKeys->applyLists(
803 manifest1, version, {{blob3, sig3, {}}}, siteUri),
804 publisherPublic,
805 ListDisposition::accepted,
806 ListDisposition::accepted);
807
808 expectUntrusted(lists.at(1));
809 expectUntrusted(lists.at(2));
810 expectTrusted(lists.at(3));
811
812 // Note that blob6a is not present, because it was dropped during
813 // processing
814 checkAvailable(
815 trustedKeys,
816 hexPublic,
817 manifest1,
818 2,
819 {{blob3, sig3}, {blob6, sig6}, {blob7, sig7}, {blob8, sig8}});
820
821 // do not re-apply lists with past or current sequence numbers
822 checkResult(
823 trustedKeys->applyLists(
824 manifest1,
825 version,
826 {{blob2, sig2, {}}, {blob3, sig3, {}}},
827 siteUri),
828 publisherPublic,
829 ListDisposition::stale,
830 ListDisposition::same_sequence);
831
832 // apply list with new publisher key updated by manifest. Also send some
833 // old lists along with the old manifest
834 auto const pubSigningKeys2 = randomKeyPair(KeyType::secp256k1);
835 auto manifest2 = base64_encode(makeManifestString(
836 publisherPublic,
837 publisherSecret,
838 pubSigningKeys2.first,
839 pubSigningKeys2.second,
840 2));
841
842 auto const sequence4 = 4;
843 auto const blob4 = makeList(
844 lists.at(4), sequence4, validUntil.time_since_epoch().count());
845 auto const sig4 = signList(blob4, pubSigningKeys2);
846
847 checkResult(
848 trustedKeys->applyLists(
849 manifest2,
850 version,
851 {{blob2, sig2, manifest1},
852 {blob3, sig3, manifest1},
853 {blob4, sig4, {}}},
854 siteUri),
855 publisherPublic,
856 ListDisposition::stale,
857 ListDisposition::accepted);
858
859 expectUntrusted(lists.at(2));
860 expectUntrusted(lists.at(3));
861 expectTrusted(lists.at(4));
862
863 checkAvailable(
864 trustedKeys,
865 hexPublic,
866 manifest2,
867 2,
868 {{blob4, sig4}, {blob6, sig6}, {blob7, sig7}, {blob8, sig8}});
869
870 auto const sequence5 = 5;
871 auto const blob5 = makeList(
872 lists.at(5), sequence5, validUntil.time_since_epoch().count());
873 auto const badSig = signList(blob5, pubSigningKeys1);
874 checkResult(
875 trustedKeys->applyLists(
876 manifest1, version, {{blob5, badSig, {}}}, siteUri),
877 publisherPublic,
878 ListDisposition::invalid,
879 ListDisposition::invalid);
880
881 expectUntrusted(lists.at(2));
882 expectUntrusted(lists.at(3));
883 expectTrusted(lists.at(4));
884 expectUntrusted(lists.at(5));
885
886 // Reprocess the pending list, but the signature is no longer valid
887 checkResult(
888 trustedKeys->applyLists(
889 manifest1,
890 version,
891 {{blob7, sig7, {}}, {blob8, sig8, {}}},
892 siteUri),
893 publisherPublic,
894 ListDisposition::invalid,
895 ListDisposition::invalid);
896
897 expectTrusted(lists.at(4));
898 expectUntrusted(lists.at(7));
899 expectUntrusted(lists.at(8));
900
901 // Automatically rotate the first pending already processed list using
902 // updateTrusted. Note that the timekeeper is NOT moved, so the close
903 // time will be ahead of the test's wall clock
904 trustedKeys->updateTrusted(
905 {},
906 effective6 + 1s,
907 env.app().getOPs(),
908 env.app().overlay(),
909 env.app().getHashRouter());
910
911 expectUntrusted(lists.at(3));
912 expectTrusted(lists.at(6));
913
914 checkAvailable(
915 trustedKeys,
916 hexPublic,
917 manifest2,
918 2,
919 {{blob6, sig6}, {blob7, sig7}, {blob8, sig8}});
920
921 // Automatically rotate the LAST pending list using updateTrusted,
922 // bypassing blob7. Note that the timekeeper IS moved, so the provided
923 // close time will be behind the test's wall clock, and thus the wall
924 // clock is used.
925 env.timeKeeper().set(effective8);
926 trustedKeys->updateTrusted(
927 {},
928 effective8 + 1s,
929 env.app().getOPs(),
930 env.app().overlay(),
931 env.app().getHashRouter());
932
933 expectUntrusted(lists.at(6));
934 expectUntrusted(lists.at(7));
935 expectTrusted(lists.at(8));
936
937 checkAvailable(trustedKeys, hexPublic, manifest2, 2, {{blob8, sig8}});
938
939 // resign the pending list with new key and validate it, but it's
940 // already valid Also try reprocessing the pending list with an
941 // explicit manifest
942 // - it is still invalid
943 auto const sig8_2 = signList(blob8, pubSigningKeys2);
944
945 checkResult(
946 trustedKeys->applyLists(
947 manifest2,
948 version,
949 {{blob8, sig8, manifest1}, {blob8, sig8_2, {}}},
950 siteUri),
951 publisherPublic,
952 ListDisposition::invalid,
953 ListDisposition::same_sequence);
954
955 expectTrusted(lists.at(8));
956
957 checkAvailable(trustedKeys, hexPublic, manifest2, 2, {{blob8, sig8}});
958
959 // do not apply list with revoked publisher key
960 // applied list is removed due to revoked publisher key
961 auto const signingKeysMax = randomKeyPair(KeyType::secp256k1);
962 auto maxManifest = base64_encode(
963 makeRevocationString(publisherPublic, publisherSecret));
964
965 auto const sequence9 = 9;
966 auto const blob9 = makeList(
967 lists.at(9), sequence9, validUntil.time_since_epoch().count());
968 auto const sig9 = signList(blob9, signingKeysMax);
969
970 checkResult(
971 trustedKeys->applyLists(
972 maxManifest, version, {{blob9, sig9, {}}}, siteUri),
973 publisherPublic,
974 ListDisposition::untrusted,
975 ListDisposition::untrusted);
976
977 BEAST_EXPECT(!trustedKeys->trustedPublisher(publisherPublic));
978 for (auto const& [num, list] : lists)
979 {
980 (void)num;
981 expectUntrusted(list);
982 }
983
984 checkAvailable(trustedKeys, hexPublic, manifest2, 0, {});
985 }
986
987 void
989 {
990 testcase("GetAvailable");
991 using namespace std::chrono_literals;
992
993 std::string const siteUri = "testApplyList.test";
994
995 ManifestCache manifests;
996 jtx::Env env(*this);
997 auto& app = env.app();
998 auto trustedKeys = std::make_unique<ValidatorList>(
999 manifests,
1000 manifests,
1001 env.app().timeKeeper(),
1002 app.config().legacy("database_path"),
1003 env.journal);
1004
1005 auto const publisherSecret = randomSecretKey();
1006 auto const publisherPublic =
1007 derivePublicKey(KeyType::ed25519, publisherSecret);
1008 auto const hexPublic =
1009 strHex(publisherPublic.begin(), publisherPublic.end());
1010 auto const pubSigningKeys1 = randomKeyPair(KeyType::secp256k1);
1011 auto const manifest = base64_encode(makeManifestString(
1012 publisherPublic,
1013 publisherSecret,
1014 pubSigningKeys1.first,
1015 pubSigningKeys1.second,
1016 1));
1017
1018 std::vector<std::string> cfgKeys1({strHex(publisherPublic)});
1019 std::vector<std::string> emptyCfgKeys;
1020
1021 BEAST_EXPECT(trustedKeys->load({}, emptyCfgKeys, cfgKeys1));
1022
1023 std::vector<Validator> const list = []() {
1024 auto constexpr listSize = 20;
1026 list.reserve(listSize);
1027 while (list.size() < listSize)
1028 list.push_back(randomValidator());
1029 return list;
1030 }();
1031
1032 // Process a list
1033 env.timeKeeper().set(env.timeKeeper().now() + 1s);
1034 NetClock::time_point const validUntil = env.timeKeeper().now() + 3600s;
1035 auto const blob =
1036 makeList(list, 1, validUntil.time_since_epoch().count());
1037 auto const sig = signList(blob, pubSigningKeys1);
1038
1039 {
1040 // list unavailable
1041 auto const available = trustedKeys->getAvailable(hexPublic);
1042 BEAST_EXPECT(!available);
1043 }
1044
1045 BEAST_EXPECT(
1046 trustedKeys->applyLists(manifest, 1, {{blob, sig, {}}}, siteUri)
1047 .bestDisposition() == ListDisposition::accepted);
1048
1049 {
1050 // invalid public key
1051 auto const available =
1052 trustedKeys->getAvailable(hexPublic + "invalid", 1);
1053 BEAST_EXPECT(!available);
1054 }
1055
1056 {
1057 // unknown public key
1058 auto const badSecret = randomSecretKey();
1059 auto const badPublic = derivePublicKey(KeyType::ed25519, badSecret);
1060 auto const hexBad = strHex(badPublic.begin(), badPublic.end());
1061
1062 auto const available = trustedKeys->getAvailable(hexBad, 1);
1063 BEAST_EXPECT(!available);
1064 }
1065 {
1066 // bad version 0
1067 auto const available = trustedKeys->getAvailable(hexPublic, 0);
1068 if (BEAST_EXPECT(available))
1069 {
1070 auto const& a = *available;
1071 BEAST_EXPECT(!a);
1072 }
1073 }
1074 {
1075 // bad version 3
1076 auto const available = trustedKeys->getAvailable(hexPublic, 3);
1077 if (BEAST_EXPECT(available))
1078 {
1079 auto const& a = *available;
1080 BEAST_EXPECT(!a);
1081 }
1082 }
1083 {
1084 // version 1
1085 auto const available = trustedKeys->getAvailable(hexPublic, 1);
1086 if (BEAST_EXPECT(available))
1087 {
1088 auto const& a = *available;
1089 BEAST_EXPECT(a[jss::public_key] == hexPublic);
1090 BEAST_EXPECT(a[jss::manifest] == manifest);
1091 BEAST_EXPECT(a[jss::version] == 1);
1092
1093 BEAST_EXPECT(a[jss::blob] == blob);
1094 BEAST_EXPECT(a[jss::signature] == sig);
1095 BEAST_EXPECT(!a.isMember(jss::blobs_v2));
1096 }
1097 }
1098
1099 {
1100 // version 2
1101 auto const available = trustedKeys->getAvailable(hexPublic, 2);
1102 if (BEAST_EXPECT(available))
1103 {
1104 auto const& a = *available;
1105 BEAST_EXPECT(a[jss::public_key] == hexPublic);
1106 BEAST_EXPECT(a[jss::manifest] == manifest);
1107 BEAST_EXPECT(a[jss::version] == 2);
1108
1109 if (BEAST_EXPECT(a.isMember(jss::blobs_v2)))
1110 {
1111 BEAST_EXPECT(!a.isMember(jss::blob));
1112 BEAST_EXPECT(!a.isMember(jss::signature));
1113 auto const& blobs_v2 = a[jss::blobs_v2];
1114 BEAST_EXPECT(blobs_v2.isArray() && blobs_v2.size() == 1);
1115
1116 BEAST_EXPECT(blobs_v2[0u][jss::blob] == blob);
1117 BEAST_EXPECT(blobs_v2[0u][jss::signature] == sig);
1118 }
1119 }
1120 }
1121 }
1122
1123 void
1125 {
1126 testcase("Update trusted");
1127
1128 std::string const siteUri = "testUpdateTrusted.test";
1129
1130 ManifestCache manifestsOuter;
1131 jtx::Env env(*this);
1132 auto& app = env.app();
1133 auto trustedKeysOuter = std::make_unique<ValidatorList>(
1134 manifestsOuter,
1135 manifestsOuter,
1136 env.timeKeeper(),
1137 app.config().legacy("database_path"),
1138 env.journal);
1139
1140 std::vector<std::string> cfgPublishersOuter;
1141 hash_set<NodeID> activeValidatorsOuter;
1142
1143 std::size_t const maxKeys = 40;
1144 {
1146 cfgKeys.reserve(maxKeys);
1147 hash_set<NodeID> unseenValidators;
1148
1149 while (cfgKeys.size() != maxKeys)
1150 {
1151 auto const valKey = randomNode();
1152 cfgKeys.push_back(toBase58(TokenType::NodePublic, valKey));
1153 if (cfgKeys.size() <= maxKeys - 5)
1154 activeValidatorsOuter.emplace(calcNodeID(valKey));
1155 else
1156 unseenValidators.emplace(calcNodeID(valKey));
1157 }
1158
1159 BEAST_EXPECT(
1160 trustedKeysOuter->load({}, cfgKeys, cfgPublishersOuter));
1161
1162 // updateTrusted should make all configured validators trusted
1163 // even if they are not active/seen
1164 TrustChanges changes = trustedKeysOuter->updateTrusted(
1165 activeValidatorsOuter,
1166 env.timeKeeper().now(),
1167 env.app().getOPs(),
1168 env.app().overlay(),
1169 env.app().getHashRouter());
1170
1171 for (auto const& val : unseenValidators)
1172 activeValidatorsOuter.emplace(val);
1173
1174 BEAST_EXPECT(changes.added == activeValidatorsOuter);
1175 BEAST_EXPECT(changes.removed.empty());
1176 BEAST_EXPECT(
1177 trustedKeysOuter->quorum() == std::ceil(cfgKeys.size() * 0.8f));
1178 for (auto const& val : cfgKeys)
1179 {
1180 if (auto const valKey =
1181 parseBase58<PublicKey>(TokenType::NodePublic, val))
1182 {
1183 BEAST_EXPECT(trustedKeysOuter->listed(*valKey));
1184 BEAST_EXPECT(trustedKeysOuter->trusted(*valKey));
1185 }
1186 else
1187 fail();
1188 }
1189
1190 changes = trustedKeysOuter->updateTrusted(
1191 activeValidatorsOuter,
1192 env.timeKeeper().now(),
1193 env.app().getOPs(),
1194 env.app().overlay(),
1195 env.app().getHashRouter());
1196 BEAST_EXPECT(changes.added.empty());
1197 BEAST_EXPECT(changes.removed.empty());
1198 BEAST_EXPECT(
1199 trustedKeysOuter->quorum() == std::ceil(cfgKeys.size() * 0.8f));
1200 }
1201 {
1202 // update with manifests
1203 auto const masterPrivate = randomSecretKey();
1204 auto const masterPublic =
1205 derivePublicKey(KeyType::ed25519, masterPrivate);
1206
1208 {toBase58(TokenType::NodePublic, masterPublic)});
1209
1210 BEAST_EXPECT(
1211 trustedKeysOuter->load({}, cfgKeys, cfgPublishersOuter));
1212
1213 auto const signingKeys1 = randomKeyPair(KeyType::secp256k1);
1214 auto const signingPublic1 = signingKeys1.first;
1215 activeValidatorsOuter.emplace(calcNodeID(masterPublic));
1216
1217 // Should not trust ephemeral signing key if there is no manifest
1218 TrustChanges changes = trustedKeysOuter->updateTrusted(
1219 activeValidatorsOuter,
1220 env.timeKeeper().now(),
1221 env.app().getOPs(),
1222 env.app().overlay(),
1223 env.app().getHashRouter());
1224 BEAST_EXPECT(changes.added == asNodeIDs({masterPublic}));
1225 BEAST_EXPECT(changes.removed.empty());
1226 BEAST_EXPECT(
1227 trustedKeysOuter->quorum() == std::ceil((maxKeys + 1) * 0.8f));
1228 BEAST_EXPECT(trustedKeysOuter->listed(masterPublic));
1229 BEAST_EXPECT(trustedKeysOuter->trusted(masterPublic));
1230 BEAST_EXPECT(!trustedKeysOuter->listed(signingPublic1));
1231 BEAST_EXPECT(!trustedKeysOuter->trusted(signingPublic1));
1232
1233 // Should trust the ephemeral signing key from the applied manifest
1234 auto m1 = deserializeManifest(makeManifestString(
1235 masterPublic,
1236 masterPrivate,
1237 signingPublic1,
1238 signingKeys1.second,
1239 1));
1240
1241 BEAST_EXPECT(
1242 manifestsOuter.applyManifest(std::move(*m1)) ==
1243 ManifestDisposition::accepted);
1244 BEAST_EXPECT(trustedKeysOuter->listed(masterPublic));
1245 BEAST_EXPECT(trustedKeysOuter->trusted(masterPublic));
1246 BEAST_EXPECT(trustedKeysOuter->listed(signingPublic1));
1247 BEAST_EXPECT(trustedKeysOuter->trusted(signingPublic1));
1248
1249 // Should only trust the ephemeral signing key
1250 // from the newest applied manifest
1251 auto const signingKeys2 = randomKeyPair(KeyType::secp256k1);
1252 auto const signingPublic2 = signingKeys2.first;
1253 auto m2 = deserializeManifest(makeManifestString(
1254 masterPublic,
1255 masterPrivate,
1256 signingPublic2,
1257 signingKeys2.second,
1258 2));
1259 BEAST_EXPECT(
1260 manifestsOuter.applyManifest(std::move(*m2)) ==
1261 ManifestDisposition::accepted);
1262 BEAST_EXPECT(trustedKeysOuter->listed(masterPublic));
1263 BEAST_EXPECT(trustedKeysOuter->trusted(masterPublic));
1264 BEAST_EXPECT(trustedKeysOuter->listed(signingPublic2));
1265 BEAST_EXPECT(trustedKeysOuter->trusted(signingPublic2));
1266 BEAST_EXPECT(!trustedKeysOuter->listed(signingPublic1));
1267 BEAST_EXPECT(!trustedKeysOuter->trusted(signingPublic1));
1268
1269 // Should not trust keys from revoked master public key
1270 auto const signingKeysMax = randomKeyPair(KeyType::secp256k1);
1271 auto const signingPublicMax = signingKeysMax.first;
1272 activeValidatorsOuter.emplace(calcNodeID(signingPublicMax));
1273 auto mMax = deserializeManifest(
1274 makeRevocationString(masterPublic, masterPrivate));
1275
1276 BEAST_EXPECT(mMax->revoked());
1277 BEAST_EXPECT(
1278 manifestsOuter.applyManifest(std::move(*mMax)) ==
1279 ManifestDisposition::accepted);
1280 BEAST_EXPECT(
1281 manifestsOuter.getSigningKey(masterPublic) == masterPublic);
1282 BEAST_EXPECT(manifestsOuter.revoked(masterPublic));
1283
1284 // Revoked key remains trusted until list is updated
1285 BEAST_EXPECT(trustedKeysOuter->listed(masterPublic));
1286 BEAST_EXPECT(trustedKeysOuter->trusted(masterPublic));
1287
1288 changes = trustedKeysOuter->updateTrusted(
1289 activeValidatorsOuter,
1290 env.timeKeeper().now(),
1291 env.app().getOPs(),
1292 env.app().overlay(),
1293 env.app().getHashRouter());
1294 BEAST_EXPECT(changes.removed == asNodeIDs({masterPublic}));
1295 BEAST_EXPECT(changes.added.empty());
1296 BEAST_EXPECT(
1297 trustedKeysOuter->quorum() == std::ceil(maxKeys * 0.8f));
1298 BEAST_EXPECT(trustedKeysOuter->listed(masterPublic));
1299 BEAST_EXPECT(!trustedKeysOuter->trusted(masterPublic));
1300 BEAST_EXPECT(!trustedKeysOuter->listed(signingPublicMax));
1301 BEAST_EXPECT(!trustedKeysOuter->trusted(signingPublicMax));
1302 BEAST_EXPECT(!trustedKeysOuter->listed(signingPublic2));
1303 BEAST_EXPECT(!trustedKeysOuter->trusted(signingPublic2));
1304 BEAST_EXPECT(!trustedKeysOuter->listed(signingPublic1));
1305 BEAST_EXPECT(!trustedKeysOuter->trusted(signingPublic1));
1306 }
1307 {
1308 // Make quorum unattainable if lists from any publishers are
1309 // unavailable
1310 auto trustedKeys = std::make_unique<ValidatorList>(
1311 manifestsOuter,
1312 manifestsOuter,
1313 env.timeKeeper(),
1314 app.config().legacy("database_path"),
1315 env.journal);
1316 auto const publisherSecret = randomSecretKey();
1317 auto const publisherPublic =
1318 derivePublicKey(KeyType::ed25519, publisherSecret);
1319
1320 std::vector<std::string> cfgPublishers({strHex(publisherPublic)});
1321 std::vector<std::string> emptyCfgKeys;
1322
1323 BEAST_EXPECT(trustedKeys->load({}, emptyCfgKeys, cfgPublishers));
1324
1325 TrustChanges changes = trustedKeys->updateTrusted(
1326 activeValidatorsOuter,
1327 env.timeKeeper().now(),
1328 env.app().getOPs(),
1329 env.app().overlay(),
1330 env.app().getHashRouter());
1331 BEAST_EXPECT(changes.removed.empty());
1332 BEAST_EXPECT(changes.added.empty());
1333 BEAST_EXPECT(
1334 trustedKeys->quorum() ==
1336 }
1337 {
1338 // Trust explicitly listed validators also when list threshold is
1339 // higher than 1
1340 auto trustedKeys = std::make_unique<ValidatorList>(
1341 manifestsOuter,
1342 manifestsOuter,
1343 env.timeKeeper(),
1344 app.config().legacy("database_path"),
1345 env.journal);
1346 auto const masterPrivate = randomSecretKey();
1347 auto const masterPublic =
1348 derivePublicKey(KeyType::ed25519, masterPrivate);
1350 {toBase58(TokenType::NodePublic, masterPublic)});
1351
1352 auto const publisher1Secret = randomSecretKey();
1353 auto const publisher1Public =
1354 derivePublicKey(KeyType::ed25519, publisher1Secret);
1355 auto const publisher2Secret = randomSecretKey();
1356 auto const publisher2Public =
1357 derivePublicKey(KeyType::ed25519, publisher2Secret);
1358 std::vector<std::string> cfgPublishers(
1359 {strHex(publisher1Public), strHex(publisher2Public)});
1360
1361 BEAST_EXPECT(
1362 trustedKeys->load({}, cfgKeys, cfgPublishers, std::size_t(2)));
1363
1364 TrustChanges changes = trustedKeys->updateTrusted(
1365 activeValidatorsOuter,
1366 env.timeKeeper().now(),
1367 env.app().getOPs(),
1368 env.app().overlay(),
1369 env.app().getHashRouter());
1370 BEAST_EXPECT(changes.removed.empty());
1371 BEAST_EXPECT(changes.added.size() == 1);
1372 BEAST_EXPECT(trustedKeys->listed(masterPublic));
1373 BEAST_EXPECT(trustedKeys->trusted(masterPublic));
1374 }
1375 {
1376 // Should use custom minimum quorum
1377 std::size_t const minQuorum = 1;
1378 ManifestCache manifests;
1379 auto trustedKeys = std::make_unique<ValidatorList>(
1380 manifests,
1381 manifests,
1382 env.timeKeeper(),
1383 app.config().legacy("database_path"),
1384 env.journal,
1385 minQuorum);
1386
1387 std::size_t n = 10;
1389 cfgKeys.reserve(n);
1390 hash_set<NodeID> expectedTrusted;
1391 hash_set<NodeID> activeValidators;
1392 NodeID toBeSeen;
1393
1394 while (cfgKeys.size() < n)
1395 {
1396 auto const valKey = randomNode();
1397 cfgKeys.push_back(toBase58(TokenType::NodePublic, valKey));
1398 expectedTrusted.emplace(calcNodeID(valKey));
1399 if (cfgKeys.size() < std::ceil(n * 0.8f))
1400 activeValidators.emplace(calcNodeID(valKey));
1401 else if (cfgKeys.size() < std::ceil(n * 0.8f))
1402 toBeSeen = calcNodeID(valKey);
1403 }
1404
1405 BEAST_EXPECT(trustedKeys->load({}, cfgKeys, cfgPublishersOuter));
1406
1407 TrustChanges changes = trustedKeys->updateTrusted(
1408 activeValidators,
1409 env.timeKeeper().now(),
1410 env.app().getOPs(),
1411 env.app().overlay(),
1412 env.app().getHashRouter());
1413 BEAST_EXPECT(changes.removed.empty());
1414 BEAST_EXPECT(changes.added == expectedTrusted);
1415 BEAST_EXPECT(trustedKeys->quorum() == minQuorum);
1416
1417 // Use configured quorum even when seen validators >= quorum
1418 activeValidators.emplace(toBeSeen);
1419 changes = trustedKeys->updateTrusted(
1420 activeValidators,
1421 env.timeKeeper().now(),
1422 env.app().getOPs(),
1423 env.app().overlay(),
1424 env.app().getHashRouter());
1425 BEAST_EXPECT(changes.removed.empty());
1426 BEAST_EXPECT(changes.added.empty());
1427 BEAST_EXPECT(trustedKeys->quorum() == minQuorum);
1428 }
1429 {
1430 // Remove expired published list
1431 auto trustedKeys = std::make_unique<ValidatorList>(
1432 manifestsOuter,
1433 manifestsOuter,
1434 env.app().timeKeeper(),
1435 app.config().legacy("database_path"),
1436 env.journal);
1437
1438 std::vector<std::string> emptyCfgKeys;
1439 auto const publisherKeys = randomKeyPair(KeyType::secp256k1);
1440 auto const pubSigningKeys = randomKeyPair(KeyType::secp256k1);
1441 auto const manifest = base64_encode(makeManifestString(
1442 publisherKeys.first,
1443 publisherKeys.second,
1444 pubSigningKeys.first,
1445 pubSigningKeys.second,
1446 1));
1447
1448 std::vector<std::string> cfgKeys({strHex(publisherKeys.first)});
1449
1450 BEAST_EXPECT(trustedKeys->load({}, emptyCfgKeys, cfgKeys));
1451
1452 std::vector<Validator> list({randomValidator(), randomValidator()});
1453 hash_set<NodeID> activeValidators(
1454 asNodeIDs({list[0].masterPublic, list[1].masterPublic}));
1455
1456 // do not apply expired list
1457 auto const version = 1;
1458 auto const sequence = 1;
1459 using namespace std::chrono_literals;
1460 NetClock::time_point const validUntil =
1461 env.timeKeeper().now() + 60s;
1462 auto const blob =
1463 makeList(list, sequence, validUntil.time_since_epoch().count());
1464 auto const sig = signList(blob, pubSigningKeys);
1465
1466 BEAST_EXPECT(
1467 ListDisposition::accepted ==
1468 trustedKeys
1469 ->applyLists(manifest, version, {{blob, sig, {}}}, siteUri)
1470 .bestDisposition());
1471
1472 TrustChanges changes = trustedKeys->updateTrusted(
1473 activeValidators,
1474 env.timeKeeper().now(),
1475 env.app().getOPs(),
1476 env.app().overlay(),
1477 env.app().getHashRouter());
1478 BEAST_EXPECT(changes.removed.empty());
1479 BEAST_EXPECT(changes.added == activeValidators);
1480 for (Validator const& val : list)
1481 {
1482 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
1483 BEAST_EXPECT(trustedKeys->trusted(val.signingPublic));
1484 }
1485 BEAST_EXPECT(trustedKeys->quorum() == 2);
1486
1487 env.timeKeeper().set(validUntil);
1488 changes = trustedKeys->updateTrusted(
1489 activeValidators,
1490 env.timeKeeper().now(),
1491 env.app().getOPs(),
1492 env.app().overlay(),
1493 env.app().getHashRouter());
1494 BEAST_EXPECT(changes.removed == activeValidators);
1495 BEAST_EXPECT(changes.added.empty());
1496 BEAST_EXPECT(!trustedKeys->trusted(list[0].masterPublic));
1497 BEAST_EXPECT(!trustedKeys->trusted(list[1].masterPublic));
1498 BEAST_EXPECT(
1499 trustedKeys->quorum() ==
1501
1502 // (Re)trust validators from new valid list
1503 std::vector<Validator> list2({list[0], randomValidator()});
1504 activeValidators.insert(calcNodeID(list2[1].masterPublic));
1505 auto const sequence2 = 2;
1506 NetClock::time_point const expiration2 =
1507 env.timeKeeper().now() + 60s;
1508 auto const blob2 = makeList(
1509 list2, sequence2, expiration2.time_since_epoch().count());
1510 auto const sig2 = signList(blob2, pubSigningKeys);
1511
1512 BEAST_EXPECT(
1513 ListDisposition::accepted ==
1514 trustedKeys
1515 ->applyLists(
1516 manifest, version, {{blob2, sig2, {}}}, siteUri)
1517 .bestDisposition());
1518
1519 changes = trustedKeys->updateTrusted(
1520 activeValidators,
1521 env.timeKeeper().now(),
1522 env.app().getOPs(),
1523 env.app().overlay(),
1524 env.app().getHashRouter());
1525 BEAST_EXPECT(changes.removed.empty());
1526 BEAST_EXPECT(
1527 changes.added ==
1528 asNodeIDs({list2[0].masterPublic, list2[1].masterPublic}));
1529 for (Validator const& val : list2)
1530 {
1531 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
1532 BEAST_EXPECT(trustedKeys->trusted(val.signingPublic));
1533 }
1534 BEAST_EXPECT(!trustedKeys->trusted(list[1].masterPublic));
1535 BEAST_EXPECT(!trustedKeys->trusted(list[1].signingPublic));
1536 BEAST_EXPECT(trustedKeys->quorum() == 2);
1537 }
1538 {
1539 // Test 1-9 configured validators
1540 auto trustedKeys = std::make_unique<ValidatorList>(
1541 manifestsOuter,
1542 manifestsOuter,
1543 env.timeKeeper(),
1544 app.config().legacy("database_path"),
1545 env.journal);
1546
1547 std::vector<std::string> cfgPublishers;
1548 hash_set<NodeID> activeValidators;
1549 hash_set<PublicKey> activeKeys;
1550
1552 cfgKeys.reserve(9);
1553
1554 while (cfgKeys.size() < cfgKeys.capacity())
1555 {
1556 auto const valKey = randomNode();
1557 cfgKeys.push_back(toBase58(TokenType::NodePublic, valKey));
1558 activeValidators.emplace(calcNodeID(valKey));
1559 activeKeys.emplace(valKey);
1560 BEAST_EXPECT(trustedKeys->load({}, cfgKeys, cfgPublishers));
1561 TrustChanges changes = trustedKeys->updateTrusted(
1562 activeValidators,
1563 env.timeKeeper().now(),
1564 env.app().getOPs(),
1565 env.app().overlay(),
1566 env.app().getHashRouter());
1567 BEAST_EXPECT(changes.removed.empty());
1568 BEAST_EXPECT(changes.added == asNodeIDs({valKey}));
1569 BEAST_EXPECT(
1570 trustedKeys->quorum() == std::ceil(cfgKeys.size() * 0.8f));
1571 for (auto const& key : activeKeys)
1572 BEAST_EXPECT(trustedKeys->trusted(key));
1573 }
1574 }
1575 {
1576 // Test 2-9 configured validators as validator
1577 auto trustedKeys = std::make_unique<ValidatorList>(
1578 manifestsOuter,
1579 manifestsOuter,
1580 env.timeKeeper(),
1581 app.config().legacy("database_path"),
1582 env.journal);
1583
1584 auto const localKey = randomNode();
1585 std::vector<std::string> cfgPublishers;
1586 hash_set<NodeID> activeValidators;
1587 hash_set<PublicKey> activeKeys;
1589 toBase58(TokenType::NodePublic, localKey)};
1590 cfgKeys.reserve(9);
1591
1592 while (cfgKeys.size() < cfgKeys.capacity())
1593 {
1594 auto const valKey = randomNode();
1595 cfgKeys.push_back(toBase58(TokenType::NodePublic, valKey));
1596 activeValidators.emplace(calcNodeID(valKey));
1597 activeKeys.emplace(valKey);
1598
1599 BEAST_EXPECT(
1600 trustedKeys->load(localKey, cfgKeys, cfgPublishers));
1601 TrustChanges changes = trustedKeys->updateTrusted(
1602 activeValidators,
1603 env.timeKeeper().now(),
1604 env.app().getOPs(),
1605 env.app().overlay(),
1606 env.app().getHashRouter());
1607 BEAST_EXPECT(changes.removed.empty());
1608 if (cfgKeys.size() > 2)
1609 BEAST_EXPECT(changes.added == asNodeIDs({valKey}));
1610 else
1611 BEAST_EXPECT(
1612 changes.added == asNodeIDs({localKey, valKey}));
1613
1614 BEAST_EXPECT(
1615 trustedKeys->quorum() == std::ceil(cfgKeys.size() * 0.8f));
1616
1617 for (auto const& key : activeKeys)
1618 BEAST_EXPECT(trustedKeys->trusted(key));
1619 }
1620 }
1621 {
1622 // Trusted set should include all validators from multiple lists
1623 ManifestCache manifests;
1624 auto trustedKeys = std::make_unique<ValidatorList>(
1625 manifests,
1626 manifests,
1627 env.timeKeeper(),
1628 app.config().legacy("database_path"),
1629 env.journal);
1630
1631 hash_set<NodeID> activeValidators;
1632 std::vector<Validator> valKeys;
1633 valKeys.reserve(maxKeys);
1634
1635 while (valKeys.size() != maxKeys)
1636 {
1637 valKeys.push_back(randomValidator());
1638 activeValidators.emplace(
1639 calcNodeID(valKeys.back().masterPublic));
1640 }
1641
1642 // locals[0]: from 0 to maxKeys - 4
1643 // locals[1]: from 1 to maxKeys - 2
1644 // locals[2]: from 2 to maxKeys
1645 constexpr static int publishers = 3;
1646 std::array<
1647 std::pair<
1648 decltype(valKeys)::const_iterator,
1649 decltype(valKeys)::const_iterator>,
1650 publishers>
1651 locals = {
1652 std::make_pair(valKeys.cbegin(), valKeys.cend() - 4),
1653 std::make_pair(valKeys.cbegin() + 1, valKeys.cend() - 2),
1654 std::make_pair(valKeys.cbegin() + 2, valKeys.cend()),
1655 };
1656
1657 auto addPublishedList = [&, this](int i) {
1658 auto const publisherSecret = randomSecretKey();
1659 auto const publisherPublic =
1660 derivePublicKey(KeyType::ed25519, publisherSecret);
1661 auto const pubSigningKeys = randomKeyPair(KeyType::secp256k1);
1662 auto const manifest = base64_encode(makeManifestString(
1663 publisherPublic,
1664 publisherSecret,
1665 pubSigningKeys.first,
1666 pubSigningKeys.second,
1667 1));
1668
1669 std::vector<std::string> cfgPublishers(
1670 {strHex(publisherPublic)});
1671 std::vector<std::string> emptyCfgKeys;
1672
1673 // Threshold of 1 will result in a union of all the lists
1674 BEAST_EXPECT(trustedKeys->load(
1675 {}, emptyCfgKeys, cfgPublishers, std::size_t(1)));
1676
1677 auto const version = 1;
1678 auto const sequence = 1;
1679 using namespace std::chrono_literals;
1680 NetClock::time_point const validUntil =
1681 env.timeKeeper().now() + 3600s;
1682 std::vector<Validator> localKeys{
1683 locals[i].first, locals[i].second};
1684 auto const blob = makeList(
1685 localKeys, sequence, validUntil.time_since_epoch().count());
1686 auto const sig = signList(blob, pubSigningKeys);
1687
1688 BEAST_EXPECT(
1689 ListDisposition::accepted ==
1690 trustedKeys
1691 ->applyLists(
1692 manifest, version, {{blob, sig, {}}}, siteUri)
1693 .bestDisposition());
1694 };
1695
1696 // Apply multiple published lists
1697 for (auto i = 0; i < publishers; ++i)
1698 addPublishedList(i);
1699 BEAST_EXPECT(trustedKeys->getListThreshold() == 1);
1700
1701 TrustChanges changes = trustedKeys->updateTrusted(
1702 activeValidators,
1703 env.timeKeeper().now(),
1704 env.app().getOPs(),
1705 env.app().overlay(),
1706 env.app().getHashRouter());
1707
1708 BEAST_EXPECT(
1709 trustedKeys->quorum() == std::ceil(valKeys.size() * 0.8f));
1710
1711 hash_set<NodeID> added;
1712 for (auto const& val : valKeys)
1713 {
1714 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
1715 added.insert(calcNodeID(val.masterPublic));
1716 }
1717 BEAST_EXPECT(changes.added == added);
1718 BEAST_EXPECT(changes.removed.empty());
1719 }
1720 {
1721 // Trusted set should include validators from intersection of lists
1722 ManifestCache manifests;
1723 auto trustedKeys = std::make_unique<ValidatorList>(
1724 manifests,
1725 manifests,
1726 env.timeKeeper(),
1727 app.config().legacy("database_path"),
1728 env.journal);
1729
1730 hash_set<NodeID> activeValidators;
1731 std::vector<Validator> valKeys;
1732 valKeys.reserve(maxKeys);
1733
1734 while (valKeys.size() != maxKeys)
1735 {
1736 valKeys.push_back(randomValidator());
1737 activeValidators.emplace(
1738 calcNodeID(valKeys.back().masterPublic));
1739 }
1740
1741 // locals[0]: from 0 to maxKeys - 4
1742 // locals[1]: from 1 to maxKeys - 2
1743 // locals[2]: from 2 to maxKeys
1744 // interesection of at least 2: same as locals[1]
1745 // intersection when 1 is dropped: from 2 to maxKeys - 4
1746 constexpr static int publishers = 3;
1747 std::array<
1748 std::pair<
1749 decltype(valKeys)::const_iterator,
1750 decltype(valKeys)::const_iterator>,
1751 publishers>
1752 locals = {
1753 std::make_pair(valKeys.cbegin(), valKeys.cend() - 4),
1754 std::make_pair(valKeys.cbegin() + 1, valKeys.cend() - 2),
1755 std::make_pair(valKeys.cbegin() + 2, valKeys.cend()),
1756 };
1757
1758 auto addPublishedList = [&, this](
1759 int i,
1760 NetClock::time_point& validUntil1,
1761 NetClock::time_point& validUntil2) {
1762 auto const publisherSecret = randomSecretKey();
1763 auto const publisherPublic =
1764 derivePublicKey(KeyType::ed25519, publisherSecret);
1765 auto const pubSigningKeys = randomKeyPair(KeyType::secp256k1);
1766 auto const manifest = base64_encode(makeManifestString(
1767 publisherPublic,
1768 publisherSecret,
1769 pubSigningKeys.first,
1770 pubSigningKeys.second,
1771 1));
1772
1773 std::vector<std::string> cfgPublishers(
1774 {strHex(publisherPublic)});
1775 std::vector<std::string> emptyCfgKeys;
1776
1777 BEAST_EXPECT(
1778 trustedKeys->load({}, emptyCfgKeys, cfgPublishers));
1779
1780 auto const version = 1;
1781 auto const sequence = 1;
1782 using namespace std::chrono_literals;
1783 // Want to drop 1 sooner
1784 NetClock::time_point const validUntil = env.timeKeeper().now() +
1785 (i == 2 ? 120s
1786 : i == 1 ? 60s
1787 : 3600s);
1788 if (i == 1)
1789 validUntil1 = validUntil;
1790 else if (i == 2)
1791 validUntil2 = validUntil;
1792 std::vector<Validator> localKeys{
1793 locals[i].first, locals[i].second};
1794 auto const blob = makeList(
1795 localKeys, sequence, validUntil.time_since_epoch().count());
1796 auto const sig = signList(blob, pubSigningKeys);
1797
1798 BEAST_EXPECT(
1799 ListDisposition::accepted ==
1800 trustedKeys
1801 ->applyLists(
1802 manifest, version, {{blob, sig, {}}}, siteUri)
1803 .bestDisposition());
1804 };
1805
1806 // Apply multiple published lists
1807 // validUntil1 is expiration time for locals[1]
1808 NetClock::time_point validUntil1, validUntil2;
1809 for (auto i = 0; i < publishers; ++i)
1810 addPublishedList(i, validUntil1, validUntil2);
1811 BEAST_EXPECT(trustedKeys->getListThreshold() == 2);
1812
1813 TrustChanges changes = trustedKeys->updateTrusted(
1814 activeValidators,
1815 env.timeKeeper().now(),
1816 env.app().getOPs(),
1817 env.app().overlay(),
1818 env.app().getHashRouter());
1819
1820 BEAST_EXPECT(
1821 trustedKeys->quorum() ==
1822 std::ceil((valKeys.size() - 3) * 0.8f));
1823
1824 for (auto const& val : valKeys)
1825 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
1826
1827 hash_set<NodeID> added;
1828 for (std::size_t i = 0; i < maxKeys; ++i)
1829 {
1830 auto const& val = valKeys[i];
1831 if (i >= 1 && i < maxKeys - 2)
1832 {
1833 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
1834 added.insert(calcNodeID(val.masterPublic));
1835 }
1836 else
1837 BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic));
1838 }
1839 BEAST_EXPECT(changes.added == added);
1840 BEAST_EXPECT(changes.removed.empty());
1841
1842 // Expire locals[1]
1843 env.timeKeeper().set(validUntil1);
1844 changes = trustedKeys->updateTrusted(
1845 activeValidators,
1846 env.timeKeeper().now(),
1847 env.app().getOPs(),
1848 env.app().overlay(),
1849 env.app().getHashRouter());
1850
1851 BEAST_EXPECT(
1852 trustedKeys->quorum() ==
1853 std::ceil((valKeys.size() - 6) * 0.8f));
1854
1855 for (auto const& val : valKeys)
1856 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
1857
1858 hash_set<NodeID> removed;
1859 for (std::size_t i = 0; i < maxKeys; ++i)
1860 {
1861 auto const& val = valKeys[i];
1862 if (i >= 2 && i < maxKeys - 4)
1863 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
1864 else
1865 {
1866 BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic));
1867 if (i >= 1 && i < maxKeys - 2)
1868 removed.insert(calcNodeID(val.masterPublic));
1869 }
1870 }
1871
1872 BEAST_EXPECT(changes.added.empty());
1873 BEAST_EXPECT(changes.removed == removed);
1874
1875 // Expire locals[2], which removes all validators
1876 env.timeKeeper().set(validUntil2);
1877 changes = trustedKeys->updateTrusted(
1878 activeValidators,
1879 env.timeKeeper().now(),
1880 env.app().getOPs(),
1881 env.app().overlay(),
1882 env.app().getHashRouter());
1883
1884 BEAST_EXPECT(
1885 trustedKeys->quorum() ==
1887
1888 removed.clear();
1889 for (std::size_t i = 0; i < maxKeys; ++i)
1890 {
1891 auto const& val = valKeys[i];
1892 if (i < maxKeys - 4)
1893 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
1894 else
1895 BEAST_EXPECT(!trustedKeys->listed(val.masterPublic));
1896
1897 BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic));
1898 if (i >= 2 && i < maxKeys - 4)
1899 removed.insert(calcNodeID(val.masterPublic));
1900 }
1901
1902 BEAST_EXPECT(changes.added.empty());
1903 BEAST_EXPECT(changes.removed == removed);
1904 }
1905 }
1906
1907 void
1909 {
1910 testcase("Expires");
1911
1912 std::string const siteUri = "testExpires.test";
1913
1914 jtx::Env env(*this);
1915 auto& app = env.app();
1916
1917 auto toStr = [](PublicKey const& publicKey) {
1918 return toBase58(TokenType::NodePublic, publicKey);
1919 };
1920
1921 // Config listed keys
1922 {
1923 ManifestCache manifests;
1924 auto trustedKeys = std::make_unique<ValidatorList>(
1925 manifests,
1926 manifests,
1927 env.timeKeeper(),
1928 app.config().legacy("database_path"),
1929 env.journal);
1930
1931 // Empty list has no expiration
1932 BEAST_EXPECT(trustedKeys->expires() == std::nullopt);
1933
1934 // Config listed keys have maximum expiry
1935 PublicKey localCfgListed = randomNode();
1936 trustedKeys->load({}, {toStr(localCfgListed)}, {});
1937 BEAST_EXPECT(
1938 trustedKeys->expires() &&
1939 trustedKeys->expires().value() == NetClock::time_point::max());
1940 BEAST_EXPECT(trustedKeys->listed(localCfgListed));
1941 }
1942
1943 // Published keys with expirations
1944 {
1945 ManifestCache manifests;
1946 auto trustedKeys = std::make_unique<ValidatorList>(
1947 manifests,
1948 manifests,
1949 env.app().timeKeeper(),
1950 app.config().legacy("database_path"),
1951 env.journal);
1952
1953 std::vector<Validator> validators = {randomValidator()};
1954 hash_set<NodeID> activeValidators;
1955 for (Validator const& val : validators)
1956 activeValidators.insert(calcNodeID(val.masterPublic));
1957 // Store prepared list data to control when it is applied
1958 struct PreparedList
1959 {
1960 PublicKey publisherPublic;
1963 int version;
1965 };
1966
1967 using namespace std::chrono_literals;
1968 auto addPublishedList = [this, &env, &trustedKeys, &validators]() {
1969 auto const publisherSecret = randomSecretKey();
1970 auto const publisherPublic =
1971 derivePublicKey(KeyType::ed25519, publisherSecret);
1972 auto const pubSigningKeys = randomKeyPair(KeyType::secp256k1);
1973 auto const manifest = base64_encode(makeManifestString(
1974 publisherPublic,
1975 publisherSecret,
1976 pubSigningKeys.first,
1977 pubSigningKeys.second,
1978 1));
1979
1980 std::vector<std::string> cfgPublishers(
1981 {strHex(publisherPublic)});
1982 std::vector<std::string> emptyCfgKeys;
1983
1984 BEAST_EXPECT(
1985 trustedKeys->load({}, emptyCfgKeys, cfgPublishers));
1986
1987 auto const version = 2;
1988 auto const sequence1 = 1;
1989 NetClock::time_point const expiration1 =
1990 env.timeKeeper().now() + 1800s;
1991 auto const blob1 = makeList(
1992 validators,
1993 sequence1,
1994 expiration1.time_since_epoch().count());
1995 auto const sig1 = signList(blob1, pubSigningKeys);
1996
1997 NetClock::time_point const effective2 = expiration1 - 300s;
1998 NetClock::time_point const expiration2 = effective2 + 1800s;
1999 auto const sequence2 = 2;
2000 auto const blob2 = makeList(
2001 validators,
2002 sequence2,
2003 expiration2.time_since_epoch().count(),
2004 effective2.time_since_epoch().count());
2005 auto const sig2 = signList(blob2, pubSigningKeys);
2006
2007 return PreparedList{
2008 publisherPublic,
2009 manifest,
2010 {{blob1, sig1, {}}, {blob2, sig2, {}}},
2011 version,
2012 {expiration1, expiration2}};
2013 };
2014
2015 // Configure two publishers and prepare 2 lists
2016 PreparedList prep1 = addPublishedList();
2017 env.timeKeeper().set(env.timeKeeper().now() + 200s);
2018 PreparedList prep2 = addPublishedList();
2019
2020 // Initially, no list has been published, so no known expiration
2021 BEAST_EXPECT(trustedKeys->expires() == std::nullopt);
2022
2023 // Apply first list
2024 checkResult(
2025 trustedKeys->applyLists(
2026 prep1.manifest, prep1.version, prep1.blobs, siteUri),
2027 prep1.publisherPublic,
2028 ListDisposition::pending,
2029 ListDisposition::accepted);
2030
2031 // One list still hasn't published, so expiration is still
2032 // unknown
2033 BEAST_EXPECT(trustedKeys->expires() == std::nullopt);
2034
2035 // Apply second list
2036 checkResult(
2037 trustedKeys->applyLists(
2038 prep2.manifest, prep2.version, prep2.blobs, siteUri),
2039 prep2.publisherPublic,
2040 ListDisposition::pending,
2041 ListDisposition::accepted);
2042 // We now have loaded both lists, so expiration is known
2043 BEAST_EXPECT(
2044 trustedKeys->expires() &&
2045 trustedKeys->expires().value() == prep1.expirations.back());
2046
2047 // Advance past the first list's LAST validFrom date. It remains
2048 // the earliest validUntil, while rotating in the second list
2049 {
2050 env.timeKeeper().set(prep1.expirations.front() - 1s);
2051 auto changes = trustedKeys->updateTrusted(
2052 activeValidators,
2053 env.timeKeeper().now(),
2054 env.app().getOPs(),
2055 env.app().overlay(),
2056 env.app().getHashRouter());
2057 BEAST_EXPECT(
2058 trustedKeys->expires() &&
2059 trustedKeys->expires().value() == prep1.expirations.back());
2060 BEAST_EXPECT(!changes.added.empty());
2061 BEAST_EXPECT(changes.removed.empty());
2062 }
2063
2064 // Advance past the first list's LAST validUntil, but it remains
2065 // the earliest validUntil, while being invalidated
2066 {
2067 env.timeKeeper().set(prep1.expirations.back() + 1s);
2068 auto changes = trustedKeys->updateTrusted(
2069 activeValidators,
2070 env.timeKeeper().now(),
2071 env.app().getOPs(),
2072 env.app().overlay(),
2073 env.app().getHashRouter());
2074 BEAST_EXPECT(
2075 trustedKeys->expires() &&
2076 trustedKeys->expires().value() == prep1.expirations.back());
2077 BEAST_EXPECT(changes.added.empty());
2078 BEAST_EXPECT(changes.removed.empty());
2079 }
2080 }
2081 }
2082
2083 void
2085 {
2086 testcase("NegativeUNL");
2087 jtx::Env env(*this);
2088 ManifestCache manifests;
2089
2090 auto createValidatorList =
2091 [&](std::uint32_t vlSize,
2092 std::optional<std::size_t> minimumQuorum = {})
2094 auto trustedKeys = std::make_shared<ValidatorList>(
2095 manifests,
2096 manifests,
2097 env.timeKeeper(),
2098 env.app().config().legacy("database_path"),
2099 env.journal,
2100 minimumQuorum);
2101
2102 std::vector<std::string> cfgPublishers;
2104 hash_set<NodeID> activeValidators;
2105 cfgKeys.reserve(vlSize);
2106 while (cfgKeys.size() < cfgKeys.capacity())
2107 {
2108 auto const valKey = randomNode();
2109 cfgKeys.push_back(toBase58(TokenType::NodePublic, valKey));
2110 activeValidators.emplace(calcNodeID(valKey));
2111 }
2112 if (trustedKeys->load({}, cfgKeys, cfgPublishers))
2113 {
2114 trustedKeys->updateTrusted(
2115 activeValidators,
2116 env.timeKeeper().now(),
2117 env.app().getOPs(),
2118 env.app().overlay(),
2119 env.app().getHashRouter());
2120 if (minimumQuorum == trustedKeys->quorum() ||
2121 trustedKeys->quorum() == std::ceil(cfgKeys.size() * 0.8f))
2122 return trustedKeys;
2123 }
2124 return nullptr;
2125 };
2126
2127 /*
2128 * Test NegativeUNL
2129 * == Combinations ==
2130 * -- UNL size: 34, 35, 57
2131 * -- nUNL size: 0%, 20%, 30%, 50%
2132 *
2133 * == with UNL size 60
2134 * -- set == get,
2135 * -- check quorum, with nUNL size: 0, 12, 30, 18
2136 * -- nUNL overlap: |nUNL - UNL| = 5, with nUNL size: 18
2137 * -- with command line minimumQuorum = 50%,
2138 * seen_reliable affected by nUNL
2139 */
2140
2141 {
2142 hash_set<NodeID> activeValidators;
2143 //== Combinations ==
2144 std::array<std::uint32_t, 4> unlSizes = {34, 35, 39, 60};
2145 std::array<std::uint32_t, 4> nUnlPercent = {0, 20, 30, 50};
2146 for (auto us : unlSizes)
2147 {
2148 for (auto np : nUnlPercent)
2149 {
2150 auto validators = createValidatorList(us);
2151 BEAST_EXPECT(validators);
2152 if (validators)
2153 {
2154 std::uint32_t nUnlSize = us * np / 100;
2155 auto unl = validators->getTrustedMasterKeys();
2157 auto it = unl.begin();
2158 for (std::uint32_t i = 0; i < nUnlSize; ++i)
2159 {
2160 nUnl.insert(*it);
2161 ++it;
2162 }
2163 validators->setNegativeUNL(nUnl);
2164 validators->updateTrusted(
2165 activeValidators,
2166 env.timeKeeper().now(),
2167 env.app().getOPs(),
2168 env.app().overlay(),
2169 env.app().getHashRouter());
2170 BEAST_EXPECT(
2171 validators->quorum() ==
2172 static_cast<std::size_t>(std::ceil(
2173 std::max((us - nUnlSize) * 0.8f, us * 0.6f))));
2174 }
2175 }
2176 }
2177 }
2178
2179 {
2180 //== with UNL size 60
2181 auto validators = createValidatorList(60);
2182 BEAST_EXPECT(validators);
2183 if (validators)
2184 {
2185 hash_set<NodeID> activeValidators;
2186 auto unl = validators->getTrustedMasterKeys();
2187 BEAST_EXPECT(unl.size() == 60);
2188 {
2189 //-- set == get,
2190 //-- check quorum, with nUNL size: 0, 30, 18, 12
2191 auto nUnlChange = [&](std::uint32_t nUnlSize,
2192 std::uint32_t quorum) -> bool {
2194 auto it = unl.begin();
2195 for (std::uint32_t i = 0; i < nUnlSize; ++i)
2196 {
2197 nUnl.insert(*it);
2198 ++it;
2199 }
2200 validators->setNegativeUNL(nUnl);
2201 auto nUnl_temp = validators->getNegativeUNL();
2202 if (nUnl_temp.size() == nUnl.size())
2203 {
2204 for (auto& n : nUnl_temp)
2205 {
2206 if (nUnl.find(n) == nUnl.end())
2207 return false;
2208 }
2209 validators->updateTrusted(
2210 activeValidators,
2211 env.timeKeeper().now(),
2212 env.app().getOPs(),
2213 env.app().overlay(),
2214 env.app().getHashRouter());
2215 return validators->quorum() == quorum;
2216 }
2217 return false;
2218 };
2219 BEAST_EXPECT(nUnlChange(0, 48));
2220 BEAST_EXPECT(nUnlChange(30, 36));
2221 BEAST_EXPECT(nUnlChange(18, 36));
2222 BEAST_EXPECT(nUnlChange(12, 39));
2223 }
2224
2225 {
2226 // nUNL overlap: |nUNL - UNL| = 5, with nUNL size:
2227 // 18
2228 auto nUnl = validators->getNegativeUNL();
2229 BEAST_EXPECT(nUnl.size() == 12);
2230 std::size_t ss = 33;
2232 data[0] = 0xED;
2233 for (int i = 0; i < 6; ++i)
2234 {
2235 Slice s(data.data(), ss);
2236 data[1]++;
2237 nUnl.emplace(s);
2238 }
2239 validators->setNegativeUNL(nUnl);
2240 validators->updateTrusted(
2241 activeValidators,
2242 env.timeKeeper().now(),
2243 env.app().getOPs(),
2244 env.app().overlay(),
2245 env.app().getHashRouter());
2246 BEAST_EXPECT(validators->quorum() == 39);
2247 }
2248 }
2249 }
2250
2251 {
2252 //== with UNL size 60
2253 //-- with command line minimumQuorum = 50%,
2254 // seen_reliable affected by nUNL
2255 auto validators = createValidatorList(60, 30);
2256 BEAST_EXPECT(validators);
2257 if (validators)
2258 {
2259 hash_set<NodeID> activeValidators;
2260 hash_set<PublicKey> unl = validators->getTrustedMasterKeys();
2261 auto it = unl.begin();
2262 for (std::uint32_t i = 0; i < 50; ++i)
2263 {
2264 activeValidators.insert(calcNodeID(*it));
2265 ++it;
2266 }
2267 validators->updateTrusted(
2268 activeValidators,
2269 env.timeKeeper().now(),
2270 env.app().getOPs(),
2271 env.app().overlay(),
2272 env.app().getHashRouter());
2273 BEAST_EXPECT(validators->quorum() == 30);
2275 it = unl.begin();
2276 for (std::uint32_t i = 0; i < 20; ++i)
2277 {
2278 nUnl.insert(*it);
2279 ++it;
2280 }
2281 validators->setNegativeUNL(nUnl);
2282 validators->updateTrusted(
2283 activeValidators,
2284 env.timeKeeper().now(),
2285 env.app().getOPs(),
2286 env.app().overlay(),
2287 env.app().getHashRouter());
2288 BEAST_EXPECT(validators->quorum() == 30);
2289 }
2290 }
2291 }
2292
2293 void
2295 {
2296 testcase("Sha512 hashing");
2297 // Tests that ValidatorList hash_append helpers with a single blob
2298 // returns the same result as ripple::Sha512Half used by the
2299 // TMValidatorList protocol message handler
2300 std::string const manifest = "This is not really a manifest";
2301 std::string const blob = "This is not really a blob";
2302 std::string const signature = "This is not really a signature";
2303 std::uint32_t const version = 1;
2304
2305 auto const global = sha512Half(manifest, blob, signature, version);
2306 BEAST_EXPECT(!!global);
2307
2308 std::vector<ValidatorBlobInfo> blobVector(1);
2309 blobVector[0].blob = blob;
2310 blobVector[0].signature = signature;
2311 BEAST_EXPECT(global == sha512Half(manifest, blobVector, version));
2312 BEAST_EXPECT(global != sha512Half(signature, blobVector, version));
2313
2314 {
2316 {99, blobVector[0]}};
2317 BEAST_EXPECT(global == sha512Half(manifest, blobMap, version));
2318 BEAST_EXPECT(global != sha512Half(blob, blobMap, version));
2319 }
2320
2321 {
2322 protocol::TMValidatorList msg1;
2323 msg1.set_manifest(manifest);
2324 msg1.set_blob(blob);
2325 msg1.set_signature(signature);
2326 msg1.set_version(version);
2327 BEAST_EXPECT(global == sha512Half(msg1));
2328 msg1.set_signature(blob);
2329 BEAST_EXPECT(global != sha512Half(msg1));
2330 }
2331
2332 {
2333 protocol::TMValidatorListCollection msg2;
2334 msg2.set_manifest(manifest);
2335 msg2.set_version(version);
2336 auto& bi = *msg2.add_blobs();
2337 bi.set_blob(blob);
2338 bi.set_signature(signature);
2339 BEAST_EXPECT(global == sha512Half(msg2));
2340 bi.set_manifest(manifest);
2341 BEAST_EXPECT(global != sha512Half(msg2));
2342 }
2343 }
2344
2345 void
2347 {
2348 testcase("Build and split messages");
2349
2350 std::uint32_t const manifestCutoff = 7;
2351 auto extractHeader = [this](Message& message) {
2352 auto const& buffer =
2353 message.getBuffer(compression::Compressed::Off);
2354
2355 boost::beast::multi_buffer buffers;
2356
2357 // simulate multi-buffer
2358 auto start = buffer.begin();
2359 auto end = buffer.end();
2360 std::vector<std::uint8_t> slice(start, end);
2361 buffers.commit(boost::asio::buffer_copy(
2362 buffers.prepare(slice.size()), boost::asio::buffer(slice)));
2363
2364 boost::system::error_code ec;
2365 auto header =
2366 detail::parseMessageHeader(ec, buffers.data(), buffers.size());
2367 BEAST_EXPECT(!ec);
2368 return std::make_pair(header, buffers);
2369 };
2370 auto extractProtocolMessage1 = [this,
2371 &extractHeader](Message& message) {
2372 auto [header, buffers] = extractHeader(message);
2373 if (BEAST_EXPECT(header) &&
2374 BEAST_EXPECT(header->message_type == protocol::mtVALIDATORLIST))
2375 {
2376 auto const msg =
2377 detail::parseMessageContent<protocol::TMValidatorList>(
2378 *header, buffers.data());
2379 BEAST_EXPECT(msg);
2380 return msg;
2381 }
2383 };
2384 auto extractProtocolMessage2 = [this,
2385 &extractHeader](Message& message) {
2386 auto [header, buffers] = extractHeader(message);
2387 if (BEAST_EXPECT(header) &&
2388 BEAST_EXPECT(
2389 header->message_type ==
2390 protocol::mtVALIDATORLISTCOLLECTION))
2391 {
2392 auto const msg = detail::parseMessageContent<
2393 protocol::TMValidatorListCollection>(
2394 *header, buffers.data());
2395 BEAST_EXPECT(msg);
2396 return msg;
2397 }
2399 };
2400 auto verifyMessage =
2401 [this,
2402 manifestCutoff,
2403 &extractProtocolMessage1,
2404 &extractProtocolMessage2](
2405 auto const version,
2406 auto const& manifest,
2407 auto const& blobInfos,
2408 auto const& messages,
2410 expectedInfo) {
2411 BEAST_EXPECT(messages.size() == expectedInfo.size());
2412 auto msgIter = expectedInfo.begin();
2413 for (auto const& messageWithHash : messages)
2414 {
2415 if (!BEAST_EXPECT(msgIter != expectedInfo.end()))
2416 break;
2417 if (!BEAST_EXPECT(messageWithHash.message))
2418 continue;
2419 auto const& expectedSeqs = msgIter->second;
2420 auto seqIter = expectedSeqs.begin();
2421 auto const size =
2422 messageWithHash.message
2423 ->getBuffer(compression::Compressed::Off)
2424 .size();
2425 // This size is arbitrary, but shouldn't change
2426 BEAST_EXPECT(size == msgIter->first);
2427 if (expectedSeqs.size() == 1)
2428 {
2429 auto const msg =
2430 extractProtocolMessage1(*messageWithHash.message);
2431 auto const expectedVersion = 1;
2432 if (BEAST_EXPECT(msg))
2433 {
2434 BEAST_EXPECT(msg->version() == expectedVersion);
2435 if (!BEAST_EXPECT(seqIter != expectedSeqs.end()))
2436 continue;
2437 auto const& expectedBlob = blobInfos.at(*seqIter);
2438 BEAST_EXPECT(
2439 (*seqIter < manifestCutoff) ==
2440 !!expectedBlob.manifest);
2441 auto const expectedManifest =
2442 *seqIter < manifestCutoff &&
2443 expectedBlob.manifest
2444 ? *expectedBlob.manifest
2445 : manifest;
2446 BEAST_EXPECT(msg->manifest() == expectedManifest);
2447 BEAST_EXPECT(msg->blob() == expectedBlob.blob);
2448 BEAST_EXPECT(
2449 msg->signature() == expectedBlob.signature);
2450 ++seqIter;
2451 BEAST_EXPECT(seqIter == expectedSeqs.end());
2452
2453 BEAST_EXPECT(
2454 messageWithHash.hash ==
2455 sha512Half(
2456 expectedManifest,
2457 expectedBlob.blob,
2458 expectedBlob.signature,
2459 expectedVersion));
2460 }
2461 }
2462 else
2463 {
2464 std::vector<ValidatorBlobInfo> hashingBlobs;
2465 hashingBlobs.reserve(msgIter->second.size());
2466
2467 auto const msg =
2468 extractProtocolMessage2(*messageWithHash.message);
2469 if (BEAST_EXPECT(msg))
2470 {
2471 BEAST_EXPECT(msg->version() == version);
2472 BEAST_EXPECT(msg->manifest() == manifest);
2473 for (auto const& blobInfo : msg->blobs())
2474 {
2475 if (!BEAST_EXPECT(
2476 seqIter != expectedSeqs.end()))
2477 break;
2478 auto const& expectedBlob =
2479 blobInfos.at(*seqIter);
2480 hashingBlobs.push_back(expectedBlob);
2481 BEAST_EXPECT(
2482 blobInfo.has_manifest() ==
2483 !!expectedBlob.manifest);
2484 BEAST_EXPECT(
2485 blobInfo.has_manifest() ==
2486 (*seqIter < manifestCutoff));
2487
2488 if (*seqIter < manifestCutoff)
2489 BEAST_EXPECT(
2490 blobInfo.manifest() ==
2491 *expectedBlob.manifest);
2492 BEAST_EXPECT(
2493 blobInfo.blob() == expectedBlob.blob);
2494 BEAST_EXPECT(
2495 blobInfo.signature() ==
2496 expectedBlob.signature);
2497 ++seqIter;
2498 }
2499 BEAST_EXPECT(seqIter == expectedSeqs.end());
2500 }
2501 BEAST_EXPECT(
2502 messageWithHash.hash ==
2503 sha512Half(manifest, hashingBlobs, version));
2504 }
2505 ++msgIter;
2506 }
2507 BEAST_EXPECT(msgIter == expectedInfo.end());
2508 };
2509 auto verifyBuildMessages =
2510 [this](
2512 std::size_t expectedSequence,
2513 std::size_t expectedSize) {
2514 BEAST_EXPECT(result.first == expectedSequence);
2515 BEAST_EXPECT(result.second == expectedSize);
2516 };
2517
2518 std::string const manifest = "This is not a manifest";
2519 std::uint32_t const version = 2;
2520 // Mutable so items can be removed in later tests.
2521 auto const blobInfos = [manifestCutoff = manifestCutoff]() {
2523
2524 for (auto seq : {5, 6, 7, 10, 12})
2525 {
2526 auto& b = bis[seq];
2528 s << "This is not a blob with sequence " << seq;
2529 b.blob = s.str();
2530 s.str(std::string());
2531 s << "This is not a signature for sequence " << seq;
2532 b.signature = s.str();
2533 if (seq < manifestCutoff)
2534 {
2535 // add a manifest for the "early" blobs
2536 s.str(std::string());
2537 s << "This is not manifest " << seq;
2538 b.manifest = s.str();
2539 }
2540 }
2541 return bis;
2542 }();
2543 auto const maxSequence = blobInfos.rbegin()->first;
2544 BEAST_EXPECT(maxSequence == 12);
2545
2547
2548 // Version 1
2549
2550 // This peer has a VL ahead of our "current"
2551 verifyBuildMessages(
2552 ValidatorList::buildValidatorListMessages(
2553 1, 8, maxSequence, version, manifest, blobInfos, messages),
2554 0,
2555 0);
2556 BEAST_EXPECT(messages.size() == 0);
2557
2558 // Don't repeat the work if messages is populated, even though the
2559 // peerSequence provided indicates it should. Note that this
2560 // situation is contrived for this test and should never happen in
2561 // real code.
2562 messages.emplace_back();
2563 verifyBuildMessages(
2564 ValidatorList::buildValidatorListMessages(
2565 1, 3, maxSequence, version, manifest, blobInfos, messages),
2566 5,
2567 0);
2568 BEAST_EXPECT(messages.size() == 1 && !messages.front().message);
2569
2570 // Generate a version 1 message
2571 messages.clear();
2572 verifyBuildMessages(
2573 ValidatorList::buildValidatorListMessages(
2574 1, 3, maxSequence, version, manifest, blobInfos, messages),
2575 5,
2576 1);
2577 if (BEAST_EXPECT(messages.size() == 1) &&
2578 BEAST_EXPECT(messages.front().message))
2579 {
2580 auto const& messageWithHash = messages.front();
2581 auto const msg = extractProtocolMessage1(*messageWithHash.message);
2582 auto const size =
2583 messageWithHash.message->getBuffer(compression::Compressed::Off)
2584 .size();
2585 // This size is arbitrary, but shouldn't change
2586 BEAST_EXPECT(size == 108);
2587 auto const& expected = blobInfos.at(5);
2588 if (BEAST_EXPECT(msg))
2589 {
2590 BEAST_EXPECT(msg->version() == 1);
2591 BEAST_EXPECT(msg->manifest() == *expected.manifest);
2592 BEAST_EXPECT(msg->blob() == expected.blob);
2593 BEAST_EXPECT(msg->signature() == expected.signature);
2594 }
2595 BEAST_EXPECT(
2596 messageWithHash.hash ==
2597 sha512Half(
2598 *expected.manifest, expected.blob, expected.signature, 1));
2599 }
2600
2601 // Version 2
2602
2603 messages.clear();
2604
2605 // This peer has a VL ahead of us.
2606 verifyBuildMessages(
2607 ValidatorList::buildValidatorListMessages(
2608 2,
2609 maxSequence * 2,
2610 maxSequence,
2611 version,
2612 manifest,
2613 blobInfos,
2614 messages),
2615 0,
2616 0);
2617 BEAST_EXPECT(messages.size() == 0);
2618
2619 // Don't repeat the work if messages is populated, even though the
2620 // peerSequence provided indicates it should. Note that this
2621 // situation is contrived for this test and should never happen in
2622 // real code.
2623 messages.emplace_back();
2624 verifyBuildMessages(
2625 ValidatorList::buildValidatorListMessages(
2626 2, 3, maxSequence, version, manifest, blobInfos, messages),
2627 maxSequence,
2628 0);
2629 BEAST_EXPECT(messages.size() == 1 && !messages.front().message);
2630
2631 // Generate a version 2 message. Don't send the current
2632 messages.clear();
2633 verifyBuildMessages(
2634 ValidatorList::buildValidatorListMessages(
2635 2, 5, maxSequence, version, manifest, blobInfos, messages),
2636 maxSequence,
2637 4);
2638 verifyMessage(
2639 version, manifest, blobInfos, messages, {{372, {6, 7, 10, 12}}});
2640
2641 // Test message splitting on size limits.
2642
2643 // Set a limit that should give two messages
2644 messages.clear();
2645 verifyBuildMessages(
2646 ValidatorList::buildValidatorListMessages(
2647 2, 5, maxSequence, version, manifest, blobInfos, messages, 300),
2648 maxSequence,
2649 4);
2650 verifyMessage(
2651 version,
2652 manifest,
2653 blobInfos,
2654 messages,
2655 {{212, {6, 7}}, {192, {10, 12}}});
2656
2657 // Set a limit between the size of the two earlier messages so one
2658 // will split and the other won't
2659 messages.clear();
2660 verifyBuildMessages(
2661 ValidatorList::buildValidatorListMessages(
2662 2, 5, maxSequence, version, manifest, blobInfos, messages, 200),
2663 maxSequence,
2664 4);
2665 verifyMessage(
2666 version,
2667 manifest,
2668 blobInfos,
2669 messages,
2670 {{108, {6}}, {108, {7}}, {192, {10, 12}}});
2671
2672 // Set a limit so that all the VLs are sent individually
2673 messages.clear();
2674 verifyBuildMessages(
2675 ValidatorList::buildValidatorListMessages(
2676 2, 5, maxSequence, version, manifest, blobInfos, messages, 150),
2677 maxSequence,
2678 4);
2679 verifyMessage(
2680 version,
2681 manifest,
2682 blobInfos,
2683 messages,
2684 {{108, {6}}, {108, {7}}, {110, {10}}, {110, {12}}});
2685
2686 // Set a limit smaller than some of the messages. Because single
2687 // messages send regardless, they will all still be sent
2688 messages.clear();
2689 verifyBuildMessages(
2690 ValidatorList::buildValidatorListMessages(
2691 2, 5, maxSequence, version, manifest, blobInfos, messages, 108),
2692 maxSequence,
2693 4);
2694 verifyMessage(
2695 version,
2696 manifest,
2697 blobInfos,
2698 messages,
2699 {{108, {6}}, {108, {7}}, {110, {10}}, {110, {12}}});
2700 }
2701
2702 void
2704 {
2705 testcase("Test quorum disabled");
2706
2707 std::string const siteUri = "testQuorumDisabled.test";
2708 jtx::Env env(*this);
2709 auto& app = env.app();
2710
2711 constexpr std::size_t maxKeys = 20;
2712 hash_set<NodeID> activeValidators;
2713 std::vector<Validator> valKeys;
2714 while (valKeys.size() != maxKeys)
2715 {
2716 valKeys.push_back(randomValidator());
2717 activeValidators.emplace(calcNodeID(valKeys.back().masterPublic));
2718 }
2719
2720 struct Publisher
2721 {
2722 bool revoked;
2723 PublicKey pubKey;
2726 NetClock::time_point expiry = {};
2727 };
2728
2729 // Create ValidatorList with a set of countTotal publishers, of which
2730 // first countRevoked are revoked and the last one expires early
2731 auto makeValidatorList = [&, this](
2732 std::size_t countTotal,
2733 std::size_t countRevoked,
2734 std::size_t listThreshold,
2735 ManifestCache& pubManifests,
2736 ManifestCache& valManifests,
2738 std::vector<Publisher>& publishers // out
2740 auto result = std::make_unique<ValidatorList>(
2741 valManifests,
2742 pubManifests,
2743 env.timeKeeper(),
2744 app.config().legacy("database_path"),
2745 env.journal);
2746
2747 std::vector<std::string> cfgPublishers;
2748 for (std::size_t i = 0; i < countTotal; ++i)
2749 {
2750 auto const publisherSecret = randomSecretKey();
2751 auto const publisherPublic =
2752 derivePublicKey(KeyType::ed25519, publisherSecret);
2753 auto const pubSigningKeys = randomKeyPair(KeyType::secp256k1);
2754 cfgPublishers.push_back(strHex(publisherPublic));
2755
2756 constexpr auto revoked =
2758 auto const manifest = base64_encode(makeManifestString(
2759 publisherPublic,
2760 publisherSecret,
2761 pubSigningKeys.first,
2762 pubSigningKeys.second,
2763 i < countRevoked ? revoked : 1));
2764 publishers.push_back(Publisher{
2765 i < countRevoked,
2766 publisherPublic,
2767 pubSigningKeys,
2768 manifest});
2769 }
2770
2771 std::vector<std::string> const emptyCfgKeys;
2772 auto threshold =
2773 listThreshold > 0 ? std::optional(listThreshold) : std::nullopt;
2774 if (self)
2775 {
2776 valManifests.applyManifest(
2777 *deserializeManifest(base64_decode(self->manifest)));
2778 BEAST_EXPECT(result->load(
2779 self->signingPublic,
2780 emptyCfgKeys,
2781 cfgPublishers,
2782 threshold));
2783 }
2784 else
2785 {
2786 BEAST_EXPECT(
2787 result->load({}, emptyCfgKeys, cfgPublishers, threshold));
2788 }
2789
2790 for (std::size_t i = 0; i < countTotal; ++i)
2791 {
2792 using namespace std::chrono_literals;
2793 publishers[i].expiry = env.timeKeeper().now() +
2794 (i == countTotal - 1 ? 60s : 3600s);
2795 auto const blob = makeList(
2796 valKeys,
2797 1,
2798 publishers[i].expiry.time_since_epoch().count());
2799 auto const sig = signList(blob, publishers[i].signingKeys);
2800
2801 BEAST_EXPECT(
2802 result
2803 ->applyLists(
2804 publishers[i].manifest,
2805 1,
2806 {{blob, sig, {}}},
2807 siteUri)
2808 .bestDisposition() ==
2809 (publishers[i].revoked ? ListDisposition::untrusted
2810 : ListDisposition::accepted));
2811 }
2812
2813 return result;
2814 };
2815
2816 // Test cases use 5 publishers.
2817 constexpr auto quorumDisabled = std::numeric_limits<std::size_t>::max();
2818 {
2819 // List threshold = 5 (same as number of trusted publishers)
2820 ManifestCache pubManifests;
2821 ManifestCache valManifests;
2822 std::vector<Publisher> publishers;
2823 // Self is a random validator
2824 auto const self = randomValidator();
2825 auto const keysTotal = valKeys.size() + 1;
2826 auto trustedKeys = makeValidatorList(
2827 5, //
2828 0,
2829 5,
2830 pubManifests,
2831 valManifests,
2832 self,
2833 publishers);
2834 BEAST_EXPECT(trustedKeys->getListThreshold() == 5);
2835 for (auto const& p : publishers)
2836 BEAST_EXPECT(trustedKeys->trustedPublisher(p.pubKey));
2837
2838 TrustChanges changes = trustedKeys->updateTrusted(
2839 activeValidators,
2840 env.timeKeeper().now(),
2841 env.app().getOPs(),
2842 env.app().overlay(),
2843 env.app().getHashRouter());
2844 BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f));
2845 BEAST_EXPECT(
2846 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
2847
2848 hash_set<NodeID> added;
2849 added.insert(calcNodeID(self.masterPublic));
2850 for (auto const& val : valKeys)
2851 {
2852 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
2853 added.insert(calcNodeID(val.masterPublic));
2854 }
2855 BEAST_EXPECT(changes.added == added);
2856 BEAST_EXPECT(changes.removed.empty());
2857
2858 // Expire one publisher - only trusted validator is self
2859 env.timeKeeper().set(publishers.back().expiry);
2860 changes = trustedKeys->updateTrusted(
2861 activeValidators,
2862 env.timeKeeper().now(),
2863 env.app().getOPs(),
2864 env.app().overlay(),
2865 env.app().getHashRouter());
2866 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
2867 BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == 1);
2868
2869 hash_set<NodeID> removed;
2870 BEAST_EXPECT(trustedKeys->trusted(self.masterPublic));
2871 for (auto const& val : valKeys)
2872 {
2873 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
2874 BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic));
2875 removed.insert(calcNodeID(val.masterPublic));
2876 }
2877 BEAST_EXPECT(changes.added.empty());
2878 BEAST_EXPECT(changes.removed == removed);
2879 }
2880 {
2881 // List threshold = 5 (same as number of trusted publishers)
2882 ManifestCache pubManifests;
2883 ManifestCache valManifests;
2884 std::vector<Publisher> publishers;
2885 auto const keysTotal = valKeys.size();
2886 auto trustedKeys = makeValidatorList(
2887 5, //
2888 0,
2889 5,
2890 pubManifests,
2891 valManifests,
2892 {},
2893 publishers);
2894 BEAST_EXPECT(trustedKeys->getListThreshold() == 5);
2895 for (auto const& p : publishers)
2896 BEAST_EXPECT(trustedKeys->trustedPublisher(p.pubKey));
2897
2898 TrustChanges changes = trustedKeys->updateTrusted(
2899 activeValidators,
2900 env.timeKeeper().now(),
2901 env.app().getOPs(),
2902 env.app().overlay(),
2903 env.app().getHashRouter());
2904 BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f));
2905 BEAST_EXPECT(
2906 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
2907
2908 hash_set<NodeID> added;
2909 for (auto const& val : valKeys)
2910 {
2911 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
2912 added.insert(calcNodeID(val.masterPublic));
2913 }
2914 BEAST_EXPECT(changes.added == added);
2915 BEAST_EXPECT(changes.removed.empty());
2916
2917 // Expire one publisher - no trusted validators
2918 env.timeKeeper().set(publishers.back().expiry);
2919 changes = trustedKeys->updateTrusted(
2920 activeValidators,
2921 env.timeKeeper().now(),
2922 env.app().getOPs(),
2923 env.app().overlay(),
2924 env.app().getHashRouter());
2925 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
2926 BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == 0);
2927
2928 hash_set<NodeID> removed;
2929 for (auto const& val : valKeys)
2930 {
2931 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
2932 BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic));
2933 removed.insert(calcNodeID(val.masterPublic));
2934 }
2935 BEAST_EXPECT(changes.added.empty());
2936 BEAST_EXPECT(changes.removed == removed);
2937 }
2938 {
2939 // List threshold = 4, 1 publisher is revoked
2940 ManifestCache pubManifests;
2941 ManifestCache valManifests;
2942 std::vector<Publisher> publishers;
2943 // Self is in UNL
2944 auto const self = valKeys[1];
2945 auto const keysTotal = valKeys.size();
2946 auto trustedKeys = makeValidatorList(
2947 5, //
2948 1,
2949 4,
2950 pubManifests,
2951 valManifests,
2952 self,
2953 publishers);
2954 BEAST_EXPECT(trustedKeys->getListThreshold() == 4);
2955 int untrustedCount = 0;
2956 for (auto const& p : publishers)
2957 {
2958 bool const trusted = trustedKeys->trustedPublisher(p.pubKey);
2959 BEAST_EXPECT(p.revoked ^ trusted);
2960 untrustedCount += trusted ? 0 : 1;
2961 }
2962 BEAST_EXPECT(untrustedCount == 1);
2963
2964 TrustChanges changes = trustedKeys->updateTrusted(
2965 activeValidators,
2966 env.timeKeeper().now(),
2967 env.app().getOPs(),
2968 env.app().overlay(),
2969 env.app().getHashRouter());
2970 BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f));
2971 BEAST_EXPECT(
2972 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
2973
2974 hash_set<NodeID> added;
2975 for (auto const& val : valKeys)
2976 {
2977 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
2978 added.insert(calcNodeID(val.masterPublic));
2979 }
2980 BEAST_EXPECT(changes.added == added);
2981 BEAST_EXPECT(changes.removed.empty());
2982
2983 // Expire one publisher - only trusted validator is self
2984 env.timeKeeper().set(publishers.back().expiry);
2985 changes = trustedKeys->updateTrusted(
2986 activeValidators,
2987 env.timeKeeper().now(),
2988 env.app().getOPs(),
2989 env.app().overlay(),
2990 env.app().getHashRouter());
2991 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
2992 BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == 1);
2993
2994 hash_set<NodeID> removed;
2995 BEAST_EXPECT(trustedKeys->trusted(self.masterPublic));
2996 for (auto const& val : valKeys)
2997 {
2998 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
2999 if (val.masterPublic != self.masterPublic)
3000 {
3001 BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic));
3002 removed.insert(calcNodeID(val.masterPublic));
3003 }
3004 }
3005 BEAST_EXPECT(changes.added.empty());
3006 BEAST_EXPECT(changes.removed == removed);
3007 }
3008 {
3009 // List threshold = 3 (default), 2 publishers are revoked
3010 ManifestCache pubManifests;
3011 ManifestCache valManifests;
3012 std::vector<Publisher> publishers;
3013 // Self is a random validator
3014 auto const self = randomValidator();
3015 auto const keysTotal = valKeys.size() + 1;
3016 auto trustedKeys = makeValidatorList(
3017 5, //
3018 2,
3019 0,
3020 pubManifests,
3021 valManifests,
3022 self,
3023 publishers);
3024 BEAST_EXPECT(trustedKeys->getListThreshold() == 3);
3025 int untrustedCount = 0;
3026 for (auto const& p : publishers)
3027 {
3028 bool const trusted = trustedKeys->trustedPublisher(p.pubKey);
3029 BEAST_EXPECT(p.revoked ^ trusted);
3030 untrustedCount += trusted ? 0 : 1;
3031 }
3032 BEAST_EXPECT(untrustedCount == 2);
3033
3034 TrustChanges changes = trustedKeys->updateTrusted(
3035 activeValidators,
3036 env.timeKeeper().now(),
3037 env.app().getOPs(),
3038 env.app().overlay(),
3039 env.app().getHashRouter());
3040 BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f));
3041 BEAST_EXPECT(
3042 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
3043
3044 hash_set<NodeID> added;
3045 added.insert(calcNodeID(self.masterPublic));
3046 for (auto const& val : valKeys)
3047 {
3048 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
3049 added.insert(calcNodeID(val.masterPublic));
3050 }
3051 BEAST_EXPECT(changes.added == added);
3052 BEAST_EXPECT(changes.removed.empty());
3053
3054 // Expire one publisher - no quorum, only trusted validator is self
3055 env.timeKeeper().set(publishers.back().expiry);
3056 changes = trustedKeys->updateTrusted(
3057 activeValidators,
3058 env.timeKeeper().now(),
3059 env.app().getOPs(),
3060 env.app().overlay(),
3061 env.app().getHashRouter());
3062 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
3063 BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == 1);
3064
3065 hash_set<NodeID> removed;
3066 BEAST_EXPECT(trustedKeys->trusted(self.masterPublic));
3067 for (auto const& val : valKeys)
3068 {
3069 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
3070 BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic));
3071 removed.insert(calcNodeID(val.masterPublic));
3072 }
3073 BEAST_EXPECT(changes.added.empty());
3074 BEAST_EXPECT(changes.removed == removed);
3075 }
3076 {
3077 // List threshold = 3 (default), 2 publishers are revoked
3078 ManifestCache pubManifests;
3079 ManifestCache valManifests;
3080 std::vector<Publisher> publishers;
3081 // Self is in UNL
3082 auto const self = valKeys[5];
3083 auto const keysTotal = valKeys.size();
3084 auto trustedKeys = makeValidatorList(
3085 5, //
3086 2,
3087 0,
3088 pubManifests,
3089 valManifests,
3090 self,
3091 publishers);
3092 BEAST_EXPECT(trustedKeys->getListThreshold() == 3);
3093 int untrustedCount = 0;
3094 for (auto const& p : publishers)
3095 {
3096 bool const trusted = trustedKeys->trustedPublisher(p.pubKey);
3097 BEAST_EXPECT(p.revoked ^ trusted);
3098 untrustedCount += trusted ? 0 : 1;
3099 }
3100 BEAST_EXPECT(untrustedCount == 2);
3101
3102 TrustChanges changes = trustedKeys->updateTrusted(
3103 activeValidators,
3104 env.timeKeeper().now(),
3105 env.app().getOPs(),
3106 env.app().overlay(),
3107 env.app().getHashRouter());
3108 BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f));
3109 BEAST_EXPECT(
3110 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
3111
3112 hash_set<NodeID> added;
3113 for (auto const& val : valKeys)
3114 {
3115 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
3116 added.insert(calcNodeID(val.masterPublic));
3117 }
3118 BEAST_EXPECT(changes.added == added);
3119 BEAST_EXPECT(changes.removed.empty());
3120
3121 // Expire one publisher - no quorum, only trusted validator is self
3122 env.timeKeeper().set(publishers.back().expiry);
3123 changes = trustedKeys->updateTrusted(
3124 activeValidators,
3125 env.timeKeeper().now(),
3126 env.app().getOPs(),
3127 env.app().overlay(),
3128 env.app().getHashRouter());
3129 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
3130 BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == 1);
3131
3132 hash_set<NodeID> removed;
3133 BEAST_EXPECT(trustedKeys->trusted(self.masterPublic));
3134 for (auto const& val : valKeys)
3135 {
3136 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
3137 if (val.masterPublic != self.masterPublic)
3138 {
3139 BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic));
3140 removed.insert(calcNodeID(val.masterPublic));
3141 }
3142 }
3143 BEAST_EXPECT(changes.added.empty());
3144 BEAST_EXPECT(changes.removed == removed);
3145 }
3146 {
3147 // List threshold = 3 (default), 2 publishers are revoked
3148 ManifestCache pubManifests;
3149 ManifestCache valManifests;
3150 std::vector<Publisher> publishers;
3151 auto const keysTotal = valKeys.size();
3152 auto trustedKeys = makeValidatorList(
3153 5, //
3154 2,
3155 0,
3156 pubManifests,
3157 valManifests,
3158 {},
3159 publishers);
3160 BEAST_EXPECT(trustedKeys->getListThreshold() == 3);
3161 int untrustedCount = 0;
3162 for (auto const& p : publishers)
3163 {
3164 bool const trusted = trustedKeys->trustedPublisher(p.pubKey);
3165 BEAST_EXPECT(p.revoked ^ trusted);
3166 untrustedCount += trusted ? 0 : 1;
3167 }
3168 BEAST_EXPECT(untrustedCount == 2);
3169
3170 TrustChanges changes = trustedKeys->updateTrusted(
3171 activeValidators,
3172 env.timeKeeper().now(),
3173 env.app().getOPs(),
3174 env.app().overlay(),
3175 env.app().getHashRouter());
3176 BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f));
3177 BEAST_EXPECT(
3178 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
3179
3180 hash_set<NodeID> added;
3181 for (auto const& val : valKeys)
3182 {
3183 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
3184 added.insert(calcNodeID(val.masterPublic));
3185 }
3186 BEAST_EXPECT(changes.added == added);
3187 BEAST_EXPECT(changes.removed.empty());
3188
3189 // Expire one publisher - no quorum, no trusted validators
3190 env.timeKeeper().set(publishers.back().expiry);
3191 changes = trustedKeys->updateTrusted(
3192 activeValidators,
3193 env.timeKeeper().now(),
3194 env.app().getOPs(),
3195 env.app().overlay(),
3196 env.app().getHashRouter());
3197 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
3198 BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == 0);
3199
3200 hash_set<NodeID> removed;
3201 for (auto const& val : valKeys)
3202 {
3203 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
3204 BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic));
3205 removed.insert(calcNodeID(val.masterPublic));
3206 }
3207 BEAST_EXPECT(changes.added.empty());
3208 BEAST_EXPECT(changes.removed == removed);
3209 }
3210 {
3211 // List threshold = 2, 1 publisher is revoked
3212 ManifestCache pubManifests;
3213 ManifestCache valManifests;
3214 std::vector<Publisher> publishers;
3215 // Self is a random validator
3216 auto const self = randomValidator();
3217 auto const keysTotal = valKeys.size() + 1;
3218 auto trustedKeys = makeValidatorList(
3219 5, //
3220 1,
3221 2,
3222 pubManifests,
3223 valManifests,
3224 self,
3225 publishers);
3226 BEAST_EXPECT(trustedKeys->getListThreshold() == 2);
3227 int untrustedCount = 0;
3228 for (auto const& p : publishers)
3229 {
3230 bool const trusted = trustedKeys->trustedPublisher(p.pubKey);
3231 BEAST_EXPECT(p.revoked ^ trusted);
3232 untrustedCount += trusted ? 0 : 1;
3233 }
3234 BEAST_EXPECT(untrustedCount == 1);
3235
3236 TrustChanges changes = trustedKeys->updateTrusted(
3237 activeValidators,
3238 env.timeKeeper().now(),
3239 env.app().getOPs(),
3240 env.app().overlay(),
3241 env.app().getHashRouter());
3242 BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f));
3243 BEAST_EXPECT(
3244 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
3245
3246 hash_set<NodeID> added;
3247 added.insert(calcNodeID(self.masterPublic));
3248 for (auto const& val : valKeys)
3249 {
3250 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
3251 added.insert(calcNodeID(val.masterPublic));
3252 }
3253 BEAST_EXPECT(changes.added == added);
3254 BEAST_EXPECT(changes.removed.empty());
3255
3256 // Expire one publisher - no quorum
3257 env.timeKeeper().set(publishers.back().expiry);
3258 changes = trustedKeys->updateTrusted(
3259 activeValidators,
3260 env.timeKeeper().now(),
3261 env.app().getOPs(),
3262 env.app().overlay(),
3263 env.app().getHashRouter());
3264 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
3265 BEAST_EXPECT(
3266 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
3267
3268 BEAST_EXPECT(trustedKeys->trusted(self.masterPublic));
3269 for (auto const& val : valKeys)
3270 {
3271 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
3272 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
3273 }
3274 BEAST_EXPECT(changes.added.empty());
3275 BEAST_EXPECT(changes.removed.empty());
3276 }
3277 {
3278 // List threshold = 1
3279 ManifestCache pubManifests;
3280 ManifestCache valManifests;
3281 std::vector<Publisher> publishers;
3282 // Self is a random validator
3283 auto const self = randomValidator();
3284 auto const keysTotal = valKeys.size() + 1;
3285 auto trustedKeys = makeValidatorList(
3286 5, //
3287 0,
3288 1,
3289 pubManifests,
3290 valManifests,
3291 self,
3292 publishers);
3293 BEAST_EXPECT(trustedKeys->getListThreshold() == 1);
3294 for (auto const& p : publishers)
3295 BEAST_EXPECT(trustedKeys->trustedPublisher(p.pubKey));
3296
3297 TrustChanges changes = trustedKeys->updateTrusted(
3298 activeValidators,
3299 env.timeKeeper().now(),
3300 env.app().getOPs(),
3301 env.app().overlay(),
3302 env.app().getHashRouter());
3303 BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f));
3304 BEAST_EXPECT(
3305 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
3306
3307 hash_set<NodeID> added;
3308 added.insert(calcNodeID(self.masterPublic));
3309 for (auto const& val : valKeys)
3310 {
3311 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
3312 added.insert(calcNodeID(val.masterPublic));
3313 }
3314 BEAST_EXPECT(changes.added == added);
3315 BEAST_EXPECT(changes.removed.empty());
3316
3317 // Expire one publisher - no quorum
3318 env.timeKeeper().set(publishers.back().expiry);
3319 changes = trustedKeys->updateTrusted(
3320 activeValidators,
3321 env.timeKeeper().now(),
3322 env.app().getOPs(),
3323 env.app().overlay(),
3324 env.app().getHashRouter());
3325 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
3326 BEAST_EXPECT(
3327 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
3328
3329 BEAST_EXPECT(trustedKeys->trusted(self.masterPublic));
3330 for (auto const& val : valKeys)
3331 {
3332 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
3333 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
3334 }
3335 BEAST_EXPECT(changes.added.empty());
3336 BEAST_EXPECT(changes.removed.empty());
3337 }
3338 {
3339 // List threshold = 1
3340 ManifestCache pubManifests;
3341 ManifestCache valManifests;
3342 std::vector<Publisher> publishers;
3343 // Self is in UNL
3344 auto const self = valKeys[7];
3345 auto const keysTotal = valKeys.size();
3346 auto trustedKeys = makeValidatorList(
3347 5, //
3348 0,
3349 1,
3350 pubManifests,
3351 valManifests,
3352 self,
3353 publishers);
3354 BEAST_EXPECT(trustedKeys->getListThreshold() == 1);
3355 for (auto const& p : publishers)
3356 BEAST_EXPECT(trustedKeys->trustedPublisher(p.pubKey));
3357
3358 TrustChanges changes = trustedKeys->updateTrusted(
3359 activeValidators,
3360 env.timeKeeper().now(),
3361 env.app().getOPs(),
3362 env.app().overlay(),
3363 env.app().getHashRouter());
3364 BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f));
3365 BEAST_EXPECT(
3366 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
3367
3368 hash_set<NodeID> added;
3369 for (auto const& val : valKeys)
3370 {
3371 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
3372 added.insert(calcNodeID(val.masterPublic));
3373 }
3374 BEAST_EXPECT(changes.added == added);
3375 BEAST_EXPECT(changes.removed.empty());
3376
3377 // Expire one publisher - no quorum
3378 env.timeKeeper().set(publishers.back().expiry);
3379 changes = trustedKeys->updateTrusted(
3380 activeValidators,
3381 env.timeKeeper().now(),
3382 env.app().getOPs(),
3383 env.app().overlay(),
3384 env.app().getHashRouter());
3385 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
3386 BEAST_EXPECT(
3387 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
3388
3389 BEAST_EXPECT(trustedKeys->trusted(self.masterPublic));
3390 for (auto const& val : valKeys)
3391 {
3392 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
3393 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
3394 }
3395 BEAST_EXPECT(changes.added.empty());
3396 BEAST_EXPECT(changes.removed.empty());
3397 }
3398 {
3399 // List threshold = 1
3400 ManifestCache pubManifests;
3401 ManifestCache valManifests;
3402 std::vector<Publisher> publishers;
3403 auto const keysTotal = valKeys.size();
3404 auto trustedKeys = makeValidatorList(
3405 5, //
3406 0,
3407 1,
3408 pubManifests,
3409 valManifests,
3410 {},
3411 publishers);
3412 BEAST_EXPECT(trustedKeys->getListThreshold() == 1);
3413 for (auto const& p : publishers)
3414 BEAST_EXPECT(trustedKeys->trustedPublisher(p.pubKey));
3415
3416 TrustChanges changes = trustedKeys->updateTrusted(
3417 activeValidators,
3418 env.timeKeeper().now(),
3419 env.app().getOPs(),
3420 env.app().overlay(),
3421 env.app().getHashRouter());
3422 BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f));
3423 BEAST_EXPECT(
3424 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
3425
3426 hash_set<NodeID> added;
3427 for (auto const& val : valKeys)
3428 {
3429 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
3430 added.insert(calcNodeID(val.masterPublic));
3431 }
3432 BEAST_EXPECT(changes.added == added);
3433 BEAST_EXPECT(changes.removed.empty());
3434
3435 // Expire one publisher - no quorum
3436 env.timeKeeper().set(publishers.back().expiry);
3437 changes = trustedKeys->updateTrusted(
3438 activeValidators,
3439 env.timeKeeper().now(),
3440 env.app().getOPs(),
3441 env.app().overlay(),
3442 env.app().getHashRouter());
3443 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
3444 BEAST_EXPECT(
3445 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
3446
3447 for (auto const& val : valKeys)
3448 {
3449 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
3450 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
3451 }
3452 BEAST_EXPECT(changes.added.empty());
3453 BEAST_EXPECT(changes.removed.empty());
3454 }
3455
3456 // Test cases use 2 publishers
3457 {
3458 // List threshold = 1, 1 publisher revoked
3459 ManifestCache pubManifests;
3460 ManifestCache valManifests;
3461 std::vector<Publisher> publishers;
3462 // Self is a random validator
3463 auto const self = randomValidator();
3464 auto const keysTotal = valKeys.size() + 1;
3465 auto trustedKeys = makeValidatorList(
3466 2, //
3467 1,
3468 1,
3469 pubManifests,
3470 valManifests,
3471 self,
3472 publishers);
3473 BEAST_EXPECT(trustedKeys->getListThreshold() == 1);
3474 int untrustedCount = 0;
3475 for (auto const& p : publishers)
3476 {
3477 bool const trusted = trustedKeys->trustedPublisher(p.pubKey);
3478 BEAST_EXPECT(p.revoked ^ trusted);
3479 untrustedCount += trusted ? 0 : 1;
3480 }
3481 BEAST_EXPECT(untrustedCount == 1);
3482
3483 TrustChanges changes = trustedKeys->updateTrusted(
3484 activeValidators,
3485 env.timeKeeper().now(),
3486 env.app().getOPs(),
3487 env.app().overlay(),
3488 env.app().getHashRouter());
3489 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
3490 BEAST_EXPECT(
3491 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
3492
3493 hash_set<NodeID> added;
3494 added.insert(calcNodeID(self.masterPublic));
3495 for (auto const& val : valKeys)
3496 {
3497 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
3498 added.insert(calcNodeID(val.masterPublic));
3499 }
3500 BEAST_EXPECT(changes.added == added);
3501 BEAST_EXPECT(changes.removed.empty());
3502
3503 // Expire one publisher - no quorum, only trusted validator is self
3504 env.timeKeeper().set(publishers.back().expiry);
3505 changes = trustedKeys->updateTrusted(
3506 activeValidators,
3507 env.timeKeeper().now(),
3508 env.app().getOPs(),
3509 env.app().overlay(),
3510 env.app().getHashRouter());
3511 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
3512 BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == 1);
3513
3514 hash_set<NodeID> removed;
3515 BEAST_EXPECT(trustedKeys->trusted(self.masterPublic));
3516 for (auto const& val : valKeys)
3517 {
3518 BEAST_EXPECT(!trustedKeys->listed(val.masterPublic));
3519 BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic));
3520 removed.insert(calcNodeID(val.masterPublic));
3521 }
3522 BEAST_EXPECT(changes.added.empty());
3523 BEAST_EXPECT(changes.removed == removed);
3524 }
3525 {
3526 // List threshold = 1, 1 publisher revoked
3527 ManifestCache pubManifests;
3528 ManifestCache valManifests;
3529 std::vector<Publisher> publishers;
3530 // Self is in UNL
3531 auto const self = valKeys[5];
3532 auto const keysTotal = valKeys.size();
3533 auto trustedKeys = makeValidatorList(
3534 2, //
3535 1,
3536 1,
3537 pubManifests,
3538 valManifests,
3539 self,
3540 publishers);
3541 BEAST_EXPECT(trustedKeys->getListThreshold() == 1);
3542 int untrustedCount = 0;
3543 for (auto const& p : publishers)
3544 {
3545 bool const trusted = trustedKeys->trustedPublisher(p.pubKey);
3546 BEAST_EXPECT(p.revoked ^ trusted);
3547 untrustedCount += trusted ? 0 : 1;
3548 }
3549 BEAST_EXPECT(untrustedCount == 1);
3550
3551 TrustChanges changes = trustedKeys->updateTrusted(
3552 activeValidators,
3553 env.timeKeeper().now(),
3554 env.app().getOPs(),
3555 env.app().overlay(),
3556 env.app().getHashRouter());
3557 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
3558 BEAST_EXPECT(
3559 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
3560
3561 hash_set<NodeID> added;
3562 for (auto const& val : valKeys)
3563 {
3564 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
3565 added.insert(calcNodeID(val.masterPublic));
3566 }
3567 BEAST_EXPECT(changes.added == added);
3568 BEAST_EXPECT(changes.removed.empty());
3569
3570 // Expire one publisher - no quorum, only trusted validator is self
3571 env.timeKeeper().set(publishers.back().expiry);
3572 changes = trustedKeys->updateTrusted(
3573 activeValidators,
3574 env.timeKeeper().now(),
3575 env.app().getOPs(),
3576 env.app().overlay(),
3577 env.app().getHashRouter());
3578 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
3579 BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == 1);
3580
3581 hash_set<NodeID> removed;
3582 BEAST_EXPECT(trustedKeys->trusted(self.masterPublic));
3583 for (auto const& val : valKeys)
3584 {
3585 if (val.masterPublic != self.masterPublic)
3586 {
3587 BEAST_EXPECT(!trustedKeys->listed(val.masterPublic));
3588 BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic));
3589 removed.insert(calcNodeID(val.masterPublic));
3590 }
3591 }
3592 BEAST_EXPECT(changes.added.empty());
3593 BEAST_EXPECT(changes.removed == removed);
3594 }
3595 {
3596 // List threshold = 1, 1 publisher revoked
3597 ManifestCache pubManifests;
3598 ManifestCache valManifests;
3599 std::vector<Publisher> publishers;
3600 auto const keysTotal = valKeys.size();
3601 auto trustedKeys = makeValidatorList(
3602 2, //
3603 1,
3604 1,
3605 pubManifests,
3606 valManifests,
3607 {},
3608 publishers);
3609 BEAST_EXPECT(trustedKeys->getListThreshold() == 1);
3610 int untrustedCount = 0;
3611 for (auto const& p : publishers)
3612 {
3613 bool const trusted = trustedKeys->trustedPublisher(p.pubKey);
3614 BEAST_EXPECT(p.revoked ^ trusted);
3615 untrustedCount += trusted ? 0 : 1;
3616 }
3617 BEAST_EXPECT(untrustedCount == 1);
3618
3619 TrustChanges changes = trustedKeys->updateTrusted(
3620 activeValidators,
3621 env.timeKeeper().now(),
3622 env.app().getOPs(),
3623 env.app().overlay(),
3624 env.app().getHashRouter());
3625 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
3626 BEAST_EXPECT(
3627 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
3628
3629 hash_set<NodeID> added;
3630 for (auto const& val : valKeys)
3631 {
3632 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
3633 added.insert(calcNodeID(val.masterPublic));
3634 }
3635 BEAST_EXPECT(changes.added == added);
3636 BEAST_EXPECT(changes.removed.empty());
3637
3638 // Expire one publisher - no quorum, no trusted validators
3639 env.timeKeeper().set(publishers.back().expiry);
3640 changes = trustedKeys->updateTrusted(
3641 activeValidators,
3642 env.timeKeeper().now(),
3643 env.app().getOPs(),
3644 env.app().overlay(),
3645 env.app().getHashRouter());
3646 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
3647 BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == 0);
3648
3649 hash_set<NodeID> removed;
3650 for (auto const& val : valKeys)
3651 {
3652 BEAST_EXPECT(!trustedKeys->listed(val.masterPublic));
3653 BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic));
3654 removed.insert(calcNodeID(val.masterPublic));
3655 }
3656 BEAST_EXPECT(changes.added.empty());
3657 BEAST_EXPECT(changes.removed == removed);
3658 }
3659 {
3660 // List threshold = 2 (same as number of trusted publishers)
3661 ManifestCache pubManifests;
3662 ManifestCache valManifests;
3663 std::vector<Publisher> publishers;
3664 // Self is a random validator
3665 auto const self = randomValidator();
3666 auto const keysTotal = valKeys.size() + 1;
3667 auto trustedKeys = makeValidatorList(
3668 2, //
3669 0,
3670 2,
3671 pubManifests,
3672 valManifests,
3673 self,
3674 publishers);
3675 BEAST_EXPECT(trustedKeys->getListThreshold() == 2);
3676 for (auto const& p : publishers)
3677 BEAST_EXPECT(trustedKeys->trustedPublisher(p.pubKey));
3678
3679 TrustChanges changes = trustedKeys->updateTrusted(
3680 activeValidators,
3681 env.timeKeeper().now(),
3682 env.app().getOPs(),
3683 env.app().overlay(),
3684 env.app().getHashRouter());
3685 BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f));
3686 BEAST_EXPECT(
3687 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
3688
3689 hash_set<NodeID> added;
3690 added.insert(calcNodeID(self.masterPublic));
3691 for (auto const& val : valKeys)
3692 {
3693 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
3694 added.insert(calcNodeID(val.masterPublic));
3695 }
3696 BEAST_EXPECT(changes.added == added);
3697 BEAST_EXPECT(changes.removed.empty());
3698
3699 // Expire one publisher - only trusted validator is self
3700 env.timeKeeper().set(publishers.back().expiry);
3701 changes = trustedKeys->updateTrusted(
3702 activeValidators,
3703 env.timeKeeper().now(),
3704 env.app().getOPs(),
3705 env.app().overlay(),
3706 env.app().getHashRouter());
3707 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
3708 BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == 1);
3709
3710 hash_set<NodeID> removed;
3711 BEAST_EXPECT(trustedKeys->trusted(self.masterPublic));
3712 for (auto const& val : valKeys)
3713 {
3714 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
3715 BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic));
3716 removed.insert(calcNodeID(val.masterPublic));
3717 }
3718 BEAST_EXPECT(changes.added.empty());
3719 BEAST_EXPECT(changes.removed == removed);
3720 }
3721 {
3722 // List threshold = 2 (same as number of trusted publishers)
3723 ManifestCache pubManifests;
3724 ManifestCache valManifests;
3725 std::vector<Publisher> publishers;
3726 // Self is in UNL
3727 auto const self = valKeys[5];
3728 auto const keysTotal = valKeys.size();
3729 auto trustedKeys = makeValidatorList(
3730 2, //
3731 0,
3732 2,
3733 pubManifests,
3734 valManifests,
3735 self,
3736 publishers);
3737 BEAST_EXPECT(trustedKeys->getListThreshold() == 2);
3738 for (auto const& p : publishers)
3739 BEAST_EXPECT(trustedKeys->trustedPublisher(p.pubKey));
3740
3741 TrustChanges changes = trustedKeys->updateTrusted(
3742 activeValidators,
3743 env.timeKeeper().now(),
3744 env.app().getOPs(),
3745 env.app().overlay(),
3746 env.app().getHashRouter());
3747 BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f));
3748 BEAST_EXPECT(
3749 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
3750
3751 hash_set<NodeID> added;
3752 added.insert(calcNodeID(self.masterPublic));
3753 for (auto const& val : valKeys)
3754 {
3755 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
3756 added.insert(calcNodeID(val.masterPublic));
3757 }
3758 BEAST_EXPECT(changes.added == added);
3759 BEAST_EXPECT(changes.removed.empty());
3760
3761 // Expire one publisher - only trusted validator is self
3762 env.timeKeeper().set(publishers.back().expiry);
3763 changes = trustedKeys->updateTrusted(
3764 activeValidators,
3765 env.timeKeeper().now(),
3766 env.app().getOPs(),
3767 env.app().overlay(),
3768 env.app().getHashRouter());
3769 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
3770 BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == 1);
3771
3772 hash_set<NodeID> removed;
3773 BEAST_EXPECT(trustedKeys->trusted(self.masterPublic));
3774 for (auto const& val : valKeys)
3775 {
3776 if (val.masterPublic != self.masterPublic)
3777 {
3778 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
3779 BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic));
3780 removed.insert(calcNodeID(val.masterPublic));
3781 }
3782 }
3783 BEAST_EXPECT(changes.added.empty());
3784 BEAST_EXPECT(changes.removed == removed);
3785 }
3786 {
3787 // List threshold = 2 (same as number of trusted publishers)
3788 ManifestCache pubManifests;
3789 ManifestCache valManifests;
3790 std::vector<Publisher> publishers;
3791 auto const keysTotal = valKeys.size();
3792 auto trustedKeys = makeValidatorList(
3793 2, //
3794 0,
3795 2,
3796 pubManifests,
3797 valManifests,
3798 {},
3799 publishers);
3800 BEAST_EXPECT(trustedKeys->getListThreshold() == 2);
3801 for (auto const& p : publishers)
3802 BEAST_EXPECT(trustedKeys->trustedPublisher(p.pubKey));
3803
3804 TrustChanges changes = trustedKeys->updateTrusted(
3805 activeValidators,
3806 env.timeKeeper().now(),
3807 env.app().getOPs(),
3808 env.app().overlay(),
3809 env.app().getHashRouter());
3810 BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f));
3811 BEAST_EXPECT(
3812 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
3813
3814 hash_set<NodeID> added;
3815 for (auto const& val : valKeys)
3816 {
3817 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
3818 added.insert(calcNodeID(val.masterPublic));
3819 }
3820 BEAST_EXPECT(changes.added == added);
3821 BEAST_EXPECT(changes.removed.empty());
3822
3823 // Expire one publisher - no trusted validators
3824 env.timeKeeper().set(publishers.back().expiry);
3825 changes = trustedKeys->updateTrusted(
3826 activeValidators,
3827 env.timeKeeper().now(),
3828 env.app().getOPs(),
3829 env.app().overlay(),
3830 env.app().getHashRouter());
3831 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
3832 BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == 0);
3833
3834 hash_set<NodeID> removed;
3835 for (auto const& val : valKeys)
3836 {
3837 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
3838 BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic));
3839 removed.insert(calcNodeID(val.masterPublic));
3840 }
3841 BEAST_EXPECT(changes.added.empty());
3842 BEAST_EXPECT(changes.removed == removed);
3843 }
3844
3845 // Test case for 1 publisher
3846 {
3847 // List threshold = 1 (default), no publisher revoked
3848 ManifestCache pubManifests;
3849 ManifestCache valManifests;
3850 std::vector<Publisher> publishers;
3851 // Self is a random validator
3852 auto const self = randomValidator();
3853 auto const keysTotal = valKeys.size() + 1;
3854 auto trustedKeys = makeValidatorList(
3855 1, //
3856 0,
3857 0,
3858 pubManifests,
3859 valManifests,
3860 self,
3861 publishers);
3862 BEAST_EXPECT(trustedKeys->getListThreshold() == 1);
3863 for (auto const& p : publishers)
3864 BEAST_EXPECT(trustedKeys->trustedPublisher(p.pubKey));
3865
3866 TrustChanges changes = trustedKeys->updateTrusted(
3867 activeValidators,
3868 env.timeKeeper().now(),
3869 env.app().getOPs(),
3870 env.app().overlay(),
3871 env.app().getHashRouter());
3872 BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f));
3873 BEAST_EXPECT(
3874 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
3875
3876 hash_set<NodeID> added;
3877 added.insert(calcNodeID(self.masterPublic));
3878 for (auto const& val : valKeys)
3879 {
3880 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
3881 added.insert(calcNodeID(val.masterPublic));
3882 }
3883 BEAST_EXPECT(changes.added == added);
3884 BEAST_EXPECT(changes.removed.empty());
3885
3886 // Expire one publisher - no quorum, only trusted validator is self
3887 env.timeKeeper().set(publishers.back().expiry);
3888 changes = trustedKeys->updateTrusted(
3889 activeValidators,
3890 env.timeKeeper().now(),
3891 env.app().getOPs(),
3892 env.app().overlay(),
3893 env.app().getHashRouter());
3894 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
3895 BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == 1);
3896
3897 hash_set<NodeID> removed;
3898 BEAST_EXPECT(trustedKeys->trusted(self.masterPublic));
3899 for (auto const& val : valKeys)
3900 {
3901 BEAST_EXPECT(!trustedKeys->listed(val.masterPublic));
3902 BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic));
3903 removed.insert(calcNodeID(val.masterPublic));
3904 }
3905 BEAST_EXPECT(changes.added.empty());
3906 BEAST_EXPECT(changes.removed == removed);
3907 }
3908
3909 // Test case for 3 publishers (for 2 is a block above)
3910 {
3911 // List threshold = 2 (default), no publisher revoked
3912 ManifestCache pubManifests;
3913 ManifestCache valManifests;
3914 std::vector<Publisher> publishers;
3915 // Self is in UNL
3916 auto const self = valKeys[2];
3917 auto const keysTotal = valKeys.size();
3918 auto trustedKeys = makeValidatorList(
3919 3, //
3920 0,
3921 0,
3922 pubManifests,
3923 valManifests,
3924 self,
3925 publishers);
3926 BEAST_EXPECT(trustedKeys->getListThreshold() == 2);
3927 for (auto const& p : publishers)
3928 BEAST_EXPECT(trustedKeys->trustedPublisher(p.pubKey));
3929
3930 TrustChanges changes = trustedKeys->updateTrusted(
3931 activeValidators,
3932 env.timeKeeper().now(),
3933 env.app().getOPs(),
3934 env.app().overlay(),
3935 env.app().getHashRouter());
3936 BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f));
3937 BEAST_EXPECT(
3938 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
3939
3940 hash_set<NodeID> added;
3941 for (auto const& val : valKeys)
3942 {
3943 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
3944 added.insert(calcNodeID(val.masterPublic));
3945 }
3946 BEAST_EXPECT(changes.added == added);
3947 BEAST_EXPECT(changes.removed.empty());
3948 }
3949
3950 // Test case for 4 publishers
3951 {
3952 // List threshold = 3 (default), no publisher revoked
3953 ManifestCache pubManifests;
3954 ManifestCache valManifests;
3955 std::vector<Publisher> publishers;
3956 auto const keysTotal = valKeys.size();
3957 auto trustedKeys = makeValidatorList(
3958 4, //
3959 0,
3960 0,
3961 pubManifests,
3962 valManifests,
3963 {},
3964 publishers);
3965 BEAST_EXPECT(trustedKeys->getListThreshold() == 3);
3966 for (auto const& p : publishers)
3967 BEAST_EXPECT(trustedKeys->trustedPublisher(p.pubKey));
3968
3969 TrustChanges changes = trustedKeys->updateTrusted(
3970 activeValidators,
3971 env.timeKeeper().now(),
3972 env.app().getOPs(),
3973 env.app().overlay(),
3974 env.app().getHashRouter());
3975 BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f));
3976 BEAST_EXPECT(
3977 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
3978
3979 hash_set<NodeID> added;
3980 for (auto const& val : valKeys)
3981 {
3982 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
3983 added.insert(calcNodeID(val.masterPublic));
3984 }
3985 BEAST_EXPECT(changes.added == added);
3986 BEAST_EXPECT(changes.removed.empty());
3987 }
3988
3989 // Test case for 6 publishers (for 5 is a large block above)
3990 {
3991 // List threshold = 4 (default), 2 publishers revoked
3992 ManifestCache pubManifests;
3993 ManifestCache valManifests;
3994 std::vector<Publisher> publishers;
3995 // Self is a random validator
3996 auto const self = randomValidator();
3997 auto const keysTotal = valKeys.size() + 1;
3998 auto trustedKeys = makeValidatorList(
3999 6, //
4000 2,
4001 0,
4002 pubManifests,
4003 valManifests,
4004 self,
4005 publishers);
4006 BEAST_EXPECT(trustedKeys->getListThreshold() == 4);
4007 int untrustedCount = 0;
4008 for (auto const& p : publishers)
4009 {
4010 bool const trusted = trustedKeys->trustedPublisher(p.pubKey);
4011 BEAST_EXPECT(p.revoked ^ trusted);
4012 untrustedCount += trusted ? 0 : 1;
4013 }
4014 BEAST_EXPECT(untrustedCount == 2);
4015
4016 TrustChanges changes = trustedKeys->updateTrusted(
4017 activeValidators,
4018 env.timeKeeper().now(),
4019 env.app().getOPs(),
4020 env.app().overlay(),
4021 env.app().getHashRouter());
4022 BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f));
4023 BEAST_EXPECT(
4024 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
4025
4026 hash_set<NodeID> added;
4027 added.insert(calcNodeID(self.masterPublic));
4028 for (auto const& val : valKeys)
4029 {
4030 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
4031 added.insert(calcNodeID(val.masterPublic));
4032 }
4033 BEAST_EXPECT(changes.added == added);
4034 BEAST_EXPECT(changes.removed.empty());
4035
4036 // Expire one publisher - no quorum, only trusted validator is self
4037 env.timeKeeper().set(publishers.back().expiry);
4038 changes = trustedKeys->updateTrusted(
4039 activeValidators,
4040 env.timeKeeper().now(),
4041 env.app().getOPs(),
4042 env.app().overlay(),
4043 env.app().getHashRouter());
4044 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
4045 BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == 1);
4046
4047 hash_set<NodeID> removed;
4048 BEAST_EXPECT(trustedKeys->trusted(self.masterPublic));
4049 for (auto const& val : valKeys)
4050 {
4051 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
4052 BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic));
4053 removed.insert(calcNodeID(val.masterPublic));
4054 }
4055 BEAST_EXPECT(changes.added.empty());
4056 BEAST_EXPECT(changes.removed == removed);
4057 }
4058
4059 // Test case for 7 publishers
4060 {
4061 // List threshold = 4 (default), 3 publishers revoked
4062 ManifestCache pubManifests;
4063 ManifestCache valManifests;
4064 std::vector<Publisher> publishers;
4065 // Self is in UNL
4066 auto const self = valKeys[2];
4067 auto const keysTotal = valKeys.size();
4068 auto trustedKeys = makeValidatorList(
4069 7, //
4070 3,
4071 0,
4072 pubManifests,
4073 valManifests,
4074 self,
4075 publishers);
4076 BEAST_EXPECT(trustedKeys->getListThreshold() == 4);
4077 int untrustedCount = 0;
4078 for (auto const& p : publishers)
4079 {
4080 bool const trusted = trustedKeys->trustedPublisher(p.pubKey);
4081 BEAST_EXPECT(p.revoked ^ trusted);
4082 untrustedCount += trusted ? 0 : 1;
4083 }
4084 BEAST_EXPECT(untrustedCount == 3);
4085
4086 TrustChanges changes = trustedKeys->updateTrusted(
4087 activeValidators,
4088 env.timeKeeper().now(),
4089 env.app().getOPs(),
4090 env.app().overlay(),
4091 env.app().getHashRouter());
4092 BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f));
4093 BEAST_EXPECT(
4094 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
4095
4096 hash_set<NodeID> added;
4097 for (auto const& val : valKeys)
4098 {
4099 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
4100 added.insert(calcNodeID(val.masterPublic));
4101 }
4102 BEAST_EXPECT(changes.added == added);
4103 BEAST_EXPECT(changes.removed.empty());
4104
4105 // Expire one publisher - only trusted validator is self
4106 env.timeKeeper().set(publishers.back().expiry);
4107 changes = trustedKeys->updateTrusted(
4108 activeValidators,
4109 env.timeKeeper().now(),
4110 env.app().getOPs(),
4111 env.app().overlay(),
4112 env.app().getHashRouter());
4113 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
4114 BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == 1);
4115
4116 hash_set<NodeID> removed;
4117 BEAST_EXPECT(trustedKeys->trusted(self.masterPublic));
4118 for (auto const& val : valKeys)
4119 {
4120 if (val.masterPublic != self.masterPublic)
4121 {
4122 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
4123 BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic));
4124 removed.insert(calcNodeID(val.masterPublic));
4125 }
4126 }
4127 BEAST_EXPECT(changes.added.empty());
4128 BEAST_EXPECT(changes.removed == removed);
4129 }
4130 }
4131
4132public:
4133 void
4134 run() override
4135 {
4136 testGenesisQuorum();
4137 testConfigLoad();
4138 testApplyLists();
4139 testGetAvailable();
4140 testUpdateTrusted();
4141 testExpires();
4142 testNegativeUNL();
4143 testSha512Hash();
4144 testBuildMessages();
4145 testQuorumDisabled();
4146 }
4147}; // namespace test
4148
4149BEAST_DEFINE_TESTSUITE(ValidatorList, app, ripple);
4150
4151} // namespace test
4152} // namespace ripple
T at(T... args)
T back(T... args)
T cbegin(T... args)
T capacity(T... args)
T ceil(T... args)
A testsuite class.
Definition suite.h:55
testcase_t testcase
Memberspace for declaring test cases.
Definition suite.h:155
virtual Config & config()=0
virtual Overlay & overlay()=0
virtual TimeKeeper & timeKeeper()=0
virtual NetworkOPs & getOPs()=0
virtual HashRouter & getHashRouter()=0
void legacy(std::string const &section, std::string value)
Set a value that is not a key/value pair.
Remembers manifests with the highest sequence number.
Definition Manifest.h:256
std::optional< PublicKey > getSigningKey(PublicKey const &pk) const
Returns master key's current signing key.
Definition Manifest.cpp:311
bool revoked(PublicKey const &pk) const
Returns true if master key has been revoked in a manifest.
Definition Manifest.cpp:371
ManifestDisposition applyManifest(Manifest m)
Add manifest to cache.
Definition Manifest.cpp:383
A public key.
Definition PublicKey.h:61
void add(Serializer &s) const override
Definition STObject.cpp:141
A secret key.
Definition SecretKey.h:38
std::size_t size() const noexcept
Definition Serializer.h:72
void const * data() const noexcept
Definition Serializer.h:78
An immutable linear range of bytes.
Definition Slice.h:46
time_point now() const override
Returns the current time.
void run() override
Runs the suite.
static hash_set< NodeID > asNodeIDs(std::initializer_list< PublicKey > const &pks)
void checkResult(ValidatorList::PublisherListStats const &result, PublicKey pubKey, ListDisposition expectedWorst, ListDisposition expectedBest)
static std::string makeRevocationString(PublicKey const &pk, SecretKey const &sk)
std::string makeList(std::vector< Validator > const &validators, std::size_t sequence, std::size_t validUntil, std::optional< std::size_t > validFrom={})
static std::string makeManifestString(PublicKey const &pk, SecretKey const &sk, PublicKey const &spk, SecretKey const &ssk, int seq)
std::string signList(std::string const &blob, std::pair< PublicKey, SecretKey > const &keys)
A transaction testing environment.
Definition Env.h:121
Application & app()
Definition Env.h:261
beast::Journal const journal
Definition Env.h:162
ManualTimeKeeper & timeKeeper()
Definition Env.h:273
Set the regular signature on a JTx.
Definition sig.h:35
T clear(T... args)
T emplace(T... args)
T cend(T... args)
T find(T... args)
T insert(T... args)
T is_same_v
T make_pair(T... args)
T max(T... args)
auto const data
General field definitions, or fields used in multiple transaction namespaces.
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
Definition envconfig.h:54
void sign(Json::Value &jv, Account const &account)
Sign automatically.
Definition utility.cpp:47
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:25
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
std::optional< Manifest > deserializeManifest(Slice s, beast::Journal journal)
Constructs Manifest from serialized string.
Definition Manifest.cpp:54
std::string base64_decode(std::string_view data)
@ accepted
List is valid.
@ same_sequence
Same sequence as current list.
@ expired
List is expired, but has the largest non-pending sequence seen so far.
PublicKey derivePublicKey(KeyType type, SecretKey const &sk)
Derive the public key from a secret key.
std::optional< KeyType > publicKeyType(Slice const &slice)
Returns the type of public key.
std::string strHex(FwdIt begin, FwdIt end)
Definition strHex.h:30
std::enable_if_t< std::is_same< T, char >::value||std::is_same< T, unsigned char >::value, Slice > makeSlice(std::array< T, N > const &a)
Definition Slice.h:244
SecretKey randomSecretKey()
Create a secret key using secure random numbers.
std::string base64_encode(std::uint8_t const *data, std::size_t len)
NodeID calcNodeID(PublicKey const &)
Calculate the 160-bit node ID from a node public key.
std::pair< PublicKey, SecretKey > randomKeyPair(KeyType type)
Create a key pair using secure random numbers.
SField const sfGeneric
@ manifest
Manifest.
sha512_half_hasher::result_type sha512Half(Args const &... args)
Returns the SHA512-Half of a series of objects.
Definition digest.h:224
T pop_back(T... args)
T push_back(T... args)
T rbegin(T... args)
T reserve(T... args)
T str(T... args)
Changes in trusted nodes after updating validator list.
hash_set< NodeID > added
hash_set< NodeID > removed
Describes the result of processing a Validator List (UNL), including some of the information from the...
std::optional< PublicKey > publisherKey
Set the sequence number on a JTx.
Definition seq.h:34
T time_since_epoch(T... args)
T to_string(T... args)