#include #include #include namespace xrpl { namespace test { class ByzantineFailureSim_test : public beast::unit_test::suite { void run() override { using namespace csf; using namespace std::chrono; // This test simulates a specific topology with nodes generating // different ledgers due to a simulated byzantine failure (injecting // an extra non-consensus transaction). Sim sim; ConsensusParms const parms{}; SimDuration const delay = round(0.2 * parms.ledgerGRANULARITY); PeerGroup a = sim.createGroup(1); PeerGroup b = sim.createGroup(1); PeerGroup c = sim.createGroup(1); PeerGroup d = sim.createGroup(1); PeerGroup e = sim.createGroup(1); PeerGroup f = sim.createGroup(1); PeerGroup g = sim.createGroup(1); a.trustAndConnect(a + b + c + g, delay); b.trustAndConnect(b + a + c + d + e, delay); c.trustAndConnect(c + a + b + d + e, delay); d.trustAndConnect(d + b + c + e + f, delay); e.trustAndConnect(e + b + c + d + f, delay); f.trustAndConnect(f + d + e + g, delay); g.trustAndConnect(g + a + f, delay); PeerGroup network = a + b + c + d + e + f + g; StreamCollector sc{std::cout}; sim.collectors.add(sc); for (TrustGraph::ForkInfo const& fi : sim.trustGraph.forkablePairs(0.8)) { std::cout << "Can fork " << PeerGroup{fi.unlA} << " " << " " << PeerGroup{fi.unlB} << " overlap " << fi.overlap << " required " << fi.required << "\n"; }; // set prior state sim.run(1); PeerGroup byzantineNodes = a + b + c + g; // All peers see some TX 0 for (Peer* peer : network) { peer->submit(Tx{0}); // Peers 0,1,2,6 will close the next ledger differently by injecting // a non-consensus approved transaction if (byzantineNodes.contains(peer)) { peer->txInjections.emplace( peer->lastClosedLedger.seq(), Tx{42}); } } sim.run(4); std::cout << "Branches: " << sim.branches() << "\n"; std::cout << "Fully synchronized: " << std::boolalpha << sim.synchronized() << "\n"; // Not tessting anything currently. pass(); } }; BEAST_DEFINE_TESTSUITE_MANUAL(ByzantineFailureSim, consensus, xrpl); } // namespace test } // namespace xrpl