3#include <xrpld/app/consensus/RCLValidations.h>
4#include <xrpld/app/misc/NegativeUNLVote.h>
5#include <xrpld/app/misc/ValidatorList.h>
7#include <xrpl/beast/unit_test.h>
8#include <xrpl/ledger/OpenView.h>
9#include <xrpl/tx/apply.h>
66 hash_map<PublicKey, std::uint32_t> nUnlLedgerSeq);
207 testcase(
"Create UNLModify Tx and apply to ledgers");
215 env.
app().config().FEES.toFees(),
227 auto txDisable_0 =
createTx(
true, l->seq(), publicKeys[0]);
228 auto txReEnable_1 =
createTx(
false, l->seq(), publicKeys[1]);
240 for (
auto i = 0; i < 256 - 2; ++i)
244 BEAST_EXPECT(l->isFlagLedger());
245 l->updateNegativeUNL();
247 auto txDisable_0 =
createTx(
true, l->seq(), publicKeys[0]);
248 auto txDisable_1 =
createTx(
true, l->seq(), publicKeys[1]);
249 auto txReEnable_2 =
createTx(
false, l->seq(), publicKeys[2]);
259 BEAST_EXPECT(good_size);
262 BEAST_EXPECT(l->validatorToDisable() == publicKeys[0]);
264 uint256 const txID = txDisable_0.getTransactionID();
265 BEAST_EXPECT(l->txExists(txID));
271 for (
auto i = 0; i < 256; ++i)
274 BEAST_EXPECT(good_size);
276 BEAST_EXPECT(l->validatorToDisable() == publicKeys[0]);
279 BEAST_EXPECT(l->isFlagLedger());
280 l->updateNegativeUNL();
285 BEAST_EXPECT(good_size);
288 BEAST_EXPECT(*(l->negativeUNL().begin()) == publicKeys[0]);
289 nUnlLedgerSeq.
emplace(publicKeys[0], l->seq());
292 auto txDisable_0 =
createTx(
true, l->seq(), publicKeys[0]);
293 auto txDisable_1 =
createTx(
true, l->seq(), publicKeys[1]);
294 auto txReEnable_0 =
createTx(
false, l->seq(), publicKeys[0]);
295 auto txReEnable_1 =
createTx(
false, l->seq(), publicKeys[1]);
296 auto txReEnable_2 =
createTx(
false, l->seq(), publicKeys[2]);
306 BEAST_EXPECT(good_size);
309 BEAST_EXPECT(l->negativeUNL().count(publicKeys[0]));
310 BEAST_EXPECT(l->validatorToDisable() == publicKeys[1]);
311 BEAST_EXPECT(l->validatorToReEnable() == publicKeys[0]);
319 for (
auto i = 0; i < 256; ++i)
322 BEAST_EXPECT(good_size);
325 BEAST_EXPECT(l->negativeUNL().count(publicKeys[0]));
326 BEAST_EXPECT(l->validatorToDisable() == publicKeys[1]);
327 BEAST_EXPECT(l->validatorToReEnable() == publicKeys[0]);
331 BEAST_EXPECT(l->isFlagLedger());
332 l->updateNegativeUNL();
337 BEAST_EXPECT(good_size);
340 BEAST_EXPECT(l->negativeUNL().count(publicKeys[1]));
343 auto txDisable_0 =
createTx(
true, l->seq(), publicKeys[0]);
349 BEAST_EXPECT(good_size);
352 BEAST_EXPECT(l->negativeUNL().count(publicKeys[1]));
353 BEAST_EXPECT(l->validatorToDisable() == publicKeys[0]);
354 nUnlLedgerSeq.
emplace(publicKeys[1], l->seq());
355 nUnlLedgerSeq.
erase(publicKeys[0]);
362 for (
auto i = 0; i < 256; ++i)
365 BEAST_EXPECT(good_size);
368 BEAST_EXPECT(l->negativeUNL().count(publicKeys[1]));
369 BEAST_EXPECT(l->validatorToDisable() == publicKeys[0]);
373 BEAST_EXPECT(l->isFlagLedger());
374 l->updateNegativeUNL();
379 BEAST_EXPECT(good_size);
382 BEAST_EXPECT(l->negativeUNL().count(publicKeys[0]));
383 BEAST_EXPECT(l->negativeUNL().count(publicKeys[1]));
384 nUnlLedgerSeq.
emplace(publicKeys[0], l->seq());
388 auto txDisable_0 =
createTx(
true, l->seq(), publicKeys[0]);
389 auto txReEnable_0 =
createTx(
false, l->seq(), publicKeys[0]);
390 auto txReEnable_1 =
createTx(
false, l->seq(), publicKeys[1]);
398 BEAST_EXPECT(good_size);
401 BEAST_EXPECT(l->negativeUNL().count(publicKeys[0]));
402 BEAST_EXPECT(l->negativeUNL().count(publicKeys[1]));
403 BEAST_EXPECT(l->validatorToReEnable() == publicKeys[0]);
410 for (
auto i = 0; i < 256; ++i)
413 BEAST_EXPECT(good_size);
416 BEAST_EXPECT(l->negativeUNL().count(publicKeys[0]));
417 BEAST_EXPECT(l->negativeUNL().count(publicKeys[1]));
418 BEAST_EXPECT(l->validatorToReEnable() == publicKeys[0]);
422 BEAST_EXPECT(l->isFlagLedger());
423 l->updateNegativeUNL();
428 BEAST_EXPECT(good_size);
431 BEAST_EXPECT(l->negativeUNL().count(publicKeys[1]));
432 nUnlLedgerSeq.
erase(publicKeys[0]);
436 auto txReEnable_1 =
createTx(
false, l->seq(), publicKeys[1]);
442 BEAST_EXPECT(good_size);
445 BEAST_EXPECT(l->negativeUNL().count(publicKeys[1]));
446 BEAST_EXPECT(l->validatorToReEnable() == publicKeys[1]);
453 for (
auto i = 0; i < 256; ++i)
456 BEAST_EXPECT(good_size);
459 BEAST_EXPECT(l->negativeUNL().count(publicKeys[1]));
460 BEAST_EXPECT(l->validatorToReEnable() == publicKeys[1]);
464 BEAST_EXPECT(l->isFlagLedger());
465 l->updateNegativeUNL();
473 for (
auto i = 0; i < 256; ++i)
478 BEAST_EXPECT(l->isFlagLedger());
479 l->updateNegativeUNL();
550 env.
app().config().FEES.toFees(),
563 if (l->isFlagLedger())
565 l->updateNegativeUNL();
613 v.setFieldH256(sfLedgerHash, ledger->header().hash);
614 v.setFieldU32(sfLedgerSequence, ledger->seq());
615 v.setFlag(vfFullValidation);
626 template <
class NeedVal
idation>
678template <
typename PreVote = decltype(defaultPreVote)>
691 return countTx(txSet) == expect;
713 BEAST_EXPECT(
countTx(txSet) == 0);
715 BEAST_EXPECT(
countTx(txSet) == 1);
717 BEAST_EXPECT(
countTx(txSet) == 2);
737 BEAST_EXPECT(vote.
choose(pad_0, candidates) == n_1);
738 BEAST_EXPECT(vote.
choose(pad_f, candidates) == n_1);
739 candidates.emplace_back(2);
740 BEAST_EXPECT(vote.
choose(pad_0, candidates) == n_1);
741 BEAST_EXPECT(vote.
choose(pad_f, candidates) == n_2);
742 candidates.emplace_back(3);
743 BEAST_EXPECT(vote.
choose(pad_0, candidates) == n_1);
744 BEAST_EXPECT(vote.
choose(pad_f, candidates) == n_3);
793 return history.
UNLNodeIDs[idx] != myId || l->seq() % 2 != 0;
806 bool const wrongChainSuccess = history.
goodHistory;
807 BEAST_EXPECT(wrongChainSuccess);
826 for (
auto& l : wrongChain)
840 BEAST_EXPECT(scoreTable);
843 for (
auto const& [n, score] : *scoreTable)
847 BEAST_EXPECT(score == 256);
851 BEAST_EXPECT(score == 0);
876 BEAST_EXPECT(scoreTable);
879 for (
auto const& [_, score] : *scoreTable)
882 BEAST_EXPECT(score == 256);
910 auto [disableCandidates, reEnableCandidates] =
912 bool const rightDisable = disableCandidates.size() == numDisable;
913 bool const rightReEnable = reEnableCandidates.size() == numReEnable;
914 return rightDisable && rightReEnable;
974 auto scoreTable = goodScoreTable;
982 auto scoreTable = goodScoreTable;
1000 auto scoreTable = goodScoreTable;
1012 NodeID const new_1(0xbead);
1013 NodeID const new_2(0xbeef);
1021 auto scoreTable = goodScoreTable;
1025 negUnl_temp.
insert(new_1);
1026 negUnl_temp.
insert(new_2);
1032 auto scoreTable = goodScoreTable;
1033 scoreTable[new_1] = 0;
1034 scoreTable[new_2] = 0;
1040 auto scoreTable = goodScoreTable;
1041 scoreTable[new_1] = 0;
1042 scoreTable[new_2] = 0;
1051 testcase(
"Find All Candidates Combination");
1095 for (
auto const& k : keys)
1098 unl.emplace(nodeIDs.
back());
1099 scoreTable[nodeIDs.
back()] = score;
1102 negUnl.insert(nodeIDs[i]);
1105 for (
auto us : unlSizes)
1107 for (
auto np : nUnlPercent)
1109 for (
auto score : scores)
1114 fillScoreTable(us, us * np / 100, score, unl, negUnl, scoreTable);
1115 BEAST_EXPECT(unl.
size() == us);
1116 BEAST_EXPECT(negUnl.
size() == us * np / 100);
1117 BEAST_EXPECT(scoreTable.
size() == us);
1125 toDisable_expect = us;
1132 toReEnable_expect = us * np / 100;
1139 toReEnable_expect = us;
1143 vote, unl, negUnl, scoreTable, toDisable_expect, toReEnable_expect));
1157 for (
auto const& k : keys)
1160 unl.emplace(nodeIDs.
back());
1164 for (
auto score : scores)
1166 scoreTable[nodeIDs[nIdx++]] = score;
1167 scoreTable[nodeIDs[nIdx++]] = score;
1169 for (; nIdx < unl_size;)
1171 scoreTable[nodeIDs[nIdx++]] = scores.
back();
1174 if (nUnl_percent == 100)
1178 else if (nUnl_percent == 50)
1181 negUnl.insert(nodeIDs[i]);
1185 for (
auto us : unlSizes)
1187 for (
auto np : nUnlPercent)
1193 fillScoreTable(us, np, unl, negUnl, scoreTable);
1194 BEAST_EXPECT(unl.
size() == us);
1195 BEAST_EXPECT(negUnl.
size() == us * np / 100);
1196 BEAST_EXPECT(scoreTable.
size() == us);
1202 toDisable_expect = 4;
1206 toReEnable_expect = negUnl.
size() - 6;
1210 toReEnable_expect = negUnl.
size() - 12;
1213 vote, unl, negUnl, scoreTable, toDisable_expect, toReEnable_expect));
1297 testcase(
"Build Score Table Combination");
1306 {{{0, 0, 0}}, {{50, 50, 50}}, {{100, 100, 100}}, {{0, 50, 100}}}};
1308 for (
auto unlSize : unlSizes)
1312 NetworkHistory history = {*
this, {unlSize, 0,
false,
false, 256 + 2}};
1333 bool const add_50 = scorePattern[sp][k] == 50 && l->seq() % 2 == 0;
1334 bool const add_100 = scorePattern[sp][k] == 100;
1335 bool const add_me = history.
UNLNodeIDs[idx] == myId;
1336 return add_50 || add_100 || add_me;
1342 BEAST_EXPECT(scoreTable);
1348 return score == 256;
1349 if (scorePattern[sp][k] == 0)
1351 if (scorePattern[sp][k] == 50)
1352 return score == 256 / 2;
1353 if (scorePattern[sp][k] == 100)
1355 return score == 256;
1362 BEAST_EXPECT(checkScores((*scoreTable)[history.
UNLNodeIDs[i]], 0));
1366 BEAST_EXPECT(checkScores((*scoreTable)[history.
UNLNodeIDs[i]], 1));
1368 for (; i < unlSize; ++i)
1370 BEAST_EXPECT(checkScores((*scoreTable)[history.
UNLNodeIDs[i]], 2));
1593 history.UNLKeySet.erase(history.UNLKeys[0]);
1594 history.UNLKeySet.erase(history.UNLKeys[1]);
1627 auto extra_key_1 = randomKeyPair(KeyType::ed25519).first;
1628 auto extra_key_2 = randomKeyPair(KeyType::ed25519).first;
1629 history.UNLKeySet.insert(extra_key_1);
1630 history.UNLKeySet.insert(extra_key_2);
1631 hash_set<NodeID> nowTrusted;
1632 nowTrusted.insert(calcNodeID(extra_key_1));
1633 nowTrusted.insert(calcNodeID(extra_key_2));
1634 vote.newValidators(history.lastLedger()->seq(), nowTrusted);
1653 auto extra_key_1 = randomKeyPair(KeyType::ed25519).first;
1654 auto extra_key_2 = randomKeyPair(KeyType::ed25519).first;
1655 history.UNLKeySet.insert(extra_key_1);
1656 history.UNLKeySet.insert(extra_key_2);
1657 hash_set<NodeID> nowTrusted;
1658 nowTrusted.insert(calcNodeID(extra_key_1));
1659 nowTrusted.insert(calcNodeID(extra_key_2));
1660 vote.newValidators(256, nowTrusted);
1682 Rules{env.
app().config().features},
1683 env.
app().config().FEES.toFees(),
1694 v.setFieldH256(sfLedgerHash, l->header().hash);
1695 v.setFieldU32(sfLedgerSequence, l->seq());
1696 v.setFlag(vfFullValidation);
1707 for (
int i = 0; i < numNodes; ++i)
1715 nUnlKeys.
insert(keyPair.first);
1721 auto& local = *nUnlKeys.
begin();
1723 validators.load(local, cfgKeys, cfgPublishers);
1724 validators.updateTrusted(
1730 BEAST_EXPECT(validators.getTrustedMasterKeys().size() == numNodes);
1731 validators.setNegativeUNL(nUnlKeys);
1732 BEAST_EXPECT(validators.getNegativeUNL().size() == negUnlSize);
1735 BEAST_EXPECT(vals.
size() == numNodes);
1736 vals = validators.negativeUNLFilter(std::move(vals));
1737 BEAST_EXPECT(vals.
size() == numNodes - negUnlSize);
1747BEAST_DEFINE_TESTSUITE(NegativeUNL, consensus,
xrpl);
1749BEAST_DEFINE_TESTSUITE(NegativeUNLVoteInternal, consensus,
xrpl);
1750BEAST_DEFINE_TESTSUITE_MANUAL(NegativeUNLVoteScoreTable, consensus,
xrpl);
1751BEAST_DEFINE_TESTSUITE_PRIO(NegativeUNLVoteGoodScore, consensus,
xrpl, 1);
1752BEAST_DEFINE_TESTSUITE(NegativeUNLVoteOffline, consensus,
xrpl);
1753BEAST_DEFINE_TESTSUITE(NegativeUNLVoteMaxListed, consensus,
xrpl);
1754BEAST_DEFINE_TESTSUITE_PRIO(NegativeUNLVoteRetiredValidator, consensus,
xrpl, 1);
1755BEAST_DEFINE_TESTSUITE(NegativeUNLVoteNewValidator, consensus,
xrpl);
1756BEAST_DEFINE_TESTSUITE(NegativeUNLVoteFilterValidations, consensus,
xrpl);
1768 bool const sameSize = l->negativeUNL().size() == size;
1769 bool const sameToDisable = (l->validatorToDisable() !=
std::nullopt) == hasToDisable;
1770 bool const sameToReEnable = (l->validatorToReEnable() !=
std::nullopt) == hasToReEnable;
1772 return sameSize && sameToDisable && sameToReEnable;
1795 if (!sle->isFieldPresent(sfDisabledValidators))
1798 auto const& nUnlData = sle->getFieldArray(sfDisabledValidators);
1799 if (nUnlData.size() != nUnlLedgerSeq.
size())
1802 for (
auto const& n : nUnlData)
1804 if (!n.isFieldPresent(sfFirstLedgerSequence) || !n.isFieldPresent(sfPublicKey))
1807 auto seq = n.getFieldU32(sfFirstLedgerSequence);
1808 auto d = n.getFieldVL(sfPublicKey);
1813 auto it = nUnlLedgerSeq.
find(pk);
1814 if (it == nUnlLedgerSeq.
end())
1816 if (it->second !=
seq)
1818 nUnlLedgerSeq.
erase(it);
1820 return nUnlLedgerSeq.
empty();
1827 for (
auto i = txSet->begin(); i != txSet->end(); ++i)
1841 for (
int i = 0; i < n; ++i)
1853 auto fill = [&](
auto& obj) {
1854 obj.setFieldU8(sfUNLModifyDisabling, disabling ? 1 : 0);
1855 obj.setFieldU32(sfLedgerSequence,
seq);
1856 obj.setFieldVL(sfUNLModifyValidator, txKey);
1858 return STTx(ttUNL_MODIFY, fill);
testcase_t testcase
Memberspace for declaring test cases.
Manager to create NegativeUNL votes.
static constexpr size_t negativeUNLHighWaterMark
An unreliable validator must have more than negativeUNLHighWaterMark validations in the last flag led...
void newValidators(LedgerIndex seq, hash_set< NodeID > const &nowTrusted)
Notify NegativeUNLVote that new validators are added.
static constexpr size_t negativeUNLMinLocalValsToVote
The minimum number of validations of the local node for it to participate in the voting.
Candidates findAllCandidates(hash_set< NodeID > const &unl, hash_set< NodeID > const &negUnl, hash_map< NodeID, std::uint32_t > const &scoreTable)
Process the score table and find all disabling and re-enabling candidates.
static NodeID choose(uint256 const &randomPadData, std::vector< NodeID > const &candidates)
Pick one candidate from a vector of candidates.
void purgeNewValidators(LedgerIndex seq)
Purge validators that are not new anymore.
static constexpr size_t negativeUNLLowWaterMark
A validator is considered unreliable if its validations is less than negativeUNLLowWaterMark in the l...
std::optional< hash_map< NodeID, std::uint32_t > > buildScoreTable(std::shared_ptr< Ledger const > const &prevLedger, hash_set< NodeID > const &unl, RCLValidations &validations)
Build a reliability measurement score table of validators' validation messages in the last flag ledge...
static constexpr size_t newValidatorDisableSkip
We don't want to disable new validators immediately after adding them.
void doVoting(std::shared_ptr< Ledger const > const &prevLedger, hash_set< PublicKey > const &unlKeys, RCLValidations &validations, std::shared_ptr< SHAMap > const &initialSet)
Cast our local vote on the NegativeUNL candidates.
hash_map< NodeID, LedgerIndex > newValidators_
void addTx(LedgerIndex seq, PublicKey const &vp, NegativeUNLModify modify, std::shared_ptr< SHAMap > const &initialSet)
Add a ttUNL_MODIFY Tx to the transaction set.
Writable ledger view that accumulates state and tx changes.
void apply(TxsRawView &to) const
Apply changes.
Wrapper over STValidation for generic Validation code.
Rules controlling protocol behavior.
virtual NetworkOPs & getOPs()=0
virtual ValidatorList & getValidators()=0
virtual HashRouter & getHashRouter()=0
virtual Family & getNodeFamily()=0
virtual Overlay & getOverlay()=0
virtual TimeKeeper & getTimeKeeper()=0
An immutable linear range of bytes.
time_point now() const override
Returns the current time, using the server's clock.
time_point closeTime() const
Returns the predicted close time, in network time.
ValStatus add(NodeID const &nodeID, Validation const &val)
Add a new validation.
time_point now() const override
Returns the current time.
void run() override
Runs the suite.
void testFilterValidations()
void run() override
Runs the suite.
Test the private member functions of NegativeUNLVote.
void testBuildScoreTableSpecialCases()
void testPickOneCandidate()
static bool checkCandidateSizes(NegativeUNLVote &vote, hash_set< NodeID > const &unl, hash_set< NodeID > const &negUnl, hash_map< NodeID, std::uint32_t > const &scoreTable, std::size_t numDisable, std::size_t numReEnable)
Find all candidates and check if the number of candidates meets expectation.
void run() override
Runs the suite.
void testFindAllCandidatesCombination()
void testFindAllCandidates()
void run() override
Runs the suite.
void run() override
Runs the suite.
void run() override
Runs the suite.
void run() override
Runs the suite.
Rest the build score table function of NegativeUNLVote.
void testBuildScoreTableCombination()
void run() override
Runs the suite.
void testNegativeUNL()
Test filling and applying ttUNL_MODIFY Tx, as well as ledger update:
void run() override
Runs the suite.
A transaction testing environment.
ManualTimeKeeper & timeKeeper()
beast::Journal const journal
T emplace_back(T... args)
Keylet const & negativeUNL() noexcept
The (fixed) index of the object containing the ledger negativeUNL.
auto const data
General field definitions, or fields used in multiple transaction namespaces.
FeatureBitset testable_amendments()
bool negUnlSizeTest(std::shared_ptr< Ledger const > const &l, size_t size, bool hasToDisable, bool hasToReEnable)
Test the size of the negative UNL in a ledger, also test if the ledger has ToDisable and/or ToReEnabl...
bool voteAndCheck(NetworkHistory &history, NodeID const &myId, std::size_t expect, PreVote const &pre=defaultPreVote)
Create a NegativeUNLVote object.
bool applyAndTestResult(jtx::Env &env, OpenView &view, STTx const &tx, bool pass)
Try to apply a ttUNL_MODIFY Tx, and test the apply result.
std::vector< PublicKey > createPublicKeys(std::size_t n)
Create fake public keys.
bool VerifyPubKeyAndSeq(std::shared_ptr< Ledger const > const &l, hash_map< PublicKey, std::uint32_t > nUnlLedgerSeq)
Verify the content of negative UNL entries (public key and ledger sequence) of a ledger.
STTx createTx(bool disabling, LedgerIndex seq, PublicKey const &txKey)
Create ttUNL_MODIFY Tx.
std::size_t countTx(std::shared_ptr< SHAMap > const &txSet)
Count the number of Tx in a TxSet.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
base_uint< 160, detail::NodeIDTag > NodeID
NodeID is a 160-bit hash representing one node.
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.
ApplyResult apply(ServiceRegistry ®istry, OpenView &view, STTx const &tx, ApplyFlags flags, beast::Journal journal)
Apply a transaction to an OpenView.
create_genesis_t const create_genesis
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
std::optional< KeyType > publicKeyType(Slice const &slice)
Returns the type of public key.
std::uint32_t LedgerIndex
A ledger index.
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.
bool isTesSuccess(TER x) noexcept
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)
Only reasonable parameters can be honored, e.g cannot hasToReEnable when nUNLSize == 0.
std::optional< int > numLedgers
if not specified, the number of ledgers in the history is calculated from negUNLSize,...
Utility class for creating validators and ledger history.
std::vector< NodeID > UNLNodeIDs
std::shared_ptr< STValidation > createSTVal(std::shared_ptr< Ledger const > const &ledger, NodeID const &v)
Create a validation.
void walkHistoryAndAddValidations(NeedValidation &&needVal)
Walk the ledger history and create validation messages for the ledgers.
RCLValidations & validations
std::shared_ptr< Ledger const > lastLedger() const
std::vector< PublicKey > UNLKeys
bool createLedgerHistory()
create ledger history and apply needed ttUNL_MODIFY tx at flag ledgers
hash_set< NodeID > UNLNodeIDSet
hash_set< PublicKey > UNLKeySet
NetworkHistory(beast::unit_test::suite &suite, Parameter const &p)
Set the sequence number on a JTx.