Raven Core  3.0.0
P2P Digital Currency
assetdb.cpp
Go to the documentation of this file.
1 // Copyright (c) 2017-2019 The Raven Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #include <util.h>
6 #include <consensus/params.h>
7 #include <script/ismine.h>
8 #include <tinyformat.h>
9 #include "assetdb.h"
10 #include "assets.h"
11 #include "validation.h"
12 
13 #include <boost/thread.hpp>
14 
15 static const char ASSET_FLAG = 'A';
16 static const char ASSET_ADDRESS_QUANTITY_FLAG = 'B';
17 static const char ADDRESS_ASSET_QUANTITY_FLAG = 'C';
18 static const char MY_ASSET_FLAG = 'M';
19 static const char BLOCK_ASSET_UNDO_DATA = 'U';
20 static const char MEMPOOL_REISSUED_TX = 'Z';
21 
22 static size_t MAX_DATABASE_RESULTS = 50000;
23 
24 CAssetsDB::CAssetsDB(size_t nCacheSize, bool fMemory, bool fWipe) : CDBWrapper(GetDataDir() / "assets", nCacheSize, fMemory, fWipe) {
25 }
26 
27 bool CAssetsDB::WriteAssetData(const CNewAsset &asset, const int nHeight, const uint256& blockHash)
28 {
29  CDatabasedAssetData data(asset, nHeight, blockHash);
30  return Write(std::make_pair(ASSET_FLAG, asset.strName), data);
31 }
32 
33 bool CAssetsDB::WriteAssetAddressQuantity(const std::string &assetName, const std::string &address, const CAmount &quantity)
34 {
35  return Write(std::make_pair(ASSET_ADDRESS_QUANTITY_FLAG, std::make_pair(assetName, address)), quantity);
36 }
37 
38 bool CAssetsDB::WriteAddressAssetQuantity(const std::string &address, const std::string &assetName, const CAmount& quantity) {
39  return Write(std::make_pair(ADDRESS_ASSET_QUANTITY_FLAG, std::make_pair(address, assetName)), quantity);
40 }
41 
42 bool CAssetsDB::ReadAssetData(const std::string& strName, CNewAsset& asset, int& nHeight, uint256& blockHash)
43 {
44 
46  bool ret = Read(std::make_pair(ASSET_FLAG, strName), data);
47 
48  if (ret) {
49  asset = data.asset;
50  nHeight = data.nHeight;
51  blockHash = data.blockHash;
52  }
53 
54  return ret;
55 }
56 
57 bool CAssetsDB::ReadAssetAddressQuantity(const std::string& assetName, const std::string& address, CAmount& quantity)
58 {
59  return Read(std::make_pair(ASSET_ADDRESS_QUANTITY_FLAG, std::make_pair(assetName, address)), quantity);
60 }
61 
62 bool CAssetsDB::ReadAddressAssetQuantity(const std::string &address, const std::string &assetName, CAmount& quantity) {
63  return Read(std::make_pair(ADDRESS_ASSET_QUANTITY_FLAG, std::make_pair(address, assetName)), quantity);
64 }
65 
66 bool CAssetsDB::EraseAssetData(const std::string& assetName)
67 {
68  return Erase(std::make_pair(ASSET_FLAG, assetName));
69 }
70 
71 bool CAssetsDB::EraseMyAssetData(const std::string& assetName)
72 {
73  return Erase(std::make_pair(MY_ASSET_FLAG, assetName));
74 }
75 
76 bool CAssetsDB::EraseAssetAddressQuantity(const std::string &assetName, const std::string &address) {
77  return Erase(std::make_pair(ASSET_ADDRESS_QUANTITY_FLAG, std::make_pair(assetName, address)));
78 }
79 
80 bool CAssetsDB::EraseAddressAssetQuantity(const std::string &address, const std::string &assetName) {
81  return Erase(std::make_pair(ADDRESS_ASSET_QUANTITY_FLAG, std::make_pair(address, assetName)));
82 }
83 
84 bool EraseAddressAssetQuantity(const std::string &address, const std::string &assetName);
85 
86 bool CAssetsDB::WriteBlockUndoAssetData(const uint256& blockhash, const std::vector<std::pair<std::string, CBlockAssetUndo> >& assetUndoData)
87 {
88  return Write(std::make_pair(BLOCK_ASSET_UNDO_DATA, blockhash), assetUndoData);
89 }
90 
91 bool CAssetsDB::ReadBlockUndoAssetData(const uint256 &blockhash, std::vector<std::pair<std::string, CBlockAssetUndo> > &assetUndoData)
92 {
93  // If it exists, return the read value.
94  if (Exists(std::make_pair(BLOCK_ASSET_UNDO_DATA, blockhash)))
95  return Read(std::make_pair(BLOCK_ASSET_UNDO_DATA, blockhash), assetUndoData);
96 
97  // If it doesn't exist, we just return true because we don't want to fail just because it didn't exist in the db
98  return true;
99 }
100 
102 {
103  return Write(MEMPOOL_REISSUED_TX, mapReissuedAssets);
104 }
105 
107 {
108  mapReissuedAssets.clear();
109  mapReissuedTx.clear();
110  // If it exists, return the read value.
111  bool rv = Read(MEMPOOL_REISSUED_TX, mapReissuedAssets);
112  if (rv) {
113  for (auto pair : mapReissuedAssets)
114  mapReissuedTx.insert(std::make_pair(pair.second, pair.first));
115  }
116  return rv;
117 }
118 
120 {
121  std::unique_ptr<CDBIterator> pcursor(NewIterator());
122 
123  pcursor->Seek(std::make_pair(ASSET_FLAG, std::string()));
124 
125  // Load assets
126  while (pcursor->Valid()) {
127  boost::this_thread::interruption_point();
128  std::pair<char, std::string> key;
129  if (pcursor->GetKey(key) && key.first == ASSET_FLAG) {
130  CDatabasedAssetData data;
131  if (pcursor->GetValue(data)) {
132  passetsCache->Put(data.asset.strName, data);
133  pcursor->Next();
134 
135  // Loaded enough from database to have in memory.
136  // No need to load everything if it is just going to be removed from the cache
137  if (passetsCache->Size() == (passetsCache->MaxSize() / 2))
138  break;
139  } else {
140  return error("%s: failed to read asset", __func__);
141  }
142  } else {
143  break;
144  }
145  }
146 
147 
148  if (fAssetIndex) {
149  std::unique_ptr<CDBIterator> pcursor3(NewIterator());
150  pcursor3->Seek(std::make_pair(ASSET_ADDRESS_QUANTITY_FLAG, std::make_pair(std::string(), std::string())));
151 
152  // Load mapAssetAddressAmount
153  while (pcursor3->Valid()) {
154  boost::this_thread::interruption_point();
155  std::pair<char, std::pair<std::string, std::string> > key; // <Asset Name, Address> -> Quantity
156  if (pcursor3->GetKey(key) && key.first == ASSET_ADDRESS_QUANTITY_FLAG) {
157  CAmount value;
158  if (pcursor3->GetValue(value)) {
160  std::make_pair(std::make_pair(key.second.first, key.second.second), value));
162  break;
163  pcursor3->Next();
164  } else {
165  return error("%s: failed to read my address quantity from database", __func__);
166  }
167  } else {
168  break;
169  }
170  }
171  }
172 
173  return true;
174 }
175 
176 bool CAssetsDB::AssetDir(std::vector<CDatabasedAssetData>& assets, const std::string filter, const size_t count, const long start)
177 {
179 
180  std::unique_ptr<CDBIterator> pcursor(NewIterator());
181  pcursor->Seek(std::make_pair(ASSET_FLAG, std::string()));
182 
183  auto prefix = filter;
184  bool wildcard = prefix.back() == '*';
185  if (wildcard)
186  prefix.pop_back();
187 
188  size_t skip = 0;
189  if (start >= 0) {
190  skip = start;
191  }
192  else {
193  // compute table size for backwards offset
194  long table_size = 0;
195  while (pcursor->Valid()) {
196  boost::this_thread::interruption_point();
197 
198  std::pair<char, std::string> key;
199  if (pcursor->GetKey(key) && key.first == ASSET_FLAG) {
200  if (prefix == "" ||
201  (wildcard && key.second.find(prefix) == 0) ||
202  (!wildcard && key.second == prefix)) {
203  table_size += 1;
204  }
205  }
206  pcursor->Next();
207  }
208  skip = table_size + start;
209  pcursor->SeekToFirst();
210  }
211 
212 
213  size_t loaded = 0;
214  size_t offset = 0;
215 
216  // Load assets
217  while (pcursor->Valid() && loaded < count) {
218  boost::this_thread::interruption_point();
219 
220  std::pair<char, std::string> key;
221  if (pcursor->GetKey(key) && key.first == ASSET_FLAG) {
222  if (prefix == "" ||
223  (wildcard && key.second.find(prefix) == 0) ||
224  (!wildcard && key.second == prefix)) {
225  if (offset < skip) {
226  offset += 1;
227  }
228  else {
229  CDatabasedAssetData data;
230  if (pcursor->GetValue(data)) {
231  assets.push_back(data);
232  loaded += 1;
233  } else {
234  return error("%s: failed to read asset", __func__);
235  }
236  }
237  }
238  pcursor->Next();
239  } else {
240  break;
241  }
242  }
243 
244  return true;
245 }
246 
247 bool CAssetsDB::AddressDir(std::vector<std::pair<std::string, CAmount> >& vecAssetAmount, int& totalEntries, const bool& fGetTotal, const std::string& address, const size_t count, const long start)
248 {
250 
251  std::unique_ptr<CDBIterator> pcursor(NewIterator());
252  pcursor->Seek(std::make_pair(ADDRESS_ASSET_QUANTITY_FLAG, std::make_pair(address, std::string())));
253 
254  if (fGetTotal) {
255  totalEntries = 0;
256  while (pcursor->Valid()) {
257  boost::this_thread::interruption_point();
258 
259  std::pair<char, std::pair<std::string, std::string> > key;
260  if (pcursor->GetKey(key) && key.first == ADDRESS_ASSET_QUANTITY_FLAG && key.second.first == address) {
261  totalEntries++;
262  }
263  pcursor->Next();
264  }
265  return true;
266  }
267 
268  size_t skip = 0;
269  if (start >= 0) {
270  skip = start;
271  }
272  else {
273  // compute table size for backwards offset
274  long table_size = 0;
275  while (pcursor->Valid()) {
276  boost::this_thread::interruption_point();
277 
278  std::pair<char, std::pair<std::string, std::string> > key;
279  if (pcursor->GetKey(key) && key.first == ADDRESS_ASSET_QUANTITY_FLAG && key.second.first == address) {
280  table_size += 1;
281  }
282  pcursor->Next();
283  }
284  skip = table_size + start;
285  pcursor->SeekToFirst();
286  }
287 
288 
289  size_t loaded = 0;
290  size_t offset = 0;
291 
292  // Load assets
293  while (pcursor->Valid() && loaded < count && loaded < MAX_DATABASE_RESULTS) {
294  boost::this_thread::interruption_point();
295 
296  std::pair<char, std::pair<std::string, std::string> > key;
297  if (pcursor->GetKey(key) && key.first == ADDRESS_ASSET_QUANTITY_FLAG && key.second.first == address) {
298  if (offset < skip) {
299  offset += 1;
300  }
301  else {
302  CAmount amount;
303  if (pcursor->GetValue(amount)) {
304  vecAssetAmount.emplace_back(std::make_pair(key.second.second, amount));
305  loaded += 1;
306  } else {
307  return error("%s: failed to Address Asset Quanity", __func__);
308  }
309  }
310  pcursor->Next();
311  } else {
312  break;
313  }
314  }
315 
316  return true;
317 }
318 
319 // Can get to total count of addresses that belong to a certain asset_name, or get you the list of all address that belong to a certain asset_name
320 bool CAssetsDB::AssetAddressDir(std::vector<std::pair<std::string, CAmount> >& vecAddressAmount, int& totalEntries, const bool& fGetTotal, const std::string& assetName, const size_t count, const long start)
321 {
323 
324  std::unique_ptr<CDBIterator> pcursor(NewIterator());
325  pcursor->Seek(std::make_pair(ASSET_ADDRESS_QUANTITY_FLAG, std::make_pair(assetName, std::string())));
326 
327  if (fGetTotal) {
328  totalEntries = 0;
329  while (pcursor->Valid()) {
330  boost::this_thread::interruption_point();
331 
332  std::pair<char, std::pair<std::string, std::string> > key;
333  if (pcursor->GetKey(key) && key.first == ASSET_ADDRESS_QUANTITY_FLAG && key.second.first == assetName) {
334  totalEntries += 1;
335  }
336  pcursor->Next();
337  }
338  return true;
339  }
340 
341  size_t skip = 0;
342  if (start >= 0) {
343  skip = start;
344  }
345  else {
346  // compute table size for backwards offset
347  long table_size = 0;
348  while (pcursor->Valid()) {
349  boost::this_thread::interruption_point();
350 
351  std::pair<char, std::pair<std::string, std::string> > key;
352  if (pcursor->GetKey(key) && key.first == ASSET_ADDRESS_QUANTITY_FLAG && key.second.first == assetName) {
353  table_size += 1;
354  }
355  pcursor->Next();
356  }
357  skip = table_size + start;
358  pcursor->SeekToFirst();
359  }
360 
361  size_t loaded = 0;
362  size_t offset = 0;
363 
364  // Load assets
365  while (pcursor->Valid() && loaded < count && loaded < MAX_DATABASE_RESULTS) {
366  boost::this_thread::interruption_point();
367 
368  std::pair<char, std::pair<std::string, std::string> > key;
369  if (pcursor->GetKey(key) && key.first == ASSET_ADDRESS_QUANTITY_FLAG && key.second.first == assetName) {
370  if (offset < skip) {
371  offset += 1;
372  }
373  else {
374  CAmount amount;
375  if (pcursor->GetValue(amount)) {
376  vecAddressAmount.emplace_back(std::make_pair(key.second.second, amount));
377  loaded += 1;
378  } else {
379  return error("%s: failed to Asset Address Quanity", __func__);
380  }
381  }
382  pcursor->Next();
383  } else {
384  break;
385  }
386  }
387 
388  return true;
389 }
390 
391 bool CAssetsDB::AssetDir(std::vector<CDatabasedAssetData>& assets)
392 {
393  return CAssetsDB::AssetDir(assets, "*", MAX_SIZE, 0);
394 }
bool Exists(const K &key) const
Definition: dbwrapper.h:260
bool WriteAssetAddressQuantity(const std::string &assetName, const std::string &address, const CAmount &quantity)
Definition: assetdb.cpp:33
bool WriteReissuedMempoolState()
Definition: assetdb.cpp:101
bool WriteBlockUndoAssetData(const uint256 &blockhash, const std::vector< std::pair< std::string, CBlockAssetUndo > > &assetUndoData)
Definition: assetdb.cpp:86
bool ReadBlockUndoAssetData(const uint256 &blockhash, std::vector< std::pair< std::string, CBlockAssetUndo > > &assetUndoData)
Definition: assetdb.cpp:91
const char * prefix
Definition: rest.cpp:568
bool EraseMyAssetData(const std::string &assetName)
Definition: assetdb.cpp:71
bool ReadAssetAddressQuantity(const std::string &assetName, const std::string &address, CAmount &quantity)
Definition: assetdb.cpp:57
std::string strName
Definition: assettypes.h:100
bool ReadAddressAssetQuantity(const std::string &address, const std::string &assetName, CAmount &quantity)
Definition: assetdb.cpp:62
bool fAssetIndex
Definition: validation.cpp:84
CDBIterator * NewIterator()
Definition: dbwrapper.h:300
bool EraseAddressAssetQuantity(const std::string &address, const std::string &assetName)
Definition: assetdb.cpp:80
bool LoadAssets()
Definition: assetdb.cpp:119
int64_t CAmount
Amount in corbies (Can be negative)
Definition: amount.h:13
bool AssetDir(std::vector< CDatabasedAssetData > &assets, const std::string filter, const size_t count, const long start)
Definition: assetdb.cpp:176
bool WriteAddressAssetQuantity(const std::string &address, const std::string &assetName, const CAmount &quantity)
Definition: assetdb.cpp:38
bool Erase(const K &key, bool fSync=false)
Definition: dbwrapper.h:279
bool EraseAssetAddressQuantity(const std::string &assetName, const std::string &address)
Definition: assetdb.cpp:76
std::map< std::string, uint256 > mapReissuedAssets
Definition: assets.cpp:41
bool ReadAssetData(const std::string &strName, CNewAsset &asset, int &nHeight, uint256 &blockHash)
Definition: assetdb.cpp:42
bool Read(const K &key, V &value) const
Definition: dbwrapper.h:226
bool EraseAssetData(const std::string &assetName)
Definition: assetdb.cpp:66
void FlushStateToDisk()
Flush all state, indexes and buffers to disk.
std::map< std::pair< std::string, std::string >, CAmount > mapAssetsAddressAmount
Definition: assets.h:74
bool WriteAssetData(const CNewAsset &asset, const int nHeight, const uint256 &blockHash)
Definition: assetdb.cpp:27
#define MAX_CACHE_ASSETS_SIZE
Definition: assets.h:65
256-bit opaque blob.
Definition: uint256.h:123
CAssetsCache * passets
Global variable that point to the active assets (protected by cs_main)
Definition: validation.cpp:227
bool Write(const K &key, const V &value, bool fSync=false)
Definition: dbwrapper.h:252
std::map< uint256, std::string > mapReissuedTx
Definition: assets.cpp:40
bool ReadReissuedMempoolState()
Definition: assetdb.cpp:106
bool AddressDir(std::vector< std::pair< std::string, CAmount > > &vecAssetAmount, int &totalEntries, const bool &fGetTotal, const std::string &address, const size_t count, const long start)
Definition: assetdb.cpp:247
bool error(const char *fmt, const Args &... args)
Definition: util.h:168
const fs::path & GetDataDir(bool fNetSpecific)
Definition: util.cpp:572
CLRUCache< std::string, CDatabasedAssetData > * passetsCache
Global variable that point to the assets metadata LRU Cache (protected by cs_main) ...
Definition: validation.cpp:228
bool AssetAddressDir(std::vector< std::pair< std::string, CAmount > > &vecAddressAmount, int &totalEntries, const bool &fGetTotal, const std::string &assetName, const size_t count, const long start)
Definition: assetdb.cpp:320
CAssetsDB(size_t nCacheSize, bool fMemory=false, bool fWipe=false)
Definition: assetdb.cpp:24