PIVX Core  5.6.99
P2P Digital Currency
flatdb.h
Go to the documentation of this file.
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 
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,
39  };
40 
41  bool Write(T& objToSave)
42  {
43  int64_t nStart = GetTimeMillis();
44 
45  // serialize, checksum data up to that point, then append checksum
46  CDataStream ssObj(SER_DISK, CLIENT_VERSION);
47  ssObj << strMagicMessage; // specific magic message for this type of object
48  ssObj << Params().MessageStart(); // network specific magic number
49  ssObj << objToSave;
50  const uint256& hash = Hash(ssObj.begin(), ssObj.end());
51  ssObj << hash;
52 
53  // open output file, and associate with CAutoFile
54  FILE* file = fopen(pathDB.string().c_str(), "wb");
55  CAutoFile fileout(file, SER_DISK, CLIENT_VERSION);
56  if (fileout.IsNull())
57  return error("%s: Failed to open file %s", __func__, pathDB.string());
58 
59  // Write and commit header, data
60  try {
61  fileout << ssObj;
62  }
63  catch (std::exception &e) {
64  return error("%s: Serialize or I/O error - %s", __func__, e.what());
65  }
66  fileout.fclose();
67 
68  LogPrintf("Written info to %s %dms\n", strFilename, GetTimeMillis() - nStart);
69  LogPrintf(" %s\n", objToSave.ToString());
70  return true;
71  }
72 
73  ReadResult Read(T& objToLoad)
74  {
75  int64_t nStart = GetTimeMillis();
76  // open input file, and associate with CAutoFile
77  FILE* file = fopen(pathDB.string().c_str(), "rb");
78  CAutoFile filein(file, SER_DISK, CLIENT_VERSION);
79  if (filein.IsNull()) {
80  error("%s: Failed to open file %s", __func__, pathDB.string());
81  return FileError;
82  }
83 
84  // use file size to size memory buffer
85  int fileSize = fs::file_size(pathDB);
86  int dataSize = fileSize - sizeof(uint256);
87  // Don't try to resize to a negative number if file is small
88  if (dataSize < 0) dataSize = 0;
89  std::vector<unsigned char> vchData;
90  vchData.resize(dataSize);
91  uint256 hashIn;
92 
93  // read data and checksum from file
94  try {
95  filein.read((char *)vchData.data(), dataSize);
96  filein >> hashIn;
97  } catch (std::exception &e) {
98  error("%s: Deserialize or I/O error - %s", __func__, e.what());
99  return HashReadError;
100  }
101  filein.fclose();
102 
103  CDataStream ssObj(vchData, SER_DISK, CLIENT_VERSION);
104 
105  // verify stored checksum matches input data
106  uint256 hashTmp = Hash(ssObj.begin(), ssObj.end());
107  if (hashIn != hashTmp) {
108  error("%s: Checksum mismatch, data corrupted", __func__);
109  return IncorrectHash;
110  }
111 
112  unsigned char pchMsgTmp[4];
113  std::string strMagicMessageTmp;
114  try {
115  // de-serialize file header (file specific magic message) and ..
116  ssObj >> strMagicMessageTmp;
117 
118  // ... verify the message matches predefined one
119  if (strMagicMessage != strMagicMessageTmp) {
120  error("%s: Invalid magic message", __func__);
121  return IncorrectMagicMessage;
122  }
123 
124  // de-serialize file header (network specific magic number) and ..
125  ssObj >> pchMsgTmp;
126 
127  // ... verify the network matches ours
128  if (memcmp(pchMsgTmp, Params().MessageStart(), sizeof(pchMsgTmp))) {
129  error("%s: Invalid network magic number", __func__);
130  return IncorrectMagicNumber;
131  }
132 
133  // de-serialize data into T object
134  ssObj >> objToLoad;
135  } catch (std::exception &e) {
136  objToLoad.Clear();
137  error("%s: Deserialize or I/O error - %s", __func__, e.what());
138  return IncorrectFormat;
139  }
140 
141  LogPrintf("Loaded info from %s %dms\n", strFilename, GetTimeMillis() - nStart);
142  LogPrintf(" %s\n", objToLoad.ToString());
143  return Ok;
144  }
145 public:
146  CFlatDB(const std::string& strFilenameIn,
147  const std::string& strMagicMessageIn) :
148  pathDB(GetDataDir() / strFilenameIn), strFilename(strFilenameIn),
149  strMagicMessage(strMagicMessageIn) {}
150 
151  fs::path GetDbPath() const { return pathDB; }
152 
153  bool Load(T& objToLoad)
154  {
155  LogPrintf("Reading info from %s...\n", strFilename);
156  ReadResult readResult = Read(objToLoad);
157  if (readResult == FileError) {
158  LogPrintf("Missing file %s, will try to recreate\n", strFilename);
159  } else if (readResult != Ok) {
160  LogPrintf("Error reading %s: ", strFilename);
161  if (readResult == IncorrectFormat) {
162  LogPrintf("%s: Magic is ok but data has invalid format, will try to recreate\n", __func__);
163  } else {
164  LogPrintf("%s: File format is unknown or invalid, please fix it manually\n", __func__);
165  // program should exit with an error
166  return false;
167  }
168  }
169  return true;
170  }
171 
172  bool Dump(T& objToSave)
173  {
174  int64_t nStart = GetTimeMillis();
175  LogPrintf("Writing info to %s...\n", strFilename);
176  Write(objToSave);
177  LogPrintf("%s dump finished %dms\n", strFilename, GetTimeMillis() - nStart);
178  return true;
179  }
180 };
181 
182 
183 #endif // PIVX_FLATDB_H
const CChainParams & Params()
Return the currently selected parameters.
Non-refcounted RAII wrapper for FILE*.
Definition: streams.h:452
bool IsNull() const
Return true if the wrapped FILE* is nullptr, false otherwise.
Definition: streams.h:501
void fclose()
Definition: streams.h:474
void read(char *pch, size_t nSize)
Definition: streams.h:509
const_iterator end() const
Definition: streams.h:163
const_iterator begin() const
Definition: streams.h:161
const CMessageHeader::MessageStartChars & MessageStart() const
Definition: chainparams.h:73
Definition: flatdb.h:25
std::string strMagicMessage
Definition: flatdb.h:29
ReadResult
Definition: flatdb.h:31
@ IncorrectFormat
Definition: flatdb.h:38
@ HashReadError
Definition: flatdb.h:34
@ FileError
Definition: flatdb.h:33
@ IncorrectMagicNumber
Definition: flatdb.h:37
@ IncorrectMagicMessage
Definition: flatdb.h:36
@ Ok
Definition: flatdb.h:32
@ IncorrectHash
Definition: flatdb.h:35
bool Dump(T &objToSave)
Definition: flatdb.h:172
fs::path GetDbPath() const
Definition: flatdb.h:151
fs::path pathDB
Definition: flatdb.h:27
bool Write(T &objToSave)
Definition: flatdb.h:41
bool Load(T &objToLoad)
Definition: flatdb.h:153
ReadResult Read(T &objToLoad)
Definition: flatdb.h:73
std::string strFilename
Definition: flatdb.h:28
CFlatDB(const std::string &strFilenameIn, const std::string &strMagicMessageIn)
Definition: flatdb.h:146
256-bit opaque blob.
Definition: uint256.h:138
uint256 Hash(const T1 pbegin, const T1 pend)
Compute the 256-bit hash of an object.
Definition: hash.h:173
#define T(expected, seed, data)
FILE * fopen(const fs::path &p, const char *mode)
Definition: fs.cpp:23
@ SER_DISK
Definition: serialize.h:175
const fs::path & GetDataDir(bool fNetSpecific)
Definition: system.cpp:724
bool error(const char *fmt, const Args &... args)
Definition: system.h:77
int64_t GetTimeMillis()
Returns the system time (not mockable)
Definition: utiltime.cpp:61