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 644 : bool Write(T& objToSave)
42 : {
43 644 : int64_t nStart = GetTimeMillis();
44 :
45 : // serialize, checksum data up to that point, then append checksum
46 644 : CDataStream ssObj(SER_DISK, CLIENT_VERSION);
47 644 : ssObj << strMagicMessage; // specific magic message for this type of object
48 644 : ssObj << Params().MessageStart(); // network specific magic number
49 644 : ssObj << objToSave;
50 644 : const uint256& hash = Hash(ssObj.begin(), ssObj.end());
51 644 : ssObj << hash;
52 :
53 : // open output file, and associate with CAutoFile
54 644 : FILE* file = fopen(pathDB.string().c_str(), "wb");
55 1288 : CAutoFile fileout(file, SER_DISK, CLIENT_VERSION);
56 644 : 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 644 : 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 644 : fileout.fclose();
67 :
68 644 : LogPrintf("Written info to %s %dms\n", strFilename, GetTimeMillis() - nStart);
69 644 : LogPrintf(" %s\n", objToSave.ToString());
70 644 : return true;
71 : }
72 :
73 572 : ReadResult Read(T& objToLoad)
74 : {
75 572 : int64_t nStart = GetTimeMillis();
76 : // open input file, and associate with CAutoFile
77 572 : FILE* file = fopen(pathDB.string().c_str(), "rb");
78 1144 : CAutoFile filein(file, SER_DISK, CLIENT_VERSION);
79 572 : if (filein.IsNull()) {
80 434 : error("%s: Failed to open file %s", __func__, pathDB.string());
81 : return FileError;
82 : }
83 :
84 : // use file size to size memory buffer
85 138 : int fileSize = fs::file_size(pathDB);
86 138 : int dataSize = fileSize - sizeof(uint256);
87 : // Don't try to resize to a negative number if file is small
88 138 : if (dataSize < 0) dataSize = 0;
89 572 : std::vector<unsigned char> vchData;
90 138 : vchData.resize(dataSize);
91 138 : uint256 hashIn;
92 :
93 : // read data and checksum from file
94 : try {
95 138 : filein.read((char *)vchData.data(), dataSize);
96 138 : 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 138 : filein.fclose();
102 :
103 276 : CDataStream ssObj(vchData, SER_DISK, CLIENT_VERSION);
104 :
105 : // verify stored checksum matches input data
106 138 : uint256 hashTmp = Hash(ssObj.begin(), ssObj.end());
107 138 : if (hashIn != hashTmp) {
108 0 : error("%s: Checksum mismatch, data corrupted", __func__);
109 : return IncorrectHash;
110 : }
111 :
112 : unsigned char pchMsgTmp[4];
113 276 : std::string strMagicMessageTmp;
114 : try {
115 : // de-serialize file header (file specific magic message) and ..
116 138 : ssObj >> strMagicMessageTmp;
117 :
118 : // ... verify the message matches predefined one
119 138 : 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 138 : ssObj >> pchMsgTmp;
126 :
127 : // ... verify the network matches ours
128 138 : 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 138 : 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 138 : LogPrintf("Loaded info from %s %dms\n", strFilename, GetTimeMillis() - nStart);
142 138 : LogPrintf(" %s\n", objToLoad.ToString());
143 138 : return Ok;
144 : }
145 : public:
146 1216 : CFlatDB(const std::string& strFilenameIn,
147 : const std::string& strMagicMessageIn) :
148 : pathDB(GetDataDir() / strFilenameIn), strFilename(strFilenameIn),
149 4864 : strMagicMessage(strMagicMessageIn) {}
150 :
151 0 : fs::path GetDbPath() const { return pathDB; }
152 :
153 572 : bool Load(T& objToLoad)
154 : {
155 572 : LogPrintf("Reading info from %s...\n", strFilename);
156 572 : ReadResult readResult = Read(objToLoad);
157 572 : if (readResult == FileError) {
158 434 : LogPrintf("Missing file %s, will try to recreate\n", strFilename);
159 138 : } 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 644 : bool Dump(T& objToSave)
173 : {
174 644 : int64_t nStart = GetTimeMillis();
175 644 : LogPrintf("Writing info to %s...\n", strFilename);
176 644 : Write(objToSave);
177 644 : LogPrintf("%s dump finished %dms\n", strFilename, GetTimeMillis() - nStart);
178 644 : return true;
179 : }
180 : };
181 :
182 :
183 : #endif // PIVX_FLATDB_H
|