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