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