Bitcoin ABC 0.34.2
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>
9#include <protocol.h>
10#include <seeder/bitcoin.h>
11#include <seeder/db.h>
12#include <seeder/test/util.h>
13#include <serialize.h>
14#include <streams.h>
15#include <util/chaintype.h>
16
17#include <boost/test/unit_test.hpp>
18
19#include <cstdint>
20#include <memory>
21#include <ostream>
22#include <string>
23#include <vector>
24
25std::ostream &operator<<(std::ostream &os, const PeerMessagingState &state) {
26 os << to_integral(state);
27 return os;
28}
29
30namespace {
31class CSeederNodeTest : public CSeederNode {
32public:
33 CSeederNodeTest(const CService &service, std::vector<CAddress> *vAddrIn)
34 : CSeederNode(service, vAddrIn) {}
35
36 void TestProcessMessage(const std::string &strCommand, DataStream &message,
37 PeerMessagingState expectedState) {
38 PeerMessagingState ret = ProcessMessage(strCommand, message);
39 BOOST_CHECK_EQUAL(ret, expectedState);
40 }
41
42 DataStream getSendBuffer() { return vSend; }
43
44 void setStartingHeight(int starting_height) {
45 nStartingHeight = starting_height;
46 };
47};
48} // namespace
49
50static const uint16_t SERVICE_PORT = 18444;
51
54 SelectParams(chain_type);
55 CNetAddr ip;
56 ip.SetInternal("bitcoin.test");
57 CService service = {ip, SERVICE_PORT};
58 vAddr.emplace_back(service, ServiceFlags());
59 testNode = std::make_unique<CSeederNodeTest>(service, &vAddr);
60 }
61
62 std::vector<CAddress> vAddr;
63 std::unique_ptr<CSeederNodeTest> testNode;
64};
65
68};
69
70BOOST_FIXTURE_TEST_SUITE(p2p_messaging_tests, SeederTestingSetup)
71
72static const int SEEDER_INIT_VERSION = 0;
73
74BOOST_AUTO_TEST_CASE(process_version_msg) {
75 DataStream versionMessage{};
76 uint64_t serviceflags = ServiceFlags(NODE_NETWORK);
77 CService addr_to = vAddr[0];
78 uint64_t addr_to_services = vAddr[0].nServices;
79 CService addr_from;
80 uint64_t nonce = 0;
81 std::string user_agent = "/Bitcoin ABC:0.0.0(seeder)/";
82
83 // Don't include the time in CAddress serialization. See D14753.
84 versionMessage << INIT_PROTO_VERSION << serviceflags << GetTime()
85 << addr_to_services << WithParams(CNetAddr::V1, addr_to)
86 << serviceflags << WithParams(CNetAddr::V1, addr_from)
87 << nonce << user_agent << GetRequireHeight();
88
89 // Verify the version is set as the initial value
90 BOOST_CHECK_EQUAL(testNode->CSeederNode::GetClientVersion(),
92 testNode->TestProcessMessage(NetMsgType::VERSION, versionMessage,
94 BOOST_CHECK_EQUAL(testNode->GetClientSubVersion(), user_agent);
95}
96
97BOOST_AUTO_TEST_CASE(process_version_msg_oversized_subver) {
98 DataStream versionMessage{};
99 uint64_t serviceflags = ServiceFlags(NODE_NETWORK);
100 CService addr_to = vAddr[0];
101 uint64_t addr_to_services = vAddr[0].nServices;
102 CService addr_from;
103 uint64_t nonce = 0;
104 // Complete VERSION with a subversion longer than MAX_SUBVERSION_LENGTH.
105 std::string oversizedSubVer(MAX_SUBVERSION_LENGTH + 1, 'a');
106
107 versionMessage << INIT_PROTO_VERSION << serviceflags << GetTime()
108 << addr_to_services << WithParams(CNetAddr::V1, addr_to)
109 << serviceflags << WithParams(CNetAddr::V1, addr_from)
110 << nonce << oversizedSubVer << GetRequireHeight();
111
112 // Deserialization failure is handled as a rejected peer message.
113 testNode->TestProcessMessage(NetMsgType::VERSION, versionMessage,
115 BOOST_CHECK(testNode->GetBan() > 0);
116 BOOST_CHECK(testNode->GetClientSubVersion().empty());
117}
118
120 DataStream verackMessage{};
121 testNode->TestProcessMessage(NetMsgType::VERACK, verackMessage,
123
124 // Seeder should respond with an ADDR message
125 CMessageHeader header;
126 DataStream sendBuffer = testNode->getSendBuffer();
127 sendBuffer >> header;
130
131 // Next message should be GETHEADERS
132 sendBuffer >> header;
135
136 CBlockLocator locator;
137 uint256 hashStop;
138 sendBuffer >> locator >> hashStop;
139 std::vector<BlockHash> expectedLocator = {
140 Params().Checkpoints().mapCheckpoints.rbegin()->second};
141 BOOST_CHECK(locator.vHave == expectedLocator);
142 BOOST_CHECK(hashStop == uint256());
143}
144
145static DataStream CreateAddrMessage(std::vector<CAddress> sendAddrs,
146 uint32_t nVersion = INIT_PROTO_VERSION) {
147 DataStream payload{};
148 payload << WithParams(CAddress::V1_NETWORK, sendAddrs);
149 return payload;
150}
151
153 // First, must send headers to satisfy the criteria that both ADDR/ADDRV2
154 // *and* HEADERS must arrive before TestNode can advance to the Finished
155 // state
156 BlockHash recentCheckpoint =
157 ::Params().Checkpoints().mapCheckpoints.rbegin()->second;
158 int recentCheckpointHeight =
159 ::Params().Checkpoints().mapCheckpoints.rbegin()->first;
160 auto header = CBlockHeader{};
161 header.hashPrevBlock = recentCheckpoint;
162 testNode->setStartingHeight(recentCheckpointHeight + 1);
163 DataStream headersMsg{};
164 WriteCompactSize(headersMsg, 1);
165 headersMsg << header;
166 // sanity check: node is expecting headers
167 BOOST_CHECK(!testNode->IsCheckpointVerified());
168 testNode->TestProcessMessage(NetMsgType::HEADERS, headersMsg,
170 BOOST_CHECK_EQUAL(testNode->GetBan(), 0);
171 // node got the checkpointed header; it can advance to Finished after
172 // addr message
173 BOOST_CHECK(testNode->IsCheckpointVerified());
174
175 // vAddrs starts with 1 entry.
176 std::vector<CAddress> sendAddrs(ADDR_SOFT_CAP - 1, vAddr[0]);
177
178 // Happy path
179 // addrs are added normally to vAddr until ADDR_SOFT_CAP is reached.
180 // Add addrs up to the soft cap.
181 DataStream addrMessage = CreateAddrMessage(sendAddrs);
182 BOOST_CHECK_EQUAL(1, vAddr.size());
183 testNode->TestProcessMessage(NetMsgType::ADDR, addrMessage,
185 BOOST_CHECK_EQUAL(ADDR_SOFT_CAP, vAddr.size());
186
187 // ADDR_SOFT_CAP is exceeded
188 sendAddrs.resize(1);
189 addrMessage = CreateAddrMessage(sendAddrs);
190 testNode->TestProcessMessage(NetMsgType::ADDR, addrMessage,
192 BOOST_CHECK_EQUAL(ADDR_SOFT_CAP + 1, vAddr.size());
193
194 // Test the seeder's behavior after ADDR_SOFT_CAP addrs
195 // Only one addr per ADDR message will be added, the rest are ignored
196 size_t expectedSize = vAddr.size() + 1;
197 for (size_t i = 1; i < 10; i++) {
198 sendAddrs.resize(i, sendAddrs[0]);
199 addrMessage = CreateAddrMessage(sendAddrs);
200 testNode->TestProcessMessage(NetMsgType::ADDR, addrMessage,
202 BOOST_CHECK_EQUAL(expectedSize, vAddr.size());
203 ++expectedSize;
204 }
205}
206
207BOOST_AUTO_TEST_CASE(ban_too_many_headers) {
208 // Process the maximum number of headers
209 auto header = CBlockHeader{};
210 DataStream maxHeaderMessages{};
211 WriteCompactSize(maxHeaderMessages, MAX_HEADERS_RESULTS);
212 for (size_t i = 0; i < MAX_HEADERS_RESULTS; i++) {
213 maxHeaderMessages << header;
214 WriteCompactSize(maxHeaderMessages, 0);
215 }
216 testNode->TestProcessMessage(NetMsgType::HEADERS, maxHeaderMessages,
218 BOOST_CHECK_EQUAL(testNode->GetBan(), 0);
219
220 // Process one too many headers
221 DataStream tooManyHeadersMessage{};
222 WriteCompactSize(tooManyHeadersMessage, MAX_HEADERS_RESULTS + 1);
223 // The message processing will abort when seeing the excessive number of
224 // headers from the compact size. No need to actually pack any header data.
225 testNode->TestProcessMessage(NetMsgType::HEADERS, tooManyHeadersMessage,
227 BOOST_CHECK(testNode->GetBan() > 0);
228}
229
230BOOST_AUTO_TEST_CASE(empty_headers) {
231 // Check that an empty headers message does not cause issues
232 DataStream zeroHeadersMessage{};
233 WriteCompactSize(zeroHeadersMessage, 0);
234 testNode->TestProcessMessage(NetMsgType::HEADERS, zeroHeadersMessage,
236 BOOST_CHECK_EQUAL(testNode->GetBan(), 0);
237}
238
240 BlockHash recentCheckpoint =
241 ::Params().Checkpoints().mapCheckpoints.rbegin()->second;
242 int recentCheckpointHeight =
243 ::Params().Checkpoints().mapCheckpoints.rbegin()->first;
244
245 // Process a HEADERS message with a first header that immediately follows
246 // our most recent checkpoint, check that it is accepted.
247 auto header = CBlockHeader{};
248 header.hashPrevBlock = recentCheckpoint;
249 testNode->setStartingHeight(recentCheckpointHeight + 1);
250 DataStream headersOnCorrectChain{};
251 // The following .reserve() call is a workaround for a spurious
252 // [-Werror=stringop-overflow=] warning in gcc <= 12.2.
253 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100366#c20
254 headersOnCorrectChain.reserve(4);
255 WriteCompactSize(headersOnCorrectChain, 1);
256 headersOnCorrectChain << header;
257 testNode->TestProcessMessage(NetMsgType::HEADERS, headersOnCorrectChain,
259 BOOST_CHECK_EQUAL(testNode->GetBan(), 0);
260 BOOST_CHECK(testNode->IsCheckpointVerified());
261}
262
264 BlockHash recentCheckpoint =
265 ::Params().Checkpoints().mapCheckpoints.rbegin()->second;
266 int recentCheckpointHeight =
267 ::Params().Checkpoints().mapCheckpoints.rbegin()->first;
268 auto header = CBlockHeader{};
269
270 // We just ignore HEADERS messages sent by nodes with a chaintip before our
271 // most recent checkpoint.
272 testNode->setStartingHeight(recentCheckpointHeight - 1);
273 DataStream shortHeaderChain{};
274 WriteCompactSize(shortHeaderChain, 1);
275 shortHeaderChain << header;
276 testNode->TestProcessMessage(NetMsgType::HEADERS, shortHeaderChain,
278 BOOST_CHECK_EQUAL(testNode->GetBan(), 0);
279 BOOST_CHECK(!testNode->IsCheckpointVerified());
280
281 // Process a HEADERS message with a first header that does not follow
282 // our most recent checkpoint, check that the node is banned.
283 BOOST_CHECK(header.hashPrevBlock != recentCheckpoint);
284 testNode->setStartingHeight(recentCheckpointHeight + 1);
285 DataStream headersOnWrongChain{};
286 WriteCompactSize(headersOnWrongChain, 1);
287 headersOnWrongChain << header;
288 testNode->TestProcessMessage(NetMsgType::HEADERS, headersOnWrongChain,
290 BOOST_CHECK(testNode->GetBan() > 0);
291 BOOST_CHECK(!testNode->IsCheckpointVerified());
292}
293
294BOOST_AUTO_TEST_SUITE_END()
void SelectParams(const ChainType chain)
Sets the params returned by Params() to those for the given BIP70 chain name.
Definition: chainparams.cpp:50
const CChainParams & Params()
Return the currently selected parameters.
Definition: chainparams.cpp:21
ChainType
Definition: chaintype.h:11
static constexpr SerParams V1_NETWORK
Definition: protocol.h:495
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:145
Message header.
Definition: protocol.h:34
bool IsMessageTypeValid() const
Definition: protocol.cpp:125
std::string GetMessageType() const
Definition: protocol.cpp:119
Network address.
Definition: netaddress.h:114
static constexpr SerParams V1
Definition: netaddress.h:255
bool SetInternal(const std::string &name)
Create an "internal" address that represents a name or FQDN.
Definition: netaddress.cpp:188
DataStream vSend
Definition: bitcoin.h:42
PeerMessagingState ProcessMessage(std::string strCommand, DataStream &recv)
Definition: bitcoin.cpp:41
A combination of a network address (CNetAddr) and a (TCP) port.
Definition: netaddress.h:573
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:118
void reserve(size_type n)
Definition: streams.h:156
256-bit opaque blob.
Definition: uint256.h:199
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_SUBVERSION_LENGTH
Maximum length of the user agent string in version message.
Definition: net.h:71
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
std::ostream & operator<<(std::ostream &os, const PeerMessagingState &state)
static DataStream CreateAddrMessage(std::vector< CAddress > sendAddrs, uint32_t nVersion=INIT_PROTO_VERSION)
BOOST_FIXTURE_TEST_CASE(process_verack_msg, MainNetSeederTestingSetup)
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
static const int INIT_PROTO_VERSION
initial proto version, to be increased after version/verack negotiation
PeerMessagingState
Definition: bitcoin.h:26
static const unsigned int ADDR_SOFT_CAP
Definition: bitcoin.h:24
static int GetRequireHeight()
Definition: db.h:27
constexpr std::underlying_type< E >::type to_integral(E e)
Definition: util.h:11
void WriteCompactSize(SizeComputer &os, uint64_t nSize)
Definition: serialize.h:1260
static auto WithParams(const Params &params, T &&t)
Return a wrapper around t that (de)serializes it with specified parameter params.
Definition: serialize.h:1331
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:108
std::vector< BlockHash > vHave
Definition: block.h:120
MapCheckpoints mapCheckpoints
Definition: chainparams.h:36
std::vector< CAddress > vAddr
std::unique_ptr< CSeederNodeTest > testNode
SeederTestingSetup(const ChainType chain_type=ChainType::REGTEST)
int64_t GetTime()
DEPRECATED Use either ClockType::now() or Now<TimePointType>() if a cast is needed.
Definition: time.cpp:80