Bitcoin Core 22.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-2020 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 <addrdb.h>
7
8#include <addrman.h>
9#include <chainparams.h>
10#include <clientversion.h>
11#include <cstdint>
12#include <hash.h>
13#include <logging/timer.h>
14#include <netbase.h>
15#include <random.h>
16#include <streams.h>
17#include <tinyformat.h>
18#include <univalue.h>
19#include <util/settings.h>
20#include <util/system.h>
21#include <util/translation.h>
22
23namespace {
24
25class DbNotFoundError : public std::exception
26{
27 using std::exception::exception;
28};
29
30template <typename Stream, typename Data>
31bool SerializeDB(Stream& stream, const Data& data)
32{
33 // Write and commit header, data
34 try {
35 CHashWriter hasher(stream.GetType(), stream.GetVersion());
36 stream << Params().MessageStart() << data;
37 hasher << Params().MessageStart() << data;
38 stream << hasher.GetHash();
39 } catch (const std::exception& e) {
40 return error("%s: Serialize or I/O error - %s", __func__, e.what());
41 }
42
43 return true;
44}
45
46template <typename Data>
47bool SerializeFileDB(const std::string& prefix, const fs::path& path, const Data& data, int version)
48{
49 // Generate random temporary filename
50 uint16_t randv = 0;
51 GetRandBytes((unsigned char*)&randv, sizeof(randv));
52 std::string tmpfn = strprintf("%s.%04x", prefix, randv);
53
54 // open temp output file, and associate with CAutoFile
55 fs::path pathTmp = gArgs.GetDataDirNet() / tmpfn;
56 FILE *file = fsbridge::fopen(pathTmp, "wb");
57 CAutoFile fileout(file, SER_DISK, version);
58 if (fileout.IsNull()) {
59 fileout.fclose();
60 remove(pathTmp);
61 return error("%s: Failed to open file %s", __func__, fs::PathToString(pathTmp));
62 }
63
64 // Serialize
65 if (!SerializeDB(fileout, data)) {
66 fileout.fclose();
67 remove(pathTmp);
68 return false;
69 }
70 if (!FileCommit(fileout.Get())) {
71 fileout.fclose();
72 remove(pathTmp);
73 return error("%s: Failed to flush file %s", __func__, fs::PathToString(pathTmp));
74 }
75 fileout.fclose();
76
77 // replace existing file, if any, with new file
78 if (!RenameOver(pathTmp, path)) {
79 remove(pathTmp);
80 return error("%s: Rename-into-place failed", __func__);
81 }
82
83 return true;
84}
85
86template <typename Stream, typename Data>
87void DeserializeDB(Stream& stream, Data& data, bool fCheckSum = true)
88{
89 CHashVerifier<Stream> verifier(&stream);
90 // de-serialize file header (network specific magic number) and ..
91 unsigned char pchMsgTmp[4];
92 verifier >> pchMsgTmp;
93 // ... verify the network matches ours
94 if (memcmp(pchMsgTmp, Params().MessageStart(), sizeof(pchMsgTmp))) {
95 throw std::runtime_error{"Invalid network magic number"};
96 }
97
98 // de-serialize data
99 verifier >> data;
100
101 // verify checksum
102 if (fCheckSum) {
103 uint256 hashTmp;
104 stream >> hashTmp;
105 if (hashTmp != verifier.GetHash()) {
106 throw std::runtime_error{"Checksum mismatch, data corrupted"};
107 }
108 }
109}
110
111template <typename Data>
112void DeserializeFileDB(const fs::path& path, Data& data, int version)
113{
114 // open input file, and associate with CAutoFile
115 FILE* file = fsbridge::fopen(path, "rb");
116 CAutoFile filein(file, SER_DISK, version);
117 if (filein.IsNull()) {
118 throw DbNotFoundError{};
119 }
120 DeserializeDB(filein, data);
121}
122} // namespace
123
125 : m_banlist_dat(ban_list_path + ".dat"),
126 m_banlist_json(ban_list_path + ".json")
127{
128}
129
130bool CBanDB::Write(const banmap_t& banSet)
131{
132 std::vector<std::string> errors;
133 if (util::WriteSettings(m_banlist_json, {{JSON_KEY, BanMapToJson(banSet)}}, errors)) {
134 return true;
135 }
136
137 for (const auto& err : errors) {
138 error("%s", err);
139 }
140 return false;
141}
142
144{
146 LogPrintf("banlist.dat ignored because it can only be read by " PACKAGE_NAME " version 22.x. Remove %s to silence this warning.\n", fs::quoted(fs::PathToString(m_banlist_dat)));
147 }
148 // If the JSON banlist does not exist, then recreate it
150 return false;
151 }
152
153 std::map<std::string, util::SettingsValue> settings;
154 std::vector<std::string> errors;
155
156 if (!util::ReadSettings(m_banlist_json, settings, errors)) {
157 for (const auto& err : errors) {
158 LogPrintf("Cannot load banlist %s: %s\n", fs::PathToString(m_banlist_json), err);
159 }
160 return false;
161 }
162
163 try {
164 BanMapFromJson(settings[JSON_KEY], banSet);
165 } catch (const std::runtime_error& e) {
166 LogPrintf("Cannot parse banlist %s: %s\n", fs::PathToString(m_banlist_json), e.what());
167 return false;
168 }
169
170 return true;
171}
172
173bool DumpPeerAddresses(const ArgsManager& args, const AddrMan& addr)
174{
175 const auto pathAddr = args.GetDataDirNet() / "peers.dat";
176 return SerializeFileDB("peers", pathAddr, addr, CLIENT_VERSION);
177}
178
179void ReadFromStream(AddrMan& addr, CDataStream& ssPeers)
180{
181 DeserializeDB(ssPeers, addr, false);
182}
183
184std::optional<bilingual_str> LoadAddrman(const std::vector<bool>& asmap, const ArgsManager& args, std::unique_ptr<AddrMan>& addrman)
185{
186 auto check_addrman = std::clamp<int32_t>(args.GetIntArg("-checkaddrman", DEFAULT_ADDRMAN_CONSISTENCY_CHECKS), 0, 1000000);
187 addrman = std::make_unique<AddrMan>(asmap, /* deterministic */ false, /* consistency_check_ratio */ check_addrman);
188
189 int64_t nStart = GetTimeMillis();
190 const auto path_addr{args.GetDataDirNet() / "peers.dat"};
191 try {
192 DeserializeFileDB(path_addr, *addrman, CLIENT_VERSION);
193 LogPrintf("Loaded %i addresses from peers.dat %dms\n", addrman->size(), GetTimeMillis() - nStart);
194 } catch (const DbNotFoundError&) {
195 // Addrman can be in an inconsistent state after failure, reset it
196 addrman = std::make_unique<AddrMan>(asmap, /* deterministic */ false, /* consistency_check_ratio */ check_addrman);
197 LogPrintf("Creating peers.dat because the file was not found (%s)\n", fs::quoted(fs::PathToString(path_addr)));
198 DumpPeerAddresses(args, *addrman);
199 } catch (const std::exception& e) {
200 addrman = nullptr;
201 return 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."),
202 e.what(), PACKAGE_BUGREPORT, fs::quoted(fs::PathToString(path_addr)));
203 }
204 return std::nullopt;
205}
206
207void DumpAnchors(const fs::path& anchors_db_path, const std::vector<CAddress>& anchors)
208{
209 LOG_TIME_SECONDS(strprintf("Flush %d outbound block-relay-only peer addresses to anchors.dat", anchors.size()));
210 SerializeFileDB("anchors", anchors_db_path, anchors, CLIENT_VERSION | ADDRV2_FORMAT);
211}
212
213std::vector<CAddress> ReadAnchors(const fs::path& anchors_db_path)
214{
215 std::vector<CAddress> anchors;
216 try {
217 DeserializeFileDB(anchors_db_path, anchors, CLIENT_VERSION | ADDRV2_FORMAT);
218 LogPrintf("Loaded %i addresses from %s\n", anchors.size(), fs::quoted(fs::PathToString(anchors_db_path.filename())));
219 } catch (const std::exception&) {
220 anchors.clear();
221 }
222
223 fs::remove(anchors_db_path);
224 return anchors;
225}
bool DumpPeerAddresses(const ArgsManager &args, const AddrMan &addr)
Definition: addrdb.cpp:173
std::vector< CAddress > ReadAnchors(const fs::path &anchors_db_path)
Read the anchor IP address database (anchors.dat)
Definition: addrdb.cpp:213
void DumpAnchors(const fs::path &anchors_db_path, const std::vector< CAddress > &anchors)
Dump the anchor IP address database (anchors.dat)
Definition: addrdb.cpp:207
void ReadFromStream(AddrMan &addr, CDataStream &ssPeers)
Only used by tests.
Definition: addrdb.cpp:179
std::optional< bilingual_str > LoadAddrman(const std::vector< bool > &asmap, const ArgsManager &args, std::unique_ptr< AddrMan > &addrman)
Returns an error string on failure.
Definition: addrdb.cpp:184
static constexpr int32_t DEFAULT_ADDRMAN_CONSISTENCY_CHECKS
Default for -checkaddrman.
Definition: addrman.h:23
#define PACKAGE_NAME
#define PACKAGE_BUGREPORT
const CChainParams & Params()
Return the currently selected parameters.
Stochastic address manager.
Definition: addrman.h:55
const fs::path & GetDataDirNet() const
Get data directory path with appended network identifier.
Definition: system.h:288
int64_t GetIntArg(const std::string &strArg, int64_t nDefault) const
Return integer argument or default value.
Definition: system.cpp:596
Non-refcounted RAII wrapper for FILE*.
Definition: streams.h:565
bool Write(const banmap_t &banSet)
Definition: addrdb.cpp:130
const fs::path m_banlist_dat
Definition: addrdb.h:35
bool Read(banmap_t &banSet)
Read the banlist from disk.
Definition: addrdb.cpp:143
static constexpr const char * JSON_KEY
JSON key under which the data is stored in the json database.
Definition: addrdb.h:33
const fs::path m_banlist_json
Definition: addrdb.h:36
CBanDB(fs::path ban_list_path)
Definition: addrdb.cpp:124
const CMessageHeader::MessageStartChars & MessageStart() const
Definition: chainparams.h:83
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:205
Reads data from an underlying stream, while hashing the read data.
Definition: hash.h:158
A writer stream (for serialization) that computes a 256-bit hash.
Definition: hash.h:101
Path class wrapper to prepare application code for transition from boost::filesystem library to std::...
Definition: fs.h:34
256-bit opaque blob.
Definition: uint256.h:124
static const int CLIENT_VERSION
bitcoind-res.rc includes this file, but it cannot cope with real c++ code.
Definition: clientversion.h:33
#define LogPrintf(...)
Definition: logging.h:187
static auto quoted(const std::string &s)
Definition: fs.h:83
static bool exists(const path &p)
Definition: fs.h:77
static std::string PathToString(const path &path)
Convert path object to byte string.
Definition: fs.h:120
FILE * fopen(const fs::path &p, const char *mode)
Definition: fs.cpp:25
bool ReadSettings(const fs::path &path, std::map< std::string, SettingsValue > &values, std::vector< std::string > &errors)
Read settings file.
Definition: settings.cpp:58
bool WriteSettings(const fs::path &path, const std::map< std::string, SettingsValue > &values, std::vector< std::string > &errors)
Write settings file.
Definition: settings.cpp:101
void BanMapFromJson(const UniValue &bans_json, banmap_t &bans)
Convert a JSON array to a banmap_t object.
Definition: net_types.cpp:54
UniValue BanMapToJson(const banmap_t &bans)
Convert a banmap_t object to a JSON array.
Definition: net_types.cpp:34
std::map< CSubNet, CBanEntry > banmap_t
Definition: net_types.h:41
static constexpr int ADDRV2_FORMAT
A flag that is ORed into the protocol version to designate that addresses should be serialized in (un...
Definition: netaddress.h:34
void GetRandBytes(unsigned char *buf, int num) noexcept
Overall design of the RNG and entropy sources.
Definition: random.cpp:584
const char * prefix
Definition: rest.cpp:714
@ SER_DISK
Definition: serialize.h:139
bool error(const char *fmt, const Args &... args)
Definition: system.h:49
int64_t GetTimeMillis()
Returns the system time (not mockable)
Definition: time.cpp:117
#define LOG_TIME_SECONDS(end_msg)
Definition: timer.h:94
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1164
bilingual_str _(const char *psz)
Translation function.
Definition: translation.h:63
bool RenameOver(fs::path src, fs::path dest)
Definition: system.cpp:1065
ArgsManager gArgs
Definition: system.cpp:85
bool FileCommit(FILE *file)
Ensure file contents are fully committed to disk, using a platform-specific feature analogous to fsyn...
Definition: system.cpp:1095