Bitcoin Core 32.99.0
P2P Digital Currency
Loading...
Searching...
No Matches
p2p_headers_presync.cpp
Go to the documentation of this file.
1// Copyright (c) 2024-present 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 <arith_uint256.h>
6#include <blockencodings.h>
7#include <net.h>
8#include <net_processing.h>
9#include <netmessagemaker.h>
10#include <node/peerman_args.h>
12#include <test/fuzz/fuzz.h>
13#include <test/fuzz/util.h>
14#include <test/util/net.h>
15#include <test/util/script.h>
17#include <test/util/time.h>
18#include <uint256.h>
19#include <validation.h>
20
21namespace {
23
24class HeadersSyncSetup : public TestingSetup
25{
26 std::vector<CNode*> m_connections;
27
28public:
29 HeadersSyncSetup(const ChainType chain_type, TestOpts opts) : TestingSetup(chain_type, opts)
30 {
33 peerman_opts.max_headers_result = FUZZ_MAX_HEADERS_RESULTS;
34 // The peerman's rng is a global that is reused, so it will be reused
35 // and may cause non-determinism between runs. This may even influence
36 // the global RNG, because seeding may be done from the global one. For
37 // now, avoid it influencing the global RNG, and initialize it with a
38 // constant instead.
39 peerman_opts.deterministic_rng = true;
40 // No txs are relayed. Disable irrelevant and possibly
41 // non-deterministic code paths.
42 peerman_opts.ignore_incoming_txs = true;
46
47 CConnman::Options options;
48 options.m_msgproc = m_node.peerman.get();
49 m_node.connman->Init(options);
50 }
51
55};
56
57void HeadersSyncSetup::ResetAndInitialize()
58{
59 m_connections.clear();
60 auto& connman = static_cast<ConnmanTestMsg&>(*m_node.connman);
61 connman.StopNodes();
62
63 static NodeId id{0};
64 std::vector<ConnectionType> conn_types = {
68 };
69
70 for (auto conn_type : conn_types) {
71 CAddress addr{};
72 m_connections.push_back(new CNode(id++, nullptr, addr, 0, 0, addr, "", conn_type, false, 0));
73 CNode& p2p_node = *m_connections.back();
74
75 connman.Handshake(
76 /*node=*/p2p_node,
77 /*successfully_connected=*/true,
78 /*remote_services=*/ServiceFlags(NODE_NETWORK | NODE_WITNESS),
79 /*local_services=*/ServiceFlags(NODE_NETWORK | NODE_WITNESS),
80 /*version=*/PROTOCOL_VERSION,
81 /*relay_txs=*/true);
82
83 connman.AddTestNode(p2p_node);
84 }
85}
86
87void HeadersSyncSetup::SendMessage(FuzzedDataProvider& fuzzed_data_provider, CSerializedNetMsg&& msg)
88{
89 auto& connman = static_cast<ConnmanTestMsg&>(*m_node.connman);
90 CNode& connection = *PickValue(fuzzed_data_provider, m_connections);
91
92 connman.FlushSendBuffer(connection);
93 (void)connman.ReceiveMsgFrom(connection, std::move(msg));
94 connection.fPauseSend = false;
95 try {
96 connman.ProcessMessagesOnce(connection);
97 } catch (const std::ios_base::failure&) {
98 }
99 m_node.peerman->SendMessages(connection);
100}
101
103{
104 CBlockHeader header;
105 header.nNonce = 0;
106 // Either use the previous difficulty or let the fuzzer choose. The upper target in the
107 // range comes from the bits value of the genesis block, which is 0x1d00ffff. The lower
108 // target comes from the bits value of mainnet block 840000, which is 0x17034219.
109 // Calling lower_target.SetCompact(0x17034219) and upper_target.SetCompact(0x1d00ffff)
110 // should return the values below.
111 //
112 // RPC commands to verify:
113 // getblockheader 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f
114 // getblockheader 0000000000000000000320283a032748cef8227873ff4872689bf23f1cda83a5
116 header.nBits = prev_nbits;
117 } else {
118 arith_uint256 lower_target = UintToArith256(uint256{"0000000000000000000342190000000000000000000000000000000000000000"});
119 arith_uint256 upper_target = UintToArith256(uint256{"00000000ffff0000000000000000000000000000000000000000000000000000"});
121 header.nBits = target.GetCompact();
122 }
124 header.hashPrevBlock = prev_hash;
126 return header;
127}
128
130{
131 auto header = ConsumeHeader(fuzzed_data_provider, prev_hash, prev_nbits);
132 // In order to reach the headers acceptance logic, the block is
133 // constructed in a way that will pass the mutation checks.
134 CBlock block{header};
136 tx.vin.resize(1);
137 tx.vout.resize(1);
138 tx.vout[0].nValue = 0;
139 tx.vin[0].scriptSig.resize(2);
140 block.vtx.push_back(MakeTransactionRef(tx));
141 block.hashMerkleRoot = block.vtx[0]->GetHash().ToUint256();
142 return block;
143}
144
145// Global setup works for this test as state modification (specifically in the
146// block index) would indicate a bug.
147HeadersSyncSetup* g_testing_setup;
148
149void initialize()
150{
151 static auto setup{
153 {
154 .setup_validation_interface = false,
155 }),
156 };
157 g_testing_setup = setup.get();
158}
159} // namespace
160
162{
164 FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
165 // The steady clock is currently only used for logging, so a constant
166 // time-point seems acceptable for now.
168
169 ChainstateManager& chainman = *g_testing_setup->m_node.chainman;
170 CBlockHeader base{chainman.GetParams().GenesisBlock()};
171 const FakeNodeClock clock{base.Time()};
172
174
175 g_testing_setup->ResetAndInitialize();
176
177 // The chain is just a single block, so this is equal to 1
178 size_t original_index_size{WITH_LOCK(cs_main, return chainman.m_blockman.m_block_index.size())};
179 arith_uint256 total_work{WITH_LOCK(cs_main, return chainman.m_best_header->nChainWork)};
180
181 std::vector<CBlockHeader> all_headers;
182
184 auto finalized_block = [&]() {
185 CBlock block = ConsumeBlock(fuzzed_data_provider, base.GetHash(), base.nBits);
186 FinalizeHeader(block, chainman);
187 return block;
188 };
189
190 // Send low-work headers, compact blocks, and blocks
191 CallOneOf(
194 // Send FUZZ_MAX_HEADERS_RESULTS headers
195 std::vector<CBlock> headers;
197 for (CBlock& header : headers) {
198 header = ConsumeHeader(fuzzed_data_provider, base.GetHash(), base.nBits);
199 FinalizeHeader(header, chainman);
200 base = header;
201 }
202
203 all_headers.insert(all_headers.end(), headers.begin(), headers.end());
204
206 g_testing_setup->SendMessage(fuzzed_data_provider, std::move(headers_msg));
207 },
209 // Send a compact block
210 auto block = finalized_block();
212
213 all_headers.push_back(block);
214
216 g_testing_setup->SendMessage(fuzzed_data_provider, std::move(headers_msg));
217 },
219 // Send a block
220 auto block = finalized_block();
221
222 all_headers.push_back(block);
223
225 g_testing_setup->SendMessage(fuzzed_data_provider, std::move(headers_msg));
226 });
227 }
228
229 // This is a conservative overestimate, as base is only moved forward when sending headers. In theory,
230 // the longest chain generated by this test is 1600 (FUZZ_MAX_HEADERS_RESULTS * 100) headers. In that case,
231 // this variable will accurately reflect the chain's total work.
233
234 // This test should never create a chain with more work than MinimumChainWork.
235 assert(total_work < chainman.MinimumChainWork());
236
237 // The headers/blocks sent in this test should never be stored, as the chains don't have the work required
238 // to meet the anti-DoS work threshold. So, if at any point the block index grew in size, then there's a bug
239 // in the headers pre-sync logic.
240 assert(WITH_LOCK(cs_main, return chainman.m_blockman.m_block_index.size()) == original_index_size);
241}
arith_uint256 UintToArith256(const uint256 &a)
node::NodeContext m_node
ChainType
Definition chaintype.h:12
A CService with information about it as peer.
Definition protocol.h:387
Nodes collect new transactions into a block, hash them into a hash tree, and scan through nonce value...
Definition block.h:27
uint32_t nNonce
Definition block.h:35
uint32_t nBits
Definition block.h:34
uint32_t nTime
Definition block.h:33
int32_t nVersion
Definition block.h:30
uint256 hashPrevBlock
Definition block.h:31
Definition block.h:74
const CBlock & GenesisBlock() const
Definition chainparams.h:94
void StopNodes() EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex
Definition net.cpp:3780
Information about a peer.
Definition net.h:686
std::atomic_bool fPauseSend
Definition net.h:754
Interface for managing multiple Chainstate objects, where each chainstate is associated with chainsta...
Definition validation.h:950
const CChainParams & GetParams() const
const arith_uint256 & MinimumChainWork() const
node::BlockManager m_blockman
A single BlockManager instance is shared across each constructed chainstate to avoid duplicating bloc...
Helper to initialize the global NodeClock, let a duration elapse, and reset it after use in a test.
Definition time.h:54
Helper to initialize the global MockableSteadyClock, let a duration elapse, and reset it after use in...
Definition time.h:29
Interface for message handling.
Definition net.h:1046
static Mutex g_msgproc_mutex
Mutex for anything that is only accessed via the msg processing thread.
Definition net.h:1049
static std::unique_ptr< PeerManager > make(CConnman &connman, AddrMan &addrman, BanMan *banman, ChainstateManager &chainman, CTxMemPool &pool, node::Warnings &warnings, Options opts)
256-bit unsigned big integer.
256-bit opaque blob.
Definition uint256.h:196
@ BLOCK_RELAY
We use block-relay-only connections to help prevent against partition attacks.
@ OUTBOUND_FULL_RELAY
These are the default connections that we use to connect with the network.
@ INBOUND
Inbound connections are those initiated by a peer.
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate.
Definition cs_main.cpp:8
static void initialize()
Definition fuzz.cpp:93
#define FUZZ_TARGET(...)
Definition fuzz.h:35
#define LIMITED_WHILE(condition, limit)
Can be used to limit a theoretically unbounded loop.
Definition fuzz.h:22
HTTPHeaders headers
CSerializedNetMsg Make(std::string msg_type, Args &&... args)
constexpr const char * HEADERS
The headers message sends one or more block headers to a node which previously requested certain head...
Definition protocol.h:123
constexpr const char * CMPCTBLOCK
Contains a CBlockHeaderAndShortTxIDs object - providing a header and list of "short txids".
Definition protocol.h:206
constexpr const char * BLOCK
The block message transmits a single serialized block.
Definition protocol.h:127
Definition basic.cpp:11
util::Result< void > ApplyArgsManOptions(const ArgsManager &args, BlockManager::Options &opts)
int64_t NodeId
Definition net.h:108
constexpr TransactionSerParams TX_WITH_WITNESS
static CTransactionRef MakeTransactionRef(Tx &&txIn)
ServiceFlags
nServices flags
Definition protocol.h:321
@ NODE_WITNESS
Definition protocol.h:332
@ NODE_NETWORK
Definition protocol.h:327
constexpr int PROTOCOL_VERSION
network protocol versioning
NetEventsInterface * m_msgproc
Definition net.h:1099
A mutable version of CTransaction.
std::vector< CTxOut > vout
std::vector< CTxIn > vin
Testing setup that configures a complete environment.
std::unique_ptr< CConnman > connman
Definition context.h:68
std::unique_ptr< CTxMemPool > mempool
Definition context.h:69
std::unique_ptr< BanMan > banman
Definition context.h:75
std::unique_ptr< AddrMan > addrman
Definition context.h:67
std::unique_ptr< ChainstateManager > chainman
Definition context.h:74
std::unique_ptr< node::Warnings > warnings
Manages all the node warnings.
Definition context.h:92
std::unique_ptr< PeerManager > peerman
Definition context.h:72
ArgsManager * args
Definition context.h:76
#define LOCK(cs)
Definition sync.h:268
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
Definition sync.h:299
SeedRandomStateForTest(SeedRand::ZEROS)
NodeSeconds ConsumeTime(FuzzedDataProvider &fuzzed_data_provider, const std::optional< int64_t > &min, const std::optional< int64_t > &max) noexcept
Definition util.cpp:34
auto & PickValue(FuzzedDataProvider &fuzzed_data_provider, Collection &col)
Definition util.h:57
size_t CallOneOf(FuzzedDataProvider &fuzzed_data_provider, Callables... callables)
Definition util.h:37
void FinalizeHeader(CBlockHeader &header, const ChainstateManager &chainman)
Definition util.h:367
arith_uint256 ConsumeArithUInt256InRange(FuzzedDataProvider &fuzzed_data_provider, const arith_uint256 &min, const arith_uint256 &max) noexcept
Definition util.h:209
@ ZEROS
Seed with a compile time constant of zeros.
static int setup(void)
Definition tests.c:8289
#define EXCLUSIVE_LOCKS_REQUIRED(...)
#define NO_THREAD_SAFETY_ANALYSIS
constexpr auto Ticks(Dur2 d)
Helper to count the seconds of a duration/time_point.
Definition time.h:82
arith_uint256 CalculateClaimedHeadersWork(std::span< const CBlockHeader > headers)
Return the sum of the claimed work on a given set of headers.
assert(!tx.IsCoinBase())
FuzzedDataProvider & fuzzed_data_provider
Definition fees.cpp:46
FakeNodeClock clock