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>
67 hash_map<PublicKey, std::uint32_t> nUnlLedgerSeq);
208 testcase(
"Create UNLModify Tx and apply to ledgers");
228 auto txDisable_0 =
createTx(
true, l->seq(), publicKeys[0]);
229 auto txReEnable_1 =
createTx(
false, l->seq(), publicKeys[1]);
241 for (
auto i = 0; i < 256 - 2; ++i)
246 BEAST_EXPECT(l->isFlagLedger());
247 l->updateNegativeUNL();
249 auto txDisable_0 =
createTx(
true, l->seq(), publicKeys[0]);
250 auto txDisable_1 =
createTx(
true, l->seq(), publicKeys[1]);
251 auto txReEnable_2 =
createTx(
false, l->seq(), publicKeys[2]);
261 BEAST_EXPECT(good_size);
264 BEAST_EXPECT(l->validatorToDisable() == publicKeys[0]);
266 uint256 txID = txDisable_0.getTransactionID();
267 BEAST_EXPECT(l->txExists(txID));
273 for (
auto i = 0; i < 256; ++i)
276 BEAST_EXPECT(good_size);
278 BEAST_EXPECT(l->validatorToDisable() == publicKeys[0]);
282 BEAST_EXPECT(l->isFlagLedger());
283 l->updateNegativeUNL();
288 BEAST_EXPECT(good_size);
291 BEAST_EXPECT(*(l->negativeUNL().begin()) == publicKeys[0]);
292 nUnlLedgerSeq.
emplace(publicKeys[0], l->seq());
295 auto txDisable_0 =
createTx(
true, l->seq(), publicKeys[0]);
296 auto txDisable_1 =
createTx(
true, l->seq(), publicKeys[1]);
297 auto txReEnable_0 =
createTx(
false, l->seq(), publicKeys[0]);
298 auto txReEnable_1 =
createTx(
false, l->seq(), publicKeys[1]);
299 auto txReEnable_2 =
createTx(
false, l->seq(), publicKeys[2]);
309 BEAST_EXPECT(good_size);
312 BEAST_EXPECT(l->negativeUNL().count(publicKeys[0]));
313 BEAST_EXPECT(l->validatorToDisable() == publicKeys[1]);
314 BEAST_EXPECT(l->validatorToReEnable() == publicKeys[0]);
322 for (
auto i = 0; i < 256; ++i)
325 BEAST_EXPECT(good_size);
328 BEAST_EXPECT(l->negativeUNL().count(publicKeys[0]));
329 BEAST_EXPECT(l->validatorToDisable() == publicKeys[1]);
330 BEAST_EXPECT(l->validatorToReEnable() == publicKeys[0]);
335 BEAST_EXPECT(l->isFlagLedger());
336 l->updateNegativeUNL();
341 BEAST_EXPECT(good_size);
344 BEAST_EXPECT(l->negativeUNL().count(publicKeys[1]));
347 auto txDisable_0 =
createTx(
true, l->seq(), publicKeys[0]);
353 BEAST_EXPECT(good_size);
356 BEAST_EXPECT(l->negativeUNL().count(publicKeys[1]));
357 BEAST_EXPECT(l->validatorToDisable() == publicKeys[0]);
358 nUnlLedgerSeq.
emplace(publicKeys[1], l->seq());
359 nUnlLedgerSeq.
erase(publicKeys[0]);
366 for (
auto i = 0; i < 256; ++i)
369 BEAST_EXPECT(good_size);
372 BEAST_EXPECT(l->negativeUNL().count(publicKeys[1]));
373 BEAST_EXPECT(l->validatorToDisable() == publicKeys[0]);
378 BEAST_EXPECT(l->isFlagLedger());
379 l->updateNegativeUNL();
384 BEAST_EXPECT(good_size);
387 BEAST_EXPECT(l->negativeUNL().count(publicKeys[0]));
388 BEAST_EXPECT(l->negativeUNL().count(publicKeys[1]));
389 nUnlLedgerSeq.
emplace(publicKeys[0], l->seq());
393 auto txDisable_0 =
createTx(
true, l->seq(), publicKeys[0]);
394 auto txReEnable_0 =
createTx(
false, l->seq(), publicKeys[0]);
395 auto txReEnable_1 =
createTx(
false, l->seq(), publicKeys[1]);
403 BEAST_EXPECT(good_size);
406 BEAST_EXPECT(l->negativeUNL().count(publicKeys[0]));
407 BEAST_EXPECT(l->negativeUNL().count(publicKeys[1]));
408 BEAST_EXPECT(l->validatorToReEnable() == publicKeys[0]);
415 for (
auto i = 0; i < 256; ++i)
418 BEAST_EXPECT(good_size);
421 BEAST_EXPECT(l->negativeUNL().count(publicKeys[0]));
422 BEAST_EXPECT(l->negativeUNL().count(publicKeys[1]));
423 BEAST_EXPECT(l->validatorToReEnable() == publicKeys[0]);
428 BEAST_EXPECT(l->isFlagLedger());
429 l->updateNegativeUNL();
434 BEAST_EXPECT(good_size);
437 BEAST_EXPECT(l->negativeUNL().count(publicKeys[1]));
438 nUnlLedgerSeq.
erase(publicKeys[0]);
442 auto txReEnable_1 =
createTx(
false, l->seq(), publicKeys[1]);
448 BEAST_EXPECT(good_size);
451 BEAST_EXPECT(l->negativeUNL().count(publicKeys[1]));
452 BEAST_EXPECT(l->validatorToReEnable() == publicKeys[1]);
459 for (
auto i = 0; i < 256; ++i)
462 BEAST_EXPECT(good_size);
465 BEAST_EXPECT(l->negativeUNL().count(publicKeys[1]));
466 BEAST_EXPECT(l->validatorToReEnable() == publicKeys[1]);
471 BEAST_EXPECT(l->isFlagLedger());
472 l->updateNegativeUNL();
480 for (
auto i = 0; i < 256; ++i)
486 BEAST_EXPECT(l->isFlagLedger());
487 l->updateNegativeUNL();
573 if (l->isFlagLedger())
575 l->updateNegativeUNL();
624 v.setFieldH256(sfLedgerHash, ledger->info().hash);
625 v.setFieldU32(sfLedgerSequence, ledger->seq());
626 v.setFlag(vfFullValidation);
637 template <
class NeedVal
idation>
689template <
typename PreVote = decltype(defaultPreVote)>
703 return countTx(txSet) == expect;
728 BEAST_EXPECT(
countTx(txSet) == 0);
730 BEAST_EXPECT(
countTx(txSet) == 1);
732 BEAST_EXPECT(
countTx(txSet) == 2);
752 BEAST_EXPECT(vote.
choose(pad_0, candidates) == n_1);
753 BEAST_EXPECT(vote.
choose(pad_f, candidates) == n_1);
754 candidates.emplace_back(2);
755 BEAST_EXPECT(vote.
choose(pad_0, candidates) == n_1);
756 BEAST_EXPECT(vote.
choose(pad_f, candidates) == n_2);
757 candidates.emplace_back(3);
758 BEAST_EXPECT(vote.
choose(pad_0, candidates) == n_1);
759 BEAST_EXPECT(vote.
choose(pad_f, candidates) == n_3);
833 BEAST_EXPECT(wrongChainSuccess);
854 for (
auto& l : wrongChain)
870 BEAST_EXPECT(scoreTable);
873 for (
auto const& [n, score] : *scoreTable)
876 BEAST_EXPECT(score == 256);
878 BEAST_EXPECT(score == 0);
906 BEAST_EXPECT(scoreTable);
909 for (
auto const& [_, score] : *scoreTable)
912 BEAST_EXPECT(score == 256);
940 auto [disableCandidates, reEnableCandidates] =
942 bool rightDisable = disableCandidates.size() == numDisable;
943 bool rightReEnable = reEnableCandidates.size() == numReEnable;
944 return rightDisable && rightReEnable;
983 vote, history.
UNLNodeIDSet, negUnl_012, goodScoreTable, 0, 3));
991 vote, history.
UNLNodeIDSet, negUnl_012, scoreTable, 35 - 3, 0));
999 vote, history.
UNLNodeIDSet, negUnl_012, scoreTable, 0, 0));
1004 auto scoreTable = goodScoreTable;
1005 scoreTable[*negUnl_012.
begin()] =
1008 vote, history.
UNLNodeIDSet, negUnl_012, scoreTable, 0, 2));
1013 auto scoreTable = goodScoreTable;
1019 vote, history.
UNLNodeIDSet, negUnl_012, scoreTable, 2, 3));
1029 vote, UNL_temp, negUnl_012, goodScoreTable, 0, 3));
1034 auto scoreTable = goodScoreTable;
1043 vote, UNL_temp, negUnl_012, scoreTable, 0, 2));
1057 auto scoreTable = goodScoreTable;
1063 negUnl_temp.
insert(new_1);
1064 negUnl_temp.
insert(new_2);
1066 vote, UNL_temp, negUnl_temp, scoreTable, 0, 3 + 2));
1070 auto scoreTable = goodScoreTable;
1071 scoreTable[new_1] = 0;
1072 scoreTable[new_2] = 0;
1074 vote, UNL_temp, negUnl_012, scoreTable, 0, 3));
1080 auto scoreTable = goodScoreTable;
1081 scoreTable[new_1] = 0;
1082 scoreTable[new_2] = 0;
1084 vote, UNL_temp, negUnl_012, scoreTable, 2, 3));
1092 testcase(
"Find All Candidates Combination");
1128 auto fillScoreTable =
1137 for (
auto const& k : keys)
1140 unl.emplace(nodeIDs.
back());
1141 scoreTable[nodeIDs.
back()] = score;
1144 negUnl.insert(nodeIDs[i]);
1147 for (
auto us : unlSizes)
1149 for (
auto np : nUnlPercent)
1151 for (
auto score : scores)
1157 us, us * np / 100, score, unl, negUnl, scoreTable);
1158 BEAST_EXPECT(unl.
size() == us);
1159 BEAST_EXPECT(negUnl.
size() == us * np / 100);
1160 BEAST_EXPECT(scoreTable.
size() == us);
1169 toDisable_expect = us;
1177 toReEnable_expect = us * np / 100;
1185 toReEnable_expect = us;
1194 toReEnable_expect));
1201 auto fillScoreTable =
1210 for (
auto const& k : keys)
1213 unl.emplace(nodeIDs.
back());
1217 for (
auto score : scores)
1219 scoreTable[nodeIDs[nIdx++]] = score;
1220 scoreTable[nodeIDs[nIdx++]] = score;
1222 for (; nIdx < unl_size;)
1224 scoreTable[nodeIDs[nIdx++]] = scores.
back();
1227 if (nUnl_percent == 100)
1231 else if (nUnl_percent == 50)
1234 negUnl.insert(nodeIDs[i]);
1238 for (
auto us : unlSizes)
1240 for (
auto np : nUnlPercent)
1246 fillScoreTable(us, np, unl, negUnl, scoreTable);
1247 BEAST_EXPECT(unl.
size() == us);
1248 BEAST_EXPECT(negUnl.
size() == us * np / 100);
1249 BEAST_EXPECT(scoreTable.
size() == us);
1255 toDisable_expect = 4;
1259 toReEnable_expect = negUnl.
size() - 6;
1263 toReEnable_expect = negUnl.
size() - 12;
1271 toReEnable_expect));
1359 testcase(
"Build Score Table Combination");
1368 {{{0, 0, 0}}, {{50, 50, 50}}, {{100, 100, 100}}, {{0, 50, 100}}}};
1370 for (
auto unlSize : unlSizes)
1375 *
this, {unlSize, 0,
false,
false, 256 + 2}};
1392 scorePattern[sp][k] == 50 && l->seq() % 2 == 0;
1393 bool add_100 = scorePattern[sp][k] == 100;
1394 bool add_me = history.
UNLNodeIDs[idx] == myId;
1395 return add_50 || add_100 || add_me;
1403 BEAST_EXPECT(scoreTable);
1410 return score == 256;
1411 if (scorePattern[sp][k] == 0)
1413 if (scorePattern[sp][k] == 50)
1414 return score == 256 / 2;
1415 if (scorePattern[sp][k] == 100)
1416 return score == 256;
1422 BEAST_EXPECT(checkScores(
1427 BEAST_EXPECT(checkScores(
1430 for (; i < unlSize; ++i)
1432 BEAST_EXPECT(checkScores(
1662 history.UNLKeySet.erase(history.UNLKeys[0]);
1663 history.UNLKeySet.erase(history.UNLKeys[1]);
1699 randomKeyPair(KeyType::ed25519).first;
1701 randomKeyPair(KeyType::ed25519).first;
1702 history.UNLKeySet.insert(extra_key_1);
1703 history.UNLKeySet.insert(extra_key_2);
1704 hash_set<NodeID> nowTrusted;
1705 nowTrusted.insert(calcNodeID(extra_key_1));
1706 nowTrusted.insert(calcNodeID(extra_key_2));
1708 history.lastLedger()->seq(), nowTrusted);
1735 randomKeyPair(KeyType::ed25519).first;
1737 randomKeyPair(KeyType::ed25519).first;
1738 history.UNLKeySet.insert(extra_key_1);
1739 history.UNLKeySet.insert(extra_key_2);
1740 hash_set<NodeID> nowTrusted;
1741 nowTrusted.insert(calcNodeID(extra_key_1));
1742 nowTrusted.insert(calcNodeID(extra_key_2));
1743 vote.newValidators(256, nowTrusted);
1776 v.setFieldH256(sfLedgerHash, l->info().hash);
1777 v.setFieldU32(sfLedgerSequence, l->seq());
1778 v.setFlag(vfFullValidation);
1789 for (
int i = 0; i < numNodes; ++i)
1797 nUnlKeys.
insert(keyPair.first);
1803 auto& local = *nUnlKeys.
begin();
1805 validators.load(local, cfgKeys, cfgPublishers);
1806 validators.updateTrusted(
1812 BEAST_EXPECT(validators.getTrustedMasterKeys().size() == numNodes);
1813 validators.setNegativeUNL(nUnlKeys);
1814 BEAST_EXPECT(validators.getNegativeUNL().size() == negUnlSize);
1817 BEAST_EXPECT(vals.
size() == numNodes);
1818 vals = validators.negativeUNLFilter(std::move(vals));
1819 BEAST_EXPECT(vals.
size() == numNodes - negUnlSize);
1829BEAST_DEFINE_TESTSUITE(NegativeUNL, consensus,
ripple);
1831BEAST_DEFINE_TESTSUITE(NegativeUNLVoteInternal, consensus,
ripple);
1832BEAST_DEFINE_TESTSUITE_MANUAL(NegativeUNLVoteScoreTable, consensus,
ripple);
1833BEAST_DEFINE_TESTSUITE_PRIO(NegativeUNLVoteGoodScore, consensus,
ripple, 1);
1834BEAST_DEFINE_TESTSUITE(NegativeUNLVoteOffline, consensus,
ripple);
1835BEAST_DEFINE_TESTSUITE(NegativeUNLVoteMaxListed, consensus,
ripple);
1836BEAST_DEFINE_TESTSUITE_PRIO(
1837 NegativeUNLVoteRetiredValidator,
1841BEAST_DEFINE_TESTSUITE(NegativeUNLVoteNewValidator, consensus,
ripple);
1842BEAST_DEFINE_TESTSUITE(NegativeUNLVoteFilterValidations, consensus,
ripple);
1854 bool sameSize = l->negativeUNL().size() == size;
1855 bool sameToDisable =
1856 (l->validatorToDisable() !=
std::nullopt) == hasToDisable;
1857 bool sameToReEnable =
1858 (l->validatorToReEnable() !=
std::nullopt) == hasToReEnable;
1860 return sameSize && sameToDisable && sameToReEnable;
1882 if (!sle->isFieldPresent(sfDisabledValidators))
1885 auto const& nUnlData = sle->getFieldArray(sfDisabledValidators);
1886 if (nUnlData.size() != nUnlLedgerSeq.
size())
1889 for (
auto const& n : nUnlData)
1891 if (!n.isFieldPresent(sfFirstLedgerSequence) ||
1892 !n.isFieldPresent(sfPublicKey))
1895 auto seq = n.getFieldU32(sfFirstLedgerSequence);
1896 auto d = n.getFieldVL(sfPublicKey);
1901 auto it = nUnlLedgerSeq.
find(pk);
1902 if (it == nUnlLedgerSeq.
end())
1904 if (it->second !=
seq)
1906 nUnlLedgerSeq.
erase(it);
1908 return nUnlLedgerSeq.
size() == 0;
1915 for (
auto i = txSet->begin(); i != txSet->end(); ++i)
1929 for (
int i = 0; i < n; ++i)
1941 auto fill = [&](
auto& obj) {
1942 obj.setFieldU8(sfUNLModifyDisabling, disabling ? 1 : 0);
1943 obj.setFieldU32(sfLedgerSequence,
seq);
1944 obj.setFieldVL(sfUNLModifyValidator, txKey);
1946 return STTx(ttUNL_MODIFY, fill);
testcase_t testcase
Memberspace for declaring test cases.
virtual Config & config()=0
virtual Overlay & overlay()=0
virtual TimeKeeper & timeKeeper()=0
virtual NetworkOPs & getOPs()=0
virtual ValidatorList & validators()=0
virtual Family & getNodeFamily()=0
virtual HashRouter & getHashRouter()=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...
NodeID choose(uint256 const &randomPadData, std::vector< NodeID > const &candidates)
Pick one candidate from a vector of candidates.
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...
void purgeNewValidators(LedgerIndex seq)
Purge validators that are not new anymore.
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.
static constexpr size_t newValidatorDisableSkip
We don't want to disable new validators immediately after adding them.
static constexpr size_t negativeUNLLowWaterMark
A validator is considered unreliable if its validations is less than negativeUNLLowWaterMark in the l...
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 newValidators(LedgerIndex seq, hash_set< NodeID > const &nowTrusted)
Notify NegativeUNLVote that new validators are added.
void addTx(LedgerIndex seq, PublicKey const &vp, NegativeUNLModify modify, std::shared_ptr< SHAMap > const &initialSet)
Add a ttUNL_MODIFY Tx to the transaction set.
static constexpr size_t negativeUNLMinLocalValsToVote
The minimum number of validations of the local node for it to participate in the voting.
Writable ledger view that accumulates state and tx changes.
void apply(TxsRawView &to) const
Apply changes.
Wrapper over STValidation for generic Validation code.
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 testPickOneCandidate()
void testFindAllCandidates()
void testBuildScoreTableSpecialCases()
void run() override
Runs the suite.
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 testFindAllCandidatesCombination()
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 run() override
Runs the suite.
void testNegativeUNL()
Test filling and applying ttUNL_MODIFY Tx, as well as ledger update:
A transaction testing environment.
beast::Journal const journal
ManualTimeKeeper & timeKeeper()
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()
std::size_t countTx(std::shared_ptr< SHAMap > const &txSet)
Count the number of Tx in a TxSet.
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 ToDisalbe and/or ToReEnabl...
std::vector< PublicKey > createPublicKeys(std::size_t n)
Create fake public keys.
STTx createTx(bool disabling, LedgerIndex seq, PublicKey const &txKey)
Create ttUNL_MODIFY Tx.
bool applyAndTestResult(jtx::Env &env, OpenView &view, STTx const &tx, bool pass)
Try to apply a ttUNL_MODIFY Tx, and test the apply result.
bool voteAndCheck(NetworkHistory &history, NodeID const &myId, std::size_t expect, PreVote const &pre=defaultPreVote)
Create a NegativeUNLVote object.
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.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
std::uint32_t LedgerIndex
A ledger index.
base_uint< 160, detail::NodeIDTag > NodeID
NodeID is a 160-bit hash representing one node.
PublicKey derivePublicKey(KeyType type, SecretKey const &sk)
Derive the public key from a secret key.
std::optional< KeyType > publicKeyType(Slice const &slice)
Returns the type of public key.
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)
SecretKey randomSecretKey()
Create a secret key using secure random numbers.
NodeID calcNodeID(PublicKey const &)
Calculate the 160-bit node ID from a node public 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::pair< PublicKey, SecretKey > randomKeyPair(KeyType type)
Create a key pair using secure random numbers.
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::shared_ptr< Ledger const > lastLedger() const
void walkHistoryAndAddValidations(NeedValidation &&needVal)
Walk the ledger history and create validation messages for the ledgers.
NetworkHistory(beast::unit_test::suite &suite, Parameter const &p)
std::vector< NodeID > UNLNodeIDs
std::shared_ptr< STValidation > createSTVal(std::shared_ptr< Ledger const > const &ledger, NodeID const &v)
Create a validation.
hash_set< NodeID > UNLNodeIDSet
std::vector< PublicKey > UNLKeys
bool createLedgerHistory()
create ledger history and apply needed ttUNL_MODIFY tx at flag ledgers
RCLValidations & validations
hash_set< PublicKey > UNLKeySet
Set the sequence number on a JTx.