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