You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

transactionrecord.cpp 8.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. // Copyright (c) 2011-2016 The Starwels developers
  2. // Distributed under the MIT software license, see the accompanying
  3. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  4. #include "transactionrecord.h"
  5. #include "base58.h"
  6. #include "consensus/consensus.h"
  7. #include "validation.h"
  8. #include "timedata.h"
  9. #include "wallet/wallet.h"
  10. #include <stdint.h>
  11. /* Return positive answer if transaction should be shown in list.
  12. */
  13. bool TransactionRecord::showTransaction(const CWalletTx &wtx)
  14. {
  15. // There are currently no cases where we hide transactions, but
  16. // we may want to use this in the future for things like RBF.
  17. return true;
  18. }
  19. /*
  20. * Decompose CWallet transaction to model transaction records.
  21. */
  22. QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *wallet, const CWalletTx &wtx)
  23. {
  24. QList<TransactionRecord> parts;
  25. int64_t nTime = wtx.GetTxTime();
  26. CAmount nCredit = wtx.GetCredit(ISMINE_ALL);
  27. CAmount nDebit = wtx.GetDebit(ISMINE_ALL);
  28. CAmount nNet = nCredit - nDebit;
  29. uint256 hash = wtx.GetHash();
  30. std::map<std::string, std::string> mapValue = wtx.mapValue;
  31. if (nNet > 0 || wtx.IsCoinBase())
  32. {
  33. //
  34. // Credit
  35. //
  36. for(unsigned int i = 0; i < wtx.tx->vout.size(); i++)
  37. {
  38. const CTxOut& txout = wtx.tx->vout[i];
  39. isminetype mine = wallet->IsMine(txout);
  40. if(mine)
  41. {
  42. TransactionRecord sub(hash, nTime);
  43. CTxDestination address;
  44. sub.idx = i; // vout index
  45. sub.credit = txout.nValue;
  46. sub.involvesWatchAddress = mine & ISMINE_WATCH_ONLY;
  47. if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*wallet, address))
  48. {
  49. // Received by Starwels Address
  50. sub.type = TransactionRecord::RecvWithAddress;
  51. sub.address = CStarwelsAddress(address).ToString();
  52. }
  53. else
  54. {
  55. // Received by IP connection (deprecated features), or a multisignature or other non-simple transaction
  56. sub.type = TransactionRecord::RecvFromOther;
  57. sub.address = mapValue["from"];
  58. }
  59. if (wtx.IsCoinBase())
  60. {
  61. // Generated
  62. sub.type = TransactionRecord::Generated;
  63. }
  64. parts.append(sub);
  65. }
  66. }
  67. }
  68. else
  69. {
  70. bool involvesWatchAddress = false;
  71. isminetype fAllFromMe = ISMINE_SPENDABLE;
  72. for (const CTxIn& txin : wtx.tx->vin)
  73. {
  74. isminetype mine = wallet->IsMine(txin);
  75. if(mine & ISMINE_WATCH_ONLY) involvesWatchAddress = true;
  76. if(fAllFromMe > mine) fAllFromMe = mine;
  77. }
  78. isminetype fAllToMe = ISMINE_SPENDABLE;
  79. for (const CTxOut& txout : wtx.tx->vout)
  80. {
  81. isminetype mine = wallet->IsMine(txout);
  82. if(mine & ISMINE_WATCH_ONLY) involvesWatchAddress = true;
  83. if(fAllToMe > mine) fAllToMe = mine;
  84. }
  85. if (fAllFromMe && fAllToMe)
  86. {
  87. // Payment to self
  88. CAmount nChange = wtx.GetChange();
  89. parts.append(TransactionRecord(hash, nTime, TransactionRecord::SendToSelf, "",
  90. -(nDebit - nChange), nCredit - nChange));
  91. parts.last().involvesWatchAddress = involvesWatchAddress; // maybe pass to TransactionRecord as constructor argument
  92. }
  93. else if (fAllFromMe)
  94. {
  95. //
  96. // Debit
  97. //
  98. CAmount nTxFee = nDebit - wtx.tx->GetValueOut();
  99. for (unsigned int nOut = 0; nOut < wtx.tx->vout.size(); nOut++)
  100. {
  101. const CTxOut& txout = wtx.tx->vout[nOut];
  102. TransactionRecord sub(hash, nTime);
  103. sub.idx = nOut;
  104. sub.involvesWatchAddress = involvesWatchAddress;
  105. if(wallet->IsMine(txout))
  106. {
  107. // Ignore parts sent to self, as this is usually the change
  108. // from a transaction sent back to our own address.
  109. continue;
  110. }
  111. CTxDestination address;
  112. if (ExtractDestination(txout.scriptPubKey, address))
  113. {
  114. // Sent to Starwels Address
  115. sub.type = TransactionRecord::SendToAddress;
  116. sub.address = CStarwelsAddress(address).ToString();
  117. }
  118. else
  119. {
  120. // Sent to IP, or other non-address transaction like OP_EVAL
  121. sub.type = TransactionRecord::SendToOther;
  122. sub.address = mapValue["to"];
  123. }
  124. CAmount nValue = txout.nValue;
  125. /* Add fee to first output */
  126. if (nTxFee > 0)
  127. {
  128. nValue += nTxFee;
  129. nTxFee = 0;
  130. }
  131. sub.debit = -nValue;
  132. parts.append(sub);
  133. }
  134. }
  135. else
  136. {
  137. //
  138. // Mixed debit transaction, can't break down payees
  139. //
  140. parts.append(TransactionRecord(hash, nTime, TransactionRecord::Other, "", nNet, 0));
  141. parts.last().involvesWatchAddress = involvesWatchAddress;
  142. }
  143. }
  144. return parts;
  145. }
  146. void TransactionRecord::updateStatus(const CWalletTx &wtx)
  147. {
  148. AssertLockHeld(cs_main);
  149. // Determine transaction status
  150. // Find the block the tx is in
  151. CBlockIndex* pindex = nullptr;
  152. BlockMap::iterator mi = mapBlockIndex.find(wtx.hashBlock);
  153. if (mi != mapBlockIndex.end())
  154. pindex = (*mi).second;
  155. // Sort order, unrecorded transactions sort to the top
  156. status.sortKey = strprintf("%010d-%01d-%010u-%03d",
  157. (pindex ? pindex->nHeight : std::numeric_limits<int>::max()),
  158. (wtx.IsCoinBase() ? 1 : 0),
  159. wtx.nTimeReceived,
  160. idx);
  161. status.countsForBalance = wtx.IsTrusted() && !(wtx.GetBlocksToMaturity() > 0);
  162. status.depth = wtx.GetDepthInMainChain();
  163. status.cur_num_blocks = chainActive.Height();
  164. if (!CheckFinalTx(wtx))
  165. {
  166. if (wtx.tx->nLockTime < LOCKTIME_THRESHOLD)
  167. {
  168. status.status = TransactionStatus::OpenUntilBlock;
  169. status.open_for = wtx.tx->nLockTime - chainActive.Height();
  170. }
  171. else
  172. {
  173. status.status = TransactionStatus::OpenUntilDate;
  174. status.open_for = wtx.tx->nLockTime;
  175. }
  176. }
  177. // For generated transactions, determine maturity
  178. else if(type == TransactionRecord::Generated)
  179. {
  180. if (wtx.GetBlocksToMaturity() > 0)
  181. {
  182. status.status = TransactionStatus::Immature;
  183. if (wtx.IsInMainChain())
  184. {
  185. status.matures_in = wtx.GetBlocksToMaturity();
  186. // Check if the block was requested by anyone
  187. if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
  188. status.status = TransactionStatus::MaturesWarning;
  189. }
  190. else
  191. {
  192. status.status = TransactionStatus::NotAccepted;
  193. }
  194. }
  195. else
  196. {
  197. status.status = TransactionStatus::Confirmed;
  198. }
  199. }
  200. else
  201. {
  202. if (status.depth < 0)
  203. {
  204. status.status = TransactionStatus::Conflicted;
  205. }
  206. else if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
  207. {
  208. status.status = TransactionStatus::Offline;
  209. }
  210. else if (status.depth == 0)
  211. {
  212. status.status = TransactionStatus::Unconfirmed;
  213. if (wtx.isAbandoned())
  214. status.status = TransactionStatus::Abandoned;
  215. }
  216. else if (status.depth < RecommendedNumConfirmations)
  217. {
  218. status.status = TransactionStatus::Confirming;
  219. }
  220. else
  221. {
  222. status.status = TransactionStatus::Confirmed;
  223. }
  224. }
  225. status.needsUpdate = false;
  226. }
  227. bool TransactionRecord::statusUpdateNeeded()
  228. {
  229. AssertLockHeld(cs_main);
  230. return status.cur_num_blocks != chainActive.Height() || status.needsUpdate;
  231. }
  232. QString TransactionRecord::getTxID() const
  233. {
  234. return QString::fromStdString(hash.ToString());
  235. }
  236. int TransactionRecord::getOutputIndex() const
  237. {
  238. return idx;
  239. }