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