mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Update validations on UNL change (RIPD-1566):
Change the trust status of existing validations based when nodes are added or removed from the UNL.
This commit is contained in:
@@ -379,7 +379,7 @@ public:
|
||||
for (auto const& val : validators)
|
||||
{
|
||||
auto v = std::make_shared <STValidation> (
|
||||
uint256(), roundTime, val, true);
|
||||
uint256(), roundTime, val, calcNodeID(val), true);
|
||||
|
||||
++i;
|
||||
STVector256 field (sfAmendments);
|
||||
|
||||
@@ -31,15 +31,38 @@ namespace test {
|
||||
class RCLValidations_test : public beast::unit_test::suite
|
||||
{
|
||||
|
||||
public:
|
||||
void
|
||||
run() override
|
||||
testChangeTrusted()
|
||||
{
|
||||
testcase("Change validation trusted status");
|
||||
PublicKey key = derivePublicKey(KeyType::ed25519, randomSecretKey());
|
||||
auto v = std::make_shared<STValidation>(
|
||||
uint256(), NetClock::time_point(), key, calcNodeID(key), true);
|
||||
|
||||
BEAST_EXPECT(!v->isTrusted());
|
||||
v->setTrusted();
|
||||
BEAST_EXPECT(v->isTrusted());
|
||||
v->setUntrusted();
|
||||
BEAST_EXPECT(!v->isTrusted());
|
||||
|
||||
RCLValidation rcv{v};
|
||||
BEAST_EXPECT(!rcv.trusted());
|
||||
rcv.setTrusted();
|
||||
BEAST_EXPECT(rcv.trusted());
|
||||
rcv.setUntrusted();
|
||||
BEAST_EXPECT(!rcv.trusted());
|
||||
}
|
||||
|
||||
void
|
||||
testRCLValidatedLedger()
|
||||
{
|
||||
testcase("RCLValidatedLedger ancestry");
|
||||
beast::Journal j;
|
||||
|
||||
using Seq = RCLValidatedLedger::Seq;
|
||||
using ID = RCLValidatedLedger::ID;
|
||||
|
||||
|
||||
// This tests RCLValidatedLedger properly implements the type
|
||||
// requirements of a LedgerTrie ledger, with its added behavior that
|
||||
// only the 256 prior ledger hashes are available to determine ancestry.
|
||||
@@ -193,8 +216,14 @@ public:
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
void
|
||||
run() override
|
||||
{
|
||||
testChangeTrusted();
|
||||
testRCLValidatedLedger();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -18,9 +18,11 @@
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/app/misc/ValidatorKeys.h>
|
||||
#include <ripple/app/misc/Manifest.h>
|
||||
#include <ripple/beast/unit_test.h>
|
||||
#include <ripple/core/Config.h>
|
||||
#include <ripple/core/ConfigSections.h>
|
||||
#include <beast/core/detail/base64.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace ripple {
|
||||
@@ -74,19 +76,24 @@ public:
|
||||
{
|
||||
beast::Journal j;
|
||||
|
||||
// Keys when using [validation_seed]
|
||||
auto const seedSecretKey =
|
||||
// Keys/ID when using [validation_seed]
|
||||
SecretKey const seedSecretKey =
|
||||
generateSecretKey(KeyType::secp256k1, *parseBase58<Seed>(seed));
|
||||
auto const seedPublicKey =
|
||||
PublicKey const seedPublicKey =
|
||||
derivePublicKey(KeyType::secp256k1, seedSecretKey);
|
||||
NodeID const seedNodeID = calcNodeID(seedPublicKey);
|
||||
|
||||
// Keys when using [validation_token]
|
||||
auto const tokenSecretKey = *parseBase58<SecretKey>(
|
||||
// Keys/ID when using [validation_token]
|
||||
SecretKey const tokenSecretKey = *parseBase58<SecretKey>(
|
||||
TokenType::TOKEN_NODE_PRIVATE, tokenSecretStr);
|
||||
|
||||
auto const tokenPublicKey =
|
||||
PublicKey const tokenPublicKey =
|
||||
derivePublicKey(KeyType::secp256k1, tokenSecretKey);
|
||||
|
||||
auto const m = Manifest::make_Manifest(
|
||||
beast::detail::base64_decode(tokenManifest));
|
||||
BEAST_EXPECT(m);
|
||||
NodeID const tokenNodeID = calcNodeID(m->masterKey);
|
||||
|
||||
{
|
||||
// No config -> no key but valid
|
||||
Config c;
|
||||
@@ -104,6 +111,7 @@ public:
|
||||
ValidatorKeys k{c, j};
|
||||
BEAST_EXPECT(k.publicKey == seedPublicKey);
|
||||
BEAST_EXPECT(k.secretKey == seedSecretKey);
|
||||
BEAST_EXPECT(k.nodeID == seedNodeID);
|
||||
BEAST_EXPECT(k.manifest.empty());
|
||||
BEAST_EXPECT(!k.configInvalid());
|
||||
}
|
||||
@@ -127,6 +135,7 @@ public:
|
||||
|
||||
BEAST_EXPECT(k.publicKey == tokenPublicKey);
|
||||
BEAST_EXPECT(k.secretKey == tokenSecretKey);
|
||||
BEAST_EXPECT(k.nodeID == tokenNodeID);
|
||||
BEAST_EXPECT(k.manifest == tokenManifest);
|
||||
BEAST_EXPECT(!k.configInvalid());
|
||||
}
|
||||
|
||||
@@ -125,6 +125,16 @@ private:
|
||||
keys.first, keys.second, makeSlice(data)));
|
||||
}
|
||||
|
||||
static hash_set<NodeID>
|
||||
asNodeIDs(std::initializer_list<PublicKey> const& pks)
|
||||
{
|
||||
hash_set<NodeID> res;
|
||||
res.reserve(pks.size());
|
||||
for (auto const& pk : pks)
|
||||
res.insert(calcNodeID(pk));
|
||||
return res;
|
||||
}
|
||||
|
||||
void
|
||||
testGenesisQuorum ()
|
||||
{
|
||||
@@ -509,9 +519,9 @@ private:
|
||||
}
|
||||
|
||||
void
|
||||
testUpdate ()
|
||||
testUpdateTrusted ()
|
||||
{
|
||||
testcase ("Update");
|
||||
testcase ("Update trusted");
|
||||
|
||||
PublicKey emptyLocalKey;
|
||||
ManifestCache manifests;
|
||||
@@ -520,7 +530,8 @@ private:
|
||||
manifests, manifests, env.timeKeeper(), beast::Journal ());
|
||||
|
||||
std::vector<std::string> cfgPublishers;
|
||||
hash_set<PublicKey> activeValidators;
|
||||
hash_set<NodeID> activeValidators;
|
||||
hash_set<NodeID> secondAddedValidators;
|
||||
|
||||
// BFT: n >= 3f+1
|
||||
std::size_t const n = 40;
|
||||
@@ -535,15 +546,18 @@ private:
|
||||
cfgKeys.push_back (toBase58(
|
||||
TokenType::TOKEN_NODE_PUBLIC, valKey));
|
||||
if (cfgKeys.size () <= n - 5)
|
||||
activeValidators.emplace (valKey);
|
||||
activeValidators.emplace (calcNodeID(valKey));
|
||||
}
|
||||
|
||||
BEAST_EXPECT(trustedKeys->load (
|
||||
emptyLocalKey, cfgKeys, cfgPublishers));
|
||||
|
||||
// onConsensusStart should make all available configured
|
||||
// updateTrusted should make all available configured
|
||||
// validators trusted
|
||||
trustedKeys->onConsensusStart (activeValidators);
|
||||
TrustChanges changes =
|
||||
trustedKeys->updateTrusted(activeValidators);
|
||||
BEAST_EXPECT(changes.added == activeValidators);
|
||||
BEAST_EXPECT(changes.removed.empty());
|
||||
// Add 1 to n because I'm not on a published list.
|
||||
BEAST_EXPECT(trustedKeys->quorum () == n + 1 - f);
|
||||
std::size_t i = 0;
|
||||
@@ -564,11 +578,19 @@ private:
|
||||
|
||||
{
|
||||
// Quorum should be 80% with all listed validators active
|
||||
hash_set<PublicKey> activeValidators;
|
||||
hash_set<NodeID> activeValidatorsNew{activeValidators};
|
||||
for (auto const valKey : cfgKeys)
|
||||
activeValidators.emplace (*parseBase58<PublicKey>(
|
||||
TokenType::TOKEN_NODE_PUBLIC, valKey));
|
||||
trustedKeys->onConsensusStart (activeValidators);
|
||||
{
|
||||
auto const ins = activeValidatorsNew.emplace(
|
||||
calcNodeID(*parseBase58<PublicKey>(
|
||||
TokenType::TOKEN_NODE_PUBLIC, valKey)));
|
||||
if(ins.second)
|
||||
secondAddedValidators.insert(*ins.first);
|
||||
}
|
||||
TrustChanges changes =
|
||||
trustedKeys->updateTrusted(activeValidatorsNew);
|
||||
BEAST_EXPECT(changes.added == secondAddedValidators);
|
||||
BEAST_EXPECT(changes.removed.empty());
|
||||
BEAST_EXPECT(trustedKeys->quorum () == cfgKeys.size() * 4/5);
|
||||
}
|
||||
}
|
||||
@@ -586,10 +608,13 @@ private:
|
||||
|
||||
auto const signingKeys1 = randomKeyPair(KeyType::secp256k1);
|
||||
auto const signingPublic1 = signingKeys1.first;
|
||||
activeValidators.emplace (masterPublic);
|
||||
activeValidators.emplace (calcNodeID(masterPublic));
|
||||
|
||||
// Should not trust ephemeral signing key if there is no manifest
|
||||
trustedKeys->onConsensusStart (activeValidators);
|
||||
TrustChanges changes =
|
||||
trustedKeys->updateTrusted(activeValidators);
|
||||
BEAST_EXPECT(changes.added == asNodeIDs({masterPublic}));
|
||||
BEAST_EXPECT(changes.removed == secondAddedValidators);
|
||||
BEAST_EXPECT(trustedKeys->listed (masterPublic));
|
||||
BEAST_EXPECT(trustedKeys->trusted (masterPublic));
|
||||
BEAST_EXPECT(!trustedKeys->listed (signingPublic1));
|
||||
@@ -603,7 +628,9 @@ private:
|
||||
BEAST_EXPECT(
|
||||
manifests.applyManifest(std::move (*m1)) ==
|
||||
ManifestDisposition::accepted);
|
||||
trustedKeys->onConsensusStart (activeValidators);
|
||||
changes = trustedKeys->updateTrusted(activeValidators);
|
||||
BEAST_EXPECT(changes.removed.empty());
|
||||
BEAST_EXPECT(changes.added.empty());
|
||||
BEAST_EXPECT(trustedKeys->quorum () == n + 2 - f);
|
||||
BEAST_EXPECT(trustedKeys->listed (masterPublic));
|
||||
BEAST_EXPECT(trustedKeys->trusted (masterPublic));
|
||||
@@ -620,7 +647,9 @@ private:
|
||||
BEAST_EXPECT(
|
||||
manifests.applyManifest(std::move (*m2)) ==
|
||||
ManifestDisposition::accepted);
|
||||
trustedKeys->onConsensusStart (activeValidators);
|
||||
changes = trustedKeys->updateTrusted (activeValidators);
|
||||
BEAST_EXPECT(changes.removed.empty());
|
||||
BEAST_EXPECT(changes.added.empty());
|
||||
BEAST_EXPECT(trustedKeys->quorum () == n + 2 - f);
|
||||
BEAST_EXPECT(trustedKeys->listed (masterPublic));
|
||||
BEAST_EXPECT(trustedKeys->trusted (masterPublic));
|
||||
@@ -632,7 +661,7 @@ private:
|
||||
// Should not trust keys from revoked master public key
|
||||
auto const signingKeysMax = randomKeyPair(KeyType::secp256k1);
|
||||
auto const signingPublicMax = signingKeysMax.first;
|
||||
activeValidators.emplace (signingPublicMax);
|
||||
activeValidators.emplace (calcNodeID(signingPublicMax));
|
||||
auto mMax = Manifest::make_Manifest (makeManifestString (
|
||||
masterPublic, masterPrivate,
|
||||
signingPublicMax, signingKeysMax.second,
|
||||
@@ -644,7 +673,9 @@ private:
|
||||
ManifestDisposition::accepted);
|
||||
BEAST_EXPECT(manifests.getSigningKey (masterPublic) == masterPublic);
|
||||
BEAST_EXPECT(manifests.revoked (masterPublic));
|
||||
trustedKeys->onConsensusStart (activeValidators);
|
||||
changes = trustedKeys->updateTrusted (activeValidators);
|
||||
BEAST_EXPECT(changes.removed == asNodeIDs({masterPublic}));
|
||||
BEAST_EXPECT(changes.added.empty());
|
||||
BEAST_EXPECT(trustedKeys->quorum () == n + 1 - f);
|
||||
BEAST_EXPECT(trustedKeys->listed (masterPublic));
|
||||
BEAST_EXPECT(!trustedKeys->trusted (masterPublic));
|
||||
@@ -670,7 +701,10 @@ private:
|
||||
BEAST_EXPECT(trustedKeys->load (
|
||||
emptyLocalKey, emptyCfgKeys, cfgPublishers));
|
||||
|
||||
trustedKeys->onConsensusStart (activeValidators);
|
||||
TrustChanges changes =
|
||||
trustedKeys->updateTrusted(activeValidators);
|
||||
BEAST_EXPECT(changes.removed.empty());
|
||||
BEAST_EXPECT(changes.added.empty());
|
||||
BEAST_EXPECT(trustedKeys->quorum () ==
|
||||
std::numeric_limits<std::size_t>::max());
|
||||
}
|
||||
@@ -680,7 +714,7 @@ private:
|
||||
manifests, manifests, env.timeKeeper(), beast::Journal ());
|
||||
|
||||
std::vector<PublicKey> keys ({ randomNode (), randomNode () });
|
||||
hash_set<PublicKey> activeValidators;
|
||||
hash_set<NodeID> activeValidators;
|
||||
std::vector<std::string> cfgKeys ({
|
||||
toBase58 (TokenType::TOKEN_NODE_PUBLIC, keys[0]),
|
||||
toBase58 (TokenType::TOKEN_NODE_PUBLIC, keys[1])});
|
||||
@@ -688,7 +722,10 @@ private:
|
||||
BEAST_EXPECT(trustedKeys->load (
|
||||
emptyLocalKey, cfgKeys, cfgPublishers));
|
||||
|
||||
trustedKeys->onConsensusStart (activeValidators);
|
||||
TrustChanges changes =
|
||||
trustedKeys->updateTrusted(activeValidators);
|
||||
BEAST_EXPECT(changes.removed.empty());
|
||||
BEAST_EXPECT(changes.added == asNodeIDs({keys[0], keys[1]}));
|
||||
|
||||
BEAST_EXPECT(trustedKeys->quorum () == 2);
|
||||
for (auto const& key : keys)
|
||||
@@ -704,16 +741,21 @@ private:
|
||||
auto const node = randomNode ();
|
||||
std::vector<std::string> cfgKeys ({
|
||||
toBase58 (TokenType::TOKEN_NODE_PUBLIC, node)});
|
||||
hash_set<PublicKey> activeValidators;
|
||||
hash_set<NodeID> activeValidators;
|
||||
|
||||
BEAST_EXPECT(trustedKeys->load (
|
||||
emptyLocalKey, cfgKeys, cfgPublishers));
|
||||
|
||||
trustedKeys->onConsensusStart (activeValidators);
|
||||
TrustChanges changes =
|
||||
trustedKeys->updateTrusted(activeValidators);
|
||||
BEAST_EXPECT(changes.removed.empty());
|
||||
BEAST_EXPECT(changes.added == asNodeIDs({node}));
|
||||
BEAST_EXPECT(trustedKeys->quorum () == minQuorum);
|
||||
|
||||
activeValidators.emplace (node);
|
||||
trustedKeys->onConsensusStart (activeValidators);
|
||||
activeValidators.emplace (calcNodeID(node));
|
||||
changes = trustedKeys->updateTrusted(activeValidators);
|
||||
BEAST_EXPECT(changes.removed.empty());
|
||||
BEAST_EXPECT(changes.added.empty());
|
||||
BEAST_EXPECT(trustedKeys->quorum () == 1);
|
||||
}
|
||||
{
|
||||
@@ -722,7 +764,7 @@ private:
|
||||
manifests, manifests, env.timeKeeper(), beast::Journal ());
|
||||
|
||||
std::vector<PublicKey> keys ({ randomNode (), randomNode () });
|
||||
hash_set<PublicKey> activeValidators ({ keys[0] });
|
||||
hash_set<NodeID> activeValidators (asNodeIDs({ keys[0] }));
|
||||
std::vector<std::string> cfgKeys ({
|
||||
toBase58 (TokenType::TOKEN_NODE_PUBLIC, keys[0]),
|
||||
toBase58 (TokenType::TOKEN_NODE_PUBLIC, keys[1])});
|
||||
@@ -731,7 +773,11 @@ private:
|
||||
BEAST_EXPECT(trustedKeys->load (
|
||||
localKey, cfgKeys, cfgPublishers));
|
||||
|
||||
trustedKeys->onConsensusStart (activeValidators);
|
||||
TrustChanges changes =
|
||||
trustedKeys->updateTrusted(activeValidators);
|
||||
BEAST_EXPECT(changes.removed.empty());
|
||||
BEAST_EXPECT(
|
||||
changes.added == asNodeIDs({keys[0], keys[1], localKey}));
|
||||
BEAST_EXPECT(trustedKeys->quorum () == 2);
|
||||
|
||||
// local validator key is always trusted
|
||||
@@ -758,7 +804,8 @@ private:
|
||||
emptyLocalKey, emptyCfgKeys, cfgKeys));
|
||||
|
||||
std::vector<Validator> list ({randomValidator(), randomValidator()});
|
||||
hash_set<PublicKey> activeValidators ({ list[0].masterPublic, list[1].masterPublic });
|
||||
hash_set<NodeID> activeValidators(
|
||||
asNodeIDs({list[0].masterPublic, list[1].masterPublic}));
|
||||
|
||||
// do not apply expired list
|
||||
auto const version = 1;
|
||||
@@ -773,16 +820,21 @@ private:
|
||||
trustedKeys->applyList (
|
||||
manifest, blob, sig, version));
|
||||
|
||||
trustedKeys->onConsensusStart (activeValidators);
|
||||
for(Validator const & val : list)
|
||||
{
|
||||
BEAST_EXPECT(trustedKeys->trusted (val.masterPublic));
|
||||
BEAST_EXPECT(trustedKeys->trusted (val.signingPublic));
|
||||
}
|
||||
TrustChanges changes =
|
||||
trustedKeys->updateTrusted(activeValidators);
|
||||
BEAST_EXPECT(changes.removed.empty());
|
||||
BEAST_EXPECT(changes.added == activeValidators);
|
||||
for(Validator const & val : list)
|
||||
{
|
||||
BEAST_EXPECT(trustedKeys->trusted (val.masterPublic));
|
||||
BEAST_EXPECT(trustedKeys->trusted (val.signingPublic));
|
||||
}
|
||||
BEAST_EXPECT(trustedKeys->quorum () == 2);
|
||||
|
||||
env.timeKeeper().set(expiration);
|
||||
trustedKeys->onConsensusStart (activeValidators);
|
||||
changes = trustedKeys->updateTrusted (activeValidators);
|
||||
BEAST_EXPECT(changes.removed == activeValidators);
|
||||
BEAST_EXPECT(changes.added.empty());
|
||||
BEAST_EXPECT(! trustedKeys->trusted (list[0].masterPublic));
|
||||
BEAST_EXPECT(! trustedKeys->trusted (list[1].masterPublic));
|
||||
BEAST_EXPECT(trustedKeys->quorum () ==
|
||||
@@ -790,7 +842,7 @@ private:
|
||||
|
||||
// (Re)trust validators from new valid list
|
||||
std::vector<Validator> list2 ({list[0], randomValidator()});
|
||||
activeValidators.insert(list2[1].masterPublic);
|
||||
activeValidators.insert(calcNodeID(list2[1].masterPublic));
|
||||
auto const sequence2 = 2;
|
||||
NetClock::time_point const expiration2 =
|
||||
env.timeKeeper().now() + 60s;
|
||||
@@ -802,14 +854,18 @@ private:
|
||||
trustedKeys->applyList (
|
||||
manifest, blob2, sig2, version));
|
||||
|
||||
trustedKeys->onConsensusStart (activeValidators);
|
||||
for(Validator const & val : list2)
|
||||
{
|
||||
BEAST_EXPECT(trustedKeys->trusted (val.masterPublic));
|
||||
BEAST_EXPECT(trustedKeys->trusted (val.signingPublic));
|
||||
}
|
||||
changes = trustedKeys->updateTrusted (activeValidators);
|
||||
BEAST_EXPECT(changes.removed.empty());
|
||||
BEAST_EXPECT(
|
||||
changes.added ==
|
||||
asNodeIDs({list2[0].masterPublic, list2[1].masterPublic}));
|
||||
for(Validator const & val : list2)
|
||||
{
|
||||
BEAST_EXPECT(trustedKeys->trusted (val.masterPublic));
|
||||
BEAST_EXPECT(trustedKeys->trusted (val.signingPublic));
|
||||
}
|
||||
BEAST_EXPECT(! trustedKeys->trusted (list[1].masterPublic));
|
||||
BEAST_EXPECT(! trustedKeys->trusted (list[1].signingPublic));
|
||||
BEAST_EXPECT(! trustedKeys->trusted (list[1].signingPublic));
|
||||
BEAST_EXPECT(trustedKeys->quorum () == 2);
|
||||
}
|
||||
{
|
||||
@@ -818,7 +874,8 @@ private:
|
||||
manifests, manifests, env.timeKeeper(), beast::Journal ());
|
||||
|
||||
std::vector<std::string> cfgPublishers;
|
||||
hash_set<PublicKey> activeValidators;
|
||||
hash_set<NodeID> activeValidators;
|
||||
hash_set<PublicKey> activeKeys;
|
||||
|
||||
std::vector<std::string> cfgKeys;
|
||||
cfgKeys.reserve(9);
|
||||
@@ -828,15 +885,19 @@ private:
|
||||
auto const valKey = randomNode();
|
||||
cfgKeys.push_back (toBase58(
|
||||
TokenType::TOKEN_NODE_PUBLIC, valKey));
|
||||
activeValidators.emplace (valKey);
|
||||
activeValidators.emplace (calcNodeID(valKey));
|
||||
activeKeys.emplace(valKey);
|
||||
|
||||
BEAST_EXPECT(trustedKeys->load (
|
||||
emptyLocalKey, cfgKeys, cfgPublishers));
|
||||
trustedKeys->onConsensusStart (activeValidators);
|
||||
TrustChanges changes =
|
||||
trustedKeys->updateTrusted(activeValidators);
|
||||
BEAST_EXPECT(changes.removed.empty());
|
||||
BEAST_EXPECT(changes.added == asNodeIDs({valKey}));
|
||||
BEAST_EXPECT(trustedKeys->quorum () ==
|
||||
((cfgKeys.size() <= 6) ? cfgKeys.size()/2 + 1 :
|
||||
cfgKeys.size() * 2/3 + 1));
|
||||
for (auto const& key : activeValidators)
|
||||
for (auto const& key : activeKeys)
|
||||
BEAST_EXPECT(trustedKeys->trusted (key));
|
||||
}
|
||||
}
|
||||
@@ -847,8 +908,8 @@ private:
|
||||
|
||||
auto const localKey = randomNode();
|
||||
std::vector<std::string> cfgPublishers;
|
||||
hash_set<PublicKey> activeValidators;
|
||||
|
||||
hash_set<NodeID> activeValidators;
|
||||
hash_set<PublicKey> activeKeys;
|
||||
std::vector<std::string> cfgKeys {
|
||||
toBase58(TokenType::TOKEN_NODE_PUBLIC, localKey)};
|
||||
cfgKeys.reserve(9);
|
||||
@@ -858,17 +919,25 @@ private:
|
||||
auto const valKey = randomNode();
|
||||
cfgKeys.push_back (toBase58(
|
||||
TokenType::TOKEN_NODE_PUBLIC, valKey));
|
||||
activeValidators.emplace (valKey);
|
||||
activeValidators.emplace (calcNodeID(valKey));
|
||||
activeKeys.emplace(valKey);
|
||||
|
||||
BEAST_EXPECT(trustedKeys->load (
|
||||
localKey, cfgKeys, cfgPublishers));
|
||||
trustedKeys->onConsensusStart (activeValidators);
|
||||
TrustChanges changes =
|
||||
trustedKeys->updateTrusted(activeValidators);
|
||||
BEAST_EXPECT(changes.removed.empty());
|
||||
if (cfgKeys.size() > 2)
|
||||
BEAST_EXPECT(changes.added == asNodeIDs({valKey}));
|
||||
else
|
||||
BEAST_EXPECT(
|
||||
changes.added == asNodeIDs({localKey, valKey}));
|
||||
|
||||
BEAST_EXPECT(trustedKeys->quorum () ==
|
||||
((cfgKeys.size() <= 6) ? cfgKeys.size()/2 + 1 :
|
||||
(cfgKeys.size() + 1) * 2/3 + 1));
|
||||
|
||||
for (auto const& key : activeValidators)
|
||||
for (auto const& key : activeKeys)
|
||||
BEAST_EXPECT(trustedKeys->trusted (key));
|
||||
}
|
||||
}
|
||||
@@ -878,15 +947,15 @@ private:
|
||||
auto trustedKeys = std::make_unique <ValidatorList> (
|
||||
manifests, manifests, env.timeKeeper(), beast::Journal ());
|
||||
|
||||
hash_set<PublicKey> activeValidators;
|
||||
|
||||
hash_set<NodeID> activeValidators;
|
||||
std::vector<Validator> valKeys;
|
||||
valKeys.reserve(n);
|
||||
|
||||
while (valKeys.size () != n)
|
||||
{
|
||||
valKeys.push_back (randomValidator());
|
||||
activeValidators.emplace (valKeys.back().masterPublic);
|
||||
activeValidators.emplace(
|
||||
calcNodeID(valKeys.back().masterPublic));
|
||||
}
|
||||
|
||||
auto addPublishedList = [this, &env, &trustedKeys, &valKeys]()
|
||||
@@ -923,17 +992,24 @@ private:
|
||||
for (auto i = 0; i < 3; ++i)
|
||||
addPublishedList();
|
||||
|
||||
trustedKeys->onConsensusStart (activeValidators);
|
||||
TrustChanges changes =
|
||||
trustedKeys->updateTrusted(activeValidators);
|
||||
|
||||
// Minimum quorum should be used
|
||||
BEAST_EXPECT(trustedKeys->quorum () == (valKeys.size() * 2/3 + 1));
|
||||
|
||||
hash_set<NodeID> added;
|
||||
std::size_t nTrusted = 0;
|
||||
for (auto const& key : activeValidators)
|
||||
for (auto const& val : valKeys)
|
||||
{
|
||||
if (trustedKeys->trusted (key))
|
||||
if (trustedKeys->trusted (val.masterPublic))
|
||||
{
|
||||
added.insert(calcNodeID(val.masterPublic));
|
||||
++nTrusted;
|
||||
}
|
||||
}
|
||||
BEAST_EXPECT(changes.added == added);
|
||||
BEAST_EXPECT(changes.removed.empty());
|
||||
|
||||
// The number of trusted keys should be 125% of the minimum quorum
|
||||
BEAST_EXPECT(nTrusted ==
|
||||
@@ -979,9 +1055,9 @@ private:
|
||||
manifests, manifests, env.app().timeKeeper(), journal);
|
||||
|
||||
std::vector<Validator> validators = {randomValidator()};
|
||||
hash_set<PublicKey> activeKeys;
|
||||
hash_set<NodeID> activeValidators;
|
||||
for(Validator const & val : validators)
|
||||
activeKeys.insert(val.masterPublic);
|
||||
activeValidators.insert(calcNodeID(val.masterPublic));
|
||||
// Store prepared list data to control when it is applied
|
||||
struct PreparedList
|
||||
{
|
||||
@@ -1053,7 +1129,7 @@ private:
|
||||
// Advance past the first list's expiration, but it remains the
|
||||
// earliest expiration
|
||||
env.timeKeeper().set(prep1.expiration + 1s);
|
||||
trustedKeys->onConsensusStart(activeKeys);
|
||||
trustedKeys->updateTrusted(activeValidators);
|
||||
BEAST_EXPECT(
|
||||
trustedKeys->expires() &&
|
||||
trustedKeys->expires().get() == prep1.expiration);
|
||||
@@ -1066,7 +1142,7 @@ public:
|
||||
testGenesisQuorum ();
|
||||
testConfigLoad ();
|
||||
testApplyList ();
|
||||
testUpdate ();
|
||||
testUpdateTrusted ();
|
||||
testExpires ();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -169,7 +169,7 @@ class Validations_test : public beast::unit_test::suite
|
||||
struct StaleData
|
||||
{
|
||||
std::vector<Validation> stale;
|
||||
hash_map<PeerKey, Validation> flushed;
|
||||
hash_map<PeerID, Validation> flushed;
|
||||
};
|
||||
|
||||
// Generic Validations adaptor that saves stale/flushed data into
|
||||
@@ -216,7 +216,7 @@ class Validations_test : public beast::unit_test::suite
|
||||
}
|
||||
|
||||
void
|
||||
flush(hash_map<PeerKey, Validation>&& remaining)
|
||||
flush(hash_map<PeerID, Validation>&& remaining)
|
||||
{
|
||||
staleData_.flushed = std::move(remaining);
|
||||
}
|
||||
@@ -250,8 +250,7 @@ class Validations_test : public beast::unit_test::suite
|
||||
ValStatus
|
||||
add(Validation const& v)
|
||||
{
|
||||
PeerKey masterKey{v.nodeID(), 0};
|
||||
return tv_.add(masterKey, v);
|
||||
return tv_.add(v.nodeID(), v);
|
||||
}
|
||||
|
||||
TestValidations&
|
||||
@@ -284,7 +283,7 @@ class Validations_test : public beast::unit_test::suite
|
||||
return staleData_.stale;
|
||||
}
|
||||
|
||||
hash_map<PeerKey, Validation> const&
|
||||
hash_map<PeerID, Validation> const&
|
||||
flushed() const
|
||||
{
|
||||
return staleData_.flushed;
|
||||
@@ -462,7 +461,7 @@ class Validations_test : public beast::unit_test::suite
|
||||
|
||||
std::vector<Trigger> triggers = {
|
||||
[&](TestValidations& vals) { vals.currentTrusted(); },
|
||||
[&](TestValidations& vals) { vals.getCurrentPublicKeys(); },
|
||||
[&](TestValidations& vals) { vals.getCurrentNodeIDs(); },
|
||||
[&](TestValidations& vals) { vals.getPreferred(genesisLedger); },
|
||||
[&](TestValidations& vals) {
|
||||
vals.getNodesAfter(ledgerA, ledgerA.id());
|
||||
@@ -610,9 +609,9 @@ class Validations_test : public beast::unit_test::suite
|
||||
ValStatus::current == harness.add(node.validate(ledgerA)));
|
||||
|
||||
{
|
||||
hash_set<PeerKey> const expectedKeys = {a.masterKey(),
|
||||
b.masterKey()};
|
||||
BEAST_EXPECT(harness.vals().getCurrentPublicKeys() == expectedKeys);
|
||||
hash_set<PeerID> const expectedKeys = {a.nodeID(),
|
||||
b.nodeID()};
|
||||
BEAST_EXPECT(harness.vals().getCurrentNodeIDs() == expectedKeys);
|
||||
}
|
||||
|
||||
harness.clock().advance(3s);
|
||||
@@ -626,14 +625,14 @@ class Validations_test : public beast::unit_test::suite
|
||||
ValStatus::current == harness.add(node.partial(ledgerAC)));
|
||||
|
||||
{
|
||||
hash_set<PeerKey> const expectedKeys = {a.masterKey(),
|
||||
b.masterKey()};
|
||||
BEAST_EXPECT(harness.vals().getCurrentPublicKeys() == expectedKeys);
|
||||
hash_set<PeerID> const expectedKeys = {a.nodeID(),
|
||||
b.nodeID()};
|
||||
BEAST_EXPECT(harness.vals().getCurrentNodeIDs() == expectedKeys);
|
||||
}
|
||||
|
||||
// Pass enough time for them to go stale
|
||||
harness.clock().advance(harness.parms().validationCURRENT_LOCAL);
|
||||
BEAST_EXPECT(harness.vals().getCurrentPublicKeys().empty());
|
||||
BEAST_EXPECT(harness.vals().getCurrentNodeIDs().empty());
|
||||
}
|
||||
|
||||
void
|
||||
@@ -719,7 +718,7 @@ class Validations_test : public beast::unit_test::suite
|
||||
if (val.trusted())
|
||||
trustedValidations[val.ledgerID()].emplace_back(val);
|
||||
}
|
||||
// d diagrees
|
||||
// d disagrees
|
||||
{
|
||||
auto const val = d.validate(ledgerB);
|
||||
BEAST_EXPECT(ValStatus::current == harness.add(val));
|
||||
@@ -786,21 +785,21 @@ class Validations_test : public beast::unit_test::suite
|
||||
Ledger ledgerA = h["a"];
|
||||
Ledger ledgerAB = h["ab"];
|
||||
|
||||
hash_map<PeerKey, Validation> expected;
|
||||
hash_map<PeerID, Validation> expected;
|
||||
for (auto const& node : {a, b, c})
|
||||
{
|
||||
auto const val = node.validate(ledgerA);
|
||||
BEAST_EXPECT(ValStatus::current == harness.add(val));
|
||||
expected.emplace(node.masterKey(), val);
|
||||
expected.emplace(node.nodeID(), val);
|
||||
}
|
||||
Validation staleA = expected.find(a.masterKey())->second;
|
||||
Validation staleA = expected.find(a.nodeID())->second;
|
||||
|
||||
// Send in a new validation for a, saving the new one into the expected
|
||||
// map after setting the proper prior ledger ID it replaced
|
||||
harness.clock().advance(1s);
|
||||
auto newVal = a.validate(ledgerAB);
|
||||
BEAST_EXPECT(ValStatus::current == harness.add(newVal));
|
||||
expected.find(a.masterKey())->second = newVal;
|
||||
expected.find(a.nodeID())->second = newVal;
|
||||
|
||||
// Now flush
|
||||
harness.vals().flush();
|
||||
@@ -1056,6 +1055,97 @@ class Validations_test : public beast::unit_test::suite
|
||||
BEAST_EXPECT(enforcer(clock.now(), Seq{1}, p));
|
||||
}
|
||||
|
||||
void
|
||||
testTrustChanged()
|
||||
{
|
||||
testcase("TrustChanged");
|
||||
using namespace std::chrono;
|
||||
|
||||
auto checker = [this](
|
||||
TestValidations& vals,
|
||||
hash_set<PeerID> const& listed,
|
||||
std::vector<Validation> const& trustedVals) {
|
||||
Ledger::ID testID = trustedVals.empty() ? this->genesisLedger.id()
|
||||
: trustedVals[0].ledgerID();
|
||||
BEAST_EXPECT(vals.currentTrusted() == trustedVals);
|
||||
BEAST_EXPECT(vals.getCurrentNodeIDs() == listed);
|
||||
BEAST_EXPECT(
|
||||
vals.getNodesAfter(this->genesisLedger, genesisLedger.id()) ==
|
||||
trustedVals.size());
|
||||
BEAST_EXPECT(
|
||||
vals.getPreferred(this->genesisLedger).second == testID);
|
||||
BEAST_EXPECT(vals.getTrustedForLedger(testID) == trustedVals);
|
||||
BEAST_EXPECT(
|
||||
vals.numTrustedForLedger(testID) == trustedVals.size());
|
||||
};
|
||||
|
||||
{
|
||||
// Trusted to untrusted
|
||||
LedgerHistoryHelper h;
|
||||
TestHarness harness(h.oracle);
|
||||
Node a = harness.makeNode();
|
||||
Ledger ledgerAB = h["ab"];
|
||||
Validation v = a.validate(ledgerAB);
|
||||
BEAST_EXPECT(ValStatus::current == harness.add(v));
|
||||
|
||||
hash_set<PeerID> listed({a.nodeID()});
|
||||
std::vector<Validation> trustedVals({v});
|
||||
checker(harness.vals(), listed, trustedVals);
|
||||
|
||||
trustedVals.clear();
|
||||
harness.vals().trustChanged({}, {a.nodeID()});
|
||||
checker(harness.vals(), listed, trustedVals);
|
||||
}
|
||||
|
||||
{
|
||||
// Untrusted to trusted
|
||||
LedgerHistoryHelper h;
|
||||
TestHarness harness(h.oracle);
|
||||
Node a = harness.makeNode();
|
||||
a.untrust();
|
||||
Ledger ledgerAB = h["ab"];
|
||||
Validation v = a.validate(ledgerAB);
|
||||
BEAST_EXPECT(ValStatus::current == harness.add(v));
|
||||
|
||||
hash_set<PeerID> listed({a.nodeID()});
|
||||
std::vector<Validation> trustedVals;
|
||||
checker(harness.vals(), listed, trustedVals);
|
||||
|
||||
trustedVals.push_back(v);
|
||||
harness.vals().trustChanged({a.nodeID()}, {});
|
||||
checker(harness.vals(), listed, trustedVals);
|
||||
}
|
||||
|
||||
{
|
||||
// Trusted but not acquired -> untrusted
|
||||
LedgerHistoryHelper h;
|
||||
TestHarness harness(h.oracle);
|
||||
Node a = harness.makeNode();
|
||||
Validation v =
|
||||
a.validate(Ledger::ID{2}, Ledger::Seq{2}, 0s, 0s, true);
|
||||
BEAST_EXPECT(ValStatus::current == harness.add(v));
|
||||
|
||||
hash_set<PeerID> listed({a.nodeID()});
|
||||
std::vector<Validation> trustedVals({v});
|
||||
auto& vals = harness.vals();
|
||||
BEAST_EXPECT(vals.currentTrusted() == trustedVals);
|
||||
BEAST_EXPECT(
|
||||
vals.getPreferred(genesisLedger).second == v.ledgerID());
|
||||
BEAST_EXPECT(
|
||||
vals.getNodesAfter(genesisLedger, genesisLedger.id()) == 0);
|
||||
|
||||
trustedVals.clear();
|
||||
harness.vals().trustChanged({}, {a.nodeID()});
|
||||
// make acquiring ledger available
|
||||
h["ab"];
|
||||
BEAST_EXPECT(vals.currentTrusted() == trustedVals);
|
||||
BEAST_EXPECT(
|
||||
vals.getPreferred(genesisLedger).second == genesisLedger.id());
|
||||
BEAST_EXPECT(
|
||||
vals.getNodesAfter(genesisLedger, genesisLedger.id()) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
run() override
|
||||
{
|
||||
@@ -1072,6 +1162,7 @@ class Validations_test : public beast::unit_test::suite
|
||||
testAcquireValidatedLedger();
|
||||
testNumTrustedForLedger();
|
||||
testSeqEnforcer();
|
||||
testTrustChanged();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -149,7 +149,7 @@ struct Peer
|
||||
}
|
||||
|
||||
void
|
||||
flush(hash_map<PeerKey, Validation>&& remaining)
|
||||
flush(hash_map<PeerID, Validation>&& remaining)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -681,9 +681,9 @@ struct Peer
|
||||
{
|
||||
v.setTrusted();
|
||||
v.setSeen(now());
|
||||
ValStatus const res = validations.add(v.key(), v);
|
||||
ValStatus const res = validations.add(v.nodeID(), v);
|
||||
|
||||
if(res == ValStatus::stale || res == ValStatus::repeatID)
|
||||
if(res == ValStatus::stale)
|
||||
return false;
|
||||
|
||||
// Acquire will try to get from network if not already local
|
||||
@@ -875,8 +875,10 @@ struct Peer
|
||||
|
||||
issue(StartRound{bestLCL, lastClosedLedger});
|
||||
|
||||
// Not yet modeling dynamic UNL.
|
||||
hash_set<PeerID> nowUntrusted;
|
||||
consensus.startRound(
|
||||
now(), bestLCL, lastClosedLedger, runAsValidator);
|
||||
now(), bestLCL, lastClosedLedger, nowUntrusted, runAsValidator);
|
||||
}
|
||||
|
||||
// Start the consensus process assuming it is not yet running
|
||||
@@ -895,7 +897,7 @@ struct Peer
|
||||
{
|
||||
// We don't care about the actual epochs, but do want the
|
||||
// generated NetClock time to be well past its epoch to ensure
|
||||
// any subtractions of two NetClock::time_point in the consensu
|
||||
// any subtractions of two NetClock::time_point in the consensus
|
||||
// code are positive. (e.g. proposeFRESHNESS)
|
||||
using namespace std::chrono;
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
@@ -173,6 +173,12 @@ public:
|
||||
trusted_ = true;
|
||||
}
|
||||
|
||||
void
|
||||
setUntrusted()
|
||||
{
|
||||
trusted_ = false;
|
||||
}
|
||||
|
||||
void
|
||||
setSeen(NetClock::time_point seen)
|
||||
{
|
||||
|
||||
@@ -308,11 +308,11 @@ public:
|
||||
|
||||
env.app().validatorSites().start();
|
||||
env.app().validatorSites().join();
|
||||
std::set<PublicKey> startKeys;
|
||||
hash_set<NodeID> startKeys;
|
||||
for (auto const& val : validators)
|
||||
startKeys.insert(val.masterPublic);
|
||||
startKeys.insert(calcNodeID(val.masterPublic));
|
||||
|
||||
env.app().validators().onConsensusStart(startKeys);
|
||||
env.app().validators().updateTrusted(startKeys);
|
||||
|
||||
{
|
||||
auto const jrr = env.rpc("server_info")[jss::result];
|
||||
|
||||
Reference in New Issue
Block a user