diff options
author | Pieter Wuille <pieter.wuille@gmail.com> | 2011-06-01 18:27:05 +0200 |
---|---|---|
committer | Pieter Wuille <pieter.wuille@gmail.com> | 2011-06-15 11:05:55 +0200 |
commit | e89b9f6a2abaa120ff0fc3cea9ae364e8cbd25e4 (patch) | |
tree | ef0789aeadd8ff3e53c2705ea9153f0e612f689c /src/main.cpp | |
parent | 19ea44208f7c2cf335c654126deb81406036e328 (diff) |
move wallet code to separate file
This introduces two new source files, keystore.cpp and wallet.cpp with
corresponding headers. Code is moved from main and db, in a preparation
for a follow-up commit which introduces the classes CWallet and CKeyStore.
Diffstat (limited to 'src/main.cpp')
-rw-r--r-- | src/main.cpp | 1281 |
1 files changed, 165 insertions, 1116 deletions
diff --git a/src/main.cpp b/src/main.cpp index 108842f3a1..8949b97be6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -54,6 +54,9 @@ CCriticalSection cs_mapRequestCount; map<string, string> mapAddressBook; CCriticalSection cs_mapAddressBook; +set<int64> setKeyPool; +CCriticalSection cs_setKeyPool; + vector<unsigned char> vchDefaultKey; double dHashesPerSec; @@ -81,160 +84,6 @@ int fUseUPnP = false; ////////////////////////////////////////////////////////////////////////////// // -// mapKeys -// - -bool AddKey(const CKey& key) -{ - CRITICAL_BLOCK(cs_mapKeys) - { - mapKeys[key.GetPubKey()] = key.GetPrivKey(); - mapPubKeys[Hash160(key.GetPubKey())] = key.GetPubKey(); - } - return CWalletDB().WriteKey(key.GetPubKey(), key.GetPrivKey()); -} - -vector<unsigned char> GenerateNewKey() -{ - RandAddSeedPerfmon(); - CKey key; - key.MakeNewKey(); - if (!AddKey(key)) - throw runtime_error("GenerateNewKey() : AddKey failed"); - return key.GetPubKey(); -} - - - - -////////////////////////////////////////////////////////////////////////////// -// -// mapWallet -// - -bool AddToWallet(const CWalletTx& wtxIn) -{ - 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" : "")); - - // Write to disk - if (fInsertedNew || fUpdated) - if (!wtx.WriteToDisk()) - 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), ""); - } - } - - // Notify UI - vWalletUpdated.push_back(hash); - } - - // Refresh UI - MainFrameRepaint(); - return true; -} - -bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate = false) -{ - 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; -} - -bool EraseFromWallet(uint256 hash) -{ - CRITICAL_BLOCK(cs_mapWallet) - { - if (mapWallet.erase(hash)) - CWalletDB().EraseTx(hash); - } - return true; -} - -void WalletUpdateSpent(const COutPoint& prevout) -{ - // 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); - } - } - } -} - - - - - - - - -////////////////////////////////////////////////////////////////////////////// -// // mapOrphanTransactions // @@ -312,190 +161,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) @@ -551,69 +216,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()); -} - - - - - - - @@ -784,6 +386,11 @@ bool CTransaction::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs, bool* pfMi return true; } +bool CTransaction::AcceptToMemoryPool(bool fCheckInputs, bool* pfMissingInputs) +{ + CTxDB txdb("r"); + return AcceptToMemoryPool(txdb, fCheckInputs, pfMissingInputs); +} bool CTransaction::AddToMemoryPoolUnchecked() { @@ -867,6 +474,12 @@ bool CMerkleTx::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs) } } +bool CMerkleTx::AcceptToMemoryPool() +{ + CTxDB txdb("r"); + return AcceptToMemoryPool(txdb); +} + bool CWalletTx::AcceptWalletTransaction(CTxDB& txdb, bool fCheckInputs) @@ -888,148 +501,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 @@ -1076,6 +551,7 @@ bool CBlock::ReadFromDisk(const CBlockIndex* pindex, bool fReadTransactions) return true; } + uint256 GetOrphanRoot(const CBlock* pblock) { // Work back to the first block in the orphan chain @@ -2221,127 +1697,6 @@ 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) { static map<unsigned int, vector<unsigned char> > mapReuseKey; @@ -2885,9 +2240,123 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) } +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; +} @@ -3096,56 +2565,6 @@ 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) { unsigned char* pdata = (unsigned char*)pbuffer; @@ -3473,7 +2892,6 @@ bool CheckWork(CBlock* pblock, CReserveKey& reservekey) return true; } - void BitcoinMiner() { printf("BitcoinMiner started\n"); @@ -3617,421 +3035,52 @@ 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 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) + try { - setCoinsRet.insert(coinLowestLarger.second); - nValueRet += coinLowestLarger.first; + vnThreadsRunning[3]++; + BitcoinMiner(); + 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) { - 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; + CWalletDB().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, NULL)) + 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); } |