20#include <test/unit_test/SuiteJournal.h>
21#include <xrpld/consensus/Consensus.h>
22#include <xrpld/consensus/ConsensusProposal.h>
23#include <xrpl/beast/clock/manual_clock.h>
24#include <xrpl/beast/unit_test.h>
42 using namespace std::chrono_literals;
49 true, 10, 10, 10, -10s, 10s, 1s, 1s, p,
journal_));
51 true, 10, 10, 10, 100h, 10s, 1s, 1s, p,
journal_));
53 true, 10, 10, 10, 10s, 100h, 1s, 1s, p,
journal_));
80 using namespace std::chrono_literals;
126 using namespace std::chrono_literals;
130 PeerGroup peers = s.createGroup(1);
131 Peer* peer = peers[0];
132 peer->targetLedgers = 1;
139 auto const& lcl = peer->lastClosedLedger;
140 BEAST_EXPECT(peer->prevLedgerID() == lcl.
id());
141 BEAST_EXPECT(lcl.seq() == Ledger::Seq{1});
142 BEAST_EXPECT(lcl.txs().size() == 1);
143 BEAST_EXPECT(lcl.txs().find(Tx{1}) != lcl.txs().end());
144 BEAST_EXPECT(peer->prevProposers == 0);
155 PeerGroup peers = sim.createGroup(5);
158 peers.trustAndConnect(
159 peers, round<milliseconds>(0.2 * parms.ledgerGRANULARITY));
162 for (
Peer* p : peers)
168 if (BEAST_EXPECT(sim.synchronized()))
170 for (
Peer const* peer : peers)
172 auto const& lcl = peer->lastClosedLedger;
173 BEAST_EXPECT(lcl.id() == peer->prevLedgerID());
174 BEAST_EXPECT(lcl.seq() == Ledger::Seq{1});
176 BEAST_EXPECT(peer->prevProposers == peers.size() - 1);
179 BEAST_EXPECT(lcl.txs().find(Tx{i}) != lcl.txs().end());
198 PeerGroup slow = sim.createGroup(1);
199 PeerGroup fast = sim.createGroup(4);
200 PeerGroup network = fast + slow;
203 network.trust(network);
207 fast, round<milliseconds>(0.2 * parms.ledgerGRANULARITY));
210 network, round<milliseconds>(1.1 * parms.ledgerGRANULARITY));
213 for (
Peer* peer : network)
220 if (BEAST_EXPECT(sim.synchronized()))
222 for (
Peer* peer : network)
224 auto const& lcl = peer->lastClosedLedger;
225 BEAST_EXPECT(lcl.id() == peer->prevLedgerID());
226 BEAST_EXPECT(lcl.seq() == Ledger::Seq{1});
228 BEAST_EXPECT(peer->prevProposers == network.size() - 1);
230 peer->prevRoundTime == network[0]->prevRoundTime);
232 BEAST_EXPECT(lcl.txs().find(Tx{0}) == lcl.txs().end());
234 BEAST_EXPECT(lcl.txs().find(Tx{i}) != lcl.txs().end());
238 peer->openTxs.find(Tx{0}) != peer->openTxs.end());
249 for (
auto isParticipant : {
true,
false})
254 PeerGroup slow = sim.createGroup(2);
255 PeerGroup fast = sim.createGroup(4);
256 PeerGroup network = fast + slow;
259 network.trust(network);
263 fast, round<milliseconds>(0.2 * parms.ledgerGRANULARITY));
267 round<milliseconds>(1.1 * parms.ledgerGRANULARITY));
269 for (
Peer* peer : slow)
270 peer->runAsValidator = isParticipant;
274 for (
Peer* peer : network)
279 if (BEAST_EXPECT(sim.synchronized()))
284 for (
Peer* peer : network)
287 auto const& lcl = peer->lastClosedLedger;
288 BEAST_EXPECT(lcl.seq() == Ledger::Seq{1});
289 BEAST_EXPECT(lcl.txs().find(Tx{0}) == lcl.txs().end());
290 BEAST_EXPECT(lcl.txs().find(Tx{1}) == lcl.txs().end());
294 lcl.txs().find(Tx{i}) != lcl.txs().end());
298 peer->openTxs.find(Tx{0}) != peer->openTxs.end());
300 peer->openTxs.find(Tx{1}) != peer->openTxs.end());
303 Peer const* slowPeer = slow[0];
306 slowPeer->prevProposers == network.size() - 1);
308 BEAST_EXPECT(slowPeer->prevProposers == fast.size());
310 for (
Peer* peer : fast)
331 peer->prevProposers == network.size() - 1);
333 peer->prevRoundTime > slowPeer->prevRoundTime);
338 peer->prevProposers == fast.size() - 1);
341 peer->prevRoundTime == slowPeer->prevRoundTime);
383 PeerGroup groupA = sim.createGroup(2);
384 PeerGroup groupB = sim.createGroup(2);
385 PeerGroup groupC = sim.createGroup(2);
386 PeerGroup network = groupA + groupB + groupC;
388 network.trust(network);
390 network, round<milliseconds>(0.2 * parms.ledgerGRANULARITY));
394 Peer* firstPeer = *groupA.begin();
395 while (firstPeer->lastClosedLedger.closeTimeResolution() >=
396 parms.proposeFRESHNESS)
400 for (
Peer* peer : groupA)
401 peer->clockSkew = parms.proposeFRESHNESS / 2;
402 for (
Peer* peer : groupB)
403 peer->clockSkew = parms.proposeFRESHNESS;
408 if (BEAST_EXPECT(sim.synchronized()))
410 for (
Peer* peer : network)
411 BEAST_EXPECT(!peer->lastClosedLedger.closeAgree());
427 for (
auto validationDelay : {0ms, parms.ledgerMIN_CLOSE})
452 PeerGroup minority = sim.createGroup(2);
453 PeerGroup majorityA = sim.createGroup(3);
454 PeerGroup majorityB = sim.createGroup(5);
456 PeerGroup majority = majorityA + majorityB;
457 PeerGroup network = minority + majority;
460 round<milliseconds>(0.2 * parms.ledgerGRANULARITY);
461 minority.trustAndConnect(minority + majorityA, delay);
462 majority.trustAndConnect(majority, delay);
464 CollectByNode<JumpCollector> jumps;
465 sim.collectors.add(jumps);
467 BEAST_EXPECT(sim.trustGraph.canFork(parms.minCONSENSUS_PCT / 100.));
474 for (
Peer* peer : network)
475 peer->delays.recvValidation = validationDelay;
476 for (
Peer* peer : (minority + majorityA))
477 peer->openTxs.insert(Tx{0});
478 for (
Peer* peer : majorityB)
479 peer->openTxs.insert(Tx{1});
505 if (BEAST_EXPECT(sim.branches() == 1))
507 for (
Peer const* peer : majority)
510 BEAST_EXPECT(jumps[peer->id].closeJumps.empty());
511 BEAST_EXPECT(jumps[peer->id].fullyValidatedJumps.empty());
513 for (
Peer const* peer : minority)
515 auto& peerJumps = jumps[peer->id];
518 if (BEAST_EXPECT(peerJumps.closeJumps.size() == 1))
520 JumpCollector::Jump
const& jump =
521 peerJumps.closeJumps.front();
523 BEAST_EXPECT(jump.from.seq() <= jump.to.seq());
524 BEAST_EXPECT(!jump.to.isAncestor(jump.from));
530 peerJumps.fullyValidatedJumps.size() == 1))
532 JumpCollector::Jump
const& jump =
533 peerJumps.fullyValidatedJumps.front();
535 BEAST_EXPECT(jump.from.seq() < jump.to.seq());
536 BEAST_EXPECT(jump.to.isAncestor(jump.from));
555 PeerGroup loner = sim.createGroup(1);
556 PeerGroup friends = sim.createGroup(3);
557 loner.trust(loner + friends);
559 PeerGroup others = sim.createGroup(6);
560 PeerGroup clique = friends + others;
561 clique.trust(clique);
563 PeerGroup network = loner + clique;
565 network, round<milliseconds>(0.2 * parms.ledgerGRANULARITY));
569 for (
Peer* peer : (loner + friends))
570 peer->openTxs.insert(Tx(0));
571 for (
Peer* peer : others)
572 peer->openTxs.insert(Tx(1));
575 for (
Peer* peer : network)
576 peer->delays.recvValidation = parms.ledgerGRANULARITY;
582 for (
Peer* p : network)
583 BEAST_EXPECT(p->prevLedgerID() == network[0]->prevLedgerID());
603 PeerGroup slow = sim.createGroup(2);
604 PeerGroup fast = sim.createGroup(4);
605 PeerGroup network = fast + slow;
607 for (
Peer* peer : network)
608 peer->consensusParms = parms;
611 network.trust(network);
639 network[0]->lastClosedLedger.closeTimeResolution();
651 if (BEAST_EXPECT(sim.synchronized()))
655 for (
Peer* peer : network)
657 BEAST_EXPECT(peer->lastClosedLedger.closeTime() > peer->now());
658 BEAST_EXPECT(peer->lastClosedLedger.closeAgree());
663 for (
Peer* peer : network)
687 BEAST_EXPECT(sim.synchronized());
698 for (
std::uint32_t overlap = 0; overlap <= numPeers; ++overlap)
706 PeerGroup aOnly = sim.createGroup(numA);
707 PeerGroup bOnly = sim.createGroup(numB);
708 PeerGroup commonOnly = sim.createGroup(overlap);
710 PeerGroup a = aOnly + commonOnly;
711 PeerGroup b = bOnly + commonOnly;
713 PeerGroup network = a + b;
716 round<milliseconds>(0.2 * parms.ledgerGRANULARITY);
717 a.trustAndConnect(a, delay);
718 b.trustAndConnect(b, delay);
722 for (
Peer* peer : network)
725 peer->openTxs.insert(Tx{
static_cast<std::uint32_t>(peer->id)});
726 for (
Peer* to : sim.trustGraph.trustedPeers(peer))
727 peer->openTxs.insert(
735 if (overlap > 0.4 * numPeers)
736 BEAST_EXPECT(sim.synchronized());
741 BEAST_EXPECT(sim.branches() <= 3);
757 PeerGroup validators = sim.createGroup(5);
758 PeerGroup center = sim.createGroup(1);
759 validators.trust(validators);
760 center.trust(validators);
762 SimDuration delay = round<milliseconds>(0.2 * parms.ledgerGRANULARITY);
763 validators.connect(center, delay);
765 center[0]->runAsValidator =
false;
771 for (
Peer* p : validators)
777 BEAST_EXPECT(sim.synchronized());
788 bool reconnected =
false;
795 : network(net), groupCfast(c), groupCsplit(split), delay(d)
812 if (who == groupCfast[0]->
id &&
828 network.
connect(groupCsplit, delay);
873 PeerGroup groupABD = sim.createGroup(2);
875 PeerGroup groupCfast = sim.createGroup(1);
877 PeerGroup groupCsplit = sim.createGroup(7);
879 PeerGroup groupNotFastC = groupABD + groupCsplit;
880 PeerGroup network = groupABD + groupCsplit + groupCfast;
882 SimDuration delay = round<milliseconds>(0.2 * parms.ledgerGRANULARITY);
883 SimDuration fDelay = round<milliseconds>(0.1 * parms.ledgerGRANULARITY);
885 network.trust(network);
888 network.connect(groupCfast, fDelay);
890 groupNotFastC.connect(groupNotFastC, delay);
892 Disruptor dc(network, groupCfast, groupCsplit, delay);
893 sim.collectors.add(dc);
897 BEAST_EXPECT(sim.synchronized());
901 for (
Peer* peer : groupABD)
903 peer->txInjections.emplace(peer->lastClosedLedger.seq(), Tx{42});
911 BEAST_EXPECT(!sim.synchronized());
912 BEAST_EXPECT(sim.branches() == 1);
915 for (
Peer* p : network)
920 BEAST_EXPECT(!sim.synchronized());
921 BEAST_EXPECT(sim.branches() == 1);
926 if (BEAST_EXPECT(sim.branches() == 1))
928 BEAST_EXPECT(sim.synchronized());
932 BEAST_EXPECT(sim.branches(groupNotFastC) == 1);
933 BEAST_EXPECT(sim.synchronized(groupNotFastC) == 1);
993 SimDuration delay = round<milliseconds>(0.2 * parms.ledgerGRANULARITY);
995 PeerGroup behind = sim.createGroup(3);
996 PeerGroup ahead = sim.createGroup(2);
997 PeerGroup network = ahead + behind;
1000 for (
Peer* p : network)
1001 trustedKeys.
insert(p->key);
1002 for (
Peer* p : network)
1003 p->trustedKeys = trustedKeys;
1005 network.trustAndConnect(network, delay);
1012 for (
Peer* p : behind)
1013 p->delays.ledgerAccept = 20s;
1018 sim.collectors.add(undoDelay);
1022 for (
Peer* p : network)
1027 sim.collectors.add(sc);
1035 auto peerSelector = makeSelector(
1040 auto txSubmitter = makeSubmitter(
1041 ConstantDistribution{
rate.inv()},
1042 sim.scheduler.now(),
1043 sim.scheduler.now() + simDuration,
1049 sim.run(simDuration);
1052 BEAST_EXPECT(sim.synchronized());
1058 testShouldCloseLedger();
1059 testCheckConsensus();
1064 testCloseTimeDisagree();
1066 testConsensusCloseTimeRounding();
1069 testPreferredByBranch();
1070 testPauseForLaggards();
Generic implementation of consensus algorithm.
Represents a peer connection in the overlay.
virtual id_t id() const =0
void testCloseTimeDisagree()
void testPauseForLaggards()
void run() override
Runs the suite.
void testConsensusCloseTimeRounding()
void testPreferredByBranch()
void testCheckConsensus()
void testShouldCloseLedger()
A group of simulation Peers.
void disconnect(PeerGroup const &o)
Destroy network connection.
void connect(PeerGroup const &o, SimDuration delay)
Establish network connection.
typename SimClock::duration SimDuration
typename SimClock::time_point SimTime
Json::Value rate(Account const &account, double multiplier)
Set a transfer rate.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
ConsensusState checkConsensus(std::size_t prevProposers, std::size_t currentProposers, std::size_t currentAgree, std::size_t currentFinished, std::chrono::milliseconds previousAgreeTime, std::chrono::milliseconds currentAgreeTime, ConsensusParms const &parms, bool proposing, beast::Journal j, std::unique_ptr< std::stringstream > const &clog)
Determine whether the network reached consensus and whether we joined.
@ MovedOn
The network has consensus without us.
@ Yes
We have consensus along with the network.
@ No
We do not have consensus.
bool shouldCloseLedger(bool anyTransactions, std::size_t prevProposers, std::size_t proposersClosed, std::size_t proposersValidated, std::chrono::milliseconds prevRoundTime, std::chrono::milliseconds timeSincePrevClose, std::chrono::milliseconds openTime, std::chrono::milliseconds idleInterval, ConsensusParms const &parms, beast::Journal j, std::unique_ptr< std::stringstream > const &clog)
Determines whether the current ledger should close at this time.
auto constexpr increaseLedgerTimeResolutionEvery
How often we increase the close time resolution (in numbers of ledgers)
Consensus algorithm parameters.
std::chrono::milliseconds ledgerGRANULARITY
How often we check state or change positions.
Represents a transfer rate.
csf::PeerGroup & groupCsplit
csf::PeerGroup & groupCfast
void on(csf::PeerID, csf::SimTime, E const &)
Disruptor(csf::PeerGroup &net, csf::PeerGroup &c, csf::PeerGroup &split, csf::SimDuration d)
void on(csf::PeerID who, csf::SimTime, csf::AcceptLedger const &e)
void on(csf::PeerID who, csf::SimTime, csf::FullyValidateLedger const &e)
void on(csf::PeerID, csf::SimTime, E const &)
void on(csf::PeerID who, csf::SimTime, csf::AcceptLedger const &e)
UndoDelay(csf::PeerGroup &a)
Peer accepted consensus results.
Peer fully validated a new ledger.
Ledger ledger
The new fully validated ledger.
A single peer in the simulation.