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