aboutsummaryrefslogtreecommitdiff
path: root/src/main.cpp
diff options
context:
space:
mode:
authorWladimir J. van der Laan <laanwj@gmail.com>2011-06-26 19:23:24 +0200
committerWladimir J. van der Laan <laanwj@gmail.com>2011-06-26 19:23:24 +0200
commite8ef3da7133dd9fc411fa8b3cc8b8fc2f9c58a98 (patch)
treea6ff0ef6f8cdd85323acc1233a29891346b994fc /src/main.cpp
parentd99f5a470c8c4e80223f7a78679db58db78ee979 (diff)
downloadbitcoin-e8ef3da7133dd9fc411fa8b3cc8b8fc2f9c58a98.tar.xz
update core to d0d80170a2ca73004e08fb85007fe055cbf4e411 (CWallet class)
Diffstat (limited to 'src/main.cpp')
-rw-r--r--src/main.cpp1443
1 files changed, 252 insertions, 1191 deletions
diff --git a/src/main.cpp b/src/main.cpp
index 2dbbd674a7..54902e82eb 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -6,7 +6,7 @@
#include "net.h"
#include "init.h"
#include "cryptopp/sha.h"
-#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
using namespace std;
@@ -16,8 +16,14 @@ using namespace boost;
// Global state
//
+CCriticalSection cs_setpwalletRegistered;
+set<CWallet*> setpwalletRegistered;
+
CCriticalSection cs_main;
+CCriticalSection cs_mapPubKeys;
+map<uint160, vector<unsigned char> > mapPubKeys;
+
map<uint256, CTransaction> mapTransactions;
CCriticalSection cs_mapTransactions;
unsigned int nTransactionsUpdated = 0;
@@ -42,22 +48,6 @@ multimap<uint256, CBlock*> mapOrphanBlocksByPrev;
map<uint256, CDataStream*> mapOrphanTransactions;
multimap<uint256, CDataStream*> mapOrphanTransactionsByPrev;
-map<uint256, CWalletTx> mapWallet;
-vector<uint256> vWalletUpdated;
-CCriticalSection cs_mapWallet;
-
-map<vector<unsigned char>, CPrivKey> mapKeys;
-map<uint160, vector<unsigned char> > mapPubKeys;
-CCriticalSection cs_mapKeys;
-CKey keyUser;
-
-map<uint256, int> mapRequestCount;
-CCriticalSection cs_mapRequestCount;
-
-map<string, string> mapAddressBook;
-CCriticalSection cs_mapAddressBook;
-
-vector<unsigned char> vchDefaultKey;
double dHashesPerSec;
int64 nHPSTimerStart;
@@ -84,151 +74,82 @@ int fUseUPnP = false;
//////////////////////////////////////////////////////////////////////////////
//
-// mapKeys
+// dispatching functions
//
-bool AddKey(const CKey& key)
+void RegisterWallet(CWallet* pwalletIn)
{
- CRITICAL_BLOCK(cs_mapKeys)
+ CRITICAL_BLOCK(cs_setpwalletRegistered)
{
- mapKeys[key.GetPubKey()] = key.GetPrivKey();
- mapPubKeys[Hash160(key.GetPubKey())] = key.GetPubKey();
+ setpwalletRegistered.insert(pwalletIn);
}
- return CWalletDB().WriteKey(key.GetPubKey(), key.GetPrivKey());
}
-vector<unsigned char> GenerateNewKey()
+void UnregisterWallet(CWallet* pwalletIn)
{
- RandAddSeedPerfmon();
- CKey key;
- key.MakeNewKey();
- if (!AddKey(key))
- throw runtime_error("GenerateNewKey() : AddKey failed");
- return key.GetPubKey();
+ CRITICAL_BLOCK(cs_setpwalletRegistered)
+ {
+ setpwalletRegistered.erase(pwalletIn);
+ }
}
-
-
-
-//////////////////////////////////////////////////////////////////////////////
-//
-// mapWallet
-//
-
-bool AddToWallet(const CWalletTx& wtxIn)
+bool static IsFromMe(CTransaction& tx)
{
- uint256 hash = wtxIn.GetHash();
- CRITICAL_BLOCK(cs_mapWallet)
- {
- // Inserts only if not already there, returns tx inserted or tx found
- pair<map<uint256, CWalletTx>::iterator, bool> ret = mapWallet.insert(make_pair(hash, wtxIn));
- CWalletTx& wtx = (*ret.first).second;
- bool fInsertedNew = ret.second;
- if (fInsertedNew)
- wtx.nTimeReceived = GetAdjustedTime();
-
- bool fUpdated = false;
- if (!fInsertedNew)
- {
- // Merge
- if (wtxIn.hashBlock != 0 && wtxIn.hashBlock != wtx.hashBlock)
- {
- wtx.hashBlock = wtxIn.hashBlock;
- fUpdated = true;
- }
- if (wtxIn.nIndex != -1 && (wtxIn.vMerkleBranch != wtx.vMerkleBranch || wtxIn.nIndex != wtx.nIndex))
- {
- wtx.vMerkleBranch = wtxIn.vMerkleBranch;
- wtx.nIndex = wtxIn.nIndex;
- fUpdated = true;
- }
- if (wtxIn.fFromMe && wtxIn.fFromMe != wtx.fFromMe)
- {
- wtx.fFromMe = wtxIn.fFromMe;
- fUpdated = true;
- }
- fUpdated |= wtx.UpdateSpent(wtxIn.vfSpent);
- }
-
- //// debug print
- printf("AddToWallet %s %s%s\n", wtxIn.GetHash().ToString().substr(0,10).c_str(), (fInsertedNew ? "new" : ""), (fUpdated ? "update" : ""));
+ BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
+ if (pwallet->IsFromMe(tx))
+ return true;
+ return false;
+}
- // Write to disk
- if (fInsertedNew || fUpdated)
- if (!wtx.WriteToDisk())
- return false;
+bool static GetTransaction(const uint256& hashTx, CWalletTx& wtx)
+{
+ BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
+ if (pwallet->GetTransaction(hashTx,wtx))
+ return true;
+ return false;
+}
- // If default receiving address gets used, replace it with a new one
- CScript scriptDefaultKey;
- scriptDefaultKey.SetBitcoinAddress(vchDefaultKey);
- BOOST_FOREACH(const CTxOut& txout, wtx.vout)
- {
- if (txout.scriptPubKey == scriptDefaultKey)
- {
- CWalletDB walletdb;
- vchDefaultKey = GetKeyFromKeyPool();
- walletdb.WriteDefaultKey(vchDefaultKey);
- walletdb.WriteName(PubKeyToAddress(vchDefaultKey), "");
- }
- }
+void static EraseFromWallets(uint256 hash)
+{
+ BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
+ pwallet->EraseFromWallet(hash);
+}
- // Notify UI
- vWalletUpdated.push_back(hash);
- }
+void static SyncWithWallets(const CTransaction& tx, const CBlock* pblock = NULL, bool fUpdate = false)
+{
+ BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
+ pwallet->AddToWalletIfInvolvingMe(tx, pblock, fUpdate);
+}
- // Refresh UI
- MainFrameRepaint();
- return true;
+void static SetBestChain(const CBlockLocator& loc)
+{
+ BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
+ pwallet->SetBestChain(loc);
}
-bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate = false)
+void static UpdatedTransaction(const uint256& hashTx)
{
- uint256 hash = tx.GetHash();
- bool fExisted = mapWallet.count(hash);
- if (fExisted && !fUpdate) return false;
- if (fExisted || tx.IsMine() || tx.IsFromMe())
- {
- CWalletTx wtx(tx);
- // Get merkle branch if transaction was found in a block
- if (pblock)
- wtx.SetMerkleBranch(pblock);
- return AddToWallet(wtx);
- }
- return false;
+ BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
+ pwallet->UpdatedTransaction(hashTx);
}
-bool EraseFromWallet(uint256 hash)
+void static PrintWallets(const CBlock& block)
{
- CRITICAL_BLOCK(cs_mapWallet)
- {
- if (mapWallet.erase(hash))
- CWalletDB().EraseTx(hash);
- }
- return true;
+ BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
+ pwallet->PrintWallet(block);
}
-void WalletUpdateSpent(const COutPoint& prevout)
+void static Inventory(const uint256& hash)
{
- // Anytime a signature is successfully verified, it's proof the outpoint is spent.
- // Update the wallet spent flag if it doesn't know due to wallet.dat being
- // restored from backup or the user making copies of wallet.dat.
- CRITICAL_BLOCK(cs_mapWallet)
- {
- map<uint256, CWalletTx>::iterator mi = mapWallet.find(prevout.hash);
- if (mi != mapWallet.end())
- {
- CWalletTx& wtx = (*mi).second;
- if (!wtx.IsSpent(prevout.n) && wtx.vout[prevout.n].IsMine())
- {
- printf("WalletUpdateSpent found spent coin %sbc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str());
- wtx.MarkSpent(prevout.n);
- wtx.WriteToDisk();
- vWalletUpdated.push_back(prevout.hash);
- }
- }
- }
+ BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
+ pwallet->Inventory(hash);
}
+void static ResendWalletTransactions()
+{
+ BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
+ pwallet->ResendWalletTransactions();
+}
@@ -241,7 +162,7 @@ void WalletUpdateSpent(const COutPoint& prevout)
// mapOrphanTransactions
//
-void AddOrphanTx(const CDataStream& vMsg)
+void static AddOrphanTx(const CDataStream& vMsg)
{
CTransaction tx;
CDataStream(vMsg) >> tx;
@@ -253,7 +174,7 @@ void AddOrphanTx(const CDataStream& vMsg)
mapOrphanTransactionsByPrev.insert(make_pair(txin.prevout.hash, pvMsg));
}
-void EraseOrphanTx(uint256 hash)
+void static EraseOrphanTx(uint256 hash)
{
if (!mapOrphanTransactions.count(hash))
return;
@@ -315,190 +236,6 @@ bool CTransaction::ReadFromDisk(COutPoint prevout)
return ReadFromDisk(txdb, prevout, txindex);
}
-bool CTxIn::IsMine() const
-{
- CRITICAL_BLOCK(cs_mapWallet)
- {
- map<uint256, CWalletTx>::iterator mi = mapWallet.find(prevout.hash);
- if (mi != mapWallet.end())
- {
- const CWalletTx& prev = (*mi).second;
- if (prevout.n < prev.vout.size())
- if (prev.vout[prevout.n].IsMine())
- return true;
- }
- }
- return false;
-}
-
-int64 CTxIn::GetDebit() const
-{
- CRITICAL_BLOCK(cs_mapWallet)
- {
- map<uint256, CWalletTx>::iterator mi = mapWallet.find(prevout.hash);
- if (mi != mapWallet.end())
- {
- const CWalletTx& prev = (*mi).second;
- if (prevout.n < prev.vout.size())
- if (prev.vout[prevout.n].IsMine())
- return prev.vout[prevout.n].nValue;
- }
- }
- return 0;
-}
-
-int64 CWalletTx::GetTxTime() const
-{
- if (!fTimeReceivedIsTxTime && hashBlock != 0)
- {
- // If we did not receive the transaction directly, we rely on the block's
- // time to figure out when it happened. We use the median over a range
- // of blocks to try to filter out inaccurate block times.
- map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
- if (mi != mapBlockIndex.end())
- {
- CBlockIndex* pindex = (*mi).second;
- if (pindex)
- return pindex->GetMedianTime();
- }
- }
- return nTimeReceived;
-}
-
-int CWalletTx::GetRequestCount() const
-{
- // Returns -1 if it wasn't being tracked
- int nRequests = -1;
- CRITICAL_BLOCK(cs_mapRequestCount)
- {
- if (IsCoinBase())
- {
- // Generated block
- if (hashBlock != 0)
- {
- map<uint256, int>::iterator mi = mapRequestCount.find(hashBlock);
- if (mi != mapRequestCount.end())
- nRequests = (*mi).second;
- }
- }
- else
- {
- // Did anyone request this transaction?
- map<uint256, int>::iterator mi = mapRequestCount.find(GetHash());
- if (mi != mapRequestCount.end())
- {
- nRequests = (*mi).second;
-
- // How about the block it's in?
- if (nRequests == 0 && hashBlock != 0)
- {
- map<uint256, int>::iterator mi = mapRequestCount.find(hashBlock);
- if (mi != mapRequestCount.end())
- nRequests = (*mi).second;
- else
- nRequests = 1; // If it's in someone else's block it must have got out
- }
- }
- }
- }
- return nRequests;
-}
-
-void CWalletTx::GetAmounts(int64& nGeneratedImmature, int64& nGeneratedMature, list<pair<string, int64> >& listReceived,
- list<pair<string, int64> >& listSent, int64& nFee, string& strSentAccount) const
-{
- nGeneratedImmature = nGeneratedMature = nFee = 0;
- listReceived.clear();
- listSent.clear();
- strSentAccount = strFromAccount;
-
- if (IsCoinBase())
- {
- if (GetBlocksToMaturity() > 0)
- nGeneratedImmature = CTransaction::GetCredit();
- else
- nGeneratedMature = GetCredit();
- return;
- }
-
- // Compute fee:
- int64 nDebit = GetDebit();
- if (nDebit > 0) // debit>0 means we signed/sent this transaction
- {
- int64 nValueOut = GetValueOut();
- nFee = nDebit - nValueOut;
- }
-
- // Sent/received. Standard client will never generate a send-to-multiple-recipients,
- // but non-standard clients might (so return a list of address/amount pairs)
- BOOST_FOREACH(const CTxOut& txout, vout)
- {
- string address;
- uint160 hash160;
- vector<unsigned char> vchPubKey;
- if (ExtractHash160(txout.scriptPubKey, hash160))
- address = Hash160ToAddress(hash160);
- else if (ExtractPubKey(txout.scriptPubKey, false, vchPubKey))
- address = PubKeyToAddress(vchPubKey);
- else
- {
- printf("CWalletTx::GetAmounts: Unknown transaction type found, txid %s\n",
- this->GetHash().ToString().c_str());
- address = " unknown ";
- }
-
- // Don't report 'change' txouts
- if (nDebit > 0 && txout.IsChange())
- continue;
-
- if (nDebit > 0)
- listSent.push_back(make_pair(address, txout.nValue));
-
- if (txout.IsMine())
- listReceived.push_back(make_pair(address, txout.nValue));
- }
-
-}
-
-void CWalletTx::GetAccountAmounts(const string& strAccount, int64& nGenerated, int64& nReceived,
- int64& nSent, int64& nFee) const
-{
- nGenerated = nReceived = nSent = nFee = 0;
-
- int64 allGeneratedImmature, allGeneratedMature, allFee;
- allGeneratedImmature = allGeneratedMature = allFee = 0;
- string strSentAccount;
- list<pair<string, int64> > listReceived;
- list<pair<string, int64> > listSent;
- GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
-
- if (strAccount == "")
- nGenerated = allGeneratedMature;
- if (strAccount == strSentAccount)
- {
- BOOST_FOREACH(const PAIRTYPE(string,int64)& s, listSent)
- nSent += s.second;
- nFee = allFee;
- }
- CRITICAL_BLOCK(cs_mapAddressBook)
- {
- BOOST_FOREACH(const PAIRTYPE(string,int64)& r, listReceived)
- {
- if (mapAddressBook.count(r.first))
- {
- if (mapAddressBook[r.first] == strAccount)
- {
- nReceived += r.second;
- }
- }
- else if (strAccount.empty())
- {
- nReceived += r.second;
- }
- }
- }
-}
-
int CMerkleTx::SetMerkleBranch(const CBlock* pblock)
@@ -554,69 +291,6 @@ int CMerkleTx::SetMerkleBranch(const CBlock* pblock)
-void CWalletTx::AddSupportingTransactions(CTxDB& txdb)
-{
- vtxPrev.clear();
-
- const int COPY_DEPTH = 3;
- if (SetMerkleBranch() < COPY_DEPTH)
- {
- vector<uint256> vWorkQueue;
- BOOST_FOREACH(const CTxIn& txin, vin)
- vWorkQueue.push_back(txin.prevout.hash);
-
- // This critsect is OK because txdb is already open
- CRITICAL_BLOCK(cs_mapWallet)
- {
- map<uint256, const CMerkleTx*> mapWalletPrev;
- set<uint256> setAlreadyDone;
- for (int i = 0; i < vWorkQueue.size(); i++)
- {
- uint256 hash = vWorkQueue[i];
- if (setAlreadyDone.count(hash))
- continue;
- setAlreadyDone.insert(hash);
-
- CMerkleTx tx;
- if (mapWallet.count(hash))
- {
- tx = mapWallet[hash];
- BOOST_FOREACH(const CMerkleTx& txWalletPrev, mapWallet[hash].vtxPrev)
- mapWalletPrev[txWalletPrev.GetHash()] = &txWalletPrev;
- }
- else if (mapWalletPrev.count(hash))
- {
- tx = *mapWalletPrev[hash];
- }
- else if (!fClient && txdb.ReadDiskTx(hash, tx))
- {
- ;
- }
- else
- {
- printf("ERROR: AddSupportingTransactions() : unsupported transaction\n");
- continue;
- }
-
- int nDepth = tx.SetMerkleBranch();
- vtxPrev.push_back(tx);
-
- if (nDepth < COPY_DEPTH)
- BOOST_FOREACH(const CTxIn& txin, tx.vin)
- vWorkQueue.push_back(txin.prevout.hash);
- }
- }
- }
-
- reverse(vtxPrev.begin(), vtxPrev.end());
-}
-
-
-
-
-
-
-
@@ -758,7 +432,7 @@ bool CTransaction::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs, bool* pfMi
nLastTime = nNow;
// -limitfreerelay unit is thousand-bytes-per-minute
// At default rate it would take over a month to fill 1GB
- if (dFreeCount > GetArg("-limitfreerelay", 15)*10*1000 && !IsFromMe())
+ if (dFreeCount > GetArg("-limitfreerelay", 15)*10*1000 && !IsFromMe(*this))
return error("AcceptToMemoryPool() : free transaction rejected by rate limiter");
if (fDebug)
printf("Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount+nSize);
@@ -781,12 +455,17 @@ bool CTransaction::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs, bool* pfMi
///// are we sure this is ok when loading transactions or restoring block txes
// If updated, erase old tx from wallet
if (ptxOld)
- EraseFromWallet(ptxOld->GetHash());
+ EraseFromWallets(ptxOld->GetHash());
printf("AcceptToMemoryPool(): accepted %s\n", hash.ToString().substr(0,10).c_str());
return true;
}
+bool CTransaction::AcceptToMemoryPool(bool fCheckInputs, bool* pfMissingInputs)
+{
+ CTxDB txdb("r");
+ return AcceptToMemoryPool(txdb, fCheckInputs, pfMissingInputs);
+}
bool CTransaction::AddToMemoryPoolUnchecked()
{
@@ -870,6 +549,12 @@ bool CMerkleTx::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs)
}
}
+bool CMerkleTx::AcceptToMemoryPool()
+{
+ CTxDB txdb("r");
+ return AcceptToMemoryPool(txdb);
+}
+
bool CWalletTx::AcceptWalletTransaction(CTxDB& txdb, bool fCheckInputs)
@@ -891,148 +576,10 @@ bool CWalletTx::AcceptWalletTransaction(CTxDB& txdb, bool fCheckInputs)
return false;
}
-int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
-{
- int ret = 0;
-
- CBlockIndex* pindex = pindexStart;
- CRITICAL_BLOCK(cs_mapWallet)
- {
- while (pindex)
- {
- CBlock block;
- block.ReadFromDisk(pindex, true);
- BOOST_FOREACH(CTransaction& tx, block.vtx)
- {
- if (AddToWalletIfInvolvingMe(tx, &block, fUpdate))
- ret++;
- }
- pindex = pindex->pnext;
- }
- }
- return ret;
-}
-
-void ReacceptWalletTransactions()
+bool CWalletTx::AcceptWalletTransaction()
{
CTxDB txdb("r");
- bool fRepeat = true;
- while (fRepeat) CRITICAL_BLOCK(cs_mapWallet)
- {
- fRepeat = false;
- vector<CDiskTxPos> vMissingTx;
- BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
- {
- CWalletTx& wtx = item.second;
- if (wtx.IsCoinBase() && wtx.IsSpent(0))
- continue;
-
- CTxIndex txindex;
- bool fUpdated = false;
- if (txdb.ReadTxIndex(wtx.GetHash(), txindex))
- {
- // Update fSpent if a tx got spent somewhere else by a copy of wallet.dat
- if (txindex.vSpent.size() != wtx.vout.size())
- {
- printf("ERROR: ReacceptWalletTransactions() : txindex.vSpent.size() %d != wtx.vout.size() %d\n", txindex.vSpent.size(), wtx.vout.size());
- continue;
- }
- for (int i = 0; i < txindex.vSpent.size(); i++)
- {
- if (wtx.IsSpent(i))
- continue;
- if (!txindex.vSpent[i].IsNull() && wtx.vout[i].IsMine())
- {
- wtx.MarkSpent(i);
- fUpdated = true;
- vMissingTx.push_back(txindex.vSpent[i]);
- }
- }
- if (fUpdated)
- {
- printf("ReacceptWalletTransactions found spent coin %sbc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str());
- wtx.MarkDirty();
- wtx.WriteToDisk();
- }
- }
- else
- {
- // Reaccept any txes of ours that aren't already in a block
- if (!wtx.IsCoinBase())
- wtx.AcceptWalletTransaction(txdb, false);
- }
- }
- if (!vMissingTx.empty())
- {
- // TODO: optimize this to scan just part of the block chain?
- if (ScanForWalletTransactions(pindexGenesisBlock))
- fRepeat = true; // Found missing transactions: re-do Reaccept.
- }
- }
-}
-
-
-void CWalletTx::RelayWalletTransaction(CTxDB& txdb)
-{
- BOOST_FOREACH(const CMerkleTx& tx, vtxPrev)
- {
- if (!tx.IsCoinBase())
- {
- uint256 hash = tx.GetHash();
- if (!txdb.ContainsTx(hash))
- RelayMessage(CInv(MSG_TX, hash), (CTransaction)tx);
- }
- }
- if (!IsCoinBase())
- {
- uint256 hash = GetHash();
- if (!txdb.ContainsTx(hash))
- {
- printf("Relaying wtx %s\n", hash.ToString().substr(0,10).c_str());
- RelayMessage(CInv(MSG_TX, hash), (CTransaction)*this);
- }
- }
-}
-
-void ResendWalletTransactions()
-{
- // Do this infrequently and randomly to avoid giving away
- // that these are our transactions.
- static int64 nNextTime;
- if (GetTime() < nNextTime)
- return;
- bool fFirst = (nNextTime == 0);
- nNextTime = GetTime() + GetRand(30 * 60);
- if (fFirst)
- return;
-
- // Only do it if there's been a new block since last time
- static int64 nLastTime;
- if (nTimeBestReceived < nLastTime)
- return;
- nLastTime = GetTime();
-
- // Rebroadcast any of our txes that aren't in a block yet
- printf("ResendWalletTransactions()\n");
- CTxDB txdb("r");
- CRITICAL_BLOCK(cs_mapWallet)
- {
- // Sort them in chronological order
- multimap<unsigned int, CWalletTx*> mapSorted;
- BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
- {
- CWalletTx& wtx = item.second;
- // Don't rebroadcast until it's had plenty of time that
- // it should have gotten in already by now.
- if (nTimeBestReceived - (int64)wtx.nTimeReceived > 5 * 60)
- mapSorted.insert(make_pair(wtx.nTimeReceived, &wtx));
- }
- BOOST_FOREACH(PAIRTYPE(const unsigned int, CWalletTx*)& item, mapSorted)
- {
- CWalletTx& wtx = *item.second;
- wtx.RelayWalletTransaction(txdb);
- }
- }
+ return AcceptWalletTransaction(txdb);
}
int CTxIndex::GetDepthInMainChain() const
@@ -1079,7 +626,7 @@ bool CBlock::ReadFromDisk(const CBlockIndex* pindex, bool fReadTransactions)
return true;
}
-uint256 GetOrphanRoot(const CBlock* pblock)
+uint256 static GetOrphanRoot(const CBlock* pblock)
{
// Work back to the first block in the orphan chain
while (mapOrphanBlocks.count(pblock->hashPrevBlock))
@@ -1087,7 +634,7 @@ uint256 GetOrphanRoot(const CBlock* pblock)
return pblock->GetHash();
}
-int64 GetBlockValue(int nHeight, int64 nFees)
+int64 static GetBlockValue(int nHeight, int64 nFees)
{
int64 nSubsidy = 50 * COIN;
@@ -1097,7 +644,7 @@ int64 GetBlockValue(int nHeight, int64 nFees)
return nSubsidy + nFees;
}
-unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast)
+unsigned int static GetNextWorkRequired(const CBlockIndex* pindexLast)
{
const int64 nTargetTimespan = 14 * 24 * 60 * 60; // two weeks
const int64 nTargetSpacing = 10 * 60;
@@ -1187,7 +734,7 @@ bool IsInitialBlockDownload()
pindexBest->GetBlockTime() < GetTime() - 24 * 60 * 60);
}
-void InvalidChainFound(CBlockIndex* pindexNew)
+void static InvalidChainFound(CBlockIndex* pindexNew)
{
if (pindexNew->bnChainWork > bnBestInvalidWork)
{
@@ -1463,12 +1010,12 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex)
// Watch for transactions paying to me
BOOST_FOREACH(CTransaction& tx, vtx)
- AddToWalletIfInvolvingMe(tx, this, true);
+ SyncWithWallets(tx, this, true);
return true;
}
-bool Reorganize(CTxDB& txdb, CBlockIndex* pindexNew)
+bool static Reorganize(CTxDB& txdb, CBlockIndex* pindexNew)
{
printf("REORGANIZE\n");
@@ -1606,10 +1153,8 @@ bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew)
// Update best block in wallet (so we can detect restored wallets)
if (!IsInitialBlockDownload())
{
- CWalletDB walletdb;
const CBlockLocator locator(pindexNew);
- if (!walletdb.WriteBestBlock(locator))
- return error("SetBestChain() : WriteWalletBest failed");
+ ::SetBestChain(locator);
}
// New best block
@@ -1663,8 +1208,7 @@ bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos)
{
// Notify UI to display prev block's coinbase if it was ours
static uint256 hashPrevBestCoinBase;
- CRITICAL_BLOCK(cs_mapWallet)
- vWalletUpdated.push_back(hashPrevBestCoinBase);
+ UpdatedTransaction(hashPrevBestCoinBase);
hashPrevBestCoinBase = vtx[0].GetHash();
}
@@ -1773,7 +1317,7 @@ bool CBlock::AcceptBlock()
return true;
}
-bool ProcessBlock(CNode* pfrom, CBlock* pblock)
+bool static ProcessBlock(CNode* pfrom, CBlock* pblock)
{
// Check for duplicate
uint256 hash = pblock->GetHash();
@@ -1835,7 +1379,7 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock)
template<typename Stream>
-bool ScanMessageStart(Stream& s)
+bool static ScanMessageStart(Stream& s)
{
// Scan ahead to the next pchMessageStart, which should normally be immediately
// at the file pointer. Leaves file pointer at end of pchMessageStart.
@@ -2050,7 +1594,7 @@ void PrintBlockTree()
for (int i = 0; i < nCol; i++)
printf("| ");
printf("|\n");
- }
+ }
nPrevCol = nCol;
// print columns
@@ -2068,16 +1612,7 @@ void PrintBlockTree()
DateTimeStrFormat("%x %H:%M:%S", block.GetBlockTime()).c_str(),
block.vtx.size());
- CRITICAL_BLOCK(cs_mapWallet)
- {
- if (mapWallet.count(block.vtx[0].GetHash()))
- {
- CWalletTx& wtx = mapWallet[block.vtx[0].GetHash()];
- printf(" mine: %d %d %d", wtx.GetDepthInMainChain(), wtx.GetBlocksToMaturity(), wtx.GetCredit());
- }
- }
- printf("\n");
-
+ PrintWallets(block);
// put the main timechain first
vector<CBlockIndex*>& vNext = mapNext[pindex];
@@ -2217,7 +1752,7 @@ bool CAlert::ProcessAlert()
//
-bool AlreadyHave(CTxDB& txdb, const CInv& inv)
+bool static AlreadyHave(CTxDB& txdb, const CInv& inv)
{
switch (inv.type)
{
@@ -2237,128 +1772,7 @@ bool AlreadyHave(CTxDB& txdb, const CInv& inv)
char pchMessageStart[4] = { 0xf9, 0xbe, 0xb4, 0xd9 };
-bool ProcessMessages(CNode* pfrom)
-{
- CDataStream& vRecv = pfrom->vRecv;
- if (vRecv.empty())
- return true;
- //if (fDebug)
- // printf("ProcessMessages(%u bytes)\n", vRecv.size());
-
- //
- // Message format
- // (4) message start
- // (12) command
- // (4) size
- // (4) checksum
- // (x) data
- //
-
- loop
- {
- // Scan for message start
- CDataStream::iterator pstart = search(vRecv.begin(), vRecv.end(), BEGIN(pchMessageStart), END(pchMessageStart));
- int nHeaderSize = vRecv.GetSerializeSize(CMessageHeader());
- if (vRecv.end() - pstart < nHeaderSize)
- {
- if (vRecv.size() > nHeaderSize)
- {
- printf("\n\nPROCESSMESSAGE MESSAGESTART NOT FOUND\n\n");
- vRecv.erase(vRecv.begin(), vRecv.end() - nHeaderSize);
- }
- break;
- }
- if (pstart - vRecv.begin() > 0)
- printf("\n\nPROCESSMESSAGE SKIPPED %d BYTES\n\n", pstart - vRecv.begin());
- vRecv.erase(vRecv.begin(), pstart);
-
- // Read header
- vector<char> vHeaderSave(vRecv.begin(), vRecv.begin() + nHeaderSize);
- CMessageHeader hdr;
- vRecv >> hdr;
- if (!hdr.IsValid())
- {
- printf("\n\nPROCESSMESSAGE: ERRORS IN HEADER %s\n\n\n", hdr.GetCommand().c_str());
- continue;
- }
- string strCommand = hdr.GetCommand();
-
- // Message size
- unsigned int nMessageSize = hdr.nMessageSize;
- if (nMessageSize > MAX_SIZE)
- {
- printf("ProcessMessage(%s, %u bytes) : nMessageSize > MAX_SIZE\n", strCommand.c_str(), nMessageSize);
- continue;
- }
- if (nMessageSize > vRecv.size())
- {
- // Rewind and wait for rest of message
- vRecv.insert(vRecv.begin(), vHeaderSave.begin(), vHeaderSave.end());
- break;
- }
-
- // Checksum
- if (vRecv.GetVersion() >= 209)
- {
- uint256 hash = Hash(vRecv.begin(), vRecv.begin() + nMessageSize);
- unsigned int nChecksum = 0;
- memcpy(&nChecksum, &hash, sizeof(nChecksum));
- if (nChecksum != hdr.nChecksum)
- {
- printf("ProcessMessage(%s, %u bytes) : CHECKSUM ERROR nChecksum=%08x hdr.nChecksum=%08x\n",
- strCommand.c_str(), nMessageSize, nChecksum, hdr.nChecksum);
- continue;
- }
- }
-
- // Copy message to its own buffer
- CDataStream vMsg(vRecv.begin(), vRecv.begin() + nMessageSize, vRecv.nType, vRecv.nVersion);
- vRecv.ignore(nMessageSize);
-
- // Process message
- bool fRet = false;
- try
- {
- CRITICAL_BLOCK(cs_main)
- fRet = ProcessMessage(pfrom, strCommand, vMsg);
- if (fShutdown)
- return true;
- }
- catch (std::ios_base::failure& e)
- {
- if (strstr(e.what(), "end of data"))
- {
- // Allow exceptions from underlength message on vRecv
- printf("ProcessMessage(%s, %u bytes) : Exception '%s' caught, normally caused by a message being shorter than its stated length\n", strCommand.c_str(), nMessageSize, e.what());
- }
- else if (strstr(e.what(), "size too large"))
- {
- // Allow exceptions from overlong size
- printf("ProcessMessage(%s, %u bytes) : Exception '%s' caught\n", strCommand.c_str(), nMessageSize, e.what());
- }
- else
- {
- PrintExceptionContinue(&e, "ProcessMessage()");
- }
- }
- catch (std::exception& e) {
- PrintExceptionContinue(&e, "ProcessMessage()");
- } catch (...) {
- PrintExceptionContinue(NULL, "ProcessMessage()");
- }
-
- if (!fRet)
- printf("ProcessMessage(%s, %u bytes) FAILED\n", strCommand.c_str(), nMessageSize);
- }
-
- vRecv.Compact();
- return true;
-}
-
-
-
-
-bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
+bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
{
static map<unsigned int, vector<unsigned char> > mapReuseKey;
RandAddSeedPerfmon();
@@ -2555,12 +1969,7 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
pfrom->PushGetBlocks(pindexBest, GetOrphanRoot(mapOrphanBlocks[inv.hash]));
// Track requests for our stuff
- CRITICAL_BLOCK(cs_mapRequestCount)
- {
- map<uint256, int>::iterator mi = mapRequestCount.find(inv.hash);
- if (mi != mapRequestCount.end())
- (*mi).second++;
- }
+ Inventory(inv.hash);
}
}
@@ -2613,12 +2022,7 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
}
// Track requests for our stuff
- CRITICAL_BLOCK(cs_mapRequestCount)
- {
- map<uint256, int>::iterator mi = mapRequestCount.find(inv.hash);
- if (mi != mapRequestCount.end())
- (*mi).second++;
- }
+ Inventory(inv.hash);
}
}
@@ -2706,7 +2110,7 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
bool fMissingInputs = false;
if (tx.AcceptToMemoryPool(true, &fMissingInputs))
{
- AddToWalletIfInvolvingMe(tx, NULL, true);
+ SyncWithWallets(tx, NULL, true);
RelayMessage(inv, vMsg);
mapAlreadyAskedFor.erase(inv);
vWorkQueue.push_back(inv.hash);
@@ -2727,7 +2131,7 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
if (tx.AcceptToMemoryPool(true))
{
printf(" accepted orphan tx %s\n", inv.hash.ToString().substr(0,10).c_str());
- AddToWalletIfInvolvingMe(tx, NULL, true);
+ SyncWithWallets(tx, NULL, true);
RelayMessage(inv, vMsg);
mapAlreadyAskedFor.erase(inv);
vWorkQueue.push_back(inv.hash);
@@ -2804,7 +2208,7 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
// Keep giving the same key to the same ip until they use it
if (!mapReuseKey.count(pfrom->addr.ip))
- mapReuseKey[pfrom->addr.ip] = GetKeyFromKeyPool();
+ mapReuseKey[pfrom->addr.ip] = pwalletMain->GetKeyFromKeyPool();
// Send back approval of order and pubkey to use
CScript scriptPubKey;
@@ -2813,37 +2217,6 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
}
- else if (strCommand == "submitorder")
- {
- uint256 hashReply;
- vRecv >> hashReply;
-
- if (!GetBoolArg("-allowreceivebyip"))
- {
- pfrom->PushMessage("reply", hashReply, (int)2);
- return true;
- }
-
- CWalletTx wtxNew;
- vRecv >> wtxNew;
- wtxNew.fFromMe = false;
-
- // Broadcast
- if (!wtxNew.AcceptWalletTransaction())
- {
- pfrom->PushMessage("reply", hashReply, (int)1);
- return error("submitorder AcceptWalletTransaction() failed, returning error 1");
- }
- wtxNew.fTimeReceivedIsTxTime = true;
- AddToWallet(wtxNew);
- wtxNew.RelayWalletTransaction();
- mapReuseKey.erase(pfrom->addr.ip);
-
- // Send back confirmation
- pfrom->PushMessage("reply", hashReply, (int)0);
- }
-
-
else if (strCommand == "reply")
{
uint256 hashReply;
@@ -2900,12 +2273,123 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
return true;
}
+bool ProcessMessages(CNode* pfrom)
+{
+ CDataStream& vRecv = pfrom->vRecv;
+ if (vRecv.empty())
+ return true;
+ //if (fDebug)
+ // printf("ProcessMessages(%u bytes)\n", vRecv.size());
+ //
+ // Message format
+ // (4) message start
+ // (12) command
+ // (4) size
+ // (4) checksum
+ // (x) data
+ //
+ loop
+ {
+ // Scan for message start
+ CDataStream::iterator pstart = search(vRecv.begin(), vRecv.end(), BEGIN(pchMessageStart), END(pchMessageStart));
+ int nHeaderSize = vRecv.GetSerializeSize(CMessageHeader());
+ if (vRecv.end() - pstart < nHeaderSize)
+ {
+ if (vRecv.size() > nHeaderSize)
+ {
+ printf("\n\nPROCESSMESSAGE MESSAGESTART NOT FOUND\n\n");
+ vRecv.erase(vRecv.begin(), vRecv.end() - nHeaderSize);
+ }
+ break;
+ }
+ if (pstart - vRecv.begin() > 0)
+ printf("\n\nPROCESSMESSAGE SKIPPED %d BYTES\n\n", pstart - vRecv.begin());
+ vRecv.erase(vRecv.begin(), pstart);
+ // Read header
+ vector<char> vHeaderSave(vRecv.begin(), vRecv.begin() + nHeaderSize);
+ CMessageHeader hdr;
+ vRecv >> hdr;
+ if (!hdr.IsValid())
+ {
+ printf("\n\nPROCESSMESSAGE: ERRORS IN HEADER %s\n\n\n", hdr.GetCommand().c_str());
+ continue;
+ }
+ string strCommand = hdr.GetCommand();
+ // Message size
+ unsigned int nMessageSize = hdr.nMessageSize;
+ if (nMessageSize > MAX_SIZE)
+ {
+ printf("ProcessMessage(%s, %u bytes) : nMessageSize > MAX_SIZE\n", strCommand.c_str(), nMessageSize);
+ continue;
+ }
+ if (nMessageSize > vRecv.size())
+ {
+ // Rewind and wait for rest of message
+ vRecv.insert(vRecv.begin(), vHeaderSave.begin(), vHeaderSave.end());
+ break;
+ }
+ // Checksum
+ if (vRecv.GetVersion() >= 209)
+ {
+ uint256 hash = Hash(vRecv.begin(), vRecv.begin() + nMessageSize);
+ unsigned int nChecksum = 0;
+ memcpy(&nChecksum, &hash, sizeof(nChecksum));
+ if (nChecksum != hdr.nChecksum)
+ {
+ printf("ProcessMessage(%s, %u bytes) : CHECKSUM ERROR nChecksum=%08x hdr.nChecksum=%08x\n",
+ strCommand.c_str(), nMessageSize, nChecksum, hdr.nChecksum);
+ continue;
+ }
+ }
+ // Copy message to its own buffer
+ CDataStream vMsg(vRecv.begin(), vRecv.begin() + nMessageSize, vRecv.nType, vRecv.nVersion);
+ vRecv.ignore(nMessageSize);
+
+ // Process message
+ bool fRet = false;
+ try
+ {
+ CRITICAL_BLOCK(cs_main)
+ fRet = ProcessMessage(pfrom, strCommand, vMsg);
+ if (fShutdown)
+ return true;
+ }
+ catch (std::ios_base::failure& e)
+ {
+ if (strstr(e.what(), "end of data"))
+ {
+ // Allow exceptions from underlength message on vRecv
+ printf("ProcessMessage(%s, %u bytes) : Exception '%s' caught, normally caused by a message being shorter than its stated length\n", strCommand.c_str(), nMessageSize, e.what());
+ }
+ else if (strstr(e.what(), "size too large"))
+ {
+ // Allow exceptions from overlong size
+ printf("ProcessMessage(%s, %u bytes) : Exception '%s' caught\n", strCommand.c_str(), nMessageSize, e.what());
+ }
+ else
+ {
+ PrintExceptionContinue(&e, "ProcessMessage()");
+ }
+ }
+ catch (std::exception& e) {
+ PrintExceptionContinue(&e, "ProcessMessage()");
+ } catch (...) {
+ PrintExceptionContinue(NULL, "ProcessMessage()");
+ }
+
+ if (!fRet)
+ printf("ProcessMessage(%s, %u bytes) FAILED\n", strCommand.c_str(), nMessageSize);
+ }
+
+ vRecv.Compact();
+ return true;
+}
bool SendMessages(CNode* pto, bool fSendTrickle)
@@ -3030,16 +2514,10 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
// always trickle our own transactions
if (!fTrickleWait)
{
- TRY_CRITICAL_BLOCK(cs_mapWallet)
- {
- map<uint256, CWalletTx>::iterator mi = mapWallet.find(inv.hash);
- if (mi != mapWallet.end())
- {
- CWalletTx& wtx = (*mi).second;
- if (wtx.fFromMe)
- fTrickleWait = true;
- }
- }
+ CWalletTx wtx;
+ if (GetTransaction(inv.hash, wtx))
+ if (wtx.fFromMe)
+ fTrickleWait = true;
}
if (fTrickleWait)
@@ -3112,57 +2590,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
// BitcoinMiner
//
-void GenerateBitcoins(bool fGenerate)
-{
- if (fGenerateBitcoins != fGenerate)
- {
- fGenerateBitcoins = fGenerate;
- CWalletDB().WriteSetting("fGenerateBitcoins", fGenerateBitcoins);
- MainFrameRepaint();
- }
- if (fGenerateBitcoins)
- {
- int nProcessors = boost::thread::hardware_concurrency();
- printf("%d processors\n", nProcessors);
- if (nProcessors < 1)
- nProcessors = 1;
- if (fLimitProcessors && nProcessors > nLimitProcessors)
- nProcessors = nLimitProcessors;
- int nAddThreads = nProcessors - vnThreadsRunning[3];
- printf("Starting %d BitcoinMiner threads\n", nAddThreads);
- for (int i = 0; i < nAddThreads; i++)
- {
- if (!CreateThread(ThreadBitcoinMiner, NULL))
- printf("Error: CreateThread(ThreadBitcoinMiner) failed\n");
- Sleep(10);
- }
- }
-}
-
-void ThreadBitcoinMiner(void* parg)
-{
- try
- {
- vnThreadsRunning[3]++;
- BitcoinMiner();
- vnThreadsRunning[3]--;
- }
- catch (std::exception& e) {
- vnThreadsRunning[3]--;
- PrintException(&e, "ThreadBitcoinMiner()");
- } catch (...) {
- vnThreadsRunning[3]--;
- PrintException(NULL, "ThreadBitcoinMiner()");
- }
- UIThreadCall(boost::bind(CalledSetStatusBar, "", 0));
- nHPSTimerStart = 0;
- if (vnThreadsRunning[3] == 0)
- dHashesPerSec = 0;
- printf("ThreadBitcoinMiner exiting, %d threads remaining\n", vnThreadsRunning[3]);
-}
-
-
-int FormatHashBlocks(void* pbuffer, unsigned int len)
+int static FormatHashBlocks(void* pbuffer, unsigned int len)
{
unsigned char* pdata = (unsigned char*)pbuffer;
unsigned int blocks = 1 + ((len + 8) / 64);
@@ -3195,7 +2623,7 @@ inline void SHA256Transform(void* pstate, void* pinput, const void* pinit)
// between calls, but periodically or if nNonce is 0xffff0000 or above,
// the block is rebuilt and nNonce starts over at zero.
//
-unsigned int ScanHash_CryptoPP(char* pmidstate, char* pdata, char* phash1, char* phash, unsigned int& nHashesDone)
+unsigned int static ScanHash_CryptoPP(char* pmidstate, char* pdata, char* phash1, char* phash, unsigned int& nHashesDone)
{
unsigned int& nNonce = *(unsigned int*)(pdata + 12);
for (;;)
@@ -3452,7 +2880,7 @@ void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash
}
-bool CheckWork(CBlock* pblock, CReserveKey& reservekey)
+bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey)
{
uint256 hash = pblock->GetHash();
uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
@@ -3477,8 +2905,8 @@ bool CheckWork(CBlock* pblock, CReserveKey& reservekey)
reservekey.KeepKey();
// Track how many getdata requests this block gets
- CRITICAL_BLOCK(cs_mapRequestCount)
- mapRequestCount[pblock->GetHash()] = 0;
+ CRITICAL_BLOCK(wallet.cs_mapRequestCount)
+ wallet.mapRequestCount[pblock->GetHash()] = 0;
// Process this block the same as if we had received it from another node
if (!ProcessBlock(NULL, pblock))
@@ -3489,14 +2917,15 @@ bool CheckWork(CBlock* pblock, CReserveKey& reservekey)
return true;
}
+void static ThreadBitcoinMiner(void* parg);
-void BitcoinMiner()
+void static BitcoinMiner(CWallet *pwallet)
{
printf("BitcoinMiner started\n");
SetThreadPriority(THREAD_PRIORITY_LOWEST);
// Each thread has its own key and counter
- CReserveKey reservekey;
+ CReserveKey reservekey(pwallet);
unsigned int nExtraNonce = 0;
int64 nPrevTime = 0;
@@ -3572,7 +3001,7 @@ void BitcoinMiner()
assert(hash == pblock->GetHash());
SetThreadPriority(THREAD_PRIORITY_NORMAL);
- CheckWork(pblock.get(), reservekey);
+ CheckWork(pblock.get(), *pwalletMain, reservekey);
SetThreadPriority(THREAD_PRIORITY_LOWEST);
break;
}
@@ -3633,421 +3062,53 @@ void BitcoinMiner()
}
}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-//////////////////////////////////////////////////////////////////////////////
-//
-// Actions
-//
-
-
-int64 GetBalance()
-{
- int64 nStart = GetTimeMillis();
-
- int64 nTotal = 0;
- CRITICAL_BLOCK(cs_mapWallet)
- {
- for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
- {
- CWalletTx* pcoin = &(*it).second;
- if (!pcoin->IsFinal() || !pcoin->IsConfirmed())
- continue;
- nTotal += pcoin->GetAvailableCredit();
- }
- }
-
- //printf("GetBalance() %"PRI64d"ms\n", GetTimeMillis() - nStart);
- return nTotal;
-}
-
-
-bool SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, set<pair<CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet)
+void static ThreadBitcoinMiner(void* parg)
{
- setCoinsRet.clear();
- nValueRet = 0;
-
- // List of values less than target
- pair<int64, pair<CWalletTx*,unsigned int> > coinLowestLarger;
- coinLowestLarger.first = INT64_MAX;
- coinLowestLarger.second.first = NULL;
- vector<pair<int64, pair<CWalletTx*,unsigned int> > > vValue;
- int64 nTotalLower = 0;
-
- CRITICAL_BLOCK(cs_mapWallet)
- {
- vector<CWalletTx*> vCoins;
- vCoins.reserve(mapWallet.size());
- for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
- vCoins.push_back(&(*it).second);
- random_shuffle(vCoins.begin(), vCoins.end(), GetRandInt);
-
- BOOST_FOREACH(CWalletTx* pcoin, vCoins)
- {
- if (!pcoin->IsFinal() || !pcoin->IsConfirmed())
- continue;
-
- if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)
- continue;
-
- int nDepth = pcoin->GetDepthInMainChain();
- if (nDepth < (pcoin->IsFromMe() ? nConfMine : nConfTheirs))
- continue;
-
- for (int i = 0; i < pcoin->vout.size(); i++)
- {
- if (pcoin->IsSpent(i) || !pcoin->vout[i].IsMine())
- continue;
-
- int64 n = pcoin->vout[i].nValue;
-
- if (n <= 0)
- continue;
-
- pair<int64,pair<CWalletTx*,unsigned int> > coin = make_pair(n,make_pair(pcoin,i));
-
- if (n == nTargetValue)
- {
- setCoinsRet.insert(coin.second);
- nValueRet += coin.first;
- return true;
- }
- else if (n < nTargetValue + CENT)
- {
- vValue.push_back(coin);
- nTotalLower += n;
- }
- else if (n < coinLowestLarger.first)
- {
- coinLowestLarger = coin;
- }
- }
- }
- }
-
- if (nTotalLower == nTargetValue || nTotalLower == nTargetValue + CENT)
- {
- for (int i = 0; i < vValue.size(); ++i)
- {
- setCoinsRet.insert(vValue[i].second);
- nValueRet += vValue[i].first;
- }
- return true;
- }
-
- if (nTotalLower < nTargetValue + (coinLowestLarger.second.first ? CENT : 0))
- {
- if (coinLowestLarger.second.first == NULL)
- return false;
- setCoinsRet.insert(coinLowestLarger.second);
- nValueRet += coinLowestLarger.first;
- return true;
- }
-
- if (nTotalLower >= nTargetValue + CENT)
- nTargetValue += CENT;
-
- // Solve subset sum by stochastic approximation
- sort(vValue.rbegin(), vValue.rend());
- vector<char> vfIncluded;
- vector<char> vfBest(vValue.size(), true);
- int64 nBest = nTotalLower;
-
- for (int nRep = 0; nRep < 1000 && nBest != nTargetValue; nRep++)
- {
- vfIncluded.assign(vValue.size(), false);
- int64 nTotal = 0;
- bool fReachedTarget = false;
- for (int nPass = 0; nPass < 2 && !fReachedTarget; nPass++)
- {
- for (int i = 0; i < vValue.size(); i++)
- {
- if (nPass == 0 ? rand() % 2 : !vfIncluded[i])
- {
- nTotal += vValue[i].first;
- vfIncluded[i] = true;
- if (nTotal >= nTargetValue)
- {
- fReachedTarget = true;
- if (nTotal < nBest)
- {
- nBest = nTotal;
- vfBest = vfIncluded;
- }
- nTotal -= vValue[i].first;
- vfIncluded[i] = false;
- }
- }
- }
- }
- }
-
- // If the next larger is still closer, return it
- if (coinLowestLarger.second.first && coinLowestLarger.first - nTargetValue <= nBest - nTargetValue)
+ CWallet* pwallet = (CWallet*)parg;
+ try
{
- setCoinsRet.insert(coinLowestLarger.second);
- nValueRet += coinLowestLarger.first;
+ vnThreadsRunning[3]++;
+ BitcoinMiner(pwallet);
+ vnThreadsRunning[3]--;
}
- else {
- for (int i = 0; i < vValue.size(); i++)
- if (vfBest[i])
- {
- setCoinsRet.insert(vValue[i].second);
- nValueRet += vValue[i].first;
- }
-
- //// debug print
- printf("SelectCoins() best subset: ");
- for (int i = 0; i < vValue.size(); i++)
- if (vfBest[i])
- printf("%s ", FormatMoney(vValue[i].first).c_str());
- printf("total %s\n", FormatMoney(nBest).c_str());
+ catch (std::exception& e) {
+ vnThreadsRunning[3]--;
+ PrintException(&e, "ThreadBitcoinMiner()");
+ } catch (...) {
+ vnThreadsRunning[3]--;
+ PrintException(NULL, "ThreadBitcoinMiner()");
}
-
- return true;
-}
-
-bool SelectCoins(int64 nTargetValue, set<pair<CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet)
-{
- return (SelectCoinsMinConf(nTargetValue, 1, 6, setCoinsRet, nValueRet) ||
- SelectCoinsMinConf(nTargetValue, 1, 1, setCoinsRet, nValueRet) ||
- SelectCoinsMinConf(nTargetValue, 0, 1, setCoinsRet, nValueRet));
+ UIThreadCall(boost::bind(CalledSetStatusBar, "", 0));
+ nHPSTimerStart = 0;
+ if (vnThreadsRunning[3] == 0)
+ dHashesPerSec = 0;
+ printf("ThreadBitcoinMiner exiting, %d threads remaining\n", vnThreadsRunning[3]);
}
-
-
-bool CreateTransaction(const vector<pair<CScript, int64> >& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet)
+void GenerateBitcoins(bool fGenerate, CWallet* pwallet)
{
- int64 nValue = 0;
- BOOST_FOREACH (const PAIRTYPE(CScript, int64)& s, vecSend)
- {
- if (nValue < 0)
- return false;
- nValue += s.second;
- }
- if (vecSend.empty() || nValue < 0)
- return false;
-
- CRITICAL_BLOCK(cs_main)
+ if (fGenerateBitcoins != fGenerate)
{
- // txdb must be opened before the mapWallet lock
- CTxDB txdb("r");
- CRITICAL_BLOCK(cs_mapWallet)
- {
- nFeeRet = nTransactionFee;
- loop
- {
- wtxNew.vin.clear();
- wtxNew.vout.clear();
- wtxNew.fFromMe = true;
-
- int64 nTotalValue = nValue + nFeeRet;
- double dPriority = 0;
- // vouts to the payees
- BOOST_FOREACH (const PAIRTYPE(CScript, int64)& s, vecSend)
- wtxNew.vout.push_back(CTxOut(s.second, s.first));
-
- // Choose coins to use
- set<pair<CWalletTx*,unsigned int> > setCoins;
- int64 nValueIn = 0;
- if (!SelectCoins(nTotalValue, setCoins, nValueIn))
- return false;
- BOOST_FOREACH(PAIRTYPE(CWalletTx*, unsigned int) pcoin, setCoins)
- {
- int64 nCredit = pcoin.first->vout[pcoin.second].nValue;
- dPriority += (double)nCredit * pcoin.first->GetDepthInMainChain();
- }
-
- int64 nChange = nValueIn - nValue - nFeeRet;
-
- // if sub-cent change is required, the fee must be raised to at least MIN_TX_FEE
- // or until nChange becomes zero
- if (nFeeRet < MIN_TX_FEE && nChange > 0 && nChange < CENT)
- {
- int64 nMoveToFee = min(nChange, MIN_TX_FEE - nFeeRet);
- nChange -= nMoveToFee;
- nFeeRet += nMoveToFee;
- }
-
- if (nChange > 0)
- {
- // Note: We use a new key here to keep it from being obvious which side is the change.
- // The drawback is that by not reusing a previous key, the change may be lost if a
- // backup is restored, if the backup doesn't have the new private key for the change.
- // If we reused the old key, it would be possible to add code to look for and
- // rediscover unknown transactions that were written with keys of ours to recover
- // post-backup change.
-
- // Reserve a new key pair from key pool
- vector<unsigned char> vchPubKey = reservekey.GetReservedKey();
- assert(mapKeys.count(vchPubKey));
-
- // Fill a vout to ourself, using same address type as the payment
- CScript scriptChange;
- if (vecSend[0].first.GetBitcoinAddressHash160() != 0)
- scriptChange.SetBitcoinAddress(vchPubKey);
- else
- scriptChange << vchPubKey << OP_CHECKSIG;
-
- // Insert change txn at random position:
- vector<CTxOut>::iterator position = wtxNew.vout.begin()+GetRandInt(wtxNew.vout.size());
- wtxNew.vout.insert(position, CTxOut(nChange, scriptChange));
- }
- else
- reservekey.ReturnKey();
-
- // Fill vin
- BOOST_FOREACH(const PAIRTYPE(CWalletTx*,unsigned int)& coin, setCoins)
- wtxNew.vin.push_back(CTxIn(coin.first->GetHash(),coin.second));
-
- // Sign
- int nIn = 0;
- BOOST_FOREACH(const PAIRTYPE(CWalletTx*,unsigned int)& coin, setCoins)
- if (!SignSignature(*coin.first, wtxNew, nIn++))
- return false;
-
- // Limit size
- unsigned int nBytes = ::GetSerializeSize(*(CTransaction*)&wtxNew, SER_NETWORK);
- if (nBytes >= MAX_BLOCK_SIZE_GEN/5)
- return false;
- dPriority /= nBytes;
-
- // Check that enough fee is included
- int64 nPayFee = nTransactionFee * (1 + (int64)nBytes / 1000);
- bool fAllowFree = CTransaction::AllowFree(dPriority);
- int64 nMinFee = wtxNew.GetMinFee(1, fAllowFree);
- if (nFeeRet < max(nPayFee, nMinFee))
- {
- nFeeRet = max(nPayFee, nMinFee);
- continue;
- }
-
- // Fill vtxPrev by copying from previous transactions vtxPrev
- wtxNew.AddSupportingTransactions(txdb);
- wtxNew.fTimeReceivedIsTxTime = true;
-
- break;
- }
- }
+ fGenerateBitcoins = fGenerate;
+ WriteSetting("fGenerateBitcoins", fGenerateBitcoins);
+ MainFrameRepaint();
}
- return true;
-}
-
-bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet)
-{
- vector< pair<CScript, int64> > vecSend;
- vecSend.push_back(make_pair(scriptPubKey, nValue));
- return CreateTransaction(vecSend, wtxNew, reservekey, nFeeRet);
-}
-
-// Call after CreateTransaction unless you want to abort
-bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
-{
- CRITICAL_BLOCK(cs_main)
+ if (fGenerateBitcoins)
{
- printf("CommitTransaction:\n%s", wtxNew.ToString().c_str());
- CRITICAL_BLOCK(cs_mapWallet)
- {
- // This is only to keep the database open to defeat the auto-flush for the
- // duration of this scope. This is the only place where this optimization
- // maybe makes sense; please don't do it anywhere else.
- CWalletDB walletdb("r");
-
- // Take key pair from key pool so it won't be used again
- reservekey.KeepKey();
-
- // Add tx to wallet, because if it has change it's also ours,
- // otherwise just for transaction history.
- AddToWallet(wtxNew);
-
- // Mark old coins as spent
- set<CWalletTx*> setCoins;
- BOOST_FOREACH(const CTxIn& txin, wtxNew.vin)
- {
- CWalletTx &pcoin = mapWallet[txin.prevout.hash];
- pcoin.MarkSpent(txin.prevout.n);
- pcoin.WriteToDisk();
- vWalletUpdated.push_back(pcoin.GetHash());
- }
- }
-
- // Track how many getdata requests our transaction gets
- CRITICAL_BLOCK(cs_mapRequestCount)
- mapRequestCount[wtxNew.GetHash()] = 0;
-
- // Broadcast
- if (!wtxNew.AcceptToMemoryPool())
+ int nProcessors = boost::thread::hardware_concurrency();
+ printf("%d processors\n", nProcessors);
+ if (nProcessors < 1)
+ nProcessors = 1;
+ if (fLimitProcessors && nProcessors > nLimitProcessors)
+ nProcessors = nLimitProcessors;
+ int nAddThreads = nProcessors - vnThreadsRunning[3];
+ printf("Starting %d BitcoinMiner threads\n", nAddThreads);
+ for (int i = 0; i < nAddThreads; i++)
{
- // This must not fail. The transaction has already been signed and recorded.
- printf("CommitTransaction() : Error: Transaction not valid");
- return false;
+ if (!CreateThread(ThreadBitcoinMiner, pwallet))
+ printf("Error: CreateThread(ThreadBitcoinMiner) failed\n");
+ Sleep(10);
}
- wtxNew.RelayWalletTransaction();
- }
- MainFrameRepaint();
- return true;
-}
-
-
-
-
-// requires cs_main lock
-string SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAskFee)
-{
- CReserveKey reservekey;
- int64 nFeeRequired;
- if (!CreateTransaction(scriptPubKey, nValue, wtxNew, reservekey, nFeeRequired))
- {
- string strError;
- if (nValue + nFeeRequired > GetBalance())
- strError = strprintf(_("Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds "), FormatMoney(nFeeRequired).c_str());
- else
- strError = _("Error: Transaction creation failed ");
- printf("SendMoney() : %s", strError.c_str());
- return strError;
}
-
- if (fAskFee && !ThreadSafeAskFee(nFeeRequired, _("Sending..."), NULL))
- return "ABORTED";
-
- if (!CommitTransaction(wtxNew, reservekey))
- return _("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.");
-
- MainFrameRepaint();
- return "";
-}
-
-
-
-// requires cs_main lock
-string SendMoneyToBitcoinAddress(string strAddress, int64 nValue, CWalletTx& wtxNew, bool fAskFee)
-{
- // Check amount
- if (nValue <= 0)
- return _("Invalid amount");
- if (nValue + nTransactionFee > GetBalance())
- return _("Insufficient funds");
-
- // Parse bitcoin address
- CScript scriptPubKey;
- if (!scriptPubKey.SetBitcoinAddress(strAddress))
- return _("Invalid bitcoin address");
-
- return SendMoney(scriptPubKey, nValue, wtxNew, fAskFee);
}