Master Core  v0.0.9 - 2abfd2849db8ba7a83957c64eb976b406713c123
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
mastercore.cpp
Go to the documentation of this file.
1 //
2 // first & so far only Master protocol source file
3 // WARNING: Work In Progress -- major refactoring will be occurring often
4 //
5 // I am adding comments to aid with navigation and overall understanding of the design.
6 // this is the 'core' portion of the node+wallet: mastercored
7 // see 'qt' subdirectory for UI files
8 //
9 // remaining work, search for: TODO, FIXME
10 //
11 
12 //
13 // global TODO: need locks on the maps in this file & balances (moneys[],reserved[] & raccept[]) !!!
14 //
15 
16 #include "base58.h"
17 #include "rpcserver.h"
18 #include "init.h"
19 #include "util.h"
20 #include "wallet.h"
21 // #include "walletdb.h"
22 #include "coincontrol.h"
23 
24 #include <stdint.h>
25 #include <string.h>
26 #include <set>
27 #include <map>
28 
29 #include <fstream>
30 #include <algorithm>
31 
32 #include <vector>
33 
34 #include <utility>
35 #include <string>
36 
37 #include <boost/assign/list_of.hpp>
38 #include <boost/algorithm/string.hpp>
39 #include <boost/algorithm/string/find.hpp>
40 #include <boost/algorithm/string/join.hpp>
41 #include <boost/lexical_cast.hpp>
42 #include <boost/format.hpp>
43 #include <boost/filesystem.hpp>
44 #include "json/json_spirit_utils.h"
45 #include "json/json_spirit_value.h"
46 
47 #include "leveldb/db.h"
48 #include "leveldb/write_batch.h"
49 
50 #include <openssl/sha.h>
51 
52 // #include "tinyformat.h"
53 
54 #include <boost/multiprecision/cpp_int.hpp>
55 
56 // comment out MY_HACK & others here - used for Unit Testing only !
57 // #define MY_HACK
58 
59 using boost::multiprecision::int128_t;
60 using boost::multiprecision::cpp_int;
61 using namespace std;
62 using namespace boost;
63 using namespace boost::assign;
64 using namespace json_spirit;
65 using namespace leveldb;
66 
67 static string exodus_address = "1EXoDusjGwvnjZUyKkxZ4UHEf77z6A5S4P";
68 static const string exodus_testnet = "mpexoDuSkGGqvqrkrjiFng38QPkJQVFyqv";
69 static const string getmoney_testnet = "moneyqMan7uh8FqdCA2BV5yZ8qVrc9ikLP";
70 
71 #include "mastercore.h"
72 
73 using namespace mastercore;
74 
75 #include "mastercore_convert.h"
76 #include "mastercore_dex.h"
77 #include "mastercore_tx.h"
78 #include "mastercore_sp.h"
79 #include "mastercore_errors.h"
80 #include "mastercore_version.h"
81 
82 // part of 'breakout' feature
83 static const int nBlockTop = 0;
84 // static const int nBlockTop = 271000;
85 
86 static int nWaterlineBlock = 0; //
87 
88 uint64_t global_MSC_total = 0;
94 
96 
97 static uint64_t exodus_prev = 0;
98 static uint64_t exodus_balance;
99 
100 static boost::filesystem::path MPPersistencePath;
101 
102 const int msc_debug_parser_data = 0;
103 const int msc_debug_parser= 0;
104 const int msc_debug_verbose=0;
105 const int msc_debug_verbose2=0;
106 const int msc_debug_verbose3=0;
107 const int msc_debug_vin = 0;
108 const int msc_debug_script= 0;
109 const int msc_debug_dex = 1;
110 const int msc_debug_send = 1;
111 const int msc_debug_tokens= 0;
112 const int msc_debug_spec = 1;
113 const int msc_debug_exo = 0;
114 const int msc_debug_tally = 1;
115 const int msc_debug_sp = 1;
116 const int msc_debug_sto = 1;
117 const int msc_debug_txdb = 0;
118 const int msc_debug_tradedb = 1;
119 const int msc_debug_persistence = 0;
120 // disable all flags for metadex for the immediate tag, then turn back on 0 & 2 at least
123 int msc_debug_metadex3= 0; // enable this to see the orderbook before & after each TX
124 
125 const static int disable_Divs = 0;
126 const static int disableLevelDB = 0;
127 
128 static int mastercoreInitialized = 0;
129 
130 static int reorgRecoveryMode = 0;
131 static int reorgRecoveryMaxHeight = 0;
132 
133 static bool bRawTX = false;
134 
135 // TODO: there would be a block height for each TX version -- rework together with BLOCKHEIGHTRESTRICTIONS above
136 static const int txRestrictionsRules[][3] = {
150 
151 // end of array marker, in addition to sizeof/sizeof
152  {-1,-1},
153 };
154 
158 
159 // a copy from main.cpp -- unfortunately that one is in a private namespace
161 {
162  if (0 < nBlockTop) return nBlockTop;
163 
164  LOCK(cs_main);
165  return chainActive.Height();
166 }
167 
169 {
170  LOCK(cs_main);
171  if (chainActive.Tip())
172  return (int)(chainActive.Tip()->GetBlockTime());
173  else
174  return (int)(Params().GenesisBlock().nTime); // Genesis block's time of current network
175 }
176 
177 //--- CUT HERE --- mostly copied from util.h & util.cpp
178 // LogPrintf() has been broken a couple of times now
179 // by well-meaning people adding mutexes in the most straightforward way.
180 // It breaks because it may be called by global destructors during shutdown.
181 // Since the order of destruction of static/global objects is undefined,
182 // defining a mutex as a global object doesn't work (the mutex gets
183 // destroyed, and then some later destructor calls OutputDebugStringF,
184 // maybe indirectly, and you get a core dump at shutdown trying to lock
185 // the mutex).
186 static boost::once_flag mp_debugPrintInitFlag = BOOST_ONCE_INIT;
187 // We use boost::call_once() to make sure these are initialized in
188 // in a thread-safe manner the first time it is called:
189 static FILE* fileout = NULL;
190 static boost::mutex* mutexDebugLog = NULL;
191 
192 static void mp_DebugPrintInit()
193 {
194  assert(fileout == NULL);
195  assert(mutexDebugLog == NULL);
196 
197  boost::filesystem::path pathDebug = GetDataDir() / LOG_FILENAME ;
198  fileout = fopen(pathDebug.string().c_str(), "a");
199  if (fileout) setbuf(fileout, NULL); // unbuffered
200 
201  mutexDebugLog = new boost::mutex();
202 }
203 
204 int mp_LogPrintStr(const std::string &str)
205 {
206  int ret = 0; // Returns total number of characters written
207  if (fPrintToConsole)
208  {
209  // print to console
210  ret = fwrite(str.data(), 1, str.size(), stdout);
211  }
212  else if (fPrintToDebugLog)
213  {
214  static bool fStartedNewLine = true;
215  boost::call_once(&mp_DebugPrintInit, mp_debugPrintInitFlag);
216 
217  if (fileout == NULL)
218  return ret;
219 
220  boost::mutex::scoped_lock scoped_lock(*mutexDebugLog);
221 
222  // reopen the log file, if requested
223  if (fReopenDebugLog) {
224  fReopenDebugLog = false;
225  boost::filesystem::path pathDebug = GetDataDir() / LOG_FILENAME ;
226  if (freopen(pathDebug.string().c_str(),"a",fileout) != NULL)
227  setbuf(fileout, NULL); // unbuffered
228  }
229 
230  // Debug print useful for profiling
231  if (fLogTimestamps && fStartedNewLine)
232  ret += fprintf(fileout, "%s ", DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime()).c_str());
233  if (!str.empty() && str[str.size()-1] == '\n')
234  fStartedNewLine = true;
235  else
236  fStartedNewLine = false;
237 
238  ret = fwrite(str.data(), 1, str.size(), fileout);
239  }
240 
241  return ret;
242 }
243 
244 // indicate whether persistence is enabled at this point, or not
245 // used to write/read files, for breakout mode, debugging, etc.
246 static bool readPersistence()
247 {
248 #ifdef MY_HACK
249  return false;
250 #else
251  return true;
252 #endif
253 }
254 
255 // indicate whether persistence is enabled at this point, or not
256 // used to write/read files, for breakout mode, debugging, etc.
257 static bool writePersistence(int block_now)
258 {
259  // if too far away from the top -- do not write
260  if (GetHeight() > (block_now + MAX_STATE_HISTORY)) return false;
261 
262  return true;
263 }
264 
265 // copied from ShrinkDebugFile, util.cpp
266 static void shrinkDebugFile()
267 {
268  // Scroll log if it's getting too big
269  const int buffer_size = 8000000; // 8MBytes
270  boost::filesystem::path pathLog = GetDataDir() / LOG_FILENAME;
271  FILE* file = fopen(pathLog.string().c_str(), "r");
272 
273  if (file && boost::filesystem::file_size(pathLog) > 50000000) // 50MBytes
274  {
275  // Restart the file with some of the end
276  char *pch = new char[buffer_size];
277  if (NULL != pch)
278  {
279  fseek(file, -buffer_size, SEEK_END);
280  int nBytes = fread(pch, 1, buffer_size, file);
281  fclose(file); file = NULL;
282 
283  file = fopen(pathLog.string().c_str(), "w");
284  if (file)
285  {
286  fwrite(pch, 1, nBytes, file);
287  fclose(file); file = NULL;
288  }
289  delete [] pch;
290  }
291  }
292  else
293  {
294  if (NULL != file) fclose(file);
295  }
296 }
297 
298 string mastercore::strMPProperty(unsigned int i)
299 {
300 string str = "*unknown*";
301 
302  // test user-token
303  if (0x80000000 & i)
304  {
305  str = strprintf("Test token: %d : 0x%08X", 0x7FFFFFFF & i, i);
306  }
307  else
308  switch (i)
309  {
310  case OMNI_PROPERTY_BTC: str = "BTC"; break;
311  case OMNI_PROPERTY_MSC: str = "MSC"; break;
312  case OMNI_PROPERTY_TMSC: str = "TMSC"; break;
313  default: str = strprintf("SP token: %d", i);
314  }
315 
316  return str;
317 }
318 
320 {
321  return (TestNet() || RegTest());
322 }
323 
324 // mostly taken from Bitcoin's FormatMoney()
325 string FormatDivisibleMP(int64_t n, bool fSign)
326 {
327 // Note: not using straight sprintf here because we do NOT want
328 // localized number formatting.
329 int64_t n_abs = (n > 0 ? n : -n);
330 int64_t quotient = n_abs/COIN;
331 int64_t remainder = n_abs%COIN;
332 string str = strprintf("%d.%08d", quotient, remainder);
333 
334  if (!fSign) return str;
335 
336  if (n < 0)
337  str.insert((unsigned int)0, 1, '-');
338  else
339  str.insert((unsigned int)0, 1, '+');
340  return str;
341 }
342 
343 std::string mastercore::FormatIndivisibleMP(int64_t n)
344 {
345  string str = strprintf("%ld", n);
346  return str;
347 }
348 
349 std::string FormatMP(unsigned int property, int64_t n, bool fSign)
350 {
351  if (isPropertyDivisible(property)) return FormatDivisibleMP(n, fSign);
352  else return FormatIndivisibleMP(n);
353 }
354 
355 string const CMPSPInfo::watermarkKey("watermark");
356 
358 
361 
364 
366 
367 static CMPPending *pendingDelete(const uint256 txid, bool bErase = false)
368 {
369  if (msc_debug_verbose3) file_log("%s(%s)\n", __FUNCTION__, txid.GetHex().c_str());
370 
371  PendingMap::iterator it = my_pending.find(txid);
372 
373  if (it != my_pending.end())
374  {
375  // display
376  CMPPending *p_pending = &(it->second);
377 
378  p_pending->print(txid);
379 
380  int64_t src_amount = getMPbalance(p_pending->src, p_pending->prop, PENDING);
381 
382  if (msc_debug_verbose3) file_log("%s()src= %ld, line %d, file: %s\n", __FUNCTION__, src_amount, __LINE__, __FILE__);
383 
384  if (src_amount)
385  {
386  update_tally_map(p_pending->src, p_pending->prop, p_pending->amount, PENDING);
387  }
388 
389  if (bErase)
390  {
391  my_pending.erase(it);
392  }
393  else
394  {
395  return &(it->second);
396  }
397  }
398 
399  return (CMPPending *) NULL;
400 }
401 
402 static int pendingAdd(const uint256 &txid, const string &FromAddress, unsigned int propId, int64_t Amount)
403 {
404 CMPPending pending;
405 
406  if (msc_debug_verbose3) file_log("%s(%s,%s,%u,%ld), line %d, file: %s\n", __FUNCTION__, txid.GetHex().c_str(), FromAddress.c_str(), propId, Amount, __LINE__, __FILE__);
407 
408  // support for pending, 0-confirm
409  if (update_tally_map(FromAddress, propId, -Amount, PENDING))
410  {
411  pending.src = FromAddress;
412  pending.amount = Amount;
413  pending.prop = propId;
414 
415  pending.print(txid);
416  my_pending.insert(std::make_pair(txid, pending));
417  }
418 
419  return 0;
420 }
421 
422 // this is the master list of all amounts for all addresses for all properties, map is sorted by Bitcoin address
423 std::map<string, CMPTally> mastercore::mp_tally_map;
424 
425 CMPTally *mastercore::getTally(const string & address)
426 {
427  LOCK (cs_tally);
428 
429  map<string, CMPTally>::iterator it = mp_tally_map.find(address);
430 
431  if (it != mp_tally_map.end()) return &(it->second);
432 
433  return (CMPTally *) NULL;
434 }
435 
436 // look at balance for an address
437 int64_t getMPbalance(const string &Address, unsigned int property, TallyType ttype)
438 {
439 uint64_t balance = 0;
440 
441  if (TALLY_TYPE_COUNT <= ttype) return 0;
442 
443  LOCK(cs_tally);
444 
445 const map<string, CMPTally>::iterator my_it = mp_tally_map.find(Address);
446 
447  if (my_it != mp_tally_map.end())
448  {
449  balance = (my_it->second).getMoney(property, ttype);
450  }
451 
452  return balance;
453 }
454 
455 int64_t getUserAvailableMPbalance(const string &Address, unsigned int property)
456 {
457 int64_t money = getMPbalance(Address, property, BALANCE);
458 int64_t pending = getMPbalance(Address, property, PENDING);
459 
460  if (0 > pending)
461  {
462  return (money + pending); // show the decrease in money available
463  }
464 
465  return money;
466 }
467 
468 static bool isRangeOK(const uint64_t input)
469 {
470  if (MAX_INT_8_BYTES < input) return false;
471 
472  return true;
473 }
474 
475 // returns false if we are out of range and/or overflow
476 // call just before multiplying large numbers
477 bool isMultiplicationOK(const uint64_t a, const uint64_t b)
478 {
479 // printf("%s(%lu, %lu): ", __FUNCTION__, a, b);
480 
481  if (!a || !b) return true;
482 
483  if (MAX_INT_8_BYTES < a) return false;
484  if (MAX_INT_8_BYTES < b) return false;
485 
486  const uint64_t result = a*b;
487 
488  if (MAX_INT_8_BYTES < result) return false;
489 
490  if ((0 != a) && (result / a != b)) return false;
491 
492  return true;
493 }
494 
495 bool mastercore::isTestEcosystemProperty(unsigned int property)
496 {
497  if ((OMNI_PROPERTY_TMSC == property) || (TEST_ECO_PROPERTY_1 <= property)) return true;
498 
499  return false;
500 }
501 
502 bool mastercore::isMainEcosystemProperty(unsigned int property)
503 {
504  if ((OMNI_PROPERTY_BTC != property) && !isTestEcosystemProperty(property)) return true;
505 
506  return false;
507 }
508 
509 bool mastercore::isMetaDExOfferActive(const uint256 txid, unsigned int propertyId)
510 {
511  for (md_PropertiesMap::iterator my_it = metadex.begin(); my_it != metadex.end(); ++my_it)
512  {
513  if (my_it->first == propertyId) //at bear minimum only go deeper if it's the right property id
514  {
515  md_PricesMap & prices = my_it->second;
516  for (md_PricesMap::iterator it = prices.begin(); it != prices.end(); ++it)
517  {
518  md_Set & indexes = (it->second);
519  for (md_Set::iterator it = indexes.begin(); it != indexes.end(); ++it)
520  {
521  CMPMetaDEx obj = *it;
522  if( obj.getHash().GetHex() == txid.GetHex() ) return true;
523  }
524  }
525  }
526  }
527  return false;
528 }
529 
531 {
532  return global_alert_message;
533 }
534 
535 bool mastercore::checkExpiredAlerts(unsigned int curBlock, uint64_t curTime)
536 {
537  //expire any alerts that need expiring
538  int32_t alertType;
539  uint64_t expiryValue;
540  uint32_t typeCheck;
541  uint32_t verCheck;
542  std::vector<std::string> vstr;
543 
544  //split the global message string if it's not empty
545  if(!global_alert_message.empty())
546  {
547  boost::split(vstr, global_alert_message, boost::is_any_of(":"), token_compress_on);
548  // make sure there are 5 tokens and they convert ok
549  if (5 == vstr.size())
550  {
551  try
552  {
553  alertType = boost::lexical_cast<int32_t>(vstr[0]);
554  expiryValue = boost::lexical_cast<uint64_t>(vstr[1]);
555  typeCheck = boost::lexical_cast<uint32_t>(vstr[2]);
556  verCheck = boost::lexical_cast<uint32_t>(vstr[3]);
557  } catch (const boost::bad_lexical_cast &e)
558  {
559  file_log("DEBUG ALERT - error in converting values from global alert string\n");
560  return false; //(something went wrong)
561  }
562  }
563  else
564  {
565  file_log("DEBUG ALERT ERROR - Something went wrong decoding the global alert string, there are not 5 tokens\n");
566  return false;
567  }
568  if ((alertType < 1) || (alertType > 4) || (expiryValue == 0))
569  {
570  file_log("DEBUG ALERT ERROR - Something went wrong decoding the global alert string, values are not as expected.\n");
571  return false;
572  }
573  switch (alertType)
574  {
575  case 1: //Text based alert only expiring by block number, show alert in UI and getalert_MP call, ignores type check value (eg use 0)
576  if (curBlock > expiryValue)
577  {
578  //the alert has expired, clear the global alert string
579  file_log("DEBUG ALERT - Expiring alert string %s\n",global_alert_message.c_str());
581  return true;
582  }
583  break;
584  case 2: //Text based alert only expiring by block time, show alert in UI and getalert_MP call, ignores type check value (eg use 0)
585  if (curTime > expiryValue)
586  {
587  //the alert has expired, clear the global alert string
588  file_log("DEBUG ALERT - Expiring alert string %s\n",global_alert_message.c_str());
590  return true;
591  }
592  break;
593  case 3: //Text based alert only expiring by client version, show alert in UI and getalert_MP call, ignores type check value (eg use 0)
594  if (OMNICORE_VERSION_BASE > expiryValue)
595  {
596  //the alert has expired, clear the global alert string
597  file_log("DEBUG ALERT - Expiring alert string %s\n",global_alert_message.c_str());
599  return true;
600  }
601  break;
602  case 4: //Update alert, show upgrade alert in UI and getalert_MP call + use isTransactionTypeAllowed to verify client support and shutdown if not present
603  //check of the new tx type is supported at live block
604  bool txSupported = isTransactionTypeAllowed(expiryValue+1, OMNI_PROPERTY_MSC, typeCheck, verCheck);
605 
606  //check if we are at/past the live blockheight
607  bool txLive = (chainActive.Height()>(int64_t)expiryValue);
608 
609  //testnet allows all types of transactions, so override this here for testing
610  //txSupported = false; //testing
611  //txLive = true; //testing
612 
613  if ((!txSupported) && (txLive))
614  {
615  // we know we have transactions live we don't understand
616  // can't be trusted to provide valid data, shutdown
617  file_log("DEBUG ALERT - Shutting down due to unsupported live TX - alert string %s\n",global_alert_message.c_str());
618  printf("DEBUG ALERT - Shutting down due to unsupported live TX - alert string %s\n",global_alert_message.c_str()); //echo to screen
619  if (!GetBoolArg("-overrideforcedshutdown", false)) StartShutdown();
620  return false;
621  }
622 
623  if ((!txSupported) && (!txLive))
624  {
625  // warn the user this version does not support the new coming TX and they will need to update
626  // we don't actually need to take any action here, we leave the alert string in place and simply don't expire it
627  }
628 
629  if (txSupported)
630  {
631  // we can simply expire this update as this version supports the new coming TX
632  file_log("DEBUG ALERT - Expiring alert string %s\n",global_alert_message.c_str());
634  return true;
635  }
636  break;
637  }
638  return false;
639  }
640  else { return false; }
641  return false;
642 }
643 
644 // get total tokens for a property
645 // optionally counts the number of addresses who own that property: n_owners_total
646 int64_t mastercore::getTotalTokens(unsigned int propertyId, int64_t *n_owners_total)
647 {
648 int64_t prev = 0, owners = 0;
649 
650  LOCK(cs_tally);
651 
652  CMPSPInfo::Entry property;
653  if (false == _my_sps->getSP(propertyId, property)) return 0; // property ID does not exist
654 
655  int64_t totalTokens = 0;
656  bool fixedIssuance = property.fixed;
657 
658  if (!fixedIssuance || n_owners_total)
659  {
660  for(map<string, CMPTally>::iterator my_it = mp_tally_map.begin(); my_it != mp_tally_map.end(); ++my_it)
661  {
662  string address = (my_it->first).c_str();
663  totalTokens += getMPbalance(address, propertyId, BALANCE);
664  totalTokens += getMPbalance(address, propertyId, SELLOFFER_RESERVE);
665  totalTokens += getMPbalance(address, propertyId, METADEX_RESERVE);
666  if (propertyId<3) totalTokens += getMPbalance(address, propertyId, ACCEPT_RESERVE);
667 
668  if (prev != totalTokens)
669  {
670  prev = totalTokens;
671  owners++;
672  }
673  }
674  }
675 
676  if (fixedIssuance)
677  {
678  totalTokens = property.num_tokens; //only valid for TX50
679  }
680 
681  if (n_owners_total) *n_owners_total = owners;
682 
683  return totalTokens;
684 }
685 
686 // return true if everything is ok
687 bool mastercore::update_tally_map(string who, unsigned int which_property, int64_t amount, TallyType ttype)
688 {
689 bool bRet = false;
690 uint64_t before, after;
691 
692  if (0 == amount)
693  {
694  file_log("%s(%s, %u=0x%X, %+ld, ttype= %d) 0 FUNDS !\n", __FUNCTION__, who.c_str(), which_property, which_property, amount, ttype);
695  return false;
696  }
697 
698  LOCK(cs_tally);
699 
700  before = getMPbalance(who, which_property, ttype);
701 
702  map<string, CMPTally>::iterator my_it = mp_tally_map.find(who);
703  if (my_it == mp_tally_map.end())
704  {
705  // insert an empty element
706  my_it = (mp_tally_map.insert(std::make_pair(who,CMPTally()))).first;
707  }
708 
709  CMPTally &tally = my_it->second;
710 
711  bRet = tally.updateMoney(which_property, amount, ttype);
712 
713  after = getMPbalance(who, which_property, ttype);
714  if (!bRet) file_log("%s(%s, %u=0x%X, %+ld, ttype=%d) INSUFFICIENT FUNDS\n", __FUNCTION__, who.c_str(), which_property, which_property, amount, ttype);
715 
716  if (msc_debug_tally)
717  {
718  if ((exodus_address != who) || (exodus_address == who && msc_debug_exo))
719  {
720  file_log("%s(%s, %u=0x%X, %+ld, ttype=%d); before=%lu, after=%lu\n",
721  __FUNCTION__, who.c_str(), which_property, which_property, amount, ttype, before, after);
722  }
723  }
724 
725  return bRet;
726 }
727 
728 std::string p128(int128_t quantity)
729 {
730  //printf("\nTest # was %s\n", boost::lexical_cast<std::string>(quantity).c_str() );
731  return boost::lexical_cast<std::string>(quantity);
732 }
733 std::string p_arb(cpp_int quantity)
734 {
735  //printf("\nTest # was %s\n", boost::lexical_cast<std::string>(quantity).c_str() );
736  return boost::lexical_cast<std::string>(quantity);
737 }
738 //calculateFundraiser does token calculations per transaction
739 //calcluateFractional does calculations for missed tokens
740 void calculateFundraiser(unsigned short int propType, uint64_t amtTransfer, unsigned char bonusPerc,
741  uint64_t fundraiserSecs, uint64_t currentSecs, uint64_t numProps, unsigned char issuerPerc, uint64_t totalTokens,
742  std::pair<uint64_t, uint64_t>& tokens, bool &close_crowdsale )
743 {
744  //uint64_t weeks_sec = 604800;
745  int128_t weeks_sec_ = 604800L;
746  //define weeks in seconds
747  int128_t precision_ = 1000000000000L;
748  //define precision for all non-bitcoin values (bonus percentages, for example)
749  int128_t percentage_precision = 100L;
750  //define precision for all percentages (10/100 = 10%)
751 
752  //uint64_t bonusSeconds = fundraiserSecs - currentSecs;
753  //calcluate the bonusseconds
754  //printf("\n bonus sec %lu\n", bonusSeconds);
755  int128_t bonusSeconds_ = fundraiserSecs - currentSecs;
756 
757  //double weeks_d = bonusSeconds / (double) weeks_sec;
758  //debugging
759 
760  int128_t weeks_ = (bonusSeconds_ / weeks_sec_) * precision_ + ( (bonusSeconds_ % weeks_sec_ ) * precision_) / weeks_sec_;
761  //calculate the whole number of weeks to apply bonus
762 
763  //printf("\n weeks_d: %.8lf \n weeks: %s + (%s / %s) =~ %.8lf \n", weeks_d, p128(bonusSeconds_ / weeks_sec_).c_str(), p128(bonusSeconds_ % weeks_sec_).c_str(), p128(weeks_sec_).c_str(), boost::lexical_cast<double>(bonusSeconds_ / weeks_sec_) + boost::lexical_cast<double> (bonusSeconds_ % weeks_sec_) / boost::lexical_cast<double>(weeks_sec_) );
764  //debugging lines
765 
766  //double ebPercentage_d = weeks_d * bonusPerc;
767  //debugging lines
768 
769  int128_t ebPercentage_ = weeks_ * bonusPerc;
770  //calculate the earlybird percentage to be applied
771 
772  //printf("\n ebPercentage_d: %.8lf \n ebPercentage: %s + (%s / %s ) =~ %.8lf \n", ebPercentage_d, p128(ebPercentage_ / precision_).c_str(), p128( (ebPercentage_) % precision_).c_str() , p128(precision_).c_str(), boost::lexical_cast<double>(ebPercentage_ / precision_) + boost::lexical_cast<double>(ebPercentage_ % precision_) / boost::lexical_cast<double>(precision_));
773  //debugging
774 
775  //double bonusPercentage_d = ( ebPercentage_d / 100 ) + 1;
776  //debugging
777 
778  int128_t bonusPercentage_ = (ebPercentage_ + (precision_ * percentage_precision) ) / percentage_precision;
779  //calcluate the bonus percentage to apply up to 'percentage_precision' number of digits
780 
781  //printf("\n bonusPercentage_d: %.18lf \n bonusPercentage: %s + (%s / %s) =~ %.11lf \n", bonusPercentage_d, p128(bonusPercentage_ / precision_).c_str(), p128(bonusPercentage_ % precision_).c_str(), p128(precision_).c_str(), boost::lexical_cast<double>(bonusPercentage_ / precision_) + boost::lexical_cast<double>(bonusPercentage_ % precision_) / boost::lexical_cast<double>(precision_));
782  //debugging
783 
784  //double issuerPercentage_d = (double) (issuerPerc * 0.01);
785  //debugging
786 
787  int128_t issuerPercentage_ = (int128_t)issuerPerc * precision_ / percentage_precision;
788 
789  //printf("\n issuerPercentage_d: %.8lf \n issuerPercentage: %s + (%s / %s) =~ %.8lf \n", issuerPercentage_d, p128(issuerPercentage_ / precision_ ).c_str(), p128(issuerPercentage_ % precision_).c_str(), p128( precision_ ).c_str(), boost::lexical_cast<double>(issuerPercentage_ / precision_) + boost::lexical_cast<double>(issuerPercentage_ % precision_) / boost::lexical_cast<double>(precision_));
790  //debugging
791 
792  int128_t satoshi_precision_ = 100000000;
793  //define the precision for bitcoin amounts (satoshi)
794  //uint64_t createdTokens, createdTokens_decimal;
795  //declare used variables for total created tokens
796 
797  //uint64_t issuerTokens, issuerTokens_decimal;
798  //declare used variables for total issuer tokens
799 
800  //printf("\n NUMBER OF PROPERTIES %ld", numProps);
801  //printf("\n AMOUNT INVESTED: %ld BONUS PERCENTAGE: %.11f and %s", amtTransfer,bonusPercentage_d, p128(bonusPercentage_).c_str());
802 
803  //long double ct = ((amtTransfer/1e8) * (long double) numProps * bonusPercentage_d);
804 
805  //int128_t createdTokens_ = (int128_t)amtTransfer*(int128_t)numProps* bonusPercentage_;
806 
807  cpp_int createdTokens = boost::lexical_cast<cpp_int>((int128_t)amtTransfer*(int128_t)numProps)* boost::lexical_cast<cpp_int>(bonusPercentage_);
808 
809  //printf("\n CREATED TOKENS UINT %s \n", p_arb(createdTokens).c_str());
810 
811  //printf("\n CREATED TOKENS %.8Lf, %s + (%s / %s) ~= %.8lf",ct, p128(createdTokens_ / (precision_ * satoshi_precision_) ).c_str(), p128(createdTokens_ % (precision_ * satoshi_precision_) ).c_str() , p128( precision_*satoshi_precision_ ).c_str(), boost::lexical_cast<double>(createdTokens_ / (precision_ * satoshi_precision_) ) + boost::lexical_cast<double>(createdTokens_ % (precision_ * satoshi_precision_)) / boost::lexical_cast<double>(precision_*satoshi_precision_));
812 
813  //long double it = (uint64_t) ct * issuerPercentage_d;
814 
815  //int128_t issuerTokens_ = (createdTokens_ / (satoshi_precision_ * precision_ )) * (issuerPercentage_ / 100) * precision_;
816 
817  cpp_int issuerTokens = (createdTokens / (satoshi_precision_ * precision_ )) * (issuerPercentage_ / 100) * precision_;
818 
819  //printf("\n ISSUER TOKENS: %.8Lf, %s + (%s / %s ) ~= %.8lf \n",it, p128(issuerTokens_ / (precision_ * satoshi_precision_ * 100 ) ).c_str(), p128( issuerTokens_ % (precision_ * satoshi_precision_ * 100 ) ).c_str(), p128(precision_*satoshi_precision_*100).c_str(), boost::lexical_cast<double>(issuerTokens_ / (precision_ * satoshi_precision_ * 100)) + boost::lexical_cast<double>(issuerTokens_ % (satoshi_precision_*precision_*100) )/ boost::lexical_cast<double>(satoshi_precision_*precision_*100));
820 
821  //printf("\n UINT %s \n", p_arb(issuerTokens).c_str());
822  //total tokens including remainders
823 
824  //printf("\n DIVISIBLE TOKENS (UI LAYER) CREATED: is ~= %.8lf, and %.8lf\n",(double)createdTokens + (double)createdTokens_decimal/(satoshi_precision *precision), (double) issuerTokens + (double)issuerTokens_decimal/(satoshi_precision*precision*percentage_precision) );
825  //if (2 == propType)
826  //printf("\n DIVISIBLE TOKENS (UI LAYER) CREATED: is ~= %.8lf, and %.8lf\n", (uint64_t) (boost::lexical_cast<double>(createdTokens_ / (precision_ * satoshi_precision_) ) + boost::lexical_cast<double>(createdTokens_ % (precision_ * satoshi_precision_)) / boost::lexical_cast<double>(precision_*satoshi_precision_) )/1e8, (uint64_t) (boost::lexical_cast<double>(issuerTokens_ / (precision_ * satoshi_precision_ * 100)) + boost::lexical_cast<double>(issuerTokens_ % (satoshi_precision_*precision_*100) )/ boost::lexical_cast<double>(satoshi_precision_*precision_*100)) / 1e8 );
827  //else
828  //printf("\n INDIVISIBLE TOKENS (UI LAYER) CREATED: is = %lu, and %lu\n", boost::lexical_cast<uint64_t>(createdTokens_ / (precision_ * satoshi_precision_ ) ), boost::lexical_cast<uint64_t>(issuerTokens_ / (precision_ * satoshi_precision_ * 100)));
829 
830  cpp_int createdTokens_int = createdTokens / (precision_ * satoshi_precision_);
831  cpp_int issuerTokens_int = issuerTokens / (precision_ * satoshi_precision_ * 100 );
832  cpp_int newTotalCreated = totalTokens + createdTokens_int + issuerTokens_int;
833 
834  if ( newTotalCreated > MAX_INT_8_BYTES) {
835  cpp_int maxCreatable = MAX_INT_8_BYTES - totalTokens;
836 
837  cpp_int created = createdTokens_int + issuerTokens_int;
838  cpp_int ratio = (created * precision_ * satoshi_precision_) / maxCreatable;
839 
840  //printf("\n created %s, ratio %s, maxCreatable %s, totalTokens %s, createdTokens_int %s, issuerTokens_int %s \n", p_arb(created).c_str(), p_arb(ratio).c_str(), p_arb(maxCreatable).c_str(), p_arb(totalTokens).c_str(), p_arb(createdTokens_int).c_str(), p_arb(issuerTokens_int).c_str() );
841  //debugging
842 
843  issuerTokens_int = (issuerTokens_int * precision_ * satoshi_precision_)/ratio;
844  //calcluate the ratio of tokens for what we can create and apply it
845  createdTokens_int = MAX_INT_8_BYTES - issuerTokens_int ;
846  //give the rest to the user
847 
848  //printf("\n created %s, ratio %s, maxCreatable %s, totalTokens %s, createdTokens_int %s, issuerTokens_int %s \n", p_arb(created).c_str(), p_arb(ratio).c_str(), p_arb(maxCreatable).c_str(), p_arb(totalTokens).c_str(), p_arb(createdTokens_int).c_str(), p_arb(issuerTokens_int).c_str() );
849  //debugging
850  close_crowdsale = true; //close up the crowdsale after assigning all tokens
851  }
852  tokens = std::make_pair(boost::lexical_cast<uint64_t>(createdTokens_int) , boost::lexical_cast<uint64_t>(issuerTokens_int));
853  //give tokens
854 }
855 
856 // certain transaction types are not live on the network until some specific block height
857 // certain transactions will be unknown to the client, i.e. "black holes" based on their version
858 // the Restrictions array is as such: type, block-allowed-in, top-version-allowed
859 bool mastercore::isTransactionTypeAllowed(int txBlock, unsigned int txProperty, unsigned int txType, unsigned short version, bool bAllowNullProperty)
860 {
861 bool bAllowed = false;
862 bool bBlackHole = false;
863 unsigned int type;
864 int block_FirstAllowed;
865 unsigned short version_TopAllowed;
866 
867  // bitcoin as property is never allowed, unless explicitly stated otherwise
868  if ((OMNI_PROPERTY_BTC == txProperty) && !bAllowNullProperty) return false;
869 
870  // everything is always allowed on Bitcoin's TestNet or with TMSC/TestEcosystem on MainNet
871  if ((isNonMainNet()) || isTestEcosystemProperty(txProperty))
872  {
873  bAllowed = true;
874  }
875 
876  for (unsigned int i = 0; i < sizeof(txRestrictionsRules)/sizeof(txRestrictionsRules[0]); i++)
877  {
878  type = txRestrictionsRules[i][0];
879  block_FirstAllowed = txRestrictionsRules[i][1];
880  version_TopAllowed = txRestrictionsRules[i][2];
881 
882  if (txType != type) continue;
883 
884  if (version_TopAllowed < version)
885  {
886  file_log("Black Hole identified !!! %d, %u, %u, %u\n", txBlock, txProperty, txType, version);
887 
888  bBlackHole = true;
889 
890  // TODO: what else?
891  // ...
892  }
893 
894  if (0 > block_FirstAllowed) break; // array contains a negative -- nothing's allowed or done parsing
895 
896  if (block_FirstAllowed <= txBlock) bAllowed = true;
897  }
898 
899  return bAllowed && !bBlackHole;
900 }
901 
903 //
904 // some old TODOs
905 // 6) verify large-number calculations (especially divisions & multiplications)
906 // 9) build in consesus checks with the masterchain.info & masterchest.info -- possibly run them automatically, daily (?)
907 // 10) need a locking mechanism between Core & Qt -- to retrieve the tally, for instance, this and similar to this: LOCK(wallet->cs_wallet);
908 //
909 
910 uint64_t calculate_and_update_devmsc(unsigned int nTime)
911 {
912 //do nothing if before end of fundraiser
913 if (nTime < 1377993874) return -9919;
914 
915 // taken mainly from msc_validate.py: def get_available_reward(height, c)
916 uint64_t devmsc = 0;
917 int64_t exodus_delta;
918 // spec constants:
919 const uint64_t all_reward = 5631623576222;
920 const double seconds_in_one_year = 31556926;
921 const double seconds_passed = nTime - 1377993874; // exodus bootstrap deadline
922 const double years = seconds_passed/seconds_in_one_year;
923 const double part_available = 1 - pow(0.5, years);
924 const double available_reward=all_reward * part_available;
925 
926  devmsc = rounduint64(available_reward);
927  exodus_delta = devmsc - exodus_prev;
928 
929  if (msc_debug_exo) file_log("devmsc=%lu, exodus_prev=%lu, exodus_delta=%ld\n", devmsc, exodus_prev, exodus_delta);
930 
931  // skip if a block's timestamp is older than that of a previous one!
932  if (0>exodus_delta) return 0;
933 
935  exodus_prev = devmsc;
936 
937  return devmsc;
938 }
939 
940 // TODO: optimize efficiency -- iterate only over wallet's addresses in the future
941 // NOTE: if we loop over wallet addresses we miss tokens that may be in change addresses (since mapAddressBook does not
942 // include change addresses). with current transaction load, about 0.02 - 0.06 seconds is spent on this function
944 {
945  //concerned about efficiency here, time how long this takes, averaging 0.02-0.04s on my system
946  //timer t;
947  int my_addresses_count = 0;
948  int64_t propertyId;
949  unsigned int nextSPID = _my_sps->peekNextSPID(1); // real eco
950  unsigned int nextTestSPID = _my_sps->peekNextSPID(2); // test eco
951 
952  //zero bals
953  for (propertyId = 1; propertyId<nextSPID; propertyId++) //main eco
954  {
955  global_balance_money_maineco[propertyId] = 0;
956  global_balance_reserved_maineco[propertyId] = 0;
957  }
958  for (propertyId = TEST_ECO_PROPERTY_1; propertyId<nextTestSPID; propertyId++) //test eco
959  {
960  global_balance_money_testeco[propertyId-2147483647] = 0;
961  global_balance_reserved_testeco[propertyId-2147483647] = 0;
962  }
963 
964  for(map<string, CMPTally>::iterator my_it = mp_tally_map.begin(); my_it != mp_tally_map.end(); ++my_it)
965  {
966  if (IsMyAddress(my_it->first))
967  {
968  for (propertyId = 1; propertyId<nextSPID; propertyId++) //main eco
969  {
970  //global_balance_money_maineco[propertyId] += getMPbalance(my_it->first, propertyId, BALANCE);
971  global_balance_money_maineco[propertyId] += getUserAvailableMPbalance(my_it->first, propertyId);
972  global_balance_reserved_maineco[propertyId] += getMPbalance(my_it->first, propertyId, SELLOFFER_RESERVE);
973  global_balance_reserved_maineco[propertyId] += getMPbalance(my_it->first, propertyId, METADEX_RESERVE);
974  if (propertyId < 3) global_balance_reserved_maineco[propertyId] += getMPbalance(my_it->first, propertyId, ACCEPT_RESERVE);
975  }
976  for (propertyId = TEST_ECO_PROPERTY_1; propertyId<nextTestSPID; propertyId++) //test eco
977  {
978  //global_balance_money_testeco[propertyId-2147483647] += getMPbalance(my_it->first, propertyId, BALANCE);
979  global_balance_money_testeco[propertyId-2147483647] += getUserAvailableMPbalance(my_it->first, propertyId);
980  global_balance_reserved_testeco[propertyId-2147483647] += getMPbalance(my_it->first, propertyId, SELLOFFER_RESERVE);
981  global_balance_reserved_testeco[propertyId-2147483647] += getMPbalance(my_it->first, propertyId, METADEX_RESERVE);
982  }
983  }
984  }
985  //printf("Global MSC totals: MSC_total= %lu, MSC_RESERVED_total= %lu\n", global_balance_money_maineco[1], global_balance_reserved_maineco[1]);
986  //std::cout << t.elapsed() << std::endl;
987  return (my_addresses_count);
988 }
989 
990 static void prepareObfuscatedHashes(const string &address, string (&ObfsHashes)[1+MAX_SHA256_OBFUSCATION_TIMES])
991 {
992 unsigned char sha_input[128];
993 unsigned char sha_result[128];
994 vector<unsigned char> vec_chars;
995 
996  strcpy((char *)sha_input, address.c_str());
997  // do only as many re-hashes as there are mastercoin packets, 255 per spec
998  for (unsigned int j = 1; j<=MAX_SHA256_OBFUSCATION_TIMES;j++)
999  {
1000  SHA256(sha_input, strlen((const char *)sha_input), sha_result);
1001 
1002  vec_chars.resize(32);
1003  memcpy(&vec_chars[0], &sha_result[0], 32);
1004  ObfsHashes[j] = HexStr(vec_chars);
1005  boost::to_upper(ObfsHashes[j]); // uppercase per spec
1006 
1007  if (msc_debug_verbose2) if (5>j) file_log("%d: sha256 hex: %s\n", j, ObfsHashes[j].c_str());
1008  strcpy((char *)sha_input, ObfsHashes[j].c_str());
1009  }
1010 }
1011 
1012 static bool getOutputType(const CScript& scriptPubKey, txnouttype& whichTypeRet)
1013 {
1014 vector<vector<unsigned char> > vSolutions;
1015 
1016  if (!Solver(scriptPubKey, whichTypeRet, vSolutions)) return false;
1017 
1018  return true;
1019 }
1020 
1021 
1022 int TXExodusFundraiser(const CTransaction &wtx, const string &sender, int64_t ExodusHighestValue, int nBlock, unsigned int nTime)
1023 {
1024  if ((nBlock >= GENESIS_BLOCK && nBlock <= LAST_EXODUS_BLOCK) || (isNonMainNet()))
1025  { //Exodus Fundraiser start/end blocks
1026  //printf("transaction: %s\n", wtx.ToString().c_str() );
1027  int deadline_timeleft=1377993600-nTime;
1028  double bonus= 1 + std::max( 0.10 * deadline_timeleft / (60 * 60 * 24 * 7), 0.0 );
1029 
1030  if (isNonMainNet())
1031  {
1032  bonus = 1;
1033 
1034  if (sender == exodus_address) return 1; // sending from Exodus should not be fundraising anything
1035  }
1036 
1037  uint64_t msc_tot= round( 100 * ExodusHighestValue * bonus );
1038  if (msc_debug_exo) file_log("Exodus Fundraiser tx detected, tx %s generated %lu.%08lu\n",wtx.GetHash().ToString().c_str(), msc_tot / COIN, msc_tot % COIN);
1039 
1040  update_tally_map(sender, OMNI_PROPERTY_MSC, msc_tot, BALANCE);
1041  update_tally_map(sender, OMNI_PROPERTY_TMSC, msc_tot, BALANCE);
1042 
1043  return 0;
1044  }
1045  return -1;
1046 }
1047 
1048 static bool isAllowedOutputType(int whichType, int nBlock)
1049 {
1050  int p2shAllowed = 0;
1051 
1052  if (P2SH_BLOCK <= nBlock || isNonMainNet()) {
1053  p2shAllowed = 1;
1054  }
1055  // validTypes:
1056  // 1) Pay to pubkey hash
1057  // 2) Pay to Script Hash (IFF p2sh is allowed)
1058  if ((TX_PUBKEYHASH == whichType) || (p2shAllowed && (TX_SCRIPTHASH == whichType))) {
1059  return true;
1060  } else {
1061  return false;
1062  }
1063 }
1064 
1065 // idx is position within the block, 0-based
1066 // int msc_tx_push(const CTransaction &wtx, int nBlock, unsigned int idx)
1067 // INPUT: bRPConly -- set to true to avoid moving funds; to be called from various RPC calls like this
1068 // RETURNS: 0 if parsed a MP TX
1069 // RETURNS: < 0 if a non-MP-TX or invalid
1070 // RETURNS: >0 if 1 or more payments have been made
1071 int parseTransaction(bool bRPConly, const CTransaction &wtx, int nBlock, unsigned int idx, CMPTransaction *mp_tx, unsigned int nTime)
1072 {
1073 string strSender;
1074 // class A: data & address storage -- combine them into a structure or something
1075 vector<string>script_data;
1076 vector<string>address_data;
1077 // vector<uint64_t>value_data;
1078 vector<int64_t>value_data;
1079 int64_t ExodusValues[MAX_BTC_OUTPUTS]= { 0 };
1080 int64_t TestNetMoneyValues[MAX_BTC_OUTPUTS] = { 0 }; // new way to get funded on TestNet, send TBTC to moneyman address
1081 string strReference;
1082 unsigned char single_pkt[MAX_PACKETS * PACKET_SIZE];
1083 unsigned int packet_size = 0;
1084 int fMultisig = 0;
1085 int marker_count = 0, getmoney_count = 0;
1086 // class B: multisig data storage
1087 vector<string>multisig_script_data;
1088 uint64_t inAll = 0;
1089 uint64_t outAll = 0;
1090 uint64_t txFee = 0;
1091 
1092  mp_tx->Set(wtx.GetHash(), nBlock, idx, nTime);
1093 
1094  // quickly go through the outputs & ensure there is a marker (a send to the Exodus address)
1095  for (unsigned int i = 0; i < wtx.vout.size(); i++)
1096  {
1097  CTxDestination dest;
1098  string strAddress;
1099 
1100  outAll += wtx.vout[i].nValue;
1101 
1102  if (ExtractDestination(wtx.vout[i].scriptPubKey, dest))
1103  {
1104  strAddress = CBitcoinAddress(dest).ToString();
1105 
1106  if (exodus_address == strAddress)
1107  {
1108  ExodusValues[marker_count++] = wtx.vout[i].nValue;
1109  }
1110  else if (isNonMainNet() && (getmoney_testnet == strAddress))
1111  {
1112  TestNetMoneyValues[getmoney_count++] = wtx.vout[i].nValue;
1113  }
1114  }
1115  }
1116  if ((isNonMainNet() && getmoney_count))
1117  {
1118  }
1119  else if (!marker_count)
1120  {
1121  return -1;
1122  }
1123 
1124  file_log("____________________________________________________________________________________________________________________________________\n");
1125  file_log("%s(block=%d, %s idx= %d); txid: %s\n", __FUNCTION__, nBlock, DateTimeStrFormat("%Y-%m-%d %H:%M:%S", nTime).c_str(),
1126  idx, wtx.GetHash().GetHex().c_str());
1127 
1128  // now save output addresses & scripts for later use
1129  // also determine if there is a multisig in there, if so = Class B
1130  for (unsigned int i = 0; i < wtx.vout.size(); i++)
1131  {
1132  CTxDestination dest;
1133  string strAddress;
1134 
1135  if (ExtractDestination(wtx.vout[i].scriptPubKey, dest))
1136  {
1137  txnouttype whichType;
1138  bool validType = false;
1139  if (!getOutputType(wtx.vout[i].scriptPubKey, whichType)) validType=false;
1140  if (isAllowedOutputType(whichType, nBlock)) validType=true;
1141 
1142  strAddress = CBitcoinAddress(dest).ToString();
1143 
1144  if ((exodus_address != strAddress) && (validType))
1145  {
1146  if (msc_debug_parser_data) file_log("saving address_data #%d: %s:%s\n", i, strAddress.c_str(), wtx.vout[i].scriptPubKey.ToString().c_str());
1147 
1148  // saving for Class A processing or reference
1149  wtx.vout[i].scriptPubKey.mscore_parse(script_data);
1150  address_data.push_back(strAddress);
1151  value_data.push_back(wtx.vout[i].nValue);
1152  }
1153  }
1154  else
1155  {
1156  // a multisig ?
1157  txnouttype type;
1158  std::vector<CTxDestination> vDest;
1159  int nRequired;
1160 
1161  if (ExtractDestinations(wtx.vout[i].scriptPubKey, type, vDest, nRequired))
1162  {
1163  ++fMultisig;
1164  }
1165  }
1166  }
1167 
1168  if (msc_debug_parser_data)
1169  {
1170  file_log("address_data.size=%lu\n", address_data.size());
1171  file_log("script_data.size=%lu\n", script_data.size());
1172  file_log("value_data.size=%lu\n", value_data.size());
1173  }
1174 
1175  int inputs_errors = 0; // several types of erroroneous MP TX inputs
1176  map <string, uint64_t> inputs_sum_of_values;
1177  // now go through inputs & identify the sender, collect input amounts
1178  // go through inputs, find the largest per Mastercoin protocol, the Sender
1179  for (unsigned int i = 0; i < wtx.vin.size(); i++)
1180  {
1181  CTxDestination address;
1182 
1183  if (msc_debug_vin) file_log("vin=%d:%s\n", i, wtx.vin[i].scriptSig.ToString().c_str());
1184 
1185  CTransaction txPrev;
1186  uint256 hashBlock;
1187  if (!GetTransaction(wtx.vin[i].prevout.hash, txPrev, hashBlock, true)) // get the vin's previous transaction
1188  {
1189  return -101;
1190  }
1191 
1192  unsigned int n = wtx.vin[i].prevout.n;
1193 
1195 
1196  uint64_t nValue = txPrev.vout[n].nValue;
1197  txnouttype whichType;
1198 
1199  inAll += nValue;
1200 
1201  if (ExtractDestination(txPrev.vout[n].scriptPubKey, source)) // extract the destination of the previous transaction's vout[n]
1202  {
1203  // we only allow pay-to-pubkeyhash, pay-to-scripthash & probably pay-to-pubkey (?)
1204  {
1205  if (!getOutputType(txPrev.vout[n].scriptPubKey, whichType)) ++inputs_errors;
1206  if (!isAllowedOutputType(whichType, nBlock)) ++inputs_errors;
1207 
1208  if (inputs_errors) break;
1209  }
1210 
1211  CBitcoinAddress addressSource(source); // convert this to an address
1212 
1213  inputs_sum_of_values[addressSource.ToString()] += nValue;
1214  }
1215  else ++inputs_errors;
1216 
1217  if (msc_debug_vin) file_log("vin=%d:%s\n", i, wtx.vin[i].ToString().c_str());
1218  } // end of inputs for loop
1219 
1220  txFee = inAll - outAll; // this is the fee paid to miners for this TX
1221 
1222  if (inputs_errors) // not a valid MP TX
1223  {
1224  return -101;
1225  }
1226 
1227  // largest by sum of values
1228  uint64_t nMax = 0;
1229  for(map<string, uint64_t>::iterator my_it = inputs_sum_of_values.begin(); my_it != inputs_sum_of_values.end(); ++my_it)
1230  {
1231  uint64_t nTemp = my_it->second;
1232 
1233  if (nTemp > nMax)
1234  {
1235  strSender = my_it->first;
1236  if (msc_debug_exo) file_log("looking for The Sender: %s , nMax=%lu, nTemp=%lu\n", strSender.c_str(), nMax, nTemp);
1237  nMax = nTemp;
1238  }
1239  }
1240 
1241  if (!strSender.empty())
1242  {
1243  if (msc_debug_verbose) file_log("The Sender: %s : His Input Sum of Values= %lu.%08lu ; fee= %lu.%08lu\n",
1244  strSender.c_str(), nMax / COIN, nMax % COIN, txFee/COIN, txFee%COIN);
1245  }
1246  else
1247  {
1248  file_log("The sender is still EMPTY !!! txid: %s\n", wtx.GetHash().GetHex().c_str());
1249  return -5;
1250  }
1251 
1252  //This calculates exodus fundraiser for each tx within a given block
1253  int64_t BTC_amount = ExodusValues[0];
1254  if (isNonMainNet())
1255  {
1256  if (MONEYMAN_TESTNET_BLOCK <= nBlock) BTC_amount = TestNetMoneyValues[0];
1257  }
1258 
1259  if (RegTest())
1260  {
1261  if (MONEYMAN_REGTEST_BLOCK <= nBlock) BTC_amount = TestNetMoneyValues[0];
1262  }
1263 
1264 // file_log("%s() amount = %ld , nBlock = %d, line %d, file: %s\n", __FUNCTION__, BTC_amount, nBlock, __LINE__, __FILE__);
1265 
1266  if (0 < BTC_amount && !bRPConly) (void) TXExodusFundraiser(wtx, strSender, BTC_amount, nBlock, nTime);
1267 
1268  // go through the outputs
1269  for (unsigned int i = 0; i < wtx.vout.size(); i++)
1270  {
1271  CTxDestination address;
1272 
1273  // if TRUE -- non-multisig
1274  if (ExtractDestination(wtx.vout[i].scriptPubKey, address))
1275  {
1276  }
1277  else
1278  {
1279  // probably a multisig -- get them
1280 
1281  txnouttype type;
1282  std::vector<CTxDestination> vDest;
1283  int nRequired;
1284 
1285  // CScript is a std::vector
1286  if (msc_debug_script) file_log("scriptPubKey: %s\n", wtx.vout[i].scriptPubKey.mscore_getHex().c_str());
1287 
1288  if (ExtractDestinations(wtx.vout[i].scriptPubKey, type, vDest, nRequired))
1289  {
1290  if (msc_debug_script) file_log(" >> multisig: ");
1291  BOOST_FOREACH(const CTxDestination &dest, vDest)
1292  {
1293  CBitcoinAddress address = CBitcoinAddress(dest);
1294  CKeyID keyID;
1295 
1296  if (!address.GetKeyID(keyID))
1297  {
1298  // TODO: add an error handler
1299  }
1300 
1301  // base_uint is a superclass of dest, size(), GetHex() is the same as ToString()
1302 // file_log("%s size=%d (%s); ", address.ToString().c_str(), keyID.size(), keyID.GetHex().c_str());
1303  if (msc_debug_script) file_log("%s ; ", address.ToString().c_str());
1304 
1305  }
1306  if (msc_debug_script) file_log("\n");
1307 
1308  wtx.vout[i].scriptPubKey.mscore_parse(multisig_script_data, false);
1309  }
1310  }
1311  } // end of the outputs' for loop
1312 
1313  string strObfuscatedHashes[1+MAX_SHA256_OBFUSCATION_TIMES];
1314  prepareObfuscatedHashes(strSender, strObfuscatedHashes);
1315 
1316  unsigned char packets[MAX_PACKETS][32];
1317  int mdata_count = 0; // multisig data count
1318  if (!fMultisig)
1319  {
1320  // ---------------------------------- Class A parsing ---------------------------
1321 
1322  // Init vars
1323  string strScriptData;
1324  string strDataAddress;
1325  string strRefAddress;
1326  unsigned char dataAddressSeq = 0xFF;
1327  unsigned char seq = 0xFF;
1328  int64_t dataAddressValue = 0;
1329 
1330  // Step 1, locate the data packet
1331  for (unsigned k = 0; k<script_data.size();k++) // loop through outputs
1332  {
1333  txnouttype whichType;
1334  if (!getOutputType(wtx.vout[k].scriptPubKey, whichType)) break; // unable to determine type, ignore output
1335  if (!isAllowedOutputType(whichType, nBlock)) break;
1336  string strSub = script_data[k].substr(2,16); // retrieve bytes 1-9 of packet for peek & decode comparison
1337  seq = (ParseHex(script_data[k].substr(0,2)))[0]; // retrieve sequence number
1338 
1339  if (("0000000000000001" == strSub) || ("0000000000000002" == strSub)) // peek & decode comparison
1340  {
1341  if (strScriptData.empty()) // confirm we have not already located a data address
1342  {
1343  strScriptData = script_data[k].substr(2*1,2*PACKET_SIZE_CLASS_A); // populate data packet
1344  strDataAddress = address_data[k]; // record data address
1345  dataAddressSeq = seq; // record data address seq num for reference matching
1346  dataAddressValue = value_data[k]; // record data address amount for reference matching
1347  if (msc_debug_parser_data) file_log("Data Address located - data[%d]:%s: %s (%lu.%08lu)\n", k, script_data[k].c_str(), address_data[k].c_str(), value_data[k] / COIN, value_data[k] % COIN);
1348  }
1349  else
1350  {
1351  // invalidate - Class A cannot be more than one data packet - possible collision, treat as default (BTC payment)
1352  strDataAddress = ""; //empty strScriptData to block further parsing
1353  if (msc_debug_parser_data) file_log("Multiple Data Addresses found (collision?) Class A invalidated, defaulting to BTC payment\n");
1354  break;
1355  }
1356  }
1357  }
1358 
1359  // Step 2, see if we can locate an address with a seqnum +1 of DataAddressSeq
1360  if (!strDataAddress.empty()) // verify Step 1, we should now have a valid data packet, if so continue parsing
1361  {
1362  unsigned char expectedRefAddressSeq = dataAddressSeq + 1;
1363  for (unsigned k = 0; k<script_data.size();k++) // loop through outputs
1364  {
1365  txnouttype whichType;
1366  if (!getOutputType(wtx.vout[k].scriptPubKey, whichType)) break; // unable to determine type, ignore output
1367  if (!isAllowedOutputType(whichType, nBlock)) break;
1368 
1369  seq = (ParseHex(script_data[k].substr(0,2)))[0]; // retrieve sequence number
1370 
1371  if ((address_data[k] != strDataAddress) && (address_data[k] != exodus_address) && (expectedRefAddressSeq == seq)) // found reference address with matching sequence number
1372  {
1373  if (strRefAddress.empty()) // confirm we have not already located a reference address
1374  {
1375  strRefAddress = address_data[k]; // set ref address
1376  if (msc_debug_parser_data) file_log("Reference Address located via seqnum - data[%d]:%s: %s (%lu.%08lu)\n", k, script_data[k].c_str(), address_data[k].c_str(), value_data[k] / COIN, value_data[k] % COIN);
1377  }
1378  else
1379  {
1380  // can't trust sequence numbers to provide reference address, there is a collision with >1 address with expected seqnum
1381  strRefAddress = ""; // blank ref address
1382  if (msc_debug_parser_data) file_log("Reference Address sequence number collision, will fall back to evaluating matching output amounts\n");
1383  break;
1384  }
1385  }
1386  }
1387  // Step 3, if we still don't have a reference address, see if we can locate an address with matching output amounts
1388  if (strRefAddress.empty())
1389  {
1390  for (unsigned k = 0; k<script_data.size();k++) // loop through outputs
1391  {
1392  txnouttype whichType;
1393  if (!getOutputType(wtx.vout[k].scriptPubKey, whichType)) break; // unable to determine type, ignore output
1394  if (!isAllowedOutputType(whichType, nBlock)) break;
1395 
1396  if ((address_data[k] != strDataAddress) && (address_data[k] != exodus_address) && (dataAddressValue == value_data[k])) // this output matches data output, check if matches exodus output
1397  {
1398  for (int exodus_idx=0;exodus_idx<marker_count;exodus_idx++)
1399  {
1400  if (value_data[k] == ExodusValues[exodus_idx]) //this output matches data address value and exodus address value, choose as ref
1401  {
1402  if (strRefAddress.empty())
1403  {
1404  strRefAddress = address_data[k];
1405  if (msc_debug_parser_data) file_log("Reference Address located via matching amounts - data[%d]:%s: %s (%lu.%08lu)\n", k, script_data[k].c_str(), address_data[k].c_str(), value_data[k] / COIN, value_data[k] % COIN);
1406  }
1407  else
1408  {
1409  strRefAddress = "";
1410  if (msc_debug_parser_data) file_log("Reference Address collision, multiple potential candidates. Class A invalidated, defaulting to BTC payment\n");
1411  break;
1412  }
1413  }
1414  }
1415  }
1416  }
1417  }
1418  } // end if (!strDataAddress.empty())
1419 
1420  // Populate expected var strReference with chosen address (if not empty)
1421  if (!strRefAddress.empty()) strReference=strRefAddress;
1422 
1423  // Last validation step, if strRefAddress is empty, blank strDataAddress so we default to BTC payment
1424  if (strRefAddress.empty()) strDataAddress="";
1425 
1426  // -------------------------------- End Class A parsing -------------------------
1427 
1428  if (strDataAddress.empty()) // an empty Data Address here means it is not Class A valid and should be defaulted to a BTC payment
1429  {
1430  // this must be the BTC payment - validate (?)
1431 // if (msc_debug_verbose) file_log("\n================BLOCK: %d======\ntxid: %s\n", nBlock, wtx.GetHash().GetHex().c_str());
1432  file_log("!! sender: %s , receiver: %s\n", strSender.c_str(), strReference.c_str());
1433  file_log("!! this may be the BTC payment for an offer !!\n");
1434 
1435  // TODO collect all payments made to non-itself & non-exodus and their amounts -- these may be purchases!!!
1436 
1437  int count = 0;
1438  // go through the outputs, once again...
1439  {
1440  for (unsigned int i = 0; i < wtx.vout.size(); i++)
1441  {
1442  CTxDestination dest;
1443 
1444  if (ExtractDestination(wtx.vout[i].scriptPubKey, dest))
1445  {
1446  const string strAddress = CBitcoinAddress(dest).ToString();
1447 
1448  if (exodus_address == strAddress) continue;
1449  file_log("payment #%d %s %11.8lf\n", count, strAddress.c_str(), (double)wtx.vout[i].nValue/(double)COIN);
1450 
1451  // check everything & pay BTC for the property we are buying here...
1452  if (bRPConly) count = 55555; // no real way to validate a payment during simple RPC call
1453  else if (0 == DEx_payment(wtx.GetHash(), i, strAddress, strSender, wtx.vout[i].nValue, nBlock)) ++count;
1454  }
1455  }
1456  }
1457  return count ? count : -5678; // return count -- the actual number of payments within this TX or error if none were made
1458  }
1459  else
1460  {
1461  // valid Class A packet almost ready
1462  if (msc_debug_parser_data) file_log("valid Class A:from=%s:to=%s:data=%s\n", strSender.c_str(), strReference.c_str(), strScriptData.c_str());
1463  packet_size = PACKET_SIZE_CLASS_A;
1464  memcpy(single_pkt, &ParseHex(strScriptData)[0], packet_size);
1465  }
1466  }
1467  else // if (fMultisig)
1468  {
1469  unsigned int k = 0;
1470  // gotta find the Reference - Z rewrite - scrappy & inefficient, can be optimized
1471 
1472  if (msc_debug_parser_data) file_log("Beginning reference identification\n");
1473 
1474  bool referenceFound = false; // bool to hold whether we've found the reference yet
1475  bool changeRemoved = false; // bool to hold whether we've ignored the first output to sender as change
1476  unsigned int potentialReferenceOutputs = 0; // int to hold number of potential reference outputs
1477 
1478  // how many potential reference outputs do we have, if just one select it right here
1479  BOOST_FOREACH(const string &addr, address_data)
1480  {
1481  // keep Michael's original debug info & k int as used elsewhere
1482  if (msc_debug_parser_data) file_log("ref? data[%d]:%s: %s (%lu.%08lu)\n",
1483  k, script_data[k].c_str(), addr.c_str(), value_data[k] / COIN, value_data[k] % COIN);
1484  ++k;
1485 
1486  if (addr != exodus_address)
1487  {
1488  ++potentialReferenceOutputs;
1489  if (1 == potentialReferenceOutputs)
1490  {
1491  strReference = addr;
1492  referenceFound = true;
1493  if (msc_debug_parser_data) file_log("Single reference potentially id'd as follows: %s \n", strReference.c_str());
1494  }
1495  else //as soon as potentialReferenceOutputs > 1 we need to go fishing
1496  {
1497  strReference = ""; // avoid leaving strReference populated for sanity
1498  referenceFound = false;
1499  if (msc_debug_parser_data) file_log("More than one potential reference candidate, blanking strReference, need to go fishing\n");
1500  }
1501  }
1502  }
1503 
1504  // do we have a reference now? or do we need to dig deeper
1505  if (!referenceFound) // multiple possible reference addresses
1506  {
1507  if (msc_debug_parser_data) file_log("Reference has not been found yet, going fishing\n");
1508 
1509  BOOST_FOREACH(const string &addr, address_data)
1510  {
1511  // !!!! address_data is ordered by vout (i think - please confirm that's correct analysis?)
1512  if (addr != exodus_address) // removed strSender restriction, not to spec
1513  {
1514  if ((addr == strSender) && (!changeRemoved))
1515  {
1516  // per spec ignore first output to sender as change if multiple possible ref addresses
1517  changeRemoved = true;
1518  if (msc_debug_parser_data) file_log("Removed change\n");
1519  }
1520  else
1521  {
1522  // this may be set several times, but last time will be highest vout
1523  strReference = addr;
1524  if (msc_debug_parser_data) file_log("Resetting strReference as follows: %s \n ", strReference.c_str());
1525  }
1526  }
1527  }
1528  }
1529 
1530  if (msc_debug_parser_data) file_log("Ending reference identification\n");
1531  if (msc_debug_parser_data) file_log("Final decision on reference identification is: %s\n", strReference.c_str());
1532 
1533  if (msc_debug_parser) file_log("%s(), line %d, file: %s\n", __FUNCTION__, __LINE__, __FILE__);
1534  // multisig , Class B; get the data packets that are found here
1535  for (unsigned int k = 0; k<multisig_script_data.size();k++)
1536  {
1537  if (msc_debug_parser) file_log("%s(), line %d, file: %s\n", __FUNCTION__, __LINE__, __FILE__);
1538  CPubKey key(ParseHex(multisig_script_data[k]));
1539  CKeyID keyID = key.GetID();
1540  string strAddress = CBitcoinAddress(keyID).ToString();
1541  char *c_addr_type = (char *)"";
1542  string strPacket;
1543 
1544  if (msc_debug_parser) file_log("%s(), line %d, file: %s\n", __FUNCTION__, __LINE__, __FILE__);
1545  {
1546  // this is a data packet, must deobfuscate now
1547  vector<unsigned char>hash = ParseHex(strObfuscatedHashes[mdata_count+1]);
1548  vector<unsigned char>packet = ParseHex(multisig_script_data[k].substr(2*1,2*PACKET_SIZE));
1549 
1550  for (unsigned int i=0;i<packet.size();i++)
1551  {
1552  packet[i] ^= hash[i];
1553  }
1554 
1555  memcpy(&packets[mdata_count], &packet[0], PACKET_SIZE);
1556  strPacket = HexStr(packet.begin(),packet.end(), false);
1557  ++mdata_count;
1558 
1559  if (MAX_PACKETS <= mdata_count)
1560  {
1561  file_log("increase MAX_PACKETS ! mdata_count= %d\n", mdata_count);
1562  return -222;
1563  }
1564  }
1565 
1566  if (msc_debug_parser_data) file_log("multisig_data[%d]:%s: %s%s\n", k, multisig_script_data[k].c_str(), strAddress.c_str(), c_addr_type);
1567 
1568  if (!strPacket.empty())
1569  {
1570  if (msc_debug_parser) file_log("packet #%d: %s\n", mdata_count, strPacket.c_str());
1571  }
1572  if (msc_debug_parser) file_log("%s(), line %d, file: %s\n", __FUNCTION__, __LINE__, __FILE__);
1573  }
1574 
1575  packet_size = mdata_count * (PACKET_SIZE - 1);
1576 
1577  if (sizeof(single_pkt)<packet_size)
1578  {
1579  return -111;
1580  }
1581 
1582  if (msc_debug_parser) file_log("%s(), line %d, file: %s\n", __FUNCTION__, __LINE__, __FILE__);
1583  } // end of if (fMultisig)
1584  if (msc_debug_parser) file_log("%s(), line %d, file: %s\n", __FUNCTION__, __LINE__, __FILE__);
1585 
1586  // now decode mastercoin packets
1587  for (int m=0;m<mdata_count;m++)
1588  {
1589  if (msc_debug_parser) file_log("m=%d: %s\n", m, HexStr(packets[m], PACKET_SIZE + packets[m], false).c_str());
1590 
1591  // check to ensure the sequence numbers are sequential and begin with 01 !
1592  if (1+m != packets[m][0])
1593  {
1594  if (msc_debug_spec) file_log("Error: non-sequential seqnum ! expected=%d, got=%d\n", 1+m, packets[m][0]);
1595  }
1596 
1597  // now ignoring sequence numbers for Class B packets
1598  memcpy(m*(PACKET_SIZE-1)+single_pkt, 1+packets[m], PACKET_SIZE-1);
1599  }
1600 
1601  if (msc_debug_verbose) file_log("single_pkt: %s\n", HexStr(single_pkt, packet_size + single_pkt, false).c_str());
1602 
1603  mp_tx->Set(strSender, strReference, 0, wtx.GetHash(), nBlock, idx, (unsigned char *)&single_pkt, packet_size, fMultisig, (inAll-outAll));
1604 
1605  return 0;
1606 }
1607 
1608 
1609 // parse blocks, potential right from Mastercoin's Exodus
1610 int msc_initial_scan(int nHeight)
1611 {
1612 int n_total = 0, n_found = 0;
1613 const int max_block = GetHeight();
1614 
1615  // this function is useless if there are not enough blocks in the blockchain yet!
1616  if ((0 >= nHeight) || (max_block < nHeight)) return -1;
1617 
1618  printf("starting block= %d, max_block= %d\n", nHeight, max_block);
1619 
1620  CBlock block;
1621  for (int blockNum = nHeight;blockNum<=max_block;blockNum++)
1622  {
1623  CBlockIndex* pblockindex = chainActive[blockNum];
1624  string strBlockHash = pblockindex->GetBlockHash().GetHex();
1625 
1626  if (msc_debug_exo) file_log("%s(%d; max=%d):%s, line %d, file: %s\n",
1627  __FUNCTION__, blockNum, max_block, strBlockHash.c_str(), __LINE__, __FILE__);
1628 
1629  ReadBlockFromDisk(block, pblockindex);
1630 
1631  int tx_count = 0;
1632  mastercore_handler_block_begin(blockNum, pblockindex);
1633  BOOST_FOREACH(const CTransaction&tx, block.vtx)
1634  {
1635  if (0 == mastercore_handler_tx(tx, blockNum, tx_count, pblockindex)) n_found++;
1636 
1637  ++tx_count;
1638  }
1639 
1640  n_total += tx_count;
1641 
1642  mastercore_handler_block_end(blockNum, pblockindex, n_found);
1643  }
1644 
1645  printf("\n");
1646  for(map<string, CMPTally>::iterator my_it = mp_tally_map.begin(); my_it != mp_tally_map.end(); ++my_it)
1647  {
1648  // my_it->first = key
1649  // my_it->second = value
1650 
1651  printf("%34s => ", (my_it->first).c_str());
1652  (my_it->second).print();
1653  }
1654 
1655  printf("starting block= %d, max_block= %d\n", nHeight, max_block);
1656  printf("n_total= %d, n_found= %d\n", n_total, n_found);
1657 
1658  return 0;
1659 }
1660 
1661 int input_msc_balances_string(const string &s)
1662 {
1663  std::vector<std::string> addrData;
1664  boost::split(addrData, s, boost::is_any_of("="), token_compress_on);
1665  if (addrData.size() != 2) {
1666  return -1;
1667  }
1668 
1669  string strAddress = addrData[0];
1670 
1671  // split the tuples of properties
1672  std::vector<std::string> vProperties;
1673  boost::split(vProperties, addrData[1], boost::is_any_of(";"), token_compress_on);
1674 
1675  std::vector<std::string>::const_iterator iter;
1676  for (iter = vProperties.begin(); iter != vProperties.end(); ++iter) {
1677  if ((*iter).empty()) {
1678  continue;
1679  }
1680 
1681  std::vector<std::string> curData;
1682  boost::split(curData, *iter, boost::is_any_of(","), token_compress_on);
1683  if (curData.size() < 1) {
1684  // malformed property entry
1685  return -1;
1686  }
1687 
1688  size_t delimPos = curData[0].find(':');
1689  int property = OMNI_PROPERTY_MSC;
1690  uint64_t balance = 0, sellReserved = 0, acceptReserved = 0;
1691 
1692  if (delimPos != curData[0].npos) {
1693  property = atoi(curData[0].substr(0,delimPos));
1694  balance = boost::lexical_cast<boost::uint64_t>(curData[0].substr(delimPos + 1, curData[0].npos));
1695  } else {
1696  balance = boost::lexical_cast<boost::uint64_t>(curData[0]);
1697  }
1698 
1699  if (curData.size() >= 2) {
1700  sellReserved = boost::lexical_cast<boost::uint64_t>(curData[1]);
1701  }
1702 
1703  if (curData.size() >= 3) {
1704  acceptReserved = boost::lexical_cast<boost::uint64_t>(curData[2]);
1705  }
1706 
1707  if (balance == 0 && sellReserved == 0 && acceptReserved == 0) {
1708  continue;
1709  }
1710 
1711  if (balance) update_tally_map(strAddress, property, balance, BALANCE);
1712  if (sellReserved) update_tally_map(strAddress, property, sellReserved, SELLOFFER_RESERVE);
1713  if (acceptReserved) update_tally_map(strAddress, property, acceptReserved, ACCEPT_RESERVE);
1714 
1715  // FIXME
1716  const uint64_t metadexReserve = 0;
1717  if (metadexReserve) update_tally_map(strAddress, property, sellReserved, METADEX_RESERVE);
1718  }
1719 
1720  return 1;
1721 }
1722 
1723 // seller-address, offer_block, amount, property, desired BTC , property_desired, fee, blocktimelimit
1724 // 13z1JFtDMGTYQvtMq5gs4LmCztK3rmEZga,299076,76375000,1,6415500,0,10000,6
1725 int input_mp_offers_string(const string &s)
1726 {
1727  int offerBlock;
1728  uint64_t amountOriginal, btcDesired, minFee, left_forsale;
1729  unsigned int prop, prop_desired;
1730  unsigned char blocktimelimit;
1731  std::vector<std::string> vstr;
1732  boost::split(vstr, s, boost::is_any_of(" ,="), token_compress_on);
1733  string sellerAddr;
1734  string txidStr;
1735  int i = 0;
1736 
1737  if ((10 != vstr.size()) && (9 != vstr.size())) return -1;
1738 
1739  sellerAddr = vstr[i++];
1740  offerBlock = atoi(vstr[i++]);
1741  amountOriginal = boost::lexical_cast<uint64_t>(vstr[i++]);
1742  prop = boost::lexical_cast<unsigned int>(vstr[i++]);
1743  btcDesired = boost::lexical_cast<uint64_t>(vstr[i++]); // metadex: amount of desired property
1744  prop_desired = boost::lexical_cast<unsigned int>(vstr[i++]);
1745  minFee = boost::lexical_cast<uint64_t>(vstr[i++]); // metadex: subaction
1746  blocktimelimit = atoi(vstr[i++]); // metadex: index of tx in block
1747  txidStr = vstr[i++];
1748 
1749  if (OMNI_PROPERTY_BTC == prop_desired)
1750  {
1751  const string combo = STR_SELLOFFER_ADDR_PROP_COMBO(sellerAddr);
1752  CMPOffer newOffer(offerBlock, amountOriginal, prop, btcDesired, minFee, blocktimelimit, uint256(txidStr));
1753 
1754  if (my_offers.insert(std::make_pair(combo, newOffer)).second)
1755  {
1756  return 0;
1757  }
1758  else
1759  {
1760  return -1;
1761  }
1762  }
1763  else
1764  {
1765  assert(10 == vstr.size());
1766 
1767  left_forsale = boost::lexical_cast<uint64_t>(vstr[i++]);
1768 
1769  CMPMetaDEx new_mdex(sellerAddr, offerBlock, prop, amountOriginal, prop_desired,
1770  btcDesired, uint256(txidStr), blocktimelimit, (unsigned char) minFee, left_forsale );
1771 
1772  XDOUBLE neworder_price = (XDOUBLE)amountOriginal / (XDOUBLE)btcDesired;
1773 
1774  if (0 >= neworder_price) return METADEX_ERROR -66;
1775 
1776  md_PricesMap temp_prices, *p_prices = get_Prices(prop);
1777  md_Set temp_indexes, *p_indexes = NULL;
1778 
1779  std::pair<md_Set::iterator,bool> ret;
1780 
1781  if (p_prices) p_indexes = get_Indexes(p_prices, neworder_price);
1782 
1783  if (!p_indexes) p_indexes = &temp_indexes;
1784  {
1785  ret = p_indexes->insert(new_mdex);
1786 
1787  if (false == ret.second) return -1;
1788  }
1789 
1790  if (!p_prices) p_prices = &temp_prices;
1791 
1792  (*p_prices)[neworder_price] = *p_indexes;
1793 
1794  metadex[prop] = *p_prices;
1795  }
1796 
1797  return 0;
1798 }
1799 
1800 // seller-address, property, buyer-address, amount, fee, block
1801 // 13z1JFtDMGTYQvtMq5gs4LmCztK3rmEZga,1, 148EFCFXbk2LrUhEHDfs9y3A5dJ4tttKVd,100000,11000,299126
1802 // 13z1JFtDMGTYQvtMq5gs4LmCztK3rmEZga,1,1Md8GwMtWpiobRnjRabMT98EW6Jh4rEUNy,50000000,11000,299132
1803 int input_mp_accepts_string(const string &s)
1804 {
1805  int nBlock;
1806  unsigned char blocktimelimit;
1807  std::vector<std::string> vstr;
1808  boost::split(vstr, s, boost::is_any_of(" ,="), token_compress_on);
1809  uint64_t amountRemaining, amountOriginal, offerOriginal, btcDesired;
1810  unsigned int prop;
1811  string sellerAddr, buyerAddr, txidStr;
1812  int i = 0;
1813 
1814  if (10 != vstr.size()) return -1;
1815 
1816  sellerAddr = vstr[i++];
1817  prop = boost::lexical_cast<unsigned int>(vstr[i++]);
1818  buyerAddr = vstr[i++];
1819  nBlock = atoi(vstr[i++]);
1820  amountRemaining = boost::lexical_cast<uint64_t>(vstr[i++]);
1821  amountOriginal = boost::lexical_cast<uint64_t>(vstr[i++]);
1822  blocktimelimit = atoi(vstr[i++]);
1823  offerOriginal = boost::lexical_cast<uint64_t>(vstr[i++]);
1824  btcDesired = boost::lexical_cast<uint64_t>(vstr[i++]);
1825  txidStr = vstr[i++];
1826 
1827  const string combo = STR_ACCEPT_ADDR_PROP_ADDR_COMBO(sellerAddr, buyerAddr);
1828  CMPAccept newAccept(amountOriginal, amountRemaining, nBlock, blocktimelimit, prop, offerOriginal, btcDesired, uint256(txidStr));
1829  if (my_accepts.insert(std::make_pair(combo, newAccept)).second) {
1830  return 0;
1831  } else {
1832  return -1;
1833  }
1834 }
1835 
1836 // exodus_prev
1837 int input_globals_state_string(const string &s)
1838 {
1839  uint64_t exodusPrev;
1840  unsigned int nextSPID, nextTestSPID;
1841  std::vector<std::string> vstr;
1842  boost::split(vstr, s, boost::is_any_of(" ,="), token_compress_on);
1843  if (3 != vstr.size()) return -1;
1844 
1845  int i = 0;
1846  exodusPrev = boost::lexical_cast<uint64_t>(vstr[i++]);
1847  nextSPID = boost::lexical_cast<unsigned int>(vstr[i++]);
1848  nextTestSPID = boost::lexical_cast<unsigned int>(vstr[i++]);
1849 
1850  exodus_prev = exodusPrev;
1851  _my_sps->init(nextSPID, nextTestSPID);
1852  return 0;
1853 }
1854 
1855 // addr,propertyId,nValue,property_desired,deadline,early_bird,percentage,txid
1856 int input_mp_crowdsale_string(const string &s)
1857 {
1858  string sellerAddr;
1859  unsigned int propertyId;
1860  uint64_t nValue;
1861  unsigned int property_desired;
1862  uint64_t deadline;
1863  unsigned char early_bird;
1864  unsigned char percentage;
1865  uint64_t u_created;
1866  uint64_t i_created;
1867 
1868  std::vector<std::string> vstr;
1869  boost::split(vstr, s, boost::is_any_of(" ,"), token_compress_on);
1870  unsigned int i = 0;
1871 
1872  if (9 > vstr.size()) return -1;
1873 
1874  sellerAddr = vstr[i++];
1875  propertyId = atoi(vstr[i++]);
1876  nValue = boost::lexical_cast<uint64_t>(vstr[i++]);
1877  property_desired = atoi(vstr[i++]);
1878  deadline = boost::lexical_cast<uint64_t>(vstr[i++]);
1879  early_bird = (unsigned char)atoi(vstr[i++]);
1880  percentage = (unsigned char)atoi(vstr[i++]);
1881  u_created = boost::lexical_cast<uint64_t>(vstr[i++]);
1882  i_created = boost::lexical_cast<uint64_t>(vstr[i++]);
1883 
1884  CMPCrowd newCrowdsale(propertyId,nValue,property_desired,deadline,early_bird,percentage,u_created,i_created);
1885 
1886  // load the remaining as database pairs
1887  while (i < vstr.size()) {
1888  std::vector<std::string> entryData;
1889  boost::split(entryData, vstr[i++], boost::is_any_of("="), token_compress_on);
1890  if ( 2 != entryData.size()) return -1;
1891 
1892  std::vector<std::string> valueData;
1893  boost::split(valueData, entryData[1], boost::is_any_of(";"), token_compress_on);
1894 
1895  std::vector<uint64_t> vals;
1896  std::vector<std::string>::const_iterator iter;
1897  for (iter = valueData.begin(); iter != valueData.end(); ++iter) {
1898  vals.push_back(boost::lexical_cast<uint64_t>(*iter));
1899  }
1900 
1901  newCrowdsale.insertDatabase(entryData[0], vals);
1902  }
1903 
1904 
1905  if (my_crowds.insert(std::make_pair(sellerAddr, newCrowdsale)).second) {
1906  return 0;
1907  } else {
1908  return -1;
1909  }
1910 
1911  return 0;
1912 }
1913 
1914 static int msc_file_load(const string &filename, int what, bool verifyHash = false)
1915 {
1916  int lines = 0;
1917  int (*inputLineFunc)(const string &) = NULL;
1918 
1919  SHA256_CTX shaCtx;
1920  SHA256_Init(&shaCtx);
1921 
1922  switch (what)
1923  {
1924  case FILETYPE_BALANCES:
1925  mp_tally_map.clear();
1926  inputLineFunc = input_msc_balances_string;
1927  break;
1928 
1929  case FILETYPE_OFFERS:
1930  my_offers.clear();
1931 
1932  // FIXME
1933  // memory leak ... gotta unallocate inner layers first....
1934  // TODO
1935  // ...
1936  metadex.clear();
1937 
1938  inputLineFunc = input_mp_offers_string;
1939  break;
1940 
1941  case FILETYPE_ACCEPTS:
1942  my_accepts.clear();
1943  inputLineFunc = input_mp_accepts_string;
1944  break;
1945 
1946  case FILETYPE_GLOBALS:
1947  inputLineFunc = input_globals_state_string;
1948  break;
1949 
1950  case FILETYPE_CROWDSALES:
1951  my_crowds.clear();
1952  inputLineFunc = input_mp_crowdsale_string;
1953  break;
1954 
1955  default:
1956  return -1;
1957  }
1958 
1959  if (msc_debug_persistence)
1960  {
1961  LogPrintf("Loading %s ... \n", filename);
1962  file_log("%s(%s), line %d, file: %s\n", __FUNCTION__, filename.c_str(), __LINE__, __FILE__);
1963  }
1964 
1965  ifstream file;
1966  file.open(filename.c_str());
1967  if (!file.is_open())
1968  {
1969  if (msc_debug_persistence) LogPrintf("%s(%s): file not found, line %d, file: %s\n", __FUNCTION__, filename.c_str(), __LINE__, __FILE__);
1970  return -1;
1971  }
1972 
1973  int res = 0;
1974 
1975  std::string fileHash;
1976  while (file.good())
1977  {
1978  std::string line;
1979  std::getline(file, line);
1980  if (line.empty() || line[0] == '#') continue;
1981 
1982  // remove \r if the file came from Windows
1983  line.erase( std::remove( line.begin(), line.end(), '\r' ), line.end() ) ;
1984 
1985  // record and skip hashes in the file
1986  if (line[0] == '!') {
1987  fileHash = line.substr(1);
1988  continue;
1989  }
1990 
1991  // update hash?
1992  if (verifyHash) {
1993  SHA256_Update(&shaCtx, line.c_str(), line.length());
1994  }
1995 
1996  if (inputLineFunc) {
1997  if (inputLineFunc(line) < 0) {
1998  res = -1;
1999  break;
2000  }
2001  }
2002 
2003  ++lines;
2004  }
2005 
2006  file.close();
2007 
2008  if (verifyHash && res == 0) {
2009  // generate and wite the double hash of all the contents written
2010  uint256 hash1;
2011  SHA256_Final((unsigned char*)&hash1, &shaCtx);
2012  uint256 hash2;
2013  SHA256((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2);
2014 
2015  if (false == boost::iequals(hash2.ToString(), fileHash)) {
2016  file_log("File %s loaded, but failed hash validation!\n", filename.c_str());
2017  res = -1;
2018  }
2019  }
2020 
2021  file_log("%s(%s), loaded lines= %d, res= %d\n", __FUNCTION__, filename.c_str(), lines, res);
2022  LogPrintf("%s(): file: %s , loaded lines= %d, res= %d\n", __FUNCTION__, filename, lines, res);
2023 
2024  return res;
2025 }
2026 
2027 static char const * const statePrefix[NUM_FILETYPES] = {
2028  "balances",
2029  "offers",
2030  "accepts",
2031  "globals",
2032  "crowdsales",
2033 };
2034 
2035 // returns the height of the state loaded
2037 {
2038  int res = -1;
2039  // check the SP database and roll it back to its latest valid state
2040  // according to the active chain
2041  uint256 spWatermark;
2042  if (0 > _my_sps->getWatermark(spWatermark)) {
2043  //trigger a full reparse, if the SP database has no watermark
2044  return -1;
2045  }
2046 
2047  CBlockIndex const *spBlockIndex = mapBlockIndex[spWatermark];
2048  if (NULL == spBlockIndex) {
2049  //trigger a full reparse, if the watermark isn't a real block
2050  return -1;
2051  }
2052 
2053  while(false == chainActive.Contains(spBlockIndex)) {
2054  int remainingSPs = _my_sps->popBlock(*spBlockIndex->phashBlock);
2055  if (remainingSPs < 0) {
2056  // trigger a full reparse, if the levelDB cannot roll back
2057  return -1;
2058  } /*else if (remainingSPs == 0) {
2059  // potential optimization here?
2060  }*/
2061  spBlockIndex = spBlockIndex->pprev;
2062  _my_sps->setWatermark(*spBlockIndex->phashBlock);
2063  }
2064 
2065  // prepare a set of available files by block hash pruning any that are
2066  // not in the active chain
2067  std::set<uint256> persistedBlocks;
2068  boost::filesystem::directory_iterator dIter(MPPersistencePath);
2069  boost::filesystem::directory_iterator endIter;
2070  for (; dIter != endIter; ++dIter) {
2071  if (false == boost::filesystem::is_regular_file(dIter->status()) || dIter->path().empty()) {
2072  // skip funny business
2073  continue;
2074  }
2075 
2076  std::string fName = (*--dIter->path().end()).string();
2077  std::vector<std::string> vstr;
2078  boost::split(vstr, fName, boost::is_any_of("-."), token_compress_on);
2079  if ( vstr.size() == 3 &&
2080  boost::equals(vstr[2], "dat")) {
2081  uint256 blockHash;
2082  blockHash.SetHex(vstr[1]);
2083  CBlockIndex *pBlockIndex = mapBlockIndex[blockHash];
2084  if (pBlockIndex == NULL || false == chainActive.Contains(pBlockIndex)) {
2085  continue;
2086  }
2087 
2088  // this is a valid block in the active chain, store it
2089  persistedBlocks.insert(blockHash);
2090  }
2091  }
2092 
2093  // using the SP's watermark after its fixed-up as the tip
2094  // walk backwards until we find a valid and full set of persisted state files
2095  // for each block we discard, roll back the SP database
2096  CBlockIndex const *curTip = spBlockIndex;
2097  while (NULL != curTip && persistedBlocks.size() > 0) {
2098  if (persistedBlocks.find(*spBlockIndex->phashBlock) != persistedBlocks.end()) {
2099  int success = -1;
2100  for (int i = 0; i < NUM_FILETYPES; ++i) {
2101  const string filename = (MPPersistencePath / (boost::format("%s-%s.dat") % statePrefix[i] % curTip->GetBlockHash().ToString()).str().c_str()).string();
2102  success = msc_file_load(filename, i, true);
2103  if (success < 0) {
2104  break;
2105  }
2106  }
2107 
2108  if (success >= 0) {
2109  res = curTip->nHeight;
2110  break;
2111  }
2112 
2113  // remove this from the persistedBlock Set
2114  persistedBlocks.erase(*spBlockIndex->phashBlock);
2115  }
2116 
2117  // go to the previous block
2118  if (0 > _my_sps->popBlock(*curTip->phashBlock)) {
2119  // trigger a full reparse, if the levelDB cannot roll back
2120  return -1;
2121  }
2122  curTip = curTip->pprev;
2123  _my_sps->setWatermark(*curTip->phashBlock);
2124  }
2125 
2126  if (persistedBlocks.size() == 0) {
2127  // trigger a reparse if we exhausted the persistence files without success
2128  return -1;
2129  }
2130 
2131  // return the height of the block we settled at
2132  return res;
2133 }
2134 
2135 static int write_msc_balances(ofstream &file, SHA256_CTX *shaCtx)
2136 {
2137  LOCK(cs_tally);
2138 
2139  map<string, CMPTally>::iterator iter;
2140  for (iter = mp_tally_map.begin(); iter != mp_tally_map.end(); ++iter) {
2141  bool emptyWallet = true;
2142 
2143  string lineOut = (*iter).first;
2144  lineOut.append("=");
2145  CMPTally &curAddr = (*iter).second;
2146  curAddr.init();
2147  unsigned int prop = 0;
2148  while (0 != (prop = curAddr.next())) {
2149  uint64_t balance = (*iter).second.getMoney(prop, BALANCE);
2150  uint64_t sellReserved = (*iter).second.getMoney(prop, SELLOFFER_RESERVE);
2151  uint64_t acceptReserved = (*iter).second.getMoney(prop, ACCEPT_RESERVE);
2152  const uint64_t metadexReserve = (*iter).second.getMoney(prop, METADEX_RESERVE);
2153 
2154  // we don't allow 0 balances to read in, so if we don't write them
2155  // it makes things match up better between persisted state and processed state
2156  if ( 0 == balance && 0 == sellReserved && 0 == acceptReserved && 0 == metadexReserve ) {
2157  continue;
2158  }
2159 
2160  emptyWallet = false;
2161 
2162  lineOut.append((boost::format("%d:%d,%d,%d,%d;")
2163  % prop
2164  % balance
2165  % sellReserved
2166  % acceptReserved
2167  % metadexReserve).str());
2168 
2169  }
2170 
2171  if (false == emptyWallet) {
2172  // add the line to the hash
2173  SHA256_Update(shaCtx, lineOut.c_str(), lineOut.length());
2174 
2175  // write the line
2176  file << lineOut << endl;
2177  }
2178  }
2179 
2180  return 0;
2181 }
2182 
2183 static int write_mp_offers(ofstream &file, SHA256_CTX *shaCtx)
2184 {
2185  OfferMap::const_iterator iter;
2186  for (iter = my_offers.begin(); iter != my_offers.end(); ++iter) {
2187  // decompose the key for address
2188  std::vector<std::string> vstr;
2189  boost::split(vstr, (*iter).first, boost::is_any_of("-"), token_compress_on);
2190  CMPOffer const &offer = (*iter).second;
2191  offer.saveOffer(file, shaCtx, vstr[0]);
2192  }
2193 
2194 
2195  return 0;
2196 }
2197 
2198 static int write_mp_metadex(ofstream &file, SHA256_CTX *shaCtx)
2199 {
2200  for (md_PropertiesMap::iterator my_it = metadex.begin(); my_it != metadex.end(); ++my_it)
2201  {
2202  md_PricesMap & prices = my_it->second;
2203  for (md_PricesMap::iterator it = prices.begin(); it != prices.end(); ++it)
2204  {
2205  md_Set & indexes = (it->second);
2206  for (md_Set::iterator it = indexes.begin(); it != indexes.end(); ++it)
2207  {
2208  CMPMetaDEx meta = *it;
2209  meta.saveOffer(file, shaCtx);
2210  }
2211  }
2212  }
2213 
2214  return 0;
2215 }
2216 
2217 static int write_mp_accepts(ofstream &file, SHA256_CTX *shaCtx)
2218 {
2219  AcceptMap::const_iterator iter;
2220  for (iter = my_accepts.begin(); iter != my_accepts.end(); ++iter) {
2221  // decompose the key for address
2222  std::vector<std::string> vstr;
2223  boost::split(vstr, (*iter).first, boost::is_any_of("-+"), token_compress_on);
2224  CMPAccept const &accept = (*iter).second;
2225  accept.saveAccept(file, shaCtx, vstr[0], vstr[1]);
2226  }
2227 
2228  return 0;
2229 }
2230 
2231 static int write_globals_state(ofstream &file, SHA256_CTX *shaCtx)
2232 {
2233  unsigned int nextSPID = _my_sps->peekNextSPID(OMNI_PROPERTY_MSC);
2234  unsigned int nextTestSPID = _my_sps->peekNextSPID(OMNI_PROPERTY_TMSC);
2235  string lineOut = (boost::format("%d,%d,%d")
2236  % exodus_prev
2237  % nextSPID
2238  % nextTestSPID
2239  ).str();
2240 
2241  // add the line to the hash
2242  SHA256_Update(shaCtx, lineOut.c_str(), lineOut.length());
2243 
2244  // write the line
2245  file << lineOut << endl;
2246 
2247  return 0;
2248 }
2249 
2250 static int write_mp_crowdsales(ofstream &file, SHA256_CTX *shaCtx)
2251 {
2252  CrowdMap::const_iterator iter;
2253  for (iter = my_crowds.begin(); iter != my_crowds.end(); ++iter) {
2254  // decompose the key for address
2255  CMPCrowd const &crowd = (*iter).second;
2256  crowd.saveCrowdSale(file, shaCtx, (*iter).first);
2257  }
2258 
2259  return 0;
2260 }
2261 
2262 static int write_state_file( CBlockIndex const *pBlockIndex, int what )
2263 {
2264  const char *blockHash = pBlockIndex->GetBlockHash().ToString().c_str();
2265  boost::filesystem::path balancePath = MPPersistencePath / (boost::format("%s-%s.dat") % statePrefix[what] % blockHash).str();
2266  ofstream file;
2267  file.open(balancePath.string().c_str());
2268 
2269  SHA256_CTX shaCtx;
2270  SHA256_Init(&shaCtx);
2271 
2272  int result = 0;
2273 
2274  switch(what) {
2275  case FILETYPE_BALANCES:
2276  result = write_msc_balances(file, &shaCtx);
2277  break;
2278 
2279  case FILETYPE_OFFERS:
2280  result = write_mp_offers(file, &shaCtx);
2281  result += write_mp_metadex(file, &shaCtx);
2282  break;
2283 
2284  case FILETYPE_ACCEPTS:
2285  result = write_mp_accepts(file, &shaCtx);
2286  break;
2287 
2288  case FILETYPE_GLOBALS:
2289  result = write_globals_state(file, &shaCtx);
2290  break;
2291 
2292  case FILETYPE_CROWDSALES:
2293  result = write_mp_crowdsales(file, &shaCtx);
2294  break;
2295  }
2296 
2297  // generate and wite the double hash of all the contents written
2298  uint256 hash1;
2299  SHA256_Final((unsigned char*)&hash1, &shaCtx);
2300  uint256 hash2;
2301  SHA256((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2);
2302  file << "!" << hash2.ToString() << endl;
2303 
2304  file.flush();
2305  file.close();
2306  return result;
2307 }
2308 
2309 static bool is_state_prefix( std::string const &str )
2310 {
2311  for (int i = 0; i < NUM_FILETYPES; ++i) {
2312  if (boost::equals(str, statePrefix[i])) {
2313  return true;
2314  }
2315  }
2316 
2317  return false;
2318 }
2319 
2320 static void prune_state_files( CBlockIndex const *topIndex )
2321 {
2322  // build a set of blockHashes for which we have any state files
2323  std::set<uint256> statefulBlockHashes;
2324 
2325  boost::filesystem::directory_iterator dIter(MPPersistencePath);
2326  boost::filesystem::directory_iterator endIter;
2327  for (; dIter != endIter; ++dIter) {
2328  std::string fName = dIter->path().empty() ? "<invalid>" : (*--dIter->path().end()).string();
2329  if (false == boost::filesystem::is_regular_file(dIter->status())) {
2330  // skip funny business
2331  file_log("Non-regular file found in persistence directory : %s\n", fName.c_str());
2332  continue;
2333  }
2334 
2335  std::vector<std::string> vstr;
2336  boost::split(vstr, fName, boost::is_any_of("-."), token_compress_on);
2337  if ( vstr.size() == 3 &&
2338  is_state_prefix(vstr[0]) &&
2339  boost::equals(vstr[2], "dat")) {
2340  uint256 blockHash;
2341  blockHash.SetHex(vstr[1]);
2342  statefulBlockHashes.insert(blockHash);
2343  } else {
2344  file_log("None state file found in persistence directory : %s\n", fName.c_str());
2345  }
2346  }
2347 
2348  // for each blockHash in the set, determine the distance from the given block
2349  std::set<uint256>::const_iterator iter;
2350  for (iter = statefulBlockHashes.begin(); iter != statefulBlockHashes.end(); ++iter) {
2351  // look up the CBlockIndex for height info
2352  CBlockIndex const *curIndex = NULL;
2353  map<uint256,CBlockIndex *>::const_iterator indexIter = mapBlockIndex.find((*iter));
2354  if (indexIter != mapBlockIndex.end()) {
2355  curIndex = (*indexIter).second;
2356  }
2357 
2358  // if we have nothing int the index, or this block is too old..
2359  if (NULL == curIndex || (topIndex->nHeight - curIndex->nHeight) > MAX_STATE_HISTORY ) {
2360  if (msc_debug_persistence)
2361  {
2362  if (curIndex) {
2363  file_log("State from Block:%s is no longer need, removing files (age-from-tip: %d)\n", (*iter).ToString().c_str(), topIndex->nHeight - curIndex->nHeight);
2364  } else {
2365  file_log("State from Block:%s is no longer need, removing files (not in index)\n", (*iter).ToString().c_str());
2366  }
2367  }
2368 
2369  // destroy the associated files!
2370  const char *blockHashStr = (*iter).ToString().c_str();
2371  for (int i = 0; i < NUM_FILETYPES; ++i) {
2372  boost::filesystem::remove(MPPersistencePath / (boost::format("%s-%s.dat") % statePrefix[i] % blockHashStr).str());
2373  }
2374  }
2375  }
2376 }
2377 
2378 int mastercore_save_state( CBlockIndex const *pBlockIndex )
2379 {
2380  // write the new state as of the given block
2381  write_state_file(pBlockIndex, FILETYPE_BALANCES);
2382  write_state_file(pBlockIndex, FILETYPE_OFFERS);
2383  write_state_file(pBlockIndex, FILETYPE_ACCEPTS);
2384  write_state_file(pBlockIndex, FILETYPE_GLOBALS);
2385  write_state_file(pBlockIndex, FILETYPE_CROWDSALES);
2386 
2387  // clean-up the directory
2388  prune_state_files(pBlockIndex);
2389 
2390  _my_sps->setWatermark(*pBlockIndex->phashBlock);
2391 
2392  return 0;
2393 }
2394 
2395 static void clear_all_state() {
2396  mp_tally_map.clear();
2397  my_offers.clear();
2398  my_accepts.clear();
2399  my_crowds.clear();
2400  _my_sps->clear();
2401  exodus_prev = 0;
2402 }
2403 
2404 // called from init.cpp of Bitcoin Core
2406 {
2407  if (mastercoreInitialized) {
2408  // nothing to do
2409  return 0;
2410  }
2411 
2412  printf("%s()%s, line %d, file: %s\n", __FUNCTION__, isNonMainNet() ? "TESTNET":"", __LINE__, __FILE__);
2413 
2414  shrinkDebugFile();
2415 
2416  file_log("\n%s OMNICORE INIT, build date: " __DATE__ " " __TIME__ "\n\n", DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime()).c_str());
2417 
2418  if (isNonMainNet())
2419  {
2421  }
2422  //If interested in changing regtest address do so here and uncomment
2423  /*if (RegTest())
2424  {
2425  exodus_address = exodus_testnet;
2426  }*/
2427 
2428  // check for --startclean option and delete MP_ folders if present
2429  if (GetBoolArg("-startclean", false))
2430  {
2431  file_log("Process was started with --startclean option, attempting to clear persistence files...");
2432  try
2433  {
2434  boost::filesystem::path persistPath = GetDataDir() / "MP_persist";
2435  boost::filesystem::path txlistPath = GetDataDir() / "MP_txlist";
2436  boost::filesystem::path tradePath = GetDataDir() / "MP_tradelist";
2437  boost::filesystem::path spPath = GetDataDir() / "MP_spinfo";
2438  boost::filesystem::path stoPath = GetDataDir() / "MP_stolist";
2439  if (boost::filesystem::exists(persistPath)) boost::filesystem::remove_all(persistPath);
2440  if (boost::filesystem::exists(txlistPath)) boost::filesystem::remove_all(txlistPath);
2441  if (boost::filesystem::exists(tradePath)) boost::filesystem::remove_all(tradePath);
2442  if (boost::filesystem::exists(spPath)) boost::filesystem::remove_all(spPath);
2443  if (boost::filesystem::exists(stoPath)) boost::filesystem::remove_all(stoPath);
2444  file_log("Success clearing persistence files (did not raise any exceptions).");
2445  }
2446  catch(boost::filesystem::filesystem_error const & e)
2447  {
2448  file_log("Exception deleting folders for --startclean option.\n");
2449  printf("Exception deleting folders for --startclean option.\n");
2450  }
2451  }
2452  t_tradelistdb = new CMPTradeList(GetDataDir() / "MP_tradelist", 1<<20, false, fReindex);
2453  s_stolistdb = new CMPSTOList(GetDataDir() / "MP_stolist", 1<<20, false, fReindex);
2454  p_txlistdb = new CMPTxList(GetDataDir() / "MP_txlist", 1<<20, false, fReindex);
2455  _my_sps = new CMPSPInfo(GetDataDir() / "MP_spinfo");
2456  MPPersistencePath = GetDataDir() / "MP_persist";
2457  boost::filesystem::create_directories(MPPersistencePath);
2458 
2459  // legacy code, setting to pre-genesis-block
2460  static int snapshotHeight = (GENESIS_BLOCK - 1);
2461  static const uint64_t snapshotDevMSC = 0;
2462 
2463  if (isNonMainNet()) snapshotHeight = START_TESTNET_BLOCK - 1;
2464 
2465  if (RegTest()) snapshotHeight = START_REGTEST_BLOCK - 1;
2466 
2468 
2469  if (readPersistence())
2470  {
2471  nWaterlineBlock = load_most_relevant_state();
2472  if (nWaterlineBlock < 0) {
2473  // persistence says we reparse!, nuke some stuff in case the partial loads left stale bits
2474  clear_all_state();
2475  }
2476 
2477  if (nWaterlineBlock < snapshotHeight)
2478  {
2479  nWaterlineBlock = snapshotHeight;
2480  exodus_prev=snapshotDevMSC;
2481  }
2482 
2483  // advance the waterline so that we start on the next unaccounted for block
2484  nWaterlineBlock += 1;
2485  }
2486  else
2487  {
2488  // my old way
2489  nWaterlineBlock = GENESIS_BLOCK - 1; // the DEX block
2490 
2491  if (TestNet()) nWaterlineBlock = START_TESTNET_BLOCK; //testnet3
2492 
2493  if (RegTest()) nWaterlineBlock = START_REGTEST_BLOCK; //testnet3
2494 
2495 #ifdef MY_HACK
2496 // nWaterlineBlock = MSC_DEX_BLOCK-3;
2497 // if (isNonMainNet()) nWaterlineBlock = 272700;
2498 
2499 #if 0
2500  if (isNonMainNet()) nWaterlineBlock = 272790;
2501 
2502  update_tally_map("mfaiZGBkY4mBqt3PHPD2qWgbaafGa7vR64" , 1 , 500000, BALANCE);
2503  update_tally_map("mxaYwMv2Brbs7CW9r5aYuEr1jKTSDXg1TH" , 1 , 100000, BALANCE);
2504 
2505  update_tally_map("mfaiZGBkY4mBqt3PHPD2qWgbaafGa7vR64" , 2 , 500000, BALANCE);
2506  update_tally_map("mxaYwMv2Brbs7CW9r5aYuEr1jKTSDXg1TH" , 2 , 100000, BALANCE);
2507 
2508  update_tally_map("mfaiZGBkY4mBqt3PHPD2qWgbaafGa7vR64" , 3 , 500000, BALANCE);
2509  update_tally_map("mxaYwMv2Brbs7CW9r5aYuEr1jKTSDXg1TH" , 3 , 100000, BALANCE);
2510 
2511  update_tally_map("mfaiZGBkY4mBqt3PHPD2qWgbaafGa7vR64" , 2147483652 , 500000, BALANCE);
2512  update_tally_map("mxaYwMv2Brbs7CW9r5aYuEr1jKTSDXg1TH" , 2147483652 , 100000, BALANCE);
2513 
2514  update_tally_map("mfaiZGBkY4mBqt3PHPD2qWgbaafGa7vR64" , 2147483660 , 500000, BALANCE);
2515  update_tally_map("mxaYwMv2Brbs7CW9r5aYuEr1jKTSDXg1TH" , 2147483660 , 100000, BALANCE);
2516 
2517  update_tally_map("mfaiZGBkY4mBqt3PHPD2qWgbaafGa7vR64" , 2147483661 , 500000, BALANCE);
2518  update_tally_map("mxaYwMv2Brbs7CW9r5aYuEr1jKTSDXg1TH" , 2147483661 , 100000, BALANCE);
2519 #endif
2520 #endif
2521  }
2522 
2523  // collect the real Exodus balances available at the snapshot time
2524  // redundant? do we need to show it both pre-parse and post-parse? if so let's label the printfs accordingly
2526  printf("[Snapshot] Exodus balance: %s\n", FormatDivisibleMP(exodus_balance).c_str());
2527 
2528  // check out levelDB for the most recently stored alert and load it into global_alert_message then check if expired
2529  (void) p_txlistdb->setLastAlert(nWaterlineBlock);
2530  // initial scan
2531  (void) msc_initial_scan(nWaterlineBlock);
2532 
2533  // display Exodus balance
2535  printf("[Initialized] Exodus balance: %s\n", FormatDivisibleMP(exodus_balance).c_str());
2536 
2537  return 0;
2538 }
2539 
2541 {
2542  printf("%s(), line %d, file: %s\n", __FUNCTION__, __LINE__, __FILE__);
2543 
2544  if (p_txlistdb)
2545  {
2546  delete p_txlistdb; p_txlistdb = NULL;
2547  }
2548  if (t_tradelistdb)
2549  {
2550  delete t_tradelistdb; t_tradelistdb = NULL;
2551  }
2552  if (s_stolistdb)
2553  {
2554  delete s_stolistdb; s_stolistdb = NULL;
2555  }
2556  file_log("\n%s OMNICORE SHUTDOWN, build date: " __DATE__ " " __TIME__ "\n\n", DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime()).c_str());
2557 
2558  if (_my_sps)
2559  {
2560  delete _my_sps; _my_sps = NULL;
2561  }
2562 
2563  return 0;
2564 }
2565 
2566 // this is called for every new transaction that comes in (actually in block parsing loop)
2567 int mastercore_handler_tx(const CTransaction &tx, int nBlock, unsigned int idx, CBlockIndex const * pBlockIndex)
2568 {
2569  if (!mastercoreInitialized) {
2570  mastercore_init();
2571  }
2572 
2573  // clear pending, if any
2574  // NOTE1: Every incoming TX is checked, not just MP-ones because:
2575  // if for some reason the incoming TX doesn't pass our parser validation steps successfuly, I'd still want to clear pending amounts for that TX.
2576  // NOTE2: Plus I wanna clear the amount before that TX is parsed by our protocol, in case we ever consider pending amounts in internal calculations.
2577  (void) pendingDelete(tx.GetHash(), true);
2578 
2579 CMPTransaction mp_obj;
2580 // save the augmented offer or accept amount into the database as well (expecting them to be numerically lower than that in the blockchain)
2581 int interp_ret = -555555, pop_ret;
2582 
2583  if (nBlock < nWaterlineBlock) return -1; // we do not care about parsing blocks prior to our waterline (empty blockchain defense)
2584 
2585  pop_ret = parseTransaction(false, tx, nBlock, idx, &mp_obj, pBlockIndex->GetBlockTime() );
2586  if (0 == pop_ret)
2587  {
2588  // true MP transaction, validity (such as insufficient funds, or offer not found) is determined elsewhere
2589 
2590  interp_ret = mp_obj.interpretPacket();
2591  if (interp_ret) file_log("!!! interpretPacket() returned %d !!!\n", interp_ret);
2592 
2593  mp_obj.print();
2594 
2595  // of course only MP-related TXs get recorded
2596  if (!disableLevelDB)
2597  {
2598  bool bValid = (0 <= interp_ret);
2599 
2600  p_txlistdb->recordTX(tx.GetHash(), bValid, nBlock, mp_obj.getType(), mp_obj.getNewAmount());
2601  }
2602  }
2603 
2604  return interp_ret;
2605 }
2606 
2607 // IsMine wrapper to determine whether the address is in our local wallet
2608 bool IsMyAddress(const std::string &address)
2609 {
2610  if (!pwalletMain) return false;
2611 
2612  const CBitcoinAddress& mscaddress = address;
2613 
2614  CTxDestination lookupaddress = mscaddress.Get();
2615 
2616  return (IsMine(*pwalletMain, lookupaddress));
2617 }
2618 
2619 // gets a label for a Bitcoin address from the wallet, mainly to the UI (used in demo)
2620 string getLabel(const string &address)
2621 {
2622 CWallet *wallet = pwalletMain;
2623 
2624  if (wallet)
2625  {
2626  LOCK(wallet->cs_wallet);
2627  CBitcoinAddress address_parsed(address);
2628  std::map<CTxDestination, CAddressBookData>::iterator mi = wallet->mapAddressBook.find(address_parsed.Get());
2629  if (mi != wallet->mapAddressBook.end())
2630  {
2631  return (mi->second.name);
2632  }
2633  }
2634 
2635  return string();
2636 }
2637 
2638 //
2639 // Determines minimum output amount to be spent by an output based on
2640 // scriptPubKey size in relation to the minimum relay fee.
2641 //
2642 // This method is very related with IsDust(nMinRelayTxFee) in core.h.
2643 //
2644 int64_t GetDustLimit(const CScript& scriptPubKey)
2645 {
2646  // The total size is based on a typical scriptSig size of 148 byte,
2647  // 8 byte accounted for the size of output value and the serialized
2648  // size of scriptPubKey.
2649  size_t nSize = ::GetSerializeSize(scriptPubKey, SER_DISK, 0) + 156;
2650 
2651  // The minimum relay fee dictates a threshold value under which a
2652  // transaction won't be relayed.
2653  int64_t nRelayTxFee = CTransaction::nMinRelayTxFee;
2654 
2655  // A transaction is considered as "dust", if less than 1/3 of the
2656  // minimum fee required to relay a transaction is spent by one of
2657  // it's outputs. The minimum relay fee is defined per 1000 byte.
2658  int64_t nDustLimit = 1 + (((nSize * nRelayTxFee * 3) - 1) / 1000);
2659 
2660  return nDustLimit;
2661 }
2662 
2663 static int64_t selectCoins(const string &FromAddress, CCoinControl &coinControl, int64_t additional)
2664 {
2665  CWallet *wallet = pwalletMain;
2666  int64_t n_max = (COIN * (20 * (0.0001))); // assume 20KBytes max TX size at 0.0001 per kilobyte
2667  // FUTURE: remove n_max and try 1st smallest input, then 2 smallest inputs etc. -- i.e. move Coin Control selection closer to CreateTransaction
2668  int64_t n_total = 0; // total output funds collected
2669 
2670  // if referenceamount is set it is needed to be accounted for here too
2671  if (0 < additional) n_max += additional;
2672 
2673  LOCK(wallet->cs_wallet);
2674 
2675  string sAddress = "";
2676 
2677  // iterate over the wallet
2678  for (map<uint256, CWalletTx>::iterator it = wallet->mapWallet.begin();
2679  it != wallet->mapWallet.end(); ++it) {
2680  const uint256& wtxid = it->first;
2681  const CWalletTx* pcoin = &(*it).second;
2682  bool bIsMine;
2683  bool bIsSpent;
2684 
2685  if (pcoin->IsTrusted()) {
2686  const int64_t nAvailable = pcoin->GetAvailableCredit();
2687 
2688  if (!nAvailable)
2689  continue;
2690 
2691  for (unsigned int i = 0; i < pcoin->vout.size(); i++) {
2692  CTxDestination dest;
2693 
2694  if (!ExtractDestination(pcoin->vout[i].scriptPubKey, dest))
2695  continue;
2696 
2697  bIsMine = IsMine(*wallet, dest);
2698  bIsSpent = wallet->IsSpent(wtxid, i);
2699 
2700  if (!bIsMine || bIsSpent)
2701  continue;
2702 
2703  int64_t n = bIsSpent ? 0 : pcoin->vout[i].nValue;
2704 
2705  sAddress = CBitcoinAddress(dest).ToString();
2706  if (msc_debug_tokens)
2707  file_log("%s:IsMine()=%s:IsSpent()=%s:%s: i=%d, nValue= %lu\n",
2708  sAddress.c_str(), bIsMine ? "yes" : "NO",
2709  bIsSpent ? "YES" : "no", wtxid.ToString().c_str(), i, n);
2710 
2711  // only use funds from the Sender's address for our MP transaction
2712  // TODO: may want to a little more selective here, i.e. use smallest possible (~0.1 BTC), but large amounts lead to faster confirmations !
2713  if (FromAddress == sAddress) {
2714  COutPoint outpt(wtxid, i);
2715  coinControl.Select(outpt);
2716 
2717  n_total += n;
2718 
2719  if (n_max <= n_total)
2720  break;
2721  }
2722  } // for pcoin end
2723  }
2724 
2725  if (n_max <= n_total)
2726  break;
2727  } // for iterate over the wallet end
2728 
2729 // return 0;
2730 return n_total;
2731 }
2732 
2733 int64_t feeCheck(const string &address)
2734 {
2735  // check the supplied address against selectCoins to determine if sufficient fees for send
2736  CCoinControl coinControl;
2737  return selectCoins(address, coinControl, 0);
2738 }
2739 
2740 //
2741 // Do we care if this is true: pubkeys[i].IsCompressed() ???
2742 // returns 0 if everything is OK, the transaction was sent
2743 int mastercore::ClassB_send(const string &senderAddress, const string &receiverAddress, const string &redemptionAddress, const vector<unsigned char> &data, uint256 & txid, int64_t referenceamount)
2744 {
2745 CWallet *wallet = pwalletMain;
2746 CCoinControl coinControl;
2747 vector< pair<CScript, int64_t> > vecSend;
2748 
2749  // pick inputs for this transaction
2750  if (0 > selectCoins(senderAddress, coinControl, referenceamount))
2751  {
2752  return MP_INPUTS_INVALID;
2753  }
2754 
2755  txid = 0;
2756 
2757  // determine the redeeming public key for our multisig outputs
2758  // partially copied from _createmultisig()
2759  CBitcoinAddress address;
2760  CPubKey redeemingPubKey;
2761  if (false == redemptionAddress.empty()) {
2762  address.SetString(redemptionAddress);
2763  } else {
2764  address.SetString(senderAddress);
2765  }
2766 
2767  // validate that the redemption Address is good
2768  if (wallet && address.IsValid())
2769  {
2770  if (address.IsScript())
2771  {
2772  file_log("%s() ERROR: Redemption Address must be specified !\n", __FUNCTION__);
2773  return MP_REDEMP_ILLEGAL;
2774  }
2775  else
2776  {
2777  CKeyID keyID;
2778 
2779  if (!address.GetKeyID(keyID))
2780  return MP_REDEMP_BAD_KEYID;
2781 
2782  if (!bRawTX)
2783  {
2784  if (!wallet->GetPubKey(keyID, redeemingPubKey))
2786 
2787  if (!redeemingPubKey.IsFullyValid())
2788  return MP_REDEMP_INVALID_PUBKEY;
2789  }
2790  }
2791  }
2792  else return MP_REDEMP_BAD_VALIDATION;
2793 
2794  int nRemainingBytes = data.size();
2795  int nNextByte = 0;
2796  unsigned char seqNum = 1;
2797  string strObfuscatedHashes[1+MAX_SHA256_OBFUSCATION_TIMES];
2798  prepareObfuscatedHashes(senderAddress, strObfuscatedHashes);
2799 
2800  while (nRemainingBytes > 0) {
2801  int nKeys = 1; //assume one key of data since we have data remaining
2802  if (nRemainingBytes > (PACKET_SIZE - 1)) {
2803  // we have enough data for 2 keys in this output
2804  nKeys += 1;
2805  }
2806 
2807  vector<CPubKey> keys;
2808  // always include the redeeming pubkey
2809  keys.push_back(redeemingPubKey);
2810 
2811  int i;
2812  for (i = 0; i < nKeys; i++)
2813  {
2814  // add sequence number
2815  vector<unsigned char> fakeKey;
2816  fakeKey.push_back(seqNum);
2817 
2818  // add up to 30 bytes of data
2819  int numBytes = nRemainingBytes < (PACKET_SIZE - 1) ? nRemainingBytes: (PACKET_SIZE - 1);
2820  fakeKey.insert(fakeKey.end(), data.begin() + nNextByte, data.begin() + nNextByte + numBytes);
2821  nNextByte += numBytes;
2822  nRemainingBytes -= numBytes;
2823 
2824  // pad to 31 total bytes with zeros
2825  while (fakeKey.size() < PACKET_SIZE) {
2826  fakeKey.push_back(0);
2827  }
2828 
2829  // xor in the obfuscation
2830  int j;
2831  vector<unsigned char>hash = ParseHex(strObfuscatedHashes[seqNum]);
2832  for (j = 0; j < PACKET_SIZE; j++) {
2833  fakeKey[j] = fakeKey[j] ^ hash[j];
2834  }
2835 
2836  // prepend the 2
2837  fakeKey.insert(fakeKey.begin(), 2);
2838 
2839  // fix up the ecdsa code point
2840  CPubKey pubKey;
2841  fakeKey.resize(33);
2842  unsigned char random_byte = (unsigned char)(GetRand(256));
2843  for (j = 0; i < 256 ; j++)
2844  {
2845  fakeKey[32] = random_byte;
2846 
2847  pubKey = CPubKey(fakeKey);
2848  file_log("pubKey check: %s\n", (HexStr(pubKey.begin(), pubKey.end()).c_str()));
2849 
2850  if (pubKey.IsFullyValid()) break;
2851 
2852  ++random_byte; // cycle 256 times, if we must to find a valid ECDSA point
2853  }
2854 
2855  keys.push_back(pubKey);
2856  seqNum++;
2857  }
2858 
2859  CScript multisig_output;
2860  multisig_output.SetMultisig(1, keys);
2861  vecSend.push_back(make_pair(multisig_output, GetDustLimit(multisig_output)));
2862  }
2863 
2864  CWalletTx wtxNew;
2865  int64_t nFeeRet = 0;
2866  std::string strFailReason;
2867  CReserveKey reserveKey(wallet);
2868 
2869  CBitcoinAddress addr = CBitcoinAddress(senderAddress); // change goes back to us
2870  coinControl.destChange = addr.Get();
2871 
2872  if (!wallet) return MP_ERR_WALLET_ACCESS;
2873 
2874  CScript scriptPubKey;
2875 
2876  // add the the reference/recepient/receiver ouput if needed
2877  if (!receiverAddress.empty())
2878  {
2879  // Send To Owners is the first use case where the receiver is empty
2880  scriptPubKey.SetDestination(CBitcoinAddress(receiverAddress).Get());
2881  vecSend.push_back(make_pair(scriptPubKey, 0 < referenceamount ? referenceamount : GetDustLimit(scriptPubKey)));
2882  }
2883 
2884  // add the marker output
2885  scriptPubKey.SetDestination(CBitcoinAddress(exodus_address).Get());
2886  vecSend.push_back(make_pair(scriptPubKey, GetDustLimit(scriptPubKey)));
2887 
2888  // selected in the parent function, i.e.: ensure we are only using the address passed in as the Sender
2889  if (!coinControl.HasSelected()) return MP_ERR_INPUTSELECT_FAIL;
2890 
2891  LOCK(wallet->cs_wallet);
2892 
2893  // the fee will be computed by Bitcoin Core, need an override (?)
2894  // TODO: look at Bitcoin Core's global: nTransactionFee (?)
2895  if (!wallet->CreateTransaction(vecSend, wtxNew, reserveKey, nFeeRet, strFailReason, &coinControl)) return MP_ERR_CREATE_TX;
2896 
2897  if (bRawTX)
2898  {
2899  CTransaction tx = (CTransaction) wtxNew;
2901  ssTx << tx;
2902  string strHex = HexStr(ssTx.begin(), ssTx.end());
2903  printf("RawTX:\n%s\n\n", strHex.c_str());
2904 
2905  return 0;
2906  }
2907 
2908  file_log("%s():%s; nFeeRet = %lu, line %d, file: %s\n", __FUNCTION__, wtxNew.ToString().c_str(), nFeeRet, __LINE__, __FILE__);
2909 
2910  if (!wallet->CommitTransaction(wtxNew, reserveKey)) return MP_ERR_COMMIT_TX;
2911 
2912  txid = wtxNew.GetHash();
2913 
2914  return 0;
2915 }
2916 
2917 // WIP: expanding the function to a general-purpose one, but still sending 1 packet only for now (30-31 bytes)
2918 uint256 mastercore::send_INTERNAL_1packet(const string &FromAddress, const string &ToAddress, const string &RedeemAddress, unsigned int PropertyID, uint64_t Amount, unsigned int PropertyID_2, uint64_t Amount_2, unsigned int TransactionType, int64_t additional, int *error_code)
2919 {
2920 const int64_t iAvailable = getMPbalance(FromAddress, PropertyID, BALANCE);
2921 const int64_t iUserAvailable = getUserAvailableMPbalance(FromAddress, PropertyID);
2922 int rc = MP_INSUF_FUNDS_BPENDI;
2923 uint256 txid = 0;
2924 const int64_t amount = Amount;
2925 const unsigned int prop = PropertyID;
2926 
2927  if (msc_debug_send) file_log("%s(From: %s , To: %s , Property= %u, Amount= %lu, Available= %ld, Pending= %ld)\n",
2928  __FUNCTION__, FromAddress.c_str(), ToAddress.c_str(), PropertyID, Amount, iAvailable, iUserAvailable);
2929 
2930  if (!isRangeOK(Amount))
2931  {
2932  rc = MP_INPUT_NOT_IN_RANGE;
2933  if (error_code) *error_code = rc;
2934 
2935  return 0;
2936  }
2937 
2938  bool bCancel_checkBypass = false;
2939  //If doing a METADEX CANCEL, use following flag to bypass funds checks
2940  if((TransactionType == MSC_TYPE_METADEX) && ((additional == CMPTransaction::CANCEL_AT_PRICE) || (additional == CMPTransaction::CANCEL_ALL_FOR_PAIR) || (additional == CMPTransaction::CANCEL_EVERYTHING)))
2941  {
2942  bCancel_checkBypass = true;
2943  }
2944 
2945  // make sure this address has enough MP property available!
2946  if ((((uint64_t)iAvailable < Amount) || (0 == Amount)) && !bCancel_checkBypass)
2947  {
2948  LogPrintf("%s(): aborted -- not enough MP property (%lu < %lu)\n", __FUNCTION__, iAvailable, Amount);
2949  if (msc_debug_send) file_log("%s(): aborted -- not enough MP property (%lu < %lu)\n", __FUNCTION__, iAvailable, Amount);
2950 
2951  if (error_code) *error_code = rc;
2952 
2953  return 0;
2954  }
2955 
2956  // check once more, this time considering PENDING amount reduction
2957  // make sure this address has enough MP property available!
2958  if (((iUserAvailable < (int64_t)Amount) || (0 == Amount)) && !bCancel_checkBypass)
2959  {
2960  LogPrintf("%s(): aborted -- not enough MP property with PENDING reduction (%lu < %lu)\n", __FUNCTION__, iUserAvailable, Amount);
2961  if (msc_debug_send) file_log("%s(): aborted -- not enough MP property with PENDING reduction (%lu < %lu)\n", __FUNCTION__, iUserAvailable, Amount);
2962 
2963  rc = MP_INSUF_FUNDS_APENDI;
2964  if (error_code) *error_code = rc;
2965 
2966  return 0;
2967  }
2968 
2969  vector<unsigned char> data;
2970  swapByteOrder32(TransactionType);
2971  swapByteOrder32(PropertyID);
2972  swapByteOrder64(Amount);
2973 
2974  PUSH_BACK_BYTES(data, TransactionType);
2975  PUSH_BACK_BYTES(data, PropertyID);
2976  PUSH_BACK_BYTES(data, Amount);
2977 
2978  if (PropertyID_2 != 0 || bCancel_checkBypass == true) // for trade_MP
2979  {
2980  //use additional to pass action byte
2981  unsigned char action = boost::lexical_cast<int>(additional);
2982  //zero out additional for trade_MP
2983  additional = 0;
2984 
2985  swapByteOrder32(PropertyID_2);
2986  swapByteOrder64(Amount_2);
2987 
2988  PUSH_BACK_BYTES(data, PropertyID_2);
2989  PUSH_BACK_BYTES(data, Amount_2);
2990  PUSH_BACK_BYTES(data, action);
2991  }
2992 
2993  rc = ClassB_send(FromAddress, ToAddress, RedeemAddress, data, txid, additional);
2994  if (msc_debug_send) file_log("ClassB_send returned %d\n", rc);
2995 
2996  if (error_code) *error_code = rc;
2997 
2998  if (0 == rc)
2999  {
3000  (void) pendingAdd(txid, FromAddress, prop, amount);
3001  }
3002 
3003  return txid;
3004 }
3005 
3006 int CMPTxList::setLastAlert(int blockHeight)
3007 {
3008  if (blockHeight > chainActive.Height()) blockHeight = chainActive.Height();
3009  if (!pdb) return 0;
3010  Slice skey, svalue;
3011  readoptions.fill_cache = false;
3012  Iterator* it = pdb->NewIterator(readoptions);
3013  string lastAlertTxid;
3014  string lastAlertData;
3015  string itData;
3016  int64_t lastAlertBlock = 0;
3017  for(it->SeekToFirst(); it->Valid(); it->Next())
3018  {
3019  skey = it->key();
3020  svalue = it->value();
3021  string itData = svalue.ToString().c_str();
3022  std::vector<std::string> vstr;
3023  boost::split(vstr, itData, boost::is_any_of(":"), token_compress_on);
3024  // we expect 5 tokens
3025  if (4 == vstr.size())
3026  {
3027  if (atoi(vstr[2]) == OMNICORE_MESSAGE_TYPE_ALERT) // is it an alert?
3028  {
3029  if (atoi(vstr[0]) == 1) // is it valid?
3030  {
3031  if ( (atoi(vstr[1]) > lastAlertBlock) && (atoi(vstr[1]) < blockHeight) ) // is it the most recent and within our parsed range?
3032  {
3033  lastAlertTxid = skey.ToString().c_str();
3034  lastAlertData = svalue.ToString().c_str();
3035  lastAlertBlock = atoi(vstr[1]);
3036  }
3037  }
3038  }
3039  }
3040  }
3041  delete it;
3042 
3043  // if lastAlertTxid is not empty, load the alert and see if it's still valid - if so, copy to global_alert_message
3044  if(lastAlertTxid.empty())
3045  {
3046  file_log("DEBUG ALERT No alerts found to load\n");
3047  }
3048  else
3049  {
3050  file_log("DEBUG ALERT Loading lastAlertTxid %s\n", lastAlertTxid);
3051 
3052  // reparse lastAlertTxid
3053  uint256 hash;
3054  hash.SetHex(lastAlertTxid);
3055  CTransaction wtx;
3056  uint256 blockHash = 0;
3057  if (!GetTransaction(hash, wtx, blockHash, true)) //can't find transaction
3058  {
3059  file_log("DEBUG ALERT Unable to load lastAlertTxid, transaction not found\n");
3060  }
3061  else
3062  {
3063  CMPTransaction mp_obj;
3064  int parseRC = parseTransaction(true, wtx, blockHeight, 0, &mp_obj);
3065  string new_global_alert_message;
3066  if (0 <= parseRC)
3067  {
3068  if (0<=mp_obj.step1())
3069  {
3070  if(65535 == mp_obj.getType())
3071  {
3072  if (0 == mp_obj.step2_Alert(&new_global_alert_message))
3073  {
3074  global_alert_message = new_global_alert_message;
3075  // check if expired
3076  CBlockIndex* mpBlockIndex = chainActive[blockHeight];
3077  (void) checkExpiredAlerts(blockHeight, mpBlockIndex->GetBlockTime());
3078  }
3079  }
3080  }
3081  }
3082  }
3083  }
3084  return 0;
3085 }
3086 
3088 {
3089  std::vector<std::string> vstr;
3090  string txidStr = txid.ToString();
3091  Slice skey, svalue;
3092  readoptions.fill_cache = false;
3093  uint256 cancelTxid;
3094  Iterator* it = pdb->NewIterator(readoptions);
3095  for(it->SeekToFirst(); it->Valid(); it->Next())
3096  {
3097  skey = it->key();
3098  svalue = it->value();
3099  string svalueStr = svalue.ToString().c_str();
3100  boost::split(vstr, svalueStr, boost::is_any_of(":"), token_compress_on);
3101  // obtain the existing affected tx count
3102  if (3 <= vstr.size())
3103  {
3104  if (vstr[0] == txidStr) { delete it; cancelTxid.SetHex(skey.ToString().c_str()); return cancelTxid; }
3105  }
3106  }
3107 
3108  delete it;
3109  return 0;
3110 }
3111 
3113 {
3114  if (!pdb) return 0;
3115  int numberOfCancels = 0;
3116  std::vector<std::string> vstr;
3117  string strValue;
3118  Status status = pdb->Get(readoptions, txid.ToString() + "-C", &strValue);
3119  if (status.ok())
3120  {
3121  // parse the string returned
3122  boost::split(vstr, strValue, boost::is_any_of(":"), token_compress_on);
3123  // obtain the number of cancels
3124  if (4 <= vstr.size())
3125  {
3126  numberOfCancels = atoi(vstr[3]);
3127  }
3128  }
3129  return numberOfCancels;
3130 }
3131 
3133 {
3134  if (!pdb) return 0;
3135  int numberOfPurchases = 0;
3136  std::vector<std::string> vstr;
3137  string strValue;
3138  Status status = pdb->Get(readoptions, txid.ToString(), &strValue);
3139  if (status.ok())
3140  {
3141  // parse the string returned
3142  boost::split(vstr, strValue, boost::is_any_of(":"), token_compress_on);
3143  // obtain the number of purchases
3144  if (4 <= vstr.size())
3145  {
3146  numberOfPurchases = atoi(vstr[3]);
3147  }
3148  }
3149  return numberOfPurchases;
3150 }
3151 
3153 {
3154  int count = 0;
3155  Slice skey, svalue;
3156  readoptions.fill_cache = false;
3157  Iterator* it = pdb->NewIterator(readoptions);
3158  for(it->SeekToFirst(); it->Valid(); it->Next())
3159  {
3160  skey = it->key();
3161  if (skey.ToString().length() == 64) { ++count; } //extra entries for cancels and purchases are more than 64 chars long
3162  }
3163  delete it;
3164  return count;
3165 }
3166 
3168 {
3169  int count = 0;
3170  Slice skey, svalue;
3171  readoptions.fill_cache = false;
3172  Iterator* it = pdb->NewIterator(readoptions);
3173  for(it->SeekToFirst(); it->Valid(); it->Next())
3174  {
3175  skey = it->key();
3176  svalue = it->value();
3177  if (skey.ToString().length() == 64)
3178  {
3179  string strValue = svalue.ToString().c_str();
3180  std::vector<std::string> vstr;
3181  boost::split(vstr, strValue, boost::is_any_of(":"), token_compress_on);
3182  if (4 == vstr.size())
3183  {
3184  if (atoi(vstr[1]) == block) { ++count; }
3185  }
3186  }
3187  }
3188  delete it;
3189  return count;
3190 }
3191 
3192 string CMPTxList::getKeyValue(string key)
3193 {
3194  if (!pdb) return "";
3195  string strValue;
3196  Status status = pdb->Get(readoptions, key, &strValue);
3197  if (status.ok()) { return strValue; } else { return ""; }
3198 }
3199 
3200 bool CMPTxList::getPurchaseDetails(const uint256 txid, int purchaseNumber, string *buyer, string *seller, uint64_t *vout, uint64_t *propertyId, uint64_t *nValue)
3201 {
3202  if (!pdb) return 0;
3203  std::vector<std::string> vstr;
3204  string strValue;
3205  Status status = pdb->Get(readoptions, txid.ToString()+"-"+to_string(purchaseNumber), &strValue);
3206  if (status.ok())
3207  {
3208  // parse the string returned
3209  boost::split(vstr, strValue, boost::is_any_of(":"), token_compress_on);
3210  // obtain the requisite details
3211  if (5 == vstr.size())
3212  {
3213  *vout = atoi(vstr[0]);
3214  *buyer = vstr[1];
3215  *seller = vstr[2];
3216  *propertyId = atoi(vstr[3]);
3217  *nValue = boost::lexical_cast<boost::uint64_t>(vstr[4]);;
3218  return true;
3219  }
3220  }
3221  return false;
3222 }
3223 
3224 void CMPTxList::recordMetaDExCancelTX(const uint256 &txidMaster, const uint256 &txidSub, bool fValid, int nBlock, unsigned int propertyId, uint64_t nValue)
3225 {
3226  if (!pdb) return;
3227 
3228  // Prep - setup vars
3229  unsigned int type = 99992104;
3230  unsigned int refNumber = 1;
3231  uint64_t existingAffectedTXCount = 0;
3232  string txidMasterStr = txidMaster.ToString() + "-C";
3233 
3234  // Step 1 - Check TXList to see if this cancel TXID exists
3235  // Step 2a - If doesn't exist leave number of affected txs & ref set to 1
3236  // Step 2b - If does exist add +1 to existing ref and set this ref as new number of affected
3237  std::vector<std::string> vstr;
3238  string strValue;
3239  Status status = pdb->Get(readoptions, txidMasterStr, &strValue);
3240  if (status.ok())
3241  {
3242  // parse the string returned
3243  boost::split(vstr, strValue, boost::is_any_of(":"), token_compress_on);
3244 
3245  // obtain the existing affected tx count
3246  if (4 <= vstr.size())
3247  {
3248  existingAffectedTXCount = atoi(vstr[3]);
3249  refNumber = existingAffectedTXCount + 1;
3250  }
3251  }
3252 
3253  // Step 3 - Create new/update master record for cancel tx in TXList
3254  const string key = txidMasterStr;
3255  const string value = strprintf("%u:%d:%u:%lu", fValid ? 1:0, nBlock, type, refNumber);
3256  file_log("METADEXCANCELDEBUG : Writing master record %s(%s, valid=%s, block= %d, type= %d, number of affected transactions= %d)\n", __FUNCTION__, txidMaster.ToString().c_str(), fValid ? "YES":"NO", nBlock, type, refNumber);
3257  if (pdb)
3258  {
3259  status = pdb->Put(writeoptions, key, value);
3260  file_log("METADEXCANCELDEBUG : %s(): %s, line %d, file: %s\n", __FUNCTION__, status.ToString().c_str(), __LINE__, __FILE__);
3261  }
3262 
3263  // Step 4 - Write sub-record with cancel details
3264  const string txidStr = txidMaster.ToString() + "-C";
3265  const string subKey = STR_REF_SUBKEY_TXID_REF_COMBO(txidStr);
3266  const string subValue = strprintf("%s:%d:%lu", txidSub.ToString(), propertyId, nValue);
3267  Status subStatus;
3268  file_log("METADEXCANCELDEBUG : Writing sub-record %s with value %s\n", subKey.c_str(), subValue.c_str());
3269  if (pdb)
3270  {
3271  subStatus = pdb->Put(writeoptions, subKey, subValue);
3272  file_log("METADEXCANCELDEBUG : %s(): %s, line %d, file: %s\n", __FUNCTION__, subStatus.ToString().c_str(), __LINE__, __FILE__);
3273  }
3274 }
3275 
3276 void CMPTxList::recordPaymentTX(const uint256 &txid, bool fValid, int nBlock, unsigned int vout, unsigned int propertyId, uint64_t nValue, string buyer, string seller)
3277 {
3278  if (!pdb) return;
3279 
3280  // Prep - setup vars
3281  unsigned int type = 99999999;
3282  uint64_t numberOfPayments = 1;
3283  unsigned int paymentNumber = 1;
3284  uint64_t existingNumberOfPayments = 0;
3285 
3286  // Step 1 - Check TXList to see if this payment TXID exists
3287  bool paymentEntryExists = p_txlistdb->exists(txid);
3288 
3289  // Step 2a - If doesn't exist leave number of payments & paymentNumber set to 1
3290  // Step 2b - If does exist add +1 to existing number of payments and set this paymentNumber as new numberOfPayments
3291  if (paymentEntryExists)
3292  {
3293  //retrieve old numberOfPayments
3294  std::vector<std::string> vstr;
3295  string strValue;
3296  Status status = pdb->Get(readoptions, txid.ToString(), &strValue);
3297  if (status.ok())
3298  {
3299  // parse the string returned
3300  boost::split(vstr, strValue, boost::is_any_of(":"), token_compress_on);
3301 
3302  // obtain the existing number of payments
3303  if (4 <= vstr.size())
3304  {
3305  existingNumberOfPayments = atoi(vstr[3]);
3306  paymentNumber = existingNumberOfPayments + 1;
3307  numberOfPayments = existingNumberOfPayments + 1;
3308  }
3309  }
3310  }
3311 
3312  // Step 3 - Create new/update master record for payment tx in TXList
3313  const string key = txid.ToString();
3314  const string value = strprintf("%u:%d:%u:%lu", fValid ? 1:0, nBlock, type, numberOfPayments);
3315  Status status;
3316  file_log("DEXPAYDEBUG : Writing master record %s(%s, valid=%s, block= %d, type= %d, number of payments= %lu)\n", __FUNCTION__, txid.ToString().c_str(), fValid ? "YES":"NO", nBlock, type, numberOfPayments);
3317  if (pdb)
3318  {
3319  status = pdb->Put(writeoptions, key, value);
3320  file_log("DEXPAYDEBUG : %s(): %s, line %d, file: %s\n", __FUNCTION__, status.ToString().c_str(), __LINE__, __FILE__);
3321  }
3322 
3323  // Step 4 - Write sub-record with payment details
3324  const string txidStr = txid.ToString();
3325  const string subKey = STR_PAYMENT_SUBKEY_TXID_PAYMENT_COMBO(txidStr);
3326  const string subValue = strprintf("%d:%s:%s:%d:%lu", vout, buyer, seller, propertyId, nValue);
3327  Status subStatus;
3328  file_log("DEXPAYDEBUG : Writing sub-record %s with value %s\n", subKey.c_str(), subValue.c_str());
3329  if (pdb)
3330  {
3331  subStatus = pdb->Put(writeoptions, subKey, subValue);
3332  file_log("DEXPAYDEBUG : %s(): %s, line %d, file: %s\n", __FUNCTION__, subStatus.ToString().c_str(), __LINE__, __FILE__);
3333  }
3334 }
3335 
3336 void CMPTxList::recordTX(const uint256 &txid, bool fValid, int nBlock, unsigned int type, uint64_t nValue)
3337 {
3338  if (!pdb) return;
3339 
3340  // overwrite detection, we should never be overwriting a tx, as that means we have redone something a second time
3341  // reorgs delete all txs from levelDB above reorg_chain_height
3342  if (p_txlistdb->exists(txid)) file_log("LEVELDB TX OVERWRITE DETECTION - %s\n", txid.ToString().c_str());
3343 
3344 const string key = txid.ToString();
3345 const string value = strprintf("%u:%d:%u:%lu", fValid ? 1:0, nBlock, type, nValue);
3346 Status status;
3347 
3348  file_log("%s(%s, valid=%s, block= %d, type= %d, value= %lu)\n",
3349  __FUNCTION__, txid.ToString().c_str(), fValid ? "YES":"NO", nBlock, type, nValue);
3350 
3351  if (pdb)
3352  {
3353  status = pdb->Put(writeoptions, key, value);
3354  ++nWritten;
3355  if (msc_debug_txdb) file_log("%s(): %s, line %d, file: %s\n", __FUNCTION__, status.ToString().c_str(), __LINE__, __FILE__);
3356  }
3357 }
3358 
3359 bool CMPTxList::exists(const uint256 &txid)
3360 {
3361  if (!pdb) return false;
3362 
3363 string strValue;
3364 Status status = pdb->Get(readoptions, txid.ToString(), &strValue);
3365 
3366  if (!status.ok())
3367  {
3368  if (status.IsNotFound()) return false;
3369  }
3370 
3371  return true;
3372 }
3373 
3374 bool CMPTxList::getTX(const uint256 &txid, string &value)
3375 {
3376 Status status = pdb->Get(readoptions, txid.ToString(), &value);
3377 
3378  ++nRead;
3379 
3380  if (status.ok())
3381  {
3382  return true;
3383  }
3384 
3385  return false;
3386 }
3387 
3389 {
3390  file_log("CMPTxList stats: nWritten= %d , nRead= %d\n", nWritten, nRead);
3391 }
3392 
3394 {
3395 int count = 0;
3396 Slice skey, svalue;
3397 
3398  readoptions.fill_cache = false;
3399 
3400  Iterator* it = pdb->NewIterator(readoptions);
3401 
3402  for(it->SeekToFirst(); it->Valid(); it->Next())
3403  {
3404  skey = it->key();
3405  svalue = it->value();
3406  ++count;
3407  printf("entry #%8d= %s:%s\n", count, skey.ToString().c_str(), svalue.ToString().c_str());
3408  }
3409 
3410  delete it;
3411 }
3412 
3413 // figure out if there was at least 1 Master Protocol transaction within the block range, or a block if starting equals ending
3414 // block numbers are inclusive
3415 // pass in bDeleteFound = true to erase each entry found within the block range
3416 bool CMPTxList::isMPinBlockRange(int starting_block, int ending_block, bool bDeleteFound)
3417 {
3418 leveldb::Slice skey, svalue;
3419 unsigned int count = 0;
3420 std::vector<std::string> vstr;
3421 int block;
3422 unsigned int n_found = 0;
3423 
3424  leveldb::Iterator* it = pdb->NewIterator(iteroptions);
3425 
3426  for(it->SeekToFirst(); it->Valid(); it->Next())
3427  {
3428  skey = it->key();
3429  svalue = it->value();
3430 
3431  ++count;
3432 
3433 // printf("%5u:%s=%s\n", count, skey.ToString().c_str(), svalue.ToString().c_str());
3434 
3435  string strvalue = it->value().ToString();
3436 
3437  // parse the string returned, find the validity flag/bit & other parameters
3438  boost::split(vstr, strvalue, boost::is_any_of(":"), token_compress_on);
3439 
3440  // only care about the block number/height here
3441  if (2 <= vstr.size())
3442  {
3443  block = atoi(vstr[1]);
3444 
3445  if ((starting_block <= block) && (block <= ending_block))
3446  {
3447  ++n_found;
3448  file_log("%s() DELETING: %s=%s\n", __FUNCTION__, skey.ToString().c_str(), svalue.ToString().c_str());
3449  if (bDeleteFound) pdb->Delete(writeoptions, skey);
3450  }
3451  }
3452  }
3453 
3454  printf("%s(%d, %d); n_found= %d\n", __FUNCTION__, starting_block, ending_block, n_found);
3455 
3456  delete it;
3457 
3458  return (n_found);
3459 }
3460 
3461 // MPSTOList here
3462 std::string CMPSTOList::getMySTOReceipts(string filterAddress)
3463 {
3464  if (!sdb) return "";
3465  string mySTOReceipts = "";
3466 
3467  Slice skey, svalue;
3468  readoptions.fill_cache = false;
3469  Iterator* it = sdb->NewIterator(readoptions);
3470  for(it->SeekToFirst(); it->Valid(); it->Next())
3471  {
3472  skey = it->key();
3473  string recipientAddress = skey.ToString();
3474  if(!IsMyAddress(recipientAddress)) continue; // not ours, not interested
3475  if((!filterAddress.empty()) && (filterAddress != recipientAddress)) continue; // not the filtered address
3476  // ours, get info
3477  svalue = it->value();
3478  string strValue = svalue.ToString();
3479  // break into individual receipts
3480  std::vector<std::string> vstr;
3481  boost::split(vstr, strValue, boost::is_any_of(","), token_compress_on);
3482  for(uint32_t i = 0; i<vstr.size(); i++)
3483  {
3484  // add to array
3485  std::vector<std::string> svstr;
3486  boost::split(svstr, vstr[i], boost::is_any_of(":"), token_compress_on);
3487  if(4 == svstr.size())
3488  {
3489  size_t txidMatch = mySTOReceipts.find(svstr[0]);
3490  if(txidMatch==std::string::npos) mySTOReceipts += svstr[0]+":"+svstr[1]+":"+recipientAddress+":"+svstr[2]+",";
3491  }
3492  }
3493  }
3494  delete it;
3495  return mySTOReceipts;
3496 }
3497 
3498 void CMPSTOList::getRecipients(const uint256 txid, string filterAddress, Array *recipientArray, uint64_t *total, uint64_t *stoFee)
3499 {
3500  if (!sdb) return;
3501 
3502  bool filter = true; //default
3503  bool filterByWallet = true; //default
3504  bool filterByAddress = false; //default
3505 
3506  if (filterAddress == "*") filter = false;
3507  if ((filterAddress != "") && (filterAddress != "*")) { filterByWallet = false; filterByAddress = true; }
3508 
3509  // iterate through SDB, dropping all records where key is not filterAddress (if filtering)
3510  int count = 0;
3511 
3512  // ugly way to do this, really we should store the fee used but for now since we know it is
3513  // always num_addresses * 0.00000001 MSC we can recalculate it on the fly
3514  *stoFee = 0;
3515 
3516  Slice skey, svalue;
3517  readoptions.fill_cache = false;
3518  Iterator* it = sdb->NewIterator(readoptions);
3519  for(it->SeekToFirst(); it->Valid(); it->Next())
3520  {
3521  skey = it->key();
3522  string recipientAddress = skey.ToString();
3523  svalue = it->value();
3524  string strValue = svalue.ToString();
3525  // see if txid is in the data
3526  size_t txidMatch = strValue.find(txid.ToString());
3527  if(txidMatch!=std::string::npos)
3528  {
3529  ++*stoFee;
3530  // the txid exists inside the data, this address was a recipient of this STO, check filter and add the details
3531  if(filter)
3532  {
3533  if( ( (filterByAddress) && (filterAddress == recipientAddress) ) || ( (filterByWallet) && (IsMyAddress(recipientAddress)) ) )
3534  { } else { continue; } // move on if no filter match (but counter still increased for fee)
3535  }
3536  std::vector<std::string> vstr;
3537  boost::split(vstr, strValue, boost::is_any_of(","), token_compress_on);
3538  for(uint32_t i = 0; i<vstr.size(); i++)
3539  {
3540  std::vector<std::string> svstr;
3541  boost::split(svstr, vstr[i], boost::is_any_of(":"), token_compress_on);
3542  if(4 == svstr.size())
3543  {
3544  if(svstr[0] == txid.ToString())
3545  {
3546  //add data to array
3547  uint64_t amount = 0;
3548  uint64_t propertyId = 0;
3549  try
3550  {
3551  amount = boost::lexical_cast<uint64_t>(svstr[3]);
3552  propertyId = boost::lexical_cast<uint64_t>(svstr[2]);
3553  } catch (const boost::bad_lexical_cast &e)
3554  {
3555  file_log("DEBUG STO - error in converting values from leveldb\n");
3556  delete it;
3557  return; //(something went wrong)
3558  }
3559  Object recipient;
3560  recipient.push_back(Pair("address", recipientAddress));
3561  if(isPropertyDivisible(propertyId))
3562  {
3563  recipient.push_back(Pair("amount", FormatDivisibleMP(amount)));
3564  }
3565  else
3566  {
3567  recipient.push_back(Pair("amount", FormatIndivisibleMP(amount)));
3568  }
3569  *total += amount;
3570  recipientArray->push_back(recipient);
3571  ++count;
3572  }
3573  }
3574  }
3575  }
3576  }
3577 
3578  delete it;
3579  return;
3580 }
3581 
3582 bool CMPSTOList::exists(string address)
3583 {
3584  if (!sdb) return false;
3585 
3586  string strValue;
3587  Status status = sdb->Get(readoptions, address, &strValue);
3588 
3589  if (!status.ok())
3590  {
3591  if (status.IsNotFound()) return false;
3592  }
3593 
3594  return true;
3595 }
3596 
3597 void CMPSTOList::recordSTOReceive(string address, const uint256 &txid, int nBlock, unsigned int propertyId, uint64_t amount)
3598 {
3599  if (!sdb) return;
3600 
3601  bool addressExists = s_stolistdb->exists(address);
3602  if (addressExists)
3603  {
3604  //retrieve existing record
3605  std::vector<std::string> vstr;
3606  string strValue;
3607  Status status = sdb->Get(readoptions, address, &strValue);
3608  if (status.ok())
3609  {
3610  // add details to record
3611  // see if we are overwriting (check)
3612  size_t txidMatch = strValue.find(txid.ToString());
3613  if(txidMatch!=std::string::npos) file_log("STODEBUG : Duplicating entry for %s : %s\n",address,txid.ToString());
3614 
3615  const string key = address;
3616  const string newValue = strprintf("%s:%d:%u:%lu,", txid.ToString(), nBlock, propertyId, amount);
3617  strValue += newValue;
3618  // write updated record
3619  Status status;
3620  if (sdb)
3621  {
3622  status = sdb->Put(writeoptions, key, strValue);
3623  file_log("STODBDEBUG : %s(): %s, line %d, file: %s\n", __FUNCTION__, status.ToString().c_str(), __LINE__, __FILE__);
3624  }
3625  }
3626  }
3627  else
3628  {
3629  const string key = address;
3630  const string value = strprintf("%s:%d:%u:%lu,", txid.ToString(), nBlock, propertyId, amount);
3631  Status status;
3632  if (sdb)
3633  {
3634  status = sdb->Put(writeoptions, key, value);
3635  file_log("STODBDEBUG : %s(): %s, line %d, file: %s\n", __FUNCTION__, status.ToString().c_str(), __LINE__, __FILE__);
3636  }
3637  }
3638 }
3639 
3641 {
3642  int count = 0;
3643  Slice skey, svalue;
3644 
3645  readoptions.fill_cache = false;
3646 
3647  Iterator* it = sdb->NewIterator(readoptions);
3648 
3649  for(it->SeekToFirst(); it->Valid(); it->Next())
3650  {
3651  skey = it->key();
3652  svalue = it->value();
3653  ++count;
3654  printf("entry #%8d= %s:%s\n", count, skey.ToString().c_str(), svalue.ToString().c_str());
3655  }
3656 
3657  delete it;
3658 }
3659 
3661 {
3662  file_log("CMPSTOList stats: tWritten= %d , tRead= %d\n", sWritten, sRead);
3663 }
3664 
3665 // delete any STO receipts after blockNum
3667 {
3668  leveldb::Slice skey, svalue;
3669  unsigned int count = 0;
3670  std::vector<std::string> vstr;
3671  unsigned int n_found = 0;
3672  leveldb::Iterator* it = sdb->NewIterator(iteroptions);
3673  for(it->SeekToFirst(); it->Valid(); it->Next())
3674  {
3675  skey = it->key();
3676  string address = skey.ToString();
3677  svalue = it->value();
3678  ++count;
3679  string strvalue = it->value().ToString();
3680  boost::split(vstr, strvalue, boost::is_any_of(","), token_compress_on);
3681  string newValue = "";
3682  bool needsUpdate = false;
3683  for(uint32_t i = 0; i<vstr.size(); i++)
3684  {
3685  std::vector<std::string> svstr;
3686  boost::split(svstr, vstr[i], boost::is_any_of(":"), token_compress_on);
3687  if(4 == svstr.size())
3688  {
3689  if(atoi(svstr[1]) <= blockNum) { newValue += vstr[i]; } else { needsUpdate = true; } // add back to new key
3690  }
3691  }
3692 
3693  if(needsUpdate)
3694  {
3695  ++n_found;
3696  const string key = address;
3697  // write updated record
3698  Status status;
3699  if (sdb)
3700  {
3701  status = sdb->Put(writeoptions, key, newValue);
3702  file_log("DEBUG STO - rewriting STO data after reorg\n");
3703  file_log("STODBDEBUG : %s(): %s, line %d, file: %s\n", __FUNCTION__, status.ToString().c_str(), __LINE__, __FILE__);
3704  }
3705  }
3706  }
3707 
3708  printf("%s(%d); stodb n_found= %d\n", __FUNCTION__, blockNum, n_found);
3709 
3710  delete it;
3711 
3712  return (n_found);
3713 }
3714 
3715 // MPTradeList here
3716 bool CMPTradeList::getMatchingTrades(const uint256 txid, unsigned int propertyId, Array *tradeArray, uint64_t *totalSold, uint64_t *totalBought)
3717 {
3718  if (!tdb) return false;
3719  leveldb::Slice skey, svalue;
3720  unsigned int count = 0;
3721  std::vector<std::string> vstr;
3722  string txidStr = txid.ToString();
3723  leveldb::Iterator* it = tdb->NewIterator(iteroptions);
3724  for(it->SeekToFirst(); it->Valid(); it->Next())
3725  {
3726  skey = it->key();
3727  svalue = it->value();
3728  string strkey = it->key().ToString();
3729  size_t txidMatch = strkey.find(txidStr);
3730  if(txidMatch!=std::string::npos)
3731  {
3732  // we have a matching trade involving this txid
3733  // get the txid of the match
3734  string matchTxid;
3735  // make sure string is correct length
3736  if (strkey.length() == 129)
3737  {
3738  if (txidMatch==0) { matchTxid = strkey.substr(65,64); } else { matchTxid = strkey.substr(0,64); }
3739 
3740  string strvalue = it->value().ToString();
3741  boost::split(vstr, strvalue, boost::is_any_of(":"), token_compress_on);
3742  if (7 == vstr.size()) // ensure there are the expected amount of tokens
3743  {
3744  string address;
3745  string address1 = vstr[0];
3746  string address2 = vstr[1];
3747  unsigned int prop1 = 0;
3748  unsigned int prop2 = 0;
3749  uint64_t uAmount1 = 0;
3750  uint64_t uAmount2 = 0;
3751  uint64_t nBought = 0;
3752  uint64_t nSold = 0;
3753  string amountBought;
3754  string amountSold;
3755  string amount1;
3756  string amount2;
3757  prop1 = boost::lexical_cast<unsigned int>(vstr[2]);
3758  prop2 = boost::lexical_cast<unsigned int>(vstr[3]);
3759  uAmount1 = boost::lexical_cast<uint64_t>(vstr[4]);
3760  uAmount2 = boost::lexical_cast<uint64_t>(vstr[5]);
3761  if(isPropertyDivisible(prop1))
3762  { amount1 = FormatDivisibleMP(uAmount1); }
3763  else
3764  { amount1 = FormatIndivisibleMP(uAmount1); }
3765  if(isPropertyDivisible(prop2))
3766  { amount2 = FormatDivisibleMP(uAmount2); }
3767  else
3768  { amount2 = FormatIndivisibleMP(uAmount2); }
3769 
3770  // correct orientation of trade
3771  if (prop1 == propertyId)
3772  {
3773  address = address1;
3774  amountBought = amount2;
3775  amountSold = amount1;
3776  nBought = uAmount2;
3777  nSold = uAmount1;
3778  }
3779  else
3780  {
3781  address = address2;
3782  amountBought = amount1;
3783  amountSold = amount2;
3784  nBought = uAmount1;
3785  nSold = uAmount2;
3786  }
3787  int blockNum = atoi(vstr[6]);
3788  Object trade;
3789  trade.push_back(Pair("txid", matchTxid));
3790  trade.push_back(Pair("address", address));
3791  trade.push_back(Pair("block", blockNum));
3792  trade.push_back(Pair("amountsold", amountSold));
3793  trade.push_back(Pair("amountbought", amountBought));
3794  tradeArray->push_back(trade);
3795  ++count;
3796  *totalBought += nBought;
3797  *totalSold += nSold;
3798  }
3799  }
3800  }
3801  }
3802  delete it;
3803  if (count) { return true; } else { return false; }
3804 }
3805 
3806 void CMPTradeList::recordTrade(const uint256 txid1, const uint256 txid2, string address1, string address2, unsigned int prop1, unsigned int prop2, uint64_t amount1, uint64_t amount2, int blockNum)
3807 {
3808  if (!tdb) return;
3809  const string key = txid1.ToString() + "+" + txid2.ToString();
3810  const string value = strprintf("%s:%s:%u:%u:%lu:%lu:%d", address1, address2, prop1, prop2, amount1, amount2, blockNum);
3811  Status status;
3812  if (tdb)
3813  {
3814  status = tdb->Put(writeoptions, key, value);
3815  ++tWritten;
3816  if (msc_debug_tradedb) file_log("%s(): %s\n", __FUNCTION__, status.ToString().c_str());
3817  }
3818 }
3819 
3820 // delete any trades after blockNum
3822 {
3823  leveldb::Slice skey, svalue;
3824  unsigned int count = 0;
3825  std::vector<std::string> vstr;
3826  int block;
3827  unsigned int n_found = 0;
3828  leveldb::Iterator* it = tdb->NewIterator(iteroptions);
3829  for(it->SeekToFirst(); it->Valid(); it->Next())
3830  {
3831  skey = it->key();
3832  svalue = it->value();
3833  ++count;
3834  string strvalue = it->value().ToString();
3835  boost::split(vstr, strvalue, boost::is_any_of(":"), token_compress_on);
3836  // only care about the block number/height here
3837  if (7 == vstr.size())
3838  {
3839  block = atoi(vstr[6]);
3840 
3841  if (block >= blockNum)
3842  {
3843  ++n_found;
3844  file_log("%s() DELETING FROM TRADEDB: %s=%s\n", __FUNCTION__, skey.ToString().c_str(), svalue.ToString().c_str());
3845  tdb->Delete(writeoptions, skey);
3846  }
3847  }
3848  }
3849 
3850  printf("%s(%d); tradedb n_found= %d\n", __FUNCTION__, blockNum, n_found);
3851 
3852  delete it;
3853 
3854  return (n_found);
3855 }
3856 
3858 {
3859  file_log("CMPTradeList stats: tWritten= %d , tRead= %d\n", tWritten, tRead);
3860 }
3861 
3863 {
3864  int count = 0;
3865  Slice skey, svalue;
3866  readoptions.fill_cache = false;
3867  Iterator* it = tdb->NewIterator(readoptions);
3868  for(it->SeekToFirst(); it->Valid(); it->Next())
3869  {
3870  ++count;
3871  }
3872  delete it;
3873  return count;
3874 }
3875 
3877 {
3878  int count = 0;
3879  Slice skey, svalue;
3880 
3881  readoptions.fill_cache = false;
3882 
3883  Iterator* it = tdb->NewIterator(readoptions);
3884 
3885  for(it->SeekToFirst(); it->Valid(); it->Next())
3886  {
3887  skey = it->key();
3888  svalue = it->value();
3889  ++count;
3890  printf("entry #%8d= %s:%s\n", count, skey.ToString().c_str(), svalue.ToString().c_str());
3891  }
3892 
3893  delete it;
3894 }
3895 
3896 // global wrapper, block numbers are inclusive, if ending_block is 0 top of the chain will be used
3897 bool mastercore::isMPinBlockRange(int starting_block, int ending_block, bool bDeleteFound)
3898 {
3899  if (!p_txlistdb) return false;
3900 
3901  if (0 == ending_block) ending_block = GetHeight(); // will scan 'til the end
3902 
3903  return p_txlistdb->isMPinBlockRange(starting_block, ending_block, bDeleteFound);
3904 }
3905 
3906 // call it like so (variable # of parameters):
3907 // int block = 0;
3908 // ...
3909 // uint64_t nNew = 0;
3910 //
3911 // if (getValidMPTX(txid, &block, &type, &nNew)) // if true -- the TX is a valid MP TX
3912 //
3913 bool mastercore::getValidMPTX(const uint256 &txid, int *block, unsigned int *type, uint64_t *nAmended)
3914 {
3915 string result;
3916 int validity = 0;
3917 
3918  if (msc_debug_txdb) file_log("%s()\n", __FUNCTION__);
3919 
3920  if (!p_txlistdb) return false;
3921 
3922  if (!p_txlistdb->getTX(txid, result)) return false;
3923 
3924  // parse the string returned, find the validity flag/bit & other parameters
3925  std::vector<std::string> vstr;
3926  boost::split(vstr, result, boost::is_any_of(":"), token_compress_on);
3927 
3928  file_log("%s() size=%lu : %s\n", __FUNCTION__, vstr.size(), result.c_str());
3929 
3930  if (1 <= vstr.size()) validity = atoi(vstr[0]);
3931 
3932  if (block)
3933  {
3934  if (2 <= vstr.size()) *block = atoi(vstr[1]);
3935  else *block = 0;
3936  }
3937 
3938  if (type)
3939  {
3940  if (3 <= vstr.size()) *type = atoi(vstr[2]);
3941  else *type = 0;
3942  }
3943 
3944  if (nAmended)
3945  {
3946  if (4 <= vstr.size()) *nAmended = boost::lexical_cast<boost::uint64_t>(vstr[3]);
3947  else nAmended = 0;
3948  }
3949 
3951 
3952  if ((int)0 == validity) return false;
3953 
3954  return true;
3955 }
3956 
3957 std::string CScript::mscore_parse(std::vector<std::string>&msc_parsed, bool bNoBypass) const
3958 {
3959  int count = 0;
3960  std::string str;
3961  opcodetype opcode;
3962  std::vector<unsigned char> vch;
3963  const_iterator pc = begin();
3964  while (pc < end())
3965  {
3966  if (!str.empty())
3967  {
3968  str += "\n";
3969  }
3970  if (!GetOp(pc, opcode, vch))
3971  {
3972  str += "[error]";
3973  return str;
3974  }
3975  if (0 <= opcode && opcode <= OP_PUSHDATA4)
3976  {
3977  str += ValueString(vch);
3978  if (count || bNoBypass) msc_parsed.push_back(ValueString(vch));
3979  count++;
3980  }
3981  else
3982  {
3983  str += GetOpName(opcode);
3984  }
3985  }
3986  return str;
3987 }
3988 
3989 int mastercore_handler_block_begin(int nBlockPrev, CBlockIndex const * pBlockIndex) {
3990  if (reorgRecoveryMode > 0) {
3991  reorgRecoveryMode = 0; // clear reorgRecovery here as this is likely re-entrant
3992 
3993  // reset states
3995  p_txlistdb->isMPinBlockRange(pBlockIndex->nHeight, reorgRecoveryMaxHeight, true);
3996  t_tradelistdb->deleteAboveBlock(pBlockIndex->nHeight);
3997  s_stolistdb->deleteAboveBlock(pBlockIndex->nHeight);
3998  reorgRecoveryMaxHeight = 0;
3999 
4000 
4001  nWaterlineBlock = GENESIS_BLOCK - 1;
4002  if (isNonMainNet()) nWaterlineBlock = START_TESTNET_BLOCK - 1;
4003  if (RegTest()) nWaterlineBlock = START_REGTEST_BLOCK - 1;
4004 
4005 
4006  if(readPersistence()) {
4007  int best_state_block = load_most_relevant_state();
4008  if (best_state_block < 0) {
4009  // unable to recover easily, remove stale stale state bits and reparse from the beginning.
4010  clear_all_state();
4011  } else {
4012  nWaterlineBlock = best_state_block;
4013  }
4014  }
4015 
4016  if (nWaterlineBlock < nBlockPrev) {
4017  // scan from the block after the best active block to catch up to the active chain
4018  msc_initial_scan(nWaterlineBlock + 1);
4019  }
4020  }
4021 
4022  if (0 < nBlockTop)
4023  if (nBlockTop < nBlockPrev + 1)
4024  return 0;
4025 
4026  (void) eraseExpiredCrowdsale(pBlockIndex);
4027 
4028  return 0;
4029 }
4030 
4031 // called once per block, after the block has been processed
4032 // TODO: consolidate into *handler_block_begin() << need to adjust Accept expiry check.............
4033 // it performs cleanup and other functions
4034 int mastercore_handler_block_end(int nBlockNow, CBlockIndex const * pBlockIndex,
4035  unsigned int countMP) {
4036  if (!mastercoreInitialized) {
4037  mastercore_init();
4038  }
4039 
4040  if (0 < nBlockTop)
4041  if (nBlockTop < nBlockNow)
4042  return 0;
4043 
4044 // for every new received block must do:
4045 // 1) remove expired entries from the accept list (per spec accept entries are valid until their blocklimit expiration; because the customer can keep paying BTC for the offer in several installments)
4046 // 2) update the amount in the Exodus address
4047  uint64_t devmsc = 0;
4048  unsigned int how_many_erased = eraseExpiredAccepts(nBlockNow);
4049 
4050  if (how_many_erased)
4051  file_log("%s(%d); erased %u accepts this block, line %d, file: %s\n",
4052  __FUNCTION__, how_many_erased, nBlockNow, __LINE__, __FILE__);
4053 
4054  // calculate devmsc as of this block and update the Exodus' balance
4055  devmsc = calculate_and_update_devmsc(pBlockIndex->GetBlockTime());
4056 
4057  if (msc_debug_exo)
4058  file_log("devmsc for block %d: %lu, Exodus balance: %lu\n", nBlockNow,
4060 
4061  // get the total MSC for this wallet, for QT display
4062  (void) set_wallet_totals();
4063 
4064  // check the alert status, do we need to do anything else here?
4065  (void) checkExpiredAlerts(nBlockNow, pBlockIndex->GetBlockTime());
4066 
4067  // save out the state after this block
4068  if (writePersistence(nBlockNow))
4069  mastercore_save_state(pBlockIndex);
4070 
4071  return 0;
4072 }
4073 
4074 int mastercore_handler_disc_begin(int nBlockNow, CBlockIndex const * pBlockIndex)
4075 {
4076  reorgRecoveryMode = 1;
4077  reorgRecoveryMaxHeight = (pBlockIndex->nHeight > reorgRecoveryMaxHeight) ? pBlockIndex->nHeight: reorgRecoveryMaxHeight;
4078  return 0;
4079 }
4080 
4081 int mastercore_handler_disc_end(int nBlockNow, CBlockIndex const * pBlockIndex) {
4082  return 0;
4083 }
4084 
4085 const std::string ExodusAddress()
4086 {
4087  return string(exodus_address);
4088 }
4089 
4090 const std::string NotificationAddress()
4091 {
4092 static const string addr = "1MpNote1jsHkbQLwEmgoMr29EoUC1nyxxV";
4093 
4094  if (isNonMainNet()) {}; // TODO pick a notification address for TestNet
4095 
4096  return addr;
4097 }
4098 
4099  // the 31-byte packet & the packet #
4100  // int interpretPacket(int blocknow, unsigned char pkt[], int size)
4101  //
4102  // RETURNS: 0 if the packet is fully valid
4103  // RETURNS: <0 if the packet is invalid
4104  // RETURNS: >0 the only known case today is: return PKT_RETURNED_OBJECT
4105  //
4106  //
4107  // the following functions may augment the amount in question (nValue):
4108  // DEx_offerCreate()
4109  // DEx_offerUpdate()
4110  // DEx_acceptCreate()
4111  // DEx_payment() -- DOES NOT fit nicely into the model, as it currently is NOT a MP TX (not even in leveldb) -- gotta rethink
4112  //
4113  // optional: provide the pointer to the CMPOffer object, it will get filled in
4114  // verify that it does via if (MSC_TYPE_TRADE_OFFER == mp_obj.getType())
4115  //
4117 {
4118 int rc = PKT_ERROR;
4119 int step_rc;
4120 std::string new_global_alert_message;
4121 
4122  if (0>step1()) return -98765;
4123 
4124  if ((obj_o) && (MSC_TYPE_TRADE_OFFER != type)) return -777; // can't fill in the Offer object !
4125  if ((mdex_o) && (MSC_TYPE_METADEX != type)) return -778; // can't fill in the MetaDEx object !
4126 
4127  // further processing for complex types
4128  // TODO: version may play a role here !
4129  switch(type)
4130  {
4131  case MSC_TYPE_SIMPLE_SEND:
4132  step_rc = step2_Value();
4133  if (0>step_rc) return step_rc;
4134 
4135  rc = logicMath_SimpleSend();
4136  break;
4137 
4138  case MSC_TYPE_TRADE_OFFER:
4139  step_rc = step2_Value();
4140  if (0>step_rc) return step_rc;
4141 
4142  rc = logicMath_TradeOffer(obj_o);
4143  break;
4144 
4146  step_rc = step2_Value();
4147  if (0>step_rc) return step_rc;
4148 
4149  rc = logicMath_AcceptOffer_BTC();
4150  break;
4151 
4153  {
4154  const char *p = step2_SmartProperty(step_rc);
4155  if (0>step_rc) return step_rc;
4156  if (!p) return (PKT_ERROR_SP -11);
4157 
4158  step_rc = step3_sp_fixed(p);
4159  if (0>step_rc) return step_rc;
4160 
4161  if (0 == step_rc)
4162  {
4163  CMPSPInfo::Entry newSP;
4164  newSP.issuer = sender;
4165  newSP.txid = txid;
4166  newSP.prop_type = prop_type;
4167  newSP.num_tokens = nValue;
4168  newSP.category.assign(category);
4169  newSP.subcategory.assign(subcategory);
4170  newSP.name.assign(name);
4171  newSP.url.assign(url);
4172  newSP.data.assign(data);
4173  newSP.fixed = true;
4174  newSP.creation_block = newSP.update_block = chainActive[block]->GetBlockHash();
4175 
4176  const unsigned int id = _my_sps->putSP(ecosystem, newSP);
4177  update_tally_map(sender, id, nValue, BALANCE);
4178  }
4179  rc = 0;
4180  break;
4181  }
4182 
4184  {
4185  const char *p = step2_SmartProperty(step_rc);
4186  if (0>step_rc) return step_rc;
4187  if (!p) return (PKT_ERROR_SP -12);
4188 
4189  step_rc = step3_sp_variable(p);
4190  if (0>step_rc) return step_rc;
4191 
4192  // check if one exists for this address already !
4193  if (NULL != getCrowd(sender)) return (PKT_ERROR_SP -20);
4194 
4195  // must check that the desired property exists in our universe
4196  if (false == _my_sps->hasSP(property)) return (PKT_ERROR_SP -30);
4197 
4198  if (0 == step_rc)
4199  {
4200  CMPSPInfo::Entry newSP;
4201  newSP.issuer = sender;
4202  newSP.txid = txid;
4203  newSP.prop_type = prop_type;
4204  newSP.num_tokens = nValue;
4205  newSP.category.assign(category);
4206  newSP.subcategory.assign(subcategory);
4207  newSP.name.assign(name);
4208  newSP.url.assign(url);
4209  newSP.data.assign(data);
4210  newSP.fixed = false;
4211  newSP.property_desired = property;
4212  newSP.deadline = deadline;
4213  newSP.early_bird = early_bird;
4214  newSP.percentage = percentage;
4215  newSP.creation_block = newSP.update_block = chainActive[block]->GetBlockHash();
4216 
4217  const unsigned int id = _my_sps->putSP(ecosystem, newSP);
4218  my_crowds.insert(std::make_pair(sender, CMPCrowd(id, nValue, property, deadline, early_bird, percentage, 0, 0)));
4219  file_log("CREATED CROWDSALE id: %u value: %lu property: %u\n", id, nValue, property);
4220  }
4221  rc = 0;
4222  break;
4223  }
4224 
4226  {
4227  CrowdMap::iterator it = my_crowds.find(sender);
4228 
4229  if (it != my_crowds.end())
4230  {
4231  // retrieve the property id from the incoming packet
4232  memcpy(&property, &pkt[4], 4);
4233  swapByteOrder32(property);
4234 
4235  if (msc_debug_sp) file_log("%s() trying to ERASE CROWDSALE for propid= %u=%X\n", __FUNCTION__, property, property);
4236 
4237  // ensure we are closing the crowdsale which we opened by checking the property
4238  if ((it->second).getPropertyId() != property)
4239  {
4240  rc = (PKT_ERROR_SP -606);
4241  break;
4242  }
4243 
4244  dumpCrowdsaleInfo(it->first, it->second);
4245 
4246  // Begin calculate Fractional
4247 
4248  CMPCrowd &crowd = it->second;
4249 
4250  CMPSPInfo::Entry sp;
4251  _my_sps->getSP(crowd.getPropertyId(), sp);
4252 
4253  //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());
4254 
4255  double missedTokens = calculateFractional(sp.prop_type,
4256  sp.early_bird,
4257  sp.deadline,
4258  sp.num_tokens,
4259  sp.percentage,
4260  crowd.getDatabase(),
4261  crowd.getIssuerCreated());
4262 
4263  //file_log("\nValues coming out of calculateFractional(): Total tokens, Tokens created, Tokens for issuer, amountMissed: issuer %s %ld %ld %ld %f\n",sp.issuer.c_str(), crowd.getUserCreated() + crowd.getIssuerCreated(), crowd.getUserCreated(), crowd.getIssuerCreated(), missedTokens);
4264  sp.historicalData = crowd.getDatabase();
4265  sp.update_block = chainActive[block]->GetBlockHash();
4266  sp.close_early = 1;
4267  sp.timeclosed = blockTime;
4268  sp.txid_close = txid;
4269  sp.missedTokens = (int64_t) missedTokens;
4270  _my_sps->updateSP(crowd.getPropertyId() , sp);
4271 
4272  update_tally_map(sp.issuer, crowd.getPropertyId(), missedTokens, BALANCE);
4273  //End
4274 
4275  my_crowds.erase(it);
4276 
4277  rc = 0;
4278  }
4279  break;
4280  }
4281 
4283  {
4284  const char *p = step2_SmartProperty(step_rc);
4285  if (0>step_rc) return step_rc;
4286  if (!p) return (PKT_ERROR_SP -11);
4287 
4288  if (0 == step_rc)
4289  {
4290  CMPSPInfo::Entry newSP;
4291  newSP.issuer = sender;
4292  newSP.txid = txid;
4293  newSP.prop_type = prop_type;
4294  newSP.category.assign(category);
4295  newSP.subcategory.assign(subcategory);
4296  newSP.name.assign(name);
4297  newSP.url.assign(url);
4298  newSP.data.assign(data);
4299  newSP.fixed = false;
4300  newSP.manual = true;
4301 
4302  const unsigned int id = _my_sps->putSP(ecosystem, newSP);
4303  file_log("CREATED MANUAL PROPERTY id: %u admin: %s \n", id, sender.c_str());
4304  }
4305  rc = 0;
4306  break;
4307  }
4308 
4310  step_rc = step2_Value();
4311  if (0>step_rc) return step_rc;
4312 
4313  rc = logicMath_GrantTokens();
4314  break;
4315 
4317  step_rc = step2_Value();
4318  if (0>step_rc) return step_rc;
4319 
4320  rc = logicMath_RevokeTokens();
4321  break;
4322 
4324  if (disable_Divs) break;
4325  else
4326  {
4327  step_rc = step2_Value();
4328  if (0>step_rc) return step_rc;
4329 
4330  boost::filesystem::path pathOwners = GetDataDir() / OWNERS_FILENAME;
4331  FILE *fp = fopen(pathOwners.string().c_str(), "a");
4332 
4333  if (fp)
4334  {
4335  printInfo(fp);
4336  }
4337  else
4338  {
4339  file_log("\nPROBLEM writing %s, errno= %d\n", OWNERS_FILENAME, errno);
4340  }
4341 
4342  rc = logicMath_SendToOwners(fp);
4343 
4344  if (fp) fclose(fp);
4345  }
4346  break;
4347 
4348  case MSC_TYPE_METADEX:
4349 #ifdef MY_HACK
4350 // if (304500 > block) return -31337;
4351 // if (305100 > block) return -31337;
4352 
4353 // if (304930 > block) return -31337;
4354 // if (307057 > block) return -31337;
4355 
4356 // if (307234 > block) return -31337;
4357 // if (307607 > block) return -31337;
4358 
4359  if (307057 > block) return -31337;
4360 #endif
4361  step_rc = step2_Value();
4362  if (0>step_rc) return step_rc;
4363 
4364  rc = logicMath_MetaDEx(mdex_o);
4365  break;
4366 
4368  // parse the property from the packet
4369  memcpy(&property, &pkt[4], 4);
4370  swapByteOrder32(property);
4371 
4372  rc = logicMath_ChangeIssuer();
4373  break;
4374 
4375  case MSC_TYPE_SAVINGS_MARK:
4376  rc = logicMath_SavingsMark();
4377  break;
4378 
4380  rc = logicMath_SavingsCompromised();
4381  break;
4382 
4384  // check the packet version is also FF
4385  if ((int)version == 65535)
4386  {
4387  rc = step2_Alert(&new_global_alert_message);
4388  if (rc == 0) global_alert_message = new_global_alert_message;
4389  // end of block handler will expire any old alerts
4390  }
4391  break;
4392 
4393  default:
4394 
4395  return (PKT_ERROR -100);
4396  }
4397 
4398  return rc;
4399 }
4400 
4402 {
4403 int rc = PKT_ERROR_SEND -1000;
4404 int invalid = 0; // unused
4405 
4406  if (!isTransactionTypeAllowed(block, property, type, version)) return (PKT_ERROR_SEND -22);
4407 
4408  if (sender.empty()) ++invalid;
4409  // special case: if can't find the receiver -- assume sending to itself !
4410  // may also be true for BTC payments........
4411  // TODO: think about this..........
4412  if (receiver.empty())
4413  {
4414  receiver = sender;
4415  }
4416  if (receiver.empty()) ++invalid;
4417 
4418  // insufficient funds check & return
4419  if (!update_tally_map(sender, property, - nValue, BALANCE))
4420  {
4421  return (PKT_ERROR -111);
4422  }
4423 
4424  update_tally_map(receiver, property, nValue, BALANCE);
4425 
4426  // is there a crowdsale running from this recepient ?
4427  {
4428  CMPCrowd *crowd;
4429 
4430  crowd = getCrowd(receiver);
4431 
4432  if (crowd && (crowd->getCurrDes() == property) )
4433  {
4434  CMPSPInfo::Entry sp;
4435  bool spFound = _my_sps->getSP(crowd->getPropertyId(), sp);
4436 
4437  file_log("INVESTMENT SEND to Crowdsale Issuer: %s\n", receiver.c_str());
4438 
4439  if (spFound)
4440  {
4441  //init this struct
4442  std::pair <uint64_t,uint64_t> tokens;
4443  //pass this in by reference to determine if max_tokens has been reached
4444  bool close_crowdsale = false;
4445  //get txid
4446  string sp_txid = sp.txid.GetHex().c_str();
4447 
4448  //Units going into the calculateFundraiser function must
4449  //match the unit of the fundraiser's property_type.
4450  //By default this means Satoshis in and satoshis out.
4451  //In the condition that your fundraiser is Divisible,
4452  //but you are accepting indivisible tokens, you must
4453  //account for 1.0 Div != 1 Indiv but actually 1.0 Div == 100000000 Indiv.
4454  //The unit must be shifted or your values will be incorrect,
4455  //that is what we check for below.
4456  if ( !(isPropertyDivisible(property)) ) {
4457  nValue = nValue * 1e8;
4458  }
4459 
4460  //file_log("\nValues going into calculateFundraiser(): hexid %s nValue %lu earlyBird %d deadline %lu blockTime %ld numProps %lu issuerPerc %d \n", txid.GetHex().c_str(), nValue, sp.early_bird, sp.deadline, (uint64_t) blockTime, sp.num_tokens, sp.percentage);
4461 
4462  // calc tokens per this fundraise
4463  calculateFundraiser(sp.prop_type, //u short
4464  nValue, // u int 64
4465  sp.early_bird, // u char
4466  sp.deadline, // u int 64
4467  (uint64_t) blockTime, // int 64
4468  sp.num_tokens, // u int 64
4469  sp.percentage, // u char
4470  getTotalTokens(crowd->getPropertyId()),
4471  tokens,
4472  close_crowdsale);
4473 
4474  //file_log(mp_fp,"\n before incrementing global tokens user: %ld issuer: %ld\n", crowd->getUserCreated(), crowd->getIssuerCreated());
4475 
4476  //getIssuerCreated() is passed into calcluateFractional() at close
4477  //getUserCreated() is a convenient way to get user created during a crowdsale
4478  crowd->incTokensUserCreated(tokens.first);
4479  crowd->incTokensIssuerCreated(tokens.second);
4480 
4481  //file_log(mp_fp,"\n after incrementing global tokens user: %ld issuer: %ld\n", crowd->getUserCreated(), crowd->getIssuerCreated());
4482 
4483  //init data to pass to txFundraiserData
4484  uint64_t txdata[] = { (uint64_t) nValue, (uint64_t) blockTime, (uint64_t) tokens.first, (uint64_t) tokens.second };
4485 
4486  std::vector<uint64_t> txDataVec(txdata, txdata + sizeof(txdata)/sizeof(txdata[0]) );
4487 
4488  //insert data
4489  crowd->insertDatabase(txid.GetHex().c_str(), txDataVec );
4490 
4491  //file_log(mp_fp,"\nValues coming out of calculateFundraiser(): hex %s: Tokens created, Tokens for issuer: %ld %ld\n",txid.GetHex().c_str(), tokens.first, tokens.second);
4492 
4493  //update sender/rec
4494  update_tally_map(sender, crowd->getPropertyId(), tokens.first, BALANCE);
4495  update_tally_map(receiver, crowd->getPropertyId(), tokens.second, BALANCE);
4496 
4497  // close crowdsale if we hit MAX_TOKENS
4498  if( close_crowdsale ) {
4499  eraseMaxedCrowdsale(receiver, blockTime, block);
4500  }
4501  }
4502  }
4503  }
4504 
4505  rc = 0;
4506 
4507  return rc;
4508 }
4509 
4511 {
4512 int rc = PKT_ERROR_STO -1000;
4513 
4514  if (!isTransactionTypeAllowed(block, property, type, version)) return (PKT_ERROR_STO -888);
4515 
4516  // totalTokens will be 0 for non-existing property
4517  int64_t totalTokens = getTotalTokens(property);
4518 
4519  file_log("\t Total Tokens: %s\n", FormatMP(property, totalTokens).c_str());
4520 
4521  if (0 >= totalTokens)
4522  {
4523  return (PKT_ERROR_STO -2);
4524  }
4525 
4526  // does the sender have enough of the property he's trying to "Send To Owners" ?
4527  if (getMPbalance(sender, property, BALANCE) < (int64_t)nValue)
4528  {
4529  return (PKT_ERROR_STO -3);
4530  }
4531 
4532  totalTokens = 0;
4533 
4534  typedef std::set<pair<int64_t, string>, SendToOwners_compare> OwnerAddrType;
4535  OwnerAddrType OwnerAddrSet;
4536 
4537  {
4538  for(map<string, CMPTally>::reverse_iterator my_it = mp_tally_map.rbegin(); my_it != mp_tally_map.rend(); ++my_it)
4539  {
4540  const string address = (my_it->first).c_str();
4541 
4542  // do not count the sender
4543  if (address == sender) continue;
4544 
4545  int64_t tokens = 0;
4546 
4547  tokens += getMPbalance(address, property, BALANCE);
4548  tokens += getMPbalance(address, property, SELLOFFER_RESERVE);
4549  tokens += getMPbalance(address, property, METADEX_RESERVE);
4550  tokens += getMPbalance(address, property, ACCEPT_RESERVE);
4551 
4552  if (tokens)
4553  {
4554  OwnerAddrSet.insert(make_pair(tokens, address));
4555  totalTokens += tokens;
4556  }
4557  }
4558  }
4559 
4560  file_log(" Excluding Sender: %s\n", FormatMP(property, totalTokens).c_str());
4561 
4562  // determine which property the fee will be paid in
4563  const unsigned int feeProperty = isTestEcosystemProperty(property) ? OMNI_PROPERTY_TMSC : OMNI_PROPERTY_MSC;
4564 
4565  uint64_t n_owners = 0;
4566  rc = 0; // almost good, the for-loop will set the error code if any
4567 
4568  for (unsigned int itern=0;itern<=1;itern++) // iteration number, loop executes twice - first time the dry run to collect n_owners
4569  { // two-iteration loop START
4570  // split up what was taken and distribute between all holders
4571  uint64_t owns, should_receive, will_really_receive, sent_so_far = 0;
4572  double percentage, piece;
4573  for(OwnerAddrType::reverse_iterator my_it = OwnerAddrSet.rbegin(); my_it != OwnerAddrSet.rend(); ++my_it)
4574  { // owners loop
4575  const string address = my_it->second;
4576 
4577  owns = my_it->first;
4578  percentage = (double) owns / (double) totalTokens;
4579  piece = percentage * nValue;
4580  should_receive = ceil(piece);
4581 
4582  // ensure that much is still available
4583  if ((nValue - sent_so_far) < should_receive)
4584  {
4585  will_really_receive = nValue - sent_so_far;
4586  }
4587  else
4588  {
4589  will_really_receive = should_receive;
4590  }
4591 
4592  sent_so_far += will_really_receive;
4593 
4594  if (itern)
4595  {
4596  // real execution of the loop
4597  if (!update_tally_map(sender, property, - will_really_receive, BALANCE))
4598  {
4599  return (PKT_ERROR_STO -1);
4600  }
4601 
4602  update_tally_map(address, property, will_really_receive, BALANCE);
4603 
4604  // add to stodb
4605  s_stolistdb->recordSTOReceive(address, txid, block, property, will_really_receive);
4606 
4607  if (sent_so_far >= nValue)
4608  {
4609  file_log("SendToOwners: DONE HERE : those who could get paid got paid, SOME DID NOT, but that's ok\n");
4610  break; // done here, everybody who could get paid got paid
4611  }
4612  }
4613  else
4614  {
4615  // dry run code
4616  ++n_owners;
4617 
4618  if (msc_debug_sto)
4619  file_log("%14lu = %s, perc= %20.10lf, piece= %20.10lf, should_get= %14lu, will_really_get= %14lu, sent_so_far= %14lu\n",
4620  owns, address.c_str(), percentage, piece, should_receive, will_really_receive, sent_so_far);
4621 
4622  // record the detailed info as needed
4623  if (fhandle) fprintf(fhandle, "%s = %s\n", address.c_str(), FormatMP(property, will_really_receive).c_str());
4624  }
4625  } // owners loop
4626 
4627  if (!itern) // first dummy iteration
4628  { // if first ITERATION BEGIN
4629  // make sure we found some owners
4630  if (0 >= n_owners)
4631  {
4632  return (PKT_ERROR_STO -4);
4633  }
4634 
4635  file_log("\t Owners: %lu\n", n_owners);
4636 
4637  const int64_t nXferFee = TRANSFER_FEE_PER_OWNER * n_owners;
4638  file_log("\t Transfer fee: %lu.%08lu %s\n", nXferFee/COIN, nXferFee%COIN, strMPProperty(feeProperty).c_str());
4639 
4640  // enough coins to pay the fee?
4641  if (getMPbalance(sender, feeProperty, BALANCE) < nXferFee)
4642  {
4643  return (PKT_ERROR_STO -5);
4644  }
4645 
4646  // special case check, only if distributing MSC or TMSC -- the property the fee will be paid in
4647  if (feeProperty == property)
4648  {
4649  if (getMPbalance(sender, feeProperty, BALANCE) < (int64_t)(nValue + nXferFee))
4650  {
4651  return (PKT_ERROR_STO -55);
4652  }
4653  }
4654 
4655  // burn MSC or TMSC here: take the transfer fee away from the sender
4656  if (!update_tally_map(sender, feeProperty, - nXferFee, BALANCE))
4657  {
4658  // impossible to reach this, the check was done just before (the check is not necessary since update_tally_map checks balances too)
4659  return (PKT_ERROR_STO -500);
4660  }
4661  } // if first ITERATION END
4662 
4663  // sent_so_far must equal nValue here
4664  if (sent_so_far != nValue)
4665  {
4666  file_log("sent_so_far= %14lu, nValue= %14lu, n_owners= %lu\n", sent_so_far, nValue, n_owners);
4667 
4668  // rc = ???
4669  }
4670  } // two-iteration loop END
4671 
4672  return rc;
4673 }
4674 
int msc_debug_metadex1
Definition: mastercore.cpp:121
uint32_t GetLatestBlockTime(void)
Definition: mastercore.cpp:168
const boost::filesystem::path & GetDataDir(bool fNetSpecific)
Definition: util.cpp:973
#define METADEX_ERROR
Definition: mastercore.h:126
std::string mscore_parse(std::vector< std::string > &msc_parsed, bool bNoBypass=true) const
int popBlock(uint256 const &block_hash)
int getNumberOfPurchases(const uint256 txid)
static bool bRawTX
Definition: mastercore.cpp:133
void SetHex(const char *psz)
Definition: uint256.h:305
uint64_t GetRand(uint64_t nMax)
Definition: util.cpp:186
const int msc_debug_script
Definition: mastercore.cpp:108
const int msc_debug_dex
Definition: mastercore.cpp:109
uint64_t global_MSC_total
Definition: mastercore.cpp:88
bool IsValid() const
Definition: base58.cpp:215
static int64_t selectCoins(const string &FromAddress, CCoinControl &coinControl, int64_t additional)
bool close_early
Definition: mastercore_sp.h:28
#define PKT_ERROR_SEND
Definition: mastercore.h:123
#define OMNICORE_VERSION_BASE
static char const *const statePrefix[NUM_FILETYPES]
void saveOffer(ofstream &file, SHA256_CTX *shaCtx) const
#define MAX_PACKETS
Definition: mastercore.h:51
string global_alert_message
Definition: mastercore.cpp:95
static string exodus_address
Definition: mastercore.cpp:67
int mastercore_handler_disc_begin(int nBlockNow, CBlockIndex const *pBlockIndex)
void saveAccept(ofstream &file, SHA256_CTX *shaCtx, string const &addr, string const &buyer) const
const int msc_debug_exo
Definition: mastercore.cpp:113
void Set(const uint256 &t, int b, unsigned int idx, int64_t bt)
bool fixed
Definition: mastercore_sp.h:38
bool IsScript() const
Definition: base58.cpp:244
bool isTestEcosystemProperty(unsigned int property)
Definition: mastercore.cpp:495
int input_globals_state_string(const string &s)
uint256 update_block
Definition: mastercore_sp.h:37
static void prune_state_files(CBlockIndex const *topIndex)
const_iterator begin() const
Definition: serialize.h:924
CMPSPInfo * _my_sps
Definition: mastercore.cpp:362
static uint64_t exodus_prev
Definition: mastercore.cpp:97
uint256 txid
Definition: mastercore_sp.h:35
static PendingMap my_pending
Definition: mastercore.cpp:365
CBlockIndex * pprev
Definition: main.h:695
Definition: init.h:13
int deleteAboveBlock(int blockNum)
int ClassB_send(const string &senderAddress, const string &receiverAddress, const string &redemptionAddress, const vector< unsigned char > &data, uint256 &txid, int64_t additional=0)
bool getTX(const uint256 &txid, string &value)
static int write_mp_metadex(ofstream &file, SHA256_CTX *shaCtx)
Definition: core.h:396
std::map< CTxDestination, CAddressBookData > mapAddressBook
Definition: wallet.h:173
static int reorgRecoveryMaxHeight
Definition: mastercore.cpp:131
CCriticalSection cs_wallet
Main wallet lock.
Definition: wallet.h:132
static uint64_t exodus_balance
Definition: mastercore.cpp:98
static int write_globals_state(ofstream &file, SHA256_CTX *shaCtx)
const int msc_debug_send
Definition: mastercore.cpp:110
md_PricesMap * get_Prices(unsigned int prop)
bool isMainEcosystemProperty(unsigned int property)
Definition: mastercore.cpp:502
int input_msc_balances_string(const string &s)
bool exists(const uint256 &txid)
static int write_state_file(CBlockIndex const *pBlockIndex, int what)
string data
Definition: mastercore_sp.h:18
int mastercore_handler_tx(const CTransaction &tx, int nBlock, unsigned int idx, CBlockIndex const *pBlockIndex)
void init(unsigned int nextSPID=0x3UL, unsigned int nextTestSPID=TEST_ECO_PROPERTY_1)
int parseTransaction(bool bRPConly, const CTransaction &wtx, int nBlock, unsigned int idx, CMPTransaction *mp_tx, unsigned int nTime)
const int msc_debug_sp
Definition: mastercore.cpp:115
bool TestNet()
Definition: chainparams.h:100
int logicMath_SimpleSend(void)
void StartShutdown()
Definition: init.cpp:99
bool exists(string address)
bool update_tally_map(string who, unsigned int which_currency, int64_t amount, TallyType ttype)
Definition: mastercore.cpp:687
uint64_t getCurrDes() const
std::string ToString() const
Definition: main.h:854
AcceptMap my_accepts
Definition: mastercore.cpp:360
cpp_dec_float_100 XDOUBLE
CCriticalSection cs_main
Definition: main.cpp:43
int64_t amount
Definition: mastercore.h:470
string issuer
Definition: mastercore_sp.h:11
bool getMatchingTrades(const uint256 txid, unsigned int propertyId, Array *tradeArray, uint64_t *totalSold, uint64_t *totalBought)
void swapByteOrder32(uint32_t &ui)
void recordMetaDExCancelTX(const uint256 &txidMaster, const uint256 &txidSub, bool fValid, int nBlock, unsigned int propertyId, uint64_t nValue)
static bool readPersistence()
Definition: mastercore.cpp:246
const int msc_debug_verbose
Definition: mastercore.cpp:104
uint256 GetHash() const
Definition: core.cpp:75
bool isMultiplicationOK(const uint64_t a, const uint64_t b)
Definition: mastercore.cpp:477
#define STR_PAYMENT_SUBKEY_TXID_PAYMENT_COMBO(txidStr)
Definition: mastercore_dex.h:9
CMPTally * getTally(const string &address)
Definition: mastercore.cpp:425
void saveCrowdSale(ofstream &file, SHA256_CTX *shaCtx, string const &addr) const
#define PKT_ERROR_STO
Definition: mastercore.h:122
#define strprintf
Definition: util.h:116
static FILE * fileout
Definition: mastercore.cpp:189
STL namespace.
uint64_t global_balance_reserved_testeco[100000]
Definition: mastercore.cpp:93
void getRecipients(const uint256 txid, string filterAddress, Array *recipientArray, uint64_t *total, uint64_t *stoFee)
#define TEST_ECO_PROPERTY_1
Definition: mastercore.h:22
Double ended buffer combining vector and stream-like interfaces.
Definition: serialize.h:839
static const int disableLevelDB
Definition: mastercore.cpp:126
const int msc_debug_tally
Definition: mastercore.cpp:114
unsigned char early_bird
Definition: mastercore_sp.h:24
int mastercore_init()
#define STR_ACCEPT_ADDR_PROP_ADDR_COMBO(_seller, _buyer)
Definition: mastercore_dex.h:8
bool hasSP(unsigned int spid)
base58-encoded Bitcoin addresses.
Definition: base58.h:101
std::map< string, CMPOffer > OfferMap
uint64_t num_tokens
Definition: mastercore_sp.h:19
bool fReindex
Definition: main.cpp:53
std::map< std::string, std::vector< uint64_t > > getDatabase() const
std::string DateTimeStrFormat(const char *pszFormat, int64_t nTime)
Definition: util.cpp:1429
const int msc_debug_verbose3
Definition: mastercore.cpp:106
static const string getmoney_testnet
Definition: mastercore.cpp:69
bool IsTrusted() const
Definition: wallet.h:669
std::map< string, CMPCrowd > CrowdMap
static bool isRangeOK(const uint64_t input)
Definition: mastercore.cpp:468
CTxDestination Get() const
Definition: base58.cpp:222
unsigned short prop_type
Definition: mastercore_sp.h:12
bool RegTest()
Definition: chainparams.h:105
#define OMNI_PROPERTY_MSC
Definition: mastercore.h:130
bool GetPubKey(const CKeyID &address, CPubKey &vchPubKeyOut) const
Definition: crypter.cpp:235
unsigned int init()
Definition: mastercore.h:212
CChain chainActive
The currently-connected chain of blocks.
Definition: main.cpp:48
uint256 txid_close
Definition: mastercore_sp.h:32
#define PUSH_BACK_BYTES(vector, value)
Pushes bytes to the end of a vector.
string src
Definition: mastercore.h:468
bool isPropertyDivisible(unsigned int propertyId)
unsigned int property_desired
Definition: mastercore_sp.h:22
volatile bool fReopenDebugLog
Definition: util.cpp:99
int deleteAboveBlock(int blockNum)
std::map< std::string, std::vector< uint64_t > > historicalData
Definition: mastercore_sp.h:43
int mastercore_handler_disc_end(int nBlockNow, CBlockIndex const *pBlockIndex)
Coin Control Features.
Definition: coincontrol.h:11
std::string p_arb(cpp_int quantity)
Definition: mastercore.cpp:733
int mastercore_handler_block_begin(int nBlockPrev, CBlockIndex const *pBlockIndex)
const int msc_debug_txdb
Definition: mastercore.cpp:117
static const int disable_Divs
Definition: mastercore.cpp:125
void recordPaymentTX(const uint256 &txid, bool fValid, int nBlock, unsigned int vout, unsigned int propertyId, uint64_t nValue, string buyer, string seller)
bool GetKeyID(CKeyID &keyID) const
Definition: base58.cpp:235
unsigned int eraseExpiredAccepts(int blockNow)
uint64_t timeclosed
Definition: mastercore_sp.h:31
void SetDestination(const CTxDestination &address)
Definition: script.cpp:1925
int getNumberOfMetaDExCancels(const uint256 txid)
int input_mp_offers_string(const string &s)
Definition: mastercore_sp.h:9
bool IsMyAddress(const std::string &address)
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)
std::string ValueString(const std::vector< unsigned char > &vch)
Definition: script.h:373
const char * url
Definition: rpcconsole.cpp:35
int input_mp_accepts_string(const string &s)
bool CreateTransaction(const std::vector< std::pair< CScript, int64_t > > &vecSend, CWalletTx &wtxNew, CReserveKey &reservekey, int64_t &nFeeRet, std::string &strFailReason, const CCoinControl *coinControl=NULL)
static bool writePersistence(int block_now)
Definition: mastercore.cpp:257
int step2_Alert(std::string *new_global_alert_message)
#define OMNI_PROPERTY_TMSC
Definition: mastercore.h:131
TransactionType
Definition: mastercore.h:54
CBlockIndex * Tip() const
Returns the index entry for the tip of this chain, or NULL if none.
Definition: main.h:1012
int msc_debug_metadex2
Definition: mastercore.cpp:122
bool getValidMPTX(const uint256 &txid, int *block=NULL, unsigned int *type=NULL, uint64_t *nAmended=NULL)
static int write_msc_balances(ofstream &file, SHA256_CTX *shaCtx)
uint64_t getIssuerCreated() const
int Height() const
Return the maximal height in the chain.
Definition: main.h:1043
const char * source
Definition: rpcconsole.cpp:36
opcodetype
Script opcodes.
Definition: script.h:223
void dumpCrowdsaleInfo(const string &address, CMPCrowd &crowd, bool bExpired=false)
bool IsSpent(const uint256 &hash, unsigned int n) const
Definition: wallet.cpp:319
int TXExodusFundraiser(const CTransaction &wtx, const string &sender, int64_t ExodusHighestValue, int nBlock, unsigned int nTime)
bool GetBoolArg(const std::string &strArg, bool fDefault)
Return boolean argument or default value.
Definition: util.cpp:519
unsigned int next()
Definition: mastercore.h:222
#define LogPrintf(...)
Definition: util.h:117
string category
Definition: mastercore_sp.h:14
bool isMPinBlockRange(int, int, bool)
#define MP_TX_PKT_V0
Definition: mastercore.h:41
int getMPTradeCountTotal()
string getLabel(const string &address)
unsigned int GetSerializeSize(char a, int, int=0)
Definition: serialize.h:105
int DEx_payment(uint256 txid, unsigned int vout, string seller, string buyer, uint64_t BTC_paid, int blockNow, uint64_t *nAmended=NULL)
OfferMap my_offers
Definition: mastercore.cpp:359
const int msc_debug_parser
Definition: mastercore.cpp:103
const std::string NotificationAddress()
CMPTradeList * t_tradelistdb
Definition: mastercore.cpp:156
#define LOCK(cs)
Definition: sync.h:156
static boost::filesystem::path MPPersistencePath
Definition: mastercore.cpp:100
void calculateFundraiser(unsigned short int propType, uint64_t amtTransfer, unsigned char bonusPerc, uint64_t fundraiserSecs, uint64_t currentSecs, uint64_t numProps, unsigned char issuerPerc, uint64_t totalTokens, std::pair< uint64_t, uint64_t > &tokens, bool &close_crowdsale)
Definition: mastercore.cpp:740
std::vector< CTxOut > vout
Definition: core.h:191
uint64_t rounduint64(long double ld)
Converts numbers to 64 bit wide unsigned integer whereby any signedness is ignored.
txnouttype
Definition: script.h:195
CTxDestination destChange
Definition: coincontrol.h:14
int setLastAlert(int blockHeight)
static const int txRestrictionsRules[][3]
Definition: mastercore.cpp:136
bool updateMoney(unsigned int which_property, int64_t amount, TallyType ttype)
Definition: mastercore.h:235
#define MAX_BTC_OUTPUTS
Definition: mastercore.h:45
An encapsulated public key.
Definition: key.h:42
std::vector< CTxIn > vin
Definition: core.h:190
void printAll()
int64_t GetDustLimit(const CScript &scriptPubKey)
#define OMNI_PROPERTY_BTC
Definition: mastercore.h:129
uint64_t global_balance_money_testeco[100000]
Definition: mastercore.cpp:92
bool isMPinBlockRange(int starting_block, int ending_block, bool bDeleteFound)
bool Solver(const CScript &scriptPubKey, txnouttype &typeRet, vector< vector< unsigned char > > &vSolutionsRet)
Definition: script.cpp:1186
uint64_t missedTokens
Definition: mastercore_sp.h:30
void printStats()
std::map< string, CMPTally > mp_tally_map
Definition: mastercore.cpp:423
uint64_t getNewAmount() const
Definition: mastercore_tx.h:88
md_PropertiesMap metadex
bool CommitTransaction(CWalletTx &wtxNew, CReserveKey &reservekey)
Definition: wallet.cpp:1401
bool isMetaDExOfferActive(const uint256 txid, unsigned int propertyId)
Definition: mastercore.cpp:509
static int pendingAdd(const uint256 &txid, const string &FromAddress, unsigned int propId, int64_t Amount)
Definition: mastercore.cpp:402
int GetHeight(void)
Definition: mastercore.cpp:160
void print(uint256 txid) const
Definition: mastercore.h:472
std::string ToString() const
Definition: base58.cpp:174
int64_t feeCheck(const string &address)
void recordSTOReceive(std::string, const uint256 &, int, unsigned int, uint64_t)
bool getSP(unsigned int spid, Entry &info)
uint64_t global_balance_reserved_maineco[100000]
Definition: mastercore.cpp:91
uint256 send_INTERNAL_1packet(const string &FromAddress, const string &ToAddress, const string &RedeemAddress, unsigned int PropertyID, uint64_t Amount, unsigned int PropertyID_2, uint64_t Amount_2, unsigned int TransactionType, int64_t additional, int *error_code=NULL)
static const string exodus_testnet
Definition: mastercore.cpp:68
string name
Definition: mastercore_sp.h:16
const int msc_debug_parser_data
Definition: mastercore.cpp:102
std::map< XDOUBLE, md_Set > md_PricesMap
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: core.h:22
static bool is_state_prefix(std::string const &str)
std::string GetHex() const
Definition: uint256.h:297
int64_t GetTime()
Definition: util.cpp:1215
uint256 findMetaDExCancel(const uint256 txid)
static CMPPending * pendingDelete(const uint256 txid, bool bErase=false)
Definition: mastercore.cpp:367
#define MAX_INT_8_BYTES
Definition: mastercore.h:26
std::string ToString() const
Definition: core.cpp:140
const int msc_debug_spec
Definition: mastercore.cpp:112
int64_t getTotalTokens(unsigned int propertyId, int64_t *n_owners_total=NULL)
Definition: mastercore.cpp:646
static int write_mp_accepts(ofstream &file, SHA256_CTX *shaCtx)
const unsigned char * begin() const
Definition: key.h:91
CCriticalSection cs_tally
Definition: mastercore.cpp:357
const char * GetOpName(opcodetype opcode)
Definition: script.cpp:80
int mastercore_save_state(CBlockIndex const *pBlockIndex)
virtual const CBlock & GenesisBlock() const =0
bool SetString(const char *psz, unsigned int nVersionBytes=1)
Definition: base58.cpp:154
#define STR_REF_SUBKEY_TXID_REF_COMBO(txidStr)
A transaction with a bunch of additional info that only the owner cares about.
Definition: wallet.h:451
void eraseMaxedCrowdsale(const string &address, uint64_t blockTime, int block)
bool fLogTimestamps
Definition: util.cpp:98
CrowdMap my_crowds
Definition: mastercore.cpp:363
string subcategory
Definition: mastercore_sp.h:15
std::string p128(int128_t quantity)
Definition: mastercore.cpp:728
#define PACKET_SIZE_CLASS_A
Definition: mastercore.h:49
void insertDatabase(std::string txhash, std::vector< uint64_t > txdata)
CMPTxList * p_txlistdb
Definition: mastercore.cpp:155
string getKeyValue(string key)
static int reorgRecoveryMode
Definition: mastercore.cpp:130
#define TRANSFER_FEE_PER_OWNER
Definition: mastercore.h:34
256-bit unsigned integer
Definition: uint256.h:531
static int nWaterlineBlock
Definition: mastercore.cpp:86
#define LOG_FILENAME
Definition: mastercore.h:16
static const int64_t COIN
Definition: util.h:38
std::set< CMPMetaDEx, MetaDEx_compare > md_Set
unsigned int nTime
Definition: core.h:352
bool getPurchaseDetails(const uint256 txid, int purchaseNumber, string *buyer, string *seller, uint64_t *vout, uint64_t *propertyId, uint64_t *nValue)
#define MP_TX_PKT_V1
Definition: mastercore.h:42
void setWatermark(uint256 const &watermark)
static int write_mp_offers(ofstream &file, SHA256_CTX *shaCtx)
bool ReadBlockFromDisk(CBlock &block, const CDiskBlockPos &pos)
Definition: main.cpp:1145
void printStats()
bool fPrintToConsole
Definition: util.cpp:92
unsigned char percentage
Definition: mastercore_sp.h:25
const int msc_debug_persistence
Definition: mastercore.cpp:119
bool ExtractDestinations(const CScript &scriptPubKey, txnouttype &typeRet, vector< CTxDestination > &addressRet, int &nRequiredRet)
Definition: script.cpp:1519
unsigned int putSP(unsigned char ecosystem, Entry const &info)
void saveOffer(ofstream &file, SHA256_CTX *shaCtx, string const &addr) const
string strMPProperty(unsigned int i)
Definition: mastercore.cpp:298
A key allocated from the key pool.
Definition: wallet.h:402
int set_wallet_totals()
Definition: mastercore.cpp:943
The block chain is a tree shaped structure starting with the genesis block at the root...
Definition: main.h:688
const CChainParams & Params()
Return the currently selected parameters.
void recordTX(const uint256 &txid, bool fValid, int nBlock, unsigned int type, uint64_t nValue)
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:401
#define PACKET_SIZE
Definition: mastercore.h:50
void * memcpy(void *a, const void *b, size_t c)
Definition: glibc_compat.cpp:7
void Select(COutPoint &output)
Definition: coincontrol.h:38
std::string ToString() const
Definition: uint256.h:340
uint64_t global_MSC_RESERVED_total
Definition: mastercore.cpp:89
static const int PROTOCOL_VERSION
Definition: version.h:29
void printStats()
md_Set * get_Indexes(md_PricesMap *p, XDOUBLE price)
static int mastercoreInitialized
Definition: mastercore.cpp:128
void SetMultisig(int nRequired, const std::vector< CPubKey > &keys)
Definition: script.cpp:1930
int getMPTransactionCountBlock(int block)
bool fPrintToDebugLog
Definition: util.cpp:93
static boost::once_flag mp_debugPrintInitFlag
Definition: mastercore.cpp:186
const std::string ExodusAddress()
CMPSTOList * s_stolistdb
Definition: mastercore.cpp:157
bool IsMine(const CKeyStore &keystore, const CTxDestination &dest)
Definition: script.cpp:1448
const int msc_debug_sto
Definition: mastercore.cpp:116
int getWatermark(uint256 &watermark)
A reference to a CKey: the Hash160 of its serialized public key.
Definition: key.h:26
std::string FormatIndivisibleMP(int64_t n)
Definition: mastercore.cpp:343
const int msc_debug_tokens
Definition: mastercore.cpp:111
bool ExtractDestination(const CScript &scriptPubKey, CTxDestination &addressRet)
Definition: script.cpp:1493
string url
Definition: mastercore_sp.h:17
int msc_initial_scan(int nHeight)
bool Contains(const CBlockIndex *pindex) const
Efficiently check whether a block is present in this chain.
Definition: main.h:1030
unsigned int peekNextSPID(unsigned char ecosystem)
static bool isAllowedOutputType(int whichType, int nBlock)
bool IsFullyValid() const
Definition: key.cpp:473
uint256 creation_block
Definition: mastercore_sp.h:36
A CWallet is an extension of a keystore, which also maintains a set of transactions and balances...
Definition: wallet.h:100
bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock, bool fAllowSlow)
Retrieve a transaction (from memory pool, or from disk, if possible)
Definition: main.cpp:1049
const int msc_debug_vin
Definition: mastercore.cpp:107
unsigned int prop
Definition: mastercore.h:469
void clear()
void incTokensUserCreated(uint64_t amount)
static string const watermarkKey
CMPCrowd * getCrowd(const string &address)
static int msc_file_load(const string &filename, int what, bool verifyHash=false)
const int msc_debug_verbose2
Definition: mastercore.cpp:105
std::map< uint256, CWalletTx > mapWallet
Definition: wallet.h:168
std::string FormatMP(unsigned int property, int64_t n, bool fSign)
Definition: mastercore.cpp:349
string FormatDivisibleMP(int64_t n, bool fSign)
Definition: mastercore.cpp:325
static int64_t nMinRelayTxFee
Fees smaller than this (in satoshi) are considered zero fee (for relaying and mining) ...
Definition: core.h:187
int const MAX_STATE_HISTORY
Definition: mastercore.h:20
void incTokensIssuerCreated(uint64_t amount)
static void clear_all_state()
static int load_most_relevant_state()
#define OWNERS_FILENAME
Definition: mastercore.h:18
std::vector< CTransaction > vtx
Definition: core.h:400
int msc_debug_metadex3
Definition: mastercore.cpp:123
#define MAX_SHA256_OBFUSCATION_TIMES
Definition: mastercore.h:47
boost::variant< CNoDestination, CKeyID, CScriptID > CTxDestination
A txout script template with a specific destination.
Definition: script.h:218
static boost::mutex * mutexDebugLog
Definition: mastercore.cpp:190
static const int nBlockTop
Definition: mastercore.cpp:83
int64_t GetAvailableCredit(bool fUseCache=true) const
Definition: wallet.h:618
The basic transaction that is broadcasted on the network and contained in blocks. ...
Definition: core.h:183
int nHeight
Definition: main.h:698
std::string getMasterCoreAlertString()
Definition: mastercore.cpp:530
static int write_mp_crowdsales(ofstream &file, SHA256_CTX *shaCtx)
uint64_t calculate_and_update_devmsc(unsigned int nTime)
Definition: mastercore.cpp:910
static const CCheckpointData data
Definition: checkpoints.cpp:56
int input_mp_crowdsale_string(const string &s)
int getMPTransactionCountTotal()
unsigned int eraseExpiredCrowdsale(CBlockIndex const *pBlockIndex)
#define PKT_ERROR_SP
Definition: mastercore.h:120
std::string HexStr(const T itbegin, const T itend, bool fSpaces=false)
Definition: util.h:263
uint64_t deadline
Definition: mastercore_sp.h:23
int64_t GetBlockTime() const
Definition: main.h:810
static void shrinkDebugFile()
Definition: mastercore.cpp:266
#define STR_SELLOFFER_ADDR_PROP_COMBO(x)
Definition: mastercore_dex.h:7
CKeyID GetID() const
Definition: key.h:131
bool checkExpiredAlerts(unsigned int curBlock, uint64_t curTime)
Definition: mastercore.cpp:535
int mastercore_shutdown()
unsigned int updateSP(unsigned int propertyID, Entry const &info)
static void mp_DebugPrintInit()
Definition: mastercore.cpp:192
unsigned int getPropertyId() const
void printAll()
void format(FormatIterator &fmtIter)
Definition: tinyformat.h:869
map< uint256, CBlockIndex * > mapBlockIndex
Definition: main.cpp:47
vector< unsigned char > ParseHex(const char *psz)
Definition: util.cpp:419
int64_t getMPbalance(const string &Address, unsigned int property, TallyType ttype)
Definition: mastercore.cpp:437
int interpretPacket(CMPOffer *obj_o=NULL, CMPMetaDEx *mdex_o=NULL)
bool isNonMainNet()
Definition: mastercore.cpp:319
std::map< uint256, CMPPending > PendingMap
Definition: mastercore.h:509
void swapByteOrder64(uint64_t &ull)
#define PKT_ERROR
Definition: mastercore.h:115
static void prepareObfuscatedHashes(const string &address, string(&ObfsHashes)[1+MAX_SHA256_OBFUSCATION_TIMES])
Definition: mastercore.cpp:990
const unsigned char * end() const
Definition: key.h:92
int64_t getUserAvailableMPbalance(const string &Address, unsigned int property)
Definition: mastercore.cpp:455
std::string getMySTOReceipts(string filterAddress)
std::map< string, CMPAccept > AcceptMap
static bool getOutputType(const CScript &scriptPubKey, txnouttype &whichTypeRet)
const int msc_debug_tradedb
Definition: mastercore.cpp:118
uint256 getHash() const
uint64_t global_balance_money_maineco[100000]
Definition: mastercore.cpp:90
CWallet * pwalletMain
int mp_LogPrintStr(const std::string &str)
Definition: mastercore.cpp:204
bool isTransactionTypeAllowed(int txBlock, unsigned int txProperty, unsigned int txType, unsigned short version, bool bAllowNullProperty=false)
Definition: mastercore.cpp:859
int atoi(const std::string &str)
Definition: util.h:242
uint256 GetBlockHash() const
Definition: main.h:805
void recordTrade(const uint256 txid1, const uint256 txid2, string address1, string address2, unsigned int prop1, unsigned int prop2, uint64_t amount1, uint64_t amount2, int blockNum)
bool HasSelected() const
Definition: coincontrol.h:27
bool manual
Definition: mastercore_sp.h:39
const_iterator end() const
Definition: serialize.h:926
int logicMath_SendToOwners(FILE *fp=NULL)
int mastercore_handler_block_end(int nBlockNow, CBlockIndex const *pBlockIndex, unsigned int countMP)
unsigned int getType() const
Definition: mastercore_tx.h:77
const uint256 * phashBlock
Definition: main.h:692
TallyType
Definition: mastercore.h:189