Bitcoin Core 28.99.0
P2P Digital Currency
addrdb.cpp
Go to the documentation of this file.
1// Copyright (c) 2009-2010 Satoshi Nakamoto
2// Copyright (c) 2009-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
6#include <bitcoin-build-config.h> // IWYU pragma: keep
7
8#include <addrdb.h>
9
10#include <addrman.h>
11#include <chainparams.h>
12#include <clientversion.h>
13#include <common/args.h>
14#include <common/settings.h>
15#include <cstdint>
16#include <hash.h>
17#include <logging.h>
18#include <logging/timer.h>
19#include <netbase.h>
20#include <netgroup.h>
21#include <random.h>
22#include <streams.h>
23#include <tinyformat.h>
24#include <univalue.h>
25#include <util/fs.h>
26#include <util/fs_helpers.h>
27#include <util/translation.h>
28
29namespace {
30
31class DbNotFoundError : public std::exception
32{
33 using std::exception::exception;
34};
35
36template <typename Stream, typename Data>
37bool SerializeDB(Stream& stream, const Data& data)
38{
39 // Write and commit header, data
40 try {
41 HashedSourceWriter hashwriter{stream};
42 hashwriter << Params().MessageStart() << data;
43 stream << hashwriter.GetHash();
44 } catch (const std::exception& e) {
45 LogError("%s: Serialize or I/O error - %s\n", __func__, e.what());
46 return false;
47 }
48
49 return true;
50}
51
52template <typename Data>
53bool SerializeFileDB(const std::string& prefix, const fs::path& path, const Data& data)
54{
55 // Generate random temporary filename
56 const uint16_t randv{FastRandomContext().rand<uint16_t>()};
57 std::string tmpfn = strprintf("%s.%04x", prefix, randv);
58
59 // open temp output file
60 fs::path pathTmp = gArgs.GetDataDirNet() / fs::u8path(tmpfn);
61 FILE *file = fsbridge::fopen(pathTmp, "wb");
62 AutoFile fileout{file};
63 if (fileout.IsNull()) {
64 fileout.fclose();
65 remove(pathTmp);
66 LogError("%s: Failed to open file %s\n", __func__, fs::PathToString(pathTmp));
67 return false;
68 }
69
70 // Serialize
71 if (!SerializeDB(fileout, data)) {
72 fileout.fclose();
73 remove(pathTmp);
74 return false;
75 }
76 if (!fileout.Commit()) {
77 fileout.fclose();
78 remove(pathTmp);
79 LogError("%s: Failed to flush file %s\n", __func__, fs::PathToString(pathTmp));
80 return false;
81 }
82 fileout.fclose();
83
84 // replace existing file, if any, with new file
85 if (!RenameOver(pathTmp, path)) {
86 remove(pathTmp);
87 LogError("%s: Rename-into-place failed\n", __func__);
88 return false;
89 }
90
91 return true;
92}
93
94template <typename Stream, typename Data>
95void DeserializeDB(Stream& stream, Data&& data, bool fCheckSum = true)
96{
97 HashVerifier verifier{stream};
98 // de-serialize file header (network specific magic number) and ..
99 MessageStartChars pchMsgTmp;
100 verifier >> pchMsgTmp;
101 // ... verify the network matches ours
102 if (pchMsgTmp != Params().MessageStart()) {
103 throw std::runtime_error{"Invalid network magic number"};
104 }
105
106 // de-serialize data
107 verifier >> data;
108
109 // verify checksum
110 if (fCheckSum) {
111 uint256 hashTmp;
112 stream >> hashTmp;
113 if (hashTmp != verifier.GetHash()) {
114 throw std::runtime_error{"Checksum mismatch, data corrupted"};
115 }
116 }
117}
118
119template <typename Data>
120void DeserializeFileDB(const fs::path& path, Data&& data)
121{
122 FILE* file = fsbridge::fopen(path, "rb");
123 AutoFile filein{file};
124 if (filein.IsNull()) {
125 throw DbNotFoundError{};
126 }
127 DeserializeDB(filein, data);
128}
129} // namespace
130
132 : m_banlist_dat(ban_list_path + ".dat"),
133 m_banlist_json(ban_list_path + ".json")
134{
135}
136
137bool CBanDB::Write(const banmap_t& banSet)
138{
139 std::vector<std::string> errors;
140 if (common::WriteSettings(m_banlist_json, {{JSON_KEY, BanMapToJson(banSet)}}, errors)) {
141 return true;
142 }
143
144 for (const auto& err : errors) {
145 LogError("%s\n", err);
146 }
147 return false;
148}
149
151{
153 LogPrintf("banlist.dat ignored because it can only be read by " CLIENT_NAME " version 22.x. Remove %s to silence this warning.\n", fs::quoted(fs::PathToString(m_banlist_dat)));
154 }
155 // If the JSON banlist does not exist, then recreate it
157 return false;
158 }
159
160 std::map<std::string, common::SettingsValue> settings;
161 std::vector<std::string> errors;
162
163 if (!common::ReadSettings(m_banlist_json, settings, errors)) {
164 for (const auto& err : errors) {
165 LogPrintf("Cannot load banlist %s: %s\n", fs::PathToString(m_banlist_json), err);
166 }
167 return false;
168 }
169
170 try {
171 BanMapFromJson(settings[JSON_KEY], banSet);
172 } catch (const std::runtime_error& e) {
173 LogPrintf("Cannot parse banlist %s: %s\n", fs::PathToString(m_banlist_json), e.what());
174 return false;
175 }
176
177 return true;
178}
179
180bool DumpPeerAddresses(const ArgsManager& args, const AddrMan& addr)
181{
182 const auto pathAddr = args.GetDataDirNet() / "peers.dat";
183 return SerializeFileDB("peers", pathAddr, addr);
184}
185
186void ReadFromStream(AddrMan& addr, DataStream& ssPeers)
187{
188 DeserializeDB(ssPeers, addr, false);
189}
190
192{
193 auto check_addrman = std::clamp<int32_t>(args.GetIntArg("-checkaddrman", DEFAULT_ADDRMAN_CONSISTENCY_CHECKS), 0, 1000000);
194 bool deterministic = HasTestOption(args, "addrman"); // use a deterministic addrman only for tests
195
196 auto addrman{std::make_unique<AddrMan>(netgroupman, deterministic, /*consistency_check_ratio=*/check_addrman)};
197
198 const auto start{SteadyClock::now()};
199 const auto path_addr{args.GetDataDirNet() / "peers.dat"};
200 try {
201 DeserializeFileDB(path_addr, *addrman);
202 LogPrintf("Loaded %i addresses from peers.dat %dms\n", addrman->Size(), Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));
203 } catch (const DbNotFoundError&) {
204 // Addrman can be in an inconsistent state after failure, reset it
205 addrman = std::make_unique<AddrMan>(netgroupman, deterministic, /*consistency_check_ratio=*/check_addrman);
206 LogPrintf("Creating peers.dat because the file was not found (%s)\n", fs::quoted(fs::PathToString(path_addr)));
207 DumpPeerAddresses(args, *addrman);
208 } catch (const InvalidAddrManVersionError&) {
209 if (!RenameOver(path_addr, (fs::path)path_addr + ".bak")) {
210 return util::Error{strprintf(_("Failed to rename invalid peers.dat file. Please move or delete it and try again."))};
211 }
212 // Addrman can be in an inconsistent state after failure, reset it
213 addrman = std::make_unique<AddrMan>(netgroupman, deterministic, /*consistency_check_ratio=*/check_addrman);
214 LogPrintf("Creating new peers.dat because the file version was not compatible (%s). Original backed up to peers.dat.bak\n", fs::quoted(fs::PathToString(path_addr)));
215 DumpPeerAddresses(args, *addrman);
216 } catch (const std::exception& e) {
217 return util::Error{strprintf(_("Invalid or corrupt peers.dat (%s). If you believe this is a bug, please report it to %s. As a workaround, you can move the file (%s) out of the way (rename, move, or delete) to have a new one created on the next start."),
218 e.what(), CLIENT_BUGREPORT, fs::quoted(fs::PathToString(path_addr)))};
219 }
220 return addrman;
221}
222
223void DumpAnchors(const fs::path& anchors_db_path, const std::vector<CAddress>& anchors)
224{
225 LOG_TIME_SECONDS(strprintf("Flush %d outbound block-relay-only peer addresses to anchors.dat", anchors.size()));
226 SerializeFileDB("anchors", anchors_db_path, CAddress::V2_DISK(anchors));
227}
228
229std::vector<CAddress> ReadAnchors(const fs::path& anchors_db_path)
230{
231 std::vector<CAddress> anchors;
232 try {
233 DeserializeFileDB(anchors_db_path, CAddress::V2_DISK(anchors));
234 LogPrintf("Loaded %i addresses from %s\n", anchors.size(), fs::quoted(fs::PathToString(anchors_db_path.filename())));
235 } catch (const std::exception&) {
236 anchors.clear();
237 }
238
239 fs::remove(anchors_db_path);
240 return anchors;
241}
bool DumpPeerAddresses(const ArgsManager &args, const AddrMan &addr)
Definition: addrdb.cpp:180
std::vector< CAddress > ReadAnchors(const fs::path &anchors_db_path)
Read the anchor IP address database (anchors.dat)
Definition: addrdb.cpp:229
util::Result< std::unique_ptr< AddrMan > > LoadAddrman(const NetGroupManager &netgroupman, const ArgsManager &args)
Returns an error string on failure.
Definition: addrdb.cpp:191
void ReadFromStream(AddrMan &addr, DataStream &ssPeers)
Only used by tests.
Definition: addrdb.cpp:186
void DumpAnchors(const fs::path &anchors_db_path, const std::vector< CAddress > &anchors)
Dump the anchor IP address database (anchors.dat)
Definition: addrdb.cpp:223
static constexpr int32_t DEFAULT_ADDRMAN_CONSISTENCY_CHECKS
Default for -checkaddrman.
Definition: addrman.h:32
ArgsManager gArgs
Definition: args.cpp:42
bool HasTestOption(const ArgsManager &args, const std::string &test_option)
Checks if a particular test option is present in -test command-line arg options.
Definition: args.cpp:715
ArgsManager & args
Definition: bitcoind.cpp:277
const CChainParams & Params()
Return the currently selected parameters.
Stochastic address manager.
Definition: addrman.h:89
fs::path GetDataDirNet() const
Get data directory path with appended network identifier.
Definition: args.h:234
int64_t GetIntArg(const std::string &strArg, int64_t nDefault) const
Return integer argument or default value.
Definition: args.cpp:482
Non-refcounted RAII wrapper for FILE*.
Definition: streams.h:392
int fclose()
Definition: streams.h:409
static constexpr SerParams V2_DISK
Definition: protocol.h:411
bool Write(const banmap_t &banSet)
Definition: addrdb.cpp:137
const fs::path m_banlist_dat
Definition: addrdb.h:36
bool Read(banmap_t &banSet)
Read the banlist from disk.
Definition: addrdb.cpp:150
static constexpr const char * JSON_KEY
JSON key under which the data is stored in the json database.
Definition: addrdb.h:34
const fs::path m_banlist_json
Definition: addrdb.h:37
CBanDB(fs::path ban_list_path)
Definition: addrdb.cpp:131
const MessageStartChars & MessageStart() const
Definition: chainparams.h:94
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:147
Fast randomness source.
Definition: random.h:377
Reads data from an underlying stream, while hashing the read data.
Definition: hash.h:151
Writes data to an underlying source stream, while hashing the written data.
Definition: hash.h:185
Netgroup manager.
Definition: netgroup.h:16
I rand() noexcept
Generate a random integer in its entire (non-negative) range.
Definition: random.h:287
Path class wrapper to block calls to the fs::path(std::string) implicit constructor and the fs::path:...
Definition: fs.h:33
path filename() const
Definition: fs.h:72
256-bit opaque blob.
Definition: uint256.h:190
bool RenameOver(fs::path src, fs::path dest)
Rename src to dest.
Definition: fs_helpers.cpp:249
#define LogError(...)
Definition: logging.h:263
#define LogPrintf(...)
Definition: logging.h:266
std::array< uint8_t, 4 > MessageStartChars
bool WriteSettings(const fs::path &path, const std::map< std::string, SettingsValue > &values, std::vector< std::string > &errors)
Write settings file.
Definition: settings.cpp:123
bool ReadSettings(const fs::path &path, std::map< std::string, SettingsValue > &values, std::vector< std::string > &errors)
Read settings file.
Definition: settings.cpp:72
static path u8path(const std::string &utf8_str)
Definition: fs.h:75
static auto quoted(const std::string &s)
Definition: fs.h:95
static bool exists(const path &p)
Definition: fs.h:89
static std::string PathToString(const path &path)
Convert path object to a byte string.
Definition: fs.h:151
FILE * fopen(const fs::path &p, const char *mode)
Definition: fs.cpp:26
void BanMapFromJson(const UniValue &bans_json, banmap_t &bans)
Convert a JSON array to a banmap_t object.
Definition: net_types.cpp:58
UniValue BanMapToJson(const banmap_t &bans)
Convert a banmap_t object to a JSON array.
Definition: net_types.cpp:38
std::map< CSubNet, CBanEntry > banmap_t
Definition: net_types.h:41
const char * prefix
Definition: rest.cpp:1009
#define LOG_TIME_SECONDS(end_msg)
Definition: timer.h:107
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1165
bilingual_str _(ConstevalStringLiteral str)
Translation function.
Definition: translation.h:80