Line data Source code
1 : // Copyright (c) 2009-2010 Satoshi Nakamoto
2 : // Copyright (c) 2009-2019 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 <random.h>
14 : #include <streams.h>
15 : #include <tinyformat.h>
16 : #include <util/system.h>
17 :
18 : namespace {
19 :
20 : template <typename Stream, typename Data>
21 1231 : bool SerializeDB(Stream& stream, const Data& data)
22 : {
23 : // Write and commit header, data
24 : try {
25 1231 : CHashWriter hasher(SER_DISK, CLIENT_VERSION);
26 1231 : stream << Params().MessageStart() << data;
27 1231 : hasher << Params().MessageStart() << data;
28 1231 : stream << hasher.GetHash();
29 1231 : } catch (const std::exception& e) {
30 0 : return error("%s: Serialize or I/O error - %s", __func__, e.what());
31 0 : }
32 :
33 1231 : return true;
34 1231 : }
35 :
36 : template <typename Data>
37 1231 : bool SerializeFileDB(const std::string& prefix, const fs::path& path, const Data& data)
38 : {
39 : // Generate random temporary filename
40 1231 : uint16_t randv = 0;
41 1231 : GetRandBytes((unsigned char*)&randv, sizeof(randv));
42 1231 : std::string tmpfn = strprintf("%s.%04x", prefix, randv);
43 :
44 : // open temp output file, and associate with CAutoFile
45 1231 : fs::path pathTmp = GetDataDir() / tmpfn;
46 1231 : FILE *file = fsbridge::fopen(pathTmp, "wb");
47 1231 : CAutoFile fileout(file, SER_DISK, CLIENT_VERSION);
48 1231 : if (fileout.IsNull()) {
49 0 : fileout.fclose();
50 0 : remove(pathTmp);
51 0 : return error("%s: Failed to open file %s", __func__, pathTmp.string());
52 : }
53 :
54 : // Serialize
55 1231 : if (!SerializeDB(fileout, data)) {
56 0 : fileout.fclose();
57 0 : remove(pathTmp);
58 0 : return false;
59 : }
60 1231 : if (!FileCommit(fileout.Get())) {
61 0 : fileout.fclose();
62 0 : remove(pathTmp);
63 0 : return error("%s: Failed to flush file %s", __func__, pathTmp.string());
64 : }
65 1231 : fileout.fclose();
66 :
67 : // replace existing file, if any, with new file
68 1231 : if (!RenameOver(pathTmp, path)) {
69 0 : remove(pathTmp);
70 0 : return error("%s: Rename-into-place failed", __func__);
71 : }
72 :
73 1231 : return true;
74 1231 : }
75 :
76 : template <typename Stream, typename Data>
77 395 : bool DeserializeDB(Stream& stream, Data& data, bool fCheckSum = true)
78 : {
79 : try {
80 395 : CHashVerifier<Stream> verifier(&stream);
81 : // de-serialize file header (network specific magic number) and ..
82 395 : unsigned char pchMsgTmp[4];
83 395 : verifier >> pchMsgTmp;
84 : // ... verify the network matches ours
85 395 : if (memcmp(pchMsgTmp, Params().MessageStart(), sizeof(pchMsgTmp)))
86 0 : return error("%s: Invalid network magic number", __func__);
87 :
88 : // de-serialize data
89 395 : verifier >> data;
90 :
91 : // verify checksum
92 394 : if (fCheckSum) {
93 393 : uint256 hashTmp;
94 393 : stream >> hashTmp;
95 393 : if (hashTmp != verifier.GetHash()) {
96 0 : return error("%s: Checksum mismatch, data corrupted", __func__);
97 : }
98 393 : }
99 395 : }
100 : catch (const std::exception& e) {
101 1 : return error("%s: Deserialize or I/O error - %s", __func__, e.what());
102 1 : }
103 :
104 394 : return true;
105 397 : }
106 :
107 : template <typename Data>
108 1100 : bool DeserializeFileDB(const fs::path& path, Data& data)
109 : {
110 : // open input file, and associate with CAutoFile
111 1100 : FILE *file = fsbridge::fopen(path, "rb");
112 1100 : CAutoFile filein(file, SER_DISK, CLIENT_VERSION);
113 1100 : if (filein.IsNull())
114 707 : return error("%s: Failed to open file %s", __func__, path.string());
115 :
116 393 : return DeserializeDB(filein, data);
117 1100 : }
118 :
119 : }
120 :
121 1216 : CBanDB::CBanDB(fs::path ban_list_path) : m_ban_list_path(std::move(ban_list_path))
122 608 : {
123 1216 : }
124 :
125 432 : bool CBanDB::Write(const banmap_t& banSet)
126 : {
127 432 : return SerializeFileDB("banlist", m_ban_list_path, banSet);
128 0 : }
129 :
130 608 : bool CBanDB::Read(banmap_t& banSet)
131 : {
132 608 : return DeserializeFileDB(m_ban_list_path, banSet);
133 : }
134 :
135 2582 : CAddrDB::CAddrDB()
136 1291 : {
137 1291 : pathAddr = GetDataDir() / "peers.dat";
138 2582 : }
139 :
140 799 : bool CAddrDB::Write(const CAddrMan& addr)
141 : {
142 799 : return SerializeFileDB("peers", pathAddr, addr);
143 0 : }
144 :
145 492 : bool CAddrDB::Read(CAddrMan& addr)
146 : {
147 492 : return DeserializeFileDB(pathAddr, addr);
148 : }
149 :
150 2 : bool CAddrDB::Read(CAddrMan& addr, CDataStream& ssPeers)
151 : {
152 2 : bool ret = DeserializeDB(ssPeers, addr, false);
153 2 : if (!ret) {
154 : // Ensure addrman is left in a clean state
155 1 : addr.Clear();
156 1 : }
157 2 : return ret;
158 : }
|