Skip to content

Commit 7d7d5e8

Browse files
committed
Merge bitcoin/bitcoin#22879: addrman: Fix format string in deserialize error
fab0b55 addrman: Fix format string in deserialize error (MarcoFalke) facce4c test: Remove useless overwrite (MarcoFalke) Pull request description: The format string is evaluated differently on modern compilers (clang 10 and later, as well as gcc 10 and later). Work around the behaviour change in compilers by pinning the underlying type of the format arguments. Can be tested by observing a failing test when running against master compiled with clang 10 or gcc 10 (or later). ACKs for top commit: jonatack: ACK fab0b55 verified the test fails on master as expected only at line 61 (assertion fixed by the code change); the last two test additions pass as expected mzumsande: ACK fab0b55 Tree-SHA512: 07462901435107f3bc79098fd7d06446bfe8fe065fffdd35adfcba8f1dd3c499575006557afe7bc74b79d690c5ef7b58e3e031e908161be5529cf237e3b30609
2 parents ecf580e + fab0b55 commit 7d7d5e8

File tree

4 files changed

+91
-6
lines changed

4 files changed

+91
-6
lines changed

src/addrman.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -243,9 +243,9 @@ void CAddrMan::Unserialize(Stream& s_)
243243
const uint8_t lowest_compatible = compat - INCOMPATIBILITY_BASE;
244244
if (lowest_compatible > FILE_FORMAT) {
245245
throw std::ios_base::failure(strprintf(
246-
"Unsupported format of addrman database: %u. It is compatible with formats >=%u, "
247-
"but the maximum supported by this version of %s is %u.",
248-
format, lowest_compatible, PACKAGE_NAME, static_cast<uint8_t>(FILE_FORMAT)));
246+
"Unsupported format of addrman database: %u. It is compatible with formats >=%u, "
247+
"but the maximum supported by this version of %s is %u.",
248+
uint8_t{format}, uint8_t{lowest_compatible}, PACKAGE_NAME, uint8_t{FILE_FORMAT}));
249249
}
250250

251251
s >> nKey;

test/functional/feature_addrman.py

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
#!/usr/bin/env python3
2+
# Copyright (c) 2021 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+
"""Test addrman functionality"""
6+
7+
import os
8+
import struct
9+
10+
from test_framework.messages import ser_uint256, hash256
11+
from test_framework.p2p import MAGIC_BYTES
12+
from test_framework.test_framework import BitcoinTestFramework
13+
from test_framework.util import assert_equal
14+
15+
16+
def serialize_addrman(*, format=1, lowest_compatible=3):
17+
new = []
18+
tried = []
19+
INCOMPATIBILITY_BASE = 32
20+
r = MAGIC_BYTES["regtest"]
21+
r += struct.pack("B", format)
22+
r += struct.pack("B", INCOMPATIBILITY_BASE + lowest_compatible)
23+
r += ser_uint256(1)
24+
r += struct.pack("i", len(new))
25+
r += struct.pack("i", len(tried))
26+
ADDRMAN_NEW_BUCKET_COUNT = 1 << 10
27+
r += struct.pack("i", ADDRMAN_NEW_BUCKET_COUNT ^ (1 << 30))
28+
for _ in range(ADDRMAN_NEW_BUCKET_COUNT):
29+
r += struct.pack("i", 0)
30+
checksum = hash256(r)
31+
r += checksum
32+
return r
33+
34+
35+
def write_addrman(peers_dat, **kwargs):
36+
with open(peers_dat, "wb") as f:
37+
f.write(serialize_addrman(**kwargs))
38+
39+
40+
class AddrmanTest(BitcoinTestFramework):
41+
def set_test_params(self):
42+
self.num_nodes = 1
43+
44+
def run_test(self):
45+
peers_dat = os.path.join(self.nodes[0].datadir, self.chain, "peers.dat")
46+
47+
self.log.info("Check that mocked addrman is valid")
48+
self.stop_node(0)
49+
write_addrman(peers_dat)
50+
with self.nodes[0].assert_debug_log(["Loaded 0 addresses from peers.dat"]):
51+
self.start_node(0, extra_args=["-checkaddrman=1"])
52+
assert_equal(self.nodes[0].getnodeaddresses(), [])
53+
54+
self.log.info("Check that addrman from future cannot be read")
55+
self.stop_node(0)
56+
write_addrman(peers_dat, lowest_compatible=111)
57+
with self.nodes[0].assert_debug_log([
58+
f'ERROR: DeserializeDB: Deserialize or I/O error - Unsupported format of addrman database: 1. It is compatible with formats >=111, but the maximum supported by this version of {self.config["environment"]["PACKAGE_NAME"]} is 3.',
59+
"Recreating peers.dat",
60+
]):
61+
self.start_node(0)
62+
assert_equal(self.nodes[0].getnodeaddresses(), [])
63+
64+
self.log.info("Check that corrupt addrman cannot be read")
65+
self.stop_node(0)
66+
with open(peers_dat, "wb") as f:
67+
f.write(serialize_addrman()[:-1])
68+
with self.nodes[0].assert_debug_log([
69+
"ERROR: DeserializeDB: Deserialize or I/O error - CAutoFile::read: end of file",
70+
"Recreating peers.dat",
71+
]):
72+
self.start_node(0)
73+
assert_equal(self.nodes[0].getnodeaddresses(), [])
74+
75+
self.log.info("Check that missing addrman is recreated")
76+
self.stop_node(0)
77+
os.remove(peers_dat)
78+
with self.nodes[0].assert_debug_log([
79+
f"Missing or invalid file {peers_dat}",
80+
"Recreating peers.dat",
81+
]):
82+
self.start_node(0)
83+
assert_equal(self.nodes[0].getnodeaddresses(), [])
84+
85+
86+
if __name__ == "__main__":
87+
AddrmanTest().main()

test/functional/feature_anchors.py

-3
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,6 @@ def set_test_params(self):
2525
self.num_nodes = 1
2626
self.disable_autoconnect = False
2727

28-
def setup_network(self):
29-
self.setup_nodes()
30-
3128
def run_test(self):
3229
node_anchors_path = os.path.join(
3330
self.nodes[0].datadir, "regtest", "anchors.dat"

test/functional/test_runner.py

+1
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,7 @@
282282
'p2p_blockfilters.py',
283283
'p2p_message_capture.py',
284284
'feature_includeconf.py',
285+
'feature_addrman.py',
285286
'feature_asmap.py',
286287
'mempool_unbroadcast.py',
287288
'mempool_compatibility.py',

0 commit comments

Comments
 (0)