Bitcoin Core  21.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 <random.h>
15 #include <streams.h>
16 #include <tinyformat.h>
17 #include <util/system.h>
18 
19 namespace {
20 
21 template <typename Stream, typename Data>
22 bool SerializeDB(Stream& stream, const Data& data)
23 {
24  // Write and commit header, data
25  try {
27  stream << Params().MessageStart() << data;
28  hasher << Params().MessageStart() << data;
29  stream << hasher.GetHash();
30  } catch (const std::exception& e) {
31  return error("%s: Serialize or I/O error - %s", __func__, e.what());
32  }
33 
34  return true;
35 }
36 
37 template <typename Data>
38 bool SerializeFileDB(const std::string& prefix, const fs::path& path, const Data& data)
39 {
40  // Generate random temporary filename
41  uint16_t randv = 0;
42  GetRandBytes((unsigned char*)&randv, sizeof(randv));
43  std::string tmpfn = strprintf("%s.%04x", prefix, randv);
44 
45  // open temp output file, and associate with CAutoFile
46  fs::path pathTmp = GetDataDir() / tmpfn;
47  FILE *file = fsbridge::fopen(pathTmp, "wb");
48  CAutoFile fileout(file, SER_DISK, CLIENT_VERSION);
49  if (fileout.IsNull()) {
50  fileout.fclose();
51  remove(pathTmp);
52  return error("%s: Failed to open file %s", __func__, pathTmp.string());
53  }
54 
55  // Serialize
56  if (!SerializeDB(fileout, data)) {
57  fileout.fclose();
58  remove(pathTmp);
59  return false;
60  }
61  if (!FileCommit(fileout.Get())) {
62  fileout.fclose();
63  remove(pathTmp);
64  return error("%s: Failed to flush file %s", __func__, pathTmp.string());
65  }
66  fileout.fclose();
67 
68  // replace existing file, if any, with new file
69  if (!RenameOver(pathTmp, path)) {
70  remove(pathTmp);
71  return error("%s: Rename-into-place failed", __func__);
72  }
73 
74  return true;
75 }
76 
77 template <typename Stream, typename Data>
78 bool DeserializeDB(Stream& stream, Data& data, bool fCheckSum = true)
79 {
80  try {
81  CHashVerifier<Stream> verifier(&stream);
82  // de-serialize file header (network specific magic number) and ..
83  unsigned char pchMsgTmp[4];
84  verifier >> pchMsgTmp;
85  // ... verify the network matches ours
86  if (memcmp(pchMsgTmp, Params().MessageStart(), sizeof(pchMsgTmp)))
87  return error("%s: Invalid network magic number", __func__);
88 
89  // de-serialize data
90  verifier >> data;
91 
92  // verify checksum
93  if (fCheckSum) {
94  uint256 hashTmp;
95  stream >> hashTmp;
96  if (hashTmp != verifier.GetHash()) {
97  return error("%s: Checksum mismatch, data corrupted", __func__);
98  }
99  }
100  }
101  catch (const std::exception& e) {
102  return error("%s: Deserialize or I/O error - %s", __func__, e.what());
103  }
104 
105  return true;
106 }
107 
108 template <typename Data>
109 bool DeserializeFileDB(const fs::path& path, Data& data)
110 {
111  // open input file, and associate with CAutoFile
112  FILE* file = fsbridge::fopen(path, "rb");
113  CAutoFile filein(file, SER_DISK, CLIENT_VERSION);
114  if (filein.IsNull()) {
115  LogPrintf("Missing or invalid file %s\n", path.string());
116  return false;
117  }
118  return DeserializeDB(filein, data);
119 }
120 } // namespace
121 
122 CBanDB::CBanDB(fs::path ban_list_path) : m_ban_list_path(std::move(ban_list_path))
123 {
124 }
125 
126 bool CBanDB::Write(const banmap_t& banSet)
127 {
128  return SerializeFileDB("banlist", m_ban_list_path, banSet);
129 }
130 
131 bool CBanDB::Read(banmap_t& banSet)
132 {
133  return DeserializeFileDB(m_ban_list_path, banSet);
134 }
135 
137 {
138  pathAddr = GetDataDir() / "peers.dat";
139 }
140 
141 bool CAddrDB::Write(const CAddrMan& addr)
142 {
143  return SerializeFileDB("peers", pathAddr, addr);
144 }
145 
147 {
148  return DeserializeFileDB(pathAddr, addr);
149 }
150 
151 bool CAddrDB::Read(CAddrMan& addr, CDataStream& ssPeers)
152 {
153  bool ret = DeserializeDB(ssPeers, addr, false);
154  if (!ret) {
155  // Ensure addrman is left in a clean state
156  addr.Clear();
157  }
158  return ret;
159 }
160 
161 void DumpAnchors(const fs::path& anchors_db_path, const std::vector<CAddress>& anchors)
162 {
163  LOG_TIME_SECONDS(strprintf("Flush %d outbound block-relay-only peer addresses to anchors.dat", anchors.size()));
164  SerializeFileDB("anchors", anchors_db_path, anchors);
165 }
166 
167 std::vector<CAddress> ReadAnchors(const fs::path& anchors_db_path)
168 {
169  std::vector<CAddress> anchors;
170  if (DeserializeFileDB(anchors_db_path, anchors)) {
171  LogPrintf("Loaded %i addresses from %s\n", anchors.size(), anchors_db_path.filename());
172  } else {
173  anchors.clear();
174  }
175 
176  fs::remove(anchors_db_path);
177  return anchors;
178 }
CBanDB::Read
bool Read(banmap_t &banSet)
Definition: addrdb.cpp:131
GetDataDir
const fs::path & GetDataDir(bool fNetSpecific)
Definition: system.cpp:770
SER_DISK
@ SER_DISK
Definition: serialize.h:167
LOG_TIME_SECONDS
#define LOG_TIME_SECONDS(end_msg)
Definition: timer.h:98
CAddrDB::CAddrDB
CAddrDB()
Definition: addrdb.cpp:136
CHashVerifier
Reads data from an underlying stream, while hashing the read data.
Definition: hash.h:157
fsbridge::fopen
FILE * fopen(const fs::path &p, const char *mode)
Definition: fs.cpp:24
streams.h
DumpAnchors
void DumpAnchors(const fs::path &anchors_db_path, const std::vector< CAddress > &anchors)
Dump the anchor IP address database (anchors.dat)
Definition: addrdb.cpp:161
CBanDB::Write
bool Write(const banmap_t &banSet)
Definition: addrdb.cpp:126
RenameOver
bool RenameOver(fs::path src, fs::path dest)
Definition: system.cpp:1058
clientversion.h
chainparams.h
CAddrDB::Write
bool Write(const CAddrMan &addr)
Definition: addrdb.cpp:141
tinyformat.h
prefix
const char * prefix
Definition: rest.cpp:682
CAutoFile
Non-refcounted RAII wrapper for FILE*.
Definition: streams.h:564
addrdb.h
random.h
timer.h
GetRandBytes
void GetRandBytes(unsigned char *buf, int num) noexcept
Overall design of the RNG and entropy sources.
Definition: random.cpp:584
LogPrintf
#define LogPrintf(...)
Definition: logging.h:183
uint256
256-bit opaque blob.
Definition: uint256.h:124
CChainParams::MessageStart
const CMessageHeader::MessageStartChars & MessageStart() const
Definition: chainparams.h:78
system.h
strprintf
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1164
CAddrMan
Stochastical (IP) address manager.
Definition: addrman.h:172
FileCommit
bool FileCommit(FILE *file)
Ensure file contents are fully committed to disk, using a platform-specific feature analogous to fsyn...
Definition: system.cpp:1088
CLIENT_VERSION
static const int CLIENT_VERSION
bitcoind-res.rc includes this file, but it cannot cope with real c++ code.
Definition: clientversion.h:33
CHashWriter
A writer stream (for serialization) that computes a 256-bit hash.
Definition: hash.h:100
CAddrMan::Clear
void Clear()
Definition: addrman.h:580
Params
const CChainParams & Params()
Return the currently selected parameters.
Definition: chainparams.cpp:538
CAddrDB::Read
bool Read(CAddrMan &addr)
Definition: addrdb.cpp:146
CBanDB::CBanDB
CBanDB(fs::path ban_list_path)
Definition: addrdb.cpp:122
hash.h
CDataStream
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:204
ReadAnchors
std::vector< CAddress > ReadAnchors(const fs::path &anchors_db_path)
Read the anchor IP address database (anchors.dat)
Definition: addrdb.cpp:167
addrman.h
CBanDB::m_ban_list_path
const fs::path m_ban_list_path
Definition: addrdb.h:69
banmap_t
std::map< CSubNet, CBanEntry > banmap_t
Definition: net_types.h:13
error
bool error(const char *fmt, const Args &... args)
Definition: system.h:50
CAddrDB::pathAddr
fs::path pathAddr
Definition: addrdb.h:57