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