]> Git Repo - VerusCoin.git/blob - main.cpp
update fSpent flag on wallet transactions if they're seen spent in case copy of walle...
[VerusCoin.git] / main.cpp
1 // Copyright (c) 2009-2010 Satoshi Nakamoto\r
2 // Distributed under the MIT/X11 software license, see the accompanying\r
3 // file license.txt or http://www.opensource.org/licenses/mit-license.php.\r
4 \r
5 #include "headers.h"\r
6 #include "sha.h"\r
7 \r
8 \r
9 \r
10 \r
11 \r
12 //\r
13 // Global state\r
14 //\r
15 \r
16 CCriticalSection cs_main;\r
17 \r
18 map<uint256, CTransaction> mapTransactions;\r
19 CCriticalSection cs_mapTransactions;\r
20 unsigned int nTransactionsUpdated = 0;\r
21 map<COutPoint, CInPoint> mapNextTx;\r
22 \r
23 map<uint256, CBlockIndex*> mapBlockIndex;\r
24 const uint256 hashGenesisBlock("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f");\r
25 CBlockIndex* pindexGenesisBlock = NULL;\r
26 int nBestHeight = -1;\r
27 uint256 hashBestChain = 0;\r
28 CBlockIndex* pindexBest = NULL;\r
29 \r
30 map<uint256, CBlock*> mapOrphanBlocks;\r
31 multimap<uint256, CBlock*> mapOrphanBlocksByPrev;\r
32 \r
33 map<uint256, CDataStream*> mapOrphanTransactions;\r
34 multimap<uint256, CDataStream*> mapOrphanTransactionsByPrev;\r
35 \r
36 map<uint256, CWalletTx> mapWallet;\r
37 vector<uint256> vWalletUpdated;\r
38 CCriticalSection cs_mapWallet;\r
39 \r
40 map<vector<unsigned char>, CPrivKey> mapKeys;\r
41 map<uint160, vector<unsigned char> > mapPubKeys;\r
42 CCriticalSection cs_mapKeys;\r
43 CKey keyUser;\r
44 \r
45 map<uint256, int> mapRequestCount;\r
46 CCriticalSection cs_mapRequestCount;\r
47 \r
48 // Settings\r
49 int fGenerateBitcoins = false;\r
50 int64 nTransactionFee = 0;\r
51 CAddress addrIncoming;\r
52 int fLimitProcessors = false;\r
53 int nLimitProcessors = 1;\r
54 \r
55 \r
56 \r
57 \r
58 \r
59 \r
60 //////////////////////////////////////////////////////////////////////////////\r
61 //\r
62 // mapKeys\r
63 //\r
64 \r
65 bool AddKey(const CKey& key)\r
66 {\r
67     CRITICAL_BLOCK(cs_mapKeys)\r
68     {\r
69         mapKeys[key.GetPubKey()] = key.GetPrivKey();\r
70         mapPubKeys[Hash160(key.GetPubKey())] = key.GetPubKey();\r
71     }\r
72     return CWalletDB().WriteKey(key.GetPubKey(), key.GetPrivKey());\r
73 }\r
74 \r
75 vector<unsigned char> GenerateNewKey()\r
76 {\r
77     CKey key;\r
78     key.MakeNewKey();\r
79     if (!AddKey(key))\r
80         throw runtime_error("GenerateNewKey() : AddKey failed\n");\r
81     return key.GetPubKey();\r
82 }\r
83 \r
84 \r
85 \r
86 \r
87 //////////////////////////////////////////////////////////////////////////////\r
88 //\r
89 // mapWallet\r
90 //\r
91 \r
92 bool AddToWallet(const CWalletTx& wtxIn)\r
93 {\r
94     uint256 hash = wtxIn.GetHash();\r
95     CRITICAL_BLOCK(cs_mapWallet)\r
96     {\r
97         // Inserts only if not already there, returns tx inserted or tx found\r
98         pair<map<uint256, CWalletTx>::iterator, bool> ret = mapWallet.insert(make_pair(hash, wtxIn));\r
99         CWalletTx& wtx = (*ret.first).second;\r
100         bool fInsertedNew = ret.second;\r
101         if (fInsertedNew)\r
102             wtx.nTimeReceived = GetAdjustedTime();\r
103 \r
104         bool fUpdated = false;\r
105         if (!fInsertedNew)\r
106         {\r
107             // Merge\r
108             if (wtxIn.hashBlock != 0 && wtxIn.hashBlock != wtx.hashBlock)\r
109             {\r
110                 wtx.hashBlock = wtxIn.hashBlock;\r
111                 fUpdated = true;\r
112             }\r
113             if (wtxIn.nIndex != -1 && (wtxIn.vMerkleBranch != wtx.vMerkleBranch || wtxIn.nIndex != wtx.nIndex))\r
114             {\r
115                 wtx.vMerkleBranch = wtxIn.vMerkleBranch;\r
116                 wtx.nIndex = wtxIn.nIndex;\r
117                 fUpdated = true;\r
118             }\r
119             if (wtxIn.fFromMe && wtxIn.fFromMe != wtx.fFromMe)\r
120             {\r
121                 wtx.fFromMe = wtxIn.fFromMe;\r
122                 fUpdated = true;\r
123             }\r
124             if (wtxIn.fSpent && wtxIn.fSpent != wtx.fSpent)\r
125             {\r
126                 wtx.fSpent = wtxIn.fSpent;\r
127                 fUpdated = true;\r
128             }\r
129         }\r
130 \r
131         //// debug print\r
132         printf("AddToWallet %s  %s%s\n", wtxIn.GetHash().ToString().substr(0,6).c_str(), (fInsertedNew ? "new" : ""), (fUpdated ? "update" : ""));\r
133 \r
134         // Write to disk\r
135         if (fInsertedNew || fUpdated)\r
136             if (!wtx.WriteToDisk())\r
137                 return false;\r
138 \r
139         // Notify UI\r
140         vWalletUpdated.push_back(hash);\r
141     }\r
142 \r
143     // Refresh UI\r
144     MainFrameRepaint();\r
145     return true;\r
146 }\r
147 \r
148 bool AddToWalletIfMine(const CTransaction& tx, const CBlock* pblock)\r
149 {\r
150     if (tx.IsMine() || mapWallet.count(tx.GetHash()))\r
151     {\r
152         CWalletTx wtx(tx);\r
153         // Get merkle branch if transaction was found in a block\r
154         if (pblock)\r
155             wtx.SetMerkleBranch(pblock);\r
156         return AddToWallet(wtx);\r
157     }\r
158     return true;\r
159 }\r
160 \r
161 bool EraseFromWallet(uint256 hash)\r
162 {\r
163     CRITICAL_BLOCK(cs_mapWallet)\r
164     {\r
165         if (mapWallet.erase(hash))\r
166             CWalletDB().EraseTx(hash);\r
167     }\r
168     return true;\r
169 }\r
170 \r
171 void WalletUpdateSpent(const COutPoint& prevout)\r
172 {\r
173     // Anytime a signature is successfully verified, it's proof the outpoint is spent.\r
174     // Update the wallet spent flag if it doesn't know due to wallet.dat being\r
175     // restored from backup or the user making copies of wallet.dat.\r
176     CRITICAL_BLOCK(cs_mapWallet)\r
177     {\r
178         map<uint256, CWalletTx>::iterator mi = mapWallet.find(prevout.hash);\r
179         if (mi != mapWallet.end())\r
180         {\r
181             CWalletTx& wtx = (*mi).second;\r
182             if (!wtx.fSpent && wtx.vout[prevout.n].IsMine())\r
183             {\r
184                 printf("WalletUpdateSpent found spent coin %sbc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str());\r
185                 wtx.fSpent = true;\r
186                 wtx.WriteToDisk();\r
187                 vWalletUpdated.push_back(prevout.hash);\r
188             }\r
189         }\r
190     }\r
191 }\r
192 \r
193 \r
194 \r
195 \r
196 \r
197 \r
198 \r
199 \r
200 //////////////////////////////////////////////////////////////////////////////\r
201 //\r
202 // mapOrphanTransactions\r
203 //\r
204 \r
205 void AddOrphanTx(const CDataStream& vMsg)\r
206 {\r
207     CTransaction tx;\r
208     CDataStream(vMsg) >> tx;\r
209     uint256 hash = tx.GetHash();\r
210     if (mapOrphanTransactions.count(hash))\r
211         return;\r
212     CDataStream* pvMsg = mapOrphanTransactions[hash] = new CDataStream(vMsg);\r
213     foreach(const CTxIn& txin, tx.vin)\r
214         mapOrphanTransactionsByPrev.insert(make_pair(txin.prevout.hash, pvMsg));\r
215 }\r
216 \r
217 void EraseOrphanTx(uint256 hash)\r
218 {\r
219     if (!mapOrphanTransactions.count(hash))\r
220         return;\r
221     const CDataStream* pvMsg = mapOrphanTransactions[hash];\r
222     CTransaction tx;\r
223     CDataStream(*pvMsg) >> tx;\r
224     foreach(const CTxIn& txin, tx.vin)\r
225     {\r
226         for (multimap<uint256, CDataStream*>::iterator mi = mapOrphanTransactionsByPrev.lower_bound(txin.prevout.hash);\r
227              mi != mapOrphanTransactionsByPrev.upper_bound(txin.prevout.hash);)\r
228         {\r
229             if ((*mi).second == pvMsg)\r
230                 mapOrphanTransactionsByPrev.erase(mi++);\r
231             else\r
232                 mi++;\r
233         }\r
234     }\r
235     delete pvMsg;\r
236     mapOrphanTransactions.erase(hash);\r
237 }\r
238 \r
239 \r
240 \r
241 \r
242 \r
243 \r
244 \r
245 \r
246 //////////////////////////////////////////////////////////////////////////////\r
247 //\r
248 // CTransaction\r
249 //\r
250 \r
251 bool CTxIn::IsMine() const\r
252 {\r
253     CRITICAL_BLOCK(cs_mapWallet)\r
254     {\r
255         map<uint256, CWalletTx>::iterator mi = mapWallet.find(prevout.hash);\r
256         if (mi != mapWallet.end())\r
257         {\r
258             const CWalletTx& prev = (*mi).second;\r
259             if (prevout.n < prev.vout.size())\r
260                 if (prev.vout[prevout.n].IsMine())\r
261                     return true;\r
262         }\r
263     }\r
264     return false;\r
265 }\r
266 \r
267 int64 CTxIn::GetDebit() const\r
268 {\r
269     CRITICAL_BLOCK(cs_mapWallet)\r
270     {\r
271         map<uint256, CWalletTx>::iterator mi = mapWallet.find(prevout.hash);\r
272         if (mi != mapWallet.end())\r
273         {\r
274             const CWalletTx& prev = (*mi).second;\r
275             if (prevout.n < prev.vout.size())\r
276                 if (prev.vout[prevout.n].IsMine())\r
277                     return prev.vout[prevout.n].nValue;\r
278         }\r
279     }\r
280     return 0;\r
281 }\r
282 \r
283 int64 CWalletTx::GetTxTime() const\r
284 {\r
285     if (!fTimeReceivedIsTxTime && hashBlock != 0)\r
286     {\r
287         // If we did not receive the transaction directly, we rely on the block's\r
288         // time to figure out when it happened.  We use the median over a range\r
289         // of blocks to try to filter out inaccurate block times.\r
290         map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);\r
291         if (mi != mapBlockIndex.end())\r
292         {\r
293             CBlockIndex* pindex = (*mi).second;\r
294             if (pindex)\r
295                 return pindex->GetMedianTime();\r
296         }\r
297     }\r
298     return nTimeReceived;\r
299 }\r
300 \r
301 int CWalletTx::GetRequestCount() const\r
302 {\r
303     // Returns -1 if it wasn't being tracked\r
304     int nRequests = -1;\r
305     CRITICAL_BLOCK(cs_mapRequestCount)\r
306     {\r
307         if (IsCoinBase())\r
308         {\r
309             // Generated block\r
310             if (hashBlock != 0)\r
311             {\r
312                 map<uint256, int>::iterator mi = mapRequestCount.find(hashBlock);\r
313                 if (mi != mapRequestCount.end())\r
314                     nRequests = (*mi).second;\r
315             }\r
316         }\r
317         else\r
318         {\r
319             // Did anyone request this transaction?\r
320             map<uint256, int>::iterator mi = mapRequestCount.find(GetHash());\r
321             if (mi != mapRequestCount.end())\r
322             {\r
323                 nRequests = (*mi).second;\r
324 \r
325                 // How about the block it's in?\r
326                 if (nRequests == 0 && hashBlock != 0)\r
327                 {\r
328                     map<uint256, int>::iterator mi = mapRequestCount.find(hashBlock);\r
329                     if (mi != mapRequestCount.end())\r
330                         nRequests = (*mi).second;\r
331                     else\r
332                         nRequests = 1; // If it's in someone else's block it must have got out\r
333                 }\r
334             }\r
335         }\r
336     }\r
337     return nRequests;\r
338 }\r
339 \r
340 \r
341 \r
342 \r
343 int CMerkleTx::SetMerkleBranch(const CBlock* pblock)\r
344 {\r
345     if (fClient)\r
346     {\r
347         if (hashBlock == 0)\r
348             return 0;\r
349     }\r
350     else\r
351     {\r
352         CBlock blockTmp;\r
353         if (pblock == NULL)\r
354         {\r
355             // Load the block this tx is in\r
356             CTxIndex txindex;\r
357             if (!CTxDB("r").ReadTxIndex(GetHash(), txindex))\r
358                 return 0;\r
359             if (!blockTmp.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos))\r
360                 return 0;\r
361             pblock = &blockTmp;\r
362         }\r
363 \r
364         // Update the tx's hashBlock\r
365         hashBlock = pblock->GetHash();\r
366 \r
367         // Locate the transaction\r
368         for (nIndex = 0; nIndex < pblock->vtx.size(); nIndex++)\r
369             if (pblock->vtx[nIndex] == *(CTransaction*)this)\r
370                 break;\r
371         if (nIndex == pblock->vtx.size())\r
372         {\r
373             vMerkleBranch.clear();\r
374             nIndex = -1;\r
375             printf("ERROR: SetMerkleBranch() : couldn't find tx in block\n");\r
376             return 0;\r
377         }\r
378 \r
379         // Fill in merkle branch\r
380         vMerkleBranch = pblock->GetMerkleBranch(nIndex);\r
381     }\r
382 \r
383     // Is the tx in a block that's in the main chain\r
384     map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);\r
385     if (mi == mapBlockIndex.end())\r
386         return 0;\r
387     CBlockIndex* pindex = (*mi).second;\r
388     if (!pindex || !pindex->IsInMainChain())\r
389         return 0;\r
390 \r
391     return pindexBest->nHeight - pindex->nHeight + 1;\r
392 }\r
393 \r
394 \r
395 \r
396 void CWalletTx::AddSupportingTransactions(CTxDB& txdb)\r
397 {\r
398     vtxPrev.clear();\r
399 \r
400     const int COPY_DEPTH = 3;\r
401     if (SetMerkleBranch() < COPY_DEPTH)\r
402     {\r
403         vector<uint256> vWorkQueue;\r
404         foreach(const CTxIn& txin, vin)\r
405             vWorkQueue.push_back(txin.prevout.hash);\r
406 \r
407         // This critsect is OK because txdb is already open\r
408         CRITICAL_BLOCK(cs_mapWallet)\r
409         {\r
410             map<uint256, const CMerkleTx*> mapWalletPrev;\r
411             set<uint256> setAlreadyDone;\r
412             for (int i = 0; i < vWorkQueue.size(); i++)\r
413             {\r
414                 uint256 hash = vWorkQueue[i];\r
415                 if (setAlreadyDone.count(hash))\r
416                     continue;\r
417                 setAlreadyDone.insert(hash);\r
418 \r
419                 CMerkleTx tx;\r
420                 if (mapWallet.count(hash))\r
421                 {\r
422                     tx = mapWallet[hash];\r
423                     foreach(const CMerkleTx& txWalletPrev, mapWallet[hash].vtxPrev)\r
424                         mapWalletPrev[txWalletPrev.GetHash()] = &txWalletPrev;\r
425                 }\r
426                 else if (mapWalletPrev.count(hash))\r
427                 {\r
428                     tx = *mapWalletPrev[hash];\r
429                 }\r
430                 else if (!fClient && txdb.ReadDiskTx(hash, tx))\r
431                 {\r
432                     ;\r
433                 }\r
434                 else\r
435                 {\r
436                     printf("ERROR: AddSupportingTransactions() : unsupported transaction\n");\r
437                     continue;\r
438                 }\r
439 \r
440                 int nDepth = tx.SetMerkleBranch();\r
441                 vtxPrev.push_back(tx);\r
442 \r
443                 if (nDepth < COPY_DEPTH)\r
444                     foreach(const CTxIn& txin, tx.vin)\r
445                         vWorkQueue.push_back(txin.prevout.hash);\r
446             }\r
447         }\r
448     }\r
449 \r
450     reverse(vtxPrev.begin(), vtxPrev.end());\r
451 }\r
452 \r
453 \r
454 \r
455 \r
456 \r
457 \r
458 \r
459 \r
460 \r
461 \r
462 \r
463 bool CTransaction::AcceptTransaction(CTxDB& txdb, bool fCheckInputs, bool* pfMissingInputs)\r
464 {\r
465     if (pfMissingInputs)\r
466         *pfMissingInputs = false;\r
467 \r
468     // Coinbase is only valid in a block, not as a loose transaction\r
469     if (IsCoinBase())\r
470         return error("AcceptTransaction() : coinbase as individual tx");\r
471 \r
472     if (!CheckTransaction())\r
473         return error("AcceptTransaction() : CheckTransaction failed");\r
474 \r
475     // To help v0.1.5 clients who would see it as negative number. please delete this later.\r
476     if (nLockTime > INT_MAX)\r
477         return error("AcceptTransaction() : not accepting nLockTime beyond 2038");\r
478 \r
479     // Do we already have it?\r
480     uint256 hash = GetHash();\r
481     CRITICAL_BLOCK(cs_mapTransactions)\r
482         if (mapTransactions.count(hash))\r
483             return false;\r
484     if (fCheckInputs)\r
485         if (txdb.ContainsTx(hash))\r
486             return false;\r
487 \r
488     // Check for conflicts with in-memory transactions\r
489     CTransaction* ptxOld = NULL;\r
490     for (int i = 0; i < vin.size(); i++)\r
491     {\r
492         COutPoint outpoint = vin[i].prevout;\r
493         if (mapNextTx.count(outpoint))\r
494         {\r
495             // Allow replacing with a newer version of the same transaction\r
496             if (i != 0)\r
497                 return false;\r
498             ptxOld = mapNextTx[outpoint].ptx;\r
499             if (!IsNewerThan(*ptxOld))\r
500                 return false;\r
501             for (int i = 0; i < vin.size(); i++)\r
502             {\r
503                 COutPoint outpoint = vin[i].prevout;\r
504                 if (!mapNextTx.count(outpoint) || mapNextTx[outpoint].ptx != ptxOld)\r
505                     return false;\r
506             }\r
507             break;\r
508         }\r
509     }\r
510 \r
511     // Check against previous transactions\r
512     map<uint256, CTxIndex> mapUnused;\r
513     int64 nFees = 0;\r
514     if (fCheckInputs && !ConnectInputs(txdb, mapUnused, CDiskTxPos(1,1,1), 0, nFees, false, false))\r
515     {\r
516         if (pfMissingInputs)\r
517             *pfMissingInputs = true;\r
518         return error("AcceptTransaction() : ConnectInputs failed %s", hash.ToString().substr(0,6).c_str());\r
519     }\r
520 \r
521     // Store transaction in memory\r
522     CRITICAL_BLOCK(cs_mapTransactions)\r
523     {\r
524         if (ptxOld)\r
525         {\r
526             printf("mapTransaction.erase(%s) replacing with new version\n", ptxOld->GetHash().ToString().c_str());\r
527             mapTransactions.erase(ptxOld->GetHash());\r
528         }\r
529         AddToMemoryPool();\r
530     }\r
531 \r
532     ///// are we sure this is ok when loading transactions or restoring block txes\r
533     // If updated, erase old tx from wallet\r
534     if (ptxOld)\r
535         EraseFromWallet(ptxOld->GetHash());\r
536 \r
537     printf("AcceptTransaction(): accepted %s\n", hash.ToString().substr(0,6).c_str());\r
538     return true;\r
539 }\r
540 \r
541 \r
542 bool CTransaction::AddToMemoryPool()\r
543 {\r
544     // Add to memory pool without checking anything.  Don't call this directly,\r
545     // call AcceptTransaction to properly check the transaction first.\r
546     CRITICAL_BLOCK(cs_mapTransactions)\r
547     {\r
548         uint256 hash = GetHash();\r
549         mapTransactions[hash] = *this;\r
550         for (int i = 0; i < vin.size(); i++)\r
551             mapNextTx[vin[i].prevout] = CInPoint(&mapTransactions[hash], i);\r
552         nTransactionsUpdated++;\r
553     }\r
554     return true;\r
555 }\r
556 \r
557 \r
558 bool CTransaction::RemoveFromMemoryPool()\r
559 {\r
560     // Remove transaction from memory pool\r
561     CRITICAL_BLOCK(cs_mapTransactions)\r
562     {\r
563         foreach(const CTxIn& txin, vin)\r
564             mapNextTx.erase(txin.prevout);\r
565         mapTransactions.erase(GetHash());\r
566         nTransactionsUpdated++;\r
567     }\r
568     return true;\r
569 }\r
570 \r
571 \r
572 \r
573 \r
574 \r
575 \r
576 int CMerkleTx::GetDepthInMainChain() const\r
577 {\r
578     if (hashBlock == 0 || nIndex == -1)\r
579         return 0;\r
580 \r
581     // Find the block it claims to be in\r
582     map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);\r
583     if (mi == mapBlockIndex.end())\r
584         return 0;\r
585     CBlockIndex* pindex = (*mi).second;\r
586     if (!pindex || !pindex->IsInMainChain())\r
587         return 0;\r
588 \r
589     // Make sure the merkle branch connects to this block\r
590     if (!fMerkleVerified)\r
591     {\r
592         if (CBlock::CheckMerkleBranch(GetHash(), vMerkleBranch, nIndex) != pindex->hashMerkleRoot)\r
593             return 0;\r
594         fMerkleVerified = true;\r
595     }\r
596 \r
597     return pindexBest->nHeight - pindex->nHeight + 1;\r
598 }\r
599 \r
600 \r
601 int CMerkleTx::GetBlocksToMaturity() const\r
602 {\r
603     if (!IsCoinBase())\r
604         return 0;\r
605     return max(0, (COINBASE_MATURITY+20) - GetDepthInMainChain());\r
606 }\r
607 \r
608 \r
609 bool CMerkleTx::AcceptTransaction(CTxDB& txdb, bool fCheckInputs)\r
610 {\r
611     if (fClient)\r
612     {\r
613         if (!IsInMainChain() && !ClientConnectInputs())\r
614             return false;\r
615         return CTransaction::AcceptTransaction(txdb, false);\r
616     }\r
617     else\r
618     {\r
619         return CTransaction::AcceptTransaction(txdb, fCheckInputs);\r
620     }\r
621 }\r
622 \r
623 \r
624 \r
625 bool CWalletTx::AcceptWalletTransaction(CTxDB& txdb, bool fCheckInputs)\r
626 {\r
627     CRITICAL_BLOCK(cs_mapTransactions)\r
628     {\r
629         foreach(CMerkleTx& tx, vtxPrev)\r
630         {\r
631             if (!tx.IsCoinBase())\r
632             {\r
633                 uint256 hash = tx.GetHash();\r
634                 if (!mapTransactions.count(hash) && !txdb.ContainsTx(hash))\r
635                     tx.AcceptTransaction(txdb, fCheckInputs);\r
636             }\r
637         }\r
638         if (!IsCoinBase())\r
639             return AcceptTransaction(txdb, fCheckInputs);\r
640     }\r
641     return true;\r
642 }\r
643 \r
644 void ReacceptWalletTransactions()\r
645 {\r
646     CTxDB txdb("r");\r
647     CRITICAL_BLOCK(cs_mapWallet)\r
648     {\r
649         foreach(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)\r
650         {\r
651             CWalletTx& wtx = item.second;\r
652             if (wtx.fSpent && wtx.IsCoinBase())\r
653                 continue;\r
654 \r
655             CTxIndex txindex;\r
656             if (txdb.ReadTxIndex(wtx.GetHash(), txindex))\r
657             {\r
658                 // Update fSpent if a tx got spent somewhere else by a copy of wallet.dat\r
659                 if (!wtx.fSpent)\r
660                 {\r
661                     if (txindex.vSpent.size() != wtx.vout.size())\r
662                     {\r
663                         printf("ERROR: ReacceptWalletTransactions() : txindex.vSpent.size() %d != wtx.vout.size() %d\n", txindex.vSpent.size(), wtx.vout.size());\r
664                         continue;\r
665                     }\r
666                     for (int i = 0; i < txindex.vSpent.size(); i++)\r
667                     {\r
668                         if (!txindex.vSpent[i].IsNull() && wtx.vout[i].IsMine())\r
669                         {\r
670                             printf("ReacceptWalletTransactions found spent coin %sbc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str());\r
671                             wtx.fSpent = true;\r
672                             wtx.WriteToDisk();\r
673                             break;\r
674                         }\r
675                     }\r
676                 }\r
677             }\r
678             else\r
679             {\r
680                 // Reaccept any txes of ours that aren't already in a block\r
681                 if (!wtx.IsCoinBase())\r
682                     wtx.AcceptWalletTransaction(txdb, false);\r
683             }\r
684         }\r
685     }\r
686 }\r
687 \r
688 \r
689 void CWalletTx::RelayWalletTransaction(CTxDB& txdb)\r
690 {\r
691     foreach(const CMerkleTx& tx, vtxPrev)\r
692     {\r
693         if (!tx.IsCoinBase())\r
694         {\r
695             uint256 hash = tx.GetHash();\r
696             if (!txdb.ContainsTx(hash))\r
697                 RelayMessage(CInv(MSG_TX, hash), (CTransaction)tx);\r
698         }\r
699     }\r
700     if (!IsCoinBase())\r
701     {\r
702         uint256 hash = GetHash();\r
703         if (!txdb.ContainsTx(hash))\r
704         {\r
705             printf("Relaying wtx %s\n", hash.ToString().substr(0,6).c_str());\r
706             RelayMessage(CInv(MSG_TX, hash), (CTransaction)*this);\r
707         }\r
708     }\r
709 }\r
710 \r
711 void RelayWalletTransactions()\r
712 {\r
713     static int64 nLastTime;\r
714     if (GetTime() - nLastTime < 10 * 60)\r
715         return;\r
716     nLastTime = GetTime();\r
717 \r
718     // Rebroadcast any of our txes that aren't in a block yet\r
719     printf("RelayWalletTransactions()\n");\r
720     CTxDB txdb("r");\r
721     CRITICAL_BLOCK(cs_mapWallet)\r
722     {\r
723         // Sort them in chronological order\r
724         multimap<unsigned int, CWalletTx*> mapSorted;\r
725         foreach(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)\r
726         {\r
727             CWalletTx& wtx = item.second;\r
728             mapSorted.insert(make_pair(wtx.nTimeReceived, &wtx));\r
729         }\r
730         foreach(PAIRTYPE(const unsigned int, CWalletTx*)& item, mapSorted)\r
731         {\r
732             CWalletTx& wtx = *item.second;\r
733             wtx.RelayWalletTransaction(txdb);\r
734         }\r
735     }\r
736 }\r
737 \r
738 \r
739 \r
740 \r
741 \r
742 \r
743 \r
744 \r
745 \r
746 \r
747 //////////////////////////////////////////////////////////////////////////////\r
748 //\r
749 // CBlock and CBlockIndex\r
750 //\r
751 \r
752 bool CBlock::ReadFromDisk(const CBlockIndex* pblockindex, bool fReadTransactions)\r
753 {\r
754     return ReadFromDisk(pblockindex->nFile, pblockindex->nBlockPos, fReadTransactions);\r
755 }\r
756 \r
757 uint256 GetOrphanRoot(const CBlock* pblock)\r
758 {\r
759     // Work back to the first block in the orphan chain\r
760     while (mapOrphanBlocks.count(pblock->hashPrevBlock))\r
761         pblock = mapOrphanBlocks[pblock->hashPrevBlock];\r
762     return pblock->GetHash();\r
763 }\r
764 \r
765 int64 CBlock::GetBlockValue(int64 nFees) const\r
766 {\r
767     int64 nSubsidy = 50 * COIN;\r
768 \r
769     // Subsidy is cut in half every 4 years\r
770     nSubsidy >>= (nBestHeight / 210000);\r
771 \r
772     return nSubsidy + nFees;\r
773 }\r
774 \r
775 unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast)\r
776 {\r
777     const unsigned int nTargetTimespan = 14 * 24 * 60 * 60; // two weeks\r
778     const unsigned int nTargetSpacing = 10 * 60;\r
779     const unsigned int nInterval = nTargetTimespan / nTargetSpacing;\r
780 \r
781     // Genesis block\r
782     if (pindexLast == NULL)\r
783         return bnProofOfWorkLimit.GetCompact();\r
784 \r
785     // Only change once per interval\r
786     if ((pindexLast->nHeight+1) % nInterval != 0)\r
787         return pindexLast->nBits;\r
788 \r
789     // Go back by what we want to be 14 days worth of blocks\r
790     const CBlockIndex* pindexFirst = pindexLast;\r
791     for (int i = 0; pindexFirst && i < nInterval-1; i++)\r
792         pindexFirst = pindexFirst->pprev;\r
793     assert(pindexFirst);\r
794 \r
795     // Limit adjustment step\r
796     unsigned int nActualTimespan = pindexLast->nTime - pindexFirst->nTime;\r
797     printf("  nActualTimespan = %d  before bounds\n", nActualTimespan);\r
798     if (nActualTimespan < nTargetTimespan/4)\r
799         nActualTimespan = nTargetTimespan/4;\r
800     if (nActualTimespan > nTargetTimespan*4)\r
801         nActualTimespan = nTargetTimespan*4;\r
802 \r
803     // Retarget\r
804     CBigNum bnNew;\r
805     bnNew.SetCompact(pindexLast->nBits);\r
806     bnNew *= nActualTimespan;\r
807     bnNew /= nTargetTimespan;\r
808 \r
809     if (bnNew > bnProofOfWorkLimit)\r
810         bnNew = bnProofOfWorkLimit;\r
811 \r
812     /// debug print\r
813     printf("GetNextWorkRequired RETARGET\n");\r
814     printf("nTargetTimespan = %d    nActualTimespan = %d\n", nTargetTimespan, nActualTimespan);\r
815     printf("Before: %08x  %s\n", pindexLast->nBits, CBigNum().SetCompact(pindexLast->nBits).getuint256().ToString().c_str());\r
816     printf("After:  %08x  %s\n", bnNew.GetCompact(), bnNew.getuint256().ToString().c_str());\r
817 \r
818     return bnNew.GetCompact();\r
819 }\r
820 \r
821 \r
822 \r
823 \r
824 \r
825 \r
826 \r
827 \r
828 \r
829 bool CTransaction::DisconnectInputs(CTxDB& txdb)\r
830 {\r
831     // Relinquish previous transactions' spent pointers\r
832     if (!IsCoinBase())\r
833     {\r
834         foreach(const CTxIn& txin, vin)\r
835         {\r
836             COutPoint prevout = txin.prevout;\r
837 \r
838             // Get prev txindex from disk\r
839             CTxIndex txindex;\r
840             if (!txdb.ReadTxIndex(prevout.hash, txindex))\r
841                 return error("DisconnectInputs() : ReadTxIndex failed");\r
842 \r
843             if (prevout.n >= txindex.vSpent.size())\r
844                 return error("DisconnectInputs() : prevout.n out of range");\r
845 \r
846             // Mark outpoint as not spent\r
847             txindex.vSpent[prevout.n].SetNull();\r
848 \r
849             // Write back\r
850             txdb.UpdateTxIndex(prevout.hash, txindex);\r
851         }\r
852     }\r
853 \r
854     // Remove transaction from index\r
855     if (!txdb.EraseTxIndex(*this))\r
856         return error("DisconnectInputs() : EraseTxPos failed");\r
857 \r
858     return true;\r
859 }\r
860 \r
861 \r
862 bool CTransaction::ConnectInputs(CTxDB& txdb, map<uint256, CTxIndex>& mapTestPool, CDiskTxPos posThisTx, int nHeight, int64& nFees, bool fBlock, bool fMiner, int64 nMinFee)\r
863 {\r
864     // Take over previous transactions' spent pointers\r
865     if (!IsCoinBase())\r
866     {\r
867         int64 nValueIn = 0;\r
868         for (int i = 0; i < vin.size(); i++)\r
869         {\r
870             COutPoint prevout = vin[i].prevout;\r
871 \r
872             // Read txindex\r
873             CTxIndex txindex;\r
874             bool fFound = true;\r
875             if (fMiner && mapTestPool.count(prevout.hash))\r
876             {\r
877                 // Get txindex from current proposed changes\r
878                 txindex = mapTestPool[prevout.hash];\r
879             }\r
880             else\r
881             {\r
882                 // Read txindex from txdb\r
883                 fFound = txdb.ReadTxIndex(prevout.hash, txindex);\r
884             }\r
885             if (!fFound && (fBlock || fMiner))\r
886                 return fMiner ? false : error("ConnectInputs() : %s prev tx %s index entry not found", GetHash().ToString().substr(0,6).c_str(),  prevout.hash.ToString().substr(0,6).c_str());\r
887 \r
888             // Read txPrev\r
889             CTransaction txPrev;\r
890             if (!fFound || txindex.pos == CDiskTxPos(1,1,1))\r
891             {\r
892                 // Get prev tx from single transactions in memory\r
893                 CRITICAL_BLOCK(cs_mapTransactions)\r
894                 {\r
895                     if (!mapTransactions.count(prevout.hash))\r
896                         return error("ConnectInputs() : %s mapTransactions prev not found %s", GetHash().ToString().substr(0,6).c_str(),  prevout.hash.ToString().substr(0,6).c_str());\r
897                     txPrev = mapTransactions[prevout.hash];\r
898                 }\r
899                 if (!fFound)\r
900                     txindex.vSpent.resize(txPrev.vout.size());\r
901             }\r
902             else\r
903             {\r
904                 // Get prev tx from disk\r
905                 if (!txPrev.ReadFromDisk(txindex.pos))\r
906                     return error("ConnectInputs() : %s ReadFromDisk prev tx %s failed", GetHash().ToString().substr(0,6).c_str(),  prevout.hash.ToString().substr(0,6).c_str());\r
907             }\r
908 \r
909             if (prevout.n >= txPrev.vout.size() || prevout.n >= txindex.vSpent.size())\r
910                 return error("ConnectInputs() : %s prevout.n out of range %d %d %d prev tx %s\n%s", GetHash().ToString().substr(0,6).c_str(), prevout.n, txPrev.vout.size(), txindex.vSpent.size(), prevout.hash.ToString().substr(0,6).c_str(), txPrev.ToString().c_str());\r
911 \r
912             // If prev is coinbase, check that it's matured\r
913             if (txPrev.IsCoinBase())\r
914                 for (CBlockIndex* pindex = pindexBest; pindex && nBestHeight - pindex->nHeight < COINBASE_MATURITY-1; pindex = pindex->pprev)\r
915                     if (pindex->nBlockPos == txindex.pos.nBlockPos && pindex->nFile == txindex.pos.nFile)\r
916                         return error("ConnectInputs() : tried to spend coinbase at depth %d", nBestHeight - pindex->nHeight);\r
917 \r
918             // Verify signature\r
919             if (!VerifySignature(txPrev, *this, i))\r
920                 return error("ConnectInputs() : %s VerifySignature failed", GetHash().ToString().substr(0,6).c_str());\r
921 \r
922             // Check for conflicts\r
923             if (!txindex.vSpent[prevout.n].IsNull())\r
924                 return fMiner ? false : error("ConnectInputs() : %s prev tx already used at %s", GetHash().ToString().substr(0,6).c_str(), txindex.vSpent[prevout.n].ToString().c_str());\r
925 \r
926             // Mark outpoints as spent\r
927             txindex.vSpent[prevout.n] = posThisTx;\r
928 \r
929             // Write back\r
930             if (fBlock)\r
931                 txdb.UpdateTxIndex(prevout.hash, txindex);\r
932             else if (fMiner)\r
933                 mapTestPool[prevout.hash] = txindex;\r
934 \r
935             nValueIn += txPrev.vout[prevout.n].nValue;\r
936         }\r
937 \r
938         // Tally transaction fees\r
939         int64 nTxFee = nValueIn - GetValueOut();\r
940         if (nTxFee < 0)\r
941             return error("ConnectInputs() : %s nTxFee < 0", GetHash().ToString().substr(0,6).c_str());\r
942         if (nTxFee < nMinFee)\r
943             return false;\r
944         nFees += nTxFee;\r
945     }\r
946 \r
947     if (fBlock)\r
948     {\r
949         // Add transaction to disk index\r
950         if (!txdb.AddTxIndex(*this, posThisTx, nHeight))\r
951             return error("ConnectInputs() : AddTxPos failed");\r
952     }\r
953     else if (fMiner)\r
954     {\r
955         // Add transaction to test pool\r
956         mapTestPool[GetHash()] = CTxIndex(CDiskTxPos(1,1,1), vout.size());\r
957     }\r
958 \r
959     return true;\r
960 }\r
961 \r
962 \r
963 bool CTransaction::ClientConnectInputs()\r
964 {\r
965     if (IsCoinBase())\r
966         return false;\r
967 \r
968     // Take over previous transactions' spent pointers\r
969     CRITICAL_BLOCK(cs_mapTransactions)\r
970     {\r
971         int64 nValueIn = 0;\r
972         for (int i = 0; i < vin.size(); i++)\r
973         {\r
974             // Get prev tx from single transactions in memory\r
975             COutPoint prevout = vin[i].prevout;\r
976             if (!mapTransactions.count(prevout.hash))\r
977                 return false;\r
978             CTransaction& txPrev = mapTransactions[prevout.hash];\r
979 \r
980             if (prevout.n >= txPrev.vout.size())\r
981                 return false;\r
982 \r
983             // Verify signature\r
984             if (!VerifySignature(txPrev, *this, i))\r
985                 return error("ConnectInputs() : VerifySignature failed");\r
986 \r
987             ///// this is redundant with the mapNextTx stuff, not sure which I want to get rid of\r
988             ///// this has to go away now that posNext is gone\r
989             // // Check for conflicts\r
990             // if (!txPrev.vout[prevout.n].posNext.IsNull())\r
991             //     return error("ConnectInputs() : prev tx already used");\r
992             //\r
993             // // Flag outpoints as used\r
994             // txPrev.vout[prevout.n].posNext = posThisTx;\r
995 \r
996             nValueIn += txPrev.vout[prevout.n].nValue;\r
997         }\r
998         if (GetValueOut() > nValueIn)\r
999             return false;\r
1000     }\r
1001 \r
1002     return true;\r
1003 }\r
1004 \r
1005 \r
1006 \r
1007 \r
1008 bool CBlock::DisconnectBlock(CTxDB& txdb, CBlockIndex* pindex)\r
1009 {\r
1010     // Disconnect in reverse order\r
1011     for (int i = vtx.size()-1; i >= 0; i--)\r
1012         if (!vtx[i].DisconnectInputs(txdb))\r
1013             return false;\r
1014 \r
1015     // Update block index on disk without changing it in memory.\r
1016     // The memory index structure will be changed after the db commits.\r
1017     if (pindex->pprev)\r
1018     {\r
1019         CDiskBlockIndex blockindexPrev(pindex->pprev);\r
1020         blockindexPrev.hashNext = 0;\r
1021         txdb.WriteBlockIndex(blockindexPrev);\r
1022     }\r
1023 \r
1024     return true;\r
1025 }\r
1026 \r
1027 bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex)\r
1028 {\r
1029     //// issue here: it doesn't know the version\r
1030     unsigned int nTxPos = pindex->nBlockPos + ::GetSerializeSize(CBlock(), SER_DISK) - 1 + GetSizeOfCompactSize(vtx.size());\r
1031 \r
1032     map<uint256, CTxIndex> mapUnused;\r
1033     int64 nFees = 0;\r
1034     foreach(CTransaction& tx, vtx)\r
1035     {\r
1036         CDiskTxPos posThisTx(pindex->nFile, pindex->nBlockPos, nTxPos);\r
1037         nTxPos += ::GetSerializeSize(tx, SER_DISK);\r
1038 \r
1039         if (!tx.ConnectInputs(txdb, mapUnused, posThisTx, pindex->nHeight, nFees, true, false))\r
1040             return false;\r
1041     }\r
1042 \r
1043     if (vtx[0].GetValueOut() > GetBlockValue(nFees))\r
1044         return false;\r
1045 \r
1046     // Update block index on disk without changing it in memory.\r
1047     // The memory index structure will be changed after the db commits.\r
1048     if (pindex->pprev)\r
1049     {\r
1050         CDiskBlockIndex blockindexPrev(pindex->pprev);\r
1051         blockindexPrev.hashNext = pindex->GetBlockHash();\r
1052         txdb.WriteBlockIndex(blockindexPrev);\r
1053     }\r
1054 \r
1055     // Watch for transactions paying to me\r
1056     foreach(CTransaction& tx, vtx)\r
1057         AddToWalletIfMine(tx, this);\r
1058 \r
1059     return true;\r
1060 }\r
1061 \r
1062 \r
1063 \r
1064 bool Reorganize(CTxDB& txdb, CBlockIndex* pindexNew)\r
1065 {\r
1066     printf("REORGANIZE\n");\r
1067 \r
1068     // Find the fork\r
1069     CBlockIndex* pfork = pindexBest;\r
1070     CBlockIndex* plonger = pindexNew;\r
1071     while (pfork != plonger)\r
1072     {\r
1073         if (!(pfork = pfork->pprev))\r
1074             return error("Reorganize() : pfork->pprev is null");\r
1075         while (plonger->nHeight > pfork->nHeight)\r
1076             if (!(plonger = plonger->pprev))\r
1077                 return error("Reorganize() : plonger->pprev is null");\r
1078     }\r
1079 \r
1080     // List of what to disconnect\r
1081     vector<CBlockIndex*> vDisconnect;\r
1082     for (CBlockIndex* pindex = pindexBest; pindex != pfork; pindex = pindex->pprev)\r
1083         vDisconnect.push_back(pindex);\r
1084 \r
1085     // List of what to connect\r
1086     vector<CBlockIndex*> vConnect;\r
1087     for (CBlockIndex* pindex = pindexNew; pindex != pfork; pindex = pindex->pprev)\r
1088         vConnect.push_back(pindex);\r
1089     reverse(vConnect.begin(), vConnect.end());\r
1090 \r
1091     // Disconnect shorter branch\r
1092     vector<CTransaction> vResurrect;\r
1093     foreach(CBlockIndex* pindex, vDisconnect)\r
1094     {\r
1095         CBlock block;\r
1096         if (!block.ReadFromDisk(pindex->nFile, pindex->nBlockPos))\r
1097             return error("Reorganize() : ReadFromDisk for disconnect failed");\r
1098         if (!block.DisconnectBlock(txdb, pindex))\r
1099             return error("Reorganize() : DisconnectBlock failed");\r
1100 \r
1101         // Queue memory transactions to resurrect\r
1102         foreach(const CTransaction& tx, block.vtx)\r
1103             if (!tx.IsCoinBase())\r
1104                 vResurrect.push_back(tx);\r
1105     }\r
1106 \r
1107     // Connect longer branch\r
1108     vector<CTransaction> vDelete;\r
1109     for (int i = 0; i < vConnect.size(); i++)\r
1110     {\r
1111         CBlockIndex* pindex = vConnect[i];\r
1112         CBlock block;\r
1113         if (!block.ReadFromDisk(pindex->nFile, pindex->nBlockPos))\r
1114             return error("Reorganize() : ReadFromDisk for connect failed");\r
1115         if (!block.ConnectBlock(txdb, pindex))\r
1116         {\r
1117             // Invalid block, delete the rest of this branch\r
1118             txdb.TxnAbort();\r
1119             for (int j = i; j < vConnect.size(); j++)\r
1120             {\r
1121                 CBlockIndex* pindex = vConnect[j];\r
1122                 pindex->EraseBlockFromDisk();\r
1123                 txdb.EraseBlockIndex(pindex->GetBlockHash());\r
1124                 mapBlockIndex.erase(pindex->GetBlockHash());\r
1125                 delete pindex;\r
1126             }\r
1127             return error("Reorganize() : ConnectBlock failed");\r
1128         }\r
1129 \r
1130         // Queue memory transactions to delete\r
1131         foreach(const CTransaction& tx, block.vtx)\r
1132             vDelete.push_back(tx);\r
1133     }\r
1134     if (!txdb.WriteHashBestChain(pindexNew->GetBlockHash()))\r
1135         return error("Reorganize() : WriteHashBestChain failed");\r
1136 \r
1137     // Commit now because resurrecting could take some time\r
1138     txdb.TxnCommit();\r
1139 \r
1140     // Disconnect shorter branch\r
1141     foreach(CBlockIndex* pindex, vDisconnect)\r
1142         if (pindex->pprev)\r
1143             pindex->pprev->pnext = NULL;\r
1144 \r
1145     // Connect longer branch\r
1146     foreach(CBlockIndex* pindex, vConnect)\r
1147         if (pindex->pprev)\r
1148             pindex->pprev->pnext = pindex;\r
1149 \r
1150     // Resurrect memory transactions that were in the disconnected branch\r
1151     foreach(CTransaction& tx, vResurrect)\r
1152         tx.AcceptTransaction(txdb, false);\r
1153 \r
1154     // Delete redundant memory transactions that are in the connected branch\r
1155     foreach(CTransaction& tx, vDelete)\r
1156         tx.RemoveFromMemoryPool();\r
1157 \r
1158     return true;\r
1159 }\r
1160 \r
1161 \r
1162 bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos)\r
1163 {\r
1164     // Check for duplicate\r
1165     uint256 hash = GetHash();\r
1166     if (mapBlockIndex.count(hash))\r
1167         return error("AddToBlockIndex() : %s already exists", hash.ToString().substr(0,16).c_str());\r
1168 \r
1169     // Construct new block index object\r
1170     CBlockIndex* pindexNew = new CBlockIndex(nFile, nBlockPos, *this);\r
1171     if (!pindexNew)\r
1172         return error("AddToBlockIndex() : new CBlockIndex failed");\r
1173     map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first;\r
1174     pindexNew->phashBlock = &((*mi).first);\r
1175     map<uint256, CBlockIndex*>::iterator miPrev = mapBlockIndex.find(hashPrevBlock);\r
1176     if (miPrev != mapBlockIndex.end())\r
1177     {\r
1178         pindexNew->pprev = (*miPrev).second;\r
1179         pindexNew->nHeight = pindexNew->pprev->nHeight + 1;\r
1180     }\r
1181 \r
1182     CTxDB txdb;\r
1183     txdb.TxnBegin();\r
1184     txdb.WriteBlockIndex(CDiskBlockIndex(pindexNew));\r
1185 \r
1186     // New best\r
1187     if (pindexNew->nHeight > nBestHeight)\r
1188     {\r
1189         if (pindexGenesisBlock == NULL && hash == hashGenesisBlock)\r
1190         {\r
1191             pindexGenesisBlock = pindexNew;\r
1192             txdb.WriteHashBestChain(hash);\r
1193         }\r
1194         else if (hashPrevBlock == hashBestChain)\r
1195         {\r
1196             // Adding to current best branch\r
1197             if (!ConnectBlock(txdb, pindexNew) || !txdb.WriteHashBestChain(hash))\r
1198             {\r
1199                 txdb.TxnAbort();\r
1200                 pindexNew->EraseBlockFromDisk();\r
1201                 mapBlockIndex.erase(pindexNew->GetBlockHash());\r
1202                 delete pindexNew;\r
1203                 return error("AddToBlockIndex() : ConnectBlock failed");\r
1204             }\r
1205             txdb.TxnCommit();\r
1206             pindexNew->pprev->pnext = pindexNew;\r
1207 \r
1208             // Delete redundant memory transactions\r
1209             foreach(CTransaction& tx, vtx)\r
1210                 tx.RemoveFromMemoryPool();\r
1211         }\r
1212         else\r
1213         {\r
1214             // New best branch\r
1215             if (!Reorganize(txdb, pindexNew))\r
1216             {\r
1217                 txdb.TxnAbort();\r
1218                 return error("AddToBlockIndex() : Reorganize failed");\r
1219             }\r
1220         }\r
1221 \r
1222         // New best link\r
1223         hashBestChain = hash;\r
1224         pindexBest = pindexNew;\r
1225         nBestHeight = pindexBest->nHeight;\r
1226         nTransactionsUpdated++;\r
1227         printf("AddToBlockIndex: new best=%s  height=%d\n", hashBestChain.ToString().substr(0,16).c_str(), nBestHeight);\r
1228     }\r
1229 \r
1230     txdb.TxnCommit();\r
1231     txdb.Close();\r
1232 \r
1233     if (pindexNew == pindexBest)\r
1234     {\r
1235         // Relay wallet transactions that haven't gotten in yet\r
1236         RelayWalletTransactions();\r
1237 \r
1238         // Notify UI to display prev block's coinbase if it was ours\r
1239         static uint256 hashPrevBestCoinBase;\r
1240         CRITICAL_BLOCK(cs_mapWallet)\r
1241             vWalletUpdated.push_back(hashPrevBestCoinBase);\r
1242         hashPrevBestCoinBase = vtx[0].GetHash();\r
1243     }\r
1244 \r
1245     MainFrameRepaint();\r
1246     return true;\r
1247 }\r
1248 \r
1249 \r
1250 \r
1251 \r
1252 bool CBlock::CheckBlock() const\r
1253 {\r
1254     // These are checks that are independent of context\r
1255     // that can be verified before saving an orphan block.\r
1256 \r
1257     // Size limits\r
1258     if (vtx.empty() || vtx.size() > MAX_SIZE || ::GetSerializeSize(*this, SER_DISK) > MAX_SIZE)\r
1259         return error("CheckBlock() : size limits failed");\r
1260 \r
1261     // Check timestamp\r
1262     if (nTime > GetAdjustedTime() + 2 * 60 * 60)\r
1263         return error("CheckBlock() : block timestamp too far in the future");\r
1264 \r
1265     // First transaction must be coinbase, the rest must not be\r
1266     if (vtx.empty() || !vtx[0].IsCoinBase())\r
1267         return error("CheckBlock() : first tx is not coinbase");\r
1268     for (int i = 1; i < vtx.size(); i++)\r
1269         if (vtx[i].IsCoinBase())\r
1270             return error("CheckBlock() : more than one coinbase");\r
1271 \r
1272     // Check transactions\r
1273     foreach(const CTransaction& tx, vtx)\r
1274         if (!tx.CheckTransaction())\r
1275             return error("CheckBlock() : CheckTransaction failed");\r
1276 \r
1277     // Check proof of work matches claimed amount\r
1278     if (CBigNum().SetCompact(nBits) > bnProofOfWorkLimit)\r
1279         return error("CheckBlock() : nBits below minimum work");\r
1280     if (GetHash() > CBigNum().SetCompact(nBits).getuint256())\r
1281         return error("CheckBlock() : hash doesn't match nBits");\r
1282 \r
1283     // Check merkleroot\r
1284     if (hashMerkleRoot != BuildMerkleTree())\r
1285         return error("CheckBlock() : hashMerkleRoot mismatch");\r
1286 \r
1287     return true;\r
1288 }\r
1289 \r
1290 bool CBlock::AcceptBlock()\r
1291 {\r
1292     // Check for duplicate\r
1293     uint256 hash = GetHash();\r
1294     if (mapBlockIndex.count(hash))\r
1295         return error("AcceptBlock() : block already in mapBlockIndex");\r
1296 \r
1297     // Get prev block index\r
1298     map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashPrevBlock);\r
1299     if (mi == mapBlockIndex.end())\r
1300         return error("AcceptBlock() : prev block not found");\r
1301     CBlockIndex* pindexPrev = (*mi).second;\r
1302 \r
1303     // Check timestamp against prev\r
1304     if (nTime <= pindexPrev->GetMedianTimePast())\r
1305         return error("AcceptBlock() : block's timestamp is too early");\r
1306 \r
1307     // Check that all transactions are finalized (starting around Mar 2010)\r
1308     if (nBestHeight > 36000)\r
1309         foreach(const CTransaction& tx, vtx)\r
1310             if (!tx.IsFinal(nTime))\r
1311                 return error("AcceptBlock() : contains a non-final transaction");\r
1312 \r
1313     // Check proof of work\r
1314     if (nBits != GetNextWorkRequired(pindexPrev))\r
1315         return error("AcceptBlock() : incorrect proof of work");\r
1316 \r
1317     // Write block to history file\r
1318     if (!CheckDiskSpace(::GetSerializeSize(*this, SER_DISK)))\r
1319         return error("AcceptBlock() : out of disk space");\r
1320     unsigned int nFile;\r
1321     unsigned int nBlockPos;\r
1322     if (!WriteToDisk(!fClient, nFile, nBlockPos))\r
1323         return error("AcceptBlock() : WriteToDisk failed");\r
1324     if (!AddToBlockIndex(nFile, nBlockPos))\r
1325         return error("AcceptBlock() : AddToBlockIndex failed");\r
1326 \r
1327     if (hashBestChain == hash && nBestHeight > 28000)\r
1328         RelayInventory(CInv(MSG_BLOCK, hash));\r
1329 \r
1330     // // Add atoms to user reviews for coins created\r
1331     // vector<unsigned char> vchPubKey;\r
1332     // if (ExtractPubKey(vtx[0].vout[0].scriptPubKey, false, vchPubKey))\r
1333     // {\r
1334     //     unsigned short nAtom = GetRand(USHRT_MAX - 100) + 100;\r
1335     //     vector<unsigned short> vAtoms(1, nAtom);\r
1336     //     AddAtomsAndPropagate(Hash(vchPubKey.begin(), vchPubKey.end()), vAtoms, true);\r
1337     // }\r
1338 \r
1339     return true;\r
1340 }\r
1341 \r
1342 bool ProcessBlock(CNode* pfrom, CBlock* pblock)\r
1343 {\r
1344     // Check for duplicate\r
1345     uint256 hash = pblock->GetHash();\r
1346     if (mapBlockIndex.count(hash))\r
1347         return error("ProcessBlock() : already have block %d %s", mapBlockIndex[hash]->nHeight, hash.ToString().substr(0,16).c_str());\r
1348     if (mapOrphanBlocks.count(hash))\r
1349         return error("ProcessBlock() : already have block (orphan) %s", hash.ToString().substr(0,16).c_str());\r
1350 \r
1351     // Preliminary checks\r
1352     if (!pblock->CheckBlock())\r
1353     {\r
1354         delete pblock;\r
1355         return error("ProcessBlock() : CheckBlock FAILED");\r
1356     }\r
1357 \r
1358     // If don't already have its previous block, shunt it off to holding area until we get it\r
1359     if (!mapBlockIndex.count(pblock->hashPrevBlock))\r
1360     {\r
1361         printf("ProcessBlock: ORPHAN BLOCK, prev=%s\n", pblock->hashPrevBlock.ToString().substr(0,16).c_str());\r
1362         mapOrphanBlocks.insert(make_pair(hash, pblock));\r
1363         mapOrphanBlocksByPrev.insert(make_pair(pblock->hashPrevBlock, pblock));\r
1364 \r
1365         // Ask this guy to fill in what we're missing\r
1366         if (pfrom)\r
1367             pfrom->PushGetBlocks(pindexBest, GetOrphanRoot(pblock));\r
1368         return true;\r
1369     }\r
1370 \r
1371     // Store to disk\r
1372     if (!pblock->AcceptBlock())\r
1373     {\r
1374         delete pblock;\r
1375         return error("ProcessBlock() : AcceptBlock FAILED");\r
1376     }\r
1377     delete pblock;\r
1378 \r
1379     // Recursively process any orphan blocks that depended on this one\r
1380     vector<uint256> vWorkQueue;\r
1381     vWorkQueue.push_back(hash);\r
1382     for (int i = 0; i < vWorkQueue.size(); i++)\r
1383     {\r
1384         uint256 hashPrev = vWorkQueue[i];\r
1385         for (multimap<uint256, CBlock*>::iterator mi = mapOrphanBlocksByPrev.lower_bound(hashPrev);\r
1386              mi != mapOrphanBlocksByPrev.upper_bound(hashPrev);\r
1387              ++mi)\r
1388         {\r
1389             CBlock* pblockOrphan = (*mi).second;\r
1390             if (pblockOrphan->AcceptBlock())\r
1391                 vWorkQueue.push_back(pblockOrphan->GetHash());\r
1392             mapOrphanBlocks.erase(pblockOrphan->GetHash());\r
1393             delete pblockOrphan;\r
1394         }\r
1395         mapOrphanBlocksByPrev.erase(hashPrev);\r
1396     }\r
1397 \r
1398     printf("ProcessBlock: ACCEPTED\n");\r
1399     return true;\r
1400 }\r
1401 \r
1402 \r
1403 \r
1404 \r
1405 \r
1406 \r
1407 \r
1408 \r
1409 template<typename Stream>\r
1410 bool ScanMessageStart(Stream& s)\r
1411 {\r
1412     // Scan ahead to the next pchMessageStart, which should normally be immediately\r
1413     // at the file pointer.  Leaves file pointer at end of pchMessageStart.\r
1414     s.clear(0);\r
1415     short prevmask = s.exceptions(0);\r
1416     const char* p = BEGIN(pchMessageStart);\r
1417     try\r
1418     {\r
1419         loop\r
1420         {\r
1421             char c;\r
1422             s.read(&c, 1);\r
1423             if (s.fail())\r
1424             {\r
1425                 s.clear(0);\r
1426                 s.exceptions(prevmask);\r
1427                 return false;\r
1428             }\r
1429             if (*p != c)\r
1430                 p = BEGIN(pchMessageStart);\r
1431             if (*p == c)\r
1432             {\r
1433                 if (++p == END(pchMessageStart))\r
1434                 {\r
1435                     s.clear(0);\r
1436                     s.exceptions(prevmask);\r
1437                     return true;\r
1438                 }\r
1439             }\r
1440         }\r
1441     }\r
1442     catch (...)\r
1443     {\r
1444         s.clear(0);\r
1445         s.exceptions(prevmask);\r
1446         return false;\r
1447     }\r
1448 }\r
1449 \r
1450 bool CheckDiskSpace(int64 nAdditionalBytes)\r
1451 {\r
1452 #ifdef __WXMSW__\r
1453     uint64 nFreeBytesAvailable = 0;     // bytes available to caller\r
1454     uint64 nTotalNumberOfBytes = 0;     // bytes on disk\r
1455     uint64 nTotalNumberOfFreeBytes = 0; // free bytes on disk\r
1456     if (!GetDiskFreeSpaceEx(GetDataDir().c_str(),\r
1457             (PULARGE_INTEGER)&nFreeBytesAvailable,\r
1458             (PULARGE_INTEGER)&nTotalNumberOfBytes,\r
1459             (PULARGE_INTEGER)&nTotalNumberOfFreeBytes))\r
1460     {\r
1461         printf("ERROR: GetDiskFreeSpaceEx() failed\n");\r
1462         return true;\r
1463     }\r
1464 #else\r
1465     uint64 nFreeBytesAvailable = filesystem::space(GetDataDir()).available;\r
1466 #endif\r
1467 \r
1468     // Check for 15MB because database could create another 10MB log file at any time\r
1469     if (nFreeBytesAvailable < (int64)15000000 + nAdditionalBytes)\r
1470     {\r
1471         fShutdown = true;\r
1472         ThreadSafeMessageBox("Warning: Your disk space is low  ", "Bitcoin", wxOK | wxICON_EXCLAMATION);\r
1473         CreateThread(Shutdown, NULL);\r
1474         return false;\r
1475     }\r
1476     return true;\r
1477 }\r
1478 \r
1479 FILE* OpenBlockFile(unsigned int nFile, unsigned int nBlockPos, const char* pszMode)\r
1480 {\r
1481     if (nFile == -1)\r
1482         return NULL;\r
1483     FILE* file = fopen(strprintf("%s/blk%04d.dat", GetDataDir().c_str(), nFile).c_str(), pszMode);\r
1484     if (!file)\r
1485         return NULL;\r
1486     if (nBlockPos != 0 && !strchr(pszMode, 'a') && !strchr(pszMode, 'w'))\r
1487     {\r
1488         if (fseek(file, nBlockPos, SEEK_SET) != 0)\r
1489         {\r
1490             fclose(file);\r
1491             return NULL;\r
1492         }\r
1493     }\r
1494     return file;\r
1495 }\r
1496 \r
1497 static unsigned int nCurrentBlockFile = 1;\r
1498 \r
1499 FILE* AppendBlockFile(unsigned int& nFileRet)\r
1500 {\r
1501     nFileRet = 0;\r
1502     loop\r
1503     {\r
1504         FILE* file = OpenBlockFile(nCurrentBlockFile, 0, "ab");\r
1505         if (!file)\r
1506             return NULL;\r
1507         if (fseek(file, 0, SEEK_END) != 0)\r
1508             return NULL;\r
1509         // FAT32 filesize max 4GB, fseek and ftell max 2GB, so we must stay under 2GB\r
1510         if (ftell(file) < 0x7F000000 - MAX_SIZE)\r
1511         {\r
1512             nFileRet = nCurrentBlockFile;\r
1513             return file;\r
1514         }\r
1515         fclose(file);\r
1516         nCurrentBlockFile++;\r
1517     }\r
1518 }\r
1519 \r
1520 bool LoadBlockIndex(bool fAllowNew)\r
1521 {\r
1522     //\r
1523     // Load block index\r
1524     //\r
1525     CTxDB txdb("cr");\r
1526     if (!txdb.LoadBlockIndex())\r
1527         return false;\r
1528     txdb.Close();\r
1529 \r
1530     //\r
1531     // Init with genesis block\r
1532     //\r
1533     if (mapBlockIndex.empty())\r
1534     {\r
1535         if (!fAllowNew)\r
1536             return false;\r
1537 \r
1538 \r
1539         // Genesis Block:\r
1540         // GetHash()      = 0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f\r
1541         // hashMerkleRoot = 0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b\r
1542         // txNew.vin[0].scriptSig     = 486604799 4 0x736B6E616220726F662074756F6C69616220646E6F63657320666F206B6E697262206E6F20726F6C6C65636E61684320393030322F6E614A2F33302073656D695420656854\r
1543         // txNew.vout[0].nValue       = 5000000000\r
1544         // txNew.vout[0].scriptPubKey = 0x5F1DF16B2B704C8A578D0BBAF74D385CDE12C11EE50455F3C438EF4C3FBCF649B6DE611FEAE06279A60939E028A8D65C10B73071A6F16719274855FEB0FD8A6704 OP_CHECKSIG\r
1545         // block.nVersion = 1\r
1546         // block.nTime    = 1231006505\r
1547         // block.nBits    = 0x1d00ffff\r
1548         // block.nNonce   = 2083236893\r
1549         // CBlock(hash=000000000019d6, ver=1, hashPrevBlock=00000000000000, hashMerkleRoot=4a5e1e, nTime=1231006505, nBits=1d00ffff, nNonce=2083236893, vtx=1)\r
1550         //   CTransaction(hash=4a5e1e, ver=1, vin.size=1, vout.size=1, nLockTime=0)\r
1551         //     CTxIn(COutPoint(000000, -1), coinbase 04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73)\r
1552         //     CTxOut(nValue=50.00000000, scriptPubKey=0x5F1DF16B2B704C8A578D0B)\r
1553         //   vMerkleTree: 4a5e1e\r
1554 \r
1555         // Genesis block\r
1556         const char* pszTimestamp = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks";\r
1557         CTransaction txNew;\r
1558         txNew.vin.resize(1);\r
1559         txNew.vout.resize(1);\r
1560         txNew.vin[0].scriptSig     = CScript() << 486604799 << CBigNum(4) << vector<unsigned char>((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp));\r
1561         txNew.vout[0].nValue       = 50 * COIN;\r
1562         txNew.vout[0].scriptPubKey = CScript() << CBigNum("0x5F1DF16B2B704C8A578D0BBAF74D385CDE12C11EE50455F3C438EF4C3FBCF649B6DE611FEAE06279A60939E028A8D65C10B73071A6F16719274855FEB0FD8A6704") << OP_CHECKSIG;\r
1563         CBlock block;\r
1564         block.vtx.push_back(txNew);\r
1565         block.hashPrevBlock = 0;\r
1566         block.hashMerkleRoot = block.BuildMerkleTree();\r
1567         block.nVersion = 1;\r
1568         block.nTime    = 1231006505;\r
1569         block.nBits    = 0x1d00ffff;\r
1570         block.nNonce   = 2083236893;\r
1571 \r
1572             //// debug print\r
1573             printf("%s\n", block.GetHash().ToString().c_str());\r
1574             printf("%s\n", block.hashMerkleRoot.ToString().c_str());\r
1575             printf("%s\n", hashGenesisBlock.ToString().c_str());\r
1576             txNew.vout[0].scriptPubKey.print();\r
1577             block.print();\r
1578             assert(block.hashMerkleRoot == uint256("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));\r
1579 \r
1580         assert(block.GetHash() == hashGenesisBlock);\r
1581 \r
1582         // Start new block file\r
1583         unsigned int nFile;\r
1584         unsigned int nBlockPos;\r
1585         if (!block.WriteToDisk(!fClient, nFile, nBlockPos))\r
1586             return error("LoadBlockIndex() : writing genesis block to disk failed");\r
1587         if (!block.AddToBlockIndex(nFile, nBlockPos))\r
1588             return error("LoadBlockIndex() : genesis block not accepted");\r
1589     }\r
1590 \r
1591     return true;\r
1592 }\r
1593 \r
1594 \r
1595 \r
1596 void PrintBlockTree()\r
1597 {\r
1598     // precompute tree structure\r
1599     map<CBlockIndex*, vector<CBlockIndex*> > mapNext;\r
1600     for (map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.begin(); mi != mapBlockIndex.end(); ++mi)\r
1601     {\r
1602         CBlockIndex* pindex = (*mi).second;\r
1603         mapNext[pindex->pprev].push_back(pindex);\r
1604         // test\r
1605         //while (rand() % 3 == 0)\r
1606         //    mapNext[pindex->pprev].push_back(pindex);\r
1607     }\r
1608 \r
1609     vector<pair<int, CBlockIndex*> > vStack;\r
1610     vStack.push_back(make_pair(0, pindexGenesisBlock));\r
1611 \r
1612     int nPrevCol = 0;\r
1613     while (!vStack.empty())\r
1614     {\r
1615         int nCol = vStack.back().first;\r
1616         CBlockIndex* pindex = vStack.back().second;\r
1617         vStack.pop_back();\r
1618 \r
1619         // print split or gap\r
1620         if (nCol > nPrevCol)\r
1621         {\r
1622             for (int i = 0; i < nCol-1; i++)\r
1623                 printf("| ");\r
1624             printf("|\\\n");\r
1625         }\r
1626         else if (nCol < nPrevCol)\r
1627         {\r
1628             for (int i = 0; i < nCol; i++)\r
1629                 printf("| ");\r
1630             printf("|\n");\r
1631         }\r
1632         nPrevCol = nCol;\r
1633 \r
1634         // print columns\r
1635         for (int i = 0; i < nCol; i++)\r
1636             printf("| ");\r
1637 \r
1638         // print item\r
1639         CBlock block;\r
1640         block.ReadFromDisk(pindex);\r
1641         printf("%d (%u,%u) %s  %s  tx %d",\r
1642             pindex->nHeight,\r
1643             pindex->nFile,\r
1644             pindex->nBlockPos,\r
1645             block.GetHash().ToString().substr(0,16).c_str(),\r
1646             DateTimeStrFormat("%x %H:%M:%S", block.nTime).c_str(),\r
1647             block.vtx.size());\r
1648 \r
1649         CRITICAL_BLOCK(cs_mapWallet)\r
1650         {\r
1651             if (mapWallet.count(block.vtx[0].GetHash()))\r
1652             {\r
1653                 CWalletTx& wtx = mapWallet[block.vtx[0].GetHash()];\r
1654                 printf("    mine:  %d  %d  %d", wtx.GetDepthInMainChain(), wtx.GetBlocksToMaturity(), wtx.GetCredit());\r
1655             }\r
1656         }\r
1657         printf("\n");\r
1658 \r
1659 \r
1660         // put the main timechain first\r
1661         vector<CBlockIndex*>& vNext = mapNext[pindex];\r
1662         for (int i = 0; i < vNext.size(); i++)\r
1663         {\r
1664             if (vNext[i]->pnext)\r
1665             {\r
1666                 swap(vNext[0], vNext[i]);\r
1667                 break;\r
1668             }\r
1669         }\r
1670 \r
1671         // iterate children\r
1672         for (int i = 0; i < vNext.size(); i++)\r
1673             vStack.push_back(make_pair(nCol+i, vNext[i]));\r
1674     }\r
1675 }\r
1676 \r
1677 \r
1678 \r
1679 \r
1680 \r
1681 \r
1682 \r
1683 \r
1684 \r
1685 \r
1686 //////////////////////////////////////////////////////////////////////////////\r
1687 //\r
1688 // Messages\r
1689 //\r
1690 \r
1691 \r
1692 bool AlreadyHave(CTxDB& txdb, const CInv& inv)\r
1693 {\r
1694     switch (inv.type)\r
1695     {\r
1696     case MSG_TX:        return mapTransactions.count(inv.hash) || txdb.ContainsTx(inv.hash);\r
1697     case MSG_BLOCK:     return mapBlockIndex.count(inv.hash) || mapOrphanBlocks.count(inv.hash);\r
1698     case MSG_REVIEW:    return true;\r
1699     case MSG_PRODUCT:   return mapProducts.count(inv.hash);\r
1700     }\r
1701     // Don't know what it is, just say we already got one\r
1702     return true;\r
1703 }\r
1704 \r
1705 \r
1706 \r
1707 \r
1708 \r
1709 \r
1710 \r
1711 bool ProcessMessages(CNode* pfrom)\r
1712 {\r
1713     CDataStream& vRecv = pfrom->vRecv;\r
1714     if (vRecv.empty())\r
1715         return true;\r
1716     //if (fDebug)\r
1717     //    printf("ProcessMessages(%d bytes)\n", vRecv.size());\r
1718 \r
1719     //\r
1720     // Message format\r
1721     //  (4) message start\r
1722     //  (12) command\r
1723     //  (4) size\r
1724     //  (x) data\r
1725     //\r
1726 \r
1727     loop\r
1728     {\r
1729         // Scan for message start\r
1730         CDataStream::iterator pstart = search(vRecv.begin(), vRecv.end(), BEGIN(pchMessageStart), END(pchMessageStart));\r
1731         if (vRecv.end() - pstart < sizeof(CMessageHeader))\r
1732         {\r
1733             if (vRecv.size() > sizeof(CMessageHeader))\r
1734             {\r
1735                 printf("\n\nPROCESSMESSAGE MESSAGESTART NOT FOUND\n\n");\r
1736                 vRecv.erase(vRecv.begin(), vRecv.end() - sizeof(CMessageHeader));\r
1737             }\r
1738             break;\r
1739         }\r
1740         if (pstart - vRecv.begin() > 0)\r
1741             printf("\n\nPROCESSMESSAGE SKIPPED %d BYTES\n\n", pstart - vRecv.begin());\r
1742         vRecv.erase(vRecv.begin(), pstart);\r
1743 \r
1744         // Read header\r
1745         CMessageHeader hdr;\r
1746         vRecv >> hdr;\r
1747         if (!hdr.IsValid())\r
1748         {\r
1749             printf("\n\nPROCESSMESSAGE: ERRORS IN HEADER %s\n\n\n", hdr.GetCommand().c_str());\r
1750             continue;\r
1751         }\r
1752         string strCommand = hdr.GetCommand();\r
1753 \r
1754         // Message size\r
1755         unsigned int nMessageSize = hdr.nMessageSize;\r
1756         if (nMessageSize > vRecv.size())\r
1757         {\r
1758             // Rewind and wait for rest of message\r
1759             ///// need a mechanism to give up waiting for overlong message size error\r
1760             //if (fDebug)\r
1761             //    printf("message-break\n");\r
1762             vRecv.insert(vRecv.begin(), BEGIN(hdr), END(hdr));\r
1763             Sleep(100);\r
1764             break;\r
1765         }\r
1766 \r
1767         // Copy message to its own buffer\r
1768         CDataStream vMsg(vRecv.begin(), vRecv.begin() + nMessageSize, vRecv.nType, vRecv.nVersion);\r
1769         vRecv.ignore(nMessageSize);\r
1770 \r
1771         // Process message\r
1772         bool fRet = false;\r
1773         try\r
1774         {\r
1775             CRITICAL_BLOCK(cs_main)\r
1776                 fRet = ProcessMessage(pfrom, strCommand, vMsg);\r
1777             if (fShutdown)\r
1778                 return true;\r
1779         }\r
1780         catch (std::ios_base::failure& e)\r
1781         {\r
1782             if (strstr(e.what(), "CDataStream::read() : end of data"))\r
1783             {\r
1784                 // Allow exceptions from underlength message on vRecv\r
1785                 printf("ProcessMessage(%s, %d bytes) : Exception '%s' caught, normally caused by a message being shorter than its stated length\n", strCommand.c_str(), nMessageSize, e.what());\r
1786             }\r
1787             else if (strstr(e.what(), ": size too large"))\r
1788             {\r
1789                 // Allow exceptions from overlong size\r
1790                 printf("ProcessMessage(%s, %d bytes) : Exception '%s' caught\n", strCommand.c_str(), nMessageSize, e.what());\r
1791             }\r
1792             else\r
1793             {\r
1794                 PrintException(&e, "ProcessMessage()");\r
1795             }\r
1796         }\r
1797         catch (std::exception& e) {\r
1798             PrintException(&e, "ProcessMessage()");\r
1799         } catch (...) {\r
1800             PrintException(NULL, "ProcessMessage()");\r
1801         }\r
1802 \r
1803         if (!fRet)\r
1804             printf("ProcessMessage(%s, %d bytes) FAILED\n", strCommand.c_str(), nMessageSize);\r
1805     }\r
1806 \r
1807     vRecv.Compact();\r
1808     return true;\r
1809 }\r
1810 \r
1811 \r
1812 \r
1813 \r
1814 bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)\r
1815 {\r
1816     static map<unsigned int, vector<unsigned char> > mapReuseKey;\r
1817     RandAddSeedPerfmon();\r
1818     if (fDebug)\r
1819         printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());\r
1820     printf("received: %s (%d bytes)\n", strCommand.c_str(), vRecv.size());\r
1821     if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0)\r
1822     {\r
1823         printf("dropmessagestest DROPPING RECV MESSAGE\n");\r
1824         return true;\r
1825     }\r
1826 \r
1827 \r
1828 \r
1829 \r
1830 \r
1831     if (strCommand == "version")\r
1832     {\r
1833         // Each connection can only send one version message\r
1834         if (pfrom->nVersion != 0)\r
1835             return false;\r
1836 \r
1837         int64 nTime;\r
1838         CAddress addrMe;\r
1839         CAddress addrFrom;\r
1840         uint64 nNonce = 1;\r
1841         string strSubVer;\r
1842         vRecv >> pfrom->nVersion >> pfrom->nServices >> nTime >> addrMe;\r
1843         if (pfrom->nVersion >= 106 && !vRecv.empty())\r
1844             vRecv >> addrFrom >> nNonce;\r
1845         if (pfrom->nVersion >= 106 && !vRecv.empty())\r
1846             vRecv >> strSubVer;\r
1847         if (pfrom->nVersion == 0)\r
1848             return false;\r
1849 \r
1850         // Disconnect if we connected to ourself\r
1851         if (nNonce == nLocalHostNonce && nNonce > 1)\r
1852         {\r
1853             pfrom->fDisconnect = true;\r
1854             return true;\r
1855         }\r
1856 \r
1857         pfrom->vSend.SetVersion(min(pfrom->nVersion, VERSION));\r
1858         pfrom->vRecv.SetVersion(min(pfrom->nVersion, VERSION));\r
1859 \r
1860         pfrom->fClient = !(pfrom->nServices & NODE_NETWORK);\r
1861         if (pfrom->fClient)\r
1862         {\r
1863             pfrom->vSend.nType |= SER_BLOCKHEADERONLY;\r
1864             pfrom->vRecv.nType |= SER_BLOCKHEADERONLY;\r
1865         }\r
1866 \r
1867         AddTimeData(pfrom->addr.ip, nTime);\r
1868 \r
1869         // Ask the first connected node for block updates\r
1870         static bool fAskedForBlocks;\r
1871         if (!fAskedForBlocks && !pfrom->fClient)\r
1872         {\r
1873             fAskedForBlocks = true;\r
1874             pfrom->PushGetBlocks(pindexBest, uint256(0));\r
1875         }\r
1876 \r
1877         pfrom->fSuccessfullyConnected = true;\r
1878 \r
1879         printf("version message: version %d\n", pfrom->nVersion);\r
1880     }\r
1881 \r
1882 \r
1883     else if (pfrom->nVersion == 0)\r
1884     {\r
1885         // Must have a version message before anything else\r
1886         return false;\r
1887     }\r
1888 \r
1889 \r
1890     else if (strCommand == "addr")\r
1891     {\r
1892         vector<CAddress> vAddr;\r
1893         vRecv >> vAddr;\r
1894         if (vAddr.size() > 50000) // lower this to 1000 later\r
1895             return error("message addr size() = %d", vAddr.size());\r
1896 \r
1897         // Store the new addresses\r
1898         foreach(CAddress& addr, vAddr)\r
1899         {\r
1900             if (fShutdown)\r
1901                 return true;\r
1902             addr.nTime = GetAdjustedTime() - 2 * 60 * 60;\r
1903             if (pfrom->fGetAddr)\r
1904                 addr.nTime -= 5 * 24 * 60 * 60;\r
1905             AddAddress(addr, false);\r
1906             pfrom->AddAddressKnown(addr);\r
1907             if (!pfrom->fGetAddr && addr.IsRoutable())\r
1908             {\r
1909                 // Put on lists to send to other nodes\r
1910                 CRITICAL_BLOCK(cs_vNodes)\r
1911                     foreach(CNode* pnode, vNodes)\r
1912                         pnode->PushAddress(addr);\r
1913             }\r
1914         }\r
1915         pfrom->fGetAddr = false;\r
1916     }\r
1917 \r
1918 \r
1919     else if (strCommand == "inv")\r
1920     {\r
1921         vector<CInv> vInv;\r
1922         vRecv >> vInv;\r
1923         if (vInv.size() > 50000)\r
1924             return error("message inv size() = %d", vInv.size());\r
1925 \r
1926         CTxDB txdb("r");\r
1927         foreach(const CInv& inv, vInv)\r
1928         {\r
1929             if (fShutdown)\r
1930                 return true;\r
1931             pfrom->AddInventoryKnown(inv);\r
1932 \r
1933             bool fAlreadyHave = AlreadyHave(txdb, inv);\r
1934             printf("  got inventory: %s  %s\n", inv.ToString().c_str(), fAlreadyHave ? "have" : "new");\r
1935 \r
1936             if (!fAlreadyHave)\r
1937                 pfrom->AskFor(inv);\r
1938             else if (inv.type == MSG_BLOCK && mapOrphanBlocks.count(inv.hash))\r
1939                 pfrom->PushGetBlocks(pindexBest, GetOrphanRoot(mapOrphanBlocks[inv.hash]));\r
1940 \r
1941             // Track requests for our stuff\r
1942             CRITICAL_BLOCK(cs_mapRequestCount)\r
1943             {\r
1944                 map<uint256, int>::iterator mi = mapRequestCount.find(inv.hash);\r
1945                 if (mi != mapRequestCount.end())\r
1946                     (*mi).second++;\r
1947             }\r
1948         }\r
1949     }\r
1950 \r
1951 \r
1952     else if (strCommand == "getdata")\r
1953     {\r
1954         vector<CInv> vInv;\r
1955         vRecv >> vInv;\r
1956         if (vInv.size() > 50000)\r
1957             return error("message getdata size() = %d", vInv.size());\r
1958 \r
1959         foreach(const CInv& inv, vInv)\r
1960         {\r
1961             if (fShutdown)\r
1962                 return true;\r
1963             printf("received getdata for: %s\n", inv.ToString().c_str());\r
1964 \r
1965             if (inv.type == MSG_BLOCK)\r
1966             {\r
1967                 // Send block from disk\r
1968                 map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(inv.hash);\r
1969                 if (mi != mapBlockIndex.end())\r
1970                 {\r
1971                     //// could optimize this to send header straight from blockindex for client\r
1972                     CBlock block;\r
1973                     block.ReadFromDisk((*mi).second, !pfrom->fClient);\r
1974                     pfrom->PushMessage("block", block);\r
1975 \r
1976                     // Trigger them to send a getblocks request for the next batch of inventory\r
1977                     if (inv.hash == pfrom->hashContinue)\r
1978                     {\r
1979                         // Bypass PushInventory, this must send even if redundant,\r
1980                         // and we want it right after the last block so they don't\r
1981                         // wait for other stuff first.\r
1982                         vector<CInv> vInv;\r
1983                         vInv.push_back(CInv(MSG_BLOCK, hashBestChain));\r
1984                         pfrom->PushMessage("inv", vInv);\r
1985                         pfrom->hashContinue = 0;\r
1986                     }\r
1987                 }\r
1988             }\r
1989             else if (inv.IsKnownType())\r
1990             {\r
1991                 // Send stream from relay memory\r
1992                 CRITICAL_BLOCK(cs_mapRelay)\r
1993                 {\r
1994                     map<CInv, CDataStream>::iterator mi = mapRelay.find(inv);\r
1995                     if (mi != mapRelay.end())\r
1996                         pfrom->PushMessage(inv.GetCommand(), (*mi).second);\r
1997                 }\r
1998             }\r
1999 \r
2000             // Track requests for our stuff\r
2001             CRITICAL_BLOCK(cs_mapRequestCount)\r
2002             {\r
2003                 map<uint256, int>::iterator mi = mapRequestCount.find(inv.hash);\r
2004                 if (mi != mapRequestCount.end())\r
2005                     (*mi).second++;\r
2006             }\r
2007         }\r
2008     }\r
2009 \r
2010 \r
2011     else if (strCommand == "getblocks")\r
2012     {\r
2013         CBlockLocator locator;\r
2014         uint256 hashStop;\r
2015         vRecv >> locator >> hashStop;\r
2016 \r
2017         // Find the first block the caller has in the main chain\r
2018         CBlockIndex* pindex = locator.GetBlockIndex();\r
2019 \r
2020         // Send the rest of the chain\r
2021         if (pindex)\r
2022             pindex = pindex->pnext;\r
2023         int nLimit = 500 + locator.GetDistanceBack();\r
2024         printf("getblocks %d to %s limit %d\n", (pindex ? pindex->nHeight : -1), hashStop.ToString().substr(0,16).c_str(), nLimit);\r
2025         for (; pindex; pindex = pindex->pnext)\r
2026         {\r
2027             if (pindex->GetBlockHash() == hashStop)\r
2028             {\r
2029                 printf("  getblocks stopping at %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString().substr(0,16).c_str());\r
2030                 break;\r
2031             }\r
2032             pfrom->PushInventory(CInv(MSG_BLOCK, pindex->GetBlockHash()));\r
2033             if (--nLimit <= 0)\r
2034             {\r
2035                 // When this block is requested, we'll send an inv that'll make them\r
2036                 // getblocks the next batch of inventory.\r
2037                 printf("  getblocks stopping at limit %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString().substr(0,16).c_str());\r
2038                 pfrom->hashContinue = pindex->GetBlockHash();\r
2039                 break;\r
2040             }\r
2041         }\r
2042     }\r
2043 \r
2044 \r
2045     else if (strCommand == "tx")\r
2046     {\r
2047         vector<uint256> vWorkQueue;\r
2048         CDataStream vMsg(vRecv);\r
2049         CTransaction tx;\r
2050         vRecv >> tx;\r
2051 \r
2052         CInv inv(MSG_TX, tx.GetHash());\r
2053         pfrom->AddInventoryKnown(inv);\r
2054 \r
2055         bool fMissingInputs = false;\r
2056         if (tx.AcceptTransaction(true, &fMissingInputs))\r
2057         {\r
2058             AddToWalletIfMine(tx, NULL);\r
2059             RelayMessage(inv, vMsg);\r
2060             mapAlreadyAskedFor.erase(inv);\r
2061             vWorkQueue.push_back(inv.hash);\r
2062 \r
2063             // Recursively process any orphan transactions that depended on this one\r
2064             for (int i = 0; i < vWorkQueue.size(); i++)\r
2065             {\r
2066                 uint256 hashPrev = vWorkQueue[i];\r
2067                 for (multimap<uint256, CDataStream*>::iterator mi = mapOrphanTransactionsByPrev.lower_bound(hashPrev);\r
2068                      mi != mapOrphanTransactionsByPrev.upper_bound(hashPrev);\r
2069                      ++mi)\r
2070                 {\r
2071                     const CDataStream& vMsg = *((*mi).second);\r
2072                     CTransaction tx;\r
2073                     CDataStream(vMsg) >> tx;\r
2074                     CInv inv(MSG_TX, tx.GetHash());\r
2075 \r
2076                     if (tx.AcceptTransaction(true))\r
2077                     {\r
2078                         printf("   accepted orphan tx %s\n", inv.hash.ToString().substr(0,6).c_str());\r
2079                         AddToWalletIfMine(tx, NULL);\r
2080                         RelayMessage(inv, vMsg);\r
2081                         mapAlreadyAskedFor.erase(inv);\r
2082                         vWorkQueue.push_back(inv.hash);\r
2083                     }\r
2084                 }\r
2085             }\r
2086 \r
2087             foreach(uint256 hash, vWorkQueue)\r
2088                 EraseOrphanTx(hash);\r
2089         }\r
2090         else if (fMissingInputs)\r
2091         {\r
2092             printf("storing orphan tx %s\n", inv.hash.ToString().substr(0,6).c_str());\r
2093             AddOrphanTx(vMsg);\r
2094         }\r
2095     }\r
2096 \r
2097 \r
2098     else if (strCommand == "review")\r
2099     {\r
2100         CDataStream vMsg(vRecv);\r
2101         CReview review;\r
2102         vRecv >> review;\r
2103 \r
2104         CInv inv(MSG_REVIEW, review.GetHash());\r
2105         pfrom->AddInventoryKnown(inv);\r
2106 \r
2107         if (review.AcceptReview())\r
2108         {\r
2109             // Relay the original message as-is in case it's a higher version than we know how to parse\r
2110             RelayMessage(inv, vMsg);\r
2111             mapAlreadyAskedFor.erase(inv);\r
2112         }\r
2113     }\r
2114 \r
2115 \r
2116     else if (strCommand == "block")\r
2117     {\r
2118         auto_ptr<CBlock> pblock(new CBlock);\r
2119         vRecv >> *pblock;\r
2120 \r
2121         //// debug print\r
2122         // printf("received block:\n");\r
2123         // pblock->print();\r
2124         printf("received block %s\n", pblock->GetHash().ToString().substr(0,16).c_str());\r
2125 \r
2126         CInv inv(MSG_BLOCK, pblock->GetHash());\r
2127         pfrom->AddInventoryKnown(inv);\r
2128 \r
2129         if (ProcessBlock(pfrom, pblock.release()))\r
2130             mapAlreadyAskedFor.erase(inv);\r
2131     }\r
2132 \r
2133 \r
2134     else if (strCommand == "getaddr")\r
2135     {\r
2136         pfrom->vAddrToSend.clear();\r
2137         int64 nSince = GetAdjustedTime() - 5 * 24 * 60 * 60; // in the last 5 days\r
2138         CRITICAL_BLOCK(cs_mapAddresses)\r
2139         {\r
2140             unsigned int nSize = mapAddresses.size();\r
2141             foreach(const PAIRTYPE(vector<unsigned char>, CAddress)& item, mapAddresses)\r
2142             {\r
2143                 if (fShutdown)\r
2144                     return true;\r
2145                 const CAddress& addr = item.second;\r
2146                 if (addr.nTime > nSince)\r
2147                     pfrom->PushAddress(addr);\r
2148             }\r
2149         }\r
2150     }\r
2151 \r
2152 \r
2153     else if (strCommand == "checkorder")\r
2154     {\r
2155         uint256 hashReply;\r
2156         CWalletTx order;\r
2157         vRecv >> hashReply >> order;\r
2158 \r
2159         /// we have a chance to check the order here\r
2160 \r
2161         // Keep giving the same key to the same ip until they use it\r
2162         if (!mapReuseKey.count(pfrom->addr.ip))\r
2163             mapReuseKey[pfrom->addr.ip] = GenerateNewKey();\r
2164 \r
2165         // Send back approval of order and pubkey to use\r
2166         CScript scriptPubKey;\r
2167         scriptPubKey << mapReuseKey[pfrom->addr.ip] << OP_CHECKSIG;\r
2168         pfrom->PushMessage("reply", hashReply, (int)0, scriptPubKey);\r
2169     }\r
2170 \r
2171 \r
2172     else if (strCommand == "submitorder")\r
2173     {\r
2174         uint256 hashReply;\r
2175         CWalletTx wtxNew;\r
2176         vRecv >> hashReply >> wtxNew;\r
2177 \r
2178         // Broadcast\r
2179         if (!wtxNew.AcceptWalletTransaction())\r
2180         {\r
2181             pfrom->PushMessage("reply", hashReply, (int)1);\r
2182             return error("submitorder AcceptWalletTransaction() failed, returning error 1");\r
2183         }\r
2184         wtxNew.fTimeReceivedIsTxTime = true;\r
2185         AddToWallet(wtxNew);\r
2186         wtxNew.RelayWalletTransaction();\r
2187         mapReuseKey.erase(pfrom->addr.ip);\r
2188 \r
2189         // Send back confirmation\r
2190         pfrom->PushMessage("reply", hashReply, (int)0);\r
2191     }\r
2192 \r
2193 \r
2194     else if (strCommand == "reply")\r
2195     {\r
2196         uint256 hashReply;\r
2197         vRecv >> hashReply;\r
2198 \r
2199         CRequestTracker tracker;\r
2200         CRITICAL_BLOCK(pfrom->cs_mapRequests)\r
2201         {\r
2202             map<uint256, CRequestTracker>::iterator mi = pfrom->mapRequests.find(hashReply);\r
2203             if (mi != pfrom->mapRequests.end())\r
2204             {\r
2205                 tracker = (*mi).second;\r
2206                 pfrom->mapRequests.erase(mi);\r
2207             }\r
2208         }\r
2209         if (!tracker.IsNull())\r
2210             tracker.fn(tracker.param1, vRecv);\r
2211     }\r
2212 \r
2213 \r
2214     else if (strCommand == "ping")\r
2215     {\r
2216     }\r
2217 \r
2218 \r
2219     else\r
2220     {\r
2221         // Ignore unknown commands for extensibility\r
2222     }\r
2223 \r
2224 \r
2225     // Update the last seen time for this node's address\r
2226     if (pfrom->fNetworkNode)\r
2227         if (strCommand == "version" || strCommand == "addr" || strCommand == "inv" || strCommand == "getdata" || strCommand == "ping")\r
2228             AddressCurrentlyConnected(pfrom->addr);\r
2229 \r
2230 \r
2231     return true;\r
2232 }\r
2233 \r
2234 \r
2235 \r
2236 \r
2237 \r
2238 \r
2239 \r
2240 \r
2241 \r
2242 bool SendMessages(CNode* pto)\r
2243 {\r
2244     CRITICAL_BLOCK(cs_main)\r
2245     {\r
2246         // Don't send anything until we get their version message\r
2247         if (pto->nVersion == 0)\r
2248             return true;\r
2249 \r
2250         // Keep-alive ping\r
2251         if (pto->nLastSend && GetTime() - pto->nLastSend > 12 * 60 && pto->vSend.empty())\r
2252             pto->PushMessage("ping");\r
2253 \r
2254         // Address refresh broadcast\r
2255         static int64 nLastRebroadcast;\r
2256         if (GetTime() - nLastRebroadcast > 24 * 60 * 60) // every 24 hours\r
2257         {\r
2258             nLastRebroadcast = GetTime();\r
2259             CRITICAL_BLOCK(cs_vNodes)\r
2260             {\r
2261                 foreach(CNode* pnode, vNodes)\r
2262                 {\r
2263                     // Periodically clear setAddrKnown to allow refresh broadcasts\r
2264                     pnode->setAddrKnown.clear();\r
2265 \r
2266                     // Rebroadcast our address\r
2267                     if (addrLocalHost.IsRoutable() && !fUseProxy)\r
2268                         pnode->PushAddress(addrLocalHost);\r
2269                 }\r
2270             }\r
2271         }\r
2272 \r
2273 \r
2274         //\r
2275         // Message: addr\r
2276         //\r
2277         vector<CAddress> vAddrToSend;\r
2278         vAddrToSend.reserve(pto->vAddrToSend.size());\r
2279         foreach(const CAddress& addr, pto->vAddrToSend)\r
2280         {\r
2281             // returns true if wasn't already contained in the set\r
2282             if (pto->setAddrKnown.insert(addr).second)\r
2283             {\r
2284                 vAddrToSend.push_back(addr);\r
2285                 if (vAddrToSend.size() >= 1000)\r
2286                 {\r
2287                     pto->PushMessage("addr", vAddrToSend);\r
2288                     vAddrToSend.clear();\r
2289                 }\r
2290             }\r
2291         }\r
2292         pto->vAddrToSend.clear();\r
2293         if (!vAddrToSend.empty())\r
2294             pto->PushMessage("addr", vAddrToSend);\r
2295 \r
2296 \r
2297         //\r
2298         // Message: inventory\r
2299         //\r
2300         vector<CInv> vInventoryToSend;\r
2301         CRITICAL_BLOCK(pto->cs_inventory)\r
2302         {\r
2303             vInventoryToSend.reserve(pto->vInventoryToSend.size());\r
2304             foreach(const CInv& inv, pto->vInventoryToSend)\r
2305             {\r
2306                 // returns true if wasn't already contained in the set\r
2307                 if (pto->setInventoryKnown.insert(inv).second)\r
2308                 {\r
2309                     vInventoryToSend.push_back(inv);\r
2310                     if (vInventoryToSend.size() >= 1000)\r
2311                     {\r
2312                         pto->PushMessage("inv", vInventoryToSend);\r
2313                         vInventoryToSend.clear();\r
2314                     }\r
2315                 }\r
2316             }\r
2317             pto->vInventoryToSend.clear();\r
2318         }\r
2319         if (!vInventoryToSend.empty())\r
2320             pto->PushMessage("inv", vInventoryToSend);\r
2321 \r
2322 \r
2323         //\r
2324         // Message: getdata\r
2325         //\r
2326         vector<CInv> vAskFor;\r
2327         int64 nNow = GetTime() * 1000000;\r
2328         CTxDB txdb("r");\r
2329         while (!pto->mapAskFor.empty() && (*pto->mapAskFor.begin()).first <= nNow)\r
2330         {\r
2331             const CInv& inv = (*pto->mapAskFor.begin()).second;\r
2332             if (!AlreadyHave(txdb, inv))\r
2333             {\r
2334                 printf("sending getdata: %s\n", inv.ToString().c_str());\r
2335                 vAskFor.push_back(inv);\r
2336                 if (vAskFor.size() >= 1000)\r
2337                 {\r
2338                     pto->PushMessage("getdata", vAskFor);\r
2339                     vAskFor.clear();\r
2340                 }\r
2341             }\r
2342             pto->mapAskFor.erase(pto->mapAskFor.begin());\r
2343         }\r
2344         if (!vAskFor.empty())\r
2345             pto->PushMessage("getdata", vAskFor);\r
2346 \r
2347     }\r
2348     return true;\r
2349 }\r
2350 \r
2351 \r
2352 \r
2353 \r
2354 \r
2355 \r
2356 \r
2357 \r
2358 \r
2359 \r
2360 \r
2361 \r
2362 \r
2363 \r
2364 //////////////////////////////////////////////////////////////////////////////\r
2365 //\r
2366 // BitcoinMiner\r
2367 //\r
2368 \r
2369 void GenerateBitcoins(bool fGenerate)\r
2370 {\r
2371     if (fGenerateBitcoins != fGenerate)\r
2372     {\r
2373         fGenerateBitcoins = fGenerate;\r
2374         CWalletDB().WriteSetting("fGenerateBitcoins", fGenerateBitcoins);\r
2375         MainFrameRepaint();\r
2376     }\r
2377     if (fGenerateBitcoins)\r
2378     {\r
2379         int nProcessors = wxThread::GetCPUCount();\r
2380         printf("%d processors\n", nProcessors);\r
2381         if (nProcessors < 1)\r
2382             nProcessors = 1;\r
2383         if (fLimitProcessors && nProcessors > nLimitProcessors)\r
2384             nProcessors = nLimitProcessors;\r
2385         int nAddThreads = nProcessors - vnThreadsRunning[3];\r
2386         printf("Starting %d BitcoinMiner threads\n", nAddThreads);\r
2387         for (int i = 0; i < nAddThreads; i++)\r
2388             if (!CreateThread(ThreadBitcoinMiner, NULL))\r
2389                 printf("Error: CreateThread(ThreadBitcoinMiner) failed\n");\r
2390     }\r
2391 }\r
2392 \r
2393 void ThreadBitcoinMiner(void* parg)\r
2394 {\r
2395     try\r
2396     {\r
2397         vnThreadsRunning[3]++;\r
2398         BitcoinMiner();\r
2399         vnThreadsRunning[3]--;\r
2400     }\r
2401     catch (std::exception& e) {\r
2402         vnThreadsRunning[3]--;\r
2403         PrintException(&e, "ThreadBitcoinMiner()");\r
2404     } catch (...) {\r
2405         vnThreadsRunning[3]--;\r
2406         PrintException(NULL, "ThreadBitcoinMiner()");\r
2407     }\r
2408 \r
2409     printf("ThreadBitcoinMiner exiting, %d threads remaining\n", vnThreadsRunning[3]);\r
2410 }\r
2411 \r
2412 int FormatHashBlocks(void* pbuffer, unsigned int len)\r
2413 {\r
2414     unsigned char* pdata = (unsigned char*)pbuffer;\r
2415     unsigned int blocks = 1 + ((len + 8) / 64);\r
2416     unsigned char* pend = pdata + 64 * blocks;\r
2417     memset(pdata + len, 0, 64 * blocks - len);\r
2418     pdata[len] = 0x80;\r
2419     unsigned int bits = len * 8;\r
2420     pend[-1] = (bits >> 0) & 0xff;\r
2421     pend[-2] = (bits >> 8) & 0xff;\r
2422     pend[-3] = (bits >> 16) & 0xff;\r
2423     pend[-4] = (bits >> 24) & 0xff;\r
2424     return blocks;\r
2425 }\r
2426 \r
2427 using CryptoPP::ByteReverse;\r
2428 static int detectlittleendian = 1;\r
2429 \r
2430 void BlockSHA256(const void* pin, unsigned int nBlocks, void* pout)\r
2431 {\r
2432     unsigned int* pinput = (unsigned int*)pin;\r
2433     unsigned int* pstate = (unsigned int*)pout;\r
2434 \r
2435     CryptoPP::SHA256::InitState(pstate);\r
2436 \r
2437     if (*(char*)&detectlittleendian != 0)\r
2438     {\r
2439         for (int n = 0; n < nBlocks; n++)\r
2440         {\r
2441             unsigned int pbuf[16];\r
2442             for (int i = 0; i < 16; i++)\r
2443                 pbuf[i] = ByteReverse(pinput[n * 16 + i]);\r
2444             CryptoPP::SHA256::Transform(pstate, pbuf);\r
2445         }\r
2446         for (int i = 0; i < 8; i++)\r
2447             pstate[i] = ByteReverse(pstate[i]);\r
2448     }\r
2449     else\r
2450     {\r
2451         for (int n = 0; n < nBlocks; n++)\r
2452             CryptoPP::SHA256::Transform(pstate, pinput + n * 16);\r
2453     }\r
2454 }\r
2455 \r
2456 \r
2457 void BitcoinMiner()\r
2458 {\r
2459     printf("BitcoinMiner started\n");\r
2460 \r
2461     CKey key;\r
2462     key.MakeNewKey();\r
2463     CBigNum bnExtraNonce = 0;\r
2464     while (fGenerateBitcoins)\r
2465     {\r
2466         SetThreadPriority(THREAD_PRIORITY_LOWEST);\r
2467         Sleep(50);\r
2468         if (fShutdown)\r
2469             return;\r
2470         while (vNodes.empty())\r
2471         {\r
2472             Sleep(1000);\r
2473             if (fShutdown)\r
2474                 return;\r
2475             if (!fGenerateBitcoins)\r
2476                 return;\r
2477         }\r
2478 \r
2479         unsigned int nTransactionsUpdatedLast = nTransactionsUpdated;\r
2480         CBlockIndex* pindexPrev = pindexBest;\r
2481         unsigned int nBits = GetNextWorkRequired(pindexPrev);\r
2482 \r
2483 \r
2484         //\r
2485         // Create coinbase tx\r
2486         //\r
2487         CTransaction txNew;\r
2488         txNew.vin.resize(1);\r
2489         txNew.vin[0].prevout.SetNull();\r
2490         txNew.vin[0].scriptSig << nBits << ++bnExtraNonce;\r
2491         txNew.vout.resize(1);\r
2492         txNew.vout[0].scriptPubKey << key.GetPubKey() << OP_CHECKSIG;\r
2493 \r
2494 \r
2495         //\r
2496         // Create new block\r
2497         //\r
2498         auto_ptr<CBlock> pblock(new CBlock());\r
2499         if (!pblock.get())\r
2500             return;\r
2501 \r
2502         // Add our coinbase tx as first transaction\r
2503         pblock->vtx.push_back(txNew);\r
2504 \r
2505         // Collect the latest transactions into the block\r
2506         int64 nFees = 0;\r
2507         CRITICAL_BLOCK(cs_main)\r
2508         CRITICAL_BLOCK(cs_mapTransactions)\r
2509         {\r
2510             CTxDB txdb("r");\r
2511             map<uint256, CTxIndex> mapTestPool;\r
2512             vector<char> vfAlreadyAdded(mapTransactions.size());\r
2513             bool fFoundSomething = true;\r
2514             unsigned int nBlockSize = 0;\r
2515             while (fFoundSomething && nBlockSize < MAX_SIZE/2)\r
2516             {\r
2517                 fFoundSomething = false;\r
2518                 unsigned int n = 0;\r
2519                 for (map<uint256, CTransaction>::iterator mi = mapTransactions.begin(); mi != mapTransactions.end(); ++mi, ++n)\r
2520                 {\r
2521                     if (vfAlreadyAdded[n])\r
2522                         continue;\r
2523                     CTransaction& tx = (*mi).second;\r
2524                     if (tx.IsCoinBase() || !tx.IsFinal())\r
2525                         continue;\r
2526 \r
2527                     // Transaction fee based on block size\r
2528                     int64 nMinFee = tx.GetMinFee(nBlockSize);\r
2529 \r
2530                     map<uint256, CTxIndex> mapTestPoolTmp(mapTestPool);\r
2531                     if (!tx.ConnectInputs(txdb, mapTestPoolTmp, CDiskTxPos(1,1,1), 0, nFees, false, true, nMinFee))\r
2532                         continue;\r
2533                     swap(mapTestPool, mapTestPoolTmp);\r
2534 \r
2535                     pblock->vtx.push_back(tx);\r
2536                     nBlockSize += ::GetSerializeSize(tx, SER_NETWORK);\r
2537                     vfAlreadyAdded[n] = true;\r
2538                     fFoundSomething = true;\r
2539                 }\r
2540             }\r
2541         }\r
2542         pblock->nBits = nBits;\r
2543         pblock->vtx[0].vout[0].nValue = pblock->GetBlockValue(nFees);\r
2544         printf("Running BitcoinMiner with %d transactions in block\n", pblock->vtx.size());\r
2545 \r
2546 \r
2547         //\r
2548         // Prebuild hash buffer\r
2549         //\r
2550         struct unnamed1\r
2551         {\r
2552             struct unnamed2\r
2553             {\r
2554                 int nVersion;\r
2555                 uint256 hashPrevBlock;\r
2556                 uint256 hashMerkleRoot;\r
2557                 unsigned int nTime;\r
2558                 unsigned int nBits;\r
2559                 unsigned int nNonce;\r
2560             }\r
2561             block;\r
2562             unsigned char pchPadding0[64];\r
2563             uint256 hash1;\r
2564             unsigned char pchPadding1[64];\r
2565         }\r
2566         tmp;\r
2567 \r
2568         tmp.block.nVersion       = pblock->nVersion;\r
2569         tmp.block.hashPrevBlock  = pblock->hashPrevBlock  = (pindexPrev ? pindexPrev->GetBlockHash() : 0);\r
2570         tmp.block.hashMerkleRoot = pblock->hashMerkleRoot = pblock->BuildMerkleTree();\r
2571         tmp.block.nTime          = pblock->nTime          = max((pindexPrev ? pindexPrev->GetMedianTimePast()+1 : 0), GetAdjustedTime());\r
2572         tmp.block.nBits          = pblock->nBits          = nBits;\r
2573         tmp.block.nNonce         = pblock->nNonce         = 1;\r
2574 \r
2575         unsigned int nBlocks0 = FormatHashBlocks(&tmp.block, sizeof(tmp.block));\r
2576         unsigned int nBlocks1 = FormatHashBlocks(&tmp.hash1, sizeof(tmp.hash1));\r
2577 \r
2578 \r
2579         //\r
2580         // Search\r
2581         //\r
2582         int64 nStart = GetTime();\r
2583         uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();\r
2584         uint256 hash;\r
2585         loop\r
2586         {\r
2587             BlockSHA256(&tmp.block, nBlocks0, &tmp.hash1);\r
2588             BlockSHA256(&tmp.hash1, nBlocks1, &hash);\r
2589 \r
2590             if (hash <= hashTarget)\r
2591             {\r
2592                 pblock->nNonce = tmp.block.nNonce;\r
2593                 assert(hash == pblock->GetHash());\r
2594 \r
2595                     //// debug print\r
2596                     printf("BitcoinMiner:\n");\r
2597                     printf("proof-of-work found  \n  hash: %s  \ntarget: %s\n", hash.GetHex().c_str(), hashTarget.GetHex().c_str());\r
2598                     pblock->print();\r
2599 \r
2600                 SetThreadPriority(THREAD_PRIORITY_NORMAL);\r
2601                 CRITICAL_BLOCK(cs_main)\r
2602                 {\r
2603                     if (pindexPrev == pindexBest)\r
2604                     {\r
2605                         // Save key\r
2606                         if (!AddKey(key))\r
2607                             return;\r
2608                         key.MakeNewKey();\r
2609 \r
2610                         // Track how many getdata requests this block gets\r
2611                         CRITICAL_BLOCK(cs_mapRequestCount)\r
2612                             mapRequestCount[pblock->GetHash()] = 0;\r
2613 \r
2614                         // Process this block the same as if we had received it from another node\r
2615                         if (!ProcessBlock(NULL, pblock.release()))\r
2616                             printf("ERROR in BitcoinMiner, ProcessBlock, block not accepted\n");\r
2617                     }\r
2618                 }\r
2619                 SetThreadPriority(THREAD_PRIORITY_LOWEST);\r
2620 \r
2621                 Sleep(500);\r
2622                 break;\r
2623             }\r
2624 \r
2625             // Update nTime every few seconds\r
2626             if ((++tmp.block.nNonce & 0xffff) == 0)\r
2627             {\r
2628                 if (fShutdown)\r
2629                     return;\r
2630                 if (!fGenerateBitcoins)\r
2631                     return;\r
2632                 if (fLimitProcessors && vnThreadsRunning[3] > nLimitProcessors)\r
2633                     return;\r
2634                 if (vNodes.empty())\r
2635                     break;\r
2636                 if (tmp.block.nNonce == 0)\r
2637                     break;\r
2638                 if (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60)\r
2639                     break;\r
2640                 if (pindexPrev != pindexBest)\r
2641                 {\r
2642                     // Pause generating during initial download\r
2643                     if (GetTime() - nStart < 20)\r
2644                     {\r
2645                         CBlockIndex* pindexTmp;\r
2646                         do\r
2647                         {\r
2648                             pindexTmp = pindexBest;\r
2649                             Sleep(10000);\r
2650                         }\r
2651                         while (pindexTmp != pindexBest);\r
2652                     }\r
2653                     break;\r
2654                 }\r
2655                 tmp.block.nTime = pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());\r
2656             }\r
2657         }\r
2658     }\r
2659 }\r
2660 \r
2661 \r
2662 \r
2663 \r
2664 \r
2665 \r
2666 \r
2667 \r
2668 \r
2669 \r
2670 \r
2671 \r
2672 \r
2673 \r
2674 \r
2675 \r
2676 \r
2677 \r
2678 //////////////////////////////////////////////////////////////////////////////\r
2679 //\r
2680 // Actions\r
2681 //\r
2682 \r
2683 \r
2684 int64 GetBalance()\r
2685 {\r
2686     int64 nStart = GetTimeMillis();\r
2687 \r
2688     int64 nTotal = 0;\r
2689     CRITICAL_BLOCK(cs_mapWallet)\r
2690     {\r
2691         for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)\r
2692         {\r
2693             CWalletTx* pcoin = &(*it).second;\r
2694             if (!pcoin->IsFinal() || pcoin->fSpent)\r
2695                 continue;\r
2696             nTotal += pcoin->GetCredit(true);\r
2697         }\r
2698     }\r
2699 \r
2700     //printf("GetBalance() %"PRI64d"ms\n", GetTimeMillis() - nStart);\r
2701     return nTotal;\r
2702 }\r
2703 \r
2704 \r
2705 \r
2706 bool SelectCoins(int64 nTargetValue, set<CWalletTx*>& setCoinsRet)\r
2707 {\r
2708     setCoinsRet.clear();\r
2709 \r
2710     // List of values less than target\r
2711     int64 nLowestLarger = INT64_MAX;\r
2712     CWalletTx* pcoinLowestLarger = NULL;\r
2713     vector<pair<int64, CWalletTx*> > vValue;\r
2714     int64 nTotalLower = 0;\r
2715 \r
2716     CRITICAL_BLOCK(cs_mapWallet)\r
2717     {\r
2718         for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)\r
2719         {\r
2720             CWalletTx* pcoin = &(*it).second;\r
2721             if (!pcoin->IsFinal() || pcoin->fSpent)\r
2722                 continue;\r
2723             int64 n = pcoin->GetCredit();\r
2724             if (n <= 0)\r
2725                 continue;\r
2726             if (n < nTargetValue)\r
2727             {\r
2728                 vValue.push_back(make_pair(n, pcoin));\r
2729                 nTotalLower += n;\r
2730             }\r
2731             else if (n == nTargetValue)\r
2732             {\r
2733                 setCoinsRet.insert(pcoin);\r
2734                 return true;\r
2735             }\r
2736             else if (n < nLowestLarger)\r
2737             {\r
2738                 nLowestLarger = n;\r
2739                 pcoinLowestLarger = pcoin;\r
2740             }\r
2741         }\r
2742     }\r
2743 \r
2744     if (nTotalLower < nTargetValue)\r
2745     {\r
2746         if (pcoinLowestLarger == NULL)\r
2747             return false;\r
2748         setCoinsRet.insert(pcoinLowestLarger);\r
2749         return true;\r
2750     }\r
2751 \r
2752     // Solve subset sum by stochastic approximation\r
2753     sort(vValue.rbegin(), vValue.rend());\r
2754     vector<char> vfIncluded;\r
2755     vector<char> vfBest(vValue.size(), true);\r
2756     int64 nBest = nTotalLower;\r
2757 \r
2758     for (int nRep = 0; nRep < 1000 && nBest != nTargetValue; nRep++)\r
2759     {\r
2760         vfIncluded.assign(vValue.size(), false);\r
2761         int64 nTotal = 0;\r
2762         bool fReachedTarget = false;\r
2763         for (int nPass = 0; nPass < 2 && !fReachedTarget; nPass++)\r
2764         {\r
2765             for (int i = 0; i < vValue.size(); i++)\r
2766             {\r
2767                 if (nPass == 0 ? rand() % 2 : !vfIncluded[i])\r
2768                 {\r
2769                     nTotal += vValue[i].first;\r
2770                     vfIncluded[i] = true;\r
2771                     if (nTotal >= nTargetValue)\r
2772                     {\r
2773                         fReachedTarget = true;\r
2774                         if (nTotal < nBest)\r
2775                         {\r
2776                             nBest = nTotal;\r
2777                             vfBest = vfIncluded;\r
2778                         }\r
2779                         nTotal -= vValue[i].first;\r
2780                         vfIncluded[i] = false;\r
2781                     }\r
2782                 }\r
2783             }\r
2784         }\r
2785     }\r
2786 \r
2787     // If the next larger is still closer, return it\r
2788     if (pcoinLowestLarger && nLowestLarger - nTargetValue <= nBest - nTargetValue)\r
2789         setCoinsRet.insert(pcoinLowestLarger);\r
2790     else\r
2791     {\r
2792         for (int i = 0; i < vValue.size(); i++)\r
2793             if (vfBest[i])\r
2794                 setCoinsRet.insert(vValue[i].second);\r
2795 \r
2796         //// debug print\r
2797         printf("SelectCoins() best subset: ");\r
2798         for (int i = 0; i < vValue.size(); i++)\r
2799             if (vfBest[i])\r
2800                 printf("%s ", FormatMoney(vValue[i].first).c_str());\r
2801         printf("total %s\n", FormatMoney(nBest).c_str());\r
2802     }\r
2803 \r
2804     return true;\r
2805 }\r
2806 \r
2807 \r
2808 \r
2809 \r
2810 bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CKey& keyRet, int64& nFeeRequiredRet)\r
2811 {\r
2812     nFeeRequiredRet = 0;\r
2813     CRITICAL_BLOCK(cs_main)\r
2814     {\r
2815         // txdb must be opened before the mapWallet lock\r
2816         CTxDB txdb("r");\r
2817         CRITICAL_BLOCK(cs_mapWallet)\r
2818         {\r
2819             int64 nFee = nTransactionFee;\r
2820             loop\r
2821             {\r
2822                 wtxNew.vin.clear();\r
2823                 wtxNew.vout.clear();\r
2824                 if (nValue < 0)\r
2825                     return false;\r
2826                 int64 nValueOut = nValue;\r
2827                 int64 nTotalValue = nValue + nFee;\r
2828 \r
2829                 // Choose coins to use\r
2830                 set<CWalletTx*> setCoins;\r
2831                 if (!SelectCoins(nTotalValue, setCoins))\r
2832                     return false;\r
2833                 int64 nValueIn = 0;\r
2834                 foreach(CWalletTx* pcoin, setCoins)\r
2835                     nValueIn += pcoin->GetCredit();\r
2836 \r
2837                 // Fill a vout to the payee\r
2838                 bool fChangeFirst = GetRand(2);\r
2839                 if (!fChangeFirst)\r
2840                     wtxNew.vout.push_back(CTxOut(nValueOut, scriptPubKey));\r
2841 \r
2842                 // Fill a vout back to self with any change\r
2843                 if (nValueIn > nTotalValue)\r
2844                 {\r
2845                     // New private key\r
2846                     if (keyRet.IsNull())\r
2847                         keyRet.MakeNewKey();\r
2848 \r
2849                     // Fill a vout to ourself\r
2850                     CScript scriptPubKey;\r
2851                     scriptPubKey << keyRet.GetPubKey() << OP_CHECKSIG;\r
2852                     wtxNew.vout.push_back(CTxOut(nValueIn - nTotalValue, scriptPubKey));\r
2853                 }\r
2854 \r
2855                 // Fill a vout to the payee\r
2856                 if (fChangeFirst)\r
2857                     wtxNew.vout.push_back(CTxOut(nValueOut, scriptPubKey));\r
2858 \r
2859                 // Fill vin\r
2860                 foreach(CWalletTx* pcoin, setCoins)\r
2861                     for (int nOut = 0; nOut < pcoin->vout.size(); nOut++)\r
2862                         if (pcoin->vout[nOut].IsMine())\r
2863                             wtxNew.vin.push_back(CTxIn(pcoin->GetHash(), nOut));\r
2864 \r
2865                 // Sign\r
2866                 int nIn = 0;\r
2867                 foreach(CWalletTx* pcoin, setCoins)\r
2868                     for (int nOut = 0; nOut < pcoin->vout.size(); nOut++)\r
2869                         if (pcoin->vout[nOut].IsMine())\r
2870                             SignSignature(*pcoin, wtxNew, nIn++);\r
2871 \r
2872                 // Check that enough fee is included\r
2873                 if (nFee < wtxNew.GetMinFee())\r
2874                 {\r
2875                     nFee = nFeeRequiredRet = wtxNew.GetMinFee();\r
2876                     continue;\r
2877                 }\r
2878 \r
2879                 // Fill vtxPrev by copying from previous transactions vtxPrev\r
2880                 wtxNew.AddSupportingTransactions(txdb);\r
2881                 wtxNew.fTimeReceivedIsTxTime = true;\r
2882 \r
2883                 break;\r
2884             }\r
2885         }\r
2886     }\r
2887     return true;\r
2888 }\r
2889 \r
2890 // Call after CreateTransaction unless you want to abort\r
2891 bool CommitTransactionSpent(const CWalletTx& wtxNew, const CKey& key)\r
2892 {\r
2893     CRITICAL_BLOCK(cs_main)\r
2894     CRITICAL_BLOCK(cs_mapWallet)\r
2895     {\r
2896         //// old: eventually should make this transactional, never want to add a\r
2897         ////  transaction without marking spent transactions, although the risk of\r
2898         ////  interruption during this step is remote.\r
2899         //// update: This matters even less now that fSpent can get corrected\r
2900         ////  when transactions are seen in VerifySignature.  The remote chance of\r
2901         ////  unmarked fSpent will be handled by that.  Don't need to make this\r
2902         ////  transactional.\r
2903 \r
2904         // This is only to keep the database open to defeat the auto-flush for the\r
2905         // duration of this scope.  This is the only place where this optimization\r
2906         // maybe makes sense; please don't do it anywhere else.\r
2907         CWalletDB walletdb("r");\r
2908 \r
2909         // Add the change's private key to wallet\r
2910         if (!key.IsNull() && !AddKey(key))\r
2911             throw runtime_error("CommitTransactionSpent() : AddKey failed\n");\r
2912 \r
2913         // Add tx to wallet, because if it has change it's also ours,\r
2914         // otherwise just for transaction history.\r
2915         AddToWallet(wtxNew);\r
2916 \r
2917         // Mark old coins as spent\r
2918         set<CWalletTx*> setCoins;\r
2919         foreach(const CTxIn& txin, wtxNew.vin)\r
2920             setCoins.insert(&mapWallet[txin.prevout.hash]);\r
2921         foreach(CWalletTx* pcoin, setCoins)\r
2922         {\r
2923             pcoin->fSpent = true;\r
2924             pcoin->WriteToDisk();\r
2925             vWalletUpdated.push_back(pcoin->GetHash());\r
2926         }\r
2927     }\r
2928     MainFrameRepaint();\r
2929     return true;\r
2930 }\r
2931 \r
2932 \r
2933 \r
2934 \r
2935 bool SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew)\r
2936 {\r
2937     CRITICAL_BLOCK(cs_main)\r
2938     {\r
2939         CKey key;\r
2940         int64 nFeeRequired;\r
2941         if (!CreateTransaction(scriptPubKey, nValue, wtxNew, key, nFeeRequired))\r
2942         {\r
2943             string strError;\r
2944             if (nValue + nFeeRequired > GetBalance())\r
2945                 strError = strprintf("Error: This is an oversized transaction that requires a transaction fee of %s  ", FormatMoney(nFeeRequired).c_str());\r
2946             else\r
2947                 strError = "Error: Transaction creation failed  ";\r
2948             wxMessageBox(strError, "Sending...");\r
2949             return error("SendMoney() : %s", strError.c_str());\r
2950         }\r
2951         if (!CommitTransactionSpent(wtxNew, key))\r
2952         {\r
2953             wxMessageBox("Error finalizing transaction  ", "Sending...");\r
2954             return error("SendMoney() : Error finalizing transaction");\r
2955         }\r
2956 \r
2957         // Track how many getdata requests our transaction gets\r
2958         CRITICAL_BLOCK(cs_mapRequestCount)\r
2959             mapRequestCount[wtxNew.GetHash()] = 0;\r
2960 \r
2961         printf("SendMoney: %s\n", wtxNew.GetHash().ToString().substr(0,6).c_str());\r
2962 \r
2963         // Broadcast\r
2964         if (!wtxNew.AcceptTransaction())\r
2965         {\r
2966             // This must not fail. The transaction has already been signed and recorded.\r
2967             wxMessageBox("Error: The transaction was rejected.  This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.", "Sending...");\r
2968             return error("SendMoney() : Error: Transaction not valid");\r
2969         }\r
2970         wtxNew.RelayWalletTransaction();\r
2971     }\r
2972     MainFrameRepaint();\r
2973     return true;\r
2974 }\r
This page took 0.221749 seconds and 4 git commands to generate.