3#include <xrpld/app/consensus/RCLValidations.h>
4#include <xrpld/app/ledger/Ledger.h>
5#include <xrpld/app/misc/NegativeUNLVote.h>
6#include <xrpld/app/misc/ValidatorList.h>
7#include <xrpld/app/tx/apply.h>
9#include <xrpl/beast/unit_test.h>
10#include <xrpl/ledger/View.h>
202 testcase(
"Create UNLModify Tx and apply to ledgers");
218 auto txDisable_0 =
createTx(
true, l->seq(), publicKeys[0]);
219 auto txReEnable_1 =
createTx(
false, l->seq(), publicKeys[1]);
231 for (
auto i = 0; i < 256 - 2; ++i)
235 BEAST_EXPECT(l->isFlagLedger());
236 l->updateNegativeUNL();
238 auto txDisable_0 =
createTx(
true, l->seq(), publicKeys[0]);
239 auto txDisable_1 =
createTx(
true, l->seq(), publicKeys[1]);
240 auto txReEnable_2 =
createTx(
false, l->seq(), publicKeys[2]);
250 BEAST_EXPECT(good_size);
253 BEAST_EXPECT(l->validatorToDisable() == publicKeys[0]);
255 uint256 txID = txDisable_0.getTransactionID();
256 BEAST_EXPECT(l->txExists(txID));
262 for (
auto i = 0; i < 256; ++i)
265 BEAST_EXPECT(good_size);
267 BEAST_EXPECT(l->validatorToDisable() == publicKeys[0]);
270 BEAST_EXPECT(l->isFlagLedger());
271 l->updateNegativeUNL();
276 BEAST_EXPECT(good_size);
279 BEAST_EXPECT(*(l->negativeUNL().begin()) == publicKeys[0]);
280 nUnlLedgerSeq.
emplace(publicKeys[0], l->seq());
283 auto txDisable_0 =
createTx(
true, l->seq(), publicKeys[0]);
284 auto txDisable_1 =
createTx(
true, l->seq(), publicKeys[1]);
285 auto txReEnable_0 =
createTx(
false, l->seq(), publicKeys[0]);
286 auto txReEnable_1 =
createTx(
false, l->seq(), publicKeys[1]);
287 auto txReEnable_2 =
createTx(
false, l->seq(), publicKeys[2]);
297 BEAST_EXPECT(good_size);
300 BEAST_EXPECT(l->negativeUNL().count(publicKeys[0]));
301 BEAST_EXPECT(l->validatorToDisable() == publicKeys[1]);
302 BEAST_EXPECT(l->validatorToReEnable() == publicKeys[0]);
310 for (
auto i = 0; i < 256; ++i)
313 BEAST_EXPECT(good_size);
316 BEAST_EXPECT(l->negativeUNL().count(publicKeys[0]));
317 BEAST_EXPECT(l->validatorToDisable() == publicKeys[1]);
318 BEAST_EXPECT(l->validatorToReEnable() == publicKeys[0]);
322 BEAST_EXPECT(l->isFlagLedger());
323 l->updateNegativeUNL();
328 BEAST_EXPECT(good_size);
331 BEAST_EXPECT(l->negativeUNL().count(publicKeys[1]));
334 auto txDisable_0 =
createTx(
true, l->seq(), publicKeys[0]);
340 BEAST_EXPECT(good_size);
343 BEAST_EXPECT(l->negativeUNL().count(publicKeys[1]));
344 BEAST_EXPECT(l->validatorToDisable() == publicKeys[0]);
345 nUnlLedgerSeq.
emplace(publicKeys[1], l->seq());
346 nUnlLedgerSeq.
erase(publicKeys[0]);
353 for (
auto i = 0; i < 256; ++i)
356 BEAST_EXPECT(good_size);
359 BEAST_EXPECT(l->negativeUNL().count(publicKeys[1]));
360 BEAST_EXPECT(l->validatorToDisable() == publicKeys[0]);
364 BEAST_EXPECT(l->isFlagLedger());
365 l->updateNegativeUNL();
370 BEAST_EXPECT(good_size);
373 BEAST_EXPECT(l->negativeUNL().count(publicKeys[0]));
374 BEAST_EXPECT(l->negativeUNL().count(publicKeys[1]));
375 nUnlLedgerSeq.
emplace(publicKeys[0], l->seq());
379 auto txDisable_0 =
createTx(
true, l->seq(), publicKeys[0]);
380 auto txReEnable_0 =
createTx(
false, l->seq(), publicKeys[0]);
381 auto txReEnable_1 =
createTx(
false, l->seq(), publicKeys[1]);
389 BEAST_EXPECT(good_size);
392 BEAST_EXPECT(l->negativeUNL().count(publicKeys[0]));
393 BEAST_EXPECT(l->negativeUNL().count(publicKeys[1]));
394 BEAST_EXPECT(l->validatorToReEnable() == publicKeys[0]);
401 for (
auto i = 0; i < 256; ++i)
404 BEAST_EXPECT(good_size);
407 BEAST_EXPECT(l->negativeUNL().count(publicKeys[0]));
408 BEAST_EXPECT(l->negativeUNL().count(publicKeys[1]));
409 BEAST_EXPECT(l->validatorToReEnable() == publicKeys[0]);
413 BEAST_EXPECT(l->isFlagLedger());
414 l->updateNegativeUNL();
419 BEAST_EXPECT(good_size);
422 BEAST_EXPECT(l->negativeUNL().count(publicKeys[1]));
423 nUnlLedgerSeq.
erase(publicKeys[0]);
427 auto txReEnable_1 =
createTx(
false, l->seq(), publicKeys[1]);
433 BEAST_EXPECT(good_size);
436 BEAST_EXPECT(l->negativeUNL().count(publicKeys[1]));
437 BEAST_EXPECT(l->validatorToReEnable() == publicKeys[1]);
444 for (
auto i = 0; i < 256; ++i)
447 BEAST_EXPECT(good_size);
450 BEAST_EXPECT(l->negativeUNL().count(publicKeys[1]));
451 BEAST_EXPECT(l->validatorToReEnable() == publicKeys[1]);
455 BEAST_EXPECT(l->isFlagLedger());
456 l->updateNegativeUNL();
464 for (
auto i = 0; i < 256; ++i)
469 BEAST_EXPECT(l->isFlagLedger());
470 l->updateNegativeUNL();
550 if (l->isFlagLedger())
552 l->updateNegativeUNL();
596 v.setFieldH256(sfLedgerHash, ledger->header().hash);
597 v.setFieldU32(sfLedgerSequence, ledger->seq());
598 v.setFlag(vfFullValidation);
609 template <
class NeedVal
idation>
661template <
typename PreVote = decltype(defaultPreVote)>
669 return countTx(txSet) == expect;
691 BEAST_EXPECT(
countTx(txSet) == 0);
693 BEAST_EXPECT(
countTx(txSet) == 1);
695 BEAST_EXPECT(
countTx(txSet) == 2);
715 BEAST_EXPECT(vote.
choose(pad_0, candidates) == n_1);
716 BEAST_EXPECT(vote.
choose(pad_f, candidates) == n_1);
717 candidates.emplace_back(2);
718 BEAST_EXPECT(vote.
choose(pad_0, candidates) == n_1);
719 BEAST_EXPECT(vote.
choose(pad_f, candidates) == n_2);
720 candidates.emplace_back(3);
721 BEAST_EXPECT(vote.
choose(pad_0, candidates) == n_1);
722 BEAST_EXPECT(vote.
choose(pad_f, candidates) == n_3);
769 return !(history.
UNLNodeIDs[idx] == myId && l->seq() % 2 == 0);
782 BEAST_EXPECT(wrongChainSuccess);
801 for (
auto& l : wrongChain)
814 BEAST_EXPECT(scoreTable);
817 for (
auto const& [n, score] : *scoreTable)
820 BEAST_EXPECT(score == 256);
822 BEAST_EXPECT(score == 0);
842 BEAST_EXPECT(scoreTable);
845 for (
auto const& [_, score] : *scoreTable)
848 BEAST_EXPECT(score == 256);
876 auto [disableCandidates, reEnableCandidates] = vote.
findAllCandidates(unl, negUnl, scoreTable);
877 bool rightDisable = disableCandidates.size() == numDisable;
878 bool rightReEnable = reEnableCandidates.size() == numReEnable;
879 return rightDisable && rightReEnable;
936 auto scoreTable = goodScoreTable;
943 auto scoreTable = goodScoreTable;
960 auto scoreTable = goodScoreTable;
981 auto scoreTable = goodScoreTable;
985 negUnl_temp.
insert(new_1);
986 negUnl_temp.
insert(new_2);
991 auto scoreTable = goodScoreTable;
992 scoreTable[new_1] = 0;
993 scoreTable[new_2] = 0;
999 auto scoreTable = goodScoreTable;
1000 scoreTable[new_1] = 0;
1001 scoreTable[new_2] = 0;
1010 testcase(
"Find All Candidates Combination");
1054 for (
auto const& k : keys)
1057 unl.emplace(nodeIDs.
back());
1058 scoreTable[nodeIDs.
back()] = score;
1061 negUnl.insert(nodeIDs[i]);
1064 for (
auto us : unlSizes)
1066 for (
auto np : nUnlPercent)
1068 for (
auto score : scores)
1073 fillScoreTable(us, us * np / 100, score, unl, negUnl, scoreTable);
1074 BEAST_EXPECT(unl.
size() == us);
1075 BEAST_EXPECT(negUnl.
size() == us * np / 100);
1076 BEAST_EXPECT(scoreTable.
size() == us);
1084 toDisable_expect = us;
1091 toReEnable_expect = us * np / 100;
1098 toReEnable_expect = us;
1116 for (
auto const& k : keys)
1119 unl.emplace(nodeIDs.
back());
1123 for (
auto score : scores)
1125 scoreTable[nodeIDs[nIdx++]] = score;
1126 scoreTable[nodeIDs[nIdx++]] = score;
1128 for (; nIdx < unl_size;)
1130 scoreTable[nodeIDs[nIdx++]] = scores.
back();
1133 if (nUnl_percent == 100)
1137 else if (nUnl_percent == 50)
1140 negUnl.insert(nodeIDs[i]);
1144 for (
auto us : unlSizes)
1146 for (
auto np : nUnlPercent)
1152 fillScoreTable(us, np, unl, negUnl, scoreTable);
1153 BEAST_EXPECT(unl.
size() == us);
1154 BEAST_EXPECT(negUnl.
size() == us * np / 100);
1155 BEAST_EXPECT(scoreTable.
size() == us);
1161 toDisable_expect = 4;
1165 toReEnable_expect = negUnl.
size() - 6;
1169 toReEnable_expect = negUnl.
size() - 12;
1255 testcase(
"Build Score Table Combination");
1264 {{{0, 0, 0}}, {{50, 50, 50}}, {{100, 100, 100}}, {{0, 50, 100}}}};
1266 for (
auto unlSize : unlSizes)
1270 NetworkHistory history = {*
this, {unlSize, 0,
false,
false, 256 + 2}};
1285 bool add_50 = scorePattern[sp][k] == 50 && l->seq() % 2 == 0;
1286 bool add_100 = scorePattern[sp][k] == 100;
1287 bool add_me = history.
UNLNodeIDs[idx] == myId;
1288 return add_50 || add_100 || add_me;
1294 BEAST_EXPECT(scoreTable);
1300 return score == 256;
1301 if (scorePattern[sp][k] == 0)
1303 if (scorePattern[sp][k] == 50)
1304 return score == 256 / 2;
1305 if (scorePattern[sp][k] == 100)
1306 return score == 256;
1312 BEAST_EXPECT(checkScores((*scoreTable)[history.
UNLNodeIDs[i]], 0));
1316 BEAST_EXPECT(checkScores((*scoreTable)[history.
UNLNodeIDs[i]], 1));
1318 for (; i < unlSize; ++i)
1320 BEAST_EXPECT(checkScores((*scoreTable)[history.
UNLNodeIDs[i]], 2));
1531 history.UNLKeySet.erase(history.UNLKeys[0]);
1532 history.UNLKeySet.erase(history.UNLKeys[1]);
1562 auto extra_key_1 = randomKeyPair(KeyType::ed25519).first;
1563 auto extra_key_2 = randomKeyPair(KeyType::ed25519).first;
1564 history.UNLKeySet.insert(extra_key_1);
1565 history.UNLKeySet.insert(extra_key_2);
1566 hash_set<NodeID> nowTrusted;
1567 nowTrusted.insert(calcNodeID(extra_key_1));
1568 nowTrusted.insert(calcNodeID(extra_key_2));
1569 vote.newValidators(history.lastLedger()->seq(), nowTrusted);
1584 auto extra_key_1 = randomKeyPair(KeyType::ed25519).first;
1585 auto extra_key_2 = randomKeyPair(KeyType::ed25519).first;
1586 history.UNLKeySet.insert(extra_key_1);
1587 history.UNLKeySet.insert(extra_key_2);
1588 hash_set<NodeID> nowTrusted;
1589 nowTrusted.insert(calcNodeID(extra_key_1));
1590 nowTrusted.insert(calcNodeID(extra_key_2));
1591 vote.newValidators(256, nowTrusted);
1617 v.setFieldH256(sfLedgerHash, l->header().hash);
1618 v.setFieldU32(sfLedgerSequence, l->seq());
1619 v.setFlag(vfFullValidation);
1630 for (
int i = 0; i < numNodes; ++i)
1638 nUnlKeys.
insert(keyPair.first);
1644 auto& local = *nUnlKeys.
begin();
1646 validators.load(local, cfgKeys, cfgPublishers);
1647 validators.updateTrusted(
1653 BEAST_EXPECT(validators.getTrustedMasterKeys().size() == numNodes);
1654 validators.setNegativeUNL(nUnlKeys);
1655 BEAST_EXPECT(validators.getNegativeUNL().size() == negUnlSize);
1658 BEAST_EXPECT(vals.
size() == numNodes);
1659 vals = validators.negativeUNLFilter(std::move(vals));
1660 BEAST_EXPECT(vals.
size() == numNodes - negUnlSize);
1670BEAST_DEFINE_TESTSUITE(NegativeUNL, consensus,
xrpl);
1672BEAST_DEFINE_TESTSUITE(NegativeUNLVoteInternal, consensus,
xrpl);
1673BEAST_DEFINE_TESTSUITE_MANUAL(NegativeUNLVoteScoreTable, consensus,
xrpl);
1674BEAST_DEFINE_TESTSUITE_PRIO(NegativeUNLVoteGoodScore, consensus,
xrpl, 1);
1675BEAST_DEFINE_TESTSUITE(NegativeUNLVoteOffline, consensus,
xrpl);
1676BEAST_DEFINE_TESTSUITE(NegativeUNLVoteMaxListed, consensus,
xrpl);
1677BEAST_DEFINE_TESTSUITE_PRIO(NegativeUNLVoteRetiredValidator, consensus,
xrpl, 1);
1678BEAST_DEFINE_TESTSUITE(NegativeUNLVoteNewValidator, consensus,
xrpl);
1679BEAST_DEFINE_TESTSUITE(NegativeUNLVoteFilterValidations, consensus,
xrpl);
1687 bool sameSize = l->negativeUNL().size() == size;
1688 bool sameToDisable = (l->validatorToDisable() !=
std::nullopt) == hasToDisable;
1689 bool sameToReEnable = (l->validatorToReEnable() !=
std::nullopt) == hasToReEnable;
1691 return sameSize && sameToDisable && sameToReEnable;
1710 if (!sle->isFieldPresent(sfDisabledValidators))
1713 auto const& nUnlData = sle->getFieldArray(sfDisabledValidators);
1714 if (nUnlData.size() != nUnlLedgerSeq.
size())
1717 for (
auto const& n : nUnlData)
1719 if (!n.isFieldPresent(sfFirstLedgerSequence) || !n.isFieldPresent(sfPublicKey))
1722 auto seq = n.getFieldU32(sfFirstLedgerSequence);
1723 auto d = n.getFieldVL(sfPublicKey);
1728 auto it = nUnlLedgerSeq.
find(pk);
1729 if (it == nUnlLedgerSeq.
end())
1731 if (it->second !=
seq)
1733 nUnlLedgerSeq.
erase(it);
1735 return nUnlLedgerSeq.
size() == 0;
1742 for (
auto i = txSet->begin(); i != txSet->end(); ++i)
1756 for (
int i = 0; i < n; ++i)
1768 auto fill = [&](
auto& obj) {
1769 obj.setFieldU8(sfUNLModifyDisabling, disabling ? 1 : 0);
1770 obj.setFieldU32(sfLedgerSequence,
seq);
1771 obj.setFieldVL(sfUNLModifyValidator, txKey);
1773 return STTx(ttUNL_MODIFY, fill);
testcase_t testcase
Memberspace for declaring test cases.
virtual Config & config()=0
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.
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_
Candidates const 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.
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.
virtual ValidatorList & validators()=0
virtual NetworkOPs & getOPs()=0
virtual Overlay & overlay()=0
virtual HashRouter & getHashRouter()=0
virtual Family & getNodeFamily()=0
virtual TimeKeeper & timeKeeper()=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()
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(Application &app, 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.
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.