Skip to content

Commit 4ff0c95

Browse files
Merge dashpay#5900: backport: merge bitcoin#21000, bitcoin#21586, bitcoin#21599, bitcoin#21604, bitcoin#23859, partial bitcoin#21798, bitcoin#26341 (auxiliary backports: part 13)
d033cd5 partial bitcoin#26341: add BIP158 false-positive element check in rpc_scanblocks.py (Kittywhiskers Van Gogh) eab94ac merge bitcoin#23859: Add missing suppressions for crypto_diff_fuzz_chacha20.cpp (Kittywhiskers Van Gogh) 0e8d4a1 partial bitcoin#21798: Create a block template in tx_pool targets (Kittywhiskers Van Gogh) ad71db2 merge bitcoin#21604: Document why no symbol names can be used for suppressions (Kittywhiskers Van Gogh) c116d84 merge bitcoin#21599: Replace file level integer overflow suppression with function level suppression (Kittywhiskers Van Gogh) 8a0dc8c merge bitcoin#21586: Add missing suppression for signed-integer-overflow:txmempool.cpp (Kittywhiskers Van Gogh) 53cf0d5 merge bitcoin#21000: Add UBSan suppressions needed for fuzz tests to not warn under -fsanitize=integer (Kittywhiskers Van Gogh) Pull request description: ## Additional Information * Dependency for dashpay#5902 * [bitcoin#21586](bitcoin#21586) was listed as DNM in the backports Google Sheet as listed below as it is `reverted as bitcoin#23059` ![Listing of bitcoin#21586 as DNM](https://github.com/dashpay/dash/assets/63189531/413c116a-b3cb-4b58-becd-0d731b0e4b0b) * [bitcoin#23059](bitcoin#23059) actually reverts [bitcoin#22925](bitcoin#22925) (which deals with `addrman.cpp`), not [bitcoin#21586](bitcoin#21586) (which deals with `txmempool.cpp`). ## Breaking Changes None, changes are limited to fuzzing, functional tests and undefined behavior exclusions ## Checklist: _Go over all the following points, and put an `x` in all the boxes that apply._ - [x] I have performed a self-review of my own code - [x] I have commented my code, particularly in hard-to-understand areas **(note: N/A)** - [x] I have added or updated relevant unit/integration/functional/e2e tests **(note: N/A)** - [x] I have made corresponding changes to the documentation **(note: N/A)** - [x] I have assigned this pull request to a milestone _(for repository code-owners and collaborators only)_ Top commit has no ACKs. Tree-SHA512: 7b6c3fcb462edc9bbcc12a0c4eab052d3ef3a6048281b162dd5650f311f6e1bae7a958adf1c03aa0dea09c56c1ddbc99d98a44023fd81f83b2325fd79dc32e80
2 parents e982db2 + d033cd5 commit 4ff0c95

File tree

8 files changed

+197
-67
lines changed

8 files changed

+197
-67
lines changed

src/test/fuzz/crypto_chacha20_poly1305_aead.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,18 +46,24 @@ FUZZ_TARGET(crypto_chacha20_poly1305_aead)
4646
assert(ok);
4747
},
4848
[&] {
49+
if (AdditionOverflow(seqnr_payload, static_cast<uint64_t>(1))) {
50+
return;
51+
}
4952
seqnr_payload += 1;
5053
aad_pos += CHACHA20_POLY1305_AEAD_AAD_LEN;
5154
if (aad_pos + CHACHA20_POLY1305_AEAD_AAD_LEN > CHACHA20_ROUND_OUTPUT) {
5255
aad_pos = 0;
56+
if (AdditionOverflow(seqnr_aad, static_cast<uint64_t>(1))) {
57+
return;
58+
}
5359
seqnr_aad += 1;
5460
}
5561
},
5662
[&] {
57-
seqnr_payload = fuzzed_data_provider.ConsumeIntegral<int>();
63+
seqnr_payload = fuzzed_data_provider.ConsumeIntegral<uint64_t>();
5864
},
5965
[&] {
60-
seqnr_aad = fuzzed_data_provider.ConsumeIntegral<int>();
66+
seqnr_aad = fuzzed_data_provider.ConsumeIntegral<uint64_t>();
6167
},
6268
[&] {
6369
is_encrypt = fuzzed_data_provider.ConsumeBool();

src/test/fuzz/pow.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,10 @@ FUZZ_TARGET_INIT(pow, initialize_pow)
4444
current_block.nHeight = current_height;
4545
}
4646
if (fuzzed_data_provider.ConsumeBool()) {
47-
current_block.nTime = fixed_time + current_height * consensus_params.nPowTargetSpacing;
47+
const uint32_t seconds = current_height * consensus_params.nPowTargetSpacing;
48+
if (!AdditionOverflow(fixed_time, seconds)) {
49+
current_block.nTime = fixed_time + seconds;
50+
}
4851
}
4952
if (fuzzed_data_provider.ConsumeBool()) {
5053
current_block.nBits = fixed_bits;

src/test/fuzz/tx_pool.cpp

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,13 +76,21 @@ void SetMempoolConstraints(ArgsManager& args, FuzzedDataProvider& fuzzed_data_pr
7676
ToString(fuzzed_data_provider.ConsumeIntegralInRange<unsigned>(0, 999)));
7777
}
7878

79+
void MockTime(FuzzedDataProvider& fuzzed_data_provider, const CChainState& chainstate)
80+
{
81+
const auto time = ConsumeTime(fuzzed_data_provider,
82+
chainstate.m_chain.Tip()->GetMedianTimePast() + 1,
83+
std::numeric_limits<decltype(chainstate.m_chain.Tip()->nTime)>::max());
84+
SetMockTime(time);
85+
}
86+
7987
FUZZ_TARGET_INIT(tx_pool_standard, initialize_tx_pool)
8088
{
8189
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
8290
const auto& node = g_setup->m_node;
8391
auto& chainstate = node.chainman->ActiveChainstate();
8492

85-
SetMockTime(ConsumeTime(fuzzed_data_provider));
93+
MockTime(fuzzed_data_provider, chainstate);
8694
SetMempoolConstraints(*node.args, fuzzed_data_provider);
8795

8896
// All RBF-spendable outpoints
@@ -161,7 +169,7 @@ FUZZ_TARGET_INIT(tx_pool_standard, initialize_tx_pool)
161169
}();
162170

163171
if (fuzzed_data_provider.ConsumeBool()) {
164-
SetMockTime(ConsumeTime(fuzzed_data_provider));
172+
MockTime(fuzzed_data_provider, chainstate);
165173
}
166174
if (fuzzed_data_provider.ConsumeBool()) {
167175
SetMempoolConstraints(*node.args, fuzzed_data_provider);
@@ -262,6 +270,10 @@ FUZZ_TARGET_INIT(tx_pool, initialize_tx_pool)
262270
{
263271
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
264272
const auto& node = g_setup->m_node;
273+
auto& chainstate = node.chainman->ActiveChainstate();
274+
275+
MockTime(fuzzed_data_provider, chainstate);
276+
SetMempoolConstraints(*node.args, fuzzed_data_provider);
265277

266278
std::vector<uint256> txids;
267279
for (const auto& outpoint : g_outpoints_coinbase_init_mature) {
@@ -273,12 +285,30 @@ FUZZ_TARGET_INIT(tx_pool, initialize_tx_pool)
273285
txids.push_back(ConsumeUInt256(fuzzed_data_provider));
274286
}
275287

276-
CTxMemPool tx_pool{/* estimator */ nullptr, /* check_ratio */ 1};
288+
CTxMemPool tx_pool_{/* estimator */ nullptr, /* check_ratio */ 1};
289+
MockedTxPool& tx_pool = *static_cast<MockedTxPool*>(&tx_pool_);
277290

278291
LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 300)
279292
{
280293
const auto mut_tx = ConsumeTransaction(fuzzed_data_provider, txids);
281294

295+
if (fuzzed_data_provider.ConsumeBool()) {
296+
MockTime(fuzzed_data_provider, chainstate);
297+
}
298+
if (fuzzed_data_provider.ConsumeBool()) {
299+
SetMempoolConstraints(*node.args, fuzzed_data_provider);
300+
}
301+
if (fuzzed_data_provider.ConsumeBool()) {
302+
tx_pool.RollingFeeUpdate();
303+
}
304+
if (fuzzed_data_provider.ConsumeBool()) {
305+
const auto& txid = fuzzed_data_provider.ConsumeBool() ?
306+
mut_tx.GetHash() :
307+
PickValue(fuzzed_data_provider, txids);
308+
const auto delta = fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(-50 * COIN, +50 * COIN);
309+
tx_pool.PrioritiseTransaction(txid, delta);
310+
}
311+
282312
const auto tx = MakeTransactionRef(mut_tx);
283313
const bool bypass_limits = fuzzed_data_provider.ConsumeBool();
284314
::fRequireStandard = fuzzed_data_provider.ConsumeBool();

src/test/fuzz/util.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include <test/util/script.h>
88
#include <util/overflow.h>
9+
#include <util/time.h>
910
#include <version.h>
1011

1112
FuzzedSock::FuzzedSock(FuzzedDataProvider& fuzzed_data_provider)
@@ -217,6 +218,14 @@ void FillNode(FuzzedDataProvider& fuzzed_data_provider, CNode& node, bool init_v
217218
}
218219
}
219220

221+
int64_t ConsumeTime(FuzzedDataProvider& fuzzed_data_provider, const std::optional<int64_t>& min, const std::optional<int64_t>& max) noexcept
222+
{
223+
// Avoid t=0 (1970-01-01T00:00:00Z) since SetMockTime(0) disables mocktime.
224+
static const int64_t time_min = ParseISO8601DateTime("1970-01-01T00:00:01Z");
225+
static const int64_t time_max = ParseISO8601DateTime("9999-12-31T23:59:59Z");
226+
return fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(min.value_or(time_min), max.value_or(time_max));
227+
}
228+
220229
CMutableTransaction ConsumeTransaction(FuzzedDataProvider& fuzzed_data_provider, const std::optional<std::vector<uint256>>& prevout_txids, const int max_num_in, const int max_num_out) noexcept
221230
{
222231
CMutableTransaction tx_mut;
@@ -248,7 +257,7 @@ CMutableTransaction ConsumeTransaction(FuzzedDataProvider& fuzzed_data_provider,
248257
return tx_mut;
249258
}
250259

251-
CScript ConsumeScript(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length) noexcept
260+
CScript ConsumeScript(FuzzedDataProvider& fuzzed_data_provider, const std::optional<size_t>& max_length) noexcept
252261
{
253262
const std::vector<uint8_t> b = ConsumeRandomLengthByteVector(fuzzed_data_provider, max_length);
254263
return {b.begin(), b.end()};

src/test/fuzz/util.h

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
#include <txmempool.h>
2929
#include <uint256.h>
3030
#include <util/overflow.h>
31-
#include <util/time.h>
3231
#include <util/vector.h>
3332
#include <version.h>
3433

@@ -61,18 +60,20 @@ auto& PickValue(FuzzedDataProvider& fuzzed_data_provider, Collection& col)
6160
return *it;
6261
}
6362

64-
[[ nodiscard ]] inline std::vector<uint8_t> ConsumeRandomLengthByteVector(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length = 4096) noexcept
63+
[[ nodiscard ]] inline std::vector<uint8_t> ConsumeRandomLengthByteVector(FuzzedDataProvider& fuzzed_data_provider, const std::optional<size_t>& max_length = std::nullopt) noexcept
6564
{
66-
const std::string s = fuzzed_data_provider.ConsumeRandomLengthString(max_length);
65+
const std::string s = max_length ?
66+
fuzzed_data_provider.ConsumeRandomLengthString(*max_length) :
67+
fuzzed_data_provider.ConsumeRandomLengthString();
6768
return {s.begin(), s.end()};
6869
}
6970

70-
[[ nodiscard ]] inline std::vector<bool> ConsumeRandomLengthBitVector(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length = 4096) noexcept
71+
[[ nodiscard ]] inline std::vector<bool> ConsumeRandomLengthBitVector(FuzzedDataProvider& fuzzed_data_provider, const std::optional<size_t>& max_length = std::nullopt) noexcept
7172
{
7273
return BytesToBits(ConsumeRandomLengthByteVector(fuzzed_data_provider, max_length));
7374
}
7475

75-
[[ nodiscard ]] inline CDataStream ConsumeDataStream(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length = 4096) noexcept
76+
[[ nodiscard ]] inline CDataStream ConsumeDataStream(FuzzedDataProvider& fuzzed_data_provider, const std::optional<size_t>& max_length = std::nullopt) noexcept
7677
{
7778
return CDataStream{ConsumeRandomLengthByteVector(fuzzed_data_provider, max_length), SER_NETWORK, INIT_PROTO_VERSION};
7879
}
@@ -99,7 +100,7 @@ template <typename T>
99100
}
100101

101102
template <typename T>
102-
[[ nodiscard ]] inline std::optional<T> ConsumeDeserializable(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length = 4096) noexcept
103+
[[ nodiscard ]] inline std::optional<T> ConsumeDeserializable(FuzzedDataProvider& fuzzed_data_provider, const std::optional<size_t>& max_length = std::nullopt) noexcept
103104
{
104105
const std::vector<uint8_t> buffer = ConsumeRandomLengthByteVector(fuzzed_data_provider, max_length);
105106
CDataStream ds{buffer, SER_NETWORK, INIT_PROTO_VERSION};
@@ -113,7 +114,7 @@ template <typename T>
113114
}
114115

115116
template <typename WeakEnumType, size_t size>
116-
[[nodiscard]] WeakEnumType ConsumeWeakEnum(FuzzedDataProvider& fuzzed_data_provider, const WeakEnumType (&all_types)[size]) noexcept
117+
[[ nodiscard ]] WeakEnumType ConsumeWeakEnum(FuzzedDataProvider& fuzzed_data_provider, const WeakEnumType (&all_types)[size]) noexcept
117118
{
118119
return fuzzed_data_provider.ConsumeBool() ?
119120
fuzzed_data_provider.PickValueInArray<WeakEnumType>(all_types) :
@@ -130,17 +131,11 @@ template <typename WeakEnumType, size_t size>
130131
return fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(0, MAX_MONEY);
131132
}
132133

133-
[[ nodiscard ]] inline int64_t ConsumeTime(FuzzedDataProvider& fuzzed_data_provider) noexcept
134-
{
135-
// Avoid t=0 (1970-01-01T00:00:00Z) since SetMockTime(0) is a no-op.
136-
static const int64_t time_min = ParseISO8601DateTime("1970-01-01T00:00:01Z");
137-
static const int64_t time_max = ParseISO8601DateTime("9999-12-31T23:59:59Z");
138-
return fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(time_min, time_max);
139-
}
134+
[[ nodiscard ]] int64_t ConsumeTime(FuzzedDataProvider& fuzzed_data_provider, const std::optional<int64_t>& min = std::nullopt, const std::optional<int64_t>& max = std::nullopt) noexcept;
140135

141136
[[ nodiscard ]] CMutableTransaction ConsumeTransaction(FuzzedDataProvider& fuzzed_data_provider, const std::optional<std::vector<uint256>>& prevout_txids, const int max_num_in = 10, const int max_num_out = 10) noexcept;
142137

143-
[[ nodiscard ]] CScript ConsumeScript(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length = 4096) noexcept;
138+
[[ nodiscard ]] CScript ConsumeScript(FuzzedDataProvider& fuzzed_data_provider, const std::optional<size_t>& max_length = std::nullopt) noexcept;
144139

145140
[[ nodiscard ]] uint32_t ConsumeSequence(FuzzedDataProvider& fuzzed_data_provider) noexcept;
146141

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#!/usr/bin/env python3
2+
# Copyright (c) 2022 The Bitcoin Core developers
3+
# Distributed under the MIT software license, see the accompanying
4+
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
5+
"""Helper routines relevant for compact block filters (BIP158).
6+
"""
7+
from .siphash import siphash
8+
9+
10+
def bip158_basic_element_hash(script_pub_key, N, block_hash):
11+
""" Calculates the ranged hash of a filter element as defined in BIP158:
12+
13+
'The first step in the filter construction is hashing the variable-sized
14+
raw items in the set to the range [0, F), where F = N * M.'
15+
16+
'The items are first passed through the pseudorandom function SipHash, which takes a
17+
128-bit key k and a variable-sized byte vector and produces a uniformly random 64-bit
18+
output. Implementations of this BIP MUST use the SipHash parameters c = 2 and d = 4.'
19+
20+
'The parameter k MUST be set to the first 16 bytes of the hash (in standard
21+
little-endian representation) of the block for which the filter is constructed. This
22+
ensures the key is deterministic while still varying from block to block.'
23+
"""
24+
M = 784931
25+
block_hash_bytes = bytes.fromhex(block_hash)[::-1]
26+
k0 = int.from_bytes(block_hash_bytes[0:8], 'little')
27+
k1 = int.from_bytes(block_hash_bytes[8:16], 'little')
28+
return (siphash(k0, k1, script_pub_key) * (N * M)) >> 64
29+
30+
31+
def bip158_relevant_scriptpubkeys(node, block_hash):
32+
""" Determines the basic filter relvant scriptPubKeys as defined in BIP158:
33+
34+
'A basic filter MUST contain exactly the following items for each transaction in a block:
35+
- The previous output script (the script being spent) for each input, except for
36+
the coinbase transaction.
37+
- The scriptPubKey of each output, aside from all OP_RETURN output scripts.'
38+
"""
39+
spks = set()
40+
for tx in node.getblock(blockhash=block_hash, verbosity=3)['tx']:
41+
# gather prevout scripts
42+
for i in tx['vin']:
43+
if 'prevout' in i:
44+
spks.add(bytes.fromhex(i['prevout']['scriptPubKey']['hex']))
45+
# gather output scripts
46+
for o in tx['vout']:
47+
if o['scriptPubKey']['type'] != 'nulldata':
48+
spks.add(bytes.fromhex(o['scriptPubKey']['hex']))
49+
return spks
Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
#!/usr/bin/env python3
2-
# Copyright (c) 2016 The Bitcoin Core developers
2+
# Copyright (c) 2016-2022 The Bitcoin Core developers
33
# Distributed under the MIT software license, see the accompanying
44
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
5-
"""Specialized SipHash-2-4 implementations.
5+
"""SipHash-2-4 implementation.
66
7-
This implements SipHash-2-4 for 256-bit integers.
7+
This implements SipHash-2-4. For convenience, an interface taking 256-bit
8+
integers is provided in addition to the one accepting generic data.
89
"""
910

1011
def rotl64(n, b):
1112
return n >> (64 - b) | (n & ((1 << (64 - b)) - 1)) << b
1213

14+
1315
def siphash_round(v0, v1, v2, v3):
1416
v0 = (v0 + v1) & ((1 << 64) - 1)
1517
v1 = rotl64(v1, 13)
@@ -27,37 +29,37 @@ def siphash_round(v0, v1, v2, v3):
2729
v2 = rotl64(v2, 32)
2830
return (v0, v1, v2, v3)
2931

30-
def siphash256(k0, k1, h):
31-
n0 = h & ((1 << 64) - 1)
32-
n1 = (h >> 64) & ((1 << 64) - 1)
33-
n2 = (h >> 128) & ((1 << 64) - 1)
34-
n3 = (h >> 192) & ((1 << 64) - 1)
32+
33+
def siphash(k0, k1, data):
34+
assert(type(data) == bytes)
3535
v0 = 0x736f6d6570736575 ^ k0
3636
v1 = 0x646f72616e646f6d ^ k1
3737
v2 = 0x6c7967656e657261 ^ k0
38-
v3 = 0x7465646279746573 ^ k1 ^ n0
39-
v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)
40-
v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)
41-
v0 ^= n0
42-
v3 ^= n1
43-
v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)
44-
v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)
45-
v0 ^= n1
46-
v3 ^= n2
38+
v3 = 0x7465646279746573 ^ k1
39+
c = 0
40+
t = 0
41+
for d in data:
42+
t |= d << (8 * (c % 8))
43+
c = (c + 1) & 0xff
44+
if (c & 7) == 0:
45+
v3 ^= t
46+
v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)
47+
v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)
48+
v0 ^= t
49+
t = 0
50+
t = t | (c << 56)
51+
v3 ^= t
4752
v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)
4853
v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)
49-
v0 ^= n2
50-
v3 ^= n3
51-
v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)
52-
v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)
53-
v0 ^= n3
54-
v3 ^= 0x2000000000000000
55-
v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)
56-
v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)
57-
v0 ^= 0x2000000000000000
58-
v2 ^= 0xFF
54+
v0 ^= t
55+
v2 ^= 0xff
5956
v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)
6057
v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)
6158
v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)
6259
v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)
6360
return v0 ^ v1 ^ v2 ^ v3
61+
62+
63+
def siphash256(k0, k1, num):
64+
assert(type(num) == int)
65+
return siphash(k0, k1, num.to_bytes(32, 'little'))

0 commit comments

Comments
 (0)