/ src / test / util / net.cpp
net.cpp
  1  // Copyright (c) 2020-2022 The Bitcoin Core developers
  2  // Distributed under the MIT software license, see the accompanying
  3  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  4  
  5  #include <test/util/net.h>
  6  
  7  #include <net.h>
  8  #include <net_processing.h>
  9  #include <netaddress.h>
 10  #include <netmessagemaker.h>
 11  #include <node/connection_types.h>
 12  #include <node/eviction.h>
 13  #include <protocol.h>
 14  #include <random.h>
 15  #include <serialize.h>
 16  #include <span.h>
 17  
 18  #include <vector>
 19  
 20  void ConnmanTestMsg::Handshake(CNode& node,
 21                                 bool successfully_connected,
 22                                 ServiceFlags remote_services,
 23                                 ServiceFlags local_services,
 24                                 int32_t version,
 25                                 bool relay_txs)
 26  {
 27      auto& peerman{static_cast<PeerManager&>(*m_msgproc)};
 28      auto& connman{*this};
 29  
 30      peerman.InitializeNode(node, local_services);
 31      FlushSendBuffer(node); // Drop the version message added by InitializeNode.
 32  
 33      CSerializedNetMsg msg_version{
 34          NetMsg::Make(NetMsgType::VERSION,
 35                  version,                                        //
 36                  Using<CustomUintFormatter<8>>(remote_services), //
 37                  int64_t{},                                      // dummy time
 38                  int64_t{},                                      // ignored service bits
 39                  CNetAddr::V1(CService{}),                       // dummy
 40                  int64_t{},                                      // ignored service bits
 41                  CNetAddr::V1(CService{}),                       // ignored
 42                  uint64_t{1},                                    // dummy nonce
 43                  std::string{},                                  // dummy subver
 44                  int32_t{},                                      // dummy starting_height
 45                  relay_txs),
 46      };
 47  
 48      (void)connman.ReceiveMsgFrom(node, std::move(msg_version));
 49      node.fPauseSend = false;
 50      connman.ProcessMessagesOnce(node);
 51      peerman.SendMessages(&node);
 52      FlushSendBuffer(node); // Drop the verack message added by SendMessages.
 53      if (node.fDisconnect) return;
 54      assert(node.nVersion == version);
 55      assert(node.GetCommonVersion() == std::min(version, PROTOCOL_VERSION));
 56      CNodeStateStats statestats;
 57      assert(peerman.GetNodeStateStats(node.GetId(), statestats));
 58      assert(statestats.m_relay_txs == (relay_txs && !node.IsBlockOnlyConn()));
 59      assert(statestats.their_services == remote_services);
 60      if (successfully_connected) {
 61          CSerializedNetMsg msg_verack{NetMsg::Make(NetMsgType::VERACK)};
 62          (void)connman.ReceiveMsgFrom(node, std::move(msg_verack));
 63          node.fPauseSend = false;
 64          connman.ProcessMessagesOnce(node);
 65          peerman.SendMessages(&node);
 66          assert(node.fSuccessfullyConnected == true);
 67      }
 68  }
 69  
 70  void ConnmanTestMsg::NodeReceiveMsgBytes(CNode& node, Span<const uint8_t> msg_bytes, bool& complete) const
 71  {
 72      assert(node.ReceiveMsgBytes(msg_bytes, complete));
 73      if (complete) {
 74          node.MarkReceivedMsgsForProcessing();
 75      }
 76  }
 77  
 78  void ConnmanTestMsg::FlushSendBuffer(CNode& node) const
 79  {
 80      LOCK(node.cs_vSend);
 81      node.vSendMsg.clear();
 82      node.m_send_memusage = 0;
 83      while (true) {
 84          const auto& [to_send, _more, _msg_type] = node.m_transport->GetBytesToSend(false);
 85          if (to_send.empty()) break;
 86          node.m_transport->MarkBytesSent(to_send.size());
 87      }
 88  }
 89  
 90  bool ConnmanTestMsg::ReceiveMsgFrom(CNode& node, CSerializedNetMsg&& ser_msg) const
 91  {
 92      bool queued = node.m_transport->SetMessageToSend(ser_msg);
 93      assert(queued);
 94      bool complete{false};
 95      while (true) {
 96          const auto& [to_send, _more, _msg_type] = node.m_transport->GetBytesToSend(false);
 97          if (to_send.empty()) break;
 98          NodeReceiveMsgBytes(node, to_send, complete);
 99          node.m_transport->MarkBytesSent(to_send.size());
100      }
101      return complete;
102  }
103  
104  CNode* ConnmanTestMsg::ConnectNodePublic(PeerManager& peerman, const char* pszDest, ConnectionType conn_type)
105  {
106      CNode* node = ConnectNode(CAddress{}, pszDest, /*fCountFailure=*/false, conn_type, /*use_v2transport=*/true);
107      if (!node) return nullptr;
108      node->SetCommonVersion(PROTOCOL_VERSION);
109      peerman.InitializeNode(*node, ServiceFlags(NODE_NETWORK | NODE_WITNESS));
110      node->fSuccessfullyConnected = true;
111      AddTestNode(*node);
112      return node;
113  }
114  
115  std::vector<NodeEvictionCandidate> GetRandomNodeEvictionCandidates(int n_candidates, FastRandomContext& random_context)
116  {
117      std::vector<NodeEvictionCandidate> candidates;
118      candidates.reserve(n_candidates);
119      for (int id = 0; id < n_candidates; ++id) {
120          candidates.push_back({
121              /*id=*/id,
122              /*m_connected=*/std::chrono::seconds{random_context.randrange(100)},
123              /*m_min_ping_time=*/std::chrono::microseconds{random_context.randrange(100)},
124              /*m_last_block_time=*/std::chrono::seconds{random_context.randrange(100)},
125              /*m_last_tx_time=*/std::chrono::seconds{random_context.randrange(100)},
126              /*fRelevantServices=*/random_context.randbool(),
127              /*m_relay_txs=*/random_context.randbool(),
128              /*fBloomFilter=*/random_context.randbool(),
129              /*nKeyedNetGroup=*/random_context.randrange(100),
130              /*prefer_evict=*/random_context.randbool(),
131              /*m_is_local=*/random_context.randbool(),
132              /*m_network=*/ALL_NETWORKS[random_context.randrange(ALL_NETWORKS.size())],
133              /*m_noban=*/false,
134              /*m_conn_type=*/ConnectionType::INBOUND,
135          });
136      }
137      return candidates;
138  }