Line data Source code
1 : // Copyright (c) 2014-2020 The Dash Core developers
2 : // Copyright (c) 2021-2022 The PIVX Core developers
3 : // Distributed under the MIT software license, see the accompanying
4 : // file COPYING or https://www.opensource.org/licenses/mit-license.php.
5 :
6 : #ifndef PIVX_FLATDB_H
7 : #define PIVX_FLATDB_H
8 :
9 : #include "chainparams.h"
10 : #include "clientversion.h"
11 : #include "fs.h"
12 : #include "hash.h"
13 : #include "logging.h"
14 : #include "streams.h"
15 : #include "utiltime.h"
16 : #include "util/system.h"
17 :
18 : /**
19 : * Generic Dumping and Loading
20 : * ---------------------------
21 : */
22 :
23 : template<typename T>
24 : class CFlatDB
25 : {
26 : private:
27 : fs::path pathDB;
28 : std::string strFilename;
29 : std::string strMagicMessage;
30 :
31 : enum ReadResult {
32 : Ok,
33 : FileError,
34 : HashReadError,
35 : IncorrectHash,
36 : IncorrectMagicMessage,
37 : IncorrectMagicNumber,
38 : IncorrectFormat
39 : };
40 :
41 770 : bool Write(T& objToSave)
42 : {
43 770 : int64_t nStart = GetTimeMillis();
44 :
45 : // serialize, checksum data up to that point, then append checksum
46 770 : CDataStream ssObj(SER_DISK, CLIENT_VERSION);
47 770 : ssObj << strMagicMessage; // specific magic message for this type of object
48 770 : ssObj << Params().MessageStart(); // network specific magic number
49 770 : ssObj << objToSave;
50 770 : const uint256& hash = Hash(ssObj.begin(), ssObj.end());
51 770 : ssObj << hash;
52 :
53 : // open output file, and associate with CAutoFile
54 770 : FILE* file = fopen(pathDB.string().c_str(), "wb");
55 1540 : CAutoFile fileout(file, SER_DISK, CLIENT_VERSION);
56 770 : if (fileout.IsNull())
57 0 : return error("%s: Failed to open file %s", __func__, pathDB.string());
58 :
59 : // Write and commit header, data
60 : try {
61 770 : fileout << ssObj;
62 : }
63 0 : catch (std::exception &e) {
64 0 : return error("%s: Serialize or I/O error - %s", __func__, e.what());
65 : }
66 770 : fileout.fclose();
67 :
68 770 : LogPrintf("Written info to %s %dms\n", strFilename, GetTimeMillis() - nStart);
69 770 : LogPrintf(" %s\n", objToSave.ToString());
70 770 : return true;
71 : }
72 :
73 696 : ReadResult Read(T& objToLoad)
74 : {
75 696 : int64_t nStart = GetTimeMillis();
76 : // open input file, and associate with CAutoFile
77 696 : FILE* file = fopen(pathDB.string().c_str(), "rb");
78 1392 : CAutoFile filein(file, SER_DISK, CLIENT_VERSION);
79 696 : if (filein.IsNull()) {
80 544 : error("%s: Failed to open file %s", __func__, pathDB.string());
81 : return FileError;
82 : }
83 :
84 : // use file size to size memory buffer
85 152 : int fileSize = fs::file_size(pathDB);
86 152 : int dataSize = fileSize - sizeof(uint256);
87 : // Don't try to resize to a negative number if file is small
88 152 : if (dataSize < 0) dataSize = 0;
89 696 : std::vector<unsigned char> vchData;
90 152 : vchData.resize(dataSize);
91 152 : uint256 hashIn;
92 :
93 : // read data and checksum from file
94 : try {
95 152 : filein.read((char *)vchData.data(), dataSize);
96 152 : filein >> hashIn;
97 0 : } catch (std::exception &e) {
98 0 : error("%s: Deserialize or I/O error - %s", __func__, e.what());
99 : return HashReadError;
100 : }
101 152 : filein.fclose();
102 :
103 304 : CDataStream ssObj(vchData, SER_DISK, CLIENT_VERSION);
104 :
105 : // verify stored checksum matches input data
106 152 : uint256 hashTmp = Hash(ssObj.begin(), ssObj.end());
107 152 : if (hashIn != hashTmp) {
108 0 : error("%s: Checksum mismatch, data corrupted", __func__);
109 : return IncorrectHash;
110 : }
111 :
112 : unsigned char pchMsgTmp[4];
113 304 : std::string strMagicMessageTmp;
114 : try {
115 : // de-serialize file header (file specific magic message) and ..
116 152 : ssObj >> strMagicMessageTmp;
117 :
118 : // ... verify the message matches predefined one
119 152 : if (strMagicMessage != strMagicMessageTmp) {
120 0 : error("%s: Invalid magic message", __func__);
121 : return IncorrectMagicMessage;
122 : }
123 :
124 : // de-serialize file header (network specific magic number) and ..
125 152 : ssObj >> pchMsgTmp;
126 :
127 : // ... verify the network matches ours
128 152 : if (memcmp(pchMsgTmp, Params().MessageStart(), sizeof(pchMsgTmp))) {
129 0 : error("%s: Invalid network magic number", __func__);
130 : return IncorrectMagicNumber;
131 : }
132 :
133 : // de-serialize data into T object
134 152 : ssObj >> objToLoad;
135 0 : } catch (std::exception &e) {
136 0 : objToLoad.Clear();
137 0 : error("%s: Deserialize or I/O error - %s", __func__, e.what());
138 : return IncorrectFormat;
139 : }
140 :
141 152 : LogPrintf("Loaded info from %s %dms\n", strFilename, GetTimeMillis() - nStart);
142 152 : LogPrintf(" %s\n", objToLoad.ToString());
143 152 : return Ok;
144 : }
145 : public:
146 1466 : CFlatDB(const std::string& strFilenameIn,
147 : const std::string& strMagicMessageIn) :
148 : pathDB(GetDataDir() / strFilenameIn), strFilename(strFilenameIn),
149 5864 : strMagicMessage(strMagicMessageIn) {}
150 :
151 0 : fs::path GetDbPath() const { return pathDB; }
152 :
153 696 : bool Load(T& objToLoad)
154 : {
155 696 : LogPrintf("Reading info from %s...\n", strFilename);
156 696 : ReadResult readResult = Read(objToLoad);
157 696 : if (readResult == FileError) {
158 544 : LogPrintf("Missing file %s, will try to recreate\n", strFilename);
159 152 : } else if (readResult != Ok) {
160 0 : LogPrintf("Error reading %s: ", strFilename);
161 0 : if (readResult == IncorrectFormat) {
162 0 : LogPrintf("%s: Magic is ok but data has invalid format, will try to recreate\n", __func__);
163 : } else {
164 0 : LogPrintf("%s: File format is unknown or invalid, please fix it manually\n", __func__);
165 : // program should exit with an error
166 0 : return false;
167 : }
168 : }
169 : return true;
170 : }
171 :
172 770 : bool Dump(T& objToSave)
173 : {
174 770 : int64_t nStart = GetTimeMillis();
175 770 : LogPrintf("Writing info to %s...\n", strFilename);
176 770 : Write(objToSave);
177 770 : LogPrintf("%s dump finished %dms\n", strFilename, GetTimeMillis() - nStart);
178 770 : return true;
179 : }
180 : };
181 :
182 :
183 : #endif // PIVX_FLATDB_H
|