Remove testnet condition
[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                 txnouttype whichType;
50                 std::vector<valtype> vSolutions;
51                 if (Solver(txout.scriptPubKey, whichType, vSolutions))
52                 {
53                     CTxDestination address;
54                     if (whichType == TX_PUBKEY)
55                     {
56                         // Pay-to-Pubkey
57                         address = CPubKey(vSolutions[0]).GetID();
58                         sub.type = TransactionRecord::RecvWithAddress;
59                         sub.address = CBitcoinAddress(address).ToString();
60                     }
61                     else if (whichType == TX_PUBKEYHASH)
62                     {
63                         // Pay-to-PubkeyHash
64                         address = CKeyID(uint160(vSolutions[0]));
65                         sub.type = TransactionRecord::RecvWithAddress;
66                         sub.address = CBitcoinAddress(address).ToString();
67                     }
68                     else if (whichType == TX_SCRIPTHASH)
69                     {
70                         // Pay-to-ScriptHash
71                         address = CScriptID(uint160(vSolutions[0]));
72                         sub.type = TransactionRecord::RecvWithAddress;
73                         sub.address = CBitcoinAddress(address).ToString();
74                     }
75                     else if (whichType == TX_PUBKEY_DROP)
76                     {
77                         // Pay-to-Pubkey-R
78                         sub.type = TransactionRecord::RecvWithAddress;
79
80                         CMalleableKeyView view;
81                         pwalletMain->CheckOwnership(CPubKey(vSolutions[0]), CPubKey(vSolutions[1]), view);
82                         sub.address = view.GetMalleablePubKey().ToString();
83                     }
84                     else
85                     {
86                         // Received by IP connection (deprecated features), or a multisignature or other non-simple transaction
87                         sub.type = TransactionRecord::RecvFromOther;
88                         sub.address = mapValue["from"];
89                     }
90                 }
91                 if (wtx.IsCoinBase())
92                 {
93                     // Generated (proof-of-work)
94                     sub.type = TransactionRecord::Generated;
95                 }
96                 if (wtx.IsCoinStake())
97                 {
98                     // Generated (proof-of-stake)
99
100                     if (hashPrev == hash)
101                         continue; // last coinstake output
102
103                     sub.type = TransactionRecord::Generated;
104                     sub.credit = nNet > 0 ? nNet : wtx.GetValueOut() - nDebit;
105                     hashPrev = hash;
106                 }
107
108                 parts.append(sub);
109             }
110         }
111     }
112     else
113     {
114         bool fAllFromMe = true;
115         BOOST_FOREACH(const CTxIn& txin, wtx.vin)
116             fAllFromMe = fAllFromMe && wallet->IsMine(txin);
117
118         bool fAllToMe = true;
119         BOOST_FOREACH(const CTxOut& txout, wtx.vout)
120             fAllToMe = fAllToMe && wallet->IsMine(txout);
121
122         if (fAllFromMe && fAllToMe)
123         {
124             // Payment to self
125             int64_t nChange = wtx.GetChange();
126
127             parts.append(TransactionRecord(hash, nTime, TransactionRecord::SendToSelf, "",
128                             -(nDebit - nChange), nCredit - nChange));
129         }
130         else if (fAllFromMe)
131         {
132             //
133             // Debit
134             //
135             int64_t nTxFee = nDebit - wtx.GetValueOut();
136
137             for (unsigned int nOut = 0; nOut < wtx.vout.size(); nOut++)
138             {
139                 const CTxOut& txout = wtx.vout[nOut];
140                 TransactionRecord sub(hash, nTime);
141                 sub.idx = parts.size();
142
143                 if(wallet->IsMine(txout))
144                 {
145                     // Ignore parts sent to self, as this is usually the change
146                     // from a transaction sent back to our own address.
147                     continue;
148                 }
149
150                 CTxDestination address;
151                 if (ExtractDestination(txout.scriptPubKey, address))
152                 {
153                     // Sent to Bitcoin Address
154                     sub.type = TransactionRecord::SendToAddress;
155                     sub.address = CBitcoinAddress(address).ToString();
156                 }
157                 else
158                 {
159                     // Sent to IP, or other non-address transaction like OP_EVAL
160                     sub.type = TransactionRecord::SendToOther;
161                     sub.address = mapValue["to"];
162                 }
163
164                 int64_t nValue = txout.nValue;
165                 /* Add fee to first output */
166                 if (nTxFee > 0)
167                 {
168                     nValue += nTxFee;
169                     nTxFee = 0;
170                 }
171                 sub.debit = -nValue;
172
173                 parts.append(sub);
174             }
175         }
176         else
177         {
178             //
179             // Mixed debit transaction, can't break down payees
180             //
181             parts.append(TransactionRecord(hash, nTime, TransactionRecord::Other, "", nNet, 0));
182         }
183     }
184
185     return parts;
186 }
187
188 void TransactionRecord::updateStatus(const CWalletTx &wtx)
189 {
190     // Determine transaction status
191
192     // Find the block the tx is in
193     CBlockIndex* pindex = NULL;
194     std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(wtx.hashBlock);
195     if (mi != mapBlockIndex.end())
196         pindex = (*mi).second;
197
198     // Sort order, unrecorded transactions sort to the top
199     status.sortKey = strprintf("%010d-%01d-%010u-%03d",
200         (pindex ? pindex->nHeight : std::numeric_limits<int>::max()),
201         (wtx.IsCoinBase() ? 1 : 0),
202         wtx.nTimeReceived,
203         idx);
204     status.confirmed = wtx.IsTrusted();
205     status.depth = wtx.GetDepthInMainChain();
206     status.cur_num_blocks = nBestHeight;
207
208     if (!wtx.IsFinal())
209     {
210         if (wtx.nLockTime < LOCKTIME_THRESHOLD)
211         {
212             status.status = TransactionStatus::OpenUntilBlock;
213             status.open_for = nBestHeight - wtx.nLockTime;
214         }
215         else
216         {
217             status.status = TransactionStatus::OpenUntilDate;
218             status.open_for = wtx.nLockTime;
219         }
220     }
221     else
222     {
223         if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
224         {
225             status.status = TransactionStatus::Offline;
226         }
227         else if (status.depth < NumConfirmations)
228         {
229             status.status = TransactionStatus::Unconfirmed;
230         }
231         else
232         {
233             status.status = TransactionStatus::HaveConfirmations;
234         }
235     }
236
237     // For generated transactions, determine maturity
238     if(type == TransactionRecord::Generated)
239     {
240         if (wtx.GetBlocksToMaturity() > 0)
241         {
242             status.maturity = TransactionStatus::Immature;
243
244             if (wtx.IsInMainChain())
245             {
246                 status.matures_in = wtx.GetBlocksToMaturity();
247
248                 // Check if the block was requested by anyone
249                 if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
250                     status.maturity = TransactionStatus::MaturesWarning;
251             }
252             else
253             {
254                 status.maturity = TransactionStatus::NotAccepted;
255             }
256         }
257         else
258         {
259             status.maturity = TransactionStatus::Mature;
260         }
261     }
262 }
263
264 bool TransactionRecord::statusUpdateNeeded()
265 {
266     return status.cur_num_blocks != nBestHeight;
267 }
268
269 std::string TransactionRecord::getTxID()
270 {
271     return hash.ToString() + strprintf("-%03d", idx);
272 }
273