19 #include <ripple/basics/random.h>
20 #include <ripple/beast/unit_test.h>
21 #include <ripple/overlay/Message.h>
22 #include <ripple/overlay/Peer.h>
23 #include <ripple/overlay/Slot.h>
24 #include <ripple/overlay/impl/Handshake.h>
25 #include <ripple/protocol/SecretKey.h>
26 #include <ripple.pb.h>
27 #include <test/jtx/Env.h>
29 #include <boost/thread.hpp>
67 onMessage(protocol::TMSquelch
const&
squelch) = 0;
189 inline static const bool is_steady =
false;
200 now_ += randDuration(min, max);
235 updateSlotAndSquelch(
240 protocol::MessageType type = protocol::mtVALIDATION) = 0;
261 : validator_(validator), peer_(peer), latency_(latency), up_(
true)
263 auto sp = peer_.lock();
272 auto sp = peer_.lock();
274 auto peer = std::dynamic_pointer_cast<PeerPartial>(sp);
275 peer->onMessage(m, f);
290 auto p = peer_.lock();
297 auto p = peer_.lock();
318 protocol::TMValidation v;
319 v.set_validation(
"validation");
320 message_ = std::make_shared<Message>(v, protocol::mtVALIDATION, pkey_);
373 for (
auto id : peers)
375 assert(links_.find(
id) != links_.end());
376 f(*links_[
id], message_);
427 auto it = links_.find(
id);
428 assert(it != links_.end());
429 it->second->up(
true);
435 auto it = links_.find(
id);
436 assert(it != links_.end());
437 it->second->up(
false);
453 : overlay_(overlay), squelch_(journal)
481 overlay_.updateSlotAndSquelch({}, *
validator, id(), f);
494 squelch_.removeSquelch(key);
522 slots_.deleteIdlePeers();
528 auto res = slots_.inState(
validator, state);
529 return res ? *res : 0;
538 protocol::MessageType type = protocol::mtVALIDATION)
override
541 slots_.updateSlotAndSquelch(key,
validator,
id, type);
548 slots_.deletePeer(
id,
true);
555 slots_.deleteIdlePeers();
563 if (peersCache_.empty() || !useCache)
565 peer = std::make_shared<PeerSim>(*
this, logs_.journal(
"Squelch"));
570 auto it = peersCache_.begin();
573 peersCache_.erase(it);
582 auto it = peers_.find(
id);
583 assert(it != peers_.end());
593 while (!peers_.empty())
594 deletePeer(peers_.begin()->first);
595 while (!peersCache_.empty())
607 for (
auto& [
id, _] : peers_)
614 deletePeer(maxId,
false);
634 auto selected = slots_.getSelected(
validator);
635 return selected.find(peer) != selected.end();
641 auto selected = slots_.getSelected(
validator);
642 assert(selected.size());
643 return *selected.begin();
661 return peers_.size();
671 if (
auto it = peers_.find(
id); it != peers_.end())
672 squelch_(
validator, it->second, squelchDuration);
677 if (
auto it = peers_.find(
id); it != peers_.end())
702 auto peer = overlay_.addPeer();
703 for (
auto& v : validators_)
723 auto peer = overlay_.addPeer();
724 for (
auto& v : validators_)
732 auto id = overlay_.deleteLastPeer();
744 while (overlay_.getNumPeers() >
MAX_PEERS)
751 assert(v < validators_.size());
752 return validators_[v];
765 std::find_if(validators_.begin(), validators_.end(), [&](
auto& v) {
766 return v.id() == validatorId;
768 assert(it != validators_.end());
784 for (
auto& v : validators_)
787 squelch.clear_validatorpubkey();
801 auto size = max - min;
817 bool resetClock =
true)
825 overlay_.resetPeers();
828 for (
int m = 0; m < nMessages; ++m)
832 validators_[v].for_links(link);
841 for (
auto& v : validators_)
843 if (overlay_.isSelected(v,
id))
856 for (
auto& v : validators_)
858 if (!overlay_.isSelected(v, peer))
860 auto peers = overlay_.getPeers(v);
861 for (
auto& [_, v] : peers)
864 if (std::get<reduce_relay::PeerState>(v) ==
886 auto peers = network_.overlay().getPeers(network_.validator(
validator));
888 <<
"num peers " << (int)network_.overlay().getNumPeers()
890 for (
auto& [k, v] : peers)
891 std::cout << k <<
":" << (int)std::get<reduce_relay::PeerState>(v)
909 auto sp = peerPtr.
lock();
911 std::dynamic_pointer_cast<PeerSim>(sp)->send(
squelch);
926 bool isSelected_ =
false;
931 bool handled_ =
false;
941 {LinkDown, {}}, {PeerDisconnected, {}}};
949 bool squelched =
false;
958 auto p = sendSquelch(key, peerPtr,
duration);
965 auto selected = network_.overlay().getSelected(
validator);
966 str <<
" selected: ";
967 for (
auto s : selected)
971 << (double)reduce_relay::epoch<milliseconds>(now)
974 <<
" random, squelched, validator: " <<
validator.id()
977 network_.overlay().isCountingState(
validator);
979 countingState ==
false &&
985 if (events[EventType::LinkDown].state_ == State::Off)
988 events[event].cnt_++;
989 events[event].validator_ =
validator.id();
991 events[event].peer_ = link.
peerId();
992 events[event].state_ = State::On;
993 events[event].time_ = now;
994 if (event == EventType::LinkDown)
998 events[event].isSelected_ =
999 network_.overlay().isSelected(
1003 events[event].isSelected_ =
1004 network_.isSelected(link.
peerId());
1007 if (r == (
int)EventType::LinkDown ||
1008 r == (
int)EventType::PeerDisconnected)
1014 if (events[EventType::PeerDisconnected].state_ == State::On)
1016 auto&
event = events[EventType::PeerDisconnected];
1017 bool allCounting = network_.allCounting(event.peer_);
1018 network_.overlay().deletePeer(
1021 if (event.isSelected_)
1022 sendSquelch(v, peerPtr, {});
1023 event.handled_ =
true;
1031 (
event.isSelected_ ==
false && !
event.handled_) ||
1032 (event.isSelected_ ==
true &&
1033 (event.handled_ || allCounting));
1034 BEAST_EXPECT(handled);
1035 event.state_ = State::Off;
1036 event.isSelected_ =
false;
1037 event.handledCnt_ += handled;
1038 event.handled_ =
false;
1039 network_.onDisconnectPeer(event.peer_);
1042 auto&
event = events[EventType::LinkDown];
1054 bool mustHandle =
false;
1055 if (event.state_ == State::On)
1058 network_.overlay().isSelected(event.key_, event.peer_);
1059 auto peers = network_.overlay().getPeers(event.key_);
1060 auto d = reduce_relay::epoch<milliseconds>(now).count() -
1061 std::get<3>(peers[event.peer_]);
1062 mustHandle =
event.isSelected_ &&
1064 network_.overlay().inState(
1067 peers.find(event.peer_) != peers.end();
1069 network_.overlay().deleteIdlePeers(
1071 event.handled_ =
true;
1072 if (mustHandle && v == event.key_)
1074 event.state_ = State::WaitReset;
1075 sendSquelch(validator, ptr, {});
1079 (
event.handled_ &&
event.state_ == State::WaitReset) ||
1080 (!event.handled_ && !mustHandle);
1081 BEAST_EXPECT(handled);
1083 if (event.state_ == State::WaitReset ||
1084 (event.state_ == State::On &&
1088 event.state_ == State::WaitReset || !
event.handled_;
1089 BEAST_EXPECT(handled);
1090 event.state_ = State::Off;
1091 event.isSelected_ =
false;
1092 event.handledCnt_ += handled;
1093 event.handled_ =
false;
1094 network_.enableLink(event.validator_, event.peer_,
true);
1098 auto& down = events[EventType::LinkDown];
1099 auto& disconnected = events[EventType::PeerDisconnected];
1101 BEAST_EXPECT(down.handledCnt_ >= down.cnt_ - 1);
1103 BEAST_EXPECT(disconnected.cnt_ == disconnected.handledCnt_);
1105 std::cout <<
"link down count: " << down.cnt_ <<
"/"
1107 <<
" peer disconnect count: " << disconnected.cnt_ <<
"/"
1108 << disconnected.handledCnt_;
1114 auto countingState = network_.overlay().isCountingState(
validator);
1115 BEAST_EXPECT(countingState == isCountingState);
1116 return countingState == isCountingState;
1134 doTest(
"Initial Round", log, [
this](
bool log) {
1135 BEAST_EXPECT(propagateAndSquelch(log));
1145 doTest(
"Peer Unsquelched Too Soon", log, [
this](
bool log) {
1146 BEAST_EXPECT(propagateNoSquelch(log, 1,
false,
false,
false));
1157 doTest(
"Peer Unsquelched", log, [
this](
bool log) {
1158 BEAST_EXPECT(propagateNoSquelch(log, 2,
true,
true,
false));
1176 sendSquelch(key, peerPtr,
duration);
1190 auto selected = network_.overlay().getSelected(network_.validator(0));
1192 BEAST_EXPECT(n == 1);
1193 auto res = checkCounting(network_.validator(0),
false);
1195 return n == 1 && res;
1205 bool resetClock =
true)
1207 bool squelched =
false;
1216 BEAST_EXPECT(
false);
1223 auto res = checkCounting(network_.validator(0), countingState);
1224 return !squelched && res;
1233 doTest(
"New Peer", log, [
this](
bool log) {
1234 BEAST_EXPECT(propagateAndSquelch(log,
true,
false));
1236 BEAST_EXPECT(propagateNoSquelch(log, 1,
true,
false,
false));
1245 doTest(
"Selected Peer Disconnects", log, [
this](
bool log) {
1247 BEAST_EXPECT(propagateAndSquelch(log,
true,
false));
1248 auto id = network_.overlay().getSelectedPeer(network_.validator(0));
1250 network_.overlay().deletePeer(
1256 BEAST_EXPECT(checkCounting(network_.validator(0),
true));
1265 doTest(
"Selected Peer Stops Relaying", log, [
this](
bool log) {
1267 BEAST_EXPECT(propagateAndSquelch(log,
true,
false));
1270 network_.overlay().deleteIdlePeers(
1274 auto peers = network_.overlay().getPeers(network_.validator(0));
1277 BEAST_EXPECT(checkCounting(network_.validator(0),
true));
1286 doTest(
"Squelched Peer Disconnects", log, [
this](
bool log) {
1288 BEAST_EXPECT(propagateAndSquelch(log,
true,
false));
1289 auto peers = network_.overlay().getPeers(network_.validator(0));
1290 auto it =
std::find_if(peers.begin(), peers.end(), [&](
auto it) {
1291 return std::get<reduce_relay::PeerState>(it.second) ==
1292 reduce_relay::PeerState::Squelched;
1294 assert(it != peers.end());
1296 network_.overlay().deletePeer(
1300 BEAST_EXPECT(unsquelched == 0);
1301 BEAST_EXPECT(checkCounting(network_.validator(0),
false));
1308 doTest(
"Config Test", log, [&](
bool log) {
1323 toLoad = (R
"rippleConfig(
1335 toLoad = R
"rippleConfig(
1350 doTest(
"Duplicate Message", log, [&](
bool log) {
1354 for (
int i = 0; i < nMessages; i++)
1357 network_.overlay().updateSlotAndSquelch(
1359 network_.validator(0),
1363 auto peers = network_.overlay().getPeers(network_.validator(0));
1366 BEAST_EXPECT(std::get<1>(peers[0]) == (nMessages - 1));
1369 network_.overlay().updateSlotAndSquelch(
1371 network_.validator(0),
1375 peers = network_.overlay().getPeers(network_.validator(0));
1376 BEAST_EXPECT(std::get<1>(peers[0]) == (nMessages - 1));
1379 network_.overlay().updateSlotAndSquelch(
1381 network_.validator(0),
1384 peers = network_.overlay().getPeers(network_.validator(0));
1386 BEAST_EXPECT(std::get<1>(peers[0]) == nMessages);
1412 doTest(
"Random Squelch", l, [&](
bool l) {
1416 auto run = [&](
int npeers) {
1419 env_.app().logs(), handler);
1427 for (
int peer = 0; peer < npeers; peer++)
1437 protocol::MessageType::mtVALIDATION);
1444 using namespace reduce_relay;
1449 handler.
maxDuration_ >= MIN_UNSQUELCH_EXPIRE.count() &&
1450 handler.
maxDuration_ <= MAX_UNSQUELCH_EXPIRE_DEFAULT.count());
1453 handler.
maxDuration_ >= MIN_UNSQUELCH_EXPIRE.count() &&
1454 handler.
maxDuration_ <= MAX_UNSQUELCH_EXPIRE_DEFAULT.count());
1463 handler.
maxDuration_ >= MIN_UNSQUELCH_EXPIRE.count() &&
1464 handler.
maxDuration_ <= MAX_UNSQUELCH_EXPIRE_PEERS.count());
1465 using namespace beast::unit_test::detail;
1466 if (handler.
maxDuration_ <= MAX_UNSQUELCH_EXPIRE_DEFAULT.count())
1468 "warning: squelch duration is low",
1476 handler.
maxDuration_ >= MIN_UNSQUELCH_EXPIRE.count() &&
1477 handler.
maxDuration_ <= MAX_UNSQUELCH_EXPIRE_PEERS.count());
1478 if (handler.
maxDuration_ <= MAX_UNSQUELCH_EXPIRE_DEFAULT.count())
1480 "warning: squelch duration is low",
1491 doTest(
"Handshake", log, [&](
bool log) {
1492 auto setEnv = [&](
bool enable) {
1495 str <<
"[reduce_relay]\n"
1496 <<
"vp_enable=" << enable <<
"\n"
1497 <<
"vp_squelch=" << enable <<
"\n"
1498 <<
"[compression]\n"
1501 env_.app().config().VP_REDUCE_RELAY_ENABLE =
1503 env_.app().config().VP_REDUCE_RELAY_SQUELCH =
1507 auto handshake = [&](
int outboundEnable,
int inboundEnable) {
1509 boost::asio::ip::address::from_string(
"172.1.1.100");
1511 setEnv(outboundEnable);
1514 env_.app().config().COMPRESSION,
1516 env_.app().config().TX_REDUCE_RELAY_ENABLE,
1517 env_.app().config().VP_REDUCE_RELAY_ENABLE);
1519 http_request.version(request.version());
1520 http_request.base() = request.base();
1523 auto const peerEnabled = inboundEnable && outboundEnable;
1528 BEAST_EXPECT(!(peerEnabled ^ inboundEnabled));
1530 setEnv(inboundEnable);
1542 auto const outboundEnabled =
1544 BEAST_EXPECT(!(peerEnabled ^ outboundEnabled));
1566 testInitialRound(log);
1567 testPeerUnsquelchedTooSoon(log);
1568 testPeerUnsquelched(log);
1570 testSquelchedPeerDisconnects(log);
1571 testSelectedPeerDisconnects(log);
1572 testSelectedPeerStopsRelaying(log);
1573 testInternalHashRouter(log);
1574 testRandomSquelch(log);
1584 doTest(
"Random Test", log, [&](
bool log) {
random(log); });