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