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