Master Core  v0.0.9 - 2abfd2849db8ba7a83957c64eb976b406713c123
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
mastercore_sp.cpp
Go to the documentation of this file.
1 // Smart Properties & Crowd Sales
2 
3 #include "base58.h"
4 #include "rpcserver.h"
5 #include "init.h"
6 #include "util.h"
7 #include "wallet.h"
8 
9 #include <stdint.h>
10 #include <string.h>
11 
12 #include <fstream>
13 #include <algorithm>
14 
15 #include <vector>
16 
17 #include <utility>
18 #include <string>
19 
20 #include <boost/assign/list_of.hpp>
21 #include <boost/algorithm/string.hpp>
22 #include <boost/algorithm/string/find.hpp>
23 #include <boost/lexical_cast.hpp>
24 #include <boost/format.hpp>
25 #include <boost/filesystem.hpp>
26 
27 #include "json/json_spirit_utils.h"
28 #include "json/json_spirit_value.h"
29 
30 #include "leveldb/db.h"
31 #include "leveldb/write_batch.h"
32 
33 using namespace std;
34 using namespace boost;
35 using namespace boost::assign;
36 using namespace json_spirit;
37 using namespace leveldb;
38 
39 #include "mastercore.h"
40 
41 using namespace mastercore;
42 
43 #include "mastercore_sp.h"
44 
45 unsigned int CMPSPInfo::updateSP(unsigned int propertyID, Entry const &info)
46 {
47  // cannot update implied SP
48  if (OMNI_PROPERTY_MSC == propertyID || OMNI_PROPERTY_TMSC == propertyID) {
49  return propertyID;
50  }
51 
52  std::string nextIdStr;
53  unsigned int res = propertyID;
54 
55  Object spInfo = info.toJSON();
56 
57  // generate the SP id
58  string spKey = (boost::format(FORMAT_BOOST_SPKEY) % propertyID).str();
59  string spValue = write_string(Value(spInfo), false);
60  string spPrevKey = (boost::format("blk-%s:sp-%d") % info.update_block.ToString() % propertyID).str();
61  string spPrevValue;
62 
63  leveldb::WriteBatch commitBatch;
64 
65  leveldb::ReadOptions readOpts;
66  readOpts.fill_cache = false;
67  leveldb::WriteOptions writeOptions;
68  writeOptions.sync = true;
69 
70  // if a value exists move it to the old key
71  if (false == pDb->Get(readOpts, spKey, &spPrevValue).IsNotFound()) {
72  commitBatch.Put(spPrevKey, spPrevValue);
73  }
74  commitBatch.Put(spKey, spValue);
75  pDb->Write(writeOptions, &commitBatch);
76 
77  file_log("Updated LevelDB with SP data successfully\n");
78  return res;
79 }
80 
81 unsigned int CMPSPInfo::putSP(unsigned char ecosystem, Entry const &info)
82 {
83  std::string nextIdStr;
84  unsigned int res = 0;
85  switch(ecosystem) {
86  case OMNI_PROPERTY_MSC: // mastercoin ecosystem, MSC: 1, TMSC: 2, First available SP = 3
87  res = next_spid++;
88  break;
89  case OMNI_PROPERTY_TMSC: // Test MSC ecosystem, same as above with high bit set
90  res = next_test_spid++;
91  break;
92  default: // non standard ecosystem, ID's start at 0
93  res = 0;
94  }
95 
96  Object spInfo = info.toJSON();
97 
98  // generate the SP id
99  string spKey = (boost::format(FORMAT_BOOST_SPKEY) % res).str();
100  string spValue = write_string(Value(spInfo), false);
101  string txIndexKey = (boost::format(FORMAT_BOOST_TXINDEXKEY) % info.txid.ToString() ).str();
102  string txValue = (boost::format("%d") % res).str();
103 
104  // sanity checking
105  string existingEntry;
106  leveldb::ReadOptions readOpts;
107  readOpts.fill_cache = true;
108  if (false == pDb->Get(readOpts, spKey, &existingEntry).IsNotFound() && false == boost::equals(spValue, existingEntry)) {
109  file_log("%s WRITING SP %d TO LEVELDB WHEN A DIFFERENT SP ALREADY EXISTS FOR THAT ID!!!\n", __FUNCTION__, res);
110  } else if (false == pDb->Get(readOpts, txIndexKey, &existingEntry).IsNotFound() && false == boost::equals(txValue, existingEntry)) {
111  file_log("%s WRITING INDEX TXID %s : SP %d IS OVERWRITING A DIFFERENT VALUE!!!\n", __FUNCTION__, info.txid.ToString().c_str(), res);
112  }
113 
114  // atomically write both the the SP and the index to the database
115  leveldb::WriteOptions writeOptions;
116  writeOptions.sync = true;
117 
118  leveldb::WriteBatch commitBatch;
119  commitBatch.Put(spKey, spValue);
120  commitBatch.Put(txIndexKey, txValue);
121 
122  pDb->Write(writeOptions, &commitBatch);
123  return res;
124 }
125 
126 
127 bool CMPSPInfo::getSP(unsigned int spid, Entry &info)
128 {
129  // special cases for constant SPs MSC and TMSC
130  if (OMNI_PROPERTY_MSC == spid) {
131  info = implied_msc;
132  return true;
133  } else if (OMNI_PROPERTY_TMSC == spid) {
134  info = implied_tmsc;
135  return true;
136  }
137 
138  leveldb::ReadOptions readOpts;
139  readOpts.fill_cache = true;
140 
141  string spKey = (boost::format(FORMAT_BOOST_SPKEY) % spid).str();
142  string spInfoStr;
143  if (false == pDb->Get(readOpts, spKey, &spInfoStr).ok()) {
144  return false;
145  }
146 
147  // parse the encoded json, failing if it doesnt parse or is an object
148  Value spInfoVal;
149  if (false == read_string(spInfoStr, spInfoVal) || spInfoVal.type() != obj_type ) {
150  return false;
151  }
152 
153  // transfer to the Entry structure
154  Object &spInfo = spInfoVal.get_obj();
155  info.fromJSON(spInfo);
156  return true;
157 }
158 
159 bool CMPSPInfo::hasSP(unsigned int spid)
160 {
161  // special cases for constant SPs MSC and TMSC
162  if (OMNI_PROPERTY_MSC == spid || OMNI_PROPERTY_TMSC == spid) {
163  return true;
164  }
165 
166  leveldb::ReadOptions readOpts;
167  readOpts.fill_cache = true;
168 
169  string spKey = (boost::format(FORMAT_BOOST_SPKEY) % spid).str();
170  leveldb::Iterator *iter = pDb->NewIterator(readOpts);
171  iter->Seek(spKey);
172  bool res = (iter->Valid() && iter->key().compare(spKey) == 0);
173  // clean up the iterator
174  delete iter;
175 
176  return res;
177 }
178 
179 unsigned int CMPSPInfo::findSPByTX(uint256 const &txid)
180 {
181  unsigned int res = 0;
182  leveldb::ReadOptions readOpts;
183  readOpts.fill_cache = true;
184 
185  string txIndexKey = (boost::format(FORMAT_BOOST_TXINDEXKEY) % txid.ToString() ).str();
186  string spidStr;
187  if (pDb->Get(readOpts, txIndexKey, &spidStr).ok()) {
188  res = boost::lexical_cast<unsigned int>(spidStr);
189  }
190 
191  return res;
192 }
193 
194 int CMPSPInfo::popBlock(uint256 const &block_hash)
195 {
196  int res = 0;
197  int remainingSPs = 0;
198  leveldb::WriteBatch commitBatch;
199 
200  leveldb::ReadOptions readOpts;
201  readOpts.fill_cache = false;
202  leveldb::Iterator *iter = pDb->NewIterator(readOpts);
203  for (iter->Seek("sp-"); iter->Valid() && iter->key().starts_with("sp-"); iter->Next()) {
204  // parse the encoded json, failing if it doesnt parse or is an object
205  Value spInfoVal;
206  if (read_string(iter->value().ToString(), spInfoVal) && spInfoVal.type() == obj_type ) {
207  Entry info;
208  info.fromJSON(spInfoVal.get_obj());
209  if (info.update_block == block_hash) {
210  // need to roll this SP back
211  if (info.update_block == info.creation_block) {
212  // this is the block that created this SP, so delete the SP and the tx index entry
213  string txIndexKey = (boost::format(FORMAT_BOOST_TXINDEXKEY) % info.txid.ToString() ).str();
214  commitBatch.Delete(iter->key());
215  commitBatch.Delete(txIndexKey);
216  } else {
217  std::vector<std::string> vstr;
218  std::string key = iter->key().ToString();
219  boost::split(vstr, key, boost::is_any_of("-"), token_compress_on);
220  unsigned int propertyID = boost::lexical_cast<unsigned int>(vstr[1]);
221 
222  string spPrevKey = (boost::format("blk-%s:sp-%d") % info.update_block.ToString() % propertyID).str();
223  string spPrevValue;
224 
225  if (false == pDb->Get(readOpts, spPrevKey, &spPrevValue).IsNotFound()) {
226  // copy the prev state to the current state and delete the old state
227  commitBatch.Put(iter->key(), spPrevValue);
228  commitBatch.Delete(spPrevKey);
229  remainingSPs++;
230  } else {
231  // failed to find a previous SP entry, trigger reparse
232  res = -1;
233  }
234  }
235  } else {
236  remainingSPs++;
237  }
238  } else {
239  // failed to parse the db json, trigger reparse
240  res = -1;
241  }
242  }
243 
244  // clean up the iterator
245  delete iter;
246 
247  leveldb::WriteOptions writeOptions;
248  writeOptions.sync = true;
249 
250  pDb->Write(writeOptions, &commitBatch);
251 
252  if (res < 0) {
253  return res;
254  } else {
255  return remainingSPs;
256  }
257 }
258 
259 CMPCrowd *mastercore::getCrowd(const string & address)
260 {
261 CrowdMap::iterator my_it = my_crowds.find(address);
262 
263  if (my_it != my_crowds.end()) return &(my_it->second);
264 
265  return (CMPCrowd *) NULL;
266 }
267 
268 bool mastercore::isPropertyDivisible(unsigned int propertyId)
269 {
270 // TODO: is a lock here needed
272 
273  if (_my_sps->getSP(propertyId, sp)) return sp.isDivisible();
274 
275  return true;
276 }
277 
278 string mastercore::getPropertyName(unsigned int propertyId)
279 {
280  CMPSPInfo::Entry sp;
281  if (_my_sps->getSP(propertyId, sp)) return sp.name;
282  return "Property Name Not Found";
283 }
284 
285 bool mastercore::isCrowdsaleActive(unsigned int propertyId)
286 {
287  for(CrowdMap::const_iterator it = my_crowds.begin(); it != my_crowds.end(); ++it)
288  {
289  CMPCrowd crowd = it->second;
290  unsigned int foundPropertyId = crowd.getPropertyId();
291  if (foundPropertyId == propertyId) return true;
292  }
293  return false;
294 }
295 
296 // save info from the crowdsale that's being erased
297 void mastercore::dumpCrowdsaleInfo(const string &address, CMPCrowd &crowd, bool bExpired)
298 {
299  boost::filesystem::path pathInfo = GetDataDir() / INFO_FILENAME;
300  FILE *fp = fopen(pathInfo.string().c_str(), "a");
301 
302  if (!fp)
303  {
304  file_log("\nPROBLEM writing %s, errno= %d\n", INFO_FILENAME, errno);
305  return;
306  }
307 
308  fprintf(fp, "\n%s\n", DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime()).c_str());
309  fprintf(fp, "\nCrowdsale ended: %s\n", bExpired ? "Expired" : "Was closed");
310 
311  crowd.print(address, fp);
312 
313  fflush(fp);
314  fclose(fp);
315 }
316 
317 // calculates and returns fundraiser bonus, issuer premine, and total tokens
318 // propType : divisible/indiv
319 // bonusPerc: bonus percentage
320 // currentSecs: number of seconds of current tx
321 // numProps: number of properties
322 // issuerPerc: percentage of tokens to issuer
323 int mastercore::calculateFractional(unsigned short int propType, unsigned char bonusPerc, uint64_t fundraiserSecs,
324  uint64_t numProps, unsigned char issuerPerc, const std::map<std::string, std::vector<uint64_t> > txFundraiserData,
325  const uint64_t amountPremined )
326 {
327 
328  //initialize variables
329  double totalCreated = 0;
330  double issuerPercentage = (double) (issuerPerc * 0.01);
331 
332  std::map<std::string, std::vector<uint64_t> >::const_iterator it;
333 
334  //iterate through fundraiser data
335  for(it = txFundraiserData.begin(); it != txFundraiserData.end(); it++) {
336 
337  // grab the seconds and amt transferred from this tx
338  uint64_t currentSecs = it->second.at(1);
339  double amtTransfer = it->second.at(0);
340 
341  //make calc for bonus given in sec
342  uint64_t bonusSeconds = fundraiserSecs - currentSecs;
343 
344  //turn it into weeks
345  double weeks = bonusSeconds / (double) 604800;
346 
347  //make it a %
348  double ebPercentage = weeks * bonusPerc;
349  double bonusPercentage = ( ebPercentage / 100 ) + 1;
350 
351  //init var
352  double createdTokens;
353 
354  //if indiv or div, do different truncation
355  if( MSC_PROPERTY_TYPE_DIVISIBLE == propType ) {
356  //calculate tokens
357  createdTokens = (amtTransfer/1e8) * (double) numProps * bonusPercentage ;
358 
359  //printf("prop 2: is %Lf, and %Lf \n", createdTokens, issuerTokens);
360 
361  //add totals up
362  totalCreated += createdTokens;
363  } else {
364  //printf("amount xfer %Lf and props %f and bonus percs %Lf \n", amtTransfer, (double) numProps, bonusPercentage);
365 
366  //same here
367  createdTokens = (uint64_t) ( (amtTransfer/1e8) * (double) numProps * bonusPercentage);
368 
369  totalCreated += createdTokens;
370  }
371  };
372 
373  // calculate premine
374  double totalPremined = totalCreated * issuerPercentage;
375  double missedTokens;
376 
377  // calculate based on div/indiv, truncation/not
378  if( 2 == propType ) {
379  missedTokens = totalPremined - amountPremined;
380  } else {
381  missedTokens = (uint64_t) (totalPremined - amountPremined);
382  }
383 
384  //return value
385  return missedTokens;
386 }
387 
388 
389 //go hunting for whether a simple send is a crowdsale purchase
390 //TODO !!!! horribly inefficient !!!! find a more efficient way to do this
391 bool mastercore::isCrowdsalePurchase(uint256 txid, string address, int64_t *propertyId, int64_t *userTokens, int64_t *issuerTokens)
392 {
393 //1. loop crowdsales (active/non-active) looking for issuer address
394 //2. loop those crowdsales for that address and check their participant txs in database
395 
396  //check for an active crowdsale to this address
397  CMPCrowd *crowd;
398  crowd = getCrowd(address);
399  if (crowd)
400  {
401  unsigned int foundPropertyId = crowd->getPropertyId();
402  std::map<std::string, std::vector<uint64_t> > database = crowd->getDatabase();
403  std::map<std::string, std::vector<uint64_t> >::const_iterator it;
404  for(it = database.begin(); it != database.end(); it++)
405  {
406  string tmpTxid = it->first; //uint256 txid = it->first;
407  string compTxid = txid.GetHex().c_str(); //convert to string to compare since this is how stored in levelDB
408  if (tmpTxid == compTxid)
409  {
410  int64_t tmpUserTokens = it->second.at(2);
411  int64_t tmpIssuerTokens = it->second.at(3);
412  *propertyId = foundPropertyId;
413  *userTokens = tmpUserTokens;
414  *issuerTokens = tmpIssuerTokens;
415  return true;
416  }
417  }
418  }
419 
420  //if we still haven't found txid, check non active crowdsales to this address
421  int64_t tmpPropertyId;
422  unsigned int nextSPID = _my_sps->peekNextSPID(1);
423  unsigned int nextTestSPID = _my_sps->peekNextSPID(2);
424 
425  for (tmpPropertyId = 1; tmpPropertyId<nextSPID; tmpPropertyId++)
426  {
427  CMPSPInfo::Entry sp;
428  if (false != _my_sps->getSP(tmpPropertyId, sp))
429  {
430  if (sp.issuer == address)
431  {
432  std::map<std::string, std::vector<uint64_t> > database = sp.historicalData;
433  std::map<std::string, std::vector<uint64_t> >::const_iterator it;
434  for(it = database.begin(); it != database.end(); it++)
435  {
436  string tmpTxid = it->first; //uint256 txid = it->first;
437  string compTxid = txid.GetHex().c_str(); //convert to string to compare since this is how stored in levelDB
438  if (tmpTxid == compTxid)
439  {
440  int64_t tmpUserTokens = it->second.at(2);
441  int64_t tmpIssuerTokens = it->second.at(3);
442  *propertyId = tmpPropertyId;
443  *userTokens = tmpUserTokens;
444  *issuerTokens = tmpIssuerTokens;
445  return true;
446  }
447  }
448  }
449  }
450  }
451  for (tmpPropertyId = TEST_ECO_PROPERTY_1; tmpPropertyId<nextTestSPID; tmpPropertyId++)
452  {
453  CMPSPInfo::Entry sp;
454  if (false != _my_sps->getSP(tmpPropertyId, sp))
455  {
456  if (sp.issuer == address)
457  {
458  std::map<std::string, std::vector<uint64_t> > database = sp.historicalData;
459  std::map<std::string, std::vector<uint64_t> >::const_iterator it;
460  for(it = database.begin(); it != database.end(); it++)
461  {
462  string tmpTxid = it->first; //uint256 txid = it->first;
463  string compTxid = txid.GetHex().c_str(); //convert to string to compare since this is how stored in levelDB
464  if (tmpTxid == compTxid)
465  {
466  int64_t tmpUserTokens = it->second.at(2);
467  int64_t tmpIssuerTokens = it->second.at(3);
468  *propertyId = tmpPropertyId;
469  *userTokens = tmpUserTokens;
470  *issuerTokens = tmpIssuerTokens;
471  return true;
472  }
473  }
474  }
475  }
476  }
477 
478  //didn't find anything, not a crowdsale purchase
479  return false;
480 }
481 
482 void mastercore::eraseMaxedCrowdsale(const string &address, uint64_t blockTime, int block)
483 {
484  CrowdMap::iterator it = my_crowds.find(address);
485 
486  if (it != my_crowds.end()) {
487 
488  CMPCrowd &crowd = it->second;
489  file_log("%s() FOUND MAXED OUT CROWDSALE from address= '%s', erasing...\n", __FUNCTION__, address.c_str());
490 
491  dumpCrowdsaleInfo(address, crowd);
492 
493  CMPSPInfo::Entry sp;
494 
495  //get sp from data struct
496  _my_sps->getSP(crowd.getPropertyId(), sp);
497 
498  //get txdata
499  sp.historicalData = crowd.getDatabase();
500  sp.close_early = 1;
501  sp.max_tokens = 1;
502  sp.timeclosed = blockTime;
503 
504  //update SP with this data
505  sp.update_block = chainActive[block]->GetBlockHash();
506  _my_sps->updateSP(crowd.getPropertyId() , sp);
507 
508  //No calculate fractional calls here, no more tokens (at MAX)
509 
510  my_crowds.erase(it);
511  }
512 }
513 
514 unsigned int mastercore::eraseExpiredCrowdsale(CBlockIndex const * pBlockIndex)
515 {
516 const int64_t blockTime = pBlockIndex->GetBlockTime();
517 unsigned int how_many_erased = 0;
518 CrowdMap::iterator my_it = my_crowds.begin();
519 
520  while (my_crowds.end() != my_it)
521  {
522  // my_it->first = key
523  // my_it->second = value
524 
525  CMPCrowd &crowd = my_it->second;
526 
527  if (blockTime > (int64_t)crowd.getDeadline())
528  {
529  file_log("%s() FOUND EXPIRED CROWDSALE from address= '%s', erasing...\n", __FUNCTION__, (my_it->first).c_str());
530 
531  // TODO: dump the info about this crowdsale being delete into a TXT file (JSON perhaps)
532  dumpCrowdsaleInfo(my_it->first, my_it->second, true);
533 
534  // Begin calculate Fractional
535  CMPSPInfo::Entry sp;
536 
537  //get sp from data struct
538  _my_sps->getSP(crowd.getPropertyId(), sp);
539 
540  //file_log("\nValues going into calculateFractional(): hexid %s earlyBird %d deadline %lu numProps %lu issuerPerc %d, issuerCreated %ld \n", sp.txid.GetHex().c_str(), sp.early_bird, sp.deadline, sp.num_tokens, sp.percentage, crowd.getIssuerCreated());
541 
542  //find missing tokens
543  double missedTokens = calculateFractional(sp.prop_type,
544  sp.early_bird,
545  sp.deadline,
546  sp.num_tokens,
547  sp.percentage,
548  crowd.getDatabase(),
549  crowd.getIssuerCreated());
550 
551 
552  //file_log("\nValues coming out of calculateFractional(): Total tokens, Tokens created, Tokens for issuer, amountMissed: issuer %s %lu %lu %lu %f\n",sp.issuer.c_str(), crowd.getUserCreated() + crowd.getIssuerCreated(), crowd.getUserCreated(), crowd.getIssuerCreated(), missedTokens);
553 
554  //get txdata
555  sp.historicalData = crowd.getDatabase();
556  sp.missedTokens = (int64_t) missedTokens;
557 
558  //update SP with this data
559  sp.update_block = pBlockIndex->GetBlockHash();
560  _my_sps->updateSP(crowd.getPropertyId() , sp);
561 
562  //update values
563  update_tally_map(sp.issuer, crowd.getPropertyId(), missedTokens, BALANCE);
564  //End
565 
566  my_crowds.erase(my_it++);
567 
568  ++how_many_erased;
569  }
570  else my_it++;
571 
572  }
573 
574  return how_many_erased;
575 }
576 
578 {
579  switch (i)
580  {
581  case MSC_PROPERTY_TYPE_DIVISIBLE: return (char *) "divisible";
582  case MSC_PROPERTY_TYPE_INDIVISIBLE: return (char *) "indivisible";
583  }
584 
585  return (char *) "*** property type error ***";
586 }
587 
588 
const boost::filesystem::path & GetDataDir(bool fNetSpecific)
Definition: util.cpp:973
int popBlock(uint256 const &block_hash)
bool close_early
Definition: mastercore_sp.h:28
uint256 update_block
Definition: mastercore_sp.h:37
CMPSPInfo * _my_sps
Definition: mastercore.cpp:362
uint256 txid
Definition: mastercore_sp.h:35
Definition: init.h:13
#define FORMAT_BOOST_TXINDEXKEY
Definition: mastercore.h:37
bool update_tally_map(string who, unsigned int which_currency, int64_t amount, TallyType ttype)
Definition: mastercore.cpp:687
#define MSC_PROPERTY_TYPE_INDIVISIBLE
Definition: mastercore.h:78
string issuer
Definition: mastercore_sp.h:11
STL namespace.
#define TEST_ECO_PROPERTY_1
Definition: mastercore.h:22
unsigned char early_bird
Definition: mastercore_sp.h:24
bool hasSP(unsigned int spid)
uint64_t num_tokens
Definition: mastercore_sp.h:19
std::map< std::string, std::vector< uint64_t > > getDatabase() const
void print(const string &address, FILE *fp=stdout) const
std::string DateTimeStrFormat(const char *pszFormat, int64_t nTime)
Definition: util.cpp:1429
unsigned short prop_type
Definition: mastercore_sp.h:12
#define OMNI_PROPERTY_MSC
Definition: mastercore.h:130
CChain chainActive
The currently-connected chain of blocks.
Definition: main.cpp:48
bool isPropertyDivisible(unsigned int propertyId)
std::map< std::string, std::vector< uint64_t > > historicalData
Definition: mastercore_sp.h:43
uint64_t timeclosed
Definition: mastercore_sp.h:31
Definition: mastercore_sp.h:9
int calculateFractional(unsigned short int propType, unsigned char bonusPerc, uint64_t fundraiserSecs, uint64_t numProps, unsigned char issuerPerc, const std::map< std::string, std::vector< uint64_t > > txFundraiserData, const uint64_t amountPremined)
#define OMNI_PROPERTY_TMSC
Definition: mastercore.h:131
bool isCrowdsalePurchase(uint256 txid, string address, int64_t *propertyId=NULL, int64_t *userTokens=NULL, int64_t *issuerTokens=NULL)
uint64_t getIssuerCreated() const
void dumpCrowdsaleInfo(const string &address, CMPCrowd &crowd, bool bExpired=false)
bool isCrowdsaleActive(unsigned int propertyId)
bool max_tokens
Definition: mastercore_sp.h:29
void fromJSON(Object const &json)
uint64_t missedTokens
Definition: mastercore_sp.h:30
bool getSP(unsigned int spid, Entry &info)
bool isDivisible() const
string name
Definition: mastercore_sp.h:16
#define MSC_PROPERTY_TYPE_DIVISIBLE
Definition: mastercore.h:79
std::string GetHex() const
Definition: uint256.h:297
int64_t GetTime()
Definition: util.cpp:1215
#define INFO_FILENAME
Definition: mastercore.h:17
void eraseMaxedCrowdsale(const string &address, uint64_t blockTime, int block)
CrowdMap my_crowds
Definition: mastercore.cpp:363
string getPropertyName(unsigned int propertyId)
256-bit unsigned integer
Definition: uint256.h:531
unsigned char percentage
Definition: mastercore_sp.h:25
unsigned int putSP(unsigned char ecosystem, Entry const &info)
char * c_strPropertyType(int i)
The block chain is a tree shaped structure starting with the genesis block at the root...
Definition: main.h:688
std::string ToString() const
Definition: uint256.h:340
unsigned int findSPByTX(uint256 const &txid)
unsigned int peekNextSPID(unsigned char ecosystem)
uint256 creation_block
Definition: mastercore_sp.h:36
CMPCrowd * getCrowd(const string &address)
unsigned int eraseExpiredCrowdsale(CBlockIndex const *pBlockIndex)
uint64_t deadline
Definition: mastercore_sp.h:23
int64_t GetBlockTime() const
Definition: main.h:810
uint64_t getDeadline() const
unsigned int updateSP(unsigned int propertyID, Entry const &info)
#define FORMAT_BOOST_SPKEY
Definition: mastercore.h:38
unsigned int getPropertyId() const
void format(FormatIterator &fmtIter)
Definition: tinyformat.h:869
Object toJSON() const
Definition: mastercore_sp.h:73
uint256 GetBlockHash() const
Definition: main.h:805