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