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