Raven Core  3.0.0
P2P Digital Currency
assets.cpp
Go to the documentation of this file.
1 // Copyright (c) 2017-2019 The Raven Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #include <regex>
6 #include <script/script.h>
7 #include <version.h>
8 #include <streams.h>
10 #include <iostream>
11 #include <script/standard.h>
12 #include <util.h>
13 #include <chainparams.h>
14 #include <base58.h>
15 #include <validation.h>
16 #include <txmempool.h>
17 #include <tinyformat.h>
18 #include <wallet/wallet.h>
19 #include <boost/algorithm/string.hpp>
20 #include <consensus/validation.h>
21 #include <rpc/protocol.h>
22 #include <net.h>
23 #include "assets.h"
24 #include "assetdb.h"
25 #include "assettypes.h"
26 #include "protocol.h"
27 #include "wallet/coincontrol.h"
28 #include "utilmoneystr.h"
29 #include "coins.h"
30 #include "wallet/wallet.h"
31 #include "LibBoolEE.h"
32 
33 #define SIX_MONTHS 15780000 // Six months worth of seconds
34 
35 #define OFFSET_THREE 3
36 #define OFFSET_FOUR 4
37 #define OFFSET_TWENTY_THREE 23
38 
39 
40 std::map<uint256, std::string> mapReissuedTx;
41 std::map<std::string, uint256> mapReissuedAssets;
42 
43 // excluding owner tag ('!')
44 static const auto MAX_NAME_LENGTH = 31;
45 static const auto MAX_CHANNEL_NAME_LENGTH = 12;
46 
47 // min lengths are expressed by quantifiers
48 static const std::regex ROOT_NAME_CHARACTERS("^[A-Z0-9._]{3,}$");
49 static const std::regex SUB_NAME_CHARACTERS("^[A-Z0-9._]+$");
50 static const std::regex UNIQUE_TAG_CHARACTERS("^[-A-Za-z0-9@$%&*()[\\]{}_.?:]+$");
51 static const std::regex MSGCHANNEL_TAG_CHARACTERS("^[A-Za-z0-9_]+$");
52 static const std::regex VOTE_TAG_CHARACTERS("^[A-Z0-9._]+$");
53 
54 // Restricted assets
55 static const std::regex QUALIFIER_NAME_CHARACTERS("#[A-Z0-9._]{3,}$");
56 static const std::regex SUB_QUALIFIER_NAME_CHARACTERS("#[A-Z0-9._]+$");
57 static const std::regex RESTRICTED_NAME_CHARACTERS("\\$[A-Z0-9._]{3,}$");
58 
59 static const std::regex DOUBLE_PUNCTUATION("^.*[._]{2,}.*$");
60 static const std::regex LEADING_PUNCTUATION("^[._].*$");
61 static const std::regex TRAILING_PUNCTUATION("^.*[._]$");
62 static const std::regex QUALIFIER_LEADING_PUNCTUATION("^[#\\$][._].*$"); // Used for qualifier assets, and restricted asset only
63 
64 static const std::string SUB_NAME_DELIMITER = "/";
65 static const std::string UNIQUE_TAG_DELIMITER = "#";
66 static const std::string MSGCHANNEL_TAG_DELIMITER = "~";
67 static const std::string VOTE_TAG_DELIMITER = "^";
68 static const std::string RESTRICTED_TAG_DELIMITER = "$";
69 
70 static const char RESTRICTED_TAG_CHAR = '$';
71 
72 static const std::regex UNIQUE_INDICATOR(R"(^[^^~#!]+#[^~#!\/]+$)");
73 static const std::regex MSGCHANNEL_INDICATOR(R"(^[^^~#!]+~[^~#!\/]+$)");
74 static const std::regex OWNER_INDICATOR(R"(^[^^~#!]+!$)");
75 static const std::regex VOTE_INDICATOR(R"(^[^^~#!]+\^[^~#!\/]+$)");
76 
77 static const std::regex QUALIFIER_INDICATOR("^[#][A-Z0-9._]{3,}$"); // Starts with #
78 static const std::regex SUB_QUALIFIER_INDICATOR("^#[A-Z0-9._]+\\/#[A-Z0-9._]+$"); // Starts with #
79 static const std::regex RESTRICTED_INDICATOR("^[\\$][A-Z0-9._]{3,}$"); // Starts with $
80 
81 static const std::regex RAVEN_NAMES("^RVN$|^RAVEN$|^RAVENCOIN$|^#RVN$|^#RAVEN$|^#RAVENCOIN$");
82 
83 bool IsRootNameValid(const std::string& name)
84 {
85  return std::regex_match(name, ROOT_NAME_CHARACTERS)
86  && !std::regex_match(name, DOUBLE_PUNCTUATION)
87  && !std::regex_match(name, LEADING_PUNCTUATION)
88  && !std::regex_match(name, TRAILING_PUNCTUATION)
89  && !std::regex_match(name, RAVEN_NAMES);
90 }
91 
92 bool IsQualifierNameValid(const std::string& name)
93 {
94  return std::regex_match(name, QUALIFIER_NAME_CHARACTERS)
95  && !std::regex_match(name, DOUBLE_PUNCTUATION)
96  && !std::regex_match(name, QUALIFIER_LEADING_PUNCTUATION)
97  && !std::regex_match(name, TRAILING_PUNCTUATION)
98  && !std::regex_match(name, RAVEN_NAMES);
99 }
100 
101 bool IsRestrictedNameValid(const std::string& name)
102 {
103  return std::regex_match(name, RESTRICTED_NAME_CHARACTERS)
104  && !std::regex_match(name, DOUBLE_PUNCTUATION)
105  && !std::regex_match(name, LEADING_PUNCTUATION)
106  && !std::regex_match(name, TRAILING_PUNCTUATION)
107  && !std::regex_match(name, RAVEN_NAMES);
108 }
109 
110 bool IsSubQualifierNameValid(const std::string& name)
111 {
112  return std::regex_match(name, SUB_QUALIFIER_NAME_CHARACTERS)
113  && !std::regex_match(name, DOUBLE_PUNCTUATION)
114  && !std::regex_match(name, LEADING_PUNCTUATION)
115  && !std::regex_match(name, TRAILING_PUNCTUATION);
116 }
117 
118 bool IsSubNameValid(const std::string& name)
119 {
120  return std::regex_match(name, SUB_NAME_CHARACTERS)
121  && !std::regex_match(name, DOUBLE_PUNCTUATION)
122  && !std::regex_match(name, LEADING_PUNCTUATION)
123  && !std::regex_match(name, TRAILING_PUNCTUATION);
124 }
125 
126 bool IsUniqueTagValid(const std::string& tag)
127 {
128  return std::regex_match(tag, UNIQUE_TAG_CHARACTERS);
129 }
130 
131 bool IsVoteTagValid(const std::string& tag)
132 {
133  return std::regex_match(tag, VOTE_TAG_CHARACTERS);
134 }
135 
136 bool IsMsgChannelTagValid(const std::string &tag)
137 {
138  return std::regex_match(tag, MSGCHANNEL_TAG_CHARACTERS)
139  && !std::regex_match(tag, DOUBLE_PUNCTUATION)
140  && !std::regex_match(tag, LEADING_PUNCTUATION)
141  && !std::regex_match(tag, TRAILING_PUNCTUATION);
142 }
143 
144 bool IsNameValidBeforeTag(const std::string& name)
145 {
146  std::vector<std::string> parts;
147  boost::split(parts, name, boost::is_any_of(SUB_NAME_DELIMITER));
148 
149  if (!IsRootNameValid(parts.front())) return false;
150 
151  if (parts.size() > 1)
152  {
153  for (unsigned long i = 1; i < parts.size(); i++)
154  {
155  if (!IsSubNameValid(parts[i])) return false;
156  }
157  }
158 
159  return true;
160 }
161 
162 bool IsQualifierNameValidBeforeTag(const std::string& name)
163 {
164  std::vector<std::string> parts;
165  boost::split(parts, name, boost::is_any_of(SUB_NAME_DELIMITER));
166 
167  if (!IsQualifierNameValid(parts.front())) return false;
168 
169  // Qualifiers can only have one sub qualifier under it
170  if (parts.size() > 2) {
171  return false;
172  }
173 
174  if (parts.size() > 1)
175  {
176 
177  for (unsigned long i = 1; i < parts.size(); i++)
178  {
179  if (!IsSubQualifierNameValid(parts[i])) return false;
180  }
181  }
182 
183  return true;
184 }
185 
186 bool IsAssetNameASubasset(const std::string& name)
187 {
188  std::vector<std::string> parts;
189  boost::split(parts, name, boost::is_any_of(SUB_NAME_DELIMITER));
190 
191  if (!IsRootNameValid(parts.front())) return false;
192 
193  return parts.size() > 1;
194 }
195 
196 bool IsAssetNameASubQualifier(const std::string& name)
197 {
198  std::vector<std::string> parts;
199  boost::split(parts, name, boost::is_any_of(SUB_NAME_DELIMITER));
200 
201  if (!IsQualifierNameValid(parts.front())) return false;
202 
203  return parts.size() > 1;
204 }
205 
206 
207 bool IsAssetNameValid(const std::string& name, AssetType& assetType, std::string& error)
208 {
209  assetType = AssetType::INVALID;
210  if (std::regex_match(name, UNIQUE_INDICATOR))
211  {
212  bool ret = IsTypeCheckNameValid(AssetType::UNIQUE, name, error);
213  if (ret)
214  assetType = AssetType::UNIQUE;
215 
216  return ret;
217  }
218  else if (std::regex_match(name, MSGCHANNEL_INDICATOR))
219  {
220  bool ret = IsTypeCheckNameValid(AssetType::MSGCHANNEL, name, error);
221  if (ret)
222  assetType = AssetType::MSGCHANNEL;
223 
224  return ret;
225  }
226  else if (std::regex_match(name, OWNER_INDICATOR))
227  {
228  bool ret = IsTypeCheckNameValid(AssetType::OWNER, name, error);
229  if (ret)
230  assetType = AssetType::OWNER;
231 
232  return ret;
233  }
234  else if (std::regex_match(name, VOTE_INDICATOR))
235  {
236  bool ret = IsTypeCheckNameValid(AssetType::VOTE, name, error);
237  if (ret)
238  assetType = AssetType::VOTE;
239 
240  return ret;
241  }
242  else if (std::regex_match(name, QUALIFIER_INDICATOR))
243  {
244  bool ret = IsTypeCheckNameValid(AssetType::QUALIFIER, name, error);
245  if (ret) {
246  if (IsAssetNameASubQualifier(name))
247  assetType = AssetType::SUB_QUALIFIER;
248  else
249  assetType = AssetType::QUALIFIER;
250  }
251 
252  return ret;
253  }
254  else if (std::regex_match(name, SUB_QUALIFIER_INDICATOR))
255  {
256  bool ret = IsTypeCheckNameValid(AssetType::SUB_QUALIFIER, name, error);
257  if (ret) {
258  if (IsAssetNameASubQualifier(name))
259  assetType = AssetType::SUB_QUALIFIER;
260  }
261 
262  return ret;
263  }
264  else if (std::regex_match(name, RESTRICTED_INDICATOR))
265  {
266  bool ret = IsTypeCheckNameValid(AssetType::RESTRICTED, name, error);
267  if (ret)
268  assetType = AssetType::RESTRICTED;
269 
270  return ret;
271  }
272  else
273  {
275  bool ret = IsTypeCheckNameValid(type, name, error);
276  if (ret)
277  assetType = type;
278 
279  return ret;
280  }
281 }
282 
283 bool IsAssetNameValid(const std::string& name)
284 {
285  AssetType _assetType;
286  std::string _error;
287  return IsAssetNameValid(name, _assetType, _error);
288 }
289 
290 bool IsAssetNameValid(const std::string& name, AssetType& assetType)
291 {
292  std::string _error;
293  return IsAssetNameValid(name, assetType, _error);
294 }
295 
296 bool IsAssetNameAnOwner(const std::string& name)
297 {
298  return IsAssetNameValid(name) && std::regex_match(name, OWNER_INDICATOR);
299 }
300 
301 bool IsAssetNameAnRestricted(const std::string& name)
302 {
303  return IsAssetNameValid(name) && std::regex_match(name, RESTRICTED_INDICATOR);
304 }
305 
306 bool IsAssetNameAQualifier(const std::string& name)
307 {
308  return IsAssetNameValid(name) && (std::regex_match(name, QUALIFIER_INDICATOR) || std::regex_match(name, SUB_QUALIFIER_INDICATOR));
309 }
310 
311 bool IsAssetNameAnMsgChannel(const std::string& name)
312 {
313  return IsAssetNameValid(name) && std::regex_match(name, MSGCHANNEL_INDICATOR);
314 }
315 
316 // TODO get the string translated below
317 bool IsTypeCheckNameValid(const AssetType type, const std::string& name, std::string& error)
318 {
319  if (type == AssetType::UNIQUE) {
320  if (name.size() > MAX_NAME_LENGTH) { error = "Name is greater than max length of " + std::to_string(MAX_NAME_LENGTH); return false; }
321  std::vector<std::string> parts;
322  boost::split(parts, name, boost::is_any_of(UNIQUE_TAG_DELIMITER));
323  bool valid = IsNameValidBeforeTag(parts.front()) && IsUniqueTagValid(parts.back());
324  if (!valid) { error = "Unique name contains invalid characters (Valid characters are: A-Z a-z 0-9 @ $ % & * ( ) [ ] { } _ . ? : -)"; return false; }
325  return true;
326  } else if (type == AssetType::MSGCHANNEL) {
327  if (name.size() > MAX_NAME_LENGTH) { error = "Name is greater than max length of " + std::to_string(MAX_NAME_LENGTH); return false; }
328  std::vector<std::string> parts;
329  boost::split(parts, name, boost::is_any_of(MSGCHANNEL_TAG_DELIMITER));
330  bool valid = IsNameValidBeforeTag(parts.front()) && IsMsgChannelTagValid(parts.back());
331  if (parts.back().size() > MAX_CHANNEL_NAME_LENGTH) { error = "Channel name is greater than max length of " + std::to_string(MAX_CHANNEL_NAME_LENGTH); return false; }
332  if (!valid) { error = "Message Channel name contains invalid characters (Valid characters are: A-Z 0-9 _ .) (special characters can't be the first or last characters)"; return false; }
333  return true;
334  } else if (type == AssetType::OWNER) {
335  if (name.size() > MAX_NAME_LENGTH) { error = "Name is greater than max length of " + std::to_string(MAX_NAME_LENGTH); return false; }
336  bool valid = IsNameValidBeforeTag(name.substr(0, name.size() - 1));
337  if (!valid) { error = "Owner name contains invalid characters (Valid characters are: A-Z 0-9 _ .) (special characters can't be the first or last characters)"; return false; }
338  return true;
339  } else if (type == AssetType::VOTE) {
340  if (name.size() > MAX_NAME_LENGTH) { error = "Name is greater than max length of " + std::to_string(MAX_NAME_LENGTH); return false; }
341  std::vector<std::string> parts;
342  boost::split(parts, name, boost::is_any_of(VOTE_TAG_DELIMITER));
343  bool valid = IsNameValidBeforeTag(parts.front()) && IsVoteTagValid(parts.back());
344  if (!valid) { error = "Vote name contains invalid characters (Valid characters are: A-Z 0-9 _ .) (special characters can't be the first or last characters)"; return false; }
345  return true;
346  } else if (type == AssetType::QUALIFIER || type == AssetType::SUB_QUALIFIER) {
347  if (name.size() > MAX_NAME_LENGTH) { error = "Name is greater than max length of " + std::to_string(MAX_NAME_LENGTH); return false; }
348  bool valid = IsQualifierNameValidBeforeTag(name);
349  if (!valid) { error = "Qualifier name contains invalid characters (Valid characters are: A-Z 0-9 _ .) (# must be the first character, _ . special characters can't be the first or last characters)"; return false; }
350  return true;
351  } else if (type == AssetType::RESTRICTED) {
352  if (name.size() > MAX_NAME_LENGTH) { error = "Name is greater than max length of " + std::to_string(MAX_NAME_LENGTH); return false; }
353  bool valid = IsRestrictedNameValid(name);
354  if (!valid) { error = "Restricted name contains invalid characters (Valid characters are: A-Z 0-9 _ .) ($ must be the first character, _ . special characters can't be the first or last characters)"; return false; }
355  return true;
356  } else {
357  if (name.size() > MAX_NAME_LENGTH - 1) { error = "Name is greater than max length of " + std::to_string(MAX_NAME_LENGTH - 1); return false; } //Assets and sub-assets need to leave one extra char for OWNER indicator
358  if (!IsAssetNameASubasset(name) && name.size() < MIN_ASSET_LENGTH) { error = "Name must be contain " + std::to_string(MIN_ASSET_LENGTH) + " characters"; return false; }
359  bool valid = IsNameValidBeforeTag(name);
360  if (!valid && IsAssetNameASubasset(name) && name.size() < 3) { error = "Name must have at least 3 characters (Valid characters are: A-Z 0-9 _ .)"; return false; }
361  if (!valid) { error = "Name contains invalid characters (Valid characters are: A-Z 0-9 _ .) (special characters can't be the first or last characters)"; return false; }
362  return true;
363  }
364 }
365 
366 std::string GetParentName(const std::string& name)
367 {
368  AssetType type;
369  if (!IsAssetNameValid(name, type))
370  return "";
371 
372  auto index = std::string::npos;
373  if (type == AssetType::SUB) {
374  index = name.find_last_of(SUB_NAME_DELIMITER);
375  } else if (type == AssetType::UNIQUE) {
376  index = name.find_last_of(UNIQUE_TAG_DELIMITER);
377  } else if (type == AssetType::MSGCHANNEL) {
378  index = name.find_last_of(MSGCHANNEL_TAG_DELIMITER);
379  } else if (type == AssetType::VOTE) {
380  index = name.find_last_of(VOTE_TAG_DELIMITER);
381  } else if (type == AssetType::ROOT) {
382  return name;
383  } else if (type == AssetType::QUALIFIER) {
384  return name;
385  } else if (type == AssetType::SUB_QUALIFIER) {
386  index = name.find_last_of(SUB_NAME_DELIMITER);
387  } else if (type == AssetType::RESTRICTED) {
388  return name;
389  }
390 
391  if (std::string::npos != index)
392  {
393  return name.substr(0, index);
394  }
395 
396  return name;
397 }
398 
399 std::string GetUniqueAssetName(const std::string& parent, const std::string& tag)
400 {
401  std::string unique = parent + "#" + tag;
402 
403  AssetType type;
404  if (!IsAssetNameValid(unique, type)) {
405  return "";
406  }
407 
408  if (type != AssetType::UNIQUE)
409  return "";
410 
411  return unique;
412 }
413 
414 bool CNewAsset::IsNull() const
415 {
416  return strName == "";
417 }
418 
420 {
421  this->strName = asset.strName;
422  this->nAmount = asset.nAmount;
423  this->units = asset.units;
424  this->nHasIPFS = asset.nHasIPFS;
425  this->nReissuable = asset.nReissuable;
426  this->strIPFSHash = asset.strIPFSHash;
427 }
428 
430 {
431  this->strName = asset.strName;
432  this->nAmount = asset.nAmount;
433  this->units = asset.units;
434  this->nHasIPFS = asset.nHasIPFS;
435  this->nReissuable = asset.nReissuable;
436  this->strIPFSHash = asset.strIPFSHash;
437  return *this;
438 }
439 
440 std::string CNewAsset::ToString()
441 {
442  std::stringstream ss;
443  ss << "Printing an asset" << "\n";
444  ss << "name : " << strName << "\n";
445  ss << "amount : " << nAmount << "\n";
446  ss << "units : " << std::to_string(units) << "\n";
447  ss << "reissuable : " << std::to_string(nReissuable) << "\n";
448  ss << "has_ipfs : " << std::to_string(nHasIPFS) << "\n";
449 
450  if (nHasIPFS)
451  ss << "ipfs_hash : " << strIPFSHash;
452 
453  return ss.str();
454 }
455 
456 CNewAsset::CNewAsset(const std::string& strName, const CAmount& nAmount, const int& units, const int& nReissuable, const int& nHasIPFS, const std::string& strIPFSHash)
457 {
458  this->SetNull();
459  this->strName = strName;
460  this->nAmount = nAmount;
461  this->units = int8_t(units);
462  this->nReissuable = int8_t(nReissuable);
463  this->nHasIPFS = int8_t(nHasIPFS);
464  this->strIPFSHash = strIPFSHash;
465 }
466 CNewAsset::CNewAsset(const std::string& strName, const CAmount& nAmount)
467 {
468  this->SetNull();
469  this->strName = strName;
470  this->nAmount = nAmount;
471  this->units = int8_t(DEFAULT_UNITS);
472  this->nReissuable = int8_t(DEFAULT_REISSUABLE);
473  this->nHasIPFS = int8_t(DEFAULT_HAS_IPFS);
474  this->strIPFSHash = DEFAULT_IPFS;
475 }
476 
477 CDatabasedAssetData::CDatabasedAssetData(const CNewAsset& asset, const int& nHeight, const uint256& blockHash)
478 {
479  this->SetNull();
480  this->asset = asset;
481  this->nHeight = nHeight;
482  this->blockHash = blockHash;
483 }
484 
486 {
487  this->SetNull();
488 }
489 
496 {
497  CDataStream ssAsset(SER_NETWORK, PROTOCOL_VERSION);
498  ssAsset << *this;
499 
500  std::vector<unsigned char> vchMessage;
501  vchMessage.push_back(RVN_R); // r
502  vchMessage.push_back(RVN_V); // v
503  vchMessage.push_back(RVN_N); // n
504  vchMessage.push_back(RVN_Q); // q
505 
506  vchMessage.insert(vchMessage.end(), ssAsset.begin(), ssAsset.end());
507  script << OP_RVN_ASSET << ToByteVector(vchMessage) << OP_DROP;
508 }
509 
511 {
512  CDataStream ssOwner(SER_NETWORK, PROTOCOL_VERSION);
513  ssOwner << std::string(this->strName + OWNER_TAG);
514 
515  std::vector<unsigned char> vchMessage;
516  vchMessage.push_back(RVN_R); // r
517  vchMessage.push_back(RVN_V); // v
518  vchMessage.push_back(RVN_N); // n
519  vchMessage.push_back(RVN_O); // o
520 
521  vchMessage.insert(vchMessage.end(), ssOwner.begin(), ssOwner.end());
522  script << OP_RVN_ASSET << ToByteVector(vchMessage) << OP_DROP;
523 }
524 
525 bool AssetFromTransaction(const CTransaction& tx, CNewAsset& asset, std::string& strAddress)
526 {
527  // Check to see if the transaction is an new asset issue tx
528  if (!tx.IsNewAsset())
529  return false;
530 
531  // Get the scriptPubKey from the last tx in vout
532  CScript scriptPubKey = tx.vout[tx.vout.size() - 1].scriptPubKey;
533 
534  return AssetFromScript(scriptPubKey, asset, strAddress);
535 }
536 
537 bool MsgChannelAssetFromTransaction(const CTransaction& tx, CNewAsset& asset, std::string& strAddress)
538 {
539  // Check to see if the transaction is an new asset issue tx
540  if (!tx.IsNewMsgChannelAsset())
541  return false;
542 
543  // Get the scriptPubKey from the last tx in vout
544  CScript scriptPubKey = tx.vout[tx.vout.size() - 1].scriptPubKey;
545 
546  return MsgChannelAssetFromScript(scriptPubKey, asset, strAddress);
547 }
548 
549 bool QualifierAssetFromTransaction(const CTransaction& tx, CNewAsset& asset, std::string& strAddress)
550 {
551  // Check to see if the transaction is an new asset qualifier issue tx
552  if (!tx.IsNewQualifierAsset())
553  return false;
554 
555  // Get the scriptPubKey from the last tx in vout
556  CScript scriptPubKey = tx.vout[tx.vout.size() - 1].scriptPubKey;
557 
558  return QualifierAssetFromScript(scriptPubKey, asset, strAddress);
559 }
560 bool RestrictedAssetFromTransaction(const CTransaction& tx, CNewAsset& asset, std::string& strAddress)
561 {
562  // Check to see if the transaction is an new asset qualifier issue tx
563  if (!tx.IsNewRestrictedAsset())
564  return false;
565 
566  // Get the scriptPubKey from the last tx in vout
567  CScript scriptPubKey = tx.vout[tx.vout.size() - 1].scriptPubKey;
568 
569  return RestrictedAssetFromScript(scriptPubKey, asset, strAddress);
570 }
571 
572 bool ReissueAssetFromTransaction(const CTransaction& tx, CReissueAsset& reissue, std::string& strAddress)
573 {
574  // Check to see if the transaction is a reissue tx
575  if (!tx.IsReissueAsset())
576  return false;
577 
578  // Get the scriptPubKey from the last tx in vout
579  CScript scriptPubKey = tx.vout[tx.vout.size() - 1].scriptPubKey;
580 
581  return ReissueAssetFromScript(scriptPubKey, reissue, strAddress);
582 }
583 
584 bool UniqueAssetFromTransaction(const CTransaction& tx, CNewAsset& asset, std::string& strAddress)
585 {
586  // Check to see if the transaction is an new asset issue tx
587  if (!tx.IsNewUniqueAsset())
588  return false;
589 
590  // Get the scriptPubKey from the last tx in vout
591  CScript scriptPubKey = tx.vout[tx.vout.size() - 1].scriptPubKey;
592 
593  return AssetFromScript(scriptPubKey, asset, strAddress);
594 }
595 
596 bool IsNewOwnerTxValid(const CTransaction& tx, const std::string& assetName, const std::string& address, std::string& errorMsg)
597 {
598  // TODO when ready to ship. Put the owner validation code in own method if needed
599  std::string ownerName;
600  std::string ownerAddress;
601  if (!OwnerFromTransaction(tx, ownerName, ownerAddress)) {
602  errorMsg = "bad-txns-bad-owner";
603  return false;
604  }
605 
606  int size = ownerName.size();
607 
608  if (ownerAddress != address) {
609  errorMsg = "bad-txns-owner-address-mismatch";
610  return false;
611  }
612 
613  if (size < OWNER_LENGTH + MIN_ASSET_LENGTH) {
614  errorMsg = "bad-txns-owner-asset-length";
615  return false;
616  }
617 
618  if (ownerName != std::string(assetName + OWNER_TAG)) {
619  errorMsg = "bad-txns-owner-name-mismatch";
620  return false;
621  }
622 
623  return true;
624 }
625 
626 bool OwnerFromTransaction(const CTransaction& tx, std::string& ownerName, std::string& strAddress)
627 {
628  // Check to see if the transaction is an new asset issue tx
629  if (!tx.IsNewAsset())
630  return false;
631 
632  // Get the scriptPubKey from the last tx in vout
633  CScript scriptPubKey = tx.vout[tx.vout.size() - 2].scriptPubKey;
634 
635  return OwnerAssetFromScript(scriptPubKey, ownerName, strAddress);
636 }
637 
638 bool TransferAssetFromScript(const CScript& scriptPubKey, CAssetTransfer& assetTransfer, std::string& strAddress)
639 {
640  int nStartingIndex = 0;
641  if (!IsScriptTransferAsset(scriptPubKey, nStartingIndex)) {
642  return false;
643  }
644 
645  CTxDestination destination;
646  ExtractDestination(scriptPubKey, destination);
647 
648  strAddress = EncodeDestination(destination);
649 
650  std::vector<unsigned char> vchTransferAsset;
651  vchTransferAsset.insert(vchTransferAsset.end(), scriptPubKey.begin() + 31, scriptPubKey.end());
652  CDataStream ssAsset(vchTransferAsset, SER_NETWORK, PROTOCOL_VERSION);
653 
654  try {
655  ssAsset >> assetTransfer;
656  } catch(std::exception& e) {
657  std::cout << "Failed to get the transfer asset from the stream: " << e.what() << std::endl;
658  return false;
659  }
660 
661  return true;
662 }
663 
664 bool AssetFromScript(const CScript& scriptPubKey, CNewAsset& assetNew, std::string& strAddress)
665 {
666  int nStartingIndex = 0;
667  if (!IsScriptNewAsset(scriptPubKey, nStartingIndex))
668  return false;
669 
670  CTxDestination destination;
671  ExtractDestination(scriptPubKey, destination);
672 
673  strAddress = EncodeDestination(destination);
674 
675  std::vector<unsigned char> vchNewAsset;
676  vchNewAsset.insert(vchNewAsset.end(), scriptPubKey.begin() + nStartingIndex, scriptPubKey.end());
677  CDataStream ssAsset(vchNewAsset, SER_NETWORK, PROTOCOL_VERSION);
678 
679  try {
680  ssAsset >> assetNew;
681  } catch(std::exception& e) {
682  std::cout << "Failed to get the asset from the stream: " << e.what() << std::endl;
683  return false;
684  }
685 
686  return true;
687 }
688 
689 bool MsgChannelAssetFromScript(const CScript& scriptPubKey, CNewAsset& assetNew, std::string& strAddress)
690 {
691  int nStartingIndex = 0;
692  if (!IsScriptNewMsgChannelAsset(scriptPubKey, nStartingIndex))
693  return false;
694 
695  CTxDestination destination;
696  ExtractDestination(scriptPubKey, destination);
697 
698  strAddress = EncodeDestination(destination);
699 
700  std::vector<unsigned char> vchNewAsset;
701  vchNewAsset.insert(vchNewAsset.end(), scriptPubKey.begin() + nStartingIndex, scriptPubKey.end());
702  CDataStream ssAsset(vchNewAsset, SER_NETWORK, PROTOCOL_VERSION);
703 
704  try {
705  ssAsset >> assetNew;
706  } catch(std::exception& e) {
707  std::cout << "Failed to get the msg channel asset from the stream: " << e.what() << std::endl;
708  return false;
709  }
710 
711  return true;
712 }
713 
714 bool QualifierAssetFromScript(const CScript& scriptPubKey, CNewAsset& assetNew, std::string& strAddress)
715 {
716  int nStartingIndex = 0;
717  if (!IsScriptNewQualifierAsset(scriptPubKey, nStartingIndex))
718  return false;
719 
720  CTxDestination destination;
721  ExtractDestination(scriptPubKey, destination);
722 
723  strAddress = EncodeDestination(destination);
724 
725  std::vector<unsigned char> vchNewAsset;
726  vchNewAsset.insert(vchNewAsset.end(), scriptPubKey.begin() + nStartingIndex, scriptPubKey.end());
727  CDataStream ssAsset(vchNewAsset, SER_NETWORK, PROTOCOL_VERSION);
728 
729  try {
730  ssAsset >> assetNew;
731  } catch(std::exception& e) {
732  std::cout << "Failed to get the qualifier asset from the stream: " << e.what() << std::endl;
733  return false;
734  }
735 
736  return true;
737 }
738 
739 bool RestrictedAssetFromScript(const CScript& scriptPubKey, CNewAsset& assetNew, std::string& strAddress)
740 {
741  int nStartingIndex = 0;
742  if (!IsScriptNewRestrictedAsset(scriptPubKey, nStartingIndex))
743  return false;
744 
745  CTxDestination destination;
746  ExtractDestination(scriptPubKey, destination);
747 
748  strAddress = EncodeDestination(destination);
749 
750  std::vector<unsigned char> vchNewAsset;
751  vchNewAsset.insert(vchNewAsset.end(), scriptPubKey.begin() + nStartingIndex, scriptPubKey.end());
752  CDataStream ssAsset(vchNewAsset, SER_NETWORK, PROTOCOL_VERSION);
753 
754  try {
755  ssAsset >> assetNew;
756  } catch(std::exception& e) {
757  std::cout << "Failed to get the restricted asset from the stream: " << e.what() << std::endl;
758  return false;
759  }
760 
761  return true;
762 }
763 
764 bool OwnerAssetFromScript(const CScript& scriptPubKey, std::string& assetName, std::string& strAddress)
765 {
766  int nStartingIndex = 0;
767  if (!IsScriptOwnerAsset(scriptPubKey, nStartingIndex))
768  return false;
769 
770  CTxDestination destination;
771  ExtractDestination(scriptPubKey, destination);
772 
773  strAddress = EncodeDestination(destination);
774 
775  std::vector<unsigned char> vchOwnerAsset;
776  vchOwnerAsset.insert(vchOwnerAsset.end(), scriptPubKey.begin() + nStartingIndex, scriptPubKey.end());
777  CDataStream ssOwner(vchOwnerAsset, SER_NETWORK, PROTOCOL_VERSION);
778 
779  try {
780  ssOwner >> assetName;
781  } catch(std::exception& e) {
782  std::cout << "Failed to get the owner asset from the stream: " << e.what() << std::endl;
783  return false;
784  }
785 
786  return true;
787 }
788 
789 bool ReissueAssetFromScript(const CScript& scriptPubKey, CReissueAsset& reissue, std::string& strAddress)
790 {
791  int nStartingIndex = 0;
792  if (!IsScriptReissueAsset(scriptPubKey, nStartingIndex))
793  return false;
794 
795  CTxDestination destination;
796  ExtractDestination(scriptPubKey, destination);
797 
798  strAddress = EncodeDestination(destination);
799 
800  std::vector<unsigned char> vchReissueAsset;
801  vchReissueAsset.insert(vchReissueAsset.end(), scriptPubKey.begin() + nStartingIndex, scriptPubKey.end());
802  CDataStream ssReissue(vchReissueAsset, SER_NETWORK, PROTOCOL_VERSION);
803 
804 
805  try {
806  ssReissue >> reissue;
807  } catch(std::exception& e) {
808  std::cout << "Failed to get the reissue asset from the stream: " << e.what() << std::endl;
809  return false;
810  }
811 
812  return true;
813 }
814 
815 bool AssetNullDataFromScript(const CScript& scriptPubKey, CNullAssetTxData& assetData, std::string& strAddress)
816 {
817  if (!scriptPubKey.IsNullAssetTxDataScript()) {
818  return false;
819  }
820 
821  CTxDestination destination;
822  ExtractDestination(scriptPubKey, destination);
823 
824  strAddress = EncodeDestination(destination);
825 
826  std::vector<unsigned char> vchAssetData;
827  vchAssetData.insert(vchAssetData.end(), scriptPubKey.begin() + OFFSET_TWENTY_THREE, scriptPubKey.end());
828  CDataStream ssData(vchAssetData, SER_NETWORK, PROTOCOL_VERSION);
829 
830  try {
831  ssData >> assetData;
832  } catch(std::exception& e) {
833  std::cout << "Failed to get the asset tx data from the stream: " << e.what() << std::endl;
834  return false;
835  }
836 
837  return true;
838 }
839 
840 bool GlobalAssetNullDataFromScript(const CScript& scriptPubKey, CNullAssetTxData& assetData)
841 {
842  if (!scriptPubKey.IsNullGlobalRestrictionAssetTxDataScript()) {
843  return false;
844  }
845 
846  std::vector<unsigned char> vchAssetData;
847  vchAssetData.insert(vchAssetData.end(), scriptPubKey.begin() + OFFSET_FOUR, scriptPubKey.end());
848  CDataStream ssData(vchAssetData, SER_NETWORK, PROTOCOL_VERSION);
849 
850  try {
851  ssData >> assetData;
852  } catch(std::exception& e) {
853  std::cout << "Failed to get the global restriction asset tx data from the stream: " << e.what() << std::endl;
854  return false;
855  }
856 
857  return true;
858 }
859 
861 {
862  if (!scriptPubKey.IsNullAssetVerifierTxDataScript()) {
863  return false;
864  }
865 
866  std::vector<unsigned char> vchAssetData;
867  vchAssetData.insert(vchAssetData.end(), scriptPubKey.begin() + OFFSET_THREE, scriptPubKey.end());
868  CDataStream ssData(vchAssetData, SER_NETWORK, PROTOCOL_VERSION);
869 
870  try {
871  ssData >> verifierData;
872  } catch(std::exception& e) {
873  std::cout << "Failed to get the verifier string from the stream: " << e.what() << std::endl;
874  return false;
875  }
876 
877  return true;
878 }
879 
882 {
883  // Check for the assets data CTxOut. This will always be the last output in the transaction
884  if (!CheckIssueDataTx(vout[vout.size() - 1]))
885  return false;
886 
887  // Check to make sure the owner asset is created
888  if (!CheckOwnerDataTx(vout[vout.size() - 2]))
889  return false;
890 
891  // Don't overlap with IsNewUniqueAsset()
892  CScript script = vout[vout.size() - 1].scriptPubKey;
894  return false;
895 
896  return true;
897 }
898 
901 {
902  // Check trailing outpoint for issue data with unique asset name
903  if (!CheckIssueDataTx(vout[vout.size() - 1]))
904  return false;
905 
906  if (!IsScriptNewUniqueAsset(vout[vout.size() - 1].scriptPubKey))
907  return false;
908 
909  return true;
910 }
911 
913 bool CTransaction::VerifyNewUniqueAsset(std::string& strError) const
914 {
915  // Must contain at least 3 outpoints (RVN burn, owner change and one or more new unique assets that share a root (should be in trailing position))
916  if (vout.size() < 3) {
917  strError = "bad-txns-unique-vout-size-to-small";
918  return false;
919  }
920 
921  // check for (and count) new unique asset outpoints. make sure they share a root.
922  std::set<std::string> setUniqueAssets;
923  std::string assetRoot = "";
924  int assetOutpointCount = 0;
925 
926  for (auto out : vout) {
927  if (IsScriptNewUniqueAsset(out.scriptPubKey)) {
928  CNewAsset asset;
929  std::string address;
930  if (!AssetFromScript(out.scriptPubKey, asset, address)) {
931  strError = "bad-txns-issue-unique-asset-from-script";
932  return false;
933  }
934  std::string root = GetParentName(asset.strName);
935  if (assetRoot.compare("") == 0)
936  assetRoot = root;
937  if (assetRoot.compare(root) != 0) {
938  strError = "bad-txns-issue-unique-asset-compare-failed";
939  return false;
940  }
941 
942  // Check for duplicate unique assets in the same transaction
943  if (setUniqueAssets.count(asset.strName)) {
944  strError = "bad-txns-issue-unique-duplicate-name-in-same-tx";
945  return false;
946  }
947 
948  setUniqueAssets.insert(asset.strName);
949  assetOutpointCount += 1;
950  }
951  }
952 
953  if (assetOutpointCount == 0) {
954  strError = "bad-txns-issue-unique-asset-bad-outpoint-count";
955  return false;
956  }
957 
958  // check for burn outpoint (must account for each new asset)
959  bool fBurnOutpointFound = false;
960  for (auto out : vout) {
961  if (CheckIssueBurnTx(out, AssetType::UNIQUE, assetOutpointCount)) {
962  fBurnOutpointFound = true;
963  break;
964  }
965  }
966 
967  if (!fBurnOutpointFound) {
968  strError = "bad-txns-issue-unique-asset-burn-outpoints-not-found";
969  return false;
970  }
971 
972  // check for owner change outpoint that matches root
973  bool fOwnerOutFound = false;
974  for (auto out : vout) {
976  std::string transferAddress;
977  if (TransferAssetFromScript(out.scriptPubKey, transfer, transferAddress)) {
978  if (assetRoot + OWNER_TAG == transfer.strName) {
979  fOwnerOutFound = true;
980  break;
981  }
982  }
983  }
984 
985  if (!fOwnerOutFound) {
986  strError = "bad-txns-issue-unique-asset-missing-owner-asset";
987  return false;
988  }
989 
990  // Loop through all of the vouts and make sure only the expected asset creations are taking place
991  int nTransfers = 0;
992  int nOwners = 0;
993  int nIssues = 0;
994  int nReissues = 0;
995  GetTxOutAssetTypes(vout, nIssues, nReissues, nTransfers, nOwners);
996 
997  if (nOwners > 0 || nReissues > 0 || nIssues != assetOutpointCount) {
998  strError = "bad-txns-failed-unique-asset-formatting-check";
999  return false;
1000  }
1001 
1002  return true;
1003 }
1004 
1006 bool CTransaction::VerifyNewAsset(std::string& strError) const {
1007  // Issuing an Asset must contain at least 3 CTxOut( Raven Burn Tx, Any Number of other Outputs ..., Owner Asset Tx, New Asset Tx)
1008  if (vout.size() < 3) {
1009  strError = "bad-txns-issue-vout-size-to-small";
1010  return false;
1011  }
1012 
1013  // Check for the assets data CTxOut. This will always be the last output in the transaction
1014  if (!CheckIssueDataTx(vout[vout.size() - 1])) {
1015  strError = "bad-txns-issue-data-not-found";
1016  return false;
1017  }
1018 
1019  // Check to make sure the owner asset is created
1020  if (!CheckOwnerDataTx(vout[vout.size() - 2])) {
1021  strError = "bad-txns-issue-owner-data-not-found";
1022  return false;
1023  }
1024 
1025  // Get the asset type
1026  CNewAsset asset;
1027  std::string address;
1028  if (!AssetFromScript(vout[vout.size() - 1].scriptPubKey, asset, address)) {
1029  strError = "bad-txns-issue-serialzation-failed";
1030  return error("%s : Failed to get new asset from transaction: %s", __func__, this->GetHash().GetHex());
1031  }
1032 
1033  AssetType assetType;
1034  IsAssetNameValid(asset.strName, assetType);
1035 
1036  std::string strOwnerName;
1037  if (!OwnerAssetFromScript(vout[vout.size() - 2].scriptPubKey, strOwnerName, address)) {
1038  strError = "bad-txns-issue-owner-serialzation-failed";
1039  return false;
1040  }
1041 
1042  if (strOwnerName != asset.strName + OWNER_TAG) {
1043  strError = "bad-txns-issue-owner-name-doesn't-match";
1044  return false;
1045  }
1046 
1047  // Check for the Burn CTxOut in one of the vouts ( This is needed because the change CTxOut is places in a random position in the CWalletTx
1048  bool fFoundIssueBurnTx = false;
1049  for (auto out : vout) {
1050  if (CheckIssueBurnTx(out, assetType)) {
1051  fFoundIssueBurnTx = true;
1052  break;
1053  }
1054  }
1055 
1056  if (!fFoundIssueBurnTx) {
1057  strError = "bad-txns-issue-burn-not-found";
1058  return false;
1059  }
1060 
1061  // Loop through all of the vouts and make sure only the expected asset creations are taking place
1062  int nTransfers = 0;
1063  int nOwners = 0;
1064  int nIssues = 0;
1065  int nReissues = 0;
1066  GetTxOutAssetTypes(vout, nIssues, nReissues, nTransfers, nOwners);
1067 
1068  if (nOwners != 1 || nIssues != 1 || nReissues > 0) {
1069  strError = "bad-txns-failed-issue-asset-formatting-check";
1070  return false;
1071  }
1072 
1073  return true;
1074 }
1075 
1078 {
1079  // Check trailing outpoint for issue data with unique asset name
1080  if (!CheckIssueDataTx(vout[vout.size() - 1]))
1081  return false;
1082 
1083  if (!IsScriptNewMsgChannelAsset(vout[vout.size() - 1].scriptPubKey))
1084  return false;
1085 
1086  return true;
1087 }
1088 
1090 bool CTransaction::VerifyNewMsgChannelAsset(std::string &strError) const
1091 {
1092  // Issuing an Asset must contain at least 3 CTxOut( Raven Burn Tx, Any Number of other Outputs ..., Owner Asset Tx, New Asset Tx)
1093  if (vout.size() < 3) {
1094  strError = "bad-txns-issue-msgchannel-vout-size-to-small";
1095  return false;
1096  }
1097 
1098  // Check for the assets data CTxOut. This will always be the last output in the transaction
1099  if (!CheckIssueDataTx(vout[vout.size() - 1])) {
1100  strError = "bad-txns-issue-data-not-found";
1101  return false;
1102  }
1103 
1104  // Get the asset type
1105  CNewAsset asset;
1106  std::string address;
1107  if (!MsgChannelAssetFromScript(vout[vout.size() - 1].scriptPubKey, asset, address)) {
1108  strError = "bad-txns-issue-msgchannel-serialzation-failed";
1109  return error("%s : Failed to get new msgchannel asset from transaction: %s", __func__, this->GetHash().GetHex());
1110  }
1111 
1112  AssetType assetType;
1113  IsAssetNameValid(asset.strName, assetType);
1114 
1115  // Check for the Burn CTxOut in one of the vouts ( This is needed because the change CTxOut is places in a random position in the CWalletTx
1116  bool fFoundIssueBurnTx = false;
1117  for (auto out : vout) {
1119  fFoundIssueBurnTx = true;
1120  break;
1121  }
1122  }
1123 
1124  if (!fFoundIssueBurnTx) {
1125  strError = "bad-txns-issue-msgchannel-burn-not-found";
1126  return false;
1127  }
1128 
1129  // check for owner change outpoint that matches root
1130  std::string root = GetParentName(asset.strName);
1131  bool fOwnerOutFound = false;
1132  for (auto out : vout) {
1134  std::string transferAddress;
1135  if (TransferAssetFromScript(out.scriptPubKey, transfer, transferAddress)) {
1136  if (root + OWNER_TAG == transfer.strName) {
1137  fOwnerOutFound = true;
1138  break;
1139  }
1140  }
1141  }
1142 
1143  if (!fOwnerOutFound) {
1144  strError = "bad-txns-issue-msg-channel-asset-bad-owner-asset";
1145  return false;
1146  }
1147 
1148  // Loop through all of the vouts and make sure only the expected asset creations are taking place
1149  int nTransfers = 0;
1150  int nOwners = 0;
1151  int nIssues = 0;
1152  int nReissues = 0;
1153  GetTxOutAssetTypes(vout, nIssues, nReissues, nTransfers, nOwners);
1154 
1155  if (nOwners != 0 || nIssues != 1 || nReissues > 0) {
1156  strError = "bad-txns-failed-issue-msgchannel-asset-formatting-check";
1157  return false;
1158  }
1159 
1160  return true;
1161 }
1162 
1165 {
1166  // Check trailing outpoint for issue data with unique asset name
1167  if (!CheckIssueDataTx(vout[vout.size() - 1]))
1168  return false;
1169 
1170  if (!IsScriptNewQualifierAsset(vout[vout.size() - 1].scriptPubKey))
1171  return false;
1172 
1173  return true;
1174 }
1175 
1177 bool CTransaction::VerifyNewQualfierAsset(std::string &strError) const
1178 {
1179  // Issuing an Asset must contain at least 2 CTxOut( Raven Burn Tx, New Asset Tx, Any Number of other Outputs...)
1180  if (vout.size() < 2) {
1181  strError = "bad-txns-issue-qualifier-vout-size-to-small";
1182  return false;
1183  }
1184 
1185  // Check for the assets data CTxOut. This will always be the last output in the transaction
1186  if (!CheckIssueDataTx(vout[vout.size() - 1])) {
1187  strError = "bad-txns-issue-qualifider-data-not-found";
1188  return false;
1189  }
1190 
1191  // Get the asset type
1192  CNewAsset asset;
1193  std::string address;
1194  if (!QualifierAssetFromScript(vout[vout.size() - 1].scriptPubKey, asset, address)) {
1195  strError = "bad-txns-issue-qualifier-serialzation-failed";
1196  return error("%s : Failed to get new qualifier asset from transaction: %s", __func__, this->GetHash().GetHex());
1197  }
1198 
1199  AssetType assetType;
1200  IsAssetNameValid(asset.strName, assetType);
1201 
1202  // Check for the Burn CTxOut in one of the vouts ( This is needed because the change CTxOut is places in a random position in the CWalletTx
1203  bool fFoundIssueBurnTx = false;
1204  for (auto out : vout) {
1205  if (CheckIssueBurnTx(out, assetType)) {
1206  fFoundIssueBurnTx = true;
1207  break;
1208  }
1209  }
1210 
1211  if (!fFoundIssueBurnTx) {
1212  strError = "bad-txns-issue-qualifier-burn-not-found";
1213  return false;
1214  }
1215 
1216  if (assetType == AssetType::SUB_QUALIFIER) {
1217  // Check that there is an asset transfer with the parent name, qualifier use just the parent name, they don't use not parent + !
1218  bool fOwnerOutFound = false;
1219  std::string root = GetParentName(asset.strName);
1220  for (auto out : vout) {
1222  std::string transferAddress;
1223  if (TransferAssetFromScript(out.scriptPubKey, transfer, transferAddress)) {
1224  if (root == transfer.strName) {
1225  fOwnerOutFound = true;
1226  break;
1227  }
1228  }
1229  }
1230 
1231  if (!fOwnerOutFound) {
1232  strError = "bad-txns-issue-sub-qualifier-parent-outpoint-not-found";
1233  return false;
1234  }
1235  }
1236 
1237  // Loop through all of the vouts and make sure only the expected asset creations are taking place
1238  int nTransfers = 0;
1239  int nOwners = 0;
1240  int nIssues = 0;
1241  int nReissues = 0;
1242  GetTxOutAssetTypes(vout, nIssues, nReissues, nTransfers, nOwners);
1243 
1244  if (nOwners != 0 || nIssues != 1 || nReissues > 0) {
1245  strError = "bad-txns-failed-issue-asset-formatting-check";
1246  return false;
1247  }
1248 
1249  return true;
1250 }
1251 
1254 {
1255  // Check trailing outpoint for issue data with unique asset name
1256  if (!CheckIssueDataTx(vout[vout.size() - 1]))
1257  return false;
1258 
1259  if (!IsScriptNewRestrictedAsset(vout[vout.size() - 1].scriptPubKey))
1260  return false;
1261 
1262  return true;
1263 }
1264 
1266 bool CTransaction::VerifyNewRestrictedAsset(std::string& strError) const {
1267  // Issuing a restricted asset must cointain at least 4 CTxOut(Raven Burn Tx, Asset Creation, Root Owner Token Transfer, and CNullAssetTxVerifierString)
1268  if (vout.size() < 4) {
1269  strError = "bad-txns-issue-restricted-vout-size-to-small";
1270  return false;
1271  }
1272 
1273  // Check for the assets data CTxOut. This will always be the last output in the transaction
1274  if (!CheckIssueDataTx(vout[vout.size() - 1])) {
1275  strError = "bad-txns-issue-restricted-data-not-found";
1276  return false;
1277  }
1278 
1279  // Get the asset type
1280  CNewAsset asset;
1281  std::string address;
1282  if (!RestrictedAssetFromScript(vout[vout.size() - 1].scriptPubKey, asset, address)) {
1283  strError = "bad-txns-issue-restricted-serialization-failed";
1284  return error("%s : Failed to get new restricted asset from transaction: %s", __func__, this->GetHash().GetHex());
1285  }
1286 
1287  AssetType assetType;
1288  IsAssetNameValid(asset.strName, assetType);
1289 
1290  // Check for the Burn CTxOut in one of the vouts ( This is needed because the change CTxOut is places in a random position in the CWalletTx
1291  bool fFoundIssueBurnTx = false;
1292  for (auto out : vout) {
1293  if (CheckIssueBurnTx(out, assetType)) {
1294  fFoundIssueBurnTx = true;
1295  break;
1296  }
1297  }
1298 
1299  if (!fFoundIssueBurnTx) {
1300  strError = "bad-txns-issue-restricted-burn-not-found";
1301  return false;
1302  }
1303 
1304  // Check that there is an asset transfer with the parent name, restricted assets use the root owner token. So issuing $TOKEN requires TOKEN!
1305  bool fRootOwnerOutFound = false;
1306  std::string root = GetParentName(asset.strName);
1307  std::string strippedRoot = root.substr(1, root.size() -1) + OWNER_TAG; // $TOKEN checks for TOKEN!
1308  for (auto out : vout) {
1310  std::string transferAddress;
1311  if (TransferAssetFromScript(out.scriptPubKey, transfer, transferAddress)) {
1312  if (strippedRoot == transfer.strName) {
1313  fRootOwnerOutFound = true;
1314  break;
1315  }
1316  }
1317  }
1318 
1319  if (!fRootOwnerOutFound) {
1320  strError = "bad-txns-issue-restricted-root-owner-token-outpoint-not-found";
1321  return false;
1322  }
1323 
1324  // Check to make sure we can get the verifier string from the transaction
1325  CNullAssetTxVerifierString verifier;
1326  if (!GetVerifierStringFromTx(verifier, strError)) {
1327  return false;
1328  }
1329 
1330  // TODO is verifier string valid check, this happen automatically when processing the nullasset tx outputs
1331 
1332  // Loop through all of the vouts and make sure only the expected asset creations are taking place
1333  int nTransfers = 0;
1334  int nOwners = 0;
1335  int nIssues = 0;
1336  int nReissues = 0;
1337  GetTxOutAssetTypes(vout, nIssues, nReissues, nTransfers, nOwners);
1338 
1339  if (nOwners != 0 || nIssues != 1 || nReissues > 0) {
1340  strError = "bad-txns-failed-issue-asset-formatting-check";
1341  return false;
1342  }
1343 
1344  return true;
1345 }
1346 
1347 bool CTransaction::GetVerifierStringFromTx(CNullAssetTxVerifierString& verifier, std::string& strError, bool& fNotFound) const
1348 {
1349  fNotFound = false;
1350  bool found = false;
1351  int count = 0;
1352  for (auto out : vout) {
1353  if (out.scriptPubKey.IsNullAssetVerifierTxDataScript()) {
1354  count++;
1355 
1356  if (count > 1) {
1357  strError = _("Multiple verifier strings found in transaction");
1358  return false;
1359  }
1360  if (!AssetNullVerifierDataFromScript(out.scriptPubKey, verifier)) {
1361  strError = _("Failed to get verifier string from output: ") + out.ToString();
1362  return false;
1363  }
1364 
1365  found = true;
1366  }
1367  }
1368 
1369  // Set error message, for if it returns false
1370  if (!found) {
1371  fNotFound = true;
1372  strError = _("Verifier string not found");
1373  }
1374 
1375  return found && count == 1;
1376 }
1377 
1378 bool CTransaction::GetVerifierStringFromTx(CNullAssetTxVerifierString& verifier, std::string& strError) const
1379 {
1380  bool fNotFound = false;
1381  return GetVerifierStringFromTx(verifier, strError, fNotFound);
1382 }
1383 
1385 {
1386  // Check for the reissue asset data CTxOut. This will always be the last output in the transaction
1387  if (!CheckReissueDataTx(vout[vout.size() - 1]))
1388  return false;
1389 
1390  return true;
1391 }
1392 
1394 bool CTransaction::VerifyReissueAsset(std::string& strError) const
1395 {
1396  // Reissuing an Asset must contain at least 3 CTxOut ( Raven Burn Tx, Any Number of other Outputs ..., Reissue Asset Tx, Owner Asset Change Tx)
1397  if (vout.size() < 3) {
1398  strError = "bad-txns-vout-size-to-small";
1399  return false;
1400  }
1401 
1402  // Check for the reissue asset data CTxOut. This will always be the last output in the transaction
1403  if (!CheckReissueDataTx(vout[vout.size() - 1])) {
1404  strError = "bad-txns-reissue-data-not-found";
1405  return false;
1406  }
1407 
1409  std::string address;
1410  if (!ReissueAssetFromScript(vout[vout.size() - 1].scriptPubKey, reissue, address)) {
1411  strError = "bad-txns-reissue-serialization-failed";
1412  return false;
1413  }
1414 
1415  // Reissuing a regular asset checks the reissue_asset_name + "!"
1416  AssetType asset_type = AssetType::INVALID;
1417  IsAssetNameValid(reissue.strName, asset_type);
1418 
1419  // This is going to be the asset name that we need to verify that the owner token of was added to the transaction
1420  std::string asset_name_to_check = reissue.strName;
1421 
1422  // If the asset type is restricted, remove the $ from the name, so we can check for the correct owner token transfer
1423  if (asset_type == AssetType::RESTRICTED) {
1424  asset_name_to_check = reissue.strName.substr(1, reissue.strName.size() -1);
1425  }
1426 
1427  // Check that there is an asset transfer, this will be the owner asset change
1428  bool fOwnerOutFound = false;
1429  for (auto out : vout) {
1431  std::string transferAddress;
1432  if (TransferAssetFromScript(out.scriptPubKey, transfer, transferAddress)) {
1433  if (asset_name_to_check + OWNER_TAG == transfer.strName) {
1434  fOwnerOutFound = true;
1435  break;
1436  }
1437  }
1438  }
1439 
1440  if (!fOwnerOutFound) {
1441  strError = "bad-txns-reissue-owner-outpoint-not-found";
1442  return false;
1443  }
1444 
1445  // Check for the Burn CTxOut in one of the vouts ( This is needed because the change CTxOut is placed in a random position in the CWalletTx
1446  bool fFoundReissueBurnTx = false;
1447  for (auto out : vout) {
1448  if (CheckReissueBurnTx(out)) {
1449  fFoundReissueBurnTx = true;
1450  break;
1451  }
1452  }
1453 
1454  if (!fFoundReissueBurnTx) {
1455  strError = "bad-txns-reissue-burn-outpoint-not-found";
1456  return false;
1457  }
1458 
1459  // Loop through all of the vouts and make sure only the expected asset creations are taking place
1460  int nTransfers = 0;
1461  int nOwners = 0;
1462  int nIssues = 0;
1463  int nReissues = 0;
1464  GetTxOutAssetTypes(vout, nIssues, nReissues, nTransfers, nOwners);
1465 
1466  if (nOwners > 0 || nReissues != 1 || nIssues > 0) {
1467  strError = "bad-txns-failed-reissue-asset-formatting-check";
1468  return false;
1469  }
1470 
1471  return true;
1472 }
1473 
1474 bool CTransaction::CheckAddingTagBurnFee(const int& count) const
1475 {
1476  // check for burn outpoint )
1477  bool fBurnOutpointFound = false;
1478  for (auto out : vout) {
1480  fBurnOutpointFound = true;
1481  break;
1482  }
1483  }
1484 
1485  return fBurnOutpointFound;
1486 }
1487 
1488 CAssetTransfer::CAssetTransfer(const std::string& strAssetName, const CAmount& nAmount, const std::string& message, const int64_t& nExpireTime)
1489 {
1490  SetNull();
1491  this->strName = strAssetName;
1492  this->nAmount = nAmount;
1493  this->message = message;
1494  if (!message.empty()) {
1495  if (nExpireTime) {
1496  this->nExpireTime = nExpireTime;
1497  } else {
1498  this->nExpireTime = 0;
1499  }
1500  }
1501 }
1502 
1503 bool CAssetTransfer::IsValid(std::string& strError) const
1504 {
1505  // Don't use this function with any sort of consensus checks
1506  // All of these checks are run with ContextualCheckTransferAsset also
1507 
1508  strError = "";
1509 
1510  if (!IsAssetNameValid(std::string(strName))) {
1511  strError = "Invalid parameter: asset_name must only consist of valid characters and have a size between 3 and 30 characters. See help for more details.";
1512  return false;
1513  }
1514 
1515  // this function is only being called in createrawtranasction, so it is fine to have a contextual check here
1516  // if this gets called anywhere else, we will need to move this to a Contextual function
1517  if (nAmount <= 0) {
1518  strError = "Invalid parameter: asset amount can't be equal to or less than zero.";
1519  return false;
1520  }
1521 
1522  if (message.empty() && nExpireTime > 0) {
1523  strError = "Invalid parameter: asset transfer expiration time requires a message to be attached to the transfer";
1524  return false;
1525  }
1526 
1527  if (nExpireTime < 0) {
1528  strError = "Invalid parameter: expiration time must be a positive value";
1529  return false;
1530  }
1531 
1532  if (message.size() && !CheckEncoded(message, strError)) {
1533  return false;
1534  }
1535 
1536  return true;
1537 }
1538 
1539 bool CAssetTransfer::ContextualCheckAgainstVerifyString(CAssetsCache *assetCache, const std::string& address, std::string& strError) const
1540 {
1541  // Get the verifier string
1542  CNullAssetTxVerifierString verifier;
1543  if (!assetCache->GetAssetVerifierStringIfExists(this->strName, verifier, true)) {
1544  // This shouldn't ever happen, but if it does we need to know
1545  strError = _("Verifier String doesn't exist for asset: ") + this->strName;
1546  return false;
1547  }
1548 
1549  if (!ContextualCheckVerifierString(assetCache, verifier.verifier_string, address, strError))
1550  return false;
1551 
1552  return true;
1553 }
1554 
1556 {
1557  CDataStream ssTransfer(SER_NETWORK, PROTOCOL_VERSION);
1558  ssTransfer << *this;
1559 
1560  std::vector<unsigned char> vchMessage;
1561  vchMessage.push_back(RVN_R); // r
1562  vchMessage.push_back(RVN_V); // v
1563  vchMessage.push_back(RVN_N); // n
1564  vchMessage.push_back(RVN_T); // t
1565 
1566  vchMessage.insert(vchMessage.end(), ssTransfer.begin(), ssTransfer.end());
1567  script << OP_RVN_ASSET << ToByteVector(vchMessage) << OP_DROP;
1568 }
1569 
1570 CReissueAsset::CReissueAsset(const std::string &strAssetName, const CAmount &nAmount, const int &nUnits, const int &nReissuable,
1571  const std::string &strIPFSHash)
1572 {
1573  SetNull();
1574  this->strName = strAssetName;
1575  this->strIPFSHash = strIPFSHash;
1576  this->nReissuable = int8_t(nReissuable);
1577  this->nAmount = nAmount;
1578  this->nUnits = nUnits;
1579 }
1580 
1582 {
1583  CDataStream ssReissue(SER_NETWORK, PROTOCOL_VERSION);
1584  ssReissue << *this;
1585 
1586  std::vector<unsigned char> vchMessage;
1587  vchMessage.push_back(RVN_R); // r
1588  vchMessage.push_back(RVN_V); // v
1589  vchMessage.push_back(RVN_N); // n
1590  vchMessage.push_back(RVN_R); // r
1591 
1592  vchMessage.insert(vchMessage.end(), ssReissue.begin(), ssReissue.end());
1593  script << OP_RVN_ASSET << ToByteVector(vchMessage) << OP_DROP;
1594 }
1595 
1597 {
1598  return strName == "" || nAmount < 0;
1599 }
1600 
1601 bool CAssetsCache::AddTransferAsset(const CAssetTransfer& transferAsset, const std::string& address, const COutPoint& out, const CTxOut& txOut)
1602 {
1603  AddToAssetBalance(transferAsset.strName, address, transferAsset.nAmount);
1604 
1605  // Add to cache so we can save to database
1606  CAssetCacheNewTransfer newTransfer(transferAsset, address, out);
1607 
1608  if (setNewTransferAssetsToRemove.count(newTransfer))
1609  setNewTransferAssetsToRemove.erase(newTransfer);
1610 
1611  setNewTransferAssetsToAdd.insert(newTransfer);
1612 
1613  return true;
1614 }
1615 
1616 void CAssetsCache::AddToAssetBalance(const std::string& strName, const std::string& address, const CAmount& nAmount)
1617 {
1618  if (fAssetIndex) {
1619  auto pair = std::make_pair(strName, address);
1620  // Add to map address -> amount map
1621 
1622  // Get the best amount
1623  if (!GetBestAssetAddressAmount(*this, strName, address))
1624  mapAssetsAddressAmount.insert(make_pair(pair, 0));
1625 
1626  // Add the new amount to the balance
1627  if (IsAssetNameAnOwner(strName))
1628  mapAssetsAddressAmount.at(pair) = OWNER_ASSET_AMOUNT;
1629  else
1630  mapAssetsAddressAmount.at(pair) += nAmount;
1631  }
1632 }
1633 
1634 bool CAssetsCache::TrySpendCoin(const COutPoint& out, const CTxOut& txOut)
1635 {
1636  // Placeholder strings that will get set if you successfully get the transfer or asset from the script
1637  std::string address = "";
1638  std::string assetName = "";
1639  CAmount nAmount = -1;
1640 
1641  // Get the asset tx data
1642  int nType = -1;
1643  bool fIsOwner = false;
1644  if (txOut.scriptPubKey.IsAssetScript(nType, fIsOwner)) {
1645 
1646  // Get the New Asset or Transfer Asset from the scriptPubKey
1647  if (nType == TX_NEW_ASSET && !fIsOwner) {
1648  CNewAsset asset;
1649  if (AssetFromScript(txOut.scriptPubKey, asset, address)) {
1650  assetName = asset.strName;
1651  nAmount = asset.nAmount;
1652  }
1653  } else if (nType == TX_TRANSFER_ASSET) {
1655  if (TransferAssetFromScript(txOut.scriptPubKey, transfer, address)) {
1656  assetName = transfer.strName;
1657  nAmount = transfer.nAmount;
1658  }
1659  } else if (nType == TX_NEW_ASSET && fIsOwner) {
1660  if (!OwnerAssetFromScript(txOut.scriptPubKey, assetName, address))
1661  return error("%s : ERROR Failed to get owner asset from the OutPoint: %s", __func__,
1662  out.ToString());
1663  nAmount = OWNER_ASSET_AMOUNT;
1664  } else if (nType == TX_REISSUE_ASSET) {
1666  if (ReissueAssetFromScript(txOut.scriptPubKey, reissue, address)) {
1667  assetName = reissue.strName;
1668  nAmount = reissue.nAmount;
1669  }
1670  }
1671  } else {
1672  // If it isn't an asset tx return true, we only fail if an error occurs
1673  return true;
1674  }
1675 
1676  // If we got the address and the assetName, proceed to remove it from the database, and in memory objects
1677  if (address != "" && assetName != "" && nAmount > 0) {
1678  if (fAssetIndex) {
1679  CAssetCacheSpendAsset spend(assetName, address, nAmount);
1680  if (GetBestAssetAddressAmount(*this, assetName, address)) {
1681  auto pair = make_pair(assetName, address);
1682  if (mapAssetsAddressAmount.count(pair))
1683  mapAssetsAddressAmount.at(pair) -= nAmount;
1684 
1685  if (mapAssetsAddressAmount.at(pair) < 0)
1686  mapAssetsAddressAmount.at(pair) = 0;
1687 
1688  // Update the cache so we can save to database
1689  vSpentAssets.push_back(spend);
1690  }
1691  }
1692  } else {
1693  return error("%s : ERROR Failed to get asset from the OutPoint: %s", __func__, out.ToString());
1694  }
1695 
1696  return true;
1697 }
1698 
1700 {
1701  return CheckIfAssetExists(asset.strName);
1702 }
1703 
1704 bool CAssetsCache::ContainsAsset(const std::string& assetName)
1705 {
1706  return CheckIfAssetExists(assetName);
1707 }
1708 
1709 bool CAssetsCache::UndoAssetCoin(const Coin& coin, const COutPoint& out)
1710 {
1711  std::string strAddress = "";
1712  std::string assetName = "";
1713  CAmount nAmount = 0;
1714 
1715  // Get the asset tx from the script
1716  int nType = -1;
1717  bool fIsOwner = false;
1718  if(coin.out.scriptPubKey.IsAssetScript(nType, fIsOwner)) {
1719 
1720  if (nType == TX_NEW_ASSET && !fIsOwner) {
1721  CNewAsset asset;
1722  if (!AssetFromScript(coin.out.scriptPubKey, asset, strAddress)) {
1723  return error("%s : Failed to get asset from script while trying to undo asset spend. OutPoint : %s",
1724  __func__,
1725  out.ToString());
1726  }
1727  assetName = asset.strName;
1728 
1729  nAmount = asset.nAmount;
1730  } else if (nType == TX_TRANSFER_ASSET) {
1732  if (!TransferAssetFromScript(coin.out.scriptPubKey, transfer, strAddress))
1733  return error(
1734  "%s : Failed to get transfer asset from script while trying to undo asset spend. OutPoint : %s",
1735  __func__,
1736  out.ToString());
1737 
1738  assetName = transfer.strName;
1739  nAmount = transfer.nAmount;
1740  } else if (nType == TX_NEW_ASSET && fIsOwner) {
1741  std::string ownerName;
1742  if (!OwnerAssetFromScript(coin.out.scriptPubKey, ownerName, strAddress))
1743  return error(
1744  "%s : Failed to get owner asset from script while trying to undo asset spend. OutPoint : %s",
1745  __func__, out.ToString());
1746  assetName = ownerName;
1747  nAmount = OWNER_ASSET_AMOUNT;
1748  } else if (nType == TX_REISSUE_ASSET) {
1750  if (!ReissueAssetFromScript(coin.out.scriptPubKey, reissue, strAddress))
1751  return error(
1752  "%s : Failed to get reissue asset from script while trying to undo asset spend. OutPoint : %s",
1753  __func__, out.ToString());
1754  assetName = reissue.strName;
1755  nAmount = reissue.nAmount;
1756  }
1757  }
1758 
1759  if (assetName == "" || strAddress == "" || nAmount == 0)
1760  return error("%s : AssetName, Address or nAmount is invalid., Asset Name: %s, Address: %s, Amount: %d", __func__, assetName, strAddress, nAmount);
1761 
1762  if (!AddBackSpentAsset(coin, assetName, strAddress, nAmount, out))
1763  return error("%s : Failed to add back the spent asset. OutPoint : %s", __func__, out.ToString());
1764 
1765  return true;
1766 }
1767 
1769 bool CAssetsCache::AddBackSpentAsset(const Coin& coin, const std::string& assetName, const std::string& address, const CAmount& nAmount, const COutPoint& out)
1770 {
1771  if (fAssetIndex) {
1772  // Update the assets address balance
1773  auto pair = std::make_pair(assetName, address);
1774 
1775  // Get the map address amount from database if the map doesn't have it already
1776  if (!GetBestAssetAddressAmount(*this, assetName, address))
1777  mapAssetsAddressAmount.insert(std::make_pair(pair, 0));
1778 
1779  mapAssetsAddressAmount.at(pair) += nAmount;
1780  }
1781 
1782  // Add the undoAmount to the vector so we know what changes are dirty and what needs to be saved to database
1783  CAssetCacheUndoAssetAmount undoAmount(assetName, address, nAmount);
1784  vUndoAssetAmount.push_back(undoAmount);
1785 
1786  return true;
1787 }
1788 
1790 bool CAssetsCache::UndoTransfer(const CAssetTransfer& transfer, const std::string& address, const COutPoint& outToRemove)
1791 {
1792  if (fAssetIndex) {
1793  // Make sure we are in a valid state to undo the transfer of the asset
1794  if (!GetBestAssetAddressAmount(*this, transfer.strName, address))
1795  return error("%s : Failed to get the assets address balance from the database. Asset : %s Address : %s",
1796  __func__, transfer.strName, address);
1797 
1798  auto pair = std::make_pair(transfer.strName, address);
1799  if (!mapAssetsAddressAmount.count(pair))
1800  return error(
1801  "%s : Tried undoing a transfer and the map of address amount didn't have the asset address pair. Asset : %s Address : %s",
1802  __func__, transfer.strName, address);
1803 
1804  if (mapAssetsAddressAmount.at(pair) < transfer.nAmount)
1805  return error(
1806  "%s : Tried undoing a transfer and the map of address amount had less than the amount we are trying to undo. Asset : %s Address : %s",
1807  __func__, transfer.strName, address);
1808 
1809  // Change the in memory balance of the asset at the address
1810  mapAssetsAddressAmount[pair] -= transfer.nAmount;
1811  }
1812 
1813  return true;
1814 }
1815 
1817 bool CAssetsCache::RemoveNewAsset(const CNewAsset& asset, const std::string address)
1818 {
1819  if (!CheckIfAssetExists(asset.strName))
1820  return error("%s : Tried removing an asset that didn't exist. Asset Name : %s", __func__, asset.strName);
1821 
1822  CAssetCacheNewAsset newAsset(asset, address, 0 , uint256());
1823 
1824  if (setNewAssetsToAdd.count(newAsset))
1825  setNewAssetsToAdd.erase(newAsset);
1826 
1827  setNewAssetsToRemove.insert(newAsset);
1828 
1829  if (fAssetIndex)
1830  mapAssetsAddressAmount[std::make_pair(asset.strName, address)] = 0;
1831 
1832  return true;
1833 }
1834 
1836 bool CAssetsCache::AddNewAsset(const CNewAsset& asset, const std::string address, const int& nHeight, const uint256& blockHash)
1837 {
1838  if(CheckIfAssetExists(asset.strName))
1839  return error("%s: Tried adding new asset, but it already existed in the set of assets: %s", __func__, asset.strName);
1840 
1841  CAssetCacheNewAsset newAsset(asset, address, nHeight, blockHash);
1842 
1843  if (setNewAssetsToRemove.count(newAsset))
1844  setNewAssetsToRemove.erase(newAsset);
1845 
1846  setNewAssetsToAdd.insert(newAsset);
1847 
1848  if (fAssetIndex) {
1849  // Insert the asset into the assests address amount map
1850  mapAssetsAddressAmount[std::make_pair(asset.strName, address)] = asset.nAmount;
1851  }
1852 
1853  return true;
1854 }
1855 
1857 bool CAssetsCache::AddReissueAsset(const CReissueAsset& reissue, const std::string address, const COutPoint& out)
1858 {
1859  auto pair = std::make_pair(reissue.strName, address);
1860 
1861  CNewAsset asset;
1862  int assetHeight;
1863  uint256 assetBlockHash;
1864  if (!GetAssetMetaDataIfExists(reissue.strName, asset, assetHeight, assetBlockHash))
1865  return error("%s: Failed to get the original asset that is getting reissued. Asset Name : %s",
1866  __func__, reissue.strName);
1867 
1868  // Insert the reissue information into the reissue map
1869  if (!mapReissuedAssetData.count(reissue.strName)) {
1870  asset.nAmount += reissue.nAmount;
1871  asset.nReissuable = reissue.nReissuable;
1872  if (reissue.nUnits != -1)
1873  asset.units = reissue.nUnits;
1874 
1875  if (reissue.strIPFSHash != "") {
1876  asset.nHasIPFS = 1;
1877  asset.strIPFSHash = reissue.strIPFSHash;
1878  }
1879  mapReissuedAssetData.insert(make_pair(reissue.strName, asset));
1880  } else {
1881  mapReissuedAssetData.at(reissue.strName).nAmount += reissue.nAmount;
1882  mapReissuedAssetData.at(reissue.strName).nReissuable = reissue.nReissuable;
1883  if (reissue.nUnits != -1) {
1884  mapReissuedAssetData.at(reissue.strName).units = reissue.nUnits;
1885  }
1886  if (reissue.strIPFSHash != "") {
1887  mapReissuedAssetData.at(reissue.strName).nHasIPFS = 1;
1888  mapReissuedAssetData.at(reissue.strName).strIPFSHash = reissue.strIPFSHash;
1889  }
1890  }
1891 
1892  CAssetCacheReissueAsset reissueAsset(reissue, address, out, assetHeight, assetBlockHash);
1893 
1894  if (setNewReissueToRemove.count(reissueAsset))
1895  setNewReissueToRemove.erase(reissueAsset);
1896 
1897  setNewReissueToAdd.insert(reissueAsset);
1898 
1899  if (fAssetIndex) {
1900  // Add the reissued amount to the address amount map
1901  if (!GetBestAssetAddressAmount(*this, reissue.strName, address))
1902  mapAssetsAddressAmount.insert(make_pair(pair, 0));
1903 
1904  // Add the reissued amount to the amount in the map
1905  mapAssetsAddressAmount[pair] += reissue.nAmount;
1906  }
1907 
1908  return true;
1909 
1910 }
1911 
1913 bool CAssetsCache::RemoveReissueAsset(const CReissueAsset& reissue, const std::string address, const COutPoint& out, const std::vector<std::pair<std::string, CBlockAssetUndo> >& vUndoIPFS)
1914 {
1915  auto pair = std::make_pair(reissue.strName, address);
1916 
1917  CNewAsset assetData;
1918  int height;
1919  uint256 blockHash;
1920  if (!GetAssetMetaDataIfExists(reissue.strName, assetData, height, blockHash))
1921  return error("%s: Tried undoing reissue of an asset, but that asset didn't exist: %s", __func__, reissue.strName);
1922 
1923  // Change the asset data by undoing what was reissued
1924  assetData.nAmount -= reissue.nAmount;
1925  assetData.nReissuable = 1;
1926 
1927  bool fVerifierStringChanged = false;
1928  std::string verifierString = "";
1929  // Find the ipfs hash in the undoblock data and restore the ipfs hash to its previous hash
1930  for (auto undoItem : vUndoIPFS) {
1931  if (undoItem.first == reissue.strName) {
1932  if (undoItem.second.fChangedIPFS)
1933  assetData.strIPFSHash = undoItem.second.strIPFS;
1934  if(undoItem.second.fChangedUnits)
1935  assetData.units = undoItem.second.nUnits;
1936  if (assetData.strIPFSHash == "")
1937  assetData.nHasIPFS = 0;
1938  if (undoItem.second.fChangedVerifierString) {
1939  fVerifierStringChanged = true;
1940  verifierString = undoItem.second.verifierString;
1941 
1942  }
1943  break;
1944  }
1945  }
1946 
1947  mapReissuedAssetData[assetData.strName] = assetData;
1948 
1949  CAssetCacheReissueAsset reissueAsset(reissue, address, out, height, blockHash);
1950 
1951  if (setNewReissueToAdd.count(reissueAsset))
1952  setNewReissueToAdd.erase(reissueAsset);
1953 
1954  setNewReissueToRemove.insert(reissueAsset);
1955 
1956  // If the verifier string was changed by this reissue, undo the change
1957  if (fVerifierStringChanged) {
1958  RemoveRestrictedVerifier(assetData.strName, verifierString, true);
1959  }
1960 
1961  if (fAssetIndex) {
1962  // Get the best amount form the database or dirty cache
1963  if (!GetBestAssetAddressAmount(*this, reissue.strName, address)) {
1964  if (reissueAsset.reissue.nAmount != 0)
1965  return error("%s : Trying to undo reissue of an asset but the assets amount isn't in the database",
1966  __func__);
1967  }
1968  mapAssetsAddressAmount[pair] -= reissue.nAmount;
1969 
1970  if (mapAssetsAddressAmount[pair] < 0)
1971  return error("%s : Tried undoing reissue of an asset, but the assets amount went negative: %s", __func__,
1972  reissue.strName);
1973  }
1974 
1975  return true;
1976 }
1977 
1979 bool CAssetsCache::AddOwnerAsset(const std::string& assetsName, const std::string address)
1980 {
1981  // Update the cache
1982  CAssetCacheNewOwner newOwner(assetsName, address);
1983 
1984  if (setNewOwnerAssetsToRemove.count(newOwner))
1985  setNewOwnerAssetsToRemove.erase(newOwner);
1986 
1987  setNewOwnerAssetsToAdd.insert(newOwner);
1988 
1989  if (fAssetIndex) {
1990  // Insert the asset into the assests address amount map
1991  mapAssetsAddressAmount[std::make_pair(assetsName, address)] = OWNER_ASSET_AMOUNT;
1992  }
1993 
1994  return true;
1995 }
1996 
1998 bool CAssetsCache::RemoveOwnerAsset(const std::string& assetsName, const std::string address)
1999 {
2000  // Update the cache
2001  CAssetCacheNewOwner newOwner(assetsName, address);
2002  if (setNewOwnerAssetsToAdd.count(newOwner))
2003  setNewOwnerAssetsToAdd.erase(newOwner);
2004 
2005  setNewOwnerAssetsToRemove.insert(newOwner);
2006 
2007  if (fAssetIndex) {
2008  auto pair = std::make_pair(assetsName, address);
2009  mapAssetsAddressAmount[pair] = 0;
2010  }
2011 
2012  return true;
2013 }
2014 
2016 bool CAssetsCache::RemoveTransfer(const CAssetTransfer &transfer, const std::string &address, const COutPoint &out)
2017 {
2018  if (!UndoTransfer(transfer, address, out))
2019  return error("%s : Failed to undo the transfer", __func__);
2020 
2021  CAssetCacheNewTransfer newTransfer(transfer, address, out);
2022  if (setNewTransferAssetsToAdd.count(newTransfer))
2023  setNewTransferAssetsToAdd.erase(newTransfer);
2024 
2025  setNewTransferAssetsToRemove.insert(newTransfer);
2026 
2027  return true;
2028 }
2029 
2031 bool CAssetsCache::AddQualifierAddress(const std::string& assetName, const std::string& address, const QualifierType type)
2032 {
2033  CAssetCacheQualifierAddress newQualifier(assetName, address, type);
2034 
2035  // We are adding a qualifier that was in a transaction, so, if the set of qualifiers
2036  // that contains qualifiers to undo contains the same qualfier assetName, and address, erase it
2037  if (setNewQualifierAddressToRemove.count(newQualifier)) {
2038  setNewQualifierAddressToRemove.erase(newQualifier);
2039  }
2040 
2041  // If the set of qualifiers from transactions contains our qualifier already, we need to overwrite it
2042  if (setNewQualifierAddressToAdd.count(newQualifier)) {
2043  setNewQualifierAddressToAdd.erase(newQualifier);
2044  }
2045 
2046  if (IsAssetNameASubQualifier(assetName)) {
2047  if (type == QualifierType::ADD_QUALIFIER) {
2048  mapRootQualifierAddressesAdd[CAssetCacheRootQualifierChecker(GetParentName(assetName), address)].insert(assetName);
2049  mapRootQualifierAddressesRemove[CAssetCacheRootQualifierChecker(GetParentName(assetName), address)].erase(assetName);
2050  } else {
2051  mapRootQualifierAddressesRemove[CAssetCacheRootQualifierChecker(GetParentName(assetName), address)].insert(assetName);
2052  mapRootQualifierAddressesAdd[CAssetCacheRootQualifierChecker(GetParentName(assetName), address)].erase(assetName);
2053  }
2054  }
2055 
2056  setNewQualifierAddressToAdd.insert(newQualifier);
2057 
2058  return true;
2059 }
2060 
2062 bool CAssetsCache::RemoveQualifierAddress(const std::string& assetName, const std::string& address, const QualifierType type)
2063 {
2064  CAssetCacheQualifierAddress newQualifier(assetName, address, type);
2065 
2066  // We are adding a qualifier that was in a transaction, so, if the set of qualifiers
2067  // that contains qualifiers to undo contains the same qualfier assetName, and address, erase it
2068  if (setNewQualifierAddressToAdd.count(newQualifier)) {
2069  setNewQualifierAddressToAdd.erase(newQualifier);
2070  }
2071 
2072  // If the set of qualifiers from transactions contains our qualifier already, we need to overwrite it
2073  if (setNewQualifierAddressToRemove.count(newQualifier)) {
2074  setNewQualifierAddressToRemove.erase(newQualifier);
2075  }
2076 
2077  if (IsAssetNameASubQualifier(assetName)) {
2078  if (type == QualifierType::ADD_QUALIFIER) {
2079  // When undoing a add, we want to remove it
2080  mapRootQualifierAddressesRemove[CAssetCacheRootQualifierChecker(GetParentName(assetName), address)].insert(assetName);
2081  mapRootQualifierAddressesAdd[CAssetCacheRootQualifierChecker(GetParentName(assetName), address)].erase(assetName);
2082  } else {
2083  // When undoing a remove, we want to add it
2084  mapRootQualifierAddressesAdd[CAssetCacheRootQualifierChecker(GetParentName(assetName), address)].insert(assetName);
2085  mapRootQualifierAddressesRemove[CAssetCacheRootQualifierChecker(GetParentName(assetName), address)].erase(assetName);
2086  }
2087  }
2088 
2089  setNewQualifierAddressToRemove.insert(newQualifier);
2090 
2091  return true;
2092 }
2093 
2094 
2096 bool CAssetsCache::AddRestrictedAddress(const std::string& assetName, const std::string& address, const RestrictedType type)
2097 {
2098  CAssetCacheRestrictedAddress newRestricted(assetName, address, type);
2099 
2100  // We are adding a restricted address that was in a transaction, so, if the set of restricted addresses
2101  // to undo contains our restricted address. Erase it
2102  if (setNewRestrictedAddressToRemove.count(newRestricted)) {
2103  setNewRestrictedAddressToRemove.erase(newRestricted);
2104  }
2105 
2106  // If the set of restricted addresses from transactions contains our restricted asset address already, we need to overwrite it
2107  if (setNewRestrictedAddressToAdd.count(newRestricted)) {
2108  setNewRestrictedAddressToAdd.erase(newRestricted);
2109  }
2110 
2111  setNewRestrictedAddressToAdd.insert(newRestricted);
2112 
2113  return true;
2114 }
2115 
2117 bool CAssetsCache::RemoveRestrictedAddress(const std::string& assetName, const std::string& address, const RestrictedType type)
2118 {
2119  CAssetCacheRestrictedAddress newRestricted(assetName, address, type);
2120 
2121  // We are undoing a restricted address transaction, so if the set that contains restricted address from new block
2122  // contains this restricted address, erase it.
2123  if (setNewRestrictedAddressToAdd.count(newRestricted)) {
2124  setNewRestrictedAddressToAdd.erase(newRestricted);
2125  }
2126 
2127  // If the set of restricted address to undo contains our restricted address already, we need to overwrite it
2128  if (setNewRestrictedAddressToRemove.count(newRestricted)) {
2129  setNewRestrictedAddressToRemove.erase(newRestricted);
2130  }
2131 
2132  setNewRestrictedAddressToRemove.insert(newRestricted);
2133 
2134  return true;
2135 }
2136 
2138 bool CAssetsCache::AddGlobalRestricted(const std::string& assetName, const RestrictedType type)
2139 {
2140  CAssetCacheRestrictedGlobal newGlobalRestriction(assetName, type);
2141 
2142  // We are adding a global restriction transaction, so if the set the contains undo global restrictions,
2143  // contains this global restriction, erase it
2144  if (setNewRestrictedGlobalToRemove.count(newGlobalRestriction)) {
2145  setNewRestrictedGlobalToRemove.erase(newGlobalRestriction);
2146  }
2147 
2148  // If the set of global restrictions to add already contains our set, overwrite it
2149  if (setNewRestrictedGlobalToAdd.count(newGlobalRestriction)) {
2150  setNewRestrictedGlobalToAdd.erase(newGlobalRestriction);
2151  }
2152 
2153  setNewRestrictedGlobalToAdd.insert(newGlobalRestriction);
2154 
2155  return true;
2156 }
2157 
2159 bool CAssetsCache::RemoveGlobalRestricted(const std::string& assetName, const RestrictedType type)
2160 {
2161  CAssetCacheRestrictedGlobal newGlobalRestriction(assetName, type);
2162 
2163  // We are undoing a global restriction transaction, so if the set the contains new global restrictions,
2164  // contains this global restriction, erase it
2165  if (setNewRestrictedGlobalToAdd.count(newGlobalRestriction)) {
2166  setNewRestrictedGlobalToAdd.erase(newGlobalRestriction);
2167  }
2168 
2169  // If the set of global restrictions to undo already contains our set, overwrite it
2170  if (setNewRestrictedGlobalToRemove.count(newGlobalRestriction)) {
2171  setNewRestrictedGlobalToRemove.erase(newGlobalRestriction);
2172  }
2173 
2174  setNewRestrictedGlobalToRemove.insert(newGlobalRestriction);
2175 
2176  return true;
2177 }
2178 
2180 bool CAssetsCache::AddRestrictedVerifier(const std::string& assetName, const std::string& verifier)
2181 {
2182  // Insert the reissue information into the reissue map
2183  CAssetCacheRestrictedVerifiers newVerifier(assetName, verifier);
2184 
2185  if (setNewRestrictedVerifierToRemove.count(newVerifier))
2186  setNewRestrictedVerifierToRemove.erase(newVerifier);
2187 
2188  setNewRestrictedVerifierToAdd.insert(newVerifier);
2189 
2190  return true;
2191 }
2192 
2194 bool CAssetsCache::RemoveRestrictedVerifier(const std::string& assetName, const std::string& verifier, const bool fUndoingReissue)
2195 {
2196  CAssetCacheRestrictedVerifiers newVerifier(assetName, verifier);
2197  newVerifier.fUndoingRessiue = fUndoingReissue;
2198 
2199  if (setNewRestrictedVerifierToAdd.count(newVerifier))
2200  setNewRestrictedVerifierToAdd.erase(newVerifier);
2201 
2202  setNewRestrictedVerifierToRemove.insert(newVerifier);
2203 
2204  return true;
2205 }
2206 
2208 {
2209  try {
2210  bool dirty = false;
2211  std::string message;
2212 
2213  // Remove new assets from the database
2214  for (auto newAsset : setNewAssetsToRemove) {
2215  passetsCache->Erase(newAsset.asset.strName);
2216  if (!passetsdb->EraseAssetData(newAsset.asset.strName)) {
2217  dirty = true;
2218  message = "_Failed Erasing New Asset Data from database";
2219  }
2220 
2221  if (dirty) {
2222  return error("%s : %s", __func__, message);
2223  }
2224 
2225  if (!prestricteddb->EraseVerifier(newAsset.asset.strName)) {
2226  dirty = true;
2227  message = "_Failed Erasing verifier of new asset removal data from database";
2228  }
2229 
2230  if (fAssetIndex) {
2231  if (!passetsdb->EraseAssetAddressQuantity(newAsset.asset.strName, newAsset.address)) {
2232  dirty = true;
2233  message = "_Failed Erasing Address Balance from database";
2234  }
2235 
2236  if (!passetsdb->EraseAddressAssetQuantity(newAsset.address, newAsset.asset.strName)) {
2237  dirty = true;
2238  message = "_Failed Erasing New Asset Address Balance from AddressAsset database";
2239  }
2240  }
2241 
2242  if (dirty) {
2243  return error("%s : %s", __func__, message);
2244  }
2245  }
2246 
2247  // Add the new assets to the database
2248  for (auto newAsset : setNewAssetsToAdd) {
2249  passetsCache->Put(newAsset.asset.strName, CDatabasedAssetData(newAsset.asset, newAsset.blockHeight, newAsset.blockHash));
2250  if (!passetsdb->WriteAssetData(newAsset.asset, newAsset.blockHeight, newAsset.blockHash)) {
2251  dirty = true;
2252  message = "_Failed Writing New Asset Data to database";
2253  }
2254 
2255  if (dirty) {
2256  return error("%s : %s", __func__, message);
2257  }
2258 
2259  if (fAssetIndex) {
2260  if (!passetsdb->WriteAssetAddressQuantity(newAsset.asset.strName, newAsset.address,
2261  newAsset.asset.nAmount)) {
2262  dirty = true;
2263  message = "_Failed Writing Address Balance to database";
2264  }
2265 
2266  if (!passetsdb->WriteAddressAssetQuantity(newAsset.address, newAsset.asset.strName,
2267  newAsset.asset.nAmount)) {
2268  dirty = true;
2269  message = "_Failed Writing Address Balance to database";
2270  }
2271  }
2272 
2273  if (dirty) {
2274  return error("%s : %s", __func__, message);
2275  }
2276  }
2277 
2278  if (fAssetIndex) {
2279  // Remove the new owners from database
2280  for (auto ownerAsset : setNewOwnerAssetsToRemove) {
2281  if (!passetsdb->EraseAssetAddressQuantity(ownerAsset.assetName, ownerAsset.address)) {
2282  dirty = true;
2283  message = "_Failed Erasing Owner Address Balance from database";
2284  }
2285 
2286  if (!passetsdb->EraseAddressAssetQuantity(ownerAsset.address, ownerAsset.assetName)) {
2287  dirty = true;
2288  message = "_Failed Erasing New Owner Address Balance from AddressAsset database";
2289  }
2290 
2291  if (dirty) {
2292  return error("%s : %s", __func__, message);
2293  }
2294  }
2295 
2296  // Add the new owners to database
2297  for (auto ownerAsset : setNewOwnerAssetsToAdd) {
2298  auto pair = std::make_pair(ownerAsset.assetName, ownerAsset.address);
2299  if (mapAssetsAddressAmount.count(pair) && mapAssetsAddressAmount.at(pair) > 0) {
2300  if (!passetsdb->WriteAssetAddressQuantity(ownerAsset.assetName, ownerAsset.address,
2301  mapAssetsAddressAmount.at(pair))) {
2302  dirty = true;
2303  message = "_Failed Writing Owner Address Balance to database";
2304  }
2305 
2306  if (!passetsdb->WriteAddressAssetQuantity(ownerAsset.address, ownerAsset.assetName,
2307  mapAssetsAddressAmount.at(pair))) {
2308  dirty = true;
2309  message = "_Failed Writing Address Balance to database";
2310  }
2311 
2312  if (dirty) {
2313  return error("%s : %s", __func__, message);
2314  }
2315  }
2316  }
2317 
2318  // Undo the transfering by updating the balances in the database
2319 
2320  for (auto undoTransfer : setNewTransferAssetsToRemove) {
2321  auto pair = std::make_pair(undoTransfer.transfer.strName, undoTransfer.address);
2322  if (mapAssetsAddressAmount.count(pair)) {
2323  if (mapAssetsAddressAmount.at(pair) == 0) {
2324  if (!passetsdb->EraseAssetAddressQuantity(undoTransfer.transfer.strName,
2325  undoTransfer.address)) {
2326  dirty = true;
2327  message = "_Failed Erasing Address Quantity from database";
2328  }
2329 
2330  if (!passetsdb->EraseAddressAssetQuantity(undoTransfer.address,
2331  undoTransfer.transfer.strName)) {
2332  dirty = true;
2333  message = "_Failed Erasing UndoTransfer Address Balance from AddressAsset database";
2334  }
2335 
2336  if (dirty) {
2337  return error("%s : %s", __func__, message);
2338  }
2339  } else {
2340  if (!passetsdb->WriteAssetAddressQuantity(undoTransfer.transfer.strName,
2341  undoTransfer.address,
2342  mapAssetsAddressAmount.at(pair))) {
2343  dirty = true;
2344  message = "_Failed Writing updated Address Quantity to database when undoing transfers";
2345  }
2346 
2347  if (!passetsdb->WriteAddressAssetQuantity(undoTransfer.address,
2348  undoTransfer.transfer.strName,
2349  mapAssetsAddressAmount.at(pair))) {
2350  dirty = true;
2351  message = "_Failed Writing Address Balance to database";
2352  }
2353 
2354  if (dirty) {
2355  return error("%s : %s", __func__, message);
2356  }
2357  }
2358  }
2359  }
2360 
2361 
2362  // Save the new transfers by updating the quantity in the database
2363  for (auto newTransfer : setNewTransferAssetsToAdd) {
2364  auto pair = std::make_pair(newTransfer.transfer.strName, newTransfer.address);
2365  // During init and reindex it disconnects and verifies blocks, can create a state where vNewTransfer will contain transfers that have already been spent. So if they aren't in the map, we can skip them.
2366  if (mapAssetsAddressAmount.count(pair)) {
2367  if (!passetsdb->WriteAssetAddressQuantity(newTransfer.transfer.strName, newTransfer.address,
2368  mapAssetsAddressAmount.at(pair))) {
2369  dirty = true;
2370  message = "_Failed Writing new address quantity to database";
2371  }
2372 
2373  if (!passetsdb->WriteAddressAssetQuantity(newTransfer.address, newTransfer.transfer.strName,
2374  mapAssetsAddressAmount.at(pair))) {
2375  dirty = true;
2376  message = "_Failed Writing Address Balance to database";
2377  }
2378 
2379  if (dirty) {
2380  return error("%s : %s", __func__, message);
2381  }
2382  }
2383  }
2384  }
2385 
2386  for (auto newReissue : setNewReissueToAdd) {
2387  auto reissue_name = newReissue.reissue.strName;
2388  auto pair = make_pair(reissue_name, newReissue.address);
2389  if (mapReissuedAssetData.count(reissue_name)) {
2390  if(!passetsdb->WriteAssetData(mapReissuedAssetData.at(reissue_name), newReissue.blockHeight, newReissue.blockHash)) {
2391  dirty = true;
2392  message = "_Failed Writing reissue asset data to database";
2393  }
2394 
2395  if (dirty) {
2396  return error("%s : %s", __func__, message);
2397  }
2398 
2399  passetsCache->Erase(reissue_name);
2400 
2401  if (fAssetIndex) {
2402 
2403  if (mapAssetsAddressAmount.count(pair) && mapAssetsAddressAmount.at(pair) > 0) {
2404  if (!passetsdb->WriteAssetAddressQuantity(pair.first, pair.second,
2405  mapAssetsAddressAmount.at(pair))) {
2406  dirty = true;
2407  message = "_Failed Writing reissue asset quantity to the address quantity database";
2408  }
2409 
2410  if (!passetsdb->WriteAddressAssetQuantity(pair.second, pair.first,
2411  mapAssetsAddressAmount.at(pair))) {
2412  dirty = true;
2413  message = "_Failed Writing Address Balance to database";
2414  }
2415 
2416  if (dirty) {
2417  return error("%s, %s", __func__, message);
2418  }
2419  }
2420  }
2421  }
2422  }
2423 
2424  for (auto undoReissue : setNewReissueToRemove) {
2425  // In the case the the issue and reissue are both being removed
2426  // we can skip this call because the removal of the issue should remove all data pertaining the to asset
2427  // Fixes the issue where the reissue data will write over the removed asset meta data that was removed above
2428  CNewAsset asset(undoReissue.reissue.strName, 0);
2429  CAssetCacheNewAsset testNewAssetCache(asset, "", 0 , uint256());
2430  if (setNewAssetsToRemove.count(testNewAssetCache)) {
2431  continue;
2432  }
2433 
2434  auto reissue_name = undoReissue.reissue.strName;
2435  if (mapReissuedAssetData.count(reissue_name)) {
2436  if(!passetsdb->WriteAssetData(mapReissuedAssetData.at(reissue_name), undoReissue.blockHeight, undoReissue.blockHash)) {
2437  dirty = true;
2438  message = "_Failed Writing undo reissue asset data to database";
2439  }
2440 
2441  if (fAssetIndex) {
2442  auto pair = make_pair(undoReissue.reissue.strName, undoReissue.address);
2443  if (mapAssetsAddressAmount.count(pair)) {
2444  if (mapAssetsAddressAmount.at(pair) == 0) {
2445  if (!passetsdb->EraseAssetAddressQuantity(reissue_name, undoReissue.address)) {
2446  dirty = true;
2447  message = "_Failed Erasing Address Balance from database";
2448  }
2449 
2450  if (!passetsdb->EraseAddressAssetQuantity(undoReissue.address, reissue_name)) {
2451  dirty = true;
2452  message = "_Failed Erasing UndoReissue Balance from AddressAsset database";
2453  }
2454  } else {
2455  if (!passetsdb->WriteAssetAddressQuantity(reissue_name, undoReissue.address,
2456  mapAssetsAddressAmount.at(pair))) {
2457  dirty = true;
2458  message = "_Failed Writing the undo of reissue of asset from database";
2459  }
2460 
2461  if (!passetsdb->WriteAddressAssetQuantity(undoReissue.address, reissue_name,
2462  mapAssetsAddressAmount.at(pair))) {
2463  dirty = true;
2464  message = "_Failed Writing Address Balance to database";
2465  }
2466  }
2467  }
2468  }
2469 
2470  if (dirty) {
2471  return error("%s : %s", __func__, message);
2472  }
2473 
2474  passetsCache->Erase(reissue_name);
2475  }
2476  }
2477 
2478  // Add new verifier strings for restricted assets
2479  for (auto newVerifier : setNewRestrictedVerifierToAdd) {
2480  auto assetName = newVerifier.assetName;
2481  if (!prestricteddb->WriteVerifier(assetName, newVerifier.verifier)) {
2482  dirty = true;
2483  message = "_Failed Writing restricted verifier to database";
2484  }
2485 
2486  if (dirty) {
2487  return error("%s : %s", __func__, message);
2488  }
2489 
2490  passetsVerifierCache->Erase(assetName);
2491  }
2492 
2493  // Undo verifier string for restricted assets
2494  for (auto undoVerifiers : setNewRestrictedVerifierToRemove) {
2495  auto assetName = undoVerifiers.assetName;
2496 
2497  // If we are undoing a reissue, we need to save back the old verifier string to database
2498  if (undoVerifiers.fUndoingRessiue) {
2499  if (!prestricteddb->WriteVerifier(assetName, undoVerifiers.verifier)) {
2500  dirty = true;
2501  message = "_Failed Writing undo restricted verifer to database";
2502  }
2503  } else {
2504  if (!prestricteddb->EraseVerifier(assetName)) {
2505  dirty = true;
2506  message = "_Failed Writing undo restricted verifer to database";
2507  }
2508  }
2509 
2510  if (dirty) {
2511  return error("%s : %s", __func__, message);
2512  }
2513 
2514  passetsVerifierCache->Erase(assetName);
2515  }
2516 
2517  // Add the new qualifier commands to the database
2518  for (auto newQualifierAddress : setNewQualifierAddressToAdd) {
2519  if (newQualifierAddress.type == QualifierType::REMOVE_QUALIFIER) {
2520  passetsQualifierCache->Erase(newQualifierAddress.GetHash().GetHex());
2521  if (!prestricteddb->EraseAddressQualifier(newQualifierAddress.address, newQualifierAddress.assetName)) {
2522  dirty = true;
2523  message = "_Failed Erasing address qualifier from database";
2524  }
2525  if (fAssetIndex && !dirty) {
2526  if (!prestricteddb->EraseQualifierAddress(newQualifierAddress.address,
2527  newQualifierAddress.assetName)) {
2528  dirty = true;
2529  message = "_Failed Erasing qualifier address from database";
2530  }
2531  }
2532  } else if (newQualifierAddress.type == QualifierType::ADD_QUALIFIER) {
2533  passetsQualifierCache->Put(newQualifierAddress.GetHash().GetHex(), 1);
2534  if (!prestricteddb->WriteAddressQualifier(newQualifierAddress.address, newQualifierAddress.assetName))
2535  {
2536  dirty = true;
2537  message = "_Failed Writing address qualifier to database";
2538  }
2539  if (fAssetIndex & !dirty) {
2540  if (!prestricteddb->WriteQualifierAddress(newQualifierAddress.address, newQualifierAddress.assetName))
2541  {
2542  dirty = true;
2543  message = "_Failed Writing qualifier address to database";
2544  }
2545  }
2546  }
2547 
2548  if (dirty) {
2549  return error("%s : %s", __func__, message);
2550  }
2551  }
2552 
2553  // Undo the qualifier commands
2554  for (auto undoQualifierAddress : setNewQualifierAddressToRemove) {
2555  if (undoQualifierAddress.type == QualifierType::REMOVE_QUALIFIER) { // If we are undoing a removal, we write the data to database
2556  passetsQualifierCache->Put(undoQualifierAddress.GetHash().GetHex(), 1);
2557  if (!prestricteddb->WriteAddressQualifier(undoQualifierAddress.address, undoQualifierAddress.assetName)) {
2558  dirty = true;
2559  message = "_Failed undoing a removal of a address qualifier from database";
2560  }
2561  if (fAssetIndex & !dirty) {
2562  if (!prestricteddb->WriteQualifierAddress(undoQualifierAddress.address, undoQualifierAddress.assetName))
2563  {
2564  dirty = true;
2565  message = "_Failed undoing a removal of a qualifier address from database";
2566  }
2567  }
2568  } else if (undoQualifierAddress.type == QualifierType::ADD_QUALIFIER) { // If we are undoing an addition, we remove the data from the database
2569  passetsQualifierCache->Erase(undoQualifierAddress.GetHash().GetHex());
2570  if (!prestricteddb->EraseAddressQualifier(undoQualifierAddress.address, undoQualifierAddress.assetName))
2571  {
2572  dirty = true;
2573  message = "_Failed undoing a addition of a address qualifier to database";
2574  }
2575  if (fAssetIndex && !dirty) {
2576  if (!prestricteddb->EraseQualifierAddress(undoQualifierAddress.address,
2577  undoQualifierAddress.assetName)) {
2578  dirty = true;
2579  message = "_Failed undoing a addition of a qualifier address from database";
2580  }
2581  }
2582  }
2583 
2584  if (dirty) {
2585  return error("%s : %s", __func__, message);
2586  }
2587  }
2588 
2589  // Add new restricted address commands
2590  for (auto newRestrictedAddress : setNewRestrictedAddressToAdd) {
2591  if (newRestrictedAddress.type == RestrictedType::UNFREEZE_ADDRESS) {
2592  passetsRestrictionCache->Erase(newRestrictedAddress.GetHash().GetHex());
2593  if (!prestricteddb->EraseRestrictedAddress(newRestrictedAddress.address, newRestrictedAddress.assetName)) {
2594  dirty = true;
2595  message = "_Failed Erasing restricted address from database";
2596  }
2597  } else if (newRestrictedAddress.type == RestrictedType::FREEZE_ADDRESS) {
2598  passetsRestrictionCache->Put(newRestrictedAddress.GetHash().GetHex(), 1);
2599  if (!prestricteddb->WriteRestrictedAddress(newRestrictedAddress.address, newRestrictedAddress.assetName))
2600  {
2601  dirty = true;
2602  message = "_Failed Writing restricted address to database";
2603  }
2604  }
2605 
2606  if (dirty) {
2607  return error("%s : %s", __func__, message);
2608  }
2609  }
2610 
2611  // Undo the qualifier addresses from database
2612  for (auto undoRestrictedAddress : setNewRestrictedAddressToRemove) {
2613  if (undoRestrictedAddress.type == RestrictedType::UNFREEZE_ADDRESS) { // If we are undoing an unfreeze, we need to freeze the address
2614  passetsRestrictionCache->Put(undoRestrictedAddress.GetHash().GetHex(), 1);
2615  if (!prestricteddb->WriteRestrictedAddress(undoRestrictedAddress.address, undoRestrictedAddress.assetName)) {
2616  dirty = true;
2617  message = "_Failed undoing a removal of a restricted address from database";
2618  }
2619  } else if (undoRestrictedAddress.type == RestrictedType::FREEZE_ADDRESS) { // If we are undoing a freeze, we need to unfreeze the address
2620  passetsRestrictionCache->Erase(undoRestrictedAddress.GetHash().GetHex());
2621  if (!prestricteddb->EraseRestrictedAddress(undoRestrictedAddress.address, undoRestrictedAddress.assetName))
2622  {
2623  dirty = true;
2624  message = "_Failed undoing a addition of a restricted address to database";
2625  }
2626  }
2627 
2628  if (dirty) {
2629  return error("%s : %s", __func__, message);
2630  }
2631  }
2632 
2633  // Add new global restriction commands
2634  for (auto newGlobalRestriction : setNewRestrictedGlobalToAdd) {
2635  if (newGlobalRestriction.type == RestrictedType::GLOBAL_UNFREEZE) {
2636  passetsGlobalRestrictionCache->Erase(newGlobalRestriction.assetName);
2637  if (!prestricteddb->EraseGlobalRestriction(newGlobalRestriction.assetName)) {
2638  dirty = true;
2639  message = "_Failed Erasing global restriction from database";
2640  }
2641  } else if (newGlobalRestriction.type == RestrictedType::GLOBAL_FREEZE) {
2642  passetsGlobalRestrictionCache->Put(newGlobalRestriction.assetName, 1);
2643  if (!prestricteddb->WriteGlobalRestriction(newGlobalRestriction.assetName))
2644  {
2645  dirty = true;
2646  message = "_Failed Writing global restriction to database";
2647  }
2648  }
2649 
2650  if (dirty) {
2651  return error("%s : %s", __func__, message);
2652  }
2653  }
2654 
2655  // Undo the global restriction commands
2656  for (auto undoGlobalRestriction : setNewRestrictedGlobalToRemove) {
2657  if (undoGlobalRestriction.type == RestrictedType::GLOBAL_UNFREEZE) { // If we are undoing an global unfreeze, we need to write a global freeze
2658  passetsGlobalRestrictionCache->Put(undoGlobalRestriction.assetName, 1);
2659  if (!prestricteddb->WriteGlobalRestriction(undoGlobalRestriction.assetName)) {
2660  dirty = true;
2661  message = "_Failed undoing a global unfreeze of a restricted asset from database";
2662  }
2663  } else if (undoGlobalRestriction.type == RestrictedType::GLOBAL_FREEZE) { // If we are undoing a global freeze, erase the freeze from the database
2664  passetsGlobalRestrictionCache->Erase(undoGlobalRestriction.assetName);
2665  if (!prestricteddb->EraseGlobalRestriction(undoGlobalRestriction.assetName))
2666  {
2667  dirty = true;
2668  message = "_Failed undoing a global freeze of a restricted asset to database";
2669  }
2670  }
2671 
2672  if (dirty) {
2673  return error("%s : %s", __func__, message);
2674  }
2675  }
2676 
2677  if (fAssetIndex) {
2678  // Undo the asset spends by updating there balance in the database
2679  for (auto undoSpend : vUndoAssetAmount) {
2680  auto pair = std::make_pair(undoSpend.assetName, undoSpend.address);
2681  if (mapAssetsAddressAmount.count(pair)) {
2682  if (!passetsdb->WriteAssetAddressQuantity(undoSpend.assetName, undoSpend.address,
2683  mapAssetsAddressAmount.at(pair))) {
2684  dirty = true;
2685  message = "_Failed Writing updated Address Quantity to database when undoing spends";
2686  }
2687 
2688  if (!passetsdb->WriteAddressAssetQuantity(undoSpend.address, undoSpend.assetName,
2689  mapAssetsAddressAmount.at(pair))) {
2690  dirty = true;
2691  message = "_Failed Writing Address Balance to database";
2692  }
2693 
2694  if (dirty) {
2695  return error("%s : %s", __func__, message);
2696  }
2697  }
2698  }
2699 
2700 
2701  // Save the assets that have been spent by erasing the quantity in the database
2702  for (auto spentAsset : vSpentAssets) {
2703  auto pair = make_pair(spentAsset.assetName, spentAsset.address);
2704  if (mapAssetsAddressAmount.count(pair)) {
2705  if (mapAssetsAddressAmount.at(pair) == 0) {
2706  if (!passetsdb->EraseAssetAddressQuantity(spentAsset.assetName, spentAsset.address)) {
2707  dirty = true;
2708  message = "_Failed Erasing a Spent Asset, from database";
2709  }
2710 
2711  if (!passetsdb->EraseAddressAssetQuantity(spentAsset.address, spentAsset.assetName)) {
2712  dirty = true;
2713  message = "_Failed Erasing a Spent Asset from AddressAsset database";
2714  }
2715 
2716  if (dirty) {
2717  return error("%s : %s", __func__, message);
2718  }
2719  } else {
2720  if (!passetsdb->WriteAssetAddressQuantity(spentAsset.assetName, spentAsset.address,
2721  mapAssetsAddressAmount.at(pair))) {
2722  dirty = true;
2723  message = "_Failed Erasing a Spent Asset, from database";
2724  }
2725 
2726  if (!passetsdb->WriteAddressAssetQuantity(spentAsset.address, spentAsset.assetName,
2727  mapAssetsAddressAmount.at(pair))) {
2728  dirty = true;
2729  message = "_Failed Writing Address Balance to database";
2730  }
2731 
2732  if (dirty) {
2733  return error("%s : %s", __func__, message);
2734  }
2735  }
2736  }
2737  }
2738  }
2739 
2740  ClearDirtyCache();
2741 
2742  return true;
2743  } catch (const std::runtime_error& e) {
2744  return error("%s : %s ", __func__, std::string("System error while flushing assets: ") + e.what());
2745  }
2746 }
2747 
2748 // This function will put all current cache data into the global passets cache.
2751 {
2752 
2753  if (!passets)
2754  return error("%s: Couldn't find passets pointer while trying to flush assets cache", __func__);
2755 
2756  try {
2757  for (auto &item : setNewAssetsToAdd) {
2758  if (passets->setNewAssetsToRemove.count(item))
2759  passets->setNewAssetsToRemove.erase(item);
2760  passets->setNewAssetsToAdd.insert(item);
2761  }
2762 
2763  for (auto &item : setNewAssetsToRemove) {
2764  if (passets->setNewAssetsToAdd.count(item))
2765  passets->setNewAssetsToAdd.erase(item);
2766  passets->setNewAssetsToRemove.insert(item);
2767  }
2768 
2769  for (auto &item : mapAssetsAddressAmount)
2770  passets->mapAssetsAddressAmount[item.first] = item.second;
2771 
2772  for (auto &item : mapReissuedAssetData)
2773  passets->mapReissuedAssetData[item.first] = item.second;
2774 
2775  for (auto &item : setNewOwnerAssetsToAdd) {
2776  if (passets->setNewOwnerAssetsToRemove.count(item))
2777  passets->setNewOwnerAssetsToRemove.erase(item);
2778  passets->setNewOwnerAssetsToAdd.insert(item);
2779  }
2780 
2781  for (auto &item : setNewOwnerAssetsToRemove) {
2782  if (passets->setNewOwnerAssetsToAdd.count(item))
2783  passets->setNewOwnerAssetsToAdd.erase(item);
2784  passets->setNewOwnerAssetsToRemove.insert(item);
2785  }
2786 
2787  for (auto &item : setNewReissueToAdd) {
2788  if (passets->setNewReissueToRemove.count(item))
2789  passets->setNewReissueToRemove.erase(item);
2790  passets->setNewReissueToAdd.insert(item);
2791  }
2792 
2793  for (auto &item : setNewReissueToRemove) {
2794  if (passets->setNewReissueToAdd.count(item))
2795  passets->setNewReissueToAdd.erase(item);
2796  passets->setNewReissueToRemove.insert(item);
2797  }
2798 
2799  for (auto &item : setNewTransferAssetsToAdd) {
2800  if (passets->setNewTransferAssetsToRemove.count(item))
2802  passets->setNewTransferAssetsToAdd.insert(item);
2803  }
2804 
2805  for (auto &item : setNewTransferAssetsToRemove) {
2806  if (passets->setNewTransferAssetsToAdd.count(item))
2807  passets->setNewTransferAssetsToAdd.erase(item);
2808  passets->setNewTransferAssetsToRemove.insert(item);
2809  }
2810 
2811  for (auto &item : vSpentAssets) {
2812  passets->vSpentAssets.emplace_back(item);
2813  }
2814 
2815  for (auto &item : vUndoAssetAmount) {
2816  passets->vUndoAssetAmount.emplace_back(item);
2817  }
2818 
2819  for(auto &item : setNewQualifierAddressToAdd) {
2820  if (passets->setNewQualifierAddressToRemove.count(item)) {
2822  }
2823 
2824  if (passets->setNewQualifierAddressToAdd.count(item)) {
2825  passets->setNewQualifierAddressToAdd.erase(item);
2826  }
2827 
2828  passets->setNewQualifierAddressToAdd.insert(item);
2829  }
2830 
2831  for(auto &item : setNewQualifierAddressToRemove) {
2832  if (passets->setNewQualifierAddressToAdd.count(item)) {
2833  passets->setNewQualifierAddressToAdd.erase(item);
2834  }
2835 
2836  if (passets->setNewQualifierAddressToRemove.count(item)) {
2838  }
2839 
2841  }
2842 
2843  for(auto &item : setNewRestrictedAddressToAdd) {
2844  if (passets->setNewRestrictedAddressToRemove.count(item)) {
2846  }
2847 
2848  if (passets->setNewRestrictedAddressToAdd.count(item)) {
2850  }
2851 
2852  passets->setNewRestrictedAddressToAdd.insert(item);
2853  }
2854 
2855  for(auto &item : setNewRestrictedAddressToRemove) {
2856  if (passets->setNewRestrictedAddressToAdd.count(item)) {
2858  }
2859 
2860  if (passets->setNewRestrictedAddressToRemove.count(item)) {
2862  }
2863 
2865  }
2866 
2867  for(auto &item : setNewRestrictedGlobalToAdd) {
2868  if (passets->setNewRestrictedGlobalToRemove.count(item)) {
2870  }
2871 
2872  if (passets->setNewRestrictedGlobalToAdd.count(item)) {
2873  passets->setNewRestrictedGlobalToAdd.erase(item);
2874  }
2875 
2876  passets->setNewRestrictedGlobalToAdd.insert(item);
2877  }
2878 
2879  for(auto &item : setNewRestrictedGlobalToRemove) {
2880  if (passets->setNewRestrictedGlobalToAdd.count(item)) {
2881  passets->setNewRestrictedGlobalToAdd.erase(item);
2882  }
2883 
2884  if (passets->setNewRestrictedGlobalToRemove.count(item)) {
2886  }
2887 
2889  }
2890 
2891  for (auto &item : setNewRestrictedVerifierToAdd) {
2892  if (passets->setNewRestrictedVerifierToRemove.count(item)) {
2894  }
2895 
2896  if (passets->setNewRestrictedVerifierToAdd.count(item)) {
2898  }
2899 
2900  passets->setNewRestrictedVerifierToAdd.insert(item);
2901  }
2902 
2903  for (auto &item : setNewRestrictedVerifierToRemove) {
2904  if (passets->setNewRestrictedVerifierToAdd.count(item)) {
2906  }
2907 
2908  if (passets->setNewRestrictedVerifierToRemove.count(item)) {
2910  }
2911 
2913  }
2914 
2915  for (auto &item : mapRootQualifierAddressesAdd) {
2916  for (auto asset : item.second) {
2917  passets->mapRootQualifierAddressesAdd[item.first].insert(asset);
2918  }
2919  }
2920 
2921  for (auto &item : mapRootQualifierAddressesRemove) {
2922  for (auto asset : item.second) {
2923  passets->mapRootQualifierAddressesAdd[item.first].insert(asset);
2924  }
2925  }
2926 
2927  return true;
2928 
2929  } catch (const std::runtime_error& e) {
2930  return error("%s : %s ", __func__, std::string("System error while flushing assets: ") + e.what());
2931  }
2932 }
2933 
2936 {
2937  // TODO make sure this is accurate
2938  return memusage::DynamicUsage(mapAssetsAddressAmount) + memusage::DynamicUsage(mapReissuedAssetData);
2939 }
2940 
2943 {
2944  // COutPoint: 32 bytes
2945  // CNewAsset: Max 80 bytes
2946  // CAssetTransfer: Asset Name, CAmount ( 40 bytes)
2947  // CReissueAsset: Max 80 bytes
2948  // CAmount: 8 bytes
2949  // Asset Name: Max 32 bytes
2950  // Address: 40 bytes
2951  // Block hash: 32 bytes
2952  // CTxOut: CAmount + CScript (105 + 8 = 113 bytes)
2953 
2954  size_t size = 0;
2955 
2956  size += (32 + 40 + 8) * vUndoAssetAmount.size(); // Asset Name, Address, CAmount
2957 
2958  size += (40 + 40 + 32) * setNewTransferAssetsToRemove.size(); // CAssetTrasnfer, Address, COutPoint
2959  size += (40 + 40 + 32) * setNewTransferAssetsToAdd.size(); // CAssetTrasnfer, Address, COutPoint
2960 
2961  size += 72 * setNewOwnerAssetsToAdd.size(); // Asset Name, Address
2962  size += 72 * setNewOwnerAssetsToRemove.size(); // Asset Name, Address
2963 
2964  size += (32 + 40 + 8) * vSpentAssets.size(); // Asset Name, Address, CAmount
2965 
2966  size += (80 + 40 + 32 + sizeof(int)) * setNewAssetsToAdd.size(); // CNewAsset, Address, Block hash, int
2967  size += (80 + 40 + 32 + sizeof(int)) * setNewAssetsToRemove.size(); // CNewAsset, Address, Block hash, int
2968 
2969  size += (80 + 40 + 32 + 32 + sizeof(int)) * setNewReissueToAdd.size(); // CReissueAsset, Address, COutPoint, Block hash, int
2970  size += (80 + 40 + 32 + 32 + sizeof(int)) * setNewReissueToRemove.size(); // CReissueAsset, Address, COutPoint, Block hash, int
2971 
2972  // TODO add the qualfier, and restricted sets into this calculation
2973 
2974  return size;
2975 }
2976 
2979 {
2980  // COutPoint: 32 bytes
2981  // CNewAsset: Max 80 bytes
2982  // CAssetTransfer: Asset Name, CAmount ( 40 bytes)
2983  // CReissueAsset: Max 80 bytes
2984  // CAmount: 8 bytes
2985  // Asset Name: Max 32 bytes
2986  // Address: 40 bytes
2987  // Block hash: 32 bytes
2988  // CTxOut: CAmount + CScript (105 + 8 = 113 bytes)
2989 
2990  size_t size = 0;
2991  size += memusage::DynamicUsage(vUndoAssetAmount);
2992  size += memusage::DynamicUsage(setNewTransferAssetsToRemove);
2993  size += memusage::DynamicUsage(setNewTransferAssetsToAdd);
2994  size += memusage::DynamicUsage(setNewOwnerAssetsToAdd);
2995  size += memusage::DynamicUsage(setNewOwnerAssetsToRemove);
2996  size += memusage::DynamicUsage(vSpentAssets);
2997  size += memusage::DynamicUsage(setNewAssetsToAdd);
2998  size += memusage::DynamicUsage(setNewAssetsToRemove);
2999  size += memusage::DynamicUsage(setNewReissueToAdd);
3000  size += memusage::DynamicUsage(setNewReissueToRemove);
3001 
3002  return size;
3003 }
3004 
3005 bool CheckIssueBurnTx(const CTxOut& txOut, const AssetType& type, const int numberIssued)
3006 {
3007  if (type == AssetType::REISSUE || type == AssetType::VOTE || type == AssetType::OWNER || type == AssetType::INVALID)
3008  return false;
3009 
3010  CAmount burnAmount = 0;
3011  std::string burnAddress = "";
3012 
3013  // Get the burn address and amount for the type of asset
3014  burnAmount = GetBurnAmount(type);
3015  burnAddress = GetBurnAddress(type);
3016 
3017  // If issuing multiple (unique) assets need to burn for each
3018  burnAmount *= numberIssued;
3019 
3020  // Check if script satisfies the burn amount
3021  if (!(txOut.nValue == burnAmount))
3022  return false;
3023 
3024  // Extract the destination
3025  CTxDestination destination;
3026  if (!ExtractDestination(txOut.scriptPubKey, destination))
3027  return false;
3028 
3029  // Verify destination is valid
3030  if (!IsValidDestination(destination))
3031  return false;
3032 
3033  // Check destination address is the burn address
3034  auto strDestination = EncodeDestination(destination);
3035  if (!(strDestination == burnAddress))
3036  return false;
3037 
3038  return true;
3039 }
3040 
3041 bool CheckIssueBurnTx(const CTxOut& txOut, const AssetType& type)
3042 {
3043  return CheckIssueBurnTx(txOut, type, 1);
3044 }
3045 
3046 bool CheckReissueBurnTx(const CTxOut& txOut)
3047 {
3048  // Check the first transaction and verify that the correct RVN Amount
3049  if (txOut.nValue != GetReissueAssetBurnAmount())
3050  return false;
3051 
3052  // Extract the destination
3053  CTxDestination destination;
3054  if (!ExtractDestination(txOut.scriptPubKey, destination))
3055  return false;
3056 
3057  // Verify destination is valid
3058  if (!IsValidDestination(destination))
3059  return false;
3060 
3061  // Check destination address is the correct burn address
3062  if (EncodeDestination(destination) != Params().ReissueAssetBurnAddress())
3063  return false;
3064 
3065  return true;
3066 }
3067 
3068 bool CheckIssueDataTx(const CTxOut& txOut)
3069 {
3070  // Verify 'rvnq' is in the transaction
3071  CScript scriptPubKey = txOut.scriptPubKey;
3072 
3073  int nStartingIndex = 0;
3074  return IsScriptNewAsset(scriptPubKey, nStartingIndex);
3075 }
3076 
3077 bool CheckReissueDataTx(const CTxOut& txOut)
3078 {
3079  // Verify 'rvnr' is in the transaction
3080  CScript scriptPubKey = txOut.scriptPubKey;
3081 
3082  return IsScriptReissueAsset(scriptPubKey);
3083 }
3084 
3085 bool CheckOwnerDataTx(const CTxOut& txOut)
3086 {
3087  // Verify 'rvnq' is in the transaction
3088  CScript scriptPubKey = txOut.scriptPubKey;
3089 
3090  return IsScriptOwnerAsset(scriptPubKey);
3091 }
3092 
3093 bool CheckTransferOwnerTx(const CTxOut& txOut)
3094 {
3095  // Verify 'rvnq' is in the transaction
3096  CScript scriptPubKey = txOut.scriptPubKey;
3097 
3098  return IsScriptTransferAsset(scriptPubKey);
3099 }
3100 
3101 bool IsScriptNewAsset(const CScript& scriptPubKey)
3102 {
3103  int index = 0;
3104  return IsScriptNewAsset(scriptPubKey, index);
3105 }
3106 
3107 bool IsScriptNewAsset(const CScript& scriptPubKey, int& nStartingIndex)
3108 {
3109  int nType = 0;
3110  bool fIsOwner =false;
3111  if (scriptPubKey.IsAssetScript(nType, fIsOwner, nStartingIndex)) {
3112  return nType == TX_NEW_ASSET && !fIsOwner;
3113  }
3114  return false;
3115 }
3116 
3117 bool IsScriptNewUniqueAsset(const CScript& scriptPubKey)
3118 {
3119  int index = 0;
3120  return IsScriptNewUniqueAsset(scriptPubKey, index);
3121 }
3122 
3123 bool IsScriptNewUniqueAsset(const CScript &scriptPubKey, int &nStartingIndex)
3124 {
3125  int nType = 0;
3126  bool fIsOwner = false;
3127  if (!scriptPubKey.IsAssetScript(nType, fIsOwner, nStartingIndex))
3128  return false;
3129 
3130  CNewAsset asset;
3131  std::string address;
3132  if (!AssetFromScript(scriptPubKey, asset, address))
3133  return false;
3134 
3135  AssetType assetType;
3136  if (!IsAssetNameValid(asset.strName, assetType))
3137  return false;
3138 
3139  return AssetType::UNIQUE == assetType;
3140 }
3141 
3142 bool IsScriptNewMsgChannelAsset(const CScript& scriptPubKey)
3143 {
3144  int index = 0;
3145  return IsScriptNewMsgChannelAsset(scriptPubKey, index);
3146 }
3147 
3148 bool IsScriptNewMsgChannelAsset(const CScript &scriptPubKey, int &nStartingIndex)
3149 {
3150  int nType = 0;
3151  bool fIsOwner = false;
3152  if (!scriptPubKey.IsAssetScript(nType, fIsOwner, nStartingIndex))
3153  return false;
3154 
3155  CNewAsset asset;
3156  std::string address;
3157  if (!AssetFromScript(scriptPubKey, asset, address))
3158  return false;
3159 
3160  AssetType assetType;
3161  if (!IsAssetNameValid(asset.strName, assetType))
3162  return false;
3163 
3164  return AssetType::MSGCHANNEL == assetType;
3165 }
3166 
3167 bool IsScriptOwnerAsset(const CScript& scriptPubKey)
3168 {
3169 
3170  int index = 0;
3171  return IsScriptOwnerAsset(scriptPubKey, index);
3172 }
3173 
3174 bool IsScriptOwnerAsset(const CScript& scriptPubKey, int& nStartingIndex)
3175 {
3176  int nType = 0;
3177  bool fIsOwner =false;
3178  if (scriptPubKey.IsAssetScript(nType, fIsOwner, nStartingIndex)) {
3179  return nType == TX_NEW_ASSET && fIsOwner;
3180  }
3181 
3182  return false;
3183 }
3184 
3185 bool IsScriptReissueAsset(const CScript& scriptPubKey)
3186 {
3187  int index = 0;
3188  return IsScriptReissueAsset(scriptPubKey, index);
3189 }
3190 
3191 bool IsScriptReissueAsset(const CScript& scriptPubKey, int& nStartingIndex)
3192 {
3193  int nType = 0;
3194  bool fIsOwner =false;
3195  if (scriptPubKey.IsAssetScript(nType, fIsOwner, nStartingIndex)) {
3196  return nType == TX_REISSUE_ASSET;
3197  }
3198 
3199  return false;
3200 }
3201 
3202 bool IsScriptTransferAsset(const CScript& scriptPubKey)
3203 {
3204  int index = 0;
3205  return IsScriptTransferAsset(scriptPubKey, index);
3206 }
3207 
3208 bool IsScriptTransferAsset(const CScript& scriptPubKey, int& nStartingIndex)
3209 {
3210  int nType = 0;
3211  bool fIsOwner = false;
3212  if (scriptPubKey.IsAssetScript(nType, fIsOwner, nStartingIndex)) {
3213  return nType == TX_TRANSFER_ASSET;
3214  }
3215 
3216  return false;
3217 }
3218 
3219 bool IsScriptNewQualifierAsset(const CScript& scriptPubKey)
3220 {
3221  int index = 0;
3222  return IsScriptNewQualifierAsset(scriptPubKey, index);
3223 }
3224 
3225 bool IsScriptNewQualifierAsset(const CScript &scriptPubKey, int &nStartingIndex)
3226 {
3227  int nType = 0;
3228  bool fIsOwner = false;
3229  if (!scriptPubKey.IsAssetScript(nType, fIsOwner, nStartingIndex))
3230  return false;
3231 
3232  CNewAsset asset;
3233  std::string address;
3234  if (!AssetFromScript(scriptPubKey, asset, address))
3235  return false;
3236 
3237  AssetType assetType;
3238  if (!IsAssetNameValid(asset.strName, assetType))
3239  return false;
3240 
3241  return AssetType::QUALIFIER == assetType || AssetType::SUB_QUALIFIER == assetType;
3242 }
3243 
3244 bool IsScriptNewRestrictedAsset(const CScript& scriptPubKey)
3245 {
3246  int index = 0;
3247  return IsScriptNewRestrictedAsset(scriptPubKey, index);
3248 }
3249 
3250 bool IsScriptNewRestrictedAsset(const CScript &scriptPubKey, int &nStartingIndex)
3251 {
3252  int nType = 0;
3253  bool fIsOwner = false;
3254  if (!scriptPubKey.IsAssetScript(nType, fIsOwner, nStartingIndex))
3255  return false;
3256 
3257  CNewAsset asset;
3258  std::string address;
3259  if (!AssetFromScript(scriptPubKey, asset, address))
3260  return false;
3261 
3262  AssetType assetType;
3263  if (!IsAssetNameValid(asset.strName, assetType))
3264  return false;
3265 
3266  return AssetType::RESTRICTED == assetType;
3267 }
3268 
3269 
3271 bool CAssetsCache::CheckIfAssetExists(const std::string& name, bool fForceDuplicateCheck)
3272 {
3273  // If we are reindexing, we don't know if an asset exists when accepting blocks
3274  if (fReindex) {
3275  return true;
3276  }
3277 
3278  // Create objects that will be used to check the dirty cache
3279  CNewAsset asset;
3280  asset.strName = name;
3281  CAssetCacheNewAsset cachedAsset(asset, "", 0, uint256());
3282 
3283  // Check the dirty caches first and see if it was recently added or removed
3284  if (setNewAssetsToRemove.count(cachedAsset)) {
3285  return false;
3286  }
3287 
3288  // Check the dirty caches first and see if it was recently added or removed
3289  if (passets->setNewAssetsToRemove.count(cachedAsset)) {
3290  return false;
3291  }
3292 
3293  if (setNewAssetsToAdd.count(cachedAsset)) {
3294  if (fForceDuplicateCheck) {
3295  return true;
3296  }
3297  else {
3298  LogPrintf("%s : Found asset %s in setNewAssetsToAdd but force duplicate check wasn't true\n", __func__, name);
3299  }
3300  }
3301 
3302  if (passets->setNewAssetsToAdd.count(cachedAsset)) {
3303  if (fForceDuplicateCheck) {
3304  return true;
3305  }
3306  else {
3307  LogPrintf("%s : Found asset %s in setNewAssetsToAdd but force duplicate check wasn't true\n", __func__, name);
3308  }
3309  }
3310 
3311  // Check the cache, if it doesn't exist in the cache. Try and read it from database
3312  if (passetsCache) {
3313  if (passetsCache->Exists(name)) {
3314  if (fForceDuplicateCheck) {
3315  return true;
3316  }
3317  else {
3318  LogPrintf("%s : Found asset %s in passetsCache but force duplicate check wasn't true\n", __func__, name);
3319  }
3320  } else {
3321  if (passetsdb) {
3322  CNewAsset readAsset;
3323  int nHeight;
3324  uint256 hash;
3325  if (passetsdb->ReadAssetData(name, readAsset, nHeight, hash)) {
3326  passetsCache->Put(readAsset.strName, CDatabasedAssetData(readAsset, nHeight, hash));
3327  if (fForceDuplicateCheck) {
3328  return true;
3329  }
3330  else {
3331  LogPrintf("%s : Found asset %s in passetsdb but force duplicate check wasn't true\n", __func__, name);
3332  }
3333  }
3334  }
3335  }
3336  }
3337  return false;
3338 }
3339 
3340 bool CAssetsCache::GetAssetMetaDataIfExists(const std::string &name, CNewAsset &asset)
3341 {
3342  int height;
3343  uint256 hash;
3344  return GetAssetMetaDataIfExists(name, asset, height, hash);
3345 }
3346 
3347 bool CAssetsCache::GetAssetMetaDataIfExists(const std::string &name, CNewAsset &asset, int& nHeight, uint256& blockHash)
3348 {
3349  // Check the map that contains the reissued asset data. If it is in this map, it hasn't been saved to disk yet
3350  if (mapReissuedAssetData.count(name)) {
3351  asset = mapReissuedAssetData.at(name);
3352  return true;
3353  }
3354 
3355  // Check the map that contains the reissued asset data. If it is in this map, it hasn't been saved to disk yet
3356  if (passets->mapReissuedAssetData.count(name)) {
3357  asset = passets->mapReissuedAssetData.at(name);
3358  return true;
3359  }
3360 
3361  // Create objects that will be used to check the dirty cache
3362  CNewAsset tempAsset;
3363  tempAsset.strName = name;
3364  CAssetCacheNewAsset cachedAsset(tempAsset, "", 0, uint256());
3365 
3366  // Check the dirty caches first and see if it was recently added or removed
3367  if (setNewAssetsToRemove.count(cachedAsset)) {
3368  LogPrintf("%s : Found in new assets to Remove - Returning False\n", __func__);
3369  return false;
3370  }
3371 
3372  // Check the dirty caches first and see if it was recently added or removed
3373  if (passets->setNewAssetsToRemove.count(cachedAsset)) {
3374  LogPrintf("%s : Found in new assets to Remove - Returning False\n", __func__);
3375  return false;
3376  }
3377 
3378  auto setIterator = setNewAssetsToAdd.find(cachedAsset);
3379  if (setIterator != setNewAssetsToAdd.end()) {
3380  asset = setIterator->asset;
3381  nHeight = setIterator->blockHeight;
3382  blockHash = setIterator->blockHash;
3383  return true;
3384  }
3385 
3386  setIterator = passets->setNewAssetsToAdd.find(cachedAsset);
3387  if (setIterator != passets->setNewAssetsToAdd.end()) {
3388  asset = setIterator->asset;
3389  nHeight = setIterator->blockHeight;
3390  blockHash = setIterator->blockHash;
3391  return true;
3392  }
3393 
3394  // Check the cache, if it doesn't exist in the cache. Try and read it from database
3395  if (passetsCache) {
3396  if (passetsCache->Exists(name)) {
3397  CDatabasedAssetData data;
3398  data = passetsCache->Get(name);
3399  asset = data.asset;
3400  nHeight = data.nHeight;
3401  blockHash = data.blockHash;
3402  return true;
3403  }
3404  }
3405 
3406  if (passetsdb && passetsCache) {
3407  CNewAsset readAsset;
3408  int height;
3409  uint256 hash;
3410  if (passetsdb->ReadAssetData(name, readAsset, height, hash)) {
3411  asset = readAsset;
3412  nHeight = height;
3413  blockHash = hash;
3414  passetsCache->Put(readAsset.strName, CDatabasedAssetData(readAsset, height, hash));
3415  return true;
3416  }
3417  }
3418 
3419  LogPrintf("%s : Didn't find asset meta data anywhere. Returning False\n", __func__);
3420  return false;
3421 }
3422 
3423 bool GetAssetInfoFromScript(const CScript& scriptPubKey, std::string& strName, CAmount& nAmount)
3424 {
3425  CAssetOutputEntry data;
3426  if(!GetAssetData(scriptPubKey, data))
3427  return false;
3428 
3429  strName = data.assetName;
3430  nAmount = data.nAmount;
3431 
3432  return true;
3433 }
3434 
3435 bool GetAssetInfoFromCoin(const Coin& coin, std::string& strName, CAmount& nAmount)
3436 {
3437  return GetAssetInfoFromScript(coin.out.scriptPubKey, strName, nAmount);
3438 }
3439 
3440 bool GetAssetData(const CScript& script, CAssetOutputEntry& data)
3441 {
3442  // Placeholder strings that will get set if you successfully get the transfer or asset from the script
3443  std::string address = "";
3444  std::string assetName = "";
3445 
3446  int nType = 0;
3447  bool fIsOwner = false;
3448  if (!script.IsAssetScript(nType, fIsOwner)) {
3449  return false;
3450  }
3451 
3452  txnouttype type = txnouttype(nType);
3453 
3454  // Get the New Asset or Transfer Asset from the scriptPubKey
3455  if (type == TX_NEW_ASSET && !fIsOwner) {
3456  CNewAsset asset;
3457  if (AssetFromScript(script, asset, address)) {
3458  data.type = TX_NEW_ASSET;
3459  data.nAmount = asset.nAmount;
3460  data.destination = DecodeDestination(address);
3461  data.assetName = asset.strName;
3462  return true;
3463  }
3464  } else if (type == TX_TRANSFER_ASSET) {
3466  if (TransferAssetFromScript(script, transfer, address)) {
3467  data.type = TX_TRANSFER_ASSET;
3468  data.nAmount = transfer.nAmount;
3469  data.destination = DecodeDestination(address);
3470  data.assetName = transfer.strName;
3471  data.message = transfer.message;
3472  data.expireTime = transfer.nExpireTime;
3473  return true;
3474  } else {
3475  LogPrintf("Failed to get transfer from script\n");
3476  }
3477  } else if (type == TX_NEW_ASSET && fIsOwner) {
3478  if (OwnerAssetFromScript(script, assetName, address)) {
3479  data.type = TX_NEW_ASSET;
3480  data.nAmount = OWNER_ASSET_AMOUNT;
3481  data.destination = DecodeDestination(address);
3482  data.assetName = assetName;
3483  return true;
3484  }
3485  } else if (type == TX_REISSUE_ASSET) {
3487  if (ReissueAssetFromScript(script, reissue, address)) {
3488  data.type = TX_REISSUE_ASSET;
3489  data.nAmount = reissue.nAmount;
3490  data.destination = DecodeDestination(address);
3491  data.assetName = reissue.strName;
3492  return true;
3493  }
3494  }
3495 
3496  return false;
3497 }
3498 
3499 void GetAllAdministrativeAssets(CWallet *pwallet, std::vector<std::string> &names, int nMinConf)
3500 {
3501  if(!pwallet)
3502  return;
3503 
3504  GetAllMyAssets(pwallet, names, nMinConf, true, true);
3505 }
3506 
3507 void GetAllMyAssets(CWallet* pwallet, std::vector<std::string>& names, int nMinConf, bool fIncludeAdministrator, bool fOnlyAdministrator)
3508 {
3509  if(!pwallet)
3510  return;
3511 
3512  std::map<std::string, std::vector<COutput> > mapAssets;
3513  pwallet->AvailableAssets(mapAssets, true, nullptr, 1, MAX_MONEY, MAX_MONEY, 0, nMinConf); // Set the mincof, set the rest to the defaults
3514 
3515  for (auto item : mapAssets) {
3516  bool isOwner = IsAssetNameAnOwner(item.first);
3517 
3518  if (isOwner) {
3519  if (fOnlyAdministrator || fIncludeAdministrator)
3520  names.emplace_back(item.first);
3521  } else {
3522  if (fOnlyAdministrator)
3523  continue;
3524  names.emplace_back(item.first);
3525  }
3526  }
3527 }
3528 
3530 {
3531  return Params().IssueAssetBurnAmount();
3532 }
3533 
3535 {
3536  return Params().ReissueAssetBurnAmount();
3537 }
3538 
3540 {
3541  return Params().IssueSubAssetBurnAmount();
3542 }
3543 
3545 {
3547 }
3548 
3550 {
3552 }
3553 
3555 {
3557 }
3558 
3560 {
3562 }
3563 
3565 {
3567 }
3568 
3570 {
3572 }
3573 
3574 CAmount GetBurnAmount(const int nType)
3575 {
3576  return GetBurnAmount((AssetType(nType)));
3577 }
3578 
3580 {
3581  switch (type) {
3582  case AssetType::ROOT:
3583  return GetIssueAssetBurnAmount();
3584  case AssetType::SUB:
3585  return GetIssueSubAssetBurnAmount();
3586  case AssetType::MSGCHANNEL:
3588  case AssetType::OWNER:
3589  return 0;
3590  case AssetType::UNIQUE:
3592  case AssetType::VOTE:
3593  return 0;
3594  case AssetType::REISSUE:
3595  return GetReissueAssetBurnAmount();
3596  case AssetType::QUALIFIER:
3600  case AssetType::RESTRICTED:
3604  default:
3605  return 0;
3606  }
3607 }
3608 
3609 std::string GetBurnAddress(const int nType)
3610 {
3611  return GetBurnAddress((AssetType(nType)));
3612 }
3613 
3614 std::string GetBurnAddress(const AssetType type)
3615 {
3616  switch (type) {
3617  case AssetType::ROOT:
3618  return Params().IssueAssetBurnAddress();
3619  case AssetType::SUB:
3620  return Params().IssueSubAssetBurnAddress();
3621  case AssetType::MSGCHANNEL:
3623  case AssetType::OWNER:
3624  return "";
3625  case AssetType::UNIQUE:
3627  case AssetType::VOTE:
3628  return "";
3629  case AssetType::REISSUE:
3630  return Params().ReissueAssetBurnAddress();
3631  case AssetType::QUALIFIER:
3635  case AssetType::RESTRICTED:
3639  default:
3640  return "";
3641  }
3642 }
3643 
3645 bool GetBestAssetAddressAmount(CAssetsCache& cache, const std::string& assetName, const std::string& address)
3646 {
3647  if (fAssetIndex) {
3648  auto pair = make_pair(assetName, address);
3649 
3650  // If the caches map has the pair, return true because the map already contains the best dirty amount
3651  if (cache.mapAssetsAddressAmount.count(pair))
3652  return true;
3653 
3654  // If the caches map has the pair, return true because the map already contains the best dirty amount
3655  if (passets->mapAssetsAddressAmount.count(pair)) {
3656  cache.mapAssetsAddressAmount[pair] = passets->mapAssetsAddressAmount.at(pair);
3657  return true;
3658  }
3659 
3660  // If the database contains the assets address amount, insert it into the database and return true
3661  CAmount nDBAmount;
3662  if (passetsdb->ReadAssetAddressQuantity(pair.first, pair.second, nDBAmount)) {
3663  cache.mapAssetsAddressAmount.insert(make_pair(pair, nDBAmount));
3664  return true;
3665  }
3666  }
3667 
3668  // The amount wasn't found return false
3669  return false;
3670 }
3671 
3673 bool GetAllMyAssetBalances(std::map<std::string, std::vector<COutput> >& outputs, std::map<std::string, CAmount>& amounts, const int confirmations, const std::string& prefix) {
3674 
3675  // Return false if no wallet was found to compute asset balances
3676  if (!vpwallets.size())
3677  return false;
3678 
3679  // Get the map of assetnames to outputs
3680  vpwallets[0]->AvailableAssets(outputs, true, nullptr, 1, MAX_MONEY, MAX_MONEY, 0, confirmations);
3681 
3682  // Loop through all pairs of Asset Name -> vector<COutput>
3683  for (const auto& pair : outputs) {
3684  if (prefix.empty() || pair.first.find(prefix) == 0) { // Check for prefix
3685  CAmount balance = 0;
3686  for (auto txout : pair.second) { // Compute balance of asset by summing all Available Outputs
3687  CAssetOutputEntry data;
3688  if (GetAssetData(txout.tx->tx->vout[txout.i].scriptPubKey, data))
3689  balance += data.nAmount;
3690  }
3691  amounts.insert(std::make_pair(pair.first, balance));
3692  }
3693  }
3694 
3695  return true;
3696 }
3697 
3698 // 46 char base58 --> 34 char KAW compatible
3699 std::string DecodeAssetData(std::string encoded)
3700 {
3701  if (encoded.size() == 46) {
3702  std::vector<unsigned char> b;
3703  DecodeBase58(encoded, b);
3704  return std::string(b.begin(), b.end());
3705  }
3706 
3707  else if (encoded.size() == 64 && IsHex(encoded)) {
3708  std::vector<unsigned char> vec = ParseHex(encoded);
3709  return std::string(vec.begin(), vec.end());
3710  }
3711 
3712  return "";
3713 
3714 };
3715 
3716 std::string EncodeAssetData(std::string decoded)
3717 {
3718  if (decoded.size() == 34) {
3719  return EncodeIPFS(decoded);
3720  }
3721  else if (decoded.size() == 32){
3722  return HexStr(decoded);
3723  }
3724 
3725  return "";
3726 }
3727 
3728 // 46 char base58 --> 34 char KAW compatible
3729 std::string DecodeIPFS(std::string encoded)
3730 {
3731  std::vector<unsigned char> b;
3732  DecodeBase58(encoded, b);
3733  return std::string(b.begin(), b.end());
3734 };
3735 
3736 // 34 char KAW compatible --> 46 char base58
3737 std::string EncodeIPFS(std::string decoded){
3738  std::vector<char> charData(decoded.begin(), decoded.end());
3739  std::vector<unsigned char> unsignedCharData;
3740  for (char c : charData)
3741  unsignedCharData.push_back(static_cast<unsigned char>(c));
3742  return EncodeBase58(unsignedCharData);
3743 };
3744 
3745 bool CreateAssetTransaction(CWallet* pwallet, CCoinControl& coinControl, const CNewAsset& asset, const std::string& address, std::pair<int, std::string>& error, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRequired, std::string* verifier_string)
3746 {
3747  std::vector<CNewAsset> assets;
3748  assets.push_back(asset);
3749  return CreateAssetTransaction(pwallet, coinControl, assets, address, error, wtxNew, reservekey, nFeeRequired, verifier_string);
3750 }
3751 
3752 bool CreateAssetTransaction(CWallet* pwallet, CCoinControl& coinControl, const std::vector<CNewAsset> assets, const std::string& address, std::pair<int, std::string>& error, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRequired, std::string* verifier_string)
3753 {
3754  std::string change_address = EncodeDestination(coinControl.destChange);
3755 
3756  auto currentActiveAssetCache = GetCurrentAssetCache();
3757  // Validate the assets data
3758  std::string strError;
3759  for (auto asset : assets) {
3760  if (!ContextualCheckNewAsset(currentActiveAssetCache, asset, strError)) {
3761  error = std::make_pair(RPC_INVALID_PARAMETER, strError);
3762  return false;
3763  }
3764  }
3765 
3766  if (!change_address.empty()) {
3767  CTxDestination destination = DecodeDestination(change_address);
3768  if (!IsValidDestination(destination)) {
3769  error = std::make_pair(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Raven address: ") + change_address);
3770  return false;
3771  }
3772  } else {
3773  // no coin control: send change to newly generated address
3774  CKeyID keyID;
3775  std::string strFailReason;
3776  if (!pwallet->CreateNewChangeAddress(reservekey, keyID, strFailReason)) {
3777  error = std::make_pair(RPC_WALLET_KEYPOOL_RAN_OUT, strFailReason);
3778  return false;
3779  }
3780 
3781  change_address = EncodeDestination(keyID);
3782  coinControl.destChange = DecodeDestination(change_address);
3783  }
3784 
3785  AssetType assetType;
3786  std::string parentName;
3787  for (auto asset : assets) {
3788  if (!IsAssetNameValid(asset.strName, assetType)) {
3789  error = std::make_pair(RPC_INVALID_PARAMETER, "Asset name not valid");
3790  return false;
3791  }
3792  if (assets.size() > 1 && assetType != AssetType::UNIQUE) {
3793  error = std::make_pair(RPC_INVALID_PARAMETER, "Only unique assets can be issued in bulk.");
3794  return false;
3795  }
3796  std::string parent = GetParentName(asset.strName);
3797  if (parentName.empty())
3798  parentName = parent;
3799  if (parentName != parent) {
3800  error = std::make_pair(RPC_INVALID_PARAMETER, "All assets must have the same parent.");
3801  return false;
3802  }
3803  }
3804 
3805  // Assign the correct burn amount and the correct burn address depending on the type of asset issuance that is happening
3806  CAmount burnAmount = GetBurnAmount(assetType) * assets.size();
3808 
3809  CAmount curBalance = pwallet->GetBalance();
3810 
3811  // Check to make sure the wallet has the RVN required by the burnAmount
3812  if (curBalance < burnAmount) {
3813  error = std::make_pair(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
3814  return false;
3815  }
3816 
3817  if (pwallet->GetBroadcastTransactions() && !g_connman) {
3818  error = std::make_pair(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
3819  return false;
3820  }
3821 
3822  LOCK2(cs_main, pwallet->cs_wallet);
3823 
3824  // Create and send the transaction
3825  std::string strTxError;
3826  std::vector<CRecipient> vecSend;
3827  int nChangePosRet = -1;
3828  bool fSubtractFeeFromAmount = false;
3829 
3830  CRecipient recipient = {scriptPubKey, burnAmount, fSubtractFeeFromAmount};
3831  vecSend.push_back(recipient);
3832 
3833  // If the asset is a subasset or unique asset. We need to send the ownertoken change back to ourselfs
3834  if (assetType == AssetType::SUB || assetType == AssetType::UNIQUE || assetType == AssetType::MSGCHANNEL) {
3835  // Get the script for the destination address for the assets
3836  CScript scriptTransferOwnerAsset = GetScriptForDestination(DecodeDestination(change_address));
3837 
3838  CAssetTransfer assetTransfer(parentName + OWNER_TAG, OWNER_ASSET_AMOUNT);
3839  assetTransfer.ConstructTransaction(scriptTransferOwnerAsset);
3840  CRecipient rec = {scriptTransferOwnerAsset, 0, fSubtractFeeFromAmount};
3841  vecSend.push_back(rec);
3842  }
3843 
3844  // If the asset is a sub qualifier. We need to send the token parent change back to ourselfs
3845  if (assetType == AssetType::SUB_QUALIFIER) {
3846  // Get the script for the destination address for the assets
3847  CScript scriptTransferQualifierAsset = GetScriptForDestination(DecodeDestination(change_address));
3848 
3849  CAssetTransfer assetTransfer(parentName, OWNER_ASSET_AMOUNT);
3850  assetTransfer.ConstructTransaction(scriptTransferQualifierAsset);
3851  CRecipient rec = {scriptTransferQualifierAsset, 0, fSubtractFeeFromAmount};
3852  vecSend.push_back(rec);
3853  }
3854 
3855  // Get the owner outpoints if this is a subasset or unique asset
3856  if (assetType == AssetType::SUB || assetType == AssetType::UNIQUE || assetType == AssetType::MSGCHANNEL) {
3857  // Verify that this wallet is the owner for the asset, and get the owner asset outpoint
3858  for (auto asset : assets) {
3859  if (!VerifyWalletHasAsset(parentName + OWNER_TAG, error)) {
3860  return false;
3861  }
3862  }
3863  }
3864 
3865  // Get the owner outpoints if this is a sub_qualifier asset
3866  if (assetType == AssetType::SUB_QUALIFIER) {
3867  // Verify that this wallet is the owner for the asset, and get the owner asset outpoint
3868  for (auto asset : assets) {
3869  if (!VerifyWalletHasAsset(parentName, error)) {
3870  return false;
3871  }
3872  }
3873  }
3874 
3875  if (assetType == AssetType::RESTRICTED) {
3876  // Restricted assets require the ROOT! token to be sent with the issuance
3877  CScript scriptTransferOwnerAsset = GetScriptForDestination(DecodeDestination(change_address));
3878 
3879  // Create a transaction that sends the ROOT owner token (e.g. $TOKEN requires TOKEN!)
3880  std::string strStripped = parentName.substr(1, parentName.size() - 1);
3881 
3882  // Verify that this wallet is the owner for the asset, and get the owner asset outpoint
3883  if (!VerifyWalletHasAsset(strStripped + OWNER_TAG, error)) {
3884  return false;
3885  }
3886 
3887  CAssetTransfer assetTransfer(strStripped + OWNER_TAG, OWNER_ASSET_AMOUNT);
3888  assetTransfer.ConstructTransaction(scriptTransferOwnerAsset);
3889 
3890  CRecipient ownerRec = {scriptTransferOwnerAsset, 0, fSubtractFeeFromAmount};
3891  vecSend.push_back(ownerRec);
3892 
3893  // Every restricted asset issuance must have a verifier string
3894  if (!verifier_string) {
3895  error = std::make_pair(RPC_INVALID_PARAMETER, "Error: Verifier string not found");
3896  return false;
3897  }
3898 
3899  // Create the asset null data transaction that will get added to the issue transaction
3900  CScript verifierScript;
3901  CNullAssetTxVerifierString verifier(*verifier_string);
3902  verifier.ConstructTransaction(verifierScript);
3903 
3904  CRecipient rec = {verifierScript, 0, false};
3905  vecSend.push_back(rec);
3906  }
3907 
3908  if (!pwallet->CreateTransactionWithAssets(vecSend, wtxNew, reservekey, nFeeRequired, nChangePosRet, strTxError, coinControl, assets, DecodeDestination(address), assetType)) {
3909  if (!fSubtractFeeFromAmount && burnAmount + nFeeRequired > curBalance)
3910  strTxError = strprintf("Error: This transaction requires a transaction fee of at least %s", FormatMoney(nFeeRequired));
3911  error = std::make_pair(RPC_WALLET_ERROR, strTxError);
3912  return false;
3913  }
3914  return true;
3915 }
3916 
3917 bool CreateReissueAssetTransaction(CWallet* pwallet, CCoinControl& coinControl, const CReissueAsset& reissueAsset, const std::string& address, std::pair<int, std::string>& error, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRequired, std::string* verifier_string)
3918 {
3919  // Create transaction variables
3920  std::string strTxError;
3921  std::vector<CRecipient> vecSend;
3922  int nChangePosRet = -1;
3923  bool fSubtractFeeFromAmount = false;
3924 
3925  // Create asset variables
3926  std::string asset_name = reissueAsset.strName;
3927  std::string change_address = EncodeDestination(coinControl.destChange);
3928 
3929  // Get the asset type
3930  AssetType asset_type = AssetType::INVALID;
3931  IsAssetNameValid(asset_name, asset_type);
3932 
3933  // Check that validitity of the address
3934  if (!IsValidDestinationString(address)) {
3935  error = std::make_pair(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Raven address: ") + address);
3936  return false;
3937  }
3938 
3939  // Build the change address
3940  if (!change_address.empty()) {
3941  CTxDestination destination = DecodeDestination(change_address);
3942  if (!IsValidDestination(destination)) {
3943  error = std::make_pair(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Raven address: ") + change_address);
3944  return false;
3945  }
3946  } else {
3947  CKeyID keyID;
3948  std::string strFailReason;
3949  if (!pwallet->CreateNewChangeAddress(reservekey, keyID, strFailReason)) {
3950  error = std::make_pair(RPC_WALLET_KEYPOOL_RAN_OUT, strFailReason);
3951  return false;
3952  }
3953 
3954  change_address = EncodeDestination(keyID);
3955  coinControl.destChange = DecodeDestination(change_address);
3956  }
3957 
3958  // Check the assets name
3959  if (!IsAssetNameValid(asset_name)) {
3960  error = std::make_pair(RPC_INVALID_PARAMS, std::string("Invalid asset name: ") + asset_name);
3961  return false;
3962  }
3963 
3964  // Check to make sure this isn't an owner token
3965  if (IsAssetNameAnOwner(asset_name)) {
3966  error = std::make_pair(RPC_INVALID_PARAMS, std::string("Owner Assets are not able to be reissued"));
3967  return false;
3968  }
3969 
3970  // passets and passetsCache need to be initialized
3971  auto currentActiveAssetCache = GetCurrentAssetCache();
3972  if (!currentActiveAssetCache) {
3973  error = std::make_pair(RPC_DATABASE_ERROR, std::string("passets isn't initialized"));
3974  return false;
3975  }
3976 
3977  // Fail if the asset cache isn't initialized
3978  if (!passetsCache) {
3979  error = std::make_pair(RPC_DATABASE_ERROR,
3980  std::string("passetsCache isn't initialized"));
3981  return false;
3982  }
3983 
3984  // Check to make sure that the reissue asset data is valid
3985  std::string strError;
3986  if (!ContextualCheckReissueAsset(currentActiveAssetCache, reissueAsset, strError)) {
3987  error = std::make_pair(RPC_VERIFY_ERROR,
3988  std::string("Failed to create reissue asset object. Error: ") + strError);
3989  return false;
3990  }
3991 
3992  // strip of the first character of the asset name, this is used for restricted assets only
3993  std::string stripped_asset_name = asset_name.substr(1, asset_name.size() - 1);
3994 
3995  // If we are reissuing a restricted asset, check to see if we have the root owner token $TOKEN check for TOKEN!
3996  if (asset_type == AssetType::RESTRICTED) {
3997  // Verify that this wallet is the owner for the asset, and get the owner asset outpoint
3998  if (!VerifyWalletHasAsset(stripped_asset_name + OWNER_TAG, error)) {
3999  return false;
4000  }
4001  } else {
4002  // Verify that this wallet is the owner for the asset, and get the owner asset outpoint
4003  if (!VerifyWalletHasAsset(asset_name + OWNER_TAG, error)) {
4004  return false;
4005  }
4006  }
4007 
4008  // Check the wallet balance
4009  CAmount curBalance = pwallet->GetBalance();
4010 
4011  // Get the current burn amount for issuing an asset
4012  CAmount burnAmount = GetReissueAssetBurnAmount();
4013 
4014  // Check to make sure the wallet has the RVN required by the burnAmount
4015  if (curBalance < burnAmount) {
4016  error = std::make_pair(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
4017  return false;
4018  }
4019 
4020  if (pwallet->GetBroadcastTransactions() && !g_connman) {
4021  error = std::make_pair(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
4022  return false;
4023  }
4024 
4025  // Get the script for the destination address for the assets
4026  CScript scriptTransferOwnerAsset = GetScriptForDestination(DecodeDestination(change_address));
4027 
4028  if (asset_type == AssetType::RESTRICTED) {
4029  CAssetTransfer assetTransfer(stripped_asset_name + OWNER_TAG, OWNER_ASSET_AMOUNT);
4030  assetTransfer.ConstructTransaction(scriptTransferOwnerAsset);
4031  } else {
4032  CAssetTransfer assetTransfer(asset_name + OWNER_TAG, OWNER_ASSET_AMOUNT);
4033  assetTransfer.ConstructTransaction(scriptTransferOwnerAsset);
4034  }
4035 
4036  if (asset_type == AssetType::RESTRICTED) {
4037  // If we are changing the verifier string, check to make sure the new address meets the new verifier string rules
4038  if (verifier_string) {
4039  if (reissueAsset.nAmount > 0) {
4040  std::string strError = "";
4041  if (!ContextualCheckVerifierString(passets, *verifier_string, address, strError))
4042  throw JSONRPCError(RPC_INVALID_PARAMETER, strError);
4043  } else {
4044  // If we aren't adding any assets but we are changing the verifier string, Check to make sure the verifier string parses correctly
4045  std::string strError = "";
4046  if (!ContextualCheckVerifierString(passets, *verifier_string, "", strError))
4047  throw JSONRPCError(RPC_INVALID_PARAMETER, strError);
4048  }
4049  } else {
4050  // If the user is reissuing more assets, and they aren't changing the verifier string, check it against the current verifier string
4051  if (reissueAsset.nAmount > 0) {
4052  CNullAssetTxVerifierString verifier;
4053  if (!passets->GetAssetVerifierStringIfExists(reissueAsset.strName, verifier))
4054  throw JSONRPCError(RPC_DATABASE_ERROR, "Failed to get the assets cache pointer");
4055 
4056  std::string strError = "";
4057  if (!ContextualCheckVerifierString(passets, verifier.verifier_string, address, strError))
4058  throw JSONRPCError(RPC_INVALID_PARAMETER, strError);
4059  }
4060  }
4061 
4062  // Every restricted asset issuance must have a verifier string
4063  if (verifier_string) {
4064  // Create the asset null data transaction that will get added to the issue transaction
4065  CScript verifierScript;
4066  CNullAssetTxVerifierString verifier(*verifier_string);
4067  verifier.ConstructTransaction(verifierScript);
4068 
4069  CRecipient rec = {verifierScript, 0, false};
4070  vecSend.push_back(rec);
4071  }
4072  }
4073 
4074  // Get the script for the burn address
4075  CScript scriptPubKeyBurn = GetScriptForDestination(DecodeDestination(Params().ReissueAssetBurnAddress()));
4076 
4077  // Create and send the transaction
4078  CRecipient recipient = {scriptPubKeyBurn, burnAmount, fSubtractFeeFromAmount};
4079  CRecipient recipient2 = {scriptTransferOwnerAsset, 0, fSubtractFeeFromAmount};
4080  vecSend.push_back(recipient);
4081  vecSend.push_back(recipient2);
4082  if (!pwallet->CreateTransactionWithReissueAsset(vecSend, wtxNew, reservekey, nFeeRequired, nChangePosRet, strTxError, coinControl, reissueAsset, DecodeDestination(address))) {
4083  if (!fSubtractFeeFromAmount && burnAmount + nFeeRequired > curBalance)
4084  strTxError = strprintf("Error: This transaction requires a transaction fee of at least %s", FormatMoney(nFeeRequired));
4085  error = std::make_pair(RPC_WALLET_ERROR, strTxError);
4086  return false;
4087  }
4088  return true;
4089 }
4090 
4091 
4092 // nullAssetTxData -> Use this for freeze/unfreeze an address or adding a qualifier to an address
4093 // nullGlobalRestrictionData -> Use this to globally freeze/unfreeze a restricted asset.
4094 bool CreateTransferAssetTransaction(CWallet* pwallet, const CCoinControl& coinControl, const std::vector< std::pair<CAssetTransfer, std::string> >vTransfers, const std::string& changeAddress, std::pair<int, std::string>& error, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRequired, std::vector<std::pair<CNullAssetTxData, std::string> >* nullAssetTxData, std::vector<CNullAssetTxData>* nullGlobalRestrictionData)
4095 {
4096  // Initialize Values for transaction
4097  std::string strTxError;
4098  std::vector<CRecipient> vecSend;
4099  int nChangePosRet = -1;
4100  bool fSubtractFeeFromAmount = false;
4101 
4102  // Check for a balance before processing transfers
4103  CAmount curBalance = pwallet->GetBalance();
4104  if (curBalance == 0) {
4105  error = std::make_pair(RPC_WALLET_INSUFFICIENT_FUNDS, std::string("This wallet doesn't contain any RVN, transfering an asset requires a network fee"));
4106  return false;
4107  }
4108 
4109  // Check for peers and connections
4110  if (pwallet->GetBroadcastTransactions() && !g_connman) {
4111  error = std::make_pair(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
4112  return false;
4113  }
4114 
4115  // Loop through all transfers and create scriptpubkeys for them
4116  for (auto transfer : vTransfers) {
4117  std::string address = transfer.second;
4118  std::string asset_name = transfer.first.strName;
4119  std::string message = transfer.first.message;
4120  CAmount nAmount = transfer.first.nAmount;
4121  int64_t expireTime = transfer.first.nExpireTime;
4122 
4123  if (!IsValidDestinationString(address)) {
4124  error = std::make_pair(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Raven address: ") + address);
4125  return false;
4126  }
4127  auto currentActiveAssetCache = GetCurrentAssetCache();
4128  if (!currentActiveAssetCache) {
4129  error = std::make_pair(RPC_DATABASE_ERROR, std::string("passets isn't initialized"));
4130  return false;
4131  }
4132 
4133  if (!VerifyWalletHasAsset(asset_name, error)) // Sets error if it fails
4134  return false;
4135 
4136  // If it is an ownership transfer, make a quick check to make sure the amount is 1
4137  if (IsAssetNameAnOwner(asset_name)) {
4138  if (nAmount != OWNER_ASSET_AMOUNT) {
4139  error = std::make_pair(RPC_INVALID_PARAMS, std::string(
4140  _("When transferring an 'Ownership Asset' the amount must always be 1. Please try again with the amount of 1")));
4141  return false;
4142  }
4143  }
4144 
4145  // If the asset is a restricted asset, check the verifier script
4146  if(IsAssetNameAnRestricted(asset_name)) {
4147  std::string strError = "";
4148 
4149  // Check for global restriction
4150  if (passets->CheckForGlobalRestriction(transfer.first.strName, true)) {
4151  error = std::make_pair(RPC_INVALID_PARAMETER, _("Unable to transfer restricted asset, this restricted asset has been globally frozen"));
4152  return false;
4153  }
4154 
4155  if (!transfer.first.ContextualCheckAgainstVerifyString(passets, address, strError)) {
4156  error = std::make_pair(RPC_INVALID_PARAMETER, strError);
4157  return false;
4158  }
4159 
4160  if (!coinControl.destChange.empty()) {
4161  std::string change_address = EncodeDestination(coinControl.destChange);
4162  // If this is a transfer of a restricted asset, check the destination address against the verifier string
4163  CNullAssetTxVerifierString verifier;
4164  if (!passets->GetAssetVerifierStringIfExists(asset_name, verifier))
4165  throw JSONRPCError(RPC_DATABASE_ERROR, _("Unable to get restricted assets verifier string. Database out of sync. Reindex required"));
4166 
4167  if (!ContextualCheckVerifierString(passets, verifier.verifier_string, change_address, strError))
4169  std::string(_("Change address can not be sent to because it doesn't have the correct qualifier tags") + strError));
4170  }
4171  }
4172 
4173  // Get the script for the burn address
4174  CScript scriptPubKey = GetScriptForDestination(DecodeDestination(address));
4175 
4176  // Update the scriptPubKey with the transfer asset information
4177  CAssetTransfer assetTransfer(asset_name, nAmount, message, expireTime);
4178  assetTransfer.ConstructTransaction(scriptPubKey);
4179 
4180  CRecipient recipient = {scriptPubKey, 0, fSubtractFeeFromAmount};
4181  vecSend.push_back(recipient);
4182  }
4183 
4184  // If assetTxData is not nullptr, the user wants to add some OP_RVN_ASSET data transactions into the transaction
4185  if (nullAssetTxData) {
4186  std::string strError = "";
4187  int nAddTagCount = 0;
4188  for (auto pair : *nullAssetTxData) {
4189 
4190  if (IsAssetNameAQualifier(pair.first.asset_name)) {
4191  if (!VerifyQualifierChange(*passets, pair.first, pair.second, strError))
4192  throw JSONRPCError(RPC_INVALID_REQUEST, strError);
4193 
4194  if (pair.first.flag == (int)QualifierType::ADD_QUALIFIER)
4195  nAddTagCount++;
4196  } else if (IsAssetNameAnRestricted(pair.first.asset_name)) {
4197  if (!VerifyRestrictedAddressChange(*passets, pair.first, pair.second, strError))
4198  throw JSONRPCError(RPC_INVALID_REQUEST, strError);
4199  }
4200 
4202  pair.first.ConstructTransaction(dataScript);
4203 
4204  CRecipient recipient = {dataScript, 0, false};
4205  vecSend.push_back(recipient);
4206  }
4207 
4208  // Add the burn recipient for adding tags to addresses
4209  if (nAddTagCount) {
4211  CRecipient addTagBurnRecipient = {addTagBurnScript, GetBurnAmount(AssetType::NULL_ADD_QUALIFIER) * nAddTagCount, false};
4212  vecSend.push_back(addTagBurnRecipient);
4213  }
4214  }
4215 
4216  // nullGlobalRestiotionData, the user wants to add OP_RVN_ASSET OP_RVN_ASSET OP_RVN_ASSETS data transaction to the transaction
4217  if (nullGlobalRestrictionData) {
4218  std::string strError = "";
4219  for (auto dataObject : *nullGlobalRestrictionData) {
4220 
4221  if (!VerifyGlobalRestrictedChange(*passets, dataObject, strError))
4222  throw JSONRPCError(RPC_INVALID_REQUEST, strError);
4223 
4224  CScript dataScript;
4225  dataObject.ConstructGlobalRestrictionTransaction(dataScript);
4226  CRecipient recipient = {dataScript, 0, false};
4227  vecSend.push_back(recipient);
4228  }
4229  }
4230 
4231  // Create and send the transaction
4232  if (!pwallet->CreateTransactionWithTransferAsset(vecSend, wtxNew, reservekey, nFeeRequired, nChangePosRet, strTxError, coinControl)) {
4233  if (!fSubtractFeeFromAmount && nFeeRequired > curBalance) {
4234  error = std::make_pair(RPC_WALLET_ERROR, strprintf("Error: This transaction requires a transaction fee of at least %s", FormatMoney(nFeeRequired)));
4235  return false;
4236  }
4237  error = std::make_pair(RPC_TRANSACTION_ERROR, strTxError);
4238  return false;
4239  }
4240  return true;
4241 }
4242 
4243 bool SendAssetTransaction(CWallet* pwallet, CWalletTx& transaction, CReserveKey& reserveKey, std::pair<int, std::string>& error, std::string& txid)
4244 {
4245  CValidationState state;
4246  if (!pwallet->CommitTransaction(transaction, reserveKey, g_connman.get(), state)) {
4247  error = std::make_pair(RPC_WALLET_ERROR, strprintf("Error: The transaction was rejected! Reason given: %s", state.GetRejectReason()));
4248  return false;
4249  }
4250 
4251  txid = transaction.GetHash().GetHex();
4252  return true;
4253 }
4254 
4255 bool VerifyWalletHasAsset(const std::string& asset_name, std::pair<int, std::string>& pairError)
4256 {
4257  CWallet* pwallet;
4258  if (vpwallets.size() > 0)
4259  pwallet = vpwallets[0];
4260  else {
4261  pairError = std::make_pair(RPC_WALLET_ERROR, strprintf("Wallet not found. Can't verify if it contains: %s", asset_name));
4262  return false;
4263  }
4264 
4265  std::vector<COutput> vCoins;
4266  std::map<std::string, std::vector<COutput> > mapAssetCoins;
4267  pwallet->AvailableAssets(mapAssetCoins);
4268 
4269  if (mapAssetCoins.count(asset_name))
4270  return true;
4271 
4272  pairError = std::make_pair(RPC_INVALID_REQUEST, strprintf("Wallet doesn't have asset: %s", asset_name));
4273  return false;
4274 }
4275 
4276 // Return true if the amount is valid with the units passed in
4277 bool CheckAmountWithUnits(const CAmount& nAmount, const int8_t nUnits)
4278 {
4279  return nAmount % int64_t(pow(10, (MAX_UNIT - nUnits))) == 0;
4280 }
4281 
4282 bool CheckEncoded(const std::string& hash, std::string& strError) {
4283  std::string encodedStr = EncodeAssetData(hash);
4284  if (encodedStr.substr(0, 2) == "Qm" && encodedStr.size() == 46) {
4285  return true;
4286  }
4287 
4288  if (AreMessagingDeployed()) {
4289  if (IsHex(encodedStr) && encodedStr.length() == 64) {
4290  return true;
4291  }
4292  }
4293 
4294  strError = _("Invalid parameter: ipfs_hash is not valid, or txid hash is not the right length");
4295 
4296  return false;
4297 }
4298 
4299 void GetTxOutAssetTypes(const std::vector<CTxOut>& vout, int& issues, int& reissues, int& transfers, int& owners)
4300 {
4301  for (auto out: vout) {
4302  int type;
4303  bool fIsOwner;
4304  if (out.scriptPubKey.IsAssetScript(type, fIsOwner)) {
4305  if (type == TX_NEW_ASSET && !fIsOwner)
4306  issues++;
4307  else if (type == TX_NEW_ASSET && fIsOwner)
4308  owners++;
4309  else if (type == TX_TRANSFER_ASSET)
4310  transfers++;
4311  else if (type == TX_REISSUE_ASSET)
4312  reissues++;
4313  }
4314  }
4315 }
4316 
4317 bool ParseAssetScript(CScript scriptPubKey, uint160 &hashBytes, std::string &assetName, CAmount &assetAmount) {
4318  int nType;
4319  bool fIsOwner;
4320  int _nStartingPoint;
4321  std::string _strAddress;
4322  bool isAsset = false;
4323  if (scriptPubKey.IsAssetScript(nType, fIsOwner, _nStartingPoint)) {
4324  if (nType == TX_NEW_ASSET) {
4325  if (fIsOwner) {
4326  if (OwnerAssetFromScript(scriptPubKey, assetName, _strAddress)) {
4327  assetAmount = OWNER_ASSET_AMOUNT;
4328  isAsset = true;
4329  } else {
4330  LogPrintf("%s : Couldn't get new owner asset from script: %s", __func__, HexStr(scriptPubKey));
4331  }
4332  } else {
4333  CNewAsset asset;
4334  if (AssetFromScript(scriptPubKey, asset, _strAddress)) {
4335  assetName = asset.strName;
4336  assetAmount = asset.nAmount;
4337  isAsset = true;
4338  } else {
4339  LogPrintf("%s : Couldn't get new asset from script: %s", __func__, HexStr(scriptPubKey));
4340  }
4341  }
4342  } else if (nType == TX_REISSUE_ASSET) {
4343  CReissueAsset asset;
4344  if (ReissueAssetFromScript(scriptPubKey, asset, _strAddress)) {
4345  assetName = asset.strName;
4346  assetAmount = asset.nAmount;
4347  isAsset = true;
4348  } else {
4349  LogPrintf("%s : Couldn't get reissue asset from script: %s", __func__, HexStr(scriptPubKey));
4350  }
4351  } else if (nType == TX_TRANSFER_ASSET) {
4352  CAssetTransfer asset;
4353  if (TransferAssetFromScript(scriptPubKey, asset, _strAddress)) {
4354  assetName = asset.strName;
4355  assetAmount = asset.nAmount;
4356  isAsset = true;
4357  } else {
4358  LogPrintf("%s : Couldn't get transfer asset from script: %s", __func__, HexStr(scriptPubKey));
4359  }
4360  } else {
4361  LogPrintf("%s : Unsupported asset type: %s", __func__, nType);
4362  }
4363  } else {
4364 // LogPrintf("%s : Found no asset in script: %s", __func__, HexStr(scriptPubKey));
4365  }
4366  if (isAsset) {
4367 // LogPrintf("%s : Found assets in script at address %s : %s (%s)", __func__, _strAddress, assetName, assetAmount);
4368  hashBytes = uint160(std::vector <unsigned char>(scriptPubKey.begin()+3, scriptPubKey.begin()+23));
4369  return true;
4370  }
4371  return false;
4372 }
4373 
4374 CNullAssetTxData::CNullAssetTxData(const std::string &strAssetname, const int8_t &nFlag)
4375 {
4376  SetNull();
4377  this->asset_name = strAssetname;
4378  this->flag = nFlag;
4379 }
4380 
4381 bool CNullAssetTxData::IsValid(std::string &strError, CAssetsCache &assetCache, bool fForceCheckPrimaryAssetExists) const
4382 {
4383  AssetType type;
4384  if (!IsAssetNameValid(asset_name, type)) {
4385  strError = _("Asset name is not valid");
4386  return false;
4387  }
4388 
4389  if (type != AssetType::QUALIFIER && type != AssetType::SUB_QUALIFIER && type != AssetType::RESTRICTED) {
4390  strError = _("Asset must be a qualifier, sub qualifier, or a restricted asset");
4391  return false;
4392  }
4393 
4394  if (flag != 0 || flag != 1) {
4395  strError = _("Flag must be 1 or 0");
4396  return false;
4397  }
4398 
4399  if (fForceCheckPrimaryAssetExists) {
4400  if (!assetCache.CheckIfAssetExists(asset_name)) {
4401  strError = _("Asset doesn't exist: ") + asset_name;
4402  return false;
4403  }
4404  }
4405 
4406  return true;
4407 }
4408 
4410 {
4411  CDataStream ssAssetTxData(SER_NETWORK, PROTOCOL_VERSION);
4412  ssAssetTxData << *this;
4413 
4414  std::vector<unsigned char> vchMessage;
4415  vchMessage.insert(vchMessage.end(), ssAssetTxData.begin(), ssAssetTxData.end());
4416  script << ToByteVector(vchMessage);
4417 }
4418 
4420 {
4421  CDataStream ssAssetTxData(SER_NETWORK, PROTOCOL_VERSION);
4422  ssAssetTxData << *this;
4423 
4424  std::vector<unsigned char> vchMessage;
4425  vchMessage.insert(vchMessage.end(), ssAssetTxData.begin(), ssAssetTxData.end());
4426  script << OP_RVN_ASSET << OP_RESERVED << OP_RESERVED << ToByteVector(vchMessage);
4427 }
4428 
4430 {
4431  SetNull();
4432  this->verifier_string = verifier;
4433 }
4434 
4436 {
4437  CDataStream ssAssetTxData(SER_NETWORK, PROTOCOL_VERSION);
4438  ssAssetTxData << *this;
4439 
4440  std::vector<unsigned char> vchMessage;
4441  vchMessage.insert(vchMessage.end(), ssAssetTxData.begin(), ssAssetTxData.end());
4442  script << OP_RVN_ASSET << OP_RESERVED << ToByteVector(vchMessage);
4443 }
4444 
4445 bool CAssetsCache::GetAssetVerifierStringIfExists(const std::string &name, CNullAssetTxVerifierString& verifierString, bool fSkipTempCache)
4446 {
4447 
4458  // Create objects that will be used to check the dirty cache
4459  CAssetCacheRestrictedVerifiers tempCacheVerifier {name, ""};
4460 
4461  auto setIterator = setNewRestrictedVerifierToRemove.find(tempCacheVerifier);
4462  // Check the dirty caches first and see if it was recently added or removed
4463  if (!fSkipTempCache && setIterator != setNewRestrictedVerifierToRemove.end()) {
4464  if (setIterator->fUndoingRessiue) {
4465  verifierString.verifier_string = setIterator->verifier;
4466  return true;
4467  }
4468  return false;
4469  }
4470 
4471  setIterator = passets->setNewRestrictedVerifierToRemove.find(tempCacheVerifier);
4472  // Check the dirty caches first and see if it was recently added or removed
4473  if (setIterator != passets->setNewRestrictedVerifierToRemove.end()) {
4474  if (setIterator->fUndoingRessiue) {
4475  verifierString.verifier_string = setIterator->verifier;
4476  return true;
4477  }
4478  return false;
4479  }
4480 
4481  setIterator = setNewRestrictedVerifierToAdd.find(tempCacheVerifier);
4482  if (!fSkipTempCache && setIterator != setNewRestrictedVerifierToAdd.end()) {
4483  verifierString.verifier_string = setIterator->verifier;
4484  return true;
4485  }
4486 
4487  setIterator = passets->setNewRestrictedVerifierToAdd.find(tempCacheVerifier);
4488  if (setIterator != passets->setNewRestrictedVerifierToAdd.end()) {
4489  verifierString.verifier_string = setIterator->verifier;
4490  return true;
4491  }
4492 
4493  // Check the cache, if it doesn't exist in the cache. Try and read it from database
4494  if (passetsVerifierCache) {
4495  if (passetsVerifierCache->Exists(name)) {
4496  verifierString = passetsVerifierCache->Get(name);
4497  return true;
4498  }
4499  }
4500 
4501  if (prestricteddb) {
4502  std::string verifier;
4503  if (prestricteddb->ReadVerifier(name, verifier)) {
4504  verifierString.verifier_string = verifier;
4506  passetsVerifierCache->Put(name, verifierString);
4507  return true;
4508  }
4509  }
4510 
4511  return false;
4512 }
4513 
4514 bool CAssetsCache::CheckForAddressQualifier(const std::string &qualifier_name, const std::string& address, bool fSkipTempCache)
4515 {
4525  // Create cache object that will be used to check the dirty caches
4526  CAssetCacheQualifierAddress cachedQualifierAddress(qualifier_name, address, QualifierType::ADD_QUALIFIER);
4527 
4528  // Check the dirty caches first and see if it was recently added or removed
4529  auto setIterator = setNewQualifierAddressToRemove.find(cachedQualifierAddress);
4530  if (!fSkipTempCache &&setIterator != setNewQualifierAddressToRemove.end()) {
4531  // Undoing a remove qualifier command, means that we are adding the qualifier to the address
4532  return setIterator->type == QualifierType::REMOVE_QUALIFIER;
4533  }
4534 
4535 
4536  setIterator = passets->setNewQualifierAddressToRemove.find(cachedQualifierAddress);
4537  if (setIterator != passets->setNewQualifierAddressToRemove.end()) {
4538  // Undoing a remove qualifier command, means that we are adding the qualifier to the address
4539  return setIterator->type == QualifierType::REMOVE_QUALIFIER;
4540  }
4541 
4542  setIterator = setNewQualifierAddressToAdd.find(cachedQualifierAddress);
4543  if (!fSkipTempCache && setIterator != setNewQualifierAddressToAdd.end()) {
4544  // Return true if we are adding the qualifier, and false if we are removing it
4545  return setIterator->type == QualifierType::ADD_QUALIFIER;
4546  }
4547 
4548 
4549  setIterator = passets->setNewQualifierAddressToAdd.find(cachedQualifierAddress);
4550  if (setIterator != passets->setNewQualifierAddressToAdd.end()) {
4551  // Return true if we are adding the qualifier, and false if we are removing it
4552  return setIterator->type == QualifierType::ADD_QUALIFIER;
4553  }
4554 
4555  auto tempCache = CAssetCacheRootQualifierChecker(qualifier_name, address);
4556  if (!fSkipTempCache && mapRootQualifierAddressesAdd.count(tempCache)){
4557  if (mapRootQualifierAddressesAdd[tempCache].size()) {
4558  return true;
4559  }
4560  }
4561 
4562  if (passets->mapRootQualifierAddressesAdd.count(tempCache)) {
4563  if (passets->mapRootQualifierAddressesAdd[tempCache].size()) {
4564  return true;
4565  }
4566  }
4567 
4568  // Check the cache, if it doesn't exist in the cache. Try and read it from database
4569  if (passetsQualifierCache) {
4570  if (passetsQualifierCache->Exists(cachedQualifierAddress.GetHash().GetHex())) {
4571  return true;
4572  }
4573  }
4574 
4575  if (prestricteddb) {
4576 
4577  // Check for exact qualifier, and add to cache if it exists
4578  if (prestricteddb->ReadAddressQualifier(address, qualifier_name)) {
4579  passetsQualifierCache->Put(cachedQualifierAddress.GetHash().GetHex(), 1);
4580  return true;
4581  }
4582 
4583  // Look for sub qualifiers
4584  if (prestricteddb->CheckForAddressRootQualifier(address, qualifier_name)){
4585  return true;
4586  }
4587  }
4588 
4589  return false;
4590 }
4591 
4592 
4593 bool CAssetsCache::CheckForAddressRestriction(const std::string &restricted_name, const std::string& address, bool fSkipTempCache)
4594 {
4604  // Create cache object that will be used to check the dirty caches (type, doesn't matter in this search)
4605  CAssetCacheRestrictedAddress cachedRestrictedAddress(restricted_name, address, RestrictedType::FREEZE_ADDRESS);
4606 
4607  // Check the dirty caches first and see if it was recently added or removed
4608  auto setIterator = setNewRestrictedAddressToRemove.find(cachedRestrictedAddress);
4609  if (!fSkipTempCache && setIterator != setNewRestrictedAddressToRemove.end()) {
4610  // Undoing a unfreeze, means that we are adding back a freeze
4611  return setIterator->type == RestrictedType::UNFREEZE_ADDRESS;
4612  }
4613 
4614  setIterator = passets->setNewRestrictedAddressToRemove.find(cachedRestrictedAddress);
4615  if (setIterator != passets->setNewRestrictedAddressToRemove.end()) {
4616  // Undoing a unfreeze, means that we are adding back a freeze
4617  return setIterator->type == RestrictedType::UNFREEZE_ADDRESS;
4618  }
4619 
4620  setIterator = setNewRestrictedAddressToAdd.find(cachedRestrictedAddress);
4621  if (!fSkipTempCache && setIterator != setNewRestrictedAddressToAdd.end()) {
4622  // Return true if we are freezing the address
4623  return setIterator->type == RestrictedType::FREEZE_ADDRESS;
4624  }
4625 
4626  setIterator = passets->setNewRestrictedAddressToAdd.find(cachedRestrictedAddress);
4627  if (setIterator != passets->setNewRestrictedAddressToAdd.end()) {
4628  // Return true if we are freezing the address
4629  return setIterator->type == RestrictedType::FREEZE_ADDRESS;
4630  }
4631 
4632  // Check the cache, if it doesn't exist in the cache. Try and read it from database
4634  if (passetsRestrictionCache->Exists(cachedRestrictedAddress.GetHash().GetHex())) {
4635  return true;
4636  }
4637  }
4638 
4639  if (prestricteddb) {
4640  if (prestricteddb->ReadRestrictedAddress(address, restricted_name)) {
4642  passetsRestrictionCache->Put(cachedRestrictedAddress.GetHash().GetHex(), 1);
4643  }
4644  return true;
4645  }
4646  }
4647 
4648  return false;
4649 }
4650 
4651 bool CAssetsCache::CheckForGlobalRestriction(const std::string &restricted_name, bool fSkipTempCache)
4652 {
4663  // Create cache object that will be used to check the dirty caches (type, doesn't matter in this search)
4664  CAssetCacheRestrictedGlobal cachedRestrictedGlobal(restricted_name, RestrictedType::GLOBAL_FREEZE);
4665 
4666  // Check the dirty caches first and see if it was recently added or removed
4667  auto setIterator = setNewRestrictedGlobalToRemove.find(cachedRestrictedGlobal);
4668  if (!fSkipTempCache && setIterator != setNewRestrictedGlobalToRemove.end()) {
4669  // Undoing a removal of a global unfreeze, means that is will become frozen
4670  return setIterator->type == RestrictedType::GLOBAL_UNFREEZE;
4671  }
4672 
4673  setIterator = passets->setNewRestrictedGlobalToRemove.find(cachedRestrictedGlobal);
4674  if (setIterator != passets->setNewRestrictedGlobalToRemove.end()) {
4675  // Undoing a removal of a global unfreeze, means that is will become frozen
4676  return setIterator->type == RestrictedType::GLOBAL_UNFREEZE;
4677  }
4678 
4679  setIterator = setNewRestrictedGlobalToAdd.find(cachedRestrictedGlobal);
4680  if (fSkipTempCache && setIterator != setNewRestrictedGlobalToAdd.end()) {
4681  // Return true if we are adding a freeze command
4682  return setIterator->type == RestrictedType::GLOBAL_FREEZE;
4683  }
4684 
4685  setIterator = passets->setNewRestrictedGlobalToAdd.find(cachedRestrictedGlobal);
4686  if (setIterator != passets->setNewRestrictedGlobalToAdd.end()) {
4687  // Return true if we are adding a freeze command
4688  return setIterator->type == RestrictedType::GLOBAL_FREEZE;
4689  }
4690 
4691  // Check the cache, if it doesn't exist in the cache. Try and read it from database
4693  if (passetsGlobalRestrictionCache->Exists(cachedRestrictedGlobal.assetName)) {
4694  return true;
4695  }
4696  }
4697 
4698  if (prestricteddb) {
4699  if (prestricteddb->ReadGlobalRestriction(restricted_name)) {
4701  passetsGlobalRestrictionCache->Put(cachedRestrictedGlobal.assetName, 1);
4702  return true;
4703  }
4704  }
4705 
4706  return false;
4707 }
4708 
4709 void ExtractVerifierStringQualifiers(const std::string& verifier, std::set<std::string>& qualifiers, bool fWithTag)
4710 {
4711  std::string s(verifier);
4712 
4713  std::regex regexSearch;
4714  if (fWithTag)
4715  regexSearch = std::regex(R"(#[A-Z0-9_.]+)");
4716  else
4717  regexSearch = std::regex(R"([A-Z0-9_.]+)");
4718 
4719  std::smatch match;
4720 
4721  while (std::regex_search(s,match,regexSearch)) {
4722  for (auto str : match)
4723  qualifiers.insert(str);
4724  s = match.suffix().str();
4725  }
4726 }
4727 
4728 std::string GetStrippedVerifierString(const std::string& verifier)
4729 {
4730  // Remove all white spaces from the verifier string
4731  std::string str_without_whitespaces = LibBoolEE::removeWhitespaces(verifier);
4732 
4733  // Remove all '#' from the verifier string
4734  std::string str_without_qualifier_tags = LibBoolEE::removeCharacter(str_without_whitespaces, QUALIFIER_CHAR);
4735 
4736  return str_without_qualifier_tags;
4737 }
4738 
4739 bool CheckVerifierString(const std::string& verifier, std::set<std::string>& setFoundQualifiers, std::string& strError, bool fWithTags)
4740 {
4741  // If verifier string is true, always return true
4742  if (verifier == "true") {
4743  return true;
4744  }
4745 
4746  // If verifier string is empty, return false
4747  if (verifier.empty()) {
4748  strError = _("Verifier string can not be empty. To default to true, use \"true\"");
4749  return false;
4750  }
4751 
4752  // Remove all white spaces, and # from the string as this is how it will be stored in database, and in the script
4753  std::string strippedVerifier = GetStrippedVerifierString(verifier);
4754 
4755  // Check the stripped size to make sure it isn't over 80
4756  if (strippedVerifier.length() > 80){
4757  strError = _("Verifier string has length greater than 80 after whitespaces and '#' are removed");
4758  return false;
4759  }
4760 
4761  // Extract the qualifiers from the verifier string
4762  ExtractVerifierStringQualifiers(verifier, setFoundQualifiers, fWithTags);
4763 
4764  // Create an object that stores if an address contains a qualifier
4765  LibBoolEE::Vals vals;
4766 
4767  // If the check address is empty
4768 
4769  // set all qualifiers in the verifier to true
4770  for (auto qualifier : setFoundQualifiers) {
4771 
4772  std::string edited_qualifier;
4773  if (!fWithTags)
4774  edited_qualifier = QUALIFIER_CHAR + qualifier;
4775  else {
4776  edited_qualifier = qualifier;
4777  }
4778 
4779  if (!IsQualifierNameValid(edited_qualifier)) {
4780  strError = "bad-txns-null-verifier-invalid-asset-name-" + qualifier;
4781  return false;
4782  }
4783 
4784  vals.insert(std::make_pair(qualifier, true));
4785  }
4786 
4787  try {
4788  LibBoolEE::resolve(verifier, vals);
4789  return true;
4790  } catch (const std::runtime_error& run_error) {
4791  strError = "bad-txns-null-verifier-failed-syntax-check";
4792  return error("%s : Verifier string failed to resolve. Please check string syntax - exception: %s\n", __func__, run_error.what());
4793  }
4794 }
4795 
4796 bool VerifyNullAssetDataFlag(const int& flag, std::string& strError)
4797 {
4798  // Check the flag
4799  if (flag != 0 && flag != 1) {
4800  strError = "bad-txns-null-data-flag-must-be-0-or-1";
4801  return false;
4802  }
4803 
4804  return true;
4805 }
4806 
4807 bool VerifyQualifierChange(CAssetsCache& cache, const CNullAssetTxData& data, const std::string& address, std::string& strError)
4808 {
4809  // Check the flag
4810  if (!VerifyNullAssetDataFlag(data.flag, strError))
4811  return false;
4812 
4813  // Check to make sure we only allow changes to the current status
4814  bool fHasQualifier = cache.CheckForAddressQualifier(data.asset_name, address, true);
4816  if (type == QualifierType::ADD_QUALIFIER) {
4817  if (fHasQualifier) {
4818  strError = "bad-txns-null-data-add-qualifier-when-already-assigned";
4819  return false;
4820  }
4821  } else if (type == QualifierType::REMOVE_QUALIFIER) {
4822  if (!fHasQualifier) {
4823  strError = "bad-txns-null-data-removing-qualifier-when-not-assigned";
4824  return false;
4825  }
4826  }
4827 
4828  return true;
4829 }
4830 
4831 bool VerifyRestrictedAddressChange(CAssetsCache& cache, const CNullAssetTxData& data, const std::string& address, std::string& strError)
4832 {
4833  // Check the flag
4834  if (!VerifyNullAssetDataFlag(data.flag, strError))
4835  return false;
4836 
4837  // Get the current status of the asset and the given address
4838  bool fIsFrozen = cache.CheckForAddressRestriction(data.asset_name, address, true);
4839 
4840  // Assign the type based on the data
4842 
4843  if (type == RestrictedType::FREEZE_ADDRESS) {
4844  if (fIsFrozen) {
4845  strError = "bad-txns-null-data-freeze-address-when-already-frozen";
4846  return false;
4847  }
4848  } else if (type == RestrictedType::UNFREEZE_ADDRESS) {
4849  if (!fIsFrozen) {
4850  strError = "bad-txns-null-data-unfreeze-address-when-not-frozen";
4851  return false;
4852  }
4853  }
4854 
4855  return true;
4856 }
4857 
4858 bool VerifyGlobalRestrictedChange(CAssetsCache& cache, const CNullAssetTxData& data, std::string& strError)
4859 {
4860  // Check the flag
4861  if (!VerifyNullAssetDataFlag(data.flag, strError))
4862  return false;
4863 
4864  // Get the current status of the asset globally
4865  bool fIsGloballyFrozen = cache.CheckForGlobalRestriction(data.asset_name, true);
4866 
4867  // Assign the type based on the data
4869 
4870  if (type == RestrictedType::GLOBAL_FREEZE) {
4871  if (fIsGloballyFrozen) {
4872  strError = "bad-txns-null-data-global-freeze-when-already-frozen";
4873  return false;
4874  }
4875  } else if (type == RestrictedType::GLOBAL_UNFREEZE) {
4876  if (!fIsGloballyFrozen) {
4877  strError = "bad-txns-null-data-global-unfreeze-when-not-frozen";
4878  return false;
4879  }
4880  }
4881 
4882  return true;
4883 }
4884 
4886 
4887 
4888 bool CheckVerifierAssetTxOut(const CTxOut& txout, std::string& strError)
4889 {
4890  CNullAssetTxVerifierString verifier;
4891  if (!AssetNullVerifierDataFromScript(txout.scriptPubKey, verifier)) {
4892  strError = "bad-txns-null-verifier-data-serialization";
4893  return false;
4894  }
4895 
4896  // All restricted verifiers should have white spaces stripped from the data before it is added to a script
4897  if ((int)verifier.verifier_string.find_first_of(' ') != -1) {
4898  strError = "bad-txns-null-verifier-data-contained-whitespaces";
4899  return false;
4900  }
4901 
4902  // All restricted verifiers should have # stripped from that data before it is added to a script
4903  if ((int)verifier.verifier_string.find_first_of('#') != -1) {
4904  strError = "bad-txns-null-verifier-data-contained-qualifier-character-#";
4905  return false;
4906  }
4907 
4908  std::set<std::string> setFoundQualifiers;
4909  if (!CheckVerifierString(verifier.verifier_string, setFoundQualifiers, strError))
4910  return false;
4911 
4912  return true;
4913 }
4915 bool ContextualCheckNullAssetTxOut(const CTxOut& txout, CAssetsCache* assetCache, std::string& strError)
4916 {
4917  // Get the data from the script
4918  CNullAssetTxData data;
4919  std::string address;
4920  if (!AssetNullDataFromScript(txout.scriptPubKey, data, address)) {
4921  strError = "bad-txns-null-asset-data-serialization";
4922  return false;
4923  }
4924 
4925  // Validate the tx data against the cache, and database
4926  if (assetCache) {
4927  if (IsAssetNameAQualifier(data.asset_name)) {
4928  if (!VerifyQualifierChange(*assetCache, data, address, strError)) {
4929  return false;
4930  }
4931 
4932  } else if (IsAssetNameAnRestricted(data.asset_name)) {
4933  if (!VerifyRestrictedAddressChange(*assetCache, data, address, strError))
4934  return false;
4935  } else {
4936  strError = "bad-txns-null-asset-data-on-non-restricted-or-qualifier-asset";
4937  return false;
4938  }
4939  }
4940  return true;
4941 }
4942 
4943 bool ContextualCheckGlobalAssetTxOut(const CTxOut& txout, CAssetsCache* assetCache, std::string& strError)
4944 {
4945  // Get the data from the script
4946  CNullAssetTxData data;
4947  if (!GlobalAssetNullDataFromScript(txout.scriptPubKey, data)) {
4948  strError = "bad-txns-null-global-asset-data-serialization";
4949  return false;
4950  }
4951 
4952  // Validate the tx data against the cache, and database
4953  if (assetCache) {
4954  if (!VerifyGlobalRestrictedChange(*assetCache, data, strError))
4955  return false;
4956  }
4957  return true;
4958 }
4959 
4960 bool ContextualCheckVerifierAssetTxOut(const CTxOut& txout, CAssetsCache* assetCache, std::string& strError)
4961 {
4962  CNullAssetTxVerifierString verifier;
4963  if (!AssetNullVerifierDataFromScript(txout.scriptPubKey, verifier)) {
4964  strError = "bad-txns-null-verifier-data-serialization";
4965  return false;
4966  }
4967 
4968  if (assetCache) {
4969  std::string strError = "";
4970  std::string address = "";
4971  std::string strVerifier = verifier.verifier_string;
4972  if (!ContextualCheckVerifierString(assetCache, strVerifier, address, strError))
4973  return false;
4974  }
4975 
4976  return true;
4977 }
4978 
4979 bool ContextualCheckVerifierString(CAssetsCache* cache, const std::string& verifier, const std::string& check_address, std::string& strError, bool fWithTags)
4980 {
4981  // If verifier is set to true, return true
4982  if (verifier == "true")
4983  return true;
4984 
4985  // Check against the non contextual changes first
4986  std::set<std::string> setFoundQualifiers;
4987  if (!CheckVerifierString(verifier, setFoundQualifiers, strError, fWithTags))
4988  return false;
4989 
4990  // Loop through each qualifier and make sure that the asset exists
4991  for(auto qualifier : setFoundQualifiers) {
4992  std::string search = qualifier;
4993  if (!fWithTags)
4994  search = QUALIFIER_CHAR + qualifier;
4995  if (!cache->CheckIfAssetExists(search, true)) {
4996  strError = "bad-txns-null-verifier-contains-non-issued-qualifier";
4997  return false;
4998  }
4999  }
5000 
5001  // If we got this far, and the check_address is empty. The CheckVerifyString method already did the syntax checks
5002  // No need to do any more checks, as it will fail because the check_address is empty
5003  if (check_address.empty())
5004  return true;
5005 
5006  // Create an object that stores if an address contains a qualifier
5007  LibBoolEE::Vals vals;
5008 
5009  // Add the qualifiers into the vals object
5010  for (auto qualifier : setFoundQualifiers) {
5011  std::string search = qualifier;
5012  if (!fWithTags)
5013  search = QUALIFIER_CHAR + qualifier;
5014 
5015  // Check to see if the address contains the qualifier
5016  bool has_qualifier = cache->CheckForAddressQualifier(search, check_address, true);
5017 
5018  // Add the true or false value into the vals
5019  vals.insert(std::make_pair(qualifier, has_qualifier));
5020  }
5021 
5022  try {
5023  bool ret = LibBoolEE::resolve(verifier, vals);
5024  if (!ret) {
5025  error("%s : The address %s failed to verify against: %s", __func__, check_address, verifier);
5026  strError = "bad-txns-null-verifier-address-failed-verification";
5027  }
5028  return ret;
5029 
5030  } catch (const std::runtime_error& run_error) {
5031  strError = "bad-txns-null-verifier-failed-contexual-syntax-check";
5032  return error("%s : Verifier string failed to resolve. Please check string syntax - exception: %s\n", __func__, run_error.what());
5033  }
5034 }
5035 
5036 bool ContextualCheckTransferAsset(CAssetsCache* assetCache, const CAssetTransfer& transfer, const std::string& address, std::string& strError)
5037 {
5038  strError = "";
5039  AssetType assetType;
5040  if (!IsAssetNameValid(transfer.strName, assetType)) {
5041  strError = "Invalid parameter: asset_name must only consist of valid characters and have a size between 3 and 30 characters. See help for more details.";
5042  return false;
5043  }
5044 
5045  if (AreMessagingDeployed()) {
5046  if (transfer.nAmount <= 0) {
5047  strError = "Invalid parameter: asset amount can't be equal to or less than zero.";
5048  return false;
5049  }
5050 
5051  if (transfer.message.empty() && transfer.nExpireTime > 0) {
5052  strError = "Invalid parameter: asset transfer expiration time requires a message to be attached to the transfer";
5053  return false;
5054  }
5055 
5056  if (transfer.nExpireTime < 0) {
5057  strError = "Invalid parameter: expiration time must be a positive value";
5058  return false;
5059  }
5060 
5061  if (transfer.message.size() && !CheckEncoded(transfer.message, strError)) {
5062  return false;
5063  }
5064  }
5065 
5066  // If the transfer is a message channel asset. Check to make sure that it is UNIQUE_ASSET_AMOUNT
5067  if (assetType == AssetType::MSGCHANNEL) {
5068  if (!AreMessagingDeployed()) {
5069  strError = "bad-txns-transfer-msgchannel-before-messaging-is-active";
5070  return false;
5071  }
5072  }
5073 
5074  if (assetType == AssetType::RESTRICTED) {
5075  if (!AreRestrictedAssetsDeployed()) {
5076  strError = "bad-txns-transfer-restricted-before-it-is-active";
5077  return false;
5078  }
5079 
5080  if (assetCache) {
5081  if (assetCache->CheckForGlobalRestriction(transfer.strName, true)) {
5082  strError = "bad-txns-transfer-restricted-asset-that-is-globally-restricted";
5083  return false;
5084  }
5085  }
5086 
5087 
5088  std::string strError = "";
5089  if (!transfer.ContextualCheckAgainstVerifyString(assetCache, address, strError)) {
5090  error("%s : %s", __func__, strError);
5091  return false;
5092  }
5093  }
5094 
5095  // If the transfer is a qualifier channel asset.
5096  if (assetType == AssetType::QUALIFIER || assetType == AssetType::SUB_QUALIFIER) {
5097  if (!AreRestrictedAssetsDeployed()) {
5098  strError = "bad-txns-transfer-qualifier-before-it-is-active";
5099  return false;
5100  }
5101  }
5102  return true;
5103 }
5104 
5105 bool CheckNewAsset(const CNewAsset& asset, std::string& strError)
5106 {
5107  strError = "";
5108 
5109  AssetType assetType;
5110  if (!IsAssetNameValid(std::string(asset.strName), assetType)) {
5111  strError = _("Invalid parameter: asset_name must only consist of valid characters and have a size between 3 and 30 characters. See help for more details.");
5112  return false;
5113  }
5114 
5115  if (assetType == AssetType::UNIQUE || assetType == AssetType::MSGCHANNEL) {
5116  if (asset.units != UNIQUE_ASSET_UNITS) {
5117  strError = _("Invalid parameter: units must be ") + std::to_string(UNIQUE_ASSET_UNITS);
5118  return false;
5119  }
5120  if (asset.nAmount != UNIQUE_ASSET_AMOUNT) {
5121  strError = _("Invalid parameter: amount must be ") + std::to_string(UNIQUE_ASSET_AMOUNT);
5122  return false;
5123  }
5124  if (asset.nReissuable != 0) {
5125  strError = _("Invalid parameter: reissuable must be 0");
5126  return false;
5127  }
5128  }
5129 
5130  if (assetType == AssetType::QUALIFIER || assetType == AssetType::SUB_QUALIFIER) {
5131  if (asset.units != QUALIFIER_ASSET_UNITS) {
5132  strError = _("Invalid parameter: units must be ") + std::to_string(QUALIFIER_ASSET_UNITS);
5133  return false;
5134  }
5136  strError = _("Invalid parameter: amount must be between ") + std::to_string(QUALIFIER_ASSET_MIN_AMOUNT) + " - " + std::to_string(QUALIFIER_ASSET_MAX_AMOUNT);
5137  return false;
5138  }
5139  if (asset.nReissuable != 0) {
5140  strError = _("Invalid parameter: reissuable must be 0");
5141  return false;
5142  }
5143  }
5144 
5145  if (assetType == AssetType::RESTRICTED) {
5146  // TODO add more restricted asset checks
5147  }
5148 
5149  if (IsAssetNameAnOwner(std::string(asset.strName))) {
5150  strError = _("Invalid parameters: asset_name can't have a '!' at the end of it. See help for more details.");
5151  return false;
5152  }
5153 
5154  if (asset.nAmount <= 0) {
5155  strError = _("Invalid parameter: asset amount can't be equal to or less than zero.");
5156  return false;
5157  }
5158 
5159  if (asset.nAmount > MAX_MONEY) {
5160  strError = _("Invalid parameter: asset amount greater than max money: ") + std::to_string(MAX_MONEY / COIN);
5161  return false;
5162  }
5163 
5164  if (asset.units < 0 || asset.units > 8) {
5165  strError = _("Invalid parameter: units must be between 0-8.");
5166  return false;
5167  }
5168 
5169  if (!CheckAmountWithUnits(asset.nAmount, asset.units)) {
5170  strError = _("Invalid parameter: amount must be divisible by the smaller unit assigned to the asset");
5171  return false;
5172  }
5173 
5174  if (asset.nReissuable != 0 && asset.nReissuable != 1) {
5175  strError = _("Invalid parameter: reissuable must be 0 or 1");
5176  return false;
5177  }
5178 
5179  if (asset.nHasIPFS != 0 && asset.nHasIPFS != 1) {
5180  strError = _("Invalid parameter: has_ipfs must be 0 or 1.");
5181  return false;
5182  }
5183 
5184  return true;
5185 }
5186 
5187 bool ContextualCheckNewAsset(CAssetsCache* assetCache, const CNewAsset& asset, std::string& strError, bool fCheckMempool)
5188 {
5189  if (!AreAssetsDeployed() && !fUnitTest) {
5190  strError = "bad-txns-new-asset-when-assets-is-not-active";
5191  return false;
5192  }
5193 
5194  if (!CheckNewAsset(asset, strError))
5195  return false;
5196 
5197  // Check our current cache to see if the asset has been created yet
5198  if (assetCache->CheckIfAssetExists(asset.strName, true)) {
5199  strError = std::string(_("Invalid parameter: asset_name '")) + asset.strName + std::string(_("' has already been used"));
5200  return false;
5201  }
5202 
5203  // Check the mempool
5204  if (fCheckMempool) {
5205  if (mempool.mapAssetToHash.count(asset.strName)) {
5206  strError = _("Asset with this name is already in the mempool");
5207  return false;
5208  }
5209  }
5210 
5211  // Check the ipfs hash as it changes when messaging goes active
5212  if (asset.nHasIPFS && asset.strIPFSHash.size() != 34) {
5213  if (!AreMessagingDeployed()) {
5214  strError = _("Invalid parameter: ipfs_hash must be 46 characters. Txid must be valid 64 character hash");
5215  return false;
5216  } else {
5217  if (asset.strIPFSHash.size() != 32) {
5218  strError = _("Invalid parameter: ipfs_hash must be 46 characters. Txid must be valid 64 character hash");
5219  return false;
5220  }
5221  }
5222  }
5223 
5224  if (asset.nHasIPFS) {
5225  if (!CheckEncoded(asset.strIPFSHash, strError))
5226  return false;
5227  }
5228 
5229  return true;
5230 }
5231 
5232 bool CheckReissueAsset(const CReissueAsset& asset, std::string& strError)
5233 {
5234  strError = "";
5235 
5236  if (asset.nAmount < 0 || asset.nAmount >= MAX_MONEY) {
5237  strError = _("Unable to reissue asset: amount must be 0 or larger");
5238  return false;
5239  }
5240 
5241  if (asset.nUnits > MAX_UNIT || asset.nUnits < -1) {
5242  strError = _("Unable to reissue asset: unit must be between 8 and -1");
5243  return false;
5244  }
5245 
5247  // Testnet has a couple blocks that have invalid nReissue values before constriants were created
5248  bool fSkip = false;
5249  if (Params().NetworkIDString() == CBaseChainParams::TESTNET) {
5250  if (asset.strName == "GAMINGWEB" && asset.nReissuable == 109) {
5251  fSkip = true;
5252  } else if (asset.strName == "UINT8" && asset.nReissuable == -47) {
5253  fSkip = true;
5254  }
5255  }
5257 
5258  if (!fSkip && asset.nReissuable != 0 && asset.nReissuable != 1) {
5259  strError = _("Unable to reissue asset: reissuable must be 0 or 1");
5260  return false;
5261  }
5262 
5263  AssetType type;
5264  IsAssetNameValid(asset.strName, type);
5265 
5266  if (type == AssetType::RESTRICTED) {
5267  // TODO Add checks for restricted asset if we can come up with any
5268  }
5269 
5270  return true;
5271 }
5272 
5273 bool ContextualCheckReissueAsset(CAssetsCache* assetCache, const CReissueAsset& reissue_asset, std::string& strError, const CTransaction& tx)
5274 {
5275  // We are using this just to get the strAddress
5277  std::string strAddress;
5278  if (!ReissueAssetFromTransaction(tx, reissue, strAddress)) {
5279  strError = "bad-txns-reissue-asset-contextual-check";
5280  return false;
5281  }
5282 
5283  // run non contextual checks
5284  if (!CheckReissueAsset(reissue_asset, strError))
5285  return false;
5286 
5287  // Check previous asset data with the reissuesd data
5288  CNewAsset prev_asset;
5289  if (!assetCache->GetAssetMetaDataIfExists(reissue_asset.strName, prev_asset)) {
5290  strError = _("Unable to reissue asset: asset_name '") + reissue_asset.strName + _("' doesn't exist in the database");
5291  return false;
5292  }
5293 
5294  if (!prev_asset.nReissuable) {
5295  // Check to make sure the asset can be reissued
5296  strError = _("Unable to reissue asset: reissuable is set to false");
5297  return false;
5298  }
5299 
5300  if (prev_asset.nAmount + reissue_asset.nAmount > MAX_MONEY) {
5301  strError = _("Unable to reissue asset: asset_name '") + reissue_asset.strName +
5302  _("' the amount trying to reissue is to large");
5303  return false;
5304  }
5305 
5306  if (!CheckAmountWithUnits(reissue_asset.nAmount, prev_asset.units)) {
5307  strError = _("Unable to reissue asset: amount must be divisible by the smaller unit assigned to the asset");
5308  return false;
5309  }
5310 
5311  if (reissue_asset.nUnits < prev_asset.units && reissue_asset.nUnits != -1) {
5312  strError = _("Unable to reissue asset: unit must be larger than current unit selection");
5313  return false;
5314  }
5315 
5316  // Check the ipfs hash
5317  if (reissue_asset.strIPFSHash != "" && reissue_asset.strIPFSHash.size() != 34 && (AreMessagingDeployed() && reissue_asset.strIPFSHash.size() != 32)) {
5318  strError = _("Invalid parameter: ipfs_hash must be 34 bytes, Txid must be 32 bytes");
5319  return false;
5320  }
5321 
5322  if (reissue_asset.strIPFSHash != "") {
5323  if (!CheckEncoded(reissue_asset.strIPFSHash, strError))
5324  return false;
5325  }
5326 
5327  if (IsAssetNameAnRestricted(reissue_asset.strName)) {
5328  CNullAssetTxVerifierString new_verifier;
5329  bool fNotFound = false;
5330 
5331  // Try and get the verifier string if it was changed
5332  if (!tx.GetVerifierStringFromTx(new_verifier, strError, fNotFound)) {
5333  // If it return false for any other reason besides not being found, fail the transaction check
5334  if (!fNotFound) {
5335  return false;
5336  }
5337  }
5338 
5339  if (reissue_asset.nAmount > 0) {
5340  // If it wasn't found, get the current verifier and validate against it
5341  if (fNotFound) {
5342  CNullAssetTxVerifierString current_verifier;
5343  if (assetCache->GetAssetVerifierStringIfExists(reissue_asset.strName, current_verifier)) {
5344  if (!ContextualCheckVerifierString(assetCache, current_verifier.verifier_string, strAddress, strError, false))
5345  return false;
5346  } else {
5347  // This should happen, but if it does. The wallet needs to shutdown,
5348  // TODO, remove this after restricted assets have been tested in testnet for some time, and this hasn't happened yet. It this has happened. Investigation is required by the dev team
5349  error("%s : failed to get verifier string from a restricted asset, this shouldn't happen, database is out of sync. Reindex required. Please report this is to development team asset name: %s, txhash : %s",__func__, reissue_asset.strName, tx.GetHash().GetHex());
5350  strError = "failed to get verifier string from a restricted asset, database is out of sync. Reindex required. Please report this is to development team";
5351  return false;
5352  }
5353  } else {
5354  if (!ContextualCheckVerifierString(assetCache, new_verifier.verifier_string, strAddress, strError, false))
5355  return false;
5356  }
5357  }
5358  }
5359 
5360 
5361  return true;
5362 }
5363 
5364 bool ContextualCheckReissueAsset(CAssetsCache* assetCache, const CReissueAsset& reissue_asset, std::string& strError)
5365 {
5366  // run non contextual checks
5367  if (!CheckReissueAsset(reissue_asset, strError))
5368  return false;
5369 
5370  // Check previous asset data with the reissuesd data
5371  if (assetCache) {
5372  CNewAsset prev_asset;
5373  if (!assetCache->GetAssetMetaDataIfExists(reissue_asset.strName, prev_asset)) {
5374  strError = _("Unable to reissue asset: asset_name '") + reissue_asset.strName +
5375  _("' doesn't exist in the database");
5376  return false;
5377  }
5378 
5379  if (!prev_asset.nReissuable) {
5380  // Check to make sure the asset can be reissued
5381  strError = _("Unable to reissue asset: reissuable is set to false");
5382  return false;
5383  }
5384 
5385  if (prev_asset.nAmount + reissue_asset.nAmount > MAX_MONEY) {
5386  strError = _("Unable to reissue asset: asset_name '") + reissue_asset.strName +
5387  _("' the amount trying to reissue is to large");
5388  return false;
5389  }
5390 
5391  if (!CheckAmountWithUnits(reissue_asset.nAmount, prev_asset.units)) {
5392  strError = _("Unable to reissue asset: amount must be divisible by the smaller unit assigned to the asset");
5393  return false;
5394  }
5395 
5396  if (reissue_asset.nUnits < prev_asset.units && reissue_asset.nUnits != -1) {
5397  strError = _("Unable to reissue asset: unit must be larger than current unit selection");
5398  return false;
5399  }
5400  }
5401 
5402  // Check the ipfs hash
5403  if (reissue_asset.strIPFSHash != "" && reissue_asset.strIPFSHash.size() != 34 && (AreMessagingDeployed() && reissue_asset.strIPFSHash.size() != 32)) {
5404  strError = _("Invalid parameter: ipfs_hash must be 34 bytes, Txid must be 32 bytes");
5405  return false;
5406  }
5407 
5408  if (reissue_asset.strIPFSHash != "") {
5409  if (!CheckEncoded(reissue_asset.strIPFSHash, strError))
5410  return false;
5411  }
5412 
5413  return true;
5414 }
5415 
5416 bool ContextualCheckUniqueAssetTx(CAssetsCache* assetCache, std::string& strError, const CTransaction& tx)
5417 {
5418  for (auto out : tx.vout)
5419  {
5420  if (IsScriptNewUniqueAsset(out.scriptPubKey))
5421  {
5422  CNewAsset asset;
5423  std::string strAddress;
5424  if (!AssetFromScript(out.scriptPubKey, asset, strAddress)) {
5425  strError = "bad-txns-issue-unique-serialization-failed";
5426  return false;
5427  }
5428 
5429  if (!ContextualCheckUniqueAsset(assetCache, asset, strError))
5430  return false;
5431  }
5432  }
5433 
5434  return true;
5435 }
5436 
5437 bool ContextualCheckUniqueAsset(CAssetsCache* assetCache, const CNewAsset& unique_asset, std::string& strError)
5438 {
5439  if (!ContextualCheckNewAsset(assetCache, unique_asset, strError))
5440  return false;
5441 
5442  return true;
5443 }
bool QualifierAssetFromTransaction(const CTransaction &tx, CNewAsset &asset, std::string &strAddress)
Definition: assets.cpp:549
bool WriteQualifierAddress(const std::string &address, const std::string &tag)
std::set< CAssetCacheRestrictedVerifiers > setNewRestrictedVerifierToAdd
Restricted Assets Verifier Caches.
Definition: assets.h:140
CAmount nValue
Definition: transaction.h:140
bool WriteAssetAddressQuantity(const std::string &assetName, const std::string &address, const CAmount &quantity)
Definition: assetdb.cpp:33
#define OWNER_LENGTH
Definition: assets.h:33
Aliases for backward compatibility.
Definition: protocol.h:64
CAmount GetAddNullQualifierTagBurnAmount()
Definition: assets.cpp:3569
CTxMemPool mempool
bool DecodeBase58(const char *psz, std::vector< unsigned char > &vch)
Decode a base58-encoded string (psz) into a byte vector (vchRet).
Definition: base58.cpp:22
const std::string & IssueUniqueAssetBurnAddress() const
Definition: chainparams.h:106
CAmount GetIssueAssetBurnAmount()
Functions to be used to get access to the current burn amount required for specific asset issuance tr...
Definition: assets.cpp:3529
#define OWNER_ASSET_AMOUNT
Definition: assets.h:35
#define UNIQUE_ASSET_AMOUNT
Definition: assets.h:36
bool ContextualCheckUniqueAsset(CAssetsCache *assetCache, const CNewAsset &unique_asset, std::string &strError)
Definition: assets.cpp:5437
RVN START.
Definition: script.h:188
bool CheckAddingTagBurnFee(const int &count) const
Definition: assets.cpp:1474
bool IsNewOwnerTxValid(const CTransaction &tx, const std::string &assetName, const std::string &address, std::string &errorMsg)
Definition: assets.cpp:596
boost::variant< CNoDestination, CKeyID, CScriptID > CTxDestination
A txout script template with a specific destination.
Definition: standard.h:89
void ConstructOwnerTransaction(CScript &script) const
Definition: assets.cpp:510
bool IsNull() const
Definition: assets.cpp:1596
std::map< std::string, bool > Vals
Valuation of atomic propositions.
Definition: LibBoolEE.h:42
void ConstructTransaction(CScript &script) const
Definition: assets.cpp:4435
CAmount GetBurnAmount(const int nType)
Definition: assets.cpp:3574
bool CheckIssueDataTx(const CTxOut &txOut)
issue asset scripts to make sure script meets the standards
Definition: assets.cpp:3068
std::string ToString()
Definition: assets.cpp:440
bool CreateAssetTransaction(CWallet *pwallet, CCoinControl &coinControl, const CNewAsset &asset, const std::string &address, std::pair< int, std::string > &error, CWalletTx &wtxNew, CReserveKey &reservekey, CAmount &nFeeRequired, std::string *verifier_string)
Creates new asset issuance transaction.
Definition: assets.cpp:3745
bool ExtractDestination(const CScript &scriptPubKey, CTxDestination &addressRet)
Parse a standard scriptPubKey for the destination address.
Definition: standard.cpp:210
#define UNIQUE_ASSET_UNITS
Definition: assets.h:37
Keypool ran out, call keypoolrefill first.
Definition: protocol.h:81
std::set< CAssetCacheRestrictedAddress > setNewRestrictedAddressToAdd
Restricted Address Asset Caches.
Definition: assets.h:132
bool WriteAddressQualifier(const std::string &address, const std::string &tag)
std::string strName
Definition: assettypes.h:239
int8_t units
Definition: assettypes.h:102
CScript scriptPubKey
Definition: transaction.h:141
const CAmount & IssueQualifierAssetBurnAmount() const
Definition: chainparams.h:98
int8_t nReissuable
Definition: assettypes.h:242
bool VerifyRestrictedAddressChange(CAssetsCache &cache, const CNullAssetTxData &data, const std::string &address, std::string &strError)
Definition: assets.cpp:4831
RestrictedType
Definition: assettypes.h:43
bool IsNewRestrictedAsset() const
Make sure to call VerifyNewAsset if this call returns true.
Definition: assets.cpp:1253
bool ContextualCheckReissueAsset(CAssetsCache *assetCache, const CReissueAsset &reissue_asset, std::string &strError, const CTransaction &tx)
Definition: assets.cpp:5273
bool RemoveGlobalRestricted(const std::string &assetName, const RestrictedType type)
Changes Memory Only, this is only called when undoing a block from the chain.
Definition: assets.cpp:2159
bool TrySpendCoin(const COutPoint &out, const CTxOut &coin)
Cache only validation functions.
Definition: assets.cpp:1634
A UTXO entry.
Definition: coins.h:32
CLRUCache< std::string, int8_t > * passetsQualifierCache
Global variable that points to the asset address qualifier LRU Cache (protected by cs_main) ...
Definition: validation.cpp:236
bool CheckOwnerDataTx(const CTxOut &txOut)
Definition: assets.cpp:3085
std::string GetBurnAddress(const int nType)
Definition: assets.cpp:3609
bool RemoveTransfer(const CAssetTransfer &transfer, const std::string &address, const COutPoint &out)
Changes Memory Only.
Definition: assets.cpp:2016
bool CheckForGlobalRestriction(const std::string &restricted_name, bool fSkipTempCache=false)
Return true if the restricted asset is globally freezing trading.
Definition: assets.cpp:4651
CCriticalSection cs_wallet
Definition: wallet.h:751
const CAmount & IssueSubQualifierAssetBurnAmount() const
Definition: chainparams.h:99
bool AddOwnerAsset(const std::string &assetsName, const std::string address)
Changes Memory Only.
Definition: assets.cpp:1979
THESE ARE ONLY TO BE USED WHEN ADDING THINGS TO THE CACHE DURING CONNECT AND DISCONNECT BLOCK...
Definition: assettypes.h:335
#define strprintf
Definition: tinyformat.h:1054
const uint256 & GetHash() const
Definition: wallet.h:277
bool CreateTransferAssetTransaction(CWallet *pwallet, const CCoinControl &coinControl, const std::vector< std::pair< CAssetTransfer, std::string > >vTransfers, const std::string &changeAddress, std::pair< int, std::string > &error, CWalletTx &wtxNew, CReserveKey &reservekey, CAmount &nFeeRequired, std::vector< std::pair< CNullAssetTxData, std::string > > *nullAssetTxData, std::vector< CNullAssetTxData > *nullGlobalRestrictionData)
Create a transfer asset transaction.
Definition: assets.cpp:4094
#define RVN_Q
Definition: assets.h:22
std::string EncodeIPFS(std::string decoded)
Definition: assets.cpp:3737
CRestrictedDB * prestricteddb
Global variable that points to the active restricted asset database (protected by cs_main) ...
Definition: validation.cpp:239
std::set< CAssetCacheQualifierAddress > setNewQualifierAddressToRemove
Definition: assets.h:129
#define OFFSET_TWENTY_THREE
Definition: assets.cpp:37
CReissueAsset reissue
Definition: assettypes.h:358
const char * prefix
Definition: rest.cpp:568
bool AssetFromScript(const CScript &scriptPubKey, CNewAsset &assetNew, std::string &strAddress)
Definition: assets.cpp:664
txnouttype type
Definition: wallet.h:193
bool EraseQualifierAddress(const std::string &address, const std::string &tag)
#define DEFAULT_UNITS
Definition: assets.h:26
std::set< CAssetCacheNewOwner > setNewOwnerAssetsToRemove
Definition: assets.h:121
bool TransferAssetFromScript(const CScript &scriptPubKey, CAssetTransfer &assetTransfer, std::string &strAddress)
Get specific asset type metadata from the given scripts.
Definition: assets.cpp:638
CCriticalSection cs_main
Global state.
Definition: validation.cpp:72
bool IsValidDestination(const CTxDestination &dest)
Check whether a CTxDestination is a CNoDestination.
Definition: standard.cpp:402
CTxOut out
unspent transaction output
Definition: coins.h:36
void ConstructTransaction(CScript &script) const
Definition: assets.cpp:1555
CTxDestination DecodeDestination(const std::string &str)
Definition: base58.cpp:333
std::string HexStr(const T itbegin, const T itend, bool fSpaces=false)
int64_t expireTime
Definition: wallet.h:198
bool Flush()
Flush all new cache entries into the passets global cache.
Definition: assets.cpp:2750
int8_t nUnits
Definition: assettypes.h:241
static std::string removeWhitespaces(const std::string &source)
Definition: LibBoolEE.cpp:131
std::string EncodeBase58(const unsigned char *pbegin, const unsigned char *pend)
Why base-58 instead of standard base-64 encoding?
Definition: base58.cpp:72
bool EraseAddressQualifier(const std::string &address, const std::string &tag)
bool AssetFromTransaction(const CTransaction &tx, CNewAsset &asset, std::string &strAddress)
These types of asset tx, have specific metadata at certain indexes in the transaction.
Definition: assets.cpp:525
bool IsSubNameValid(const std::string &name)
Definition: assets.cpp:118
#define DEFAULT_HAS_IPFS
Definition: assets.h:28
const CAmount & IssueMsgChannelAssetBurnAmount() const
Definition: chainparams.h:97
bool ReadAssetAddressQuantity(const std::string &assetName, const std::string &address, CAmount &quantity)
Definition: assetdb.cpp:57
bool QualifierAssetFromScript(const CScript &scriptPubKey, CNewAsset &assetNew, std::string &strAddress)
Definition: assets.cpp:714
std::vector< CWalletRef > vpwallets
Definition: wallet.cpp:44
std::string DecodeIPFS(std::string encoded)
Definition: assets.cpp:3729
std::string strName
Definition: assettypes.h:100
void ConstructTransaction(CScript &script) const
Definition: assets.cpp:1581
bool VerifyNewUniqueAsset(std::string &strError) const
Call this function after IsNewUniqueAsset.
Definition: assets.cpp:913
size_t GetCacheSizeV2() const
Get an estimated size of the cache in bytes that will be needed inorder to save to database...
Definition: assets.cpp:2978
const std::string & IssueSubQualifierAssetBurnAddress() const
Definition: chainparams.h:109
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:147
bool AssetNullDataFromScript(const CScript &scriptPubKey, CNullAssetTxData &assetData, std::string &strAddress)
Definition: assets.cpp:815
CAmount GetIssueSubAssetBurnAmount()
Definition: assets.cpp:3539
std::string ToString() const
Definition: transaction.cpp:14
std::set< CAssetCacheNewTransfer > setNewTransferAssetsToRemove
Definition: assets.h:125
#define MIN_ASSET_LENGTH
Definition: assets.h:30
bool RemoveRestrictedVerifier(const std::string &assetName, const std::string &verifier, const bool fUndoingReissue=false)
Changes Memory Only.
Definition: assets.cpp:2194
CAmount GetIssueSubQualifierAssetBurnAmount()
Definition: assets.cpp:3559
bool IsAssetNameASubQualifier(const std::string &name)
Check if an asset is a sub qualifier.
Definition: assets.cpp:196
std::string strName
Definition: assettypes.h:190
bool ContainsAsset(const CNewAsset &asset)
Help functions.
Definition: assets.cpp:1699
CAssetsDB * passetsdb
RVN START.
Definition: validation.cpp:226
bool ReissueAssetFromScript(const CScript &scriptPubKey, CReissueAsset &reissue, std::string &strAddress)
Definition: assets.cpp:789
bool IsScriptNewMsgChannelAsset(const CScript &scriptPubKey)
Check script and see if it matches the message channel issuance template.
Definition: assets.cpp:3142
bool IsNewQualifierAsset() const
Make sure to call VerifyNewQualifierAsset if this call returns true.
Definition: assets.cpp:1164
const CAmount & IssueUniqueAssetBurnAmount() const
Definition: chainparams.h:96
#define RVN_T
Definition: assets.h:23
bool IsValid(std::string &strError) const
Definition: assets.cpp:1503
#define RVN_N
Definition: assets.h:21
std::string asset_name
Definition: assettypes.h:278
bool fAssetIndex
Definition: validation.cpp:84
std::string strIPFSHash
Definition: assettypes.h:105
bool RemoveNewAsset(const CNewAsset &asset, const std::string address)
Cache only undo functions.
Definition: assets.cpp:1817
#define QUALIFIER_CHAR
Definition: assets.h:41
bool ReadGlobalRestriction(const std::string &assetName)
bool IsNewAsset() const
RVN START.
Definition: assets.cpp:881
Coin Control Features.
Definition: coincontrol.h:17
bool fUnitTest
Definition: validation.cpp:99
CAmount GetBalance() const
Definition: wallet.cpp:2010
bool CheckIssueBurnTx(const CTxOut &txOut, const AssetType &type, const int numberIssued)
Check to make sure the script contains the burn transaction.
Definition: assets.cpp:3005
#define QUALIFIER_ASSET_MAX_AMOUNT
Definition: assets.h:44
Invalid, missing or duplicate parameter.
Definition: protocol.h:54
int8_t nReissuable
Definition: assettypes.h:103
bool EraseAddressAssetQuantity(const std::string &address, const std::string &assetName)
Definition: assetdb.cpp:80
const std::string & ReissueAssetBurnAddress() const
Definition: chainparams.h:104
std::set< CAssetCacheNewOwner > setNewOwnerAssetsToAdd
Ownership Assets Caches.
Definition: assets.h:120
CLRUCache< std::string, int8_t > * passetsRestrictionCache
Global variable that points to the asset address restriction LRU Cache (protected by cs_main) ...
Definition: validation.cpp:237
RVN START.
Definition: wallet.h:191
bool IsVoteTagValid(const std::string &tag)
Definition: assets.cpp:131
static std::string removeCharacter(const std::string &source, const char ch)
Definition: LibBoolEE.cpp:141
bool GetAssetData(const CScript &script, CAssetOutputEntry &data)
Definition: assets.cpp:3440
bool IsAssetNameAnMsgChannel(const std::string &name)
Check if an asset is a message channel.
Definition: assets.cpp:311
bool IsNameValidBeforeTag(const std::string &name)
Definition: assets.cpp:144
#define QUALIFIER_ASSET_UNITS
Definition: assets.h:45
int64_t CAmount
Amount in corbies (Can be negative)
Definition: amount.h:13
std::vector< CAssetCacheUndoAssetAmount > vUndoAssetAmount
These are memory only containers that show dirty entries that will be databased when flushed...
Definition: assets.h:108
std::set< CAssetCacheNewAsset > setNewAssetsToRemove
New Assets Caches.
Definition: assets.h:112
bool RemoveOwnerAsset(const std::string &assetsName, const std::string address)
Changes Memory Only.
Definition: assets.cpp:1998
std::vector< CAssetCacheSpendAsset > vSpentAssets
Definition: assets.h:109
bool CheckTransferOwnerTx(const CTxOut &txOut)
Definition: assets.cpp:3093
General error during transaction or block submission.
Definition: protocol.h:57
bool IsQualifierNameValidBeforeTag(const std::string &name)
Definition: assets.cpp:162
bool OwnerFromTransaction(const CTransaction &tx, std::string &ownerName, std::string &strAddress)
Definition: assets.cpp:626
void GetAllMyAssets(CWallet *pwallet, std::vector< std::string > &names, int nMinConf, bool fIncludeAdministrator, bool fOnlyAdministrator)
Definition: assets.cpp:3507
bool AreMessagingDeployed()
#define MAX_UNIT
Definition: assettypes.h:16
iterator end()
Definition: prevector.h:293
#define LOCK2(cs1, cs2)
Definition: sync.h:177
bool IsMsgChannelTagValid(const std::string &tag)
Definition: assets.cpp:136
bool GlobalAssetNullDataFromScript(const CScript &scriptPubKey, CNullAssetTxData &assetData)
Definition: assets.cpp:840
bool VerifyGlobalRestrictedChange(CAssetsCache &cache, const CNullAssetTxData &data, std::string &strError)
Definition: assets.cpp:4858
bool IsAssetNameValid(const std::string &name, AssetType &assetType, std::string &error)
Definition: assets.cpp:207
int8_t nHasIPFS
Definition: assettypes.h:104
void push_back(const T &value)
Definition: prevector.h:412
const std::string & IssueMsgChannelAssetBurnAddress() const
Definition: chainparams.h:107
std::string DecodeAssetData(std::string encoded)
Decode and Encode IPFS hashes, or OIP hashes.
Definition: assets.cpp:3699
bool IsAssetNameASubasset(const std::string &name)
Definition: assets.cpp:186
bool DumpCacheToDatabase()
Write asset cache data to database.
Definition: assets.cpp:2207
bool UndoTransfer(const CAssetTransfer &transfer, const std::string &address, const COutPoint &outToRemove)
Changes Memory Only.
Definition: assets.cpp:1790
bool ContextualCheckVerifierAssetTxOut(const CTxOut &txout, CAssetsCache *assetCache, std::string &strError)
Definition: assets.cpp:4960
bool IsValidDestinationString(const std::string &str, const CChainParams &params)
Definition: base58.cpp:338
CAmount GetIssueUniqueAssetBurnAmount()
Definition: assets.cpp:3544
#define LogPrintf(...)
Definition: util.h:149
bool CheckIfAssetExists(const std::string &name, bool fForceDuplicateCheck=true)
Returns true if an asset with this name already exists.
Definition: assets.cpp:3271
std::set< CAssetCacheRestrictedAddress > setNewRestrictedAddressToRemove
Definition: assets.h:133
bool CreateTransactionWithReissueAsset(const std::vector< CRecipient > &vecSend, CWalletTx &wtxNew, CReserveKey &reservekey, CAmount &nFeeRet, int &nChangePosInOut, std::string &strFailReason, const CCoinControl &coin_control, const CReissueAsset &reissueAsset, const CTxDestination destination, bool sign=true)
Definition: wallet.cpp:3081
bool IsScriptOwnerAsset(const CScript &scriptPubKey)
Check script and see if it matches the owner issuance template.
Definition: assets.cpp:3167
CLRUCache< std::string, CNullAssetTxVerifierString > * passetsVerifierCache
Global variable that points to the asset verifier LRU Cache (protected by cs_main) ...
Definition: validation.cpp:235
bool WriteAddressAssetQuantity(const std::string &address, const std::string &assetName, const CAmount &quantity)
Definition: assetdb.cpp:38
bool AreAssetsDeployed()
RVN START.
bool VerifyNewQualfierAsset(std::string &strError) const
To be called on CTransactions where IsNewQualifierAsset returns true.
Definition: assets.cpp:1177
#define DEFAULT_IPFS
Definition: assets.h:29
UniValue transfer(const JSONRPCRequest &request)
Definition: assets.cpp:1101
bool VerifyNullAssetDataFlag(const int &flag, std::string &strError)
Helper methods that validate changes to null asset data transaction databases.
Definition: assets.cpp:4796
bool GetAssetMetaDataIfExists(const std::string &name, CNewAsset &asset)
Returns true if an asset with the name exists, and it was able to get the asset metadata from databas...
Definition: assets.cpp:3340
CAssetsCache * GetCurrentAssetCache()
bool IsRootNameValid(const std::string &name)
Definition: assets.cpp:83
bool MsgChannelAssetFromTransaction(const CTransaction &tx, CNewAsset &asset, std::string &strAddress)
Definition: assets.cpp:537
void ExtractVerifierStringQualifiers(const std::string &verifier, std::set< std::string > &qualifiers, bool fWithTag)
Helper method for extracting #TAGS from a verifier string.
Definition: assets.cpp:4709
bool EraseAssetAddressQuantity(const std::string &assetName, const std::string &address)
Definition: assetdb.cpp:76
void ConstructTransaction(CScript &script) const
Constructs a CScript that carries the asset name and quantity and adds to to the end of the given scr...
Definition: assets.cpp:495
bool IsScriptNewRestrictedAsset(const CScript &scriptPubKey)
Check script and see if it matches the restricted issueance template.
Definition: assets.cpp:3244
bool EraseGlobalRestriction(const std::string &assetName)
#define RVN_R
Definition: assets.h:19
bool ContextualCheckNewAsset(CAssetsCache *assetCache, const CNewAsset &asset, std::string &strError, bool fCheckMempool)
Definition: assets.cpp:5187
const uint256 & GetHash() const
Definition: transaction.h:320
#define OWNER_TAG
Definition: assets.h:32
bool ContextualCheckNullAssetTxOut(const CTxOut &txout, CAssetsCache *assetCache, std::string &strError)
Definition: assets.cpp:4915
bool ReadVerifier(const std::string &assetName, std::string &verifier)
std::string assetName
Definition: wallet.h:194
CTxDestination destChange
Definition: coincontrol.h:20
bool EraseVerifier(const std::string &assetName)
std::map< std::string, uint256 > mapReissuedAssets
Definition: assets.cpp:41
bool CheckForAddressRootQualifier(const std::string &address, const std::string &qualifier)
bool RemoveQualifierAddress(const std::string &assetName, const std::string &address, const QualifierType type)
Changes Memory Only, this is only called when undoing a block from the chain.
Definition: assets.cpp:2062
std::string GetRejectReason() const
Definition: validation.h:92
bool ParseAssetScript(CScript scriptPubKey, uint160 &hashBytes, std::string &assetName, CAmount &assetAmount)
Helper method for extracting address bytes, asset name and amount from an asset script.
Definition: assets.cpp:4317
bool ReadAssetData(const std::string &strName, CNewAsset &asset, int &nHeight, uint256 &blockHash)
Definition: assetdb.cpp:42
bool IsHex(const std::string &str)
const std::vector< CTxOut > vout
Definition: transaction.h:288
#define RVN_V
Definition: assets.h:20
CAmount GetIssueRestrictedAssetBurnAmount()
Definition: assets.cpp:3564
bool IsValid(std::string &strError, CAssetsCache &assetCache, bool fForceCheckPrimaryAssetExists) const
Definition: assets.cpp:4381
bool CreateNewChangeAddress(CReserveKey &reservekey, CKeyID &keyID, std::string &strFailReason)
RVN START.
Definition: wallet.cpp:2756
void SetNull()
Definition: assettypes.h:118
bool VerifyQualifierChange(CAssetsCache &cache, const CNullAssetTxData &data, const std::string &address, std::string &strError)
Definition: assets.cpp:4807
static bool resolve(const std::string &source, const Vals &valuation)
Definition: LibBoolEE.cpp:59
bool EraseRestrictedAddress(const std::string &address, const std::string &assetName)
bool ContextualCheckGlobalAssetTxOut(const CTxOut &txout, CAssetsCache *assetCache, std::string &strError)
Definition: assets.cpp:4943
bool CreateTransactionWithAssets(const std::vector< CRecipient > &vecSend, CWalletTx &wtxNew, CReserveKey &reservekey, CAmount &nFeeRet, int &nChangePosInOut, std::string &strFailReason, const CCoinControl &coin_control, const std::vector< CNewAsset > assets, const CTxDestination destination, const AssetType &assetType, bool sign=true)
RVN START.
Definition: wallet.cpp:3064
const CAmount & ReissueAssetBurnAmount() const
Definition: chainparams.h:94
bool GetAssetInfoFromScript(const CScript &scriptPubKey, std::string &strName, CAmount &nAmount)
Definition: assets.cpp:3423
std::set< CAssetCacheQualifierAddress > setNewQualifierAddressToAdd
Qualfier Address Asset Caches.
Definition: assets.h:128
bool IsRestrictedNameValid(const std::string &name)
Definition: assets.cpp:101
bool OwnerAssetFromScript(const CScript &scriptPubKey, std::string &assetName, std::string &strAddress)
Definition: assets.cpp:764
An output of a transaction.
Definition: transaction.h:137
int64_t nExpireTime
Definition: assettypes.h:193
Invalid address or key.
Definition: protocol.h:52
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a Raven scriptPubKey for the given CTxDestination.
Definition: standard.cpp:347
bool CheckReissueBurnTx(const CTxOut &txOut)
Check to make sure the script contains the reissue burn data.
Definition: assets.cpp:3046
CNewAsset & operator=(const CNewAsset &asset)
Definition: assets.cpp:429
const std::string & IssueQualifierAssetBurnAddress() const
Definition: chainparams.h:108
bool IsScriptNewAsset(const CScript &scriptPubKey)
Check script and see if it matches the asset issuance template.
Definition: assets.cpp:3101
const std::string & IssueRestrictedAssetBurnAddress() const
Definition: chainparams.h:110
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:22
bool GetVerifierStringFromTx(CNullAssetTxVerifierString &verifier, std::string &strError) const
Definition: assets.cpp:1378
bool IsNullAssetVerifierTxDataScript() const
Definition: script.cpp:348
CAmount GetReissueAssetBurnAmount()
Definition: assets.cpp:3534
bool SendAssetTransaction(CWallet *pwallet, CWalletTx &transaction, CReserveKey &reserveKey, std::pair< int, std::string > &error, std::string &txid)
Send any type of asset transaction to the network.
Definition: assets.cpp:4243
CLRUCache< std::string, int8_t > * passetsGlobalRestrictionCache
Global variable that points to the global asset restriction LRU Cache (protected by cs_main) ...
Definition: validation.cpp:238
std::string FormatMoney(const CAmount &n)
Money parsing/formatting utilities.
void ConstructTransaction(CScript &script) const
Definition: assets.cpp:4409
const std::string & AddNullQualifierTagBurnAddress() const
Definition: chainparams.h:111
CAmount GetIssueMsgChannelAssetBurnAmount()
Definition: assets.cpp:3549
bool RemoveReissueAsset(const CReissueAsset &reissue, const std::string address, const COutPoint &out, const std::vector< std::pair< std::string, CBlockAssetUndo > > &vUndoIPFS)
Changes Memory Only.
Definition: assets.cpp:1913
#define OFFSET_FOUR
Definition: assets.cpp:36
bool AddGlobalRestricted(const std::string &assetName, const RestrictedType type)
Changes Memory Only, this only called when adding a block to the chain.
Definition: assets.cpp:2138
bool EraseAssetData(const std::string &assetName)
Definition: assetdb.cpp:66
std::string GetUniqueAssetName(const std::string &parent, const std::string &tag)
Build a unique asset buy giving the root name, and the tag name (ROOT, TAG) => ROOT::TAG.
Definition: assets.cpp:399
std::map< std::pair< std::string, std::string >, CAmount > mapAssetsAddressAmount
Definition: assets.h:74
std::string GetStrippedVerifierString(const std::string &verifier)
Definition: assets.cpp:4728
bool ContextualCheckAgainstVerifyString(CAssetsCache *assetCache, const std::string &address, std::string &strError) const
Definition: assets.cpp:1539
bool WriteAssetData(const CNewAsset &asset, const int nHeight, const uint256 &blockHash)
Definition: assetdb.cpp:27
A transaction with a bunch of additional info that only the owner cares about.
Definition: wallet.h:285
std::map< CAssetCacheRootQualifierChecker, std::set< std::string > > mapRootQualifierAddressesAdd
Root Qualifier Address Map.
Definition: assets.h:144
bool RestrictedAssetFromTransaction(const CTransaction &tx, CNewAsset &asset, std::string &strAddress)
Definition: assets.cpp:560
void GetAllAdministrativeAssets(CWallet *pwallet, std::vector< std::string > &names, int nMinConf)
Definition: assets.cpp:3499
bool UniqueAssetFromTransaction(const CTransaction &tx, CNewAsset &asset, std::string &strAddress)
Definition: assets.cpp:584
CAmount GetIssueQualifierAssetBurnAmount()
Definition: assets.cpp:3554
bool ReadAddressQualifier(const std::string &address, const std::string &tag)
bool AreRestrictedAssetsDeployed()
AssetType
Definition: assettypes.h:21
std::set< CAssetCacheReissueAsset > setNewReissueToRemove
New Reissue Caches.
Definition: assets.h:116
bool GetBroadcastTransactions() const
Inquire whether this wallet broadcasts transactions.
Definition: wallet.h:1148
bool RemoveRestrictedAddress(const std::string &assetName, const std::string &address, const RestrictedType type)
Changes Memory Only, this is only called when undoing a block from the chain.
Definition: assets.cpp:2117
std::set< CAssetCacheNewAsset > setNewAssetsToAdd
Definition: assets.h:113
const CAmount & IssueAssetBurnAmount() const
RVN Start.
Definition: chainparams.h:93
Database error.
Definition: protocol.h:55
bool MsgChannelAssetFromScript(const CScript &scriptPubKey, CNewAsset &assetNew, std::string &strAddress)
Definition: assets.cpp:689
bool IsScriptTransferAsset(const CScript &scriptPubKey)
Check script and see if it matches the transfer asset template.
Definition: assets.cpp:3202
bool AddQualifierAddress(const std::string &assetName, const std::string &address, const QualifierType type)
Changes Memory Only, this only called when adding a block to the chain.
Definition: assets.cpp:2031
bool IsScriptReissueAsset(const CScript &scriptPubKey)
Check script and see if it matches the reissue template.
Definition: assets.cpp:3185
CAmount nAmount
Definition: assettypes.h:240
bool GetAssetInfoFromCoin(const Coin &coin, std::string &strName, CAmount &nAmount)
Definition: assets.cpp:3435
std::atomic_bool fReindex
txnouttype
Definition: standard.h:57
RVN END.
Definition: validation.h:30
256-bit opaque blob.
Definition: uint256.h:123
bool AddRestrictedAddress(const std::string &assetName, const std::string &address, const RestrictedType type)
Changes Memory Only, this only called when adding a block to the chain.
Definition: assets.cpp:2096
void AvailableAssets(std::map< std::string, std::vector< COutput > > &mapAssetCoins, bool fOnlySafe=true, const CCoinControl *coinControl=nullptr, const CAmount &nMinimumAmount=1, const CAmount &nMaximumAmount=MAX_MONEY, const CAmount &nMinimumSumAmount=MAX_MONEY, const uint64_t &nMaximumCount=0, const int &nMinDepth=0, const int &nMaxDepth=9999999) const
Helper function that calls AvailableCoinsAll, used for transfering assets.
Definition: wallet.cpp:2165
CAssetsCache * passets
Global variable that point to the active assets (protected by cs_main)
Definition: validation.cpp:227
bool AddTransferAsset(const CAssetTransfer &transferAsset, const std::string &address, const COutPoint &out, const CTxOut &txOut)
Definition: assets.cpp:1601
CAmount nAmount
Definition: assettypes.h:101
bool AddNewAsset(const CNewAsset &asset, const std::string address, const int &nHeight, const uint256 &blockHash)
Cache only add asset functions.
Definition: assets.cpp:1836
bool WriteRestrictedAddress(const std::string &address, const std::string &assetName)
std::set< CAssetCacheReissueAsset > setNewReissueToAdd
Definition: assets.h:117
const_iterator end() const
Definition: streams.h:236
const std::string & IssueSubAssetBurnAddress() const
Definition: chainparams.h:105
std::string EncodeDestination(const CTxDestination &dest)
Definition: base58.cpp:326
const_iterator begin() const
Definition: streams.h:234
iterator insert(iterator it, const char &x=char())
Definition: streams.h:245
std::string message
Definition: wallet.h:197
A key allocated from the key pool.
Definition: wallet.h:1193
bool ReissueAssetFromTransaction(const CTransaction &tx, CReissueAsset &reissue, std::string &strAddress)
Definition: assets.cpp:572
bool VerifyWalletHasAsset(const std::string &asset_name, std::pair< int, std::string > &pairError)
Verifies that this wallet owns the give asset.
Definition: assets.cpp:4255
std::map< std::string, uint256 > mapAssetToHash
Definition: txmempool.h:471
const CChainParams & Params()
Return the currently selected parameters.
bool IsNewMsgChannelAsset() const
Make sure to call VerifyNewUniqueAsset if this call returns true.
Definition: assets.cpp:1077
bool IsNullAssetTxDataScript() const
Definition: script.cpp:331
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:396
bool CreateReissueAssetTransaction(CWallet *pwallet, CCoinControl &coinControl, const CReissueAsset &reissueAsset, const std::string &address, std::pair< int, std::string > &error, CWalletTx &wtxNew, CReserveKey &reservekey, CAmount &nFeeRequired, std::string *verifier_string)
Create a reissue asset transaction.
Definition: assets.cpp:3917
bool CheckAmountWithUnits(const CAmount &nAmount, const int8_t nUnits)
Checks the amount and units, and makes sure that the amount uses the correct decimals.
Definition: assets.cpp:4277
Not enough funds in wallet or account.
Definition: protocol.h:79
std::string GetParentName(const std::string &name)
Get the root name of an asset.
Definition: assets.cpp:366
bool GetAllMyAssetBalances(std::map< std::string, std::vector< COutput > > &outputs, std::map< std::string, CAmount > &amounts, const int confirmations, const std::string &prefix)
sets balances with the total quantity of each owned asset
Definition: assets.cpp:3673
std::map< uint256, std::string > mapReissuedTx
Definition: assets.cpp:40
std::set< CAssetCacheRestrictedGlobal > setNewRestrictedGlobalToRemove
Definition: assets.h:137
const CAmount & IssueRestrictedAssetBurnAmount() const
Definition: chainparams.h:100
bool CheckForAddressQualifier(const std::string &qualifier_name, const std::string &address, bool fSkipTempCache=false)
Return true if the address has the given qualifier assigned to it.
Definition: assets.cpp:4514
RVN START.
Definition: standard.h:69
A reference to a CKey: the Hash160 of its serialized public key.
Definition: pubkey.h:30
bool ContextualCheckVerifierString(CAssetsCache *cache, const std::string &verifier, const std::string &check_address, std::string &strError, bool fWithTags)
Definition: assets.cpp:4979
std::set< CAssetCacheRestrictedGlobal > setNewRestrictedGlobalToAdd
Restricted Global Asset Caches.
Definition: assets.h:136
#define DEFAULT_REISSUABLE
Definition: assets.h:27
bool GetBestAssetAddressAmount(CAssetsCache &cache, const std::string &assetName, const std::string &address)
This will get the amount that an address for a certain asset contains from the database if they cache...
Definition: assets.cpp:3645
std::string message
Definition: assettypes.h:192
std::string GetHex() const
Definition: uint256.cpp:22
bool VerifyNewMsgChannelAsset(std::string &strError) const
To be called on CTransactions where IsNewAsset returns true.
Definition: assets.cpp:1090
bool CheckEncoded(const std::string &hash, std::string &strError)
Check the Encoded hash and make sure it is either an IPFS hash or a OIP hash.
Definition: assets.cpp:4282
A CWallet is an extension of a keystore, which also maintains a set of transactions and balances...
Definition: wallet.h:673
size_t GetCacheSize() const
Get the size of the none databased cache.
Definition: assets.cpp:2942
#define RVN_O
Definition: assets.h:24
bool IsAssetNameAQualifier(const std::string &name)
Check if an asset is a qualifier asset or sub qualifier.
Definition: assets.cpp:306
std::unique_ptr< CConnman > g_connman
Definition: init.cpp:81
160-bit opaque blob.
Definition: uint256.h:112
bool ContextualCheckTransferAsset(CAssetsCache *assetCache, const CAssetTransfer &transfer, const std::string &address, std::string &strError)
Definition: assets.cpp:5036
bool VerifyReissueAsset(std::string &strError) const
To be called on CTransactions where IsReissueAsset returns true.
Definition: assets.cpp:1394
void GetTxOutAssetTypes(const std::vector< CTxOut > &vout, int &issues, int &reissues, int &transfers, int &owners)
Definition: assets.cpp:4299
bool RestrictedAssetFromScript(const CScript &scriptPubKey, CNewAsset &assetNew, std::string &strAddress)
Definition: assets.cpp:739
bool error(const char *fmt, const Args &... args)
Definition: util.h:168
const std::string & IssueAssetBurnAddress() const
Definition: chainparams.h:103
iterator begin()
Definition: prevector.h:291
bool WriteGlobalRestriction(const std::string &assetName)
bool AssetNullVerifierDataFromScript(const CScript &scriptPubKey, CNullAssetTxVerifierString &verifierData)
Definition: assets.cpp:860
bool CheckVerifierAssetTxOut(const CTxOut &txout, std::string &strError)
Definition: assets.cpp:4888
bool CreateTransactionWithTransferAsset(const std::vector< CRecipient > &vecSend, CWalletTx &wtxNew, CReserveKey &reservekey, CAmount &nFeeRet, int &nChangePosInOut, std::string &strFailReason, const CCoinControl &coin_control, bool sign=true)
Definition: wallet.cpp:3071
static const std::string TESTNET
Standard JSON-RPC 2.0 errors.
Definition: protocol.h:38
Wallet errors.
Definition: protocol.h:78
bool IsSubQualifierNameValid(const std::string &name)
Definition: assets.cpp:110
bool CheckVerifierString(const std::string &verifier, std::set< std::string > &setFoundQualifiers, std::string &strError, bool fWithTags)
Definition: assets.cpp:4739
bool CheckReissueAsset(const CReissueAsset &asset, std::string &strError)
Definition: assets.cpp:5232
#define OFFSET_THREE
Definition: assets.cpp:35
bool AddRestrictedVerifier(const std::string &assetName, const std::string &verifier)
Changes Memory Only.
Definition: assets.cpp:2180
size_t DynamicMemoryUsage() const
Calculate the size of the CAssets (in bytes)
Definition: assets.cpp:2935
bool IsTypeCheckNameValid(const AssetType type, const std::string &name, std::string &error)
Given a type, and an asset name, return if that name is valid based on the type.
Definition: assets.cpp:317
UniValue JSONRPCError(int code, const std::string &message)
Definition: protocol.cpp:55
bool IsReissueAsset() const
Definition: assets.cpp:1384
No valid connection manager instance found.
Definition: protocol.h:75
QualifierType
Definition: assettypes.h:37
bool GetAssetVerifierStringIfExists(const std::string &name, CNullAssetTxVerifierString &verifier, bool fSkipTempCache=false)
Returns true if the Asset Verifier String was found for an asset_name, if fSkipTempCache is true...
Definition: assets.cpp:4445
bool CheckForAddressRestriction(const std::string &restricted_name, const std::string &address, bool fSkipTempCache=false)
Return true if the address is marked as frozen.
Definition: assets.cpp:4593
CAmount nAmount
Definition: wallet.h:196
The basic transaction that is broadcasted on the network and contained in blocks. ...
Definition: transaction.h:270
CLRUCache< std::string, CDatabasedAssetData > * passetsCache
Global variable that point to the assets metadata LRU Cache (protected by cs_main) ...
Definition: validation.cpp:228
void AddToAssetBalance(const std::string &strName, const std::string &address, const CAmount &nAmount)
Definition: assets.cpp:1616
bool AddReissueAsset(const CReissueAsset &reissue, const std::string address, const COutPoint &out)
Changes Memory Only.
Definition: assets.cpp:1857
bool WriteVerifier(const std::string &assetName, const std::string &verifier)
bool VerifyNewRestrictedAsset(std::string &strError) const
To be called on CTransactions where IsNewRestrictedAsset returns true.
Definition: assets.cpp:1266
std::set< CAssetCacheNewTransfer > setNewTransferAssetsToAdd
Transfer Assets Caches.
Definition: assets.h:124
CTxDestination destination
Definition: wallet.h:195
bool IsNull() const
Definition: assets.cpp:414
std::set< CAssetCacheRestrictedVerifiers > setNewRestrictedVerifierToRemove
Definition: assets.h:141
bool IsNewUniqueAsset() const
Make sure to call VerifyNewUniqueAsset if this call returns true.
Definition: assets.cpp:900
std::string strIPFSHash
Definition: assettypes.h:243
bool VerifyNewAsset(std::string &strError) const
To be called on CTransactions where IsNewAsset returns true.
Definition: assets.cpp:1006
void ConstructGlobalRestrictionTransaction(CScript &script) const
Definition: assets.cpp:4419
bool AddBackSpentAsset(const Coin &coin, const std::string &assetName, const std::string &address, const CAmount &nAmount, const COutPoint &out)
Changes Memory Only.
Definition: assets.cpp:1769
std::string EncodeAssetData(std::string decoded)
Definition: assets.cpp:3716
std::map< std::string, CNewAsset > mapReissuedAssetData
Definition: assets.h:77
#define QUALIFIER_ASSET_MIN_AMOUNT
Definition: assets.h:43
bool IsUniqueTagValid(const std::string &tag)
Check if an unique tagname is valid.
Definition: assets.cpp:126
bool IsNullGlobalRestrictionAssetTxDataScript() const
Definition: script.cpp:338
CAmount nAmount
Definition: assettypes.h:191
bool ContextualCheckUniqueAssetTx(CAssetsCache *assetCache, std::string &strError, const CTransaction &tx)
Definition: assets.cpp:5416
const CAmount & IssueSubAssetBurnAmount() const
Definition: chainparams.h:95
const CAmount & AddNullQualifierTagBurnAmount() const
Definition: chainparams.h:101
std::string _(const char *psz)
Translation function: Call Translate signal on UI interface, which returns a boost::optional result...
Definition: util.h:66
bool CheckReissueDataTx(const CTxOut &txOut)
Definition: assets.cpp:3077
UniValue reissue(const JSONRPCRequest &request)
Definition: assets.cpp:1465
bool IsQualifierNameValid(const std::string &name)
Definition: assets.cpp:92
CScript GetScriptForNullAssetDataDestination(const CTxDestination &dest)
Generate a script that contains an address used for qualifier, and restricted assets data transaction...
Definition: standard.cpp:355
bool IsScriptNewQualifierAsset(const CScript &scriptPubKey)
Check script and see if it matches the qualifier issuance template.
Definition: assets.cpp:3219
bool IsAssetNameAnRestricted(const std::string &name)
Check if an asset is a restricted asset.
Definition: assets.cpp:301
bool UndoAssetCoin(const Coin &coin, const COutPoint &out)
Definition: assets.cpp:1709
std::vector< unsigned char > ToByteVector(const T &in)
Definition: script.h:45
bool IsAssetNameAnOwner(const std::string &name)
Check if an asset is an owner.
Definition: assets.cpp:296
bool IsAssetScript(int &nType, bool &fIsOwner, int &nStartingIndex) const
Definition: script.cpp:245
std::vector< unsigned char > ParseHex(const char *psz)
bool IsScriptNewUniqueAsset(const CScript &scriptPubKey)
Check script and see if it matches the unquie issuance template.
Definition: assets.cpp:3117
bool CommitTransaction(CWalletTx &wtxNew, CReserveKey &reservekey, CConnman *connman, CValidationState &state)
RVN END.
Definition: wallet.cpp:3683
bool ReadRestrictedAddress(const std::string &address, const std::string &assetName)
bool CheckNewAsset(const CNewAsset &asset, std::string &strError)
Definition: assets.cpp:5105