Bitcoin ABC  0.26.3
P2P Digital Currency
p2p_messaging_tests.cpp
Go to the documentation of this file.
1 // Copyright (c) 2019 The Bitcoin 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 <chainparams.h>
6 #include <common/system.h>
7 #include <net_processing.h>
8 #include <protocol.h>
9 #include <seeder/bitcoin.h>
10 #include <seeder/db.h>
11 #include <seeder/test/util.h>
12 #include <serialize.h>
13 #include <streams.h>
14 #include <version.h>
15 
16 #include <boost/test/unit_test.hpp>
17 
18 #include <cstdint>
19 #include <memory>
20 #include <ostream>
21 #include <string>
22 #include <vector>
23 
24 std::ostream &operator<<(std::ostream &os, const PeerMessagingState &state) {
25  os << to_integral(state);
26  return os;
27 }
28 
29 namespace {
30 class CSeederNodeTest : public CSeederNode {
31 public:
32  CSeederNodeTest(const CService &service, std::vector<CAddress> *vAddrIn)
33  : CSeederNode(service, vAddrIn) {}
34 
35  void TestProcessMessage(const std::string &strCommand, CDataStream &message,
36  PeerMessagingState expectedState) {
37  PeerMessagingState ret = ProcessMessage(strCommand, message);
38  BOOST_CHECK_EQUAL(ret, expectedState);
39  }
40 
41  CDataStream getSendBuffer() { return vSend; }
42 
43  void setStartingHeight(int starting_height) {
44  nStartingHeight = starting_height;
45  };
46 };
47 } // namespace
48 
49 static const uint16_t SERVICE_PORT = 18444;
50 
52  SeederTestingSetup(const std::string chain = CBaseChainParams::REGTEST) {
53  SelectParams(chain);
54  CNetAddr ip;
55  ip.SetInternal("bitcoin.test");
56  CService service = {ip, SERVICE_PORT};
57  vAddr.emplace_back(service, ServiceFlags());
58  testNode = std::make_unique<CSeederNodeTest>(service, &vAddr);
59  }
60 
61  std::vector<CAddress> vAddr;
62  std::unique_ptr<CSeederNodeTest> testNode;
63 };
64 
67 };
68 
69 BOOST_FIXTURE_TEST_SUITE(p2p_messaging_tests, SeederTestingSetup)
70 
71 static const int SEEDER_INIT_VERSION = 0;
72 
73 BOOST_AUTO_TEST_CASE(process_version_msg) {
75  uint64_t serviceflags = ServiceFlags(NODE_NETWORK);
76  CService addr_to = vAddr[0];
77  uint64_t addr_to_services = vAddr[0].nServices;
78  CService addr_from;
79  uint64_t nonce = 0;
80  std::string user_agent = "/Bitcoin ABC:0.0.0(seeder)/";
81 
82  // Don't include the time in CAddress serialization. See D14753.
83  versionMessage << INIT_PROTO_VERSION << serviceflags << GetTime()
84  << addr_to_services << addr_to << serviceflags << addr_from
85  << nonce << user_agent << GetRequireHeight();
86 
87  // Verify the version is set as the initial value
88  BOOST_CHECK_EQUAL(testNode->CSeederNode::GetClientVersion(),
90  testNode->TestProcessMessage(NetMsgType::VERSION, versionMessage,
92  // Verify the version has been updated
93  BOOST_CHECK_EQUAL(testNode->CSeederNode::GetClientVersion(),
94  versionMessage.GetVersion());
95 }
96 
97 BOOST_AUTO_TEST_CASE(process_verack_msg) {
98  CDataStream verackMessage(SER_NETWORK, 0);
99  verackMessage.SetVersion(INIT_PROTO_VERSION);
100  testNode->TestProcessMessage(NetMsgType::VERACK, verackMessage,
102 
103  // Seeder should respond with an ADDR message
104  const CMessageHeader::MessageMagic netMagic = Params().NetMagic();
105  CMessageHeader header(netMagic);
106  CDataStream sendBuffer = testNode->getSendBuffer();
107  sendBuffer >> header;
108  BOOST_CHECK(header.IsValidWithoutConfig(netMagic));
110 
111  // Next message should be GETHEADERS
112  sendBuffer >> header;
113  BOOST_CHECK(header.IsValidWithoutConfig(netMagic));
115 
116  CBlockLocator locator;
117  uint256 hashStop;
118  sendBuffer >> locator >> hashStop;
119  std::vector<BlockHash> expectedLocator = {
120  Params().Checkpoints().mapCheckpoints.rbegin()->second};
121  BOOST_CHECK(locator.vHave == expectedLocator);
122  BOOST_CHECK(hashStop == uint256());
123 }
124 
125 static CDataStream CreateAddrMessage(std::vector<CAddress> sendAddrs,
126  uint32_t nVersion = INIT_PROTO_VERSION) {
127  CDataStream payload(SER_NETWORK, 0);
128  payload.SetVersion(nVersion);
129  payload << sendAddrs;
130  return payload;
131 }
132 
133 BOOST_AUTO_TEST_CASE(process_addr_msg) {
134  // vAddrs starts with 1 entry.
135  std::vector<CAddress> sendAddrs(ADDR_SOFT_CAP - 1, vAddr[0]);
136 
137  // Happy path
138  // addrs are added normally to vAddr until ADDR_SOFT_CAP is reached.
139  // Add addrs up to the soft cap.
140  CDataStream addrMessage = CreateAddrMessage(sendAddrs);
141  BOOST_CHECK_EQUAL(1, vAddr.size());
142  testNode->TestProcessMessage(NetMsgType::ADDR, addrMessage,
144  BOOST_CHECK_EQUAL(ADDR_SOFT_CAP, vAddr.size());
145 
146  // ADDR_SOFT_CAP is exceeded
147  sendAddrs.resize(1);
148  addrMessage = CreateAddrMessage(sendAddrs);
149  testNode->TestProcessMessage(NetMsgType::ADDR, addrMessage,
151  BOOST_CHECK_EQUAL(ADDR_SOFT_CAP + 1, vAddr.size());
152 
153  // Test the seeder's behavior after ADDR_SOFT_CAP addrs
154  // Only one addr per ADDR message will be added, the rest are ignored
155  size_t expectedSize = vAddr.size() + 1;
156  for (size_t i = 1; i < 10; i++) {
157  sendAddrs.resize(i, sendAddrs[0]);
158  addrMessage = CreateAddrMessage(sendAddrs);
159  testNode->TestProcessMessage(NetMsgType::ADDR, addrMessage,
161  BOOST_CHECK_EQUAL(expectedSize, vAddr.size());
162  ++expectedSize;
163  }
164 }
165 
166 BOOST_AUTO_TEST_CASE(ban_too_many_headers) {
167  // Process the maximum number of headers
168  auto header = CBlockHeader{};
169  CDataStream maxHeaderMessages(SER_NETWORK, 0);
170  maxHeaderMessages.SetVersion(INIT_PROTO_VERSION);
171  WriteCompactSize(maxHeaderMessages, MAX_HEADERS_RESULTS);
172  for (size_t i = 0; i < MAX_HEADERS_RESULTS; i++) {
173  maxHeaderMessages << header;
174  WriteCompactSize(maxHeaderMessages, 0);
175  }
176  testNode->TestProcessMessage(NetMsgType::HEADERS, maxHeaderMessages,
178  BOOST_CHECK_EQUAL(testNode->GetBan(), 0);
179 
180  // Process one too many headers
181  CDataStream tooManyHeadersMessage(SER_NETWORK, 0);
182  tooManyHeadersMessage.SetVersion(INIT_PROTO_VERSION);
183  WriteCompactSize(tooManyHeadersMessage, MAX_HEADERS_RESULTS + 1);
184  // The message processing will abort when seeing the excessive number of
185  // headers from the compact size. No need to actually pack any header data.
186  testNode->TestProcessMessage(NetMsgType::HEADERS, tooManyHeadersMessage,
188  BOOST_CHECK(testNode->GetBan() > 0);
189 }
190 
191 BOOST_AUTO_TEST_CASE(empty_headers) {
192  // Check that an empty headers message does not cause issues
193  CDataStream zeroHeadersMessage(SER_NETWORK, 0);
194  zeroHeadersMessage.SetVersion(INIT_PROTO_VERSION);
195  WriteCompactSize(zeroHeadersMessage, 0);
196  testNode->TestProcessMessage(NetMsgType::HEADERS, zeroHeadersMessage,
198  BOOST_CHECK_EQUAL(testNode->GetBan(), 0);
199 }
200 
202  BlockHash recentCheckpoint =
203  ::Params().Checkpoints().mapCheckpoints.rbegin()->second;
204  int recentCheckpointHeight =
205  ::Params().Checkpoints().mapCheckpoints.rbegin()->first;
206 
207  // Process a HEADERS message with a first header that immediately follows
208  // our most recent checkpoint, check that it is accepted.
209  auto header = CBlockHeader{};
210  header.hashPrevBlock = recentCheckpoint;
211  testNode->setStartingHeight(recentCheckpointHeight + 1);
212  CDataStream headersOnCorrectChain(SER_NETWORK, 0);
213  headersOnCorrectChain.SetVersion(INIT_PROTO_VERSION);
214  WriteCompactSize(headersOnCorrectChain, 1);
215  headersOnCorrectChain << header;
216  testNode->TestProcessMessage(NetMsgType::HEADERS, headersOnCorrectChain,
218  BOOST_CHECK_EQUAL(testNode->GetBan(), 0);
219 
220  // We just ignore HEADERS messages sent by nodes with a chaintip before our
221  // most recent checkpoint.
222  header.hashPrevBlock = BlockHash{};
223  testNode->setStartingHeight(recentCheckpointHeight - 1);
224  CDataStream shortHeaderChain(SER_NETWORK, 0);
225  shortHeaderChain.SetVersion(INIT_PROTO_VERSION);
226  WriteCompactSize(shortHeaderChain, 1);
227  shortHeaderChain << header;
228  testNode->TestProcessMessage(NetMsgType::HEADERS, shortHeaderChain,
230  BOOST_CHECK_EQUAL(testNode->GetBan(), 0);
231 
232  // Process a HEADERS message with a first header that does not follow
233  // our most recent checkpoint, check that the node is banned.
234  header.hashPrevBlock = BlockHash{};
235  testNode->setStartingHeight(recentCheckpointHeight + 1);
236  CDataStream headersOnWrongChain(SER_NETWORK, 0);
237  headersOnWrongChain.SetVersion(INIT_PROTO_VERSION);
238  WriteCompactSize(headersOnWrongChain, 1);
239  headersOnWrongChain << header;
240  testNode->TestProcessMessage(NetMsgType::HEADERS, headersOnWrongChain,
242  BOOST_CHECK(testNode->GetBan() > 0);
243 }
244 
245 BOOST_AUTO_TEST_SUITE_END()
void SelectParams(const std::string &network)
Sets the params returned by Params() to those for the given BIP70 chain name.
Definition: chainparams.cpp:51
const CChainParams & Params()
Return the currently selected parameters.
Definition: chainparams.cpp:19
CBaseChainParams defines the base parameters (shared between bitcoin-cli and bitcoind) of a given ins...
static const std::string REGTEST
Nodes collect new transactions into a block, hash them into a hash tree, and scan through nonce value...
Definition: block.h:23
BlockHash hashPrevBlock
Definition: block.h:27
const CCheckpointData & Checkpoints() const
Definition: chainparams.h:134
const CMessageHeader::MessageMagic & NetMagic() const
Definition: chainparams.h:94
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:177
void SetVersion(int n)
Definition: streams.h:338
int GetVersion() const
Definition: streams.h:339
Message header.
Definition: protocol.h:34
bool IsValidWithoutConfig(const MessageMagic &magic) const
This is a transition method in order to stay compatible with older code that do not use the config.
Definition: protocol.cpp:177
std::string GetCommand() const
Definition: protocol.cpp:119
std::array< uint8_t, MESSAGE_START_SIZE > MessageMagic
Definition: protocol.h:46
Network address.
Definition: netaddress.h:121
bool SetInternal(const std::string &name)
Create an "internal" address that represents a name or FQDN.
Definition: netaddress.cpp:188
CDataStream vSend
Definition: bitcoin.h:42
PeerMessagingState ProcessMessage(std::string strCommand, CDataStream &recv)
Definition: bitcoin.cpp:41
A combination of a network address (CNetAddr) and a (TCP) port.
Definition: netaddress.h:545
256-bit opaque blob.
Definition: uint256.h:129
static node::NodeContext testNode
const char * HEADERS
The headers message sends one or more block headers to a node which previously requested certain head...
Definition: protocol.cpp:29
const char * GETADDR
The getaddr message requests an addr message from the receiving node, preferably one with lots of IP ...
Definition: protocol.cpp:31
const char * ADDR
The addr (IP address) message relays connection information for peers on the network.
Definition: protocol.cpp:20
const char * VERSION
The version message provides information about the transmitting node to the receiving node at the beg...
Definition: protocol.cpp:18
const char * GETHEADERS
The getheaders message requests a headers message that provides block headers starting from a particu...
Definition: protocol.cpp:27
const char * VERACK
The verack message acknowledges a previously-received version message, informing the connecting node ...
Definition: protocol.cpp:19
static const unsigned int MAX_HEADERS_RESULTS
Number of headers sent in one getheaders result.
#define BOOST_CHECK_EQUAL(v1, v2)
Definition: object.cpp:18
#define BOOST_CHECK(expr)
Definition: object.cpp:17
static const uint16_t SERVICE_PORT
static CDataStream CreateAddrMessage(std::vector< CAddress > sendAddrs, uint32_t nVersion=INIT_PROTO_VERSION)
BOOST_FIXTURE_TEST_CASE(good_checkpoint, MainNetSeederTestingSetup)
std::ostream & operator<<(std::ostream &os, const PeerMessagingState &state)
BOOST_AUTO_TEST_CASE(process_version_msg)
static const int SEEDER_INIT_VERSION
ServiceFlags
nServices flags.
Definition: protocol.h:335
@ NODE_NETWORK
Definition: protocol.h:342
PeerMessagingState
Definition: bitcoin.h:26
static const unsigned int ADDR_SOFT_CAP
Definition: bitcoin.h:24
static int GetRequireHeight()
Definition: db.h:28
constexpr std::underlying_type< E >::type to_integral(E e)
Definition: util.h:11
@ SER_NETWORK
Definition: serialize.h:152
void WriteCompactSize(CSizeComputer &os, uint64_t nSize)
Definition: serialize.h:1254
BOOST_FIXTURE_TEST_SUITE(stakingrewards_tests, StakingRewardsActivationTestingSetup) BOOST_AUTO_TEST_CASE(isstakingrewardsactivated)
A BlockHash is a unqiue identifier for a block.
Definition: blockhash.h:13
Describes a place in the block chain to another node such that if the other node doesn't have the sam...
Definition: block.h:105
std::vector< BlockHash > vHave
Definition: block.h:106
MapCheckpoints mapCheckpoints
Definition: chainparams.h:34
std::vector< CAddress > vAddr
std::unique_ptr< CSeederNodeTest > testNode
SeederTestingSetup(const std::string chain=CBaseChainParams::REGTEST)
int64_t GetTime()
Definition: time.cpp:109
static const int INIT_PROTO_VERSION
initial proto version, to be increased after version/verack negotiation
Definition: version.h:14