transactionrecord.cpp
1 // Copyright (c) 2011-present 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 11 #include <cstdint> 12 13 #include <QDateTime> 14 15 /* Return positive answer if transaction should be shown in list. 16 */ 17 bool TransactionRecord::showTransaction() 18 { 19 // There are currently no cases where we hide transactions, but 20 // we may want to use this in the future for things like RBF. 21 return true; 22 } 23 24 /* 25 * Decompose CWallet transaction to model transaction records. 26 */ 27 QList<TransactionRecord> TransactionRecord::decomposeTransaction(const interfaces::WalletTx& wtx) 28 { 29 QList<TransactionRecord> parts; 30 int64_t nTime = wtx.time; 31 CAmount nCredit = wtx.credit; 32 CAmount nDebit = wtx.debit; 33 CAmount nNet = nCredit - nDebit; 34 Txid hash = wtx.tx->GetHash(); 35 std::map<std::string, std::string> mapValue = wtx.value_map; 36 37 bool all_from_me = true; 38 bool any_from_me = false; 39 if (wtx.is_coinbase) { 40 all_from_me = false; 41 } else { 42 for (const bool mine : wtx.txin_is_mine) 43 { 44 all_from_me = all_from_me && mine; 45 if (mine) any_from_me = true; 46 } 47 } 48 49 if (all_from_me || !any_from_me) { 50 CAmount nTxFee = nDebit - wtx.tx->GetValueOut(); 51 52 for(unsigned int i = 0; i < wtx.tx->vout.size(); i++) 53 { 54 const CTxOut& txout = wtx.tx->vout[i]; 55 56 if (all_from_me) { 57 // Change is only really possible if we're the sender 58 // Otherwise, someone just sent bitcoins to a change address, which should be shown 59 if (wtx.txout_is_change[i]) { 60 continue; 61 } 62 63 // 64 // Debit 65 // 66 67 TransactionRecord sub(hash, nTime); 68 sub.idx = i; 69 70 if (!std::get_if<CNoDestination>(&wtx.txout_address[i])) 71 { 72 // Sent to Bitcoin Address 73 sub.type = TransactionRecord::SendToAddress; 74 sub.address = EncodeDestination(wtx.txout_address[i]); 75 } 76 else 77 { 78 // Sent to IP, or other non-address transaction like OP_EVAL 79 sub.type = TransactionRecord::SendToOther; 80 sub.address = mapValue["to"]; 81 } 82 83 CAmount nValue = txout.nValue; 84 /* Add fee to first output */ 85 if (nTxFee > 0) 86 { 87 nValue += nTxFee; 88 nTxFee = 0; 89 } 90 sub.debit = -nValue; 91 92 parts.append(sub); 93 } 94 95 bool mine = wtx.txout_is_mine[i]; 96 if(mine) 97 { 98 // 99 // Credit 100 // 101 102 TransactionRecord sub(hash, nTime); 103 sub.idx = i; // vout index 104 sub.credit = txout.nValue; 105 if (wtx.txout_address_is_mine[i]) 106 { 107 // Received by Bitcoin Address 108 sub.type = TransactionRecord::RecvWithAddress; 109 sub.address = EncodeDestination(wtx.txout_address[i]); 110 } 111 else 112 { 113 // Received by IP connection (deprecated features), or a multisignature or other non-simple transaction 114 sub.type = TransactionRecord::RecvFromOther; 115 sub.address = mapValue["from"]; 116 } 117 if (wtx.is_coinbase) 118 { 119 // Generated 120 sub.type = TransactionRecord::Generated; 121 } 122 123 parts.append(sub); 124 } 125 } 126 } else { 127 // 128 // Mixed debit transaction, can't break down payees 129 // 130 parts.append(TransactionRecord(hash, nTime, TransactionRecord::Other, "", nNet, 0)); 131 } 132 133 return parts; 134 } 135 136 void TransactionRecord::updateStatus(const interfaces::WalletTxStatus& wtx, const uint256& block_hash, int numBlocks, int64_t block_time) 137 { 138 // Determine transaction status 139 140 // Sort order, unrecorded transactions sort to the top 141 int typesort; 142 switch (type) { 143 case SendToAddress: case SendToOther: 144 typesort = 2; break; 145 case RecvWithAddress: case RecvFromOther: 146 typesort = 3; break; 147 default: 148 typesort = 9; 149 } 150 status.sortKey = strprintf("%010d-%01d-%010u-%03d-%d", 151 wtx.block_height, 152 wtx.is_coinbase ? 1 : 0, 153 wtx.time_received, 154 idx, 155 typesort); 156 status.countsForBalance = wtx.is_trusted && !(wtx.blocks_to_maturity > 0); 157 status.depth = wtx.depth_in_main_chain; 158 status.m_cur_block_hash = block_hash; 159 160 // For generated transactions, determine maturity 161 if (type == TransactionRecord::Generated) { 162 if (wtx.blocks_to_maturity > 0) 163 { 164 status.status = TransactionStatus::Immature; 165 166 if (wtx.is_in_main_chain) 167 { 168 status.matures_in = wtx.blocks_to_maturity; 169 } 170 else 171 { 172 status.status = TransactionStatus::NotAccepted; 173 } 174 } 175 else 176 { 177 status.status = TransactionStatus::Confirmed; 178 } 179 } 180 else 181 { 182 if (status.depth < 0) 183 { 184 status.status = TransactionStatus::Conflicted; 185 } 186 else if (status.depth == 0) 187 { 188 status.status = TransactionStatus::Unconfirmed; 189 if (wtx.is_abandoned) 190 status.status = TransactionStatus::Abandoned; 191 } 192 else if (status.depth < RecommendedNumConfirmations) 193 { 194 status.status = TransactionStatus::Confirming; 195 } 196 else 197 { 198 status.status = TransactionStatus::Confirmed; 199 } 200 } 201 status.needsUpdate = false; 202 } 203 204 bool TransactionRecord::statusUpdateNeeded(const uint256& block_hash) const 205 { 206 assert(!block_hash.IsNull()); 207 return status.m_cur_block_hash != block_hash || status.needsUpdate; 208 } 209 210 QString TransactionRecord::getTxHash() const 211 { 212 return QString::fromStdString(hash.ToString()); 213 } 214 215 int TransactionRecord::getOutputIndex() const 216 { 217 return idx; 218 }