Line data Source code
1 : // Copyright (c) 2011-2019 The Bitcoin 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 <qt/transactionrecord.h> 6 : 7 : #include <chain.h> 8 : #include <interfaces/wallet.h> 9 : #include <key_io.h> 10 : #include <wallet/ismine.h> 11 : 12 : #include <stdint.h> 13 : 14 : #include <QDateTime> 15 : 16 : /* Return positive answer if transaction should be shown in list. 17 : */ 18 0 : bool TransactionRecord::showTransaction() 19 : { 20 : // There are currently no cases where we hide transactions, but 21 : // we may want to use this in the future for things like RBF. 22 0 : return true; 23 : } 24 : 25 : /* 26 : * Decompose CWallet transaction to model transaction records. 27 : */ 28 0 : QList<TransactionRecord> TransactionRecord::decomposeTransaction(const interfaces::WalletTx& wtx) 29 : { 30 0 : QList<TransactionRecord> parts; 31 0 : int64_t nTime = wtx.time; 32 0 : CAmount nCredit = wtx.credit; 33 0 : CAmount nDebit = wtx.debit; 34 0 : CAmount nNet = nCredit - nDebit; 35 0 : uint256 hash = wtx.tx->GetHash(); 36 0 : std::map<std::string, std::string> mapValue = wtx.value_map; 37 : 38 0 : if (nNet > 0 || wtx.is_coinbase) 39 : { 40 : // 41 : // Credit 42 : // 43 0 : for(unsigned int i = 0; i < wtx.tx->vout.size(); i++) 44 : { 45 0 : const CTxOut& txout = wtx.tx->vout[i]; 46 0 : isminetype mine = wtx.txout_is_mine[i]; 47 0 : if(mine) 48 : { 49 0 : TransactionRecord sub(hash, nTime); 50 0 : sub.idx = i; // vout index 51 0 : sub.credit = txout.nValue; 52 0 : sub.involvesWatchAddress = mine & ISMINE_WATCH_ONLY; 53 0 : if (wtx.txout_address_is_mine[i]) 54 : { 55 : // Received by Bitcoin Address 56 0 : sub.type = TransactionRecord::RecvWithAddress; 57 0 : sub.address = EncodeDestination(wtx.txout_address[i]); 58 0 : } 59 : else 60 : { 61 : // Received by IP connection (deprecated features), or a multisignature or other non-simple transaction 62 0 : sub.type = TransactionRecord::RecvFromOther; 63 0 : sub.address = mapValue["from"]; 64 : } 65 0 : if (wtx.is_coinbase) 66 : { 67 : // Generated 68 0 : sub.type = TransactionRecord::Generated; 69 0 : } 70 : 71 0 : parts.append(sub); 72 0 : } 73 : } 74 0 : } 75 : else 76 : { 77 : bool involvesWatchAddress = false; 78 : isminetype fAllFromMe = ISMINE_SPENDABLE; 79 0 : for (const isminetype mine : wtx.txin_is_mine) 80 : { 81 0 : if(mine & ISMINE_WATCH_ONLY) involvesWatchAddress = true; 82 0 : if(fAllFromMe > mine) fAllFromMe = mine; 83 : } 84 : 85 : isminetype fAllToMe = ISMINE_SPENDABLE; 86 0 : for (const isminetype mine : wtx.txout_is_mine) 87 : { 88 0 : if(mine & ISMINE_WATCH_ONLY) involvesWatchAddress = true; 89 0 : if(fAllToMe > mine) fAllToMe = mine; 90 : } 91 : 92 0 : if (fAllFromMe && fAllToMe) 93 : { 94 : // Payment to self 95 0 : std::string address; 96 0 : for (auto it = wtx.txout_address.begin(); it != wtx.txout_address.end(); ++it) { 97 0 : if (it != wtx.txout_address.begin()) address += ", "; 98 0 : address += EncodeDestination(*it); 99 : } 100 : 101 0 : CAmount nChange = wtx.change; 102 0 : parts.append(TransactionRecord(hash, nTime, TransactionRecord::SendToSelf, address, -(nDebit - nChange), nCredit - nChange)); 103 0 : parts.last().involvesWatchAddress = involvesWatchAddress; // maybe pass to TransactionRecord as constructor argument 104 0 : } 105 0 : else if (fAllFromMe) 106 : { 107 : // 108 : // Debit 109 : // 110 0 : CAmount nTxFee = nDebit - wtx.tx->GetValueOut(); 111 : 112 0 : for (unsigned int nOut = 0; nOut < wtx.tx->vout.size(); nOut++) 113 : { 114 0 : const CTxOut& txout = wtx.tx->vout[nOut]; 115 0 : TransactionRecord sub(hash, nTime); 116 0 : sub.idx = nOut; 117 0 : sub.involvesWatchAddress = involvesWatchAddress; 118 : 119 0 : if(wtx.txout_is_mine[nOut]) 120 : { 121 : // Ignore parts sent to self, as this is usually the change 122 : // from a transaction sent back to our own address. 123 0 : continue; 124 : } 125 : 126 0 : if (!boost::get<CNoDestination>(&wtx.txout_address[nOut])) 127 : { 128 : // Sent to Bitcoin Address 129 0 : sub.type = TransactionRecord::SendToAddress; 130 0 : sub.address = EncodeDestination(wtx.txout_address[nOut]); 131 0 : } 132 : else 133 : { 134 : // Sent to IP, or other non-address transaction like OP_EVAL 135 0 : sub.type = TransactionRecord::SendToOther; 136 0 : sub.address = mapValue["to"]; 137 : } 138 : 139 0 : CAmount nValue = txout.nValue; 140 : /* Add fee to first output */ 141 0 : if (nTxFee > 0) 142 : { 143 0 : nValue += nTxFee; 144 : nTxFee = 0; 145 0 : } 146 0 : sub.debit = -nValue; 147 : 148 0 : parts.append(sub); 149 0 : } 150 0 : } 151 : else 152 : { 153 : // 154 : // Mixed debit transaction, can't break down payees 155 : // 156 0 : parts.append(TransactionRecord(hash, nTime, TransactionRecord::Other, "", nNet, 0)); 157 0 : parts.last().involvesWatchAddress = involvesWatchAddress; 158 : } 159 0 : } 160 : 161 : return parts; 162 0 : } 163 : 164 0 : void TransactionRecord::updateStatus(const interfaces::WalletTxStatus& wtx, const uint256& block_hash, int numBlocks, int64_t block_time) 165 : { 166 : // Determine transaction status 167 : 168 : // Sort order, unrecorded transactions sort to the top 169 0 : status.sortKey = strprintf("%010d-%01d-%010u-%03d", 170 0 : wtx.block_height, 171 0 : wtx.is_coinbase ? 1 : 0, 172 0 : wtx.time_received, 173 0 : idx); 174 0 : status.countsForBalance = wtx.is_trusted && !(wtx.blocks_to_maturity > 0); 175 0 : status.depth = wtx.depth_in_main_chain; 176 0 : status.m_cur_block_hash = block_hash; 177 : 178 0 : const bool up_to_date = ((int64_t)QDateTime::currentMSecsSinceEpoch() / 1000 - block_time < MAX_BLOCK_TIME_GAP); 179 0 : if (up_to_date && !wtx.is_final) { 180 0 : if (wtx.lock_time < LOCKTIME_THRESHOLD) { 181 0 : status.status = TransactionStatus::OpenUntilBlock; 182 0 : status.open_for = wtx.lock_time - numBlocks; 183 0 : } 184 : else 185 : { 186 0 : status.status = TransactionStatus::OpenUntilDate; 187 0 : status.open_for = wtx.lock_time; 188 : } 189 : } 190 : // For generated transactions, determine maturity 191 0 : else if(type == TransactionRecord::Generated) 192 : { 193 0 : if (wtx.blocks_to_maturity > 0) 194 : { 195 0 : status.status = TransactionStatus::Immature; 196 : 197 0 : if (wtx.is_in_main_chain) 198 : { 199 0 : status.matures_in = wtx.blocks_to_maturity; 200 0 : } 201 : else 202 : { 203 0 : status.status = TransactionStatus::NotAccepted; 204 : } 205 : } 206 : else 207 : { 208 0 : status.status = TransactionStatus::Confirmed; 209 : } 210 : } 211 : else 212 : { 213 0 : if (status.depth < 0) 214 : { 215 0 : status.status = TransactionStatus::Conflicted; 216 0 : } 217 0 : else if (status.depth == 0) 218 : { 219 0 : status.status = TransactionStatus::Unconfirmed; 220 0 : if (wtx.is_abandoned) 221 0 : status.status = TransactionStatus::Abandoned; 222 : } 223 0 : else if (status.depth < RecommendedNumConfirmations) 224 : { 225 0 : status.status = TransactionStatus::Confirming; 226 0 : } 227 : else 228 : { 229 0 : status.status = TransactionStatus::Confirmed; 230 : } 231 : } 232 0 : status.needsUpdate = false; 233 0 : } 234 : 235 0 : bool TransactionRecord::statusUpdateNeeded(const uint256& block_hash) const 236 : { 237 0 : assert(!block_hash.IsNull()); 238 0 : return status.m_cur_block_hash != block_hash || status.needsUpdate; 239 : } 240 : 241 0 : QString TransactionRecord::getTxHash() const 242 : { 243 0 : return QString::fromStdString(hash.ToString()); 244 0 : } 245 : 246 0 : int TransactionRecord::getOutputIndex() const 247 : { 248 0 : return idx; 249 : }