diff options
Diffstat (limited to 'src')
60 files changed, 1263 insertions, 1243 deletions
diff --git a/src/addrman.cpp b/src/addrman.cpp index 8fb40b46df..345261e229 100644 --- a/src/addrman.cpp +++ b/src/addrman.cpp @@ -8,12 +8,12 @@ using namespace std; int CAddrInfo::GetTriedBucket(const std::vector<unsigned char> &nKey) const { - CDataStream ss1(SER_GETHASH); + CDataStream ss1(SER_GETHASH, 0); std::vector<unsigned char> vchKey = GetKey(); ss1 << nKey << vchKey; uint64 hash1 = Hash(ss1.begin(), ss1.end()).Get64(); - CDataStream ss2(SER_GETHASH); + CDataStream ss2(SER_GETHASH, 0); std::vector<unsigned char> vchGroupKey = GetGroup(); ss2 << nKey << vchGroupKey << (hash1 % ADDRMAN_TRIED_BUCKETS_PER_GROUP); uint64 hash2 = Hash(ss2.begin(), ss2.end()).Get64(); @@ -22,13 +22,13 @@ int CAddrInfo::GetTriedBucket(const std::vector<unsigned char> &nKey) const int CAddrInfo::GetNewBucket(const std::vector<unsigned char> &nKey, const CNetAddr& src) const { - CDataStream ss1(SER_GETHASH); + CDataStream ss1(SER_GETHASH, 0); std::vector<unsigned char> vchGroupKey = GetGroup(); std::vector<unsigned char> vchSourceGroupKey = src.GetGroup(); ss1 << nKey << vchGroupKey << vchSourceGroupKey; uint64 hash1 = Hash(ss1.begin(), ss1.end()).Get64(); - CDataStream ss2(SER_GETHASH); + CDataStream ss2(SER_GETHASH, 0); ss2 << nKey << vchSourceGroupKey << (hash1 % ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP); uint64 hash2 = Hash(ss2.begin(), ss2.end()).Get64(); return hash2 % ADDRMAN_NEW_BUCKET_COUNT; @@ -124,7 +124,7 @@ int CAddrMan::SelectTried(int nKBucket) // random shuffle the first few elements (using the entire list) // find the least recently tried among them int64 nOldest = -1; - for (int i=0; i<ADDRMAN_TRIED_ENTRIES_INSPECT_ON_EVICT && i<vTried.size(); i++) + for (unsigned int i = 0; i < ADDRMAN_TRIED_ENTRIES_INSPECT_ON_EVICT && i < vTried.size(); i++) { int nPos = GetRandInt(vTried.size() - i) + i; int nTemp = vTried[nPos]; @@ -270,7 +270,7 @@ void CAddrMan::Good_(const CService &addr, int64 nTime) // find a bucket it is in now int nRnd = GetRandInt(vvNew.size()); int nUBucket = -1; - for (int n = 0; n < vvNew.size(); n++) + for (unsigned int n = 0; n < vvNew.size(); n++) { int nB = (n+nRnd) % vvNew.size(); std::set<int> &vNew = vvNew[nB]; diff --git a/src/allocators.h b/src/allocators.h index 85d9cfbbb8..cdea66dd38 100644 --- a/src/allocators.h +++ b/src/allocators.h @@ -8,6 +8,9 @@ #include <string> #ifdef WIN32 +#ifdef _WIN32_WINNT +#undef _WIN32_WINNT +#endif #define _WIN32_WINNT 0x0501 #define WIN32_LEAN_AND_MEAN 1 #ifndef NOMINMAX diff --git a/src/base58.h b/src/base58.h index 7fefbc5d74..90ce34b05b 100644 --- a/src/base58.h +++ b/src/base58.h @@ -288,7 +288,7 @@ public: bool IsValid() const { - int nExpectedSize = 20; + unsigned int nExpectedSize = 20; bool fExpectTestNet = false; switch(nVersion) { diff --git a/src/bignum.h b/src/bignum.h index daf5f6883a..cea8e1e357 100644 --- a/src/bignum.h +++ b/src/bignum.h @@ -9,7 +9,7 @@ #include <vector> #include <openssl/bn.h> -#include "util.h" +#include "util.h" // for uint64 /** Errors thrown by the bignum class */ class bignum_error : public std::runtime_error diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index 63c51ada8d..3c2d69e506 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -3,10 +3,14 @@ // Distributed under the MIT/X11 software license, see the accompanying // file license.txt or http://www.opensource.org/licenses/mit-license.php. -#include "headers.h" +#include "main.h" +#include "wallet.h" #include "db.h" +#include "walletdb.h" #include "net.h" #include "init.h" +#include "ui_interface.h" + #undef printf #include <boost/asio.hpp> #include <boost/filesystem.hpp> @@ -138,7 +142,7 @@ Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex) { Object result; result.push_back(Pair("hash", block.GetHash().GetHex())); - result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK))); + result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION))); result.push_back(Pair("height", blockindex->nHeight)); result.push_back(Pair("version", block.nVersion)); result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex())); @@ -201,7 +205,7 @@ Value help(const Array& params, bool fHelp) // Help text is returned in an exception string strHelp = string(e.what()); if (strCommand == "") - if (strHelp.find('\n') != -1) + if (strHelp.find('\n') != string::npos) strHelp = strHelp.substr(0, strHelp.find('\n')); strRet += strHelp + "\n"; } @@ -363,7 +367,7 @@ Value getmininginfo(const Array& params, bool fHelp) obj.push_back(Pair("generate", GetBoolArg("-gen"))); obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", -1))); obj.push_back(Pair("hashespersec", gethashespersec(params, false))); - obj.push_back(Pair("pooledtx", (uint64_t)nPooledTx)); + obj.push_back(Pair("pooledtx", (uint64_t)mempool.size())); obj.push_back(Pair("testnet", fTestNet)); return obj; } @@ -598,7 +602,7 @@ Value signmessage(const Array& params, bool fHelp) if (!pwalletMain->GetKey(addr, key)) throw JSONRPCError(-4, "Private key not available"); - CDataStream ss(SER_GETHASH); + CDataStream ss(SER_GETHASH, 0); ss << strMessageMagic; ss << strMessage; @@ -630,7 +634,7 @@ Value verifymessage(const Array& params, bool fHelp) if (fInvalid) throw JSONRPCError(-5, "Malformed base64 encoding"); - CDataStream ss(SER_GETHASH); + CDataStream ss(SER_GETHASH, 0); ss << strMessageMagic; ss << strMessage; @@ -1000,7 +1004,7 @@ Value addmultisigaddress(const Array& params, bool fHelp) "(got %d, need at least %d)", keys.size(), nRequired)); std::vector<CKey> pubkeys; pubkeys.resize(keys.size()); - for (int i = 0; i < keys.size(); i++) + for (unsigned int i = 0; i < keys.size(); i++) { const std::string& ks = keys[i].get_str(); @@ -1917,7 +1921,7 @@ Value getmemorypool(const Array& params, bool fHelp) if(tx.IsCoinBase()) continue; - CDataStream ssTx; + CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); ssTx << tx; transactions.push_back(HexStr(ssTx.begin(), ssTx.end())); @@ -1939,7 +1943,7 @@ Value getmemorypool(const Array& params, bool fHelp) else { // Parse parameters - CDataStream ssBlock(ParseHex(params[0].get_str())); + CDataStream ssBlock(ParseHex(params[0].get_str()), SER_NETWORK, PROTOCOL_VERSION); CBlock pblock; ssBlock >> pblock; diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp index f5ce053870..cf56fa0695 100644 --- a/src/checkpoints.cpp +++ b/src/checkpoints.cpp @@ -5,9 +5,11 @@ #include <boost/assign/list_of.hpp> // for 'map_list_of()' #include <boost/foreach.hpp> -#include "headers.h" #include "checkpoints.h" +#include "main.h" +#include "uint256.h" + namespace Checkpoints { typedef std::map<int, uint256> MapCheckpoints; diff --git a/src/checkpoints.h b/src/checkpoints.h index 38902ac0a1..5d3228f3fc 100644 --- a/src/checkpoints.h +++ b/src/checkpoints.h @@ -5,7 +5,6 @@ #define BITCOIN_CHECKPOINT_H #include <map> -#include "util.h" class uint256; class CBlockIndex; diff --git a/src/compat.h b/src/compat.h index 882610031a..db340445b2 100644 --- a/src/compat.h +++ b/src/compat.h @@ -5,6 +5,28 @@ #ifndef _BITCOIN_COMPAT_H #define _BITCOIN_COMPAT_H 1 +#ifdef WIN32 +#define _WIN32_WINNT 0x0501 +#define WIN32_LEAN_AND_MEAN 1 +#ifndef NOMINMAX +#define NOMINMAX +#endif +#include <winsock2.h> +#include <mswsock.h> +#include <ws2tcpip.h> +#else +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/fcntl.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <net/if.h> +#include <ifaddrs.h> +#endif +#ifdef BSD +#include <netinet/in.h> +#endif + typedef u_int SOCKET; #ifdef WIN32 #define MSG_NOSIGNAL 0 @@ -39,4 +61,5 @@ inline int myclosesocket(SOCKET& hSocket) } #define closesocket(s) myclosesocket(s) + #endif diff --git a/src/crypter.cpp b/src/crypter.cpp index 83041addb4..4f37575a6a 100644 --- a/src/crypter.cpp +++ b/src/crypter.cpp @@ -6,14 +6,11 @@ #include <openssl/evp.h> #include <vector> #include <string> -#include "headers.h" #ifdef WIN32 #include <windows.h> #endif #include "crypter.h" -#include "main.h" -#include "util.h" bool CCrypter::SetKeyFromPassphrase(const SecureString& strKeyData, const std::vector<unsigned char>& chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod) { @@ -31,7 +28,7 @@ bool CCrypter::SetKeyFromPassphrase(const SecureString& strKeyData, const std::v i = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha512(), &chSalt[0], (unsigned char *)&strKeyData[0], strKeyData.size(), nRounds, chKey, chIV); - if (i != WALLET_CRYPTO_KEY_SIZE) + if (i != (int)WALLET_CRYPTO_KEY_SIZE) { memset(&chKey, 0, sizeof chKey); memset(&chIV, 0, sizeof chIV); diff --git a/src/crypter.h b/src/crypter.h index 59a005a220..d1bdb92c91 100644 --- a/src/crypter.h +++ b/src/crypter.h @@ -6,6 +6,7 @@ #include "allocators.h" /* for SecureString */ #include "key.h" +#include "serialize.h" const unsigned int WALLET_CRYPTO_KEY_SIZE = 32; const unsigned int WALLET_CRYPTO_SALT_SIZE = 8; diff --git a/src/db.cpp b/src/db.cpp index 0652e4a8f6..c38070f347 100644 --- a/src/db.cpp +++ b/src/db.cpp @@ -3,19 +3,22 @@ // Distributed under the MIT/X11 software license, see the accompanying // file license.txt or http://www.opensource.org/licenses/mit-license.php. -#include "headers.h" #include "db.h" -#include "net.h" +#include "util.h" +#include "main.h" #include <boost/version.hpp> #include <boost/filesystem.hpp> #include <boost/filesystem/fstream.hpp> +#ifndef WIN32 +#include "sys/stat.h" +#endif + using namespace std; using namespace boost; unsigned int nWalletDBUpdated; -uint64 nAccountingEntryNumber = 0; @@ -23,10 +26,10 @@ uint64 nAccountingEntryNumber = 0; // CDB // -static CCriticalSection cs_db; +CCriticalSection cs_db; static bool fDbEnvInit = false; DbEnv dbenv(0); -static map<string, int> mapFileUseCount; +map<string, int> mapFileUseCount; static map<string, Db*> mapDb; static void EnvShutdown() @@ -175,7 +178,7 @@ void CDB::Close() } } -void static CloseDb(const string& strFile) +void CloseDb(const string& strFile) { { LOCK(cs_db); @@ -227,8 +230,8 @@ bool CDB::Rewrite(const string& strFile, const char* pszSkip) if (pcursor) while (fSuccess) { - CDataStream ssKey; - CDataStream ssValue; + CDataStream ssKey(SER_DISK, CLIENT_VERSION); + CDataStream ssValue(SER_DISK, CLIENT_VERSION); int ret = db.ReadAtCursor(pcursor, ssKey, ssValue, DB_NEXT); if (ret == DB_NOTFOUND) { @@ -384,10 +387,10 @@ bool CTxDB::ReadOwnerTxes(uint160 hash160, int nMinHeight, vector<CTransaction>& loop { // Read next record - CDataStream ssKey; + CDataStream ssKey(SER_DISK, CLIENT_VERSION); if (fFlags == DB_SET_RANGE) ssKey << string("owner") << hash160 << CDiskTxPos(0, 0, 0); - CDataStream ssValue; + CDataStream ssValue(SER_DISK, CLIENT_VERSION); int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags); fFlags = DB_NEXT; if (ret == DB_NOTFOUND) @@ -512,10 +515,10 @@ bool CTxDB::LoadBlockIndex() loop { // Read next record - CDataStream ssKey; + CDataStream ssKey(SER_DISK, CLIENT_VERSION); if (fFlags == DB_SET_RANGE) ssKey << make_pair(string("blockindex"), uint256(0)); - CDataStream ssValue; + CDataStream ssValue(SER_DISK, CLIENT_VERSION); int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags); fFlags = DB_NEXT; if (ret == DB_NOTFOUND) @@ -752,8 +755,8 @@ bool CAddrDB::LoadAddresses() loop { // Read next record - CDataStream ssKey; - CDataStream ssValue; + CDataStream ssKey(SER_DISK, CLIENT_VERSION); + CDataStream ssValue(SER_DISK, CLIENT_VERSION); int ret = ReadAtCursor(pcursor, ssKey, ssValue); if (ret == DB_NOTFOUND) break; @@ -788,414 +791,3 @@ bool LoadAddresses() } - - -// -// CWalletDB -// - -bool CWalletDB::WriteName(const string& strAddress, const string& strName) -{ - nWalletDBUpdated++; - return Write(make_pair(string("name"), strAddress), strName); -} - -bool CWalletDB::EraseName(const string& strAddress) -{ - // This should only be used for sending addresses, never for receiving addresses, - // receiving addresses must always have an address book entry if they're not change return. - nWalletDBUpdated++; - return Erase(make_pair(string("name"), strAddress)); -} - -bool CWalletDB::ReadAccount(const string& strAccount, CAccount& account) -{ - account.SetNull(); - return Read(make_pair(string("acc"), strAccount), account); -} - -bool CWalletDB::WriteAccount(const string& strAccount, const CAccount& account) -{ - return Write(make_pair(string("acc"), strAccount), account); -} - -bool CWalletDB::WriteAccountingEntry(const CAccountingEntry& acentry) -{ - return Write(boost::make_tuple(string("acentry"), acentry.strAccount, ++nAccountingEntryNumber), acentry); -} - -int64 CWalletDB::GetAccountCreditDebit(const string& strAccount) -{ - list<CAccountingEntry> entries; - ListAccountCreditDebit(strAccount, entries); - - int64 nCreditDebit = 0; - BOOST_FOREACH (const CAccountingEntry& entry, entries) - nCreditDebit += entry.nCreditDebit; - - return nCreditDebit; -} - -void CWalletDB::ListAccountCreditDebit(const string& strAccount, list<CAccountingEntry>& entries) -{ - bool fAllAccounts = (strAccount == "*"); - - Dbc* pcursor = GetCursor(); - if (!pcursor) - throw runtime_error("CWalletDB::ListAccountCreditDebit() : cannot create DB cursor"); - unsigned int fFlags = DB_SET_RANGE; - loop - { - // Read next record - CDataStream ssKey; - if (fFlags == DB_SET_RANGE) - ssKey << boost::make_tuple(string("acentry"), (fAllAccounts? string("") : strAccount), uint64(0)); - CDataStream ssValue; - int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags); - fFlags = DB_NEXT; - if (ret == DB_NOTFOUND) - break; - else if (ret != 0) - { - pcursor->close(); - throw runtime_error("CWalletDB::ListAccountCreditDebit() : error scanning DB"); - } - - // Unserialize - string strType; - ssKey >> strType; - if (strType != "acentry") - break; - CAccountingEntry acentry; - ssKey >> acentry.strAccount; - if (!fAllAccounts && acentry.strAccount != strAccount) - break; - - ssValue >> acentry; - entries.push_back(acentry); - } - - pcursor->close(); -} - - -int CWalletDB::LoadWallet(CWallet* pwallet) -{ - pwallet->vchDefaultKey.clear(); - int nFileVersion = 0; - vector<uint256> vWalletUpgrade; - bool fIsEncrypted = false; - - //// todo: shouldn't we catch exceptions and try to recover and continue? - { - LOCK(pwallet->cs_wallet); - int nMinVersion = 0; - if (Read((string)"minversion", nMinVersion)) - { - if (nMinVersion > CLIENT_VERSION) - return DB_TOO_NEW; - pwallet->LoadMinVersion(nMinVersion); - } - - // Get cursor - Dbc* pcursor = GetCursor(); - if (!pcursor) - { - printf("Error getting wallet database cursor\n"); - return DB_CORRUPT; - } - - loop - { - // Read next record - CDataStream ssKey; - CDataStream ssValue; - int ret = ReadAtCursor(pcursor, ssKey, ssValue); - if (ret == DB_NOTFOUND) - break; - else if (ret != 0) - { - printf("Error reading next record from wallet database\n"); - return DB_CORRUPT; - } - - // Unserialize - // Taking advantage of the fact that pair serialization - // is just the two items serialized one after the other - string strType; - ssKey >> strType; - if (strType == "name") - { - string strAddress; - ssKey >> strAddress; - ssValue >> pwallet->mapAddressBook[strAddress]; - } - else if (strType == "tx") - { - uint256 hash; - ssKey >> hash; - CWalletTx& wtx = pwallet->mapWallet[hash]; - ssValue >> wtx; - wtx.BindWallet(pwallet); - - if (wtx.GetHash() != hash) - printf("Error in wallet.dat, hash mismatch\n"); - - // Undo serialize changes in 31600 - if (31404 <= wtx.fTimeReceivedIsTxTime && wtx.fTimeReceivedIsTxTime <= 31703) - { - if (!ssValue.empty()) - { - char fTmp; - char fUnused; - ssValue >> fTmp >> fUnused >> wtx.strFromAccount; - printf("LoadWallet() upgrading tx ver=%d %d '%s' %s\n", wtx.fTimeReceivedIsTxTime, fTmp, wtx.strFromAccount.c_str(), hash.ToString().c_str()); - wtx.fTimeReceivedIsTxTime = fTmp; - } - else - { - printf("LoadWallet() repairing tx ver=%d %s\n", wtx.fTimeReceivedIsTxTime, hash.ToString().c_str()); - wtx.fTimeReceivedIsTxTime = 0; - } - vWalletUpgrade.push_back(hash); - } - - //// debug print - //printf("LoadWallet %s\n", wtx.GetHash().ToString().c_str()); - //printf(" %12I64d %s %s %s\n", - // wtx.vout[0].nValue, - // DateTimeStrFormat("%x %H:%M:%S", wtx.GetBlockTime()).c_str(), - // wtx.hashBlock.ToString().substr(0,20).c_str(), - // wtx.mapValue["message"].c_str()); - } - else if (strType == "acentry") - { - string strAccount; - ssKey >> strAccount; - uint64 nNumber; - ssKey >> nNumber; - if (nNumber > nAccountingEntryNumber) - nAccountingEntryNumber = nNumber; - } - else if (strType == "key" || strType == "wkey") - { - vector<unsigned char> vchPubKey; - ssKey >> vchPubKey; - CKey key; - if (strType == "key") - { - CPrivKey pkey; - ssValue >> pkey; - key.SetPubKey(vchPubKey); - key.SetPrivKey(pkey); - if (key.GetPubKey() != vchPubKey) - { - printf("Error reading wallet database: CPrivKey pubkey inconsistency\n"); - return DB_CORRUPT; - } - if (!key.IsValid()) - { - printf("Error reading wallet database: invalid CPrivKey\n"); - return DB_CORRUPT; - } - } - else - { - CWalletKey wkey; - ssValue >> wkey; - key.SetPubKey(vchPubKey); - key.SetPrivKey(wkey.vchPrivKey); - if (key.GetPubKey() != vchPubKey) - { - printf("Error reading wallet database: CWalletKey pubkey inconsistency\n"); - return DB_CORRUPT; - } - if (!key.IsValid()) - { - printf("Error reading wallet database: invalid CWalletKey\n"); - return DB_CORRUPT; - } - } - if (!pwallet->LoadKey(key)) - { - printf("Error reading wallet database: LoadKey failed\n"); - return DB_CORRUPT; - } - } - else if (strType == "mkey") - { - unsigned int nID; - ssKey >> nID; - CMasterKey kMasterKey; - ssValue >> kMasterKey; - if(pwallet->mapMasterKeys.count(nID) != 0) - { - printf("Error reading wallet database: duplicate CMasterKey id %u\n", nID); - return DB_CORRUPT; - } - pwallet->mapMasterKeys[nID] = kMasterKey; - if (pwallet->nMasterKeyMaxID < nID) - pwallet->nMasterKeyMaxID = nID; - } - else if (strType == "ckey") - { - vector<unsigned char> vchPubKey; - ssKey >> vchPubKey; - vector<unsigned char> vchPrivKey; - ssValue >> vchPrivKey; - if (!pwallet->LoadCryptedKey(vchPubKey, vchPrivKey)) - { - printf("Error reading wallet database: LoadCryptedKey failed\n"); - return DB_CORRUPT; - } - fIsEncrypted = true; - } - else if (strType == "defaultkey") - { - ssValue >> pwallet->vchDefaultKey; - } - else if (strType == "pool") - { - int64 nIndex; - ssKey >> nIndex; - pwallet->setKeyPool.insert(nIndex); - } - else if (strType == "version") - { - ssValue >> nFileVersion; - if (nFileVersion == 10300) - nFileVersion = 300; - } - else if (strType == "cscript") - { - uint160 hash; - ssKey >> hash; - CScript script; - ssValue >> script; - if (!pwallet->LoadCScript(script)) - { - printf("Error reading wallet database: LoadCScript failed\n"); - return DB_CORRUPT; - } - } - } - pcursor->close(); - } - - BOOST_FOREACH(uint256 hash, vWalletUpgrade) - WriteTx(hash, pwallet->mapWallet[hash]); - - printf("nFileVersion = %d\n", nFileVersion); - - - // Rewrite encrypted wallets of versions 0.4.0 and 0.5.0rc: - if (fIsEncrypted && (nFileVersion == 40000 || nFileVersion == 50000)) - return DB_NEED_REWRITE; - - if (nFileVersion < CLIENT_VERSION) // Update - WriteVersion(CLIENT_VERSION); - - return DB_LOAD_OK; -} - -void ThreadFlushWalletDB(void* parg) -{ - const string& strFile = ((const string*)parg)[0]; - static bool fOneThread; - if (fOneThread) - return; - fOneThread = true; - if (!GetBoolArg("-flushwallet", true)) - return; - - unsigned int nLastSeen = nWalletDBUpdated; - unsigned int nLastFlushed = nWalletDBUpdated; - int64 nLastWalletUpdate = GetTime(); - while (!fShutdown) - { - Sleep(500); - - if (nLastSeen != nWalletDBUpdated) - { - nLastSeen = nWalletDBUpdated; - nLastWalletUpdate = GetTime(); - } - - if (nLastFlushed != nWalletDBUpdated && GetTime() - nLastWalletUpdate >= 2) - { - TRY_LOCK(cs_db,lockDb); - if (lockDb) - { - // Don't do this if any databases are in use - int nRefCount = 0; - map<string, int>::iterator mi = mapFileUseCount.begin(); - while (mi != mapFileUseCount.end()) - { - nRefCount += (*mi).second; - mi++; - } - - if (nRefCount == 0 && !fShutdown) - { - map<string, int>::iterator mi = mapFileUseCount.find(strFile); - if (mi != mapFileUseCount.end()) - { - printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str()); - printf("Flushing wallet.dat\n"); - nLastFlushed = nWalletDBUpdated; - int64 nStart = GetTimeMillis(); - - // Flush wallet.dat so it's self contained - CloseDb(strFile); - dbenv.txn_checkpoint(0, 0, 0); - dbenv.lsn_reset(strFile.c_str(), 0); - - mapFileUseCount.erase(mi++); - printf("Flushed wallet.dat %"PRI64d"ms\n", GetTimeMillis() - nStart); - } - } - } - } - } -} - -bool BackupWallet(const CWallet& wallet, const string& strDest) -{ - if (!wallet.fFileBacked) - return false; - while (!fShutdown) - { - { - LOCK(cs_db); - if (!mapFileUseCount.count(wallet.strWalletFile) || mapFileUseCount[wallet.strWalletFile] == 0) - { - // Flush log data to the dat file - CloseDb(wallet.strWalletFile); - dbenv.txn_checkpoint(0, 0, 0); - dbenv.lsn_reset(wallet.strWalletFile.c_str(), 0); - mapFileUseCount.erase(wallet.strWalletFile); - - // Copy wallet.dat - filesystem::path pathSrc = GetDataDir() / wallet.strWalletFile; - filesystem::path pathDest(strDest); - if (filesystem::is_directory(pathDest)) - pathDest /= wallet.strWalletFile; - - try { -#if BOOST_VERSION >= 104000 - filesystem::copy_file(pathSrc, pathDest, filesystem::copy_option::overwrite_if_exists); -#else - filesystem::copy_file(pathSrc, pathDest); -#endif - printf("copied wallet.dat to %s\n", pathDest.string().c_str()); - return true; - } catch(const filesystem::filesystem_error &e) { - printf("error copying wallet.dat to %s - %s\n", pathDest.string().c_str(), e.what()); - return false; - } - } - } - Sleep(100); - } - return false; -} @@ -5,7 +5,7 @@ #ifndef BITCOIN_DB_H #define BITCOIN_DB_H -#include "key.h" +#include "main.h" #include <map> #include <string> @@ -13,8 +13,6 @@ #include <db_cxx.h> -class CAccount; -class CAccountingEntry; class CAddress; class CAddrMan; class CBlockLocator; @@ -59,7 +57,7 @@ protected: return false; // Key - CDataStream ssKey(SER_DISK); + CDataStream ssKey(SER_DISK, CLIENT_VERSION); ssKey.reserve(1000); ssKey << key; Dbt datKey(&ssKey[0], ssKey.size()); @@ -73,7 +71,7 @@ protected: return false; // Unserialize value - CDataStream ssValue((char*)datValue.get_data(), (char*)datValue.get_data() + datValue.get_size(), SER_DISK); + CDataStream ssValue((char*)datValue.get_data(), (char*)datValue.get_data() + datValue.get_size(), SER_DISK, CLIENT_VERSION); ssValue >> value; // Clear and free memory @@ -91,13 +89,13 @@ protected: assert(!"Write called on database in read-only mode"); // Key - CDataStream ssKey(SER_DISK); + CDataStream ssKey(SER_DISK, CLIENT_VERSION); ssKey.reserve(1000); ssKey << key; Dbt datKey(&ssKey[0], ssKey.size()); // Value - CDataStream ssValue(SER_DISK); + CDataStream ssValue(SER_DISK, CLIENT_VERSION); ssValue.reserve(10000); ssValue << value; Dbt datValue(&ssValue[0], ssValue.size()); @@ -120,7 +118,7 @@ protected: assert(!"Erase called on database in read-only mode"); // Key - CDataStream ssKey(SER_DISK); + CDataStream ssKey(SER_DISK, CLIENT_VERSION); ssKey.reserve(1000); ssKey << key; Dbt datKey(&ssKey[0], ssKey.size()); @@ -140,7 +138,7 @@ protected: return false; // Key - CDataStream ssKey(SER_DISK); + CDataStream ssKey(SER_DISK, CLIENT_VERSION); ssKey.reserve(1000); ssKey << key; Dbt datKey(&ssKey[0], ssKey.size()); @@ -313,198 +311,4 @@ public: bool LoadAddresses(); -/** A key pool entry */ -class CKeyPool -{ -public: - int64 nTime; - std::vector<unsigned char> vchPubKey; - - CKeyPool() - { - nTime = GetTime(); - } - - CKeyPool(const std::vector<unsigned char>& vchPubKeyIn) - { - nTime = GetTime(); - vchPubKey = vchPubKeyIn; - } - - IMPLEMENT_SERIALIZE - ( - if (!(nType & SER_GETHASH)) - READWRITE(nVersion); - READWRITE(nTime); - READWRITE(vchPubKey); - ) -}; - - - -/** Error statuses for the wallet database */ -enum DBErrors -{ - DB_LOAD_OK, - DB_CORRUPT, - DB_TOO_NEW, - DB_LOAD_FAIL, - DB_NEED_REWRITE -}; - -/** Access to the wallet database (wallet.dat) */ -class CWalletDB : public CDB -{ -public: - CWalletDB(std::string strFilename, const char* pszMode="r+") : CDB(strFilename.c_str(), pszMode) - { - } -private: - CWalletDB(const CWalletDB&); - void operator=(const CWalletDB&); -public: - bool ReadName(const std::string& strAddress, std::string& strName) - { - strName = ""; - return Read(std::make_pair(std::string("name"), strAddress), strName); - } - - bool WriteName(const std::string& strAddress, const std::string& strName); - - bool EraseName(const std::string& strAddress); - - bool ReadTx(uint256 hash, CWalletTx& wtx) - { - return Read(std::make_pair(std::string("tx"), hash), wtx); - } - - bool WriteTx(uint256 hash, const CWalletTx& wtx) - { - nWalletDBUpdated++; - return Write(std::make_pair(std::string("tx"), hash), wtx); - } - - bool EraseTx(uint256 hash) - { - nWalletDBUpdated++; - return Erase(std::make_pair(std::string("tx"), hash)); - } - - bool ReadKey(const std::vector<unsigned char>& vchPubKey, CPrivKey& vchPrivKey) - { - vchPrivKey.clear(); - return Read(std::make_pair(std::string("key"), vchPubKey), vchPrivKey); - } - - bool WriteKey(const std::vector<unsigned char>& vchPubKey, const CPrivKey& vchPrivKey) - { - nWalletDBUpdated++; - return Write(std::make_pair(std::string("key"), vchPubKey), vchPrivKey, false); - } - - bool WriteCryptedKey(const std::vector<unsigned char>& vchPubKey, const std::vector<unsigned char>& vchCryptedSecret, bool fEraseUnencryptedKey = true) - { - nWalletDBUpdated++; - if (!Write(std::make_pair(std::string("ckey"), vchPubKey), vchCryptedSecret, false)) - return false; - if (fEraseUnencryptedKey) - { - Erase(std::make_pair(std::string("key"), vchPubKey)); - Erase(std::make_pair(std::string("wkey"), vchPubKey)); - } - return true; - } - - bool WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey) - { - nWalletDBUpdated++; - return Write(std::make_pair(std::string("mkey"), nID), kMasterKey, true); - } - - // Support for BIP 0013 : see https://en.bitcoin.it/wiki/BIP_0013 - bool ReadCScript(const uint160 &hash, CScript& redeemScript) - { - redeemScript.clear(); - return Read(std::make_pair(std::string("cscript"), hash), redeemScript); - } - - bool WriteCScript(const uint160& hash, const CScript& redeemScript) - { - nWalletDBUpdated++; - return Write(std::make_pair(std::string("cscript"), hash), redeemScript, false); - } - - bool WriteBestBlock(const CBlockLocator& locator) - { - nWalletDBUpdated++; - return Write(std::string("bestblock"), locator); - } - - bool ReadBestBlock(CBlockLocator& locator) - { - return Read(std::string("bestblock"), locator); - } - - bool ReadDefaultKey(std::vector<unsigned char>& vchPubKey) - { - vchPubKey.clear(); - return Read(std::string("defaultkey"), vchPubKey); - } - - bool WriteDefaultKey(const std::vector<unsigned char>& vchPubKey) - { - nWalletDBUpdated++; - return Write(std::string("defaultkey"), vchPubKey); - } - - bool ReadPool(int64 nPool, CKeyPool& keypool) - { - return Read(std::make_pair(std::string("pool"), nPool), keypool); - } - - bool WritePool(int64 nPool, const CKeyPool& keypool) - { - nWalletDBUpdated++; - return Write(std::make_pair(std::string("pool"), nPool), keypool); - } - - bool ErasePool(int64 nPool) - { - nWalletDBUpdated++; - return Erase(std::make_pair(std::string("pool"), nPool)); - } - - // Settings are no longer stored in wallet.dat; these are - // used only for backwards compatibility: - template<typename T> - bool ReadSetting(const std::string& strKey, T& value) - { - return Read(std::make_pair(std::string("setting"), strKey), value); - } - template<typename T> - bool WriteSetting(const std::string& strKey, const T& value) - { - nWalletDBUpdated++; - return Write(std::make_pair(std::string("setting"), strKey), value); - } - bool EraseSetting(const std::string& strKey) - { - nWalletDBUpdated++; - return Erase(std::make_pair(std::string("setting"), strKey)); - } - - bool WriteMinVersion(int nVersion) - { - return Write(std::string("minversion"), nVersion); - } - - bool ReadAccount(const std::string& strAccount, CAccount& account); - bool WriteAccount(const std::string& strAccount, const CAccount& account); - bool WriteAccountingEntry(const CAccountingEntry& acentry); - int64 GetAccountCreditDebit(const std::string& strAccount); - void ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& acentries); - - int LoadWallet(CWallet* pwallet); -}; - -#endif +#endif // BITCOIN_DB_H diff --git a/src/headers.h b/src/headers.h deleted file mode 100644 index ceee028977..0000000000 --- a/src/headers.h +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2012 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying -// file license.txt or http://www.opensource.org/licenses/mit-license.php. - -#ifdef _MSC_VER -#pragma warning(disable:4786) -#pragma warning(disable:4804) -#pragma warning(disable:4805) -#pragma warning(disable:4717) -#endif -#ifdef _WIN32_WINNT -#undef _WIN32_WINNT -#endif -#define _WIN32_WINNT 0x0501 -#ifdef _WIN32_IE -#undef _WIN32_IE -#endif -#define _WIN32_IE 0x0400 -#define WIN32_LEAN_AND_MEAN 1 -#ifndef NOMINMAX -#define NOMINMAX -#endif -// Include boost/foreach here as it defines __STDC_LIMIT_MACROS on some systems. -#include <boost/foreach.hpp> - -#if (defined(__unix__) || defined(unix)) && !defined(USG) -#include <sys/param.h> // to get BSD define -#endif -#ifdef MAC_OSX -#ifndef BSD -#define BSD 1 -#endif -#endif -#include <openssl/buffer.h> -#include <openssl/ecdsa.h> -#include <openssl/evp.h> -#include <openssl/rand.h> -#include <openssl/sha.h> -#include <openssl/ripemd.h> -#include <db_cxx.h> -#include <stdio.h> -#include <stdlib.h> -#include <time.h> -#include <math.h> -#include <float.h> -#include <assert.h> -#include <iostream> -#include <sstream> -#include <string> -#include <vector> -#include <list> -#include <deque> -#include <map> - -#ifdef WIN32 -#include <windows.h> -#include <winsock2.h> -#include <mswsock.h> -#include <shlobj.h> -#include <shlwapi.h> -#include <io.h> -#include <process.h> -#include <malloc.h> -#else -#include <sys/time.h> -#include <sys/resource.h> -#include <sys/socket.h> -#include <sys/stat.h> -#include <arpa/inet.h> -#include <netdb.h> -#include <unistd.h> -#include <errno.h> -#include <net/if.h> -#include <ifaddrs.h> -#include <fcntl.h> -#include <signal.h> -#endif -#ifdef BSD -#include <netinet/in.h> -#endif - - -#include "serialize.h" -#include "uint256.h" -#include "util.h" -#include "bignum.h" -#include "base58.h" -#include "main.h" -#include "wallet.h" -#include "ui_interface.h" diff --git a/src/init.cpp b/src/init.cpp index 2be0027a5b..0eb37fe99c 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -2,19 +2,20 @@ // Copyright (c) 2009-2012 The Bitcoin developers // Distributed under the MIT/X11 software license, see the accompanying // file license.txt or http://www.opensource.org/licenses/mit-license.php. -#include "headers.h" #include "db.h" +#include "walletdb.h" #include "bitcoinrpc.h" #include "net.h" #include "init.h" -#include "strlcpy.h" +#include "util.h" +#include "ui_interface.h" #include <boost/filesystem.hpp> #include <boost/filesystem/fstream.hpp> #include <boost/filesystem/convenience.hpp> #include <boost/interprocess/sync/file_lock.hpp> -#ifdef WIN32 -#define strncasecmp strnicmp +#ifndef WIN32 +#include <signal.h> #endif using namespace std; @@ -583,145 +584,3 @@ bool AppInit2(int argc, char* argv[]) return true; } -#ifdef WIN32 -boost::filesystem::path StartupShortcutPath() -{ - return MyGetSpecialFolderPath(CSIDL_STARTUP, true) / "Bitcoin.lnk"; -} - -bool GetStartOnSystemStartup() -{ - return filesystem::exists(StartupShortcutPath()); -} - -bool SetStartOnSystemStartup(bool fAutoStart) -{ - // If the shortcut exists already, remove it for updating - boost::filesystem::remove(StartupShortcutPath()); - - if (fAutoStart) - { - CoInitialize(NULL); - - // Get a pointer to the IShellLink interface. - IShellLink* psl = NULL; - HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL, - CLSCTX_INPROC_SERVER, IID_IShellLink, - reinterpret_cast<void**>(&psl)); - - if (SUCCEEDED(hres)) - { - // Get the current executable path - TCHAR pszExePath[MAX_PATH]; - GetModuleFileName(NULL, pszExePath, sizeof(pszExePath)); - - TCHAR pszArgs[5] = TEXT("-min"); - - // Set the path to the shortcut target - psl->SetPath(pszExePath); - PathRemoveFileSpec(pszExePath); - psl->SetWorkingDirectory(pszExePath); - psl->SetShowCmd(SW_SHOWMINNOACTIVE); - psl->SetArguments(pszArgs); - - // Query IShellLink for the IPersistFile interface for - // saving the shortcut in persistent storage. - IPersistFile* ppf = NULL; - hres = psl->QueryInterface(IID_IPersistFile, - reinterpret_cast<void**>(&ppf)); - if (SUCCEEDED(hres)) - { - WCHAR pwsz[MAX_PATH]; - // Ensure that the string is ANSI. - MultiByteToWideChar(CP_ACP, 0, StartupShortcutPath().string().c_str(), -1, pwsz, MAX_PATH); - // Save the link by calling IPersistFile::Save. - hres = ppf->Save(pwsz, TRUE); - ppf->Release(); - psl->Release(); - CoUninitialize(); - return true; - } - psl->Release(); - } - CoUninitialize(); - return false; - } - return true; -} - -#elif defined(LINUX) - -// Follow the Desktop Application Autostart Spec: -// http://standards.freedesktop.org/autostart-spec/autostart-spec-latest.html - -boost::filesystem::path GetAutostartDir() -{ - namespace fs = boost::filesystem; - - char* pszConfigHome = getenv("XDG_CONFIG_HOME"); - if (pszConfigHome) return fs::path(pszConfigHome) / "autostart"; - char* pszHome = getenv("HOME"); - if (pszHome) return fs::path(pszHome) / ".config" / "autostart"; - return fs::path(); -} - -boost::filesystem::path GetAutostartFilePath() -{ - return GetAutostartDir() / "bitcoin.desktop"; -} - -bool GetStartOnSystemStartup() -{ - boost::filesystem::ifstream optionFile(GetAutostartFilePath()); - if (!optionFile.good()) - return false; - // Scan through file for "Hidden=true": - string line; - while (!optionFile.eof()) - { - getline(optionFile, line); - if (line.find("Hidden") != string::npos && - line.find("true") != string::npos) - return false; - } - optionFile.close(); - - return true; -} - -bool SetStartOnSystemStartup(bool fAutoStart) -{ - if (!fAutoStart) - boost::filesystem::remove(GetAutostartFilePath()); - else - { - char pszExePath[MAX_PATH+1]; - memset(pszExePath, 0, sizeof(pszExePath)); - if (readlink("/proc/self/exe", pszExePath, sizeof(pszExePath)-1) == -1) - return false; - - boost::filesystem::create_directories(GetAutostartDir()); - - boost::filesystem::ofstream optionFile(GetAutostartFilePath(), ios_base::out|ios_base::trunc); - if (!optionFile.good()) - return false; - // Write a bitcoin.desktop file to the autostart directory: - optionFile << "[Desktop Entry]\n"; - optionFile << "Type=Application\n"; - optionFile << "Name=Bitcoin\n"; - optionFile << "Exec=" << pszExePath << " -min\n"; - optionFile << "Terminal=false\n"; - optionFile << "Hidden=false\n"; - optionFile.close(); - } - return true; -} -#else - -// TODO: OSX startup stuff; see: -// http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPSystemStartup/Articles/CustomLogin.html - -bool GetStartOnSystemStartup() { return false; } -bool SetStartOnSystemStartup(bool fAutoStart) { return false; } - -#endif diff --git a/src/init.h b/src/init.h index 0d60e7549f..e3971c85e3 100644 --- a/src/init.h +++ b/src/init.h @@ -5,6 +5,8 @@ #ifndef BITCOIN_INIT_H #define BITCOIN_INIT_H +#include "wallet.h" + extern CWallet* pwalletMain; void Shutdown(void* parg); diff --git a/src/irc.cpp b/src/irc.cpp index 09bacc1658..237497055d 100644 --- a/src/irc.cpp +++ b/src/irc.cpp @@ -3,10 +3,10 @@ // Distributed under the MIT/X11 software license, see the accompanying // file license.txt or http://www.opensource.org/licenses/mit-license.php. -#include "headers.h" #include "irc.h" #include "net.h" #include "strlcpy.h" +#include "base58.h" using namespace std; using namespace boost; @@ -108,13 +108,13 @@ int RecvUntil(SOCKET hSocket, const char* psz1, const char* psz2=NULL, const cha if (!RecvLineIRC(hSocket, strLine)) return 0; printf("IRC %s\n", strLine.c_str()); - if (psz1 && strLine.find(psz1) != -1) + if (psz1 && strLine.find(psz1) != string::npos) return 1; - if (psz2 && strLine.find(psz2) != -1) + if (psz2 && strLine.find(psz2) != string::npos) return 2; - if (psz3 && strLine.find(psz3) != -1) + if (psz3 && strLine.find(psz3) != string::npos) return 3; - if (psz4 && strLine.find(psz4) != -1) + if (psz4 && strLine.find(psz4) != string::npos) return 4; } } @@ -12,7 +12,7 @@ #include <openssl/ecdsa.h> #include <openssl/obj_mac.h> -#include "serialize.h" +#include "allocators.h" #include "uint256.h" // secp160k1 @@ -173,7 +173,7 @@ public: CPrivKey GetPrivKey() const { - unsigned int nSize = i2d_ECPrivateKey(pkey, NULL); + int nSize = i2d_ECPrivateKey(pkey, NULL); if (!nSize) throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey failed"); CPrivKey vchPrivKey(nSize, 0); @@ -196,7 +196,7 @@ public: std::vector<unsigned char> GetPubKey() const { - unsigned int nSize = i2o_ECPublicKey(pkey, NULL); + int nSize = i2o_ECPublicKey(pkey, NULL); if (!nSize) throw key_error("CKey::GetPubKey() : i2o_ECPublicKey failed"); std::vector<unsigned char> vchPubKey(nSize, 0); diff --git a/src/keystore.cpp b/src/keystore.cpp index 7b46f6b07a..313518711b 100644 --- a/src/keystore.cpp +++ b/src/keystore.cpp @@ -3,9 +3,7 @@ // Distributed under the MIT/X11 software license, see the accompanying // file license.txt or http://www.opensource.org/licenses/mit-license.php. -#include "headers.h" -#include "crypter.h" -#include "db.h" +#include "keystore.h" #include "script.h" bool CKeyStore::GetPubKey(const CBitcoinAddress &address, std::vector<unsigned char> &vchPubKeyOut) const diff --git a/src/keystore.h b/src/keystore.h index 5d29ac1cb9..76820e204b 100644 --- a/src/keystore.h +++ b/src/keystore.h @@ -6,7 +6,10 @@ #define BITCOIN_KEYSTORE_H #include "crypter.h" -#include "script.h" +#include "util.h" +#include "base58.h" + +class CScript; /** A virtual base class for key stores */ class CKeyStore diff --git a/src/main.cpp b/src/main.cpp index f2932804e3..78d84d9064 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,11 +2,11 @@ // Copyright (c) 2009-2012 The Bitcoin developers // Distributed under the MIT/X11 software license, see the accompanying // file license.txt or http://www.opensource.org/licenses/mit-license.php. -#include "headers.h" #include "checkpoints.h" #include "db.h" #include "net.h" #include "init.h" +#include "ui_interface.h" #include <boost/algorithm/string/replace.hpp> #include <boost/filesystem.hpp> #include <boost/filesystem/fstream.hpp> @@ -23,10 +23,8 @@ set<CWallet*> setpwalletRegistered; CCriticalSection cs_main; -static map<uint256, CTransaction> mapTransactions; -CCriticalSection cs_mapTransactions; +CTxMemPool mempool; unsigned int nTransactionsUpdated = 0; -map<COutPoint, CInPoint> mapNextTx; map<uint256, CBlockIndex*> mapBlockIndex; uint256 hashGenesisBlock("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"); @@ -288,7 +286,7 @@ bool CTransaction::AreInputsStandard(const MapPrevTx& mapInputs) const if (IsCoinBase()) return true; // Coinbases don't use vin normally - for (int i = 0; i < vin.size(); i++) + for (unsigned int i = 0; i < vin.size(); i++) { const CTxOut& prev = GetOutputFor(vin[i], mapInputs); @@ -411,7 +409,7 @@ bool CTransaction::CheckTransaction() const if (vout.empty()) return DoS(10, error("CTransaction::CheckTransaction() : vout empty")); // Size limits - if (::GetSerializeSize(*this, SER_NETWORK) > MAX_BLOCK_SIZE) + if (::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE) return DoS(100, error("CTransaction::CheckTransaction() : size limits failed")); // Check for negative or overflow output values @@ -451,31 +449,32 @@ bool CTransaction::CheckTransaction() const return true; } -bool CTransaction::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs, bool* pfMissingInputs) +bool CTxMemPool::accept(CTxDB& txdb, CTransaction &tx, bool fCheckInputs, + bool* pfMissingInputs) { if (pfMissingInputs) *pfMissingInputs = false; - if (!CheckTransaction()) - return error("AcceptToMemoryPool() : CheckTransaction failed"); + if (!tx.CheckTransaction()) + return error("CTxMemPool::accept() : CheckTransaction failed"); // Coinbase is only valid in a block, not as a loose transaction - if (IsCoinBase()) - return DoS(100, error("AcceptToMemoryPool() : coinbase as individual tx")); + if (tx.IsCoinBase()) + return tx.DoS(100, error("CTxMemPool::accept() : coinbase as individual tx")); // To help v0.1.5 clients who would see it as a negative number - if ((int64)nLockTime > std::numeric_limits<int>::max()) - return error("AcceptToMemoryPool() : not accepting nLockTime beyond 2038 yet"); + if ((int64)tx.nLockTime > std::numeric_limits<int>::max()) + return error("CTxMemPool::accept() : not accepting nLockTime beyond 2038 yet"); // Rather not work on nonstandard transactions (unless -testnet) - if (!fTestNet && !IsStandard()) - return error("AcceptToMemoryPool() : nonstandard transaction type"); + if (!fTestNet && !tx.IsStandard()) + return error("CTxMemPool::accept() : nonstandard transaction type"); // Do we already have it? - uint256 hash = GetHash(); + uint256 hash = tx.GetHash(); { - LOCK(cs_mapTransactions); - if (mapTransactions.count(hash)) + LOCK(cs); + if (mapTx.count(hash)) return false; } if (fCheckInputs) @@ -484,9 +483,9 @@ bool CTransaction::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs, bool* pfMi // Check for conflicts with in-memory transactions CTransaction* ptxOld = NULL; - for (int i = 0; i < vin.size(); i++) + for (unsigned int i = 0; i < tx.vin.size(); i++) { - COutPoint outpoint = vin[i].prevout; + COutPoint outpoint = tx.vin[i].prevout; if (mapNextTx.count(outpoint)) { // Disable replacement feature for now @@ -498,11 +497,11 @@ bool CTransaction::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs, bool* pfMi ptxOld = mapNextTx[outpoint].ptx; if (ptxOld->IsFinal()) return false; - if (!IsNewerThan(*ptxOld)) + if (!tx.IsNewerThan(*ptxOld)) return false; - for (int i = 0; i < vin.size(); i++) + for (unsigned int i = 0; i < tx.vin.size(); i++) { - COutPoint outpoint = vin[i].prevout; + COutPoint outpoint = tx.vin[i].prevout; if (!mapNextTx.count(outpoint) || mapNextTx[outpoint].ptx != ptxOld) return false; } @@ -515,29 +514,29 @@ bool CTransaction::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs, bool* pfMi MapPrevTx mapInputs; map<uint256, CTxIndex> mapUnused; bool fInvalid = false; - if (!FetchInputs(txdb, mapUnused, false, false, mapInputs, fInvalid)) + if (!tx.FetchInputs(txdb, mapUnused, false, false, mapInputs, fInvalid)) { if (fInvalid) - return error("AcceptToMemoryPool() : FetchInputs found invalid tx %s", hash.ToString().substr(0,10).c_str()); + return error("CTxMemPool::accept() : FetchInputs found invalid tx %s", hash.ToString().substr(0,10).c_str()); if (pfMissingInputs) *pfMissingInputs = true; - return error("AcceptToMemoryPool() : FetchInputs failed %s", hash.ToString().substr(0,10).c_str()); + return error("CTxMemPool::accept() : FetchInputs failed %s", hash.ToString().substr(0,10).c_str()); } // Check for non-standard pay-to-script-hash in inputs - if (!AreInputsStandard(mapInputs) && !fTestNet) - return error("AcceptToMemoryPool() : nonstandard transaction input"); + if (!tx.AreInputsStandard(mapInputs) && !fTestNet) + return error("CTxMemPool::accept() : nonstandard transaction input"); // Note: if you modify this code to accept non-standard transactions, then // you should add code here to check that the transaction does a // reasonable number of ECDSA signature verifications. - int64 nFees = GetValueIn(mapInputs)-GetValueOut(); - unsigned int nSize = ::GetSerializeSize(*this, SER_NETWORK); + int64 nFees = tx.GetValueIn(mapInputs)-tx.GetValueOut(); + unsigned int nSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); // Don't accept it if it can't get into a block - if (nFees < GetMinFee(1000, true, GMF_RELAY)) - return error("AcceptToMemoryPool() : not enough fees"); + if (nFees < tx.GetMinFee(1000, true, GMF_RELAY)) + return error("CTxMemPool::accept() : not enough fees"); // Continuously rate-limit free transactions // This mitigates 'penny-flooding' -- sending thousands of free transactions just to @@ -556,8 +555,8 @@ 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(*this)) - return error("AcceptToMemoryPool() : free transaction rejected by rate limiter"); + if (dFreeCount > GetArg("-limitfreerelay", 15)*10*1000 && !IsFromMe(tx)) + return error("CTxMemPool::accept() : free transaction rejected by rate limiter"); if (fDebug) printf("Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount+nSize); dFreeCount += nSize; @@ -566,21 +565,21 @@ bool CTransaction::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs, bool* pfMi // Check against previous transactions // This is done last to help prevent CPU exhaustion denial-of-service attacks. - if (!ConnectInputs(mapInputs, mapUnused, CDiskTxPos(1,1,1), pindexBest, false, false)) + if (!tx.ConnectInputs(mapInputs, mapUnused, CDiskTxPos(1,1,1), pindexBest, false, false)) { - return error("AcceptToMemoryPool() : ConnectInputs failed %s", hash.ToString().substr(0,10).c_str()); + return error("CTxMemPool::accept() : ConnectInputs failed %s", hash.ToString().substr(0,10).c_str()); } } // Store transaction in memory { - LOCK(cs_mapTransactions); + LOCK(cs); if (ptxOld) { - printf("AcceptToMemoryPool() : replacing tx %s with new version\n", ptxOld->GetHash().ToString().c_str()); - ptxOld->RemoveFromMemoryPool(); + printf("CTxMemPool::accept() : replacing tx %s with new version\n", ptxOld->GetHash().ToString().c_str()); + remove(*ptxOld); } - AddToMemoryPoolUnchecked(); + addUnchecked(tx); } ///// are we sure this is ok when loading transactions or restoring block txes @@ -588,43 +587,44 @@ bool CTransaction::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs, bool* pfMi if (ptxOld) EraseFromWallets(ptxOld->GetHash()); - printf("AcceptToMemoryPool(): accepted %s\n", hash.ToString().substr(0,10).c_str()); + printf("CTxMemPool::accept() : accepted %s\n", hash.ToString().substr(0,10).c_str()); return true; } -uint64 nPooledTx = 0; +bool CTransaction::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs, bool* pfMissingInputs) +{ + return mempool.accept(txdb, *this, fCheckInputs, pfMissingInputs); +} -bool CTransaction::AddToMemoryPoolUnchecked() +bool CTxMemPool::addUnchecked(CTransaction &tx) { - printf("AcceptToMemoryPoolUnchecked(): size %lu\n", mapTransactions.size()); + printf("addUnchecked(): size %lu\n", mapTx.size()); // Add to memory pool without checking anything. Don't call this directly, - // call AcceptToMemoryPool to properly check the transaction first. + // call CTxMemPool::accept to properly check the transaction first. { - LOCK(cs_mapTransactions); - uint256 hash = GetHash(); - mapTransactions[hash] = *this; - for (int i = 0; i < vin.size(); i++) - mapNextTx[vin[i].prevout] = CInPoint(&mapTransactions[hash], i); + LOCK(cs); + uint256 hash = tx.GetHash(); + mapTx[hash] = tx; + for (unsigned int i = 0; i < tx.vin.size(); i++) + mapNextTx[tx.vin[i].prevout] = CInPoint(&mapTx[hash], i); nTransactionsUpdated++; - ++nPooledTx; } return true; } -bool CTransaction::RemoveFromMemoryPool() +bool CTxMemPool::remove(CTransaction &tx) { // Remove transaction from memory pool { - LOCK(cs_mapTransactions); - uint256 hash = GetHash(); - if (mapTransactions.count(hash)) + LOCK(cs); + uint256 hash = tx.GetHash(); + if (mapTx.count(hash)) { - BOOST_FOREACH(const CTxIn& txin, vin) + BOOST_FOREACH(const CTxIn& txin, tx.vin) mapNextTx.erase(txin.prevout); - mapTransactions.erase(hash); + mapTx.erase(hash); nTransactionsUpdated++; - --nPooledTx; } } return true; @@ -695,14 +695,14 @@ bool CWalletTx::AcceptWalletTransaction(CTxDB& txdb, bool fCheckInputs) { { - LOCK(cs_mapTransactions); + LOCK(mempool.cs); // Add previous supporting transactions first BOOST_FOREACH(CMerkleTx& tx, vtxPrev) { if (!tx.IsCoinBase()) { uint256 hash = tx.GetHash(); - if (!mapTransactions.count(hash) && !txdb.ContainsTx(hash)) + if (!mempool.exists(hash) && !txdb.ContainsTx(hash)) tx.AcceptToMemoryPool(txdb, fCheckInputs); } } @@ -989,7 +989,7 @@ bool CTransaction::FetchInputs(CTxDB& txdb, const map<uint256, CTxIndex>& mapTes if (IsCoinBase()) return true; // Coinbase transactions have no inputs to fetch. - for (int i = 0; i < vin.size(); i++) + for (unsigned int i = 0; i < vin.size(); i++) { COutPoint prevout = vin[i].prevout; if (inputsRet.count(prevout.hash)) @@ -1017,10 +1017,10 @@ bool CTransaction::FetchInputs(CTxDB& txdb, const map<uint256, CTxIndex>& mapTes { // Get prev tx from single transactions in memory { - LOCK(cs_mapTransactions); - if (!mapTransactions.count(prevout.hash)) - return error("FetchInputs() : %s mapTransactions prev not found %s", GetHash().ToString().substr(0,10).c_str(), prevout.hash.ToString().substr(0,10).c_str()); - txPrev = mapTransactions[prevout.hash]; + LOCK(mempool.cs); + if (!mempool.exists(prevout.hash)) + return error("FetchInputs() : %s mempool Tx prev not found %s", GetHash().ToString().substr(0,10).c_str(), prevout.hash.ToString().substr(0,10).c_str()); + txPrev = mempool.lookup(prevout.hash); } if (!fFound) txindex.vSpent.resize(txPrev.vout.size()); @@ -1034,7 +1034,7 @@ bool CTransaction::FetchInputs(CTxDB& txdb, const map<uint256, CTxIndex>& mapTes } // Make sure all prevout.n's are valid: - for (int i = 0; i < vin.size(); i++) + for (unsigned int i = 0; i < vin.size(); i++) { const COutPoint prevout = vin[i].prevout; assert(inputsRet.count(prevout.hash) != 0); @@ -1071,7 +1071,7 @@ int64 CTransaction::GetValueIn(const MapPrevTx& inputs) const return 0; int64 nResult = 0; - for (int i = 0; i < vin.size(); i++) + for (unsigned int i = 0; i < vin.size(); i++) { nResult += GetOutputFor(vin[i], inputs).nValue; } @@ -1085,7 +1085,7 @@ int CTransaction::GetP2SHSigOpCount(const MapPrevTx& inputs) const return 0; int nSigOps = 0; - for (int i = 0; i < vin.size(); i++) + for (unsigned int i = 0; i < vin.size(); i++) { const CTxOut& prevout = GetOutputFor(vin[i], inputs); if (prevout.scriptPubKey.IsPayToScriptHash()) @@ -1106,7 +1106,7 @@ bool CTransaction::ConnectInputs(MapPrevTx inputs, { int64 nValueIn = 0; int64 nFees = 0; - for (int i = 0; i < vin.size(); i++) + for (unsigned int i = 0; i < vin.size(); i++) { COutPoint prevout = vin[i].prevout; assert(inputs.count(prevout.hash) > 0); @@ -1183,15 +1183,15 @@ bool CTransaction::ClientConnectInputs() // Take over previous transactions' spent pointers { - LOCK(cs_mapTransactions); + LOCK(mempool.cs); int64 nValueIn = 0; - for (int i = 0; i < vin.size(); i++) + for (unsigned int i = 0; i < vin.size(); i++) { // Get prev tx from single transactions in memory COutPoint prevout = vin[i].prevout; - if (!mapTransactions.count(prevout.hash)) + if (!mempool.exists(prevout.hash)) return false; - CTransaction& txPrev = mapTransactions[prevout.hash]; + CTransaction& txPrev = mempool.lookup(prevout.hash); if (prevout.n >= txPrev.vout.size()) return false; @@ -1200,7 +1200,8 @@ bool CTransaction::ClientConnectInputs() if (!VerifySignature(txPrev, *this, i, true, 0)) return error("ConnectInputs() : VerifySignature failed"); - ///// this is redundant with the mapNextTx stuff, not sure which I want to get rid of + ///// this is redundant with the mempool.mapNextTx stuff, + ///// not sure which I want to get rid of ///// this has to go away now that posNext is gone // // Check for conflicts // if (!txPrev.vout[prevout.n].posNext.IsNull()) @@ -1279,7 +1280,7 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex) bool fStrictPayToScriptHash = (pindex->nTime >= nBIP16SwitchTime); //// issue here: it doesn't know the version - unsigned int nTxPos = pindex->nBlockPos + ::GetSerializeSize(CBlock(), SER_DISK) - 1 + GetSizeOfCompactSize(vtx.size()); + unsigned int nTxPos = pindex->nBlockPos + ::GetSerializeSize(CBlock(), SER_DISK, CLIENT_VERSION) - 1 + GetSizeOfCompactSize(vtx.size()); map<uint256, CTxIndex> mapQueuedChanges; int64 nFees = 0; @@ -1291,7 +1292,7 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex) return DoS(100, error("ConnectBlock() : too many sigops")); CDiskTxPos posThisTx(pindex->nFile, pindex->nBlockPos, nTxPos); - nTxPos += ::GetSerializeSize(tx, SER_DISK); + nTxPos += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION); MapPrevTx mapInputs; if (!tx.IsCoinBase()) @@ -1396,7 +1397,7 @@ bool static Reorganize(CTxDB& txdb, CBlockIndex* pindexNew) // Connect longer branch vector<CTransaction> vDelete; - for (int i = 0; i < vConnect.size(); i++) + for (unsigned int i = 0; i < vConnect.size(); i++) { CBlockIndex* pindex = vConnect[i]; CBlock block; @@ -1436,7 +1437,7 @@ bool static Reorganize(CTxDB& txdb, CBlockIndex* pindexNew) // Delete redundant memory transactions that are in the connected branch BOOST_FOREACH(CTransaction& tx, vDelete) - tx.RemoveFromMemoryPool(); + mempool.remove(tx); printf("REORGANIZE: done\n"); @@ -1472,7 +1473,7 @@ bool CBlock::SetBestChainInner(CTxDB& txdb, CBlockIndex *pindexNew) // Delete redundant memory transactions BOOST_FOREACH(CTransaction& tx, vtx) - tx.RemoveFromMemoryPool(); + mempool.remove(tx); return true; } @@ -1621,7 +1622,7 @@ bool CBlock::CheckBlock() const // that can be verified before saving an orphan block. // Size limits - if (vtx.empty() || vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(*this, SER_NETWORK) > MAX_BLOCK_SIZE) + if (vtx.empty() || vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE) return DoS(100, error("CheckBlock() : size limits failed")); // Check proof of work matches claimed amount @@ -1635,7 +1636,7 @@ bool CBlock::CheckBlock() const // First transaction must be coinbase, the rest must not be if (vtx.empty() || !vtx[0].IsCoinBase()) return DoS(100, error("CheckBlock() : first tx is not coinbase")); - for (int i = 1; i < vtx.size(); i++) + for (unsigned int i = 1; i < vtx.size(); i++) if (vtx[i].IsCoinBase()) return DoS(100, error("CheckBlock() : more than one coinbase")); @@ -1691,7 +1692,7 @@ bool CBlock::AcceptBlock() return DoS(100, error("AcceptBlock() : rejected by checkpoint lockin at %d", nHeight)); // Write block to history file - if (!CheckDiskSpace(::GetSerializeSize(*this, SER_DISK))) + if (!CheckDiskSpace(::GetSerializeSize(*this, SER_DISK, CLIENT_VERSION))) return error("AcceptBlock() : out of disk space"); unsigned int nFile = -1; unsigned int nBlockPos = 0; @@ -1771,7 +1772,7 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock) // Recursively process any orphan blocks that depended on this one vector<uint256> vWorkQueue; vWorkQueue.push_back(hash); - for (int i = 0; i < vWorkQueue.size(); i++) + for (unsigned int i = 0; i < vWorkQueue.size(); i++) { uint256 hashPrev = vWorkQueue[i]; for (multimap<uint256, CBlock*>::iterator mi = mapOrphanBlocksByPrev.lower_bound(hashPrev); @@ -1995,7 +1996,7 @@ void PrintBlockTree() // put the main timechain first vector<CBlockIndex*>& vNext = mapNext[pindex]; - for (int i = 0; i < vNext.size(); i++) + for (unsigned int i = 0; i < vNext.size(); i++) { if (vNext[i]->pnext) { @@ -2005,7 +2006,7 @@ void PrintBlockTree() } // iterate children - for (int i = 0; i < vNext.size(); i++) + for (unsigned int i = 0; i < vNext.size(); i++) vStack.push_back(make_pair(nCol+i, vNext[i])); } } @@ -2135,8 +2136,21 @@ bool static AlreadyHave(CTxDB& txdb, const CInv& inv) { switch (inv.type) { - case MSG_TX: return mapTransactions.count(inv.hash) || mapOrphanTransactions.count(inv.hash) || txdb.ContainsTx(inv.hash); - case MSG_BLOCK: return mapBlockIndex.count(inv.hash) || mapOrphanBlocks.count(inv.hash); + case MSG_TX: + { + bool txInMap = false; + { + LOCK(mempool.cs); + txInMap = (mempool.exists(inv.hash)); + } + return txInMap || + mapOrphanTransactions.count(inv.hash) || + txdb.ContainsTx(inv.hash); + } + + case MSG_BLOCK: + return mapBlockIndex.count(inv.hash) || + mapOrphanBlocks.count(inv.hash); } // Don't know what it is, just say we already got one return true; @@ -2183,7 +2197,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) CAddress addrFrom; uint64 nNonce = 1; vRecv >> pfrom->nVersion >> pfrom->nServices >> nTime >> addrMe; - if (pfrom->nVersion < 209) + if (pfrom->nVersion < MIN_PROTO_VERSION) { // Since February 20, 2012, the protocol is initiated at version 209, // and earlier versions are no longer supported @@ -2233,7 +2247,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) } // Get recent addresses - if (pfrom->nVersion >= 31402 || addrman.size() < 1000) + if (pfrom->nVersion >= CADDR_TIME_VERSION || addrman.size() < 1000) { pfrom->PushMessage("getaddr"); pfrom->fGetAddr = true; @@ -2250,7 +2264,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) // Ask the first connected node for block updates static int nAskedForBlocks = 0; if (!pfrom->fClient && - (pfrom->nVersion < 32000 || pfrom->nVersion >= 32400) && + (pfrom->nVersion < NOBLKS_VERSION_START || + pfrom->nVersion >= NOBLKS_VERSION_END) && (nAskedForBlocks < 1 || vNodes.size() <= 1)) { nAskedForBlocks++; @@ -2292,7 +2307,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) vRecv >> vAddr; // Don't want addr from older versions unless seeding - if (pfrom->nVersion < 31402 && addrman.size() > 1000) + if (pfrom->nVersion < CADDR_TIME_VERSION && addrman.size() > 1000) return true; if (vAddr.size() > 1000) { @@ -2329,7 +2344,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) multimap<uint256, CNode*> mapMix; BOOST_FOREACH(CNode* pnode, vNodes) { - if (pnode->nVersion < 31402) + if (pnode->nVersion < CADDR_TIME_VERSION) continue; unsigned int nPointer; memcpy(&nPointer, &pnode, sizeof(nPointer)); @@ -2360,7 +2375,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) } CTxDB txdb("r"); - for (int nInv = 0; nInv < vInv.size(); nInv++) + for (unsigned int nInv = 0; nInv < vInv.size(); nInv++) { const CInv &inv = vInv[nInv]; @@ -2467,7 +2482,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) pfrom->PushInventory(CInv(MSG_BLOCK, pindex->GetBlockHash())); CBlock block; block.ReadFromDisk(pindex, true); - nBytes += block.GetSerializeSize(SER_NETWORK); + nBytes += block.GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION); if (--nLimit <= 0 || nBytes >= SendBufferSize()/2) { // When this block is requested, we'll send an inv that'll make them @@ -2536,7 +2551,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) vWorkQueue.push_back(inv.hash); // Recursively process any orphan transactions that depended on this one - for (int i = 0; i < vWorkQueue.size(); i++) + for (unsigned int i = 0; i < vWorkQueue.size(); i++) { uint256 hashPrev = vWorkQueue[i]; for (multimap<uint256, CDataStream*>::iterator mi = mapOrphanTransactionsByPrev.lower_bound(hashPrev); @@ -2651,6 +2666,23 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) else if (strCommand == "ping") { + if (pfrom->nVersion > BIP0031_VERSION) + { + uint64 nonce = 0; + vRecv >> nonce; + // Echo the message back with the nonce. This allows for two useful features: + // + // 1) A remote node can quickly check if the connection is operational + // 2) Remote nodes can measure the latency of the network thread. If this node + // is overloaded it won't respond to pings quickly and the remote node can + // avoid sending us more work, like chain download requests. + // + // The nonce stops the remote getting confused between different pings: without + // it, if the remote node sends a ping once per second and this node takes 5 + // seconds to respond to each, the 5th ping the remote sends would appear to + // return very quickly. + pfrom->PushMessage("pong", nonce); + } } @@ -2807,15 +2839,20 @@ bool ProcessMessages(CNode* pfrom) bool SendMessages(CNode* pto, bool fSendTrickle) { - { - LOCK(cs_main); + TRY_LOCK(cs_main, lockMain); + if (lockMain) { // Don't send anything until we get their version message if (pto->nVersion == 0) return true; - // Keep-alive ping - if (pto->nLastSend && GetTime() - pto->nLastSend > 30 * 60 && pto->vSend.empty()) - pto->PushMessage("ping"); + // Keep-alive ping. We send a nonce of zero because we don't use it anywhere + // right now. + if (pto->nLastSend && GetTime() - pto->nLastSend > 30 * 60 && pto->vSend.empty()) { + if (pto->nVersion > BIP0031_VERSION) + pto->PushMessage("ping", 0); + else + pto->PushMessage("ping"); + } // Resend wallet transactions that haven't gotten in a block yet ResendWalletTransactions(); @@ -3093,14 +3130,14 @@ CBlock* CreateNewBlock(CReserveKey& reservekey) // Collect memory pool transactions into the block int64 nFees = 0; { - LOCK2(cs_main, cs_mapTransactions); + LOCK2(cs_main, mempool.cs); CTxDB txdb("r"); // Priority order to process transactions list<COrphan> vOrphan; // list memory doesn't move map<uint256, vector<COrphan*> > mapDependers; multimap<double, CTransaction*> mapPriority; - for (map<uint256, CTransaction>::iterator mi = mapTransactions.begin(); mi != mapTransactions.end(); ++mi) + for (map<uint256, CTransaction>::iterator mi = mempool.mapTx.begin(); mi != mempool.mapTx.end(); ++mi) { CTransaction& tx = (*mi).second; if (tx.IsCoinBase() || !tx.IsFinal()) @@ -3138,7 +3175,7 @@ CBlock* CreateNewBlock(CReserveKey& reservekey) } // Priority is sum(valuein * age) / txsize - dPriority /= ::GetSerializeSize(tx, SER_NETWORK); + dPriority /= ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); if (porphan) porphan->dPriority = dPriority; @@ -3167,7 +3204,7 @@ CBlock* CreateNewBlock(CReserveKey& reservekey) mapPriority.erase(mapPriority.begin()); // Size limits - unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK); + unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); if (nBlockSize + nTxSize >= MAX_BLOCK_SIZE_GEN) continue; @@ -3294,7 +3331,7 @@ void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash FormatHashBlocks(&tmp.hash1, sizeof(tmp.hash1)); // Byte swap all the input buffer - for (int i = 0; i < sizeof(tmp)/4; i++) + for (unsigned int i = 0; i < sizeof(tmp)/4; i++) ((unsigned int*)&tmp)[i] = ByteReverse(((unsigned int*)&tmp)[i]); // Precalc the first half of the first hash, which stays constant @@ -3419,7 +3456,7 @@ void static BitcoinMiner(CWallet *pwallet) // Check if something found if (nNonceFound != -1) { - for (int i = 0; i < sizeof(hash)/4; i++) + for (unsigned int i = 0; i < sizeof(hash)/4; i++) ((unsigned int*)&hash)[i] = ByteReverse(((unsigned int*)&hash)[i]); if (hash <= hashTarget) diff --git a/src/main.h b/src/main.h index a89c0935fe..d12a3cc258 100644 --- a/src/main.h +++ b/src/main.h @@ -7,10 +7,7 @@ #include "bignum.h" #include "net.h" -#include "key.h" #include "script.h" -#include "db.h" -#include "version.h" #ifdef WIN32 #include <io.h> /* for _commit */ @@ -18,13 +15,11 @@ #include <list> +class CWallet; class CBlock; class CBlockIndex; -class CWalletTx; -class CWallet; class CKeyItem; class CReserveKey; -class CWalletDB; class CAddress; class CInv; @@ -35,8 +30,6 @@ static const unsigned int MAX_BLOCK_SIZE = 1000000; static const unsigned int MAX_BLOCK_SIZE_GEN = MAX_BLOCK_SIZE/2; static const int MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE/50; static const int MAX_ORPHAN_TRANSACTIONS = MAX_BLOCK_SIZE/100; -static const int64 COIN = 100000000; -static const int64 CENT = 1000000; static const int64 MIN_TX_FEE = 50000; static const int64 MIN_RELAY_TX_FEE = 10000; static const int64 MAX_MONEY = 21000000 * COIN; @@ -67,7 +60,6 @@ extern CBigNum bnBestChainWork; extern CBigNum bnBestInvalidWork; extern uint256 hashBestChain; extern CBlockIndex* pindexBest; -extern uint64 nPooledTx; extern unsigned int nTransactionsUpdated; extern uint64 nLastBlockTx; extern uint64 nLastBlockSize; @@ -457,13 +449,13 @@ public: { if (vin.size() != old.vin.size()) return false; - for (int i = 0; i < vin.size(); i++) + for (unsigned int i = 0; i < vin.size(); i++) if (vin[i].prevout != old.vin[i].prevout) return false; bool fNewer = false; unsigned int nLowest = std::numeric_limits<unsigned int>::max(); - for (int i = 0; i < vin.size(); i++) + for (unsigned int i = 0; i < vin.size(); i++) { if (vin[i].nSequence != old.vin[i].nSequence) { @@ -550,7 +542,7 @@ public: // Base fee is either MIN_TX_FEE or MIN_RELAY_TX_FEE int64 nBaseFee = (mode == GMF_RELAY) ? MIN_RELAY_TX_FEE : MIN_TX_FEE; - unsigned int nBytes = ::GetSerializeSize(*this, SER_NETWORK); + unsigned int nBytes = ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION); unsigned int nNewBlockSize = nBlockSize + nBytes; int64 nMinFee = (1 + (int64)nBytes / 1000) * nBaseFee; @@ -595,7 +587,7 @@ public: bool ReadFromDisk(CDiskTxPos pos, FILE** pfileRet=NULL) { - CAutoFile filein = OpenBlockFile(pos.nFile, 0, pfileRet ? "rb+" : "rb"); + CAutoFile filein = CAutoFile(OpenBlockFile(pos.nFile, 0, pfileRet ? "rb+" : "rb"), SER_DISK, CLIENT_VERSION); if (!filein) return error("CTransaction::ReadFromDisk() : OpenBlockFile failed"); @@ -637,9 +629,9 @@ public: vin.size(), vout.size(), nLockTime); - for (int i = 0; i < vin.size(); i++) + for (unsigned int i = 0; i < vin.size(); i++) str += " " + vin[i].ToString() + "\n"; - for (int i = 0; i < vout.size(); i++) + for (unsigned int i = 0; i < vout.size(); i++) str += " " + vout[i].ToString() + "\n"; return str; } @@ -689,9 +681,6 @@ public: protected: const CTxOut& GetOutputFor(const CTxIn& input, const MapPrevTx& inputs) const; - bool AddToMemoryPoolUnchecked(); -public: - bool RemoveFromMemoryPool(); }; @@ -946,7 +935,7 @@ public: bool WriteToDisk(unsigned int& nFileRet, unsigned int& nBlockPosRet) { // Open history file to append - CAutoFile fileout = AppendBlockFile(nFileRet); + CAutoFile fileout = CAutoFile(AppendBlockFile(nFileRet), SER_DISK, CLIENT_VERSION); if (!fileout) return error("CBlock::WriteToDisk() : AppendBlockFile failed"); @@ -979,7 +968,7 @@ public: SetNull(); // Open history file to read - CAutoFile filein = OpenBlockFile(nFile, nBlockPos, "rb"); + CAutoFile filein = CAutoFile(OpenBlockFile(nFile, nBlockPos, "rb"), SER_DISK, CLIENT_VERSION); if (!filein) return error("CBlock::ReadFromDisk() : OpenBlockFile failed"); if (!fReadTransactions) @@ -1006,13 +995,13 @@ public: hashMerkleRoot.ToString().substr(0,10).c_str(), nTime, nBits, nNonce, vtx.size()); - for (int i = 0; i < vtx.size(); i++) + for (unsigned int i = 0; i < vtx.size(); i++) { printf(" "); vtx[i].print(); } printf(" vMerkleTree: "); - for (int i = 0; i < vMerkleTree.size(); i++) + for (unsigned int i = 0; i < vMerkleTree.size(); i++) printf("%s ", vMerkleTree[i].ToString().substr(0,10).c_str()); printf("\n"); } @@ -1140,7 +1129,7 @@ public: bool EraseBlockFromDisk() { // Open history file - CAutoFile fileout = OpenBlockFile(nFile, nBlockPos, "rb+"); + CAutoFile fileout = CAutoFile(OpenBlockFile(nFile, nBlockPos, "rb+"), SER_DISK, CLIENT_VERSION); if (!fileout) return false; @@ -1600,7 +1589,7 @@ public: return error("CAlert::CheckSignature() : verify signature failed"); // Now unserialize the data - CDataStream sMsg(vchMsg); + CDataStream sMsg(vchMsg, SER_NETWORK, PROTOCOL_VERSION); sMsg >> *(CUnsignedAlert*)this; return true; } @@ -1608,4 +1597,35 @@ public: bool ProcessAlert(); }; +class CTxMemPool +{ +public: + mutable CCriticalSection cs; + std::map<uint256, CTransaction> mapTx; + std::map<COutPoint, CInPoint> mapNextTx; + + bool accept(CTxDB& txdb, CTransaction &tx, + bool fCheckInputs, bool* pfMissingInputs); + bool addUnchecked(CTransaction &tx); + bool remove(CTransaction &tx); + + unsigned long size() + { + LOCK(cs); + return mapTx.size(); + } + + bool exists(uint256 hash) + { + return (mapTx.count(hash) != 0); + } + + CTransaction& lookup(uint256 hash) + { + return mapTx[hash]; + } +}; + +extern CTxMemPool mempool; + #endif diff --git a/src/makefile.linux-mingw b/src/makefile.linux-mingw index 9f005424f6..1ea65cd2e5 100644 --- a/src/makefile.linux-mingw +++ b/src/makefile.linux-mingw @@ -62,6 +62,7 @@ OBJS= \ obj/script.o \ obj/util.o \ obj/wallet.o \ + obj/walletdb.o \ obj/noui.o all: bitcoind.exe diff --git a/src/makefile.mingw b/src/makefile.mingw index 397fdf4f32..5584df5603 100644 --- a/src/makefile.mingw +++ b/src/makefile.mingw @@ -59,6 +59,7 @@ OBJS= \ obj/script.o \ obj/util.o \ obj/wallet.o \ + obj/walletdb.o \ obj/noui.o diff --git a/src/makefile.osx b/src/makefile.osx index e2e35de5cc..aaac6700bd 100644 --- a/src/makefile.osx +++ b/src/makefile.osx @@ -84,6 +84,7 @@ OBJS= \ obj/script.o \ obj/util.o \ obj/wallet.o \ + obj/walletdb.o \ obj/noui.o ifdef USE_UPNP diff --git a/src/makefile.unix b/src/makefile.unix index 9bc780d53c..fc901ca02c 100644 --- a/src/makefile.unix +++ b/src/makefile.unix @@ -103,6 +103,7 @@ OBJS= \ obj/script.o \ obj/util.o \ obj/wallet.o \ + obj/walletdb.o \ obj/noui.o diff --git a/src/net.cpp b/src/net.cpp index b0f365061c..38c0d3d582 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -3,13 +3,13 @@ // Distributed under the MIT/X11 software license, see the accompanying // file license.txt or http://www.opensource.org/licenses/mit-license.php. -#include "headers.h" #include "irc.h" #include "db.h" #include "net.h" #include "init.h" #include "strlcpy.h" #include "addrman.h" +#include "ui_interface.h" #ifdef WIN32 #include <string.h> @@ -162,14 +162,14 @@ bool GetMyExternalIP2(const CService& addrConnect, const char* pszGet, const cha } if (pszKeyword == NULL) break; - if (strLine.find(pszKeyword) != -1) + if (strLine.find(pszKeyword) != string::npos) { strLine = strLine.substr(strLine.find(pszKeyword) + strlen(pszKeyword)); break; } } closesocket(hSocket); - if (strLine.find("<") != -1) + if (strLine.find("<") != string::npos) strLine = strLine.substr(0, strLine.find("<")); strLine = strLine.substr(strspn(strLine.c_str(), " \t\n\r")); while (strLine.size() > 0 && isspace(strLine[strLine.size()-1])) @@ -624,7 +624,7 @@ void ThreadSocketHandler2(void* parg) if (hSocketMax > -1) { printf("socket select error %d\n", nErr); - for (int i = 0; i <= hSocketMax; i++) + for (unsigned int i = 0; i <= hSocketMax; i++) FD_SET(i, &fdsetRecv); } FD_ZERO(&fdsetSend); @@ -1024,7 +1024,7 @@ void ThreadDNSAddressSeed2(void* parg) { printf("Loading addresses from DNS seeds (could take a while)\n"); - for (int seed_idx = 0; seed_idx < ARRAYLEN(strDNSSeed); seed_idx++) { + for (unsigned int seed_idx = 0; seed_idx < ARRAYLEN(strDNSSeed); seed_idx++) { vector<CNetAddr> vaddr; vector<CAddress> vAdd; if (LookupHost(strDNSSeed[seed_idx][1], vaddr)) @@ -1238,7 +1238,7 @@ void ThreadOpenConnections2(void* parg) if (addrman.size()==0 && (GetTime() - nStart > 60 || fTOR) && !fTestNet) { std::vector<CAddress> vAdd; - for (int i = 0; i < ARRAYLEN(pnSeed); i++) + for (unsigned int i = 0; i < ARRAYLEN(pnSeed); i++) { // It'll only connect to one or two seed nodes because once it connects, // it'll get a pile of addresses with newer timestamps. @@ -117,7 +117,7 @@ public: int64 nLastRecv; int64 nLastSendEmpty; int64 nTimeConnected; - unsigned int nHeaderStart; + int nHeaderStart; unsigned int nMessageStart; CAddress addr; int nVersion; @@ -157,14 +157,10 @@ public: CCriticalSection cs_inventory; std::multimap<int64, CInv> mapAskFor; - CNode(SOCKET hSocketIn, CAddress addrIn, bool fInboundIn=false) + CNode(SOCKET hSocketIn, CAddress addrIn, bool fInboundIn=false) : vSend(SER_NETWORK, MIN_PROTO_VERSION), vRecv(SER_NETWORK, MIN_PROTO_VERSION) { nServices = 0; hSocket = hSocketIn; - vSend.SetType(SER_NETWORK); - vRecv.SetType(SER_NETWORK); - vSend.SetVersion(209); - vRecv.SetVersion(209); nLastSend = 0; nLastRecv = 0; nLastSendEmpty = GetTime(); @@ -299,7 +295,7 @@ public: void AbortMessage() { - if (nHeaderStart == -1) + if (nHeaderStart < 0) return; vSend.resize(nHeaderStart); nHeaderStart = -1; @@ -319,7 +315,7 @@ public: return; } - if (nHeaderStart == -1) + if (nHeaderStart < 0) return; // Set the size @@ -344,7 +340,7 @@ public: void EndMessageAbortIfEmpty() { - if (nHeaderStart == -1) + if (nHeaderStart < 0) return; int nSize = vSend.size() - nMessageStart; if (nSize > 0) @@ -612,7 +608,7 @@ inline void RelayInventory(const CInv& inv) template<typename T> void RelayMessage(const CInv& inv, const T& a) { - CDataStream ss(SER_NETWORK); + CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss.reserve(10000); ss << a; RelayMessage(inv, ss); @@ -631,7 +627,7 @@ inline void RelayMessage<>(const CInv& inv, const CDataStream& ss) } // Save original serialized message so newer versions are preserved - mapRelay[inv] = ss; + mapRelay.insert(std::make_pair(inv, ss)); vRelayExpiration.push_back(std::make_pair(GetTime() + 15 * 60, inv)); } diff --git a/src/netbase.cpp b/src/netbase.cpp index baf7c412a0..8b30ffc140 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -22,7 +22,7 @@ int nConnectTimeout = 5000; static const unsigned char pchIPv4[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff }; -bool static LookupIntern(const char *pszName, std::vector<CNetAddr>& vIP, int nMaxSolutions, bool fAllowLookup) +bool static LookupIntern(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions, bool fAllowLookup) { vIP.clear(); struct addrinfo aiHint; @@ -77,7 +77,7 @@ bool static LookupIntern(const char *pszName, std::vector<CNetAddr>& vIP, int nM return (vIP.size() > 0); } -bool LookupHost(const char *pszName, std::vector<CNetAddr>& vIP, int nMaxSolutions, bool fAllowLookup) +bool LookupHost(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions, bool fAllowLookup) { if (pszName[0] == 0) return false; @@ -93,12 +93,12 @@ bool LookupHost(const char *pszName, std::vector<CNetAddr>& vIP, int nMaxSolutio return LookupIntern(pszHost, vIP, nMaxSolutions, fAllowLookup); } -bool LookupHostNumeric(const char *pszName, std::vector<CNetAddr>& vIP, int nMaxSolutions) +bool LookupHostNumeric(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions) { return LookupHost(pszName, vIP, nMaxSolutions, false); } -bool Lookup(const char *pszName, std::vector<CService>& vAddr, int portDefault, bool fAllowLookup, int nMaxSolutions) +bool Lookup(const char *pszName, std::vector<CService>& vAddr, int portDefault, bool fAllowLookup, unsigned int nMaxSolutions) { if (pszName[0] == 0) return false; @@ -136,7 +136,7 @@ bool Lookup(const char *pszName, std::vector<CService>& vAddr, int portDefault, if (!fRet) return false; vAddr.resize(vIP.size()); - for (int i = 0; i < vIP.size(); i++) + for (unsigned int i = 0; i < vIP.size(); i++) vAddr[i] = CService(vIP[i], port); return true; } diff --git a/src/netbase.h b/src/netbase.h index 9e79de4253..00b6850b2a 100644 --- a/src/netbase.h +++ b/src/netbase.h @@ -7,27 +7,6 @@ #include <string> #include <vector> -#ifdef WIN32 -#define _WIN32_WINNT 0x0501 -#define WIN32_LEAN_AND_MEAN 1 -#ifndef NOMINMAX -#define NOMINMAX -#endif -#include <winsock2.h> -#include <mswsock.h> -#include <ws2tcpip.h> -#else -#include <sys/types.h> -#include <sys/socket.h> -#include <arpa/inet.h> -#include <netdb.h> -#include <net/if.h> -#include <ifaddrs.h> -#endif -#ifdef BSD -#include <netinet/in.h> -#endif - #include "serialize.h" #include "compat.h" @@ -134,10 +113,10 @@ class CService : public CNetAddr ) }; -bool LookupHost(const char *pszName, std::vector<CNetAddr>& vIP, int nMaxSolutions = 0, bool fAllowLookup = true); -bool LookupHostNumeric(const char *pszName, std::vector<CNetAddr>& vIP, int nMaxSolutions = 0); +bool LookupHost(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions = 0, bool fAllowLookup = true); +bool LookupHostNumeric(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions = 0); bool Lookup(const char *pszName, CService& addr, int portDefault = 0, bool fAllowLookup = true); -bool Lookup(const char *pszName, std::vector<CService>& vAddr, int portDefault = 0, bool fAllowLookup = true, int nMaxSolutions = 0); +bool Lookup(const char *pszName, std::vector<CService>& vAddr, int portDefault = 0, bool fAllowLookup = true, unsigned int nMaxSolutions = 0); bool LookupNumeric(const char *pszName, CService& addr, int portDefault = 0); bool ConnectSocket(const CService &addr, SOCKET& hSocketRet, int nTimeout = nConnectTimeout); diff --git a/src/noui.cpp b/src/noui.cpp index 077e460a70..08a08b439a 100644 --- a/src/noui.cpp +++ b/src/noui.cpp @@ -5,7 +5,6 @@ #include "ui_interface.h" #include <string> -#include "headers.h" #include "init.h" int ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style) diff --git a/src/protocol.cpp b/src/protocol.cpp index 15fbf9fc0d..06306cf8e1 100644 --- a/src/protocol.cpp +++ b/src/protocol.cpp @@ -107,7 +107,7 @@ CInv::CInv(int typeIn, const uint256& hashIn) CInv::CInv(const std::string& strType, const uint256& hashIn) { - int i; + unsigned int i; for (i = 1; i < ARRAYLEN(ppszTypeName); i++) { if (strType == ppszTypeName[i]) diff --git a/src/protocol.h b/src/protocol.h index e639127355..f7331c1923 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -12,7 +12,6 @@ #include "serialize.h" #include "netbase.h" -#include "util.h" #include <string> #include "uint256.h" @@ -79,9 +78,10 @@ class CAddress : public CService if (fRead) pthis->Init(); if (nType & SER_DISK) - READWRITE(nVersion); - if ((nType & SER_DISK) || (nVersion >= 31402 && !(nType & SER_GETHASH))) - READWRITE(nTime); + READWRITE(nVersion); + if ((nType & SER_DISK) || + (nVersion >= CADDR_TIME_VERSION && !(nType & SER_GETHASH))) + READWRITE(nTime); READWRITE(nServices); READWRITE(*pip); ) diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp index 0239a167d7..7b95f51c04 100644 --- a/src/qt/addresstablemodel.cpp +++ b/src/qt/addresstablemodel.cpp @@ -2,7 +2,7 @@ #include "guiutil.h" #include "walletmodel.h" -#include "headers.h" +#include "wallet.h" #include <QFont> #include <QColor> diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 463b2cfa79..c7830871b5 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -7,8 +7,8 @@ #include "optionsmodel.h" #include "guiutil.h" -#include "headers.h" #include "init.h" +#include "ui_interface.h" #include "qtipcserver.h" #include <QApplication> diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index 284bee0e8e..cb602ce327 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -4,7 +4,7 @@ #include "addresstablemodel.h" #include "transactiontablemodel.h" -#include "headers.h" +#include "main.h" #include <QDateTime> diff --git a/src/qt/csvmodelwriter.cpp b/src/qt/csvmodelwriter.cpp index 4b21b8c4be..84578b3322 100644 --- a/src/qt/csvmodelwriter.cpp +++ b/src/qt/csvmodelwriter.cpp @@ -6,7 +6,7 @@ CSVModelWriter::CSVModelWriter(const QString &filename, QObject *parent) : QObject(parent), - filename(filename) + filename(filename), model(0) { } diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index cb2473240e..f1e8a5f1bc 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -3,8 +3,6 @@ #include "walletmodel.h" #include "bitcoinunits.h" -#include "headers.h" - #include <QString> #include <QDateTime> #include <QDoubleValidator> diff --git a/src/qt/messagepage.cpp b/src/qt/messagepage.cpp index 46a0cbae24..18bb64fe6c 100644 --- a/src/qt/messagepage.cpp +++ b/src/qt/messagepage.cpp @@ -91,7 +91,7 @@ void MessagePage::on_signMessage_clicked() return; } - CDataStream ss(SER_GETHASH); + CDataStream ss(SER_GETHASH, 0); ss << strMessageMagic; ss << ui->message->document()->toPlainText().toStdString(); diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index ed2225cbf5..f7d9b0da2e 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -2,8 +2,8 @@ #include "bitcoinunits.h" #include <QSettings> -#include "headers.h" #include "init.h" +#include "walletdb.h" OptionsModel::OptionsModel(QObject *parent) : QAbstractListModel(parent) diff --git a/src/qt/qtipcserver.cpp b/src/qt/qtipcserver.cpp index 3c7889ca71..102ac0ff4e 100644 --- a/src/qt/qtipcserver.cpp +++ b/src/qt/qtipcserver.cpp @@ -7,7 +7,8 @@ #include <boost/tokenizer.hpp> #include <boost/date_time/posix_time/posix_time.hpp> -#include "headers.h" +#include "ui_interface.h" +#include "util.h" #include "qtipcserver.h" using namespace boost::interprocess; diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index dd7dd61390..286cddf2a9 100644 --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -3,7 +3,9 @@ #include "guiutil.h" #include "bitcoinunits.h" -#include "headers.h" +#include "main.h" +#include "wallet.h" +#include "db.h" #include "ui_interface.h" #include <QString> diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp index 57210dcc02..32350eaa5a 100644 --- a/src/qt/transactionrecord.cpp +++ b/src/qt/transactionrecord.cpp @@ -1,6 +1,6 @@ #include "transactionrecord.h" -#include "headers.h" +#include "wallet.h" /* Return positive answer if transaction should be shown in list. */ @@ -146,12 +146,6 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet * // // Mixed debit transaction, can't break down payees // - bool fAllMine = true; - BOOST_FOREACH(const CTxOut& txout, wtx.vout) - fAllMine = fAllMine && wallet->IsMine(txout); - BOOST_FOREACH(const CTxIn& txin, wtx.vin) - fAllMine = fAllMine && wallet->IsMine(txin); - parts.append(TransactionRecord(hash, nTime, TransactionRecord::Other, "", nNet, 0)); } } diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index 41c9db1123..5f505f444e 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -8,7 +8,7 @@ #include "addresstablemodel.h" #include "bitcoinunits.h" -#include "headers.h" +#include "wallet.h" #include <QLocale> #include <QList> diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 9c28a8abc8..7a83f6cefb 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -4,8 +4,9 @@ #include "addresstablemodel.h" #include "transactiontablemodel.h" -#include "headers.h" -#include "db.h" // for BackupWallet +#include "ui_interface.h" +#include "wallet.h" +#include "walletdb.h" // for BackupWallet #include <QSet> diff --git a/src/rpcdump.cpp b/src/rpcdump.cpp index 5bb4789cd3..1bc87e9217 100644 --- a/src/rpcdump.cpp +++ b/src/rpcdump.cpp @@ -2,9 +2,9 @@ // Distributed under the MIT/X11 software license, see the accompanying // file license.txt or http://www.opensource.org/licenses/mit-license.php. -#include "headers.h" #include "init.h" // for pwalletMain #include "bitcoinrpc.h" +#include "ui_interface.h" #include <boost/lexical_cast.hpp> diff --git a/src/script.cpp b/src/script.cpp index 21f101e1c5..fc0a5b3eaa 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -2,11 +2,17 @@ // Copyright (c) 2009-2012 The Bitcoin developers // Distributed under the MIT/X11 software license, see the accompanying // file license.txt or http://www.opensource.org/licenses/mit-license.php. -#include "headers.h" +#include <boost/foreach.hpp> using namespace std; using namespace boost; +#include "script.h" +#include "keystore.h" +#include "bignum.h" +#include "key.h" +#include "main.h" + bool CheckSig(vector<unsigned char> vchSig, vector<unsigned char> vchPubKey, CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType); @@ -1086,7 +1092,7 @@ uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int } // Serialize and hash - CDataStream ss(SER_GETHASH); + CDataStream ss(SER_GETHASH, 0); ss.reserve(10000); ss << txTmp << nHashType; return Hash(ss.begin(), ss.end()); diff --git a/src/serialize.h b/src/serialize.h index 2d4aaba6a9..12ea1ec695 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -20,6 +20,7 @@ #include <boost/tuple/tuple_io.hpp> #include "allocators.h" +#include "version.h" typedef long long int64; typedef unsigned long long uint64; @@ -29,8 +30,6 @@ class CDataStream; class CAutoFile; static const unsigned int MAX_SIZE = 0x02000000; -static const int PROTOCOL_VERSION = 60000; - // Used to bypass the rule against non-const reference to temporary // where it makes sense with wrappers such as CFlatData or CTxDB template<typename T> @@ -58,7 +57,7 @@ enum }; #define IMPLEMENT_SERIALIZE(statements) \ - unsigned int GetSerializeSize(int nType=0, int nVersion=PROTOCOL_VERSION) const \ + unsigned int GetSerializeSize(int nType, int nVersion) const \ { \ CSerActionGetSerializeSize ser_action; \ const bool fGetSize = true; \ @@ -73,7 +72,7 @@ enum return nSerSize; \ } \ template<typename Stream> \ - void Serialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION) const \ + void Serialize(Stream& s, int nType, int nVersion) const \ { \ CSerActionSerialize ser_action; \ const bool fGetSize = false; \ @@ -84,7 +83,7 @@ enum {statements} \ } \ template<typename Stream> \ - void Unserialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION) \ + void Unserialize(Stream& s, int nType, int nVersion) \ { \ CSerActionUnserialize ser_action; \ const bool fGetSize = false; \ @@ -276,48 +275,6 @@ public: } }; - - -/** string stored as a fixed length field */ -template<std::size_t LEN> -class CFixedFieldString -{ -protected: - const std::string* pcstr; - std::string* pstr; -public: - explicit CFixedFieldString(const std::string& str) : pcstr(&str), pstr(NULL) { } - explicit CFixedFieldString(std::string& str) : pcstr(&str), pstr(&str) { } - - unsigned int GetSerializeSize(int, int=0) const - { - return LEN; - } - - template<typename Stream> - void Serialize(Stream& s, int, int=0) const - { - char pszBuf[LEN]; - strncpy(pszBuf, pcstr->c_str(), LEN); - s.write(pszBuf, LEN); - } - - template<typename Stream> - void Unserialize(Stream& s, int, int=0) - { - if (pstr == NULL) - throw std::ios_base::failure("CFixedFieldString::Unserialize : trying to unserialize to const string"); - char pszBuf[LEN+1]; - s.read(pszBuf, LEN); - pszBuf[LEN] = '\0'; - *pstr = pszBuf; - } -}; - - - - - // // Forward declarations // @@ -330,43 +287,43 @@ template<typename Stream, typename C> void Unserialize(Stream& is, std::basic_st // vector template<typename T, typename A> unsigned int GetSerializeSize_impl(const std::vector<T, A>& v, int nType, int nVersion, const boost::true_type&); template<typename T, typename A> unsigned int GetSerializeSize_impl(const std::vector<T, A>& v, int nType, int nVersion, const boost::false_type&); -template<typename T, typename A> inline unsigned int GetSerializeSize(const std::vector<T, A>& v, int nType, int nVersion=PROTOCOL_VERSION); +template<typename T, typename A> inline unsigned int GetSerializeSize(const std::vector<T, A>& v, int nType, int nVersion); template<typename Stream, typename T, typename A> void Serialize_impl(Stream& os, const std::vector<T, A>& v, int nType, int nVersion, const boost::true_type&); template<typename Stream, typename T, typename A> void Serialize_impl(Stream& os, const std::vector<T, A>& v, int nType, int nVersion, const boost::false_type&); -template<typename Stream, typename T, typename A> inline void Serialize(Stream& os, const std::vector<T, A>& v, int nType, int nVersion=PROTOCOL_VERSION); +template<typename Stream, typename T, typename A> inline void Serialize(Stream& os, const std::vector<T, A>& v, int nType, int nVersion); template<typename Stream, typename T, typename A> void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion, const boost::true_type&); template<typename Stream, typename T, typename A> void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion, const boost::false_type&); -template<typename Stream, typename T, typename A> inline void Unserialize(Stream& is, std::vector<T, A>& v, int nType, int nVersion=PROTOCOL_VERSION); +template<typename Stream, typename T, typename A> inline void Unserialize(Stream& is, std::vector<T, A>& v, int nType, int nVersion); // others derived from vector -extern inline unsigned int GetSerializeSize(const CScript& v, int nType, int nVersion=PROTOCOL_VERSION); -template<typename Stream> void Serialize(Stream& os, const CScript& v, int nType, int nVersion=PROTOCOL_VERSION); -template<typename Stream> void Unserialize(Stream& is, CScript& v, int nType, int nVersion=PROTOCOL_VERSION); +extern inline unsigned int GetSerializeSize(const CScript& v, int nType, int nVersion); +template<typename Stream> void Serialize(Stream& os, const CScript& v, int nType, int nVersion); +template<typename Stream> void Unserialize(Stream& is, CScript& v, int nType, int nVersion); // pair -template<typename K, typename T> unsigned int GetSerializeSize(const std::pair<K, T>& item, int nType, int nVersion=PROTOCOL_VERSION); -template<typename Stream, typename K, typename T> void Serialize(Stream& os, const std::pair<K, T>& item, int nType, int nVersion=PROTOCOL_VERSION); -template<typename Stream, typename K, typename T> void Unserialize(Stream& is, std::pair<K, T>& item, int nType, int nVersion=PROTOCOL_VERSION); +template<typename K, typename T> unsigned int GetSerializeSize(const std::pair<K, T>& item, int nType, int nVersion); +template<typename Stream, typename K, typename T> void Serialize(Stream& os, const std::pair<K, T>& item, int nType, int nVersion); +template<typename Stream, typename K, typename T> void Unserialize(Stream& is, std::pair<K, T>& item, int nType, int nVersion); // 3 tuple -template<typename T0, typename T1, typename T2> unsigned int GetSerializeSize(const boost::tuple<T0, T1, T2>& item, int nType, int nVersion=PROTOCOL_VERSION); -template<typename Stream, typename T0, typename T1, typename T2> void Serialize(Stream& os, const boost::tuple<T0, T1, T2>& item, int nType, int nVersion=PROTOCOL_VERSION); -template<typename Stream, typename T0, typename T1, typename T2> void Unserialize(Stream& is, boost::tuple<T0, T1, T2>& item, int nType, int nVersion=PROTOCOL_VERSION); +template<typename T0, typename T1, typename T2> unsigned int GetSerializeSize(const boost::tuple<T0, T1, T2>& item, int nType, int nVersion); +template<typename Stream, typename T0, typename T1, typename T2> void Serialize(Stream& os, const boost::tuple<T0, T1, T2>& item, int nType, int nVersion); +template<typename Stream, typename T0, typename T1, typename T2> void Unserialize(Stream& is, boost::tuple<T0, T1, T2>& item, int nType, int nVersion); // 4 tuple -template<typename T0, typename T1, typename T2, typename T3> unsigned int GetSerializeSize(const boost::tuple<T0, T1, T2, T3>& item, int nType, int nVersion=PROTOCOL_VERSION); -template<typename Stream, typename T0, typename T1, typename T2, typename T3> void Serialize(Stream& os, const boost::tuple<T0, T1, T2, T3>& item, int nType, int nVersion=PROTOCOL_VERSION); -template<typename Stream, typename T0, typename T1, typename T2, typename T3> void Unserialize(Stream& is, boost::tuple<T0, T1, T2, T3>& item, int nType, int nVersion=PROTOCOL_VERSION); +template<typename T0, typename T1, typename T2, typename T3> unsigned int GetSerializeSize(const boost::tuple<T0, T1, T2, T3>& item, int nType, int nVersion); +template<typename Stream, typename T0, typename T1, typename T2, typename T3> void Serialize(Stream& os, const boost::tuple<T0, T1, T2, T3>& item, int nType, int nVersion); +template<typename Stream, typename T0, typename T1, typename T2, typename T3> void Unserialize(Stream& is, boost::tuple<T0, T1, T2, T3>& item, int nType, int nVersion); // map -template<typename K, typename T, typename Pred, typename A> unsigned int GetSerializeSize(const std::map<K, T, Pred, A>& m, int nType, int nVersion=PROTOCOL_VERSION); -template<typename Stream, typename K, typename T, typename Pred, typename A> void Serialize(Stream& os, const std::map<K, T, Pred, A>& m, int nType, int nVersion=PROTOCOL_VERSION); -template<typename Stream, typename K, typename T, typename Pred, typename A> void Unserialize(Stream& is, std::map<K, T, Pred, A>& m, int nType, int nVersion=PROTOCOL_VERSION); +template<typename K, typename T, typename Pred, typename A> unsigned int GetSerializeSize(const std::map<K, T, Pred, A>& m, int nType, int nVersion); +template<typename Stream, typename K, typename T, typename Pred, typename A> void Serialize(Stream& os, const std::map<K, T, Pred, A>& m, int nType, int nVersion); +template<typename Stream, typename K, typename T, typename Pred, typename A> void Unserialize(Stream& is, std::map<K, T, Pred, A>& m, int nType, int nVersion); // set -template<typename K, typename Pred, typename A> unsigned int GetSerializeSize(const std::set<K, Pred, A>& m, int nType, int nVersion=PROTOCOL_VERSION); -template<typename Stream, typename K, typename Pred, typename A> void Serialize(Stream& os, const std::set<K, Pred, A>& m, int nType, int nVersion=PROTOCOL_VERSION); -template<typename Stream, typename K, typename Pred, typename A> void Unserialize(Stream& is, std::set<K, Pred, A>& m, int nType, int nVersion=PROTOCOL_VERSION); +template<typename K, typename Pred, typename A> unsigned int GetSerializeSize(const std::set<K, Pred, A>& m, int nType, int nVersion); +template<typename Stream, typename K, typename Pred, typename A> void Serialize(Stream& os, const std::set<K, Pred, A>& m, int nType, int nVersion); +template<typename Stream, typename K, typename Pred, typename A> void Unserialize(Stream& is, std::set<K, Pred, A>& m, int nType, int nVersion); @@ -379,19 +336,19 @@ template<typename Stream, typename K, typename Pred, typename A> void Unserializ // Thanks to Boost serialization for this idea. // template<typename T> -inline unsigned int GetSerializeSize(const T& a, long nType, int nVersion=PROTOCOL_VERSION) +inline unsigned int GetSerializeSize(const T& a, long nType, int nVersion) { return a.GetSerializeSize((int)nType, nVersion); } template<typename Stream, typename T> -inline void Serialize(Stream& os, const T& a, long nType, int nVersion=PROTOCOL_VERSION) +inline void Serialize(Stream& os, const T& a, long nType, int nVersion) { a.Serialize(os, (int)nType, nVersion); } template<typename Stream, typename T> -inline void Unserialize(Stream& is, T& a, long nType, int nVersion=PROTOCOL_VERSION) +inline void Unserialize(Stream& is, T& a, long nType, int nVersion) { a.Unserialize(is, (int)nType, nVersion); } @@ -479,10 +436,6 @@ inline void Serialize(Stream& os, const std::vector<T, A>& v, int nType, int nVe template<typename Stream, typename T, typename A> void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion, const boost::true_type&) { - //unsigned int nSize = ReadCompactSize(is); - //v.resize(nSize); - //is.read((char*)&v[0], nSize * sizeof(T)); - // Limit size per read so bogus size value won't cause out of memory v.clear(); unsigned int nSize = ReadCompactSize(is); @@ -499,11 +452,6 @@ void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion, template<typename Stream, typename T, typename A> void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion, const boost::false_type&) { - //unsigned int nSize = ReadCompactSize(is); - //v.resize(nSize); - //for (std::vector<T, A>::iterator vi = v.begin(); vi != v.end(); ++vi) - // Unserialize(is, (*vi), nType, nVersion); - v.clear(); unsigned int nSize = ReadCompactSize(is); unsigned int i = 0; @@ -782,39 +730,39 @@ public: typedef vector_type::const_iterator const_iterator; typedef vector_type::reverse_iterator reverse_iterator; - explicit CDataStream(int nTypeIn=SER_NETWORK, int nVersionIn=PROTOCOL_VERSION) + explicit CDataStream(int nTypeIn, int nVersionIn) { Init(nTypeIn, nVersionIn); } - CDataStream(const_iterator pbegin, const_iterator pend, int nTypeIn=SER_NETWORK, int nVersionIn=PROTOCOL_VERSION) : vch(pbegin, pend) + CDataStream(const_iterator pbegin, const_iterator pend, int nTypeIn, int nVersionIn) : vch(pbegin, pend) { Init(nTypeIn, nVersionIn); } #if !defined(_MSC_VER) || _MSC_VER >= 1300 - CDataStream(const char* pbegin, const char* pend, int nTypeIn=SER_NETWORK, int nVersionIn=PROTOCOL_VERSION) : vch(pbegin, pend) + CDataStream(const char* pbegin, const char* pend, int nTypeIn, int nVersionIn) : vch(pbegin, pend) { Init(nTypeIn, nVersionIn); } #endif - CDataStream(const vector_type& vchIn, int nTypeIn=SER_NETWORK, int nVersionIn=PROTOCOL_VERSION) : vch(vchIn.begin(), vchIn.end()) + CDataStream(const vector_type& vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end()) { Init(nTypeIn, nVersionIn); } - CDataStream(const std::vector<char>& vchIn, int nTypeIn=SER_NETWORK, int nVersionIn=PROTOCOL_VERSION) : vch(vchIn.begin(), vchIn.end()) + CDataStream(const std::vector<char>& vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end()) { Init(nTypeIn, nVersionIn); } - CDataStream(const std::vector<unsigned char>& vchIn, int nTypeIn=SER_NETWORK, int nVersionIn=PROTOCOL_VERSION) : vch((char*)&vchIn.begin()[0], (char*)&vchIn.end()[0]) + CDataStream(const std::vector<unsigned char>& vchIn, int nTypeIn, int nVersionIn) : vch((char*)&vchIn.begin()[0], (char*)&vchIn.end()[0]) { Init(nTypeIn, nVersionIn); } - void Init(int nTypeIn=SER_NETWORK, int nVersionIn=PROTOCOL_VERSION) + void Init(int nTypeIn, int nVersionIn) { nReadPos = 0; nType = nTypeIn; @@ -1028,7 +976,7 @@ public: } template<typename Stream> - void Serialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION) const + void Serialize(Stream& s, int nType, int nVersion) const { // Special case: stream << stream concatenates like stream += stream if (!vch.empty()) @@ -1137,7 +1085,7 @@ public: typedef FILE element_type; - CAutoFile(FILE* filenew=NULL, int nTypeIn=SER_DISK, int nVersionIn=PROTOCOL_VERSION) + CAutoFile(FILE* filenew, int nTypeIn, int nVersionIn) { file = filenew; nType = nTypeIn; @@ -1190,7 +1138,7 @@ public: void ReadVersion() { *this >> nVersion; } void WriteVersion() { *this << nVersion; } - CAutoFile& read(char* pch, int nSize) + CAutoFile& read(char* pch, size_t nSize) { if (!file) throw std::ios_base::failure("CAutoFile::read : file handle is NULL"); @@ -1199,7 +1147,7 @@ public: return (*this); } - CAutoFile& write(const char* pch, int nSize) + CAutoFile& write(const char* pch, size_t nSize) { if (!file) throw std::ios_base::failure("CAutoFile::write : file handle is NULL"); diff --git a/src/strlcpy.h b/src/strlcpy.h index d4d1908e7a..2cc786e953 100644 --- a/src/strlcpy.h +++ b/src/strlcpy.h @@ -15,6 +15,10 @@ */ #ifndef BITCOIN_STRLCPY_H #define BITCOIN_STRLCPY_H + +#include <stdlib.h> +#include <string.h> + /* * Copy src to string dst of size siz. At most siz-1 characters * will be copied. Always NUL terminates (unless siz == 0). diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp index 0b89414048..c0b00102a0 100644 --- a/src/test/DoS_tests.cpp +++ b/src/test/DoS_tests.cpp @@ -168,7 +168,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans) tx.vout[0].nValue = 1*CENT; tx.vout[0].scriptPubKey.SetBitcoinAddress(key.GetPubKey()); - CDataStream ds; + CDataStream ds(SER_DISK, CLIENT_VERSION); ds << tx; AddOrphanTx(ds); } @@ -187,7 +187,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans) tx.vout[0].scriptPubKey.SetBitcoinAddress(key.GetPubKey()); SignSignature(keystore, txPrev, tx, 0); - CDataStream ds; + CDataStream ds(SER_DISK, CLIENT_VERSION); ds << tx; AddOrphanTx(ds); } diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index d4abd6d2a7..5712b4a1b1 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -1,6 +1,7 @@ #include <boost/test/unit_test.hpp> #include "uint256.h" +#include "util.h" extern void SHA256Transform(void* pstate, void* pinput, const void* pinit); @@ -11,7 +12,7 @@ BOOST_AUTO_TEST_CASE(sha256transform_equality) unsigned int pSHA256InitState[8] = {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19}; - unsigned char pstate[32]; + // unsigned char pstate[32]; unsigned char pinput[64]; int i; diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index 99163e55f2..b680ede9a5 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -12,7 +12,7 @@ BOOST_AUTO_TEST_CASE(basic_transaction_tests) // Random real transaction (e2769b09e784f32f62ef849763d4f45b98e07ba658647343b915ff832b110436) unsigned char ch[] = {0x01, 0x00, 0x00, 0x00, 0x01, 0x6b, 0xff, 0x7f, 0xcd, 0x4f, 0x85, 0x65, 0xef, 0x40, 0x6d, 0xd5, 0xd6, 0x3d, 0x4f, 0xf9, 0x4f, 0x31, 0x8f, 0xe8, 0x20, 0x27, 0xfd, 0x4d, 0xc4, 0x51, 0xb0, 0x44, 0x74, 0x01, 0x9f, 0x74, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x49, 0x30, 0x46, 0x02, 0x21, 0x00, 0xda, 0x0d, 0xc6, 0xae, 0xce, 0xfe, 0x1e, 0x06, 0xef, 0xdf, 0x05, 0x77, 0x37, 0x57, 0xde, 0xb1, 0x68, 0x82, 0x09, 0x30, 0xe3, 0xb0, 0xd0, 0x3f, 0x46, 0xf5, 0xfc, 0xf1, 0x50, 0xbf, 0x99, 0x0c, 0x02, 0x21, 0x00, 0xd2, 0x5b, 0x5c, 0x87, 0x04, 0x00, 0x76, 0xe4, 0xf2, 0x53, 0xf8, 0x26, 0x2e, 0x76, 0x3e, 0x2d, 0xd5, 0x1e, 0x7f, 0xf0, 0xbe, 0x15, 0x77, 0x27, 0xc4, 0xbc, 0x42, 0x80, 0x7f, 0x17, 0xbd, 0x39, 0x01, 0x41, 0x04, 0xe6, 0xc2, 0x6e, 0xf6, 0x7d, 0xc6, 0x10, 0xd2, 0xcd, 0x19, 0x24, 0x84, 0x78, 0x9a, 0x6c, 0xf9, 0xae, 0xa9, 0x93, 0x0b, 0x94, 0x4b, 0x7e, 0x2d, 0xb5, 0x34, 0x2b, 0x9d, 0x9e, 0x5b, 0x9f, 0xf7, 0x9a, 0xff, 0x9a, 0x2e, 0xe1, 0x97, 0x8d, 0xd7, 0xfd, 0x01, 0xdf, 0xc5, 0x22, 0xee, 0x02, 0x28, 0x3d, 0x3b, 0x06, 0xa9, 0xd0, 0x3a, 0xcf, 0x80, 0x96, 0x96, 0x8d, 0x7d, 0xbb, 0x0f, 0x91, 0x78, 0xff, 0xff, 0xff, 0xff, 0x02, 0x8b, 0xa7, 0x94, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x19, 0x76, 0xa9, 0x14, 0xba, 0xde, 0xec, 0xfd, 0xef, 0x05, 0x07, 0x24, 0x7f, 0xc8, 0xf7, 0x42, 0x41, 0xd7, 0x3b, 0xc0, 0x39, 0x97, 0x2d, 0x7b, 0x88, 0xac, 0x40, 0x94, 0xa8, 0x02, 0x00, 0x00, 0x00, 0x00, 0x19, 0x76, 0xa9, 0x14, 0xc1, 0x09, 0x32, 0x48, 0x3f, 0xec, 0x93, 0xed, 0x51, 0xf5, 0xfe, 0x95, 0xe7, 0x25, 0x59, 0xf2, 0xcc, 0x70, 0x43, 0xf9, 0x88, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00}; vector<unsigned char> vch(ch, ch + sizeof(ch) -1); - CDataStream stream(vch); + CDataStream stream(vch, SER_DISK, CLIENT_VERSION); CTransaction tx; stream >> tx; BOOST_CHECK_MESSAGE(tx.CheckTransaction(), "Simple deserialized transaction should be valid."); diff --git a/src/uint256.h b/src/uint256.h index 0947816785..bf3c55bccb 100644 --- a/src/uint256.h +++ b/src/uint256.h @@ -5,9 +5,8 @@ #ifndef BITCOIN_UINT256_H #define BITCOIN_UINT256_H -#include "serialize.h" - #include <limits.h> +#include <string.h> #include <string> #include <vector> @@ -287,7 +286,7 @@ public: std::string GetHex() const { char psz[sizeof(pn)*2 + 1]; - for (int i = 0; i < sizeof(pn); i++) + for (unsigned int i = 0; i < sizeof(pn); i++) sprintf(psz + i*2, "%02x", ((unsigned char*)pn)[sizeof(pn) - i - 1]); return std::string(psz, psz + sizeof(pn)*2); } @@ -354,19 +353,22 @@ public: return pn[2*n] | (uint64)pn[2*n+1] << 32; } - unsigned int GetSerializeSize(int nType=0, int nVersion=PROTOCOL_VERSION) const +// unsigned int GetSerializeSize(int nType=0, int nVersion=PROTOCOL_VERSION) const + unsigned int GetSerializeSize(int nType, int nVersion) const { return sizeof(pn); } template<typename Stream> - void Serialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION) const +// void Serialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION) const + void Serialize(Stream& s, int nType, int nVersion) const { s.write((char*)pn, sizeof(pn)); } template<typename Stream> - void Unserialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION) +// void Unserialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION) + void Unserialize(Stream& s, int nType, int nVersion) { s.read((char*)pn, sizeof(pn)); } diff --git a/src/util.cpp b/src/util.cpp index a5427c061b..ac65d417b3 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -3,8 +3,10 @@ // Distributed under the MIT/X11 software license, see the accompanying // file license.txt or http://www.opensource.org/licenses/mit-license.php. -#include "headers.h" +#include "util.h" #include "strlcpy.h" +#include "version.h" +#include "ui_interface.h" #include <boost/algorithm/string/join.hpp> // Work around clang compilation problem in Boost 1.46: @@ -24,6 +26,31 @@ namespace boost { #include <boost/interprocess/sync/interprocess_mutex.hpp> #include <boost/interprocess/sync/interprocess_recursive_mutex.hpp> #include <boost/foreach.hpp> +#include <openssl/crypto.h> +#include <openssl/rand.h> + +#ifdef WIN32 +#ifdef _MSC_VER +#pragma warning(disable:4786) +#pragma warning(disable:4804) +#pragma warning(disable:4805) +#pragma warning(disable:4717) +#endif +#ifdef _WIN32_WINNT +#undef _WIN32_WINNT +#endif +#define _WIN32_WINNT 0x0501 +#ifdef _WIN32_IE +#undef _WIN32_IE +#endif +#define _WIN32_IE 0x0400 +#define WIN32_LEAN_AND_MEAN 1 +#ifndef NOMINMAX +#define NOMINMAX +#endif +#include "shlobj.h" +#include "shlwapi.h" +#endif using namespace std; using namespace boost; @@ -301,7 +328,6 @@ bool error(const char *format, ...) va_end(arg_ptr); if (ret < 0 || ret >= limit) { - ret = limit - 1; buffer[limit-1] = 0; } printf("ERROR: %s\n", buffer); @@ -1065,6 +1091,149 @@ std::string FormatSubVersion(const std::string& name, int nClientVersion, const return ss.str(); } +#ifdef WIN32 +boost::filesystem::path static StartupShortcutPath() +{ + return MyGetSpecialFolderPath(CSIDL_STARTUP, true) / "Bitcoin.lnk"; +} + +bool GetStartOnSystemStartup() +{ + return filesystem::exists(StartupShortcutPath()); +} + +bool SetStartOnSystemStartup(bool fAutoStart) +{ + // If the shortcut exists already, remove it for updating + boost::filesystem::remove(StartupShortcutPath()); + + if (fAutoStart) + { + CoInitialize(NULL); + + // Get a pointer to the IShellLink interface. + IShellLink* psl = NULL; + HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL, + CLSCTX_INPROC_SERVER, IID_IShellLink, + reinterpret_cast<void**>(&psl)); + + if (SUCCEEDED(hres)) + { + // Get the current executable path + TCHAR pszExePath[MAX_PATH]; + GetModuleFileName(NULL, pszExePath, sizeof(pszExePath)); + + TCHAR pszArgs[5] = TEXT("-min"); + + // Set the path to the shortcut target + psl->SetPath(pszExePath); + PathRemoveFileSpec(pszExePath); + psl->SetWorkingDirectory(pszExePath); + psl->SetShowCmd(SW_SHOWMINNOACTIVE); + psl->SetArguments(pszArgs); + + // Query IShellLink for the IPersistFile interface for + // saving the shortcut in persistent storage. + IPersistFile* ppf = NULL; + hres = psl->QueryInterface(IID_IPersistFile, + reinterpret_cast<void**>(&ppf)); + if (SUCCEEDED(hres)) + { + WCHAR pwsz[MAX_PATH]; + // Ensure that the string is ANSI. + MultiByteToWideChar(CP_ACP, 0, StartupShortcutPath().string().c_str(), -1, pwsz, MAX_PATH); + // Save the link by calling IPersistFile::Save. + hres = ppf->Save(pwsz, TRUE); + ppf->Release(); + psl->Release(); + CoUninitialize(); + return true; + } + psl->Release(); + } + CoUninitialize(); + return false; + } + return true; +} + +#elif defined(LINUX) + +// Follow the Desktop Application Autostart Spec: +// http://standards.freedesktop.org/autostart-spec/autostart-spec-latest.html + +boost::filesystem::path static GetAutostartDir() +{ + namespace fs = boost::filesystem; + + char* pszConfigHome = getenv("XDG_CONFIG_HOME"); + if (pszConfigHome) return fs::path(pszConfigHome) / "autostart"; + char* pszHome = getenv("HOME"); + if (pszHome) return fs::path(pszHome) / ".config" / "autostart"; + return fs::path(); +} + +boost::filesystem::path static GetAutostartFilePath() +{ + return GetAutostartDir() / "bitcoin.desktop"; +} + +bool GetStartOnSystemStartup() +{ + boost::filesystem::ifstream optionFile(GetAutostartFilePath()); + if (!optionFile.good()) + return false; + // Scan through file for "Hidden=true": + string line; + while (!optionFile.eof()) + { + getline(optionFile, line); + if (line.find("Hidden") != string::npos && + line.find("true") != string::npos) + return false; + } + optionFile.close(); + + return true; +} + +bool SetStartOnSystemStartup(bool fAutoStart) +{ + if (!fAutoStart) + boost::filesystem::remove(GetAutostartFilePath()); + else + { + char pszExePath[MAX_PATH+1]; + memset(pszExePath, 0, sizeof(pszExePath)); + if (readlink("/proc/self/exe", pszExePath, sizeof(pszExePath)-1) == -1) + return false; + + boost::filesystem::create_directories(GetAutostartDir()); + + boost::filesystem::ofstream optionFile(GetAutostartFilePath(), ios_base::out|ios_base::trunc); + if (!optionFile.good()) + return false; + // Write a bitcoin.desktop file to the autostart directory: + optionFile << "[Desktop Entry]\n"; + optionFile << "Type=Application\n"; + optionFile << "Name=Bitcoin\n"; + optionFile << "Exec=" << pszExePath << " -min\n"; + optionFile << "Terminal=false\n"; + optionFile << "Hidden=false\n"; + optionFile.close(); + } + return true; +} +#else + +// TODO: OSX startup stuff; see: +// http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPSystemStartup/Articles/CustomLogin.html + +bool GetStartOnSystemStartup() { return false; } +bool SetStartOnSystemStartup(bool fAutoStart) { return false; } + +#endif + #ifdef DEBUG_LOCKORDER diff --git a/src/util.h b/src/util.h index f6cb3caa1d..d9ec68c620 100644 --- a/src/util.h +++ b/src/util.h @@ -31,11 +31,14 @@ typedef int pid_t; /* define for windows compatiblity */ #include <openssl/sha.h> #include <openssl/ripemd.h> -#include "netbase.h" +#include "netbase.h" // for AddTimeData typedef long long int64; typedef unsigned long long uint64; +static const int64 COIN = 100000000; +static const int64 CENT = 1000000; + #define loop for (;;) #define BEGIN(a) ((char*)&(a)) #define END(a) ((char*)&((&(a))[1])) @@ -160,9 +163,8 @@ boost::filesystem::path GetConfigFile(); boost::filesystem::path GetPidFile(); void CreatePidFile(const boost::filesystem::path &path, pid_t pid); bool ReadConfigFile(std::map<std::string, std::string>& mapSettingsRet, std::map<std::string, std::vector<std::string> >& mapMultiSettingsRet); -#ifdef WIN32 -boost::filesystem::path MyGetSpecialFolderPath(int nFolder, bool fCreate); -#endif +bool GetStartOnSystemStartup(); +bool SetStartOnSystemStartup(bool fAutoStart); void ShrinkDebugFile(); int GetRandInt(int nMax); uint64 GetRand(uint64 nMax); diff --git a/src/version.cpp b/src/version.cpp index e1be5f491b..0c1e8bfa80 100644 --- a/src/version.cpp +++ b/src/version.cpp @@ -11,18 +11,8 @@ const std::string CLIENT_NAME("Satoshi"); // Client version number -#define CLIENT_VERSION_MAJOR 0 -#define CLIENT_VERSION_MINOR 6 -#define CLIENT_VERSION_REVISION 0 -#define CLIENT_VERSION_BUILD 99 #define CLIENT_VERSION_SUFFIX "-beta" -const int CLIENT_VERSION = 1000000 * CLIENT_VERSION_MAJOR - + 10000 * CLIENT_VERSION_MINOR - + 100 * CLIENT_VERSION_REVISION - + 1 * CLIENT_VERSION_BUILD; - - // The following part of the code determines the CLIENT_BUILD variable. // Several mechanisms are used for this: diff --git a/src/version.h b/src/version.h index c93b28fb7d..f63b1bdadd 100644 --- a/src/version.h +++ b/src/version.h @@ -6,9 +6,43 @@ #include <string> +// +// client versioning +// + +static const int CLIENT_VERSION_MAJOR = 0; +static const int CLIENT_VERSION_MINOR = 6; +static const int CLIENT_VERSION_REVISION = 0; +static const int CLIENT_VERSION_BUILD = 99; + +static const int CLIENT_VERSION = + 1000000 * CLIENT_VERSION_MAJOR + + 10000 * CLIENT_VERSION_MINOR + + 100 * CLIENT_VERSION_REVISION + + 1 * CLIENT_VERSION_BUILD; + extern const std::string CLIENT_NAME; extern const std::string CLIENT_BUILD; extern const std::string CLIENT_DATE; -extern const int CLIENT_VERSION; + +// +// network protocol versioning +// + +static const int PROTOCOL_VERSION = 60001; + +// earlier versions not supported as of Feb 2012, and are disconnected +static const int MIN_PROTO_VERSION = 209; + +// nTime field added to CAddress, starting with this version; +// if possible, avoid requesting addresses nodes older than this +static const int CADDR_TIME_VERSION = 31402; + +// only request blocks from nodes outside this range of versions +static const int NOBLKS_VERSION_START = 32000; +static const int NOBLKS_VERSION_END = 32400; + +// BIP 0031, pong message, is enabled for all versions AFTER this one +static const int BIP0031_VERSION = 60000; #endif diff --git a/src/wallet.cpp b/src/wallet.cpp index ff10e0cef8..53836be0cd 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -3,9 +3,10 @@ // Distributed under the MIT/X11 software license, see the accompanying // file license.txt or http://www.opensource.org/licenses/mit-license.php. -#include "headers.h" -#include "db.h" +#include "wallet.h" +#include "walletdb.h" #include "crypter.h" +#include "ui_interface.h" using namespace std; @@ -137,6 +138,11 @@ bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, return false; } +void CWallet::SetBestChain(const CBlockLocator& loc) +{ + CWalletDB walletdb(strWalletFile); + walletdb.WriteBestBlock(loc); +} // This class implements an addrIncoming entry that causes pre-0.4 // clients to crash on startup if reading a private-key-encrypted wallet. @@ -615,7 +621,7 @@ void CWalletTx::AddSupportingTransactions(CTxDB& txdb) LOCK(pwallet->cs_wallet); map<uint256, const CMerkleTx*> mapWalletPrev; set<uint256> setAlreadyDone; - for (int i = 0; i < vWorkQueue.size(); i++) + for (unsigned int i = 0; i < vWorkQueue.size(); i++) { uint256 hash = vWorkQueue[i]; if (setAlreadyDone.count(hash)) @@ -723,7 +729,7 @@ void CWallet::ReacceptWalletTransactions() 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++) + for (unsigned int i = 0; i < txindex.vSpent.size(); i++) { if (wtx.IsSpent(i)) continue; @@ -902,7 +908,7 @@ bool CWallet::SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfThe if (nDepth < (pcoin->IsFromMe() ? nConfMine : nConfTheirs)) continue; - for (int i = 0; i < pcoin->vout.size(); i++) + for (unsigned int i = 0; i < pcoin->vout.size(); i++) { if (pcoin->IsSpent(i) || !IsMine(pcoin->vout[i])) continue; @@ -935,7 +941,7 @@ bool CWallet::SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfThe if (nTotalLower == nTargetValue || nTotalLower == nTargetValue + CENT) { - for (int i = 0; i < vValue.size(); ++i) + for (unsigned int i = 0; i < vValue.size(); ++i) { setCoinsRet.insert(vValue[i].second); nValueRet += vValue[i].first; @@ -968,7 +974,7 @@ bool CWallet::SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfThe bool fReachedTarget = false; for (int nPass = 0; nPass < 2 && !fReachedTarget; nPass++) { - for (int i = 0; i < vValue.size(); i++) + for (unsigned int i = 0; i < vValue.size(); i++) { if (nPass == 0 ? rand() % 2 : !vfIncluded[i]) { @@ -997,7 +1003,7 @@ bool CWallet::SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfThe nValueRet += coinLowestLarger.first; } else { - for (int i = 0; i < vValue.size(); i++) + for (unsigned int i = 0; i < vValue.size(); i++) if (vfBest[i]) { setCoinsRet.insert(vValue[i].second); @@ -1006,7 +1012,7 @@ bool CWallet::SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfThe //// debug print printf("SelectCoins() best subset: "); - for (int i = 0; i < vValue.size(); i++) + for (unsigned 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()); @@ -1116,7 +1122,7 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64> >& vecSend, CW return false; // Limit size - unsigned int nBytes = ::GetSerializeSize(*(CTransaction*)&wtxNew, SER_NETWORK); + unsigned int nBytes = ::GetSerializeSize(*(CTransaction*)&wtxNew, SER_NETWORK, PROTOCOL_VERSION); if (nBytes >= MAX_BLOCK_SIZE_GEN/5) return false; dPriority /= nBytes; diff --git a/src/wallet.h b/src/wallet.h index 869e888fcd..c1461b1feb 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -5,7 +5,7 @@ #ifndef BITCOIN_WALLET_H #define BITCOIN_WALLET_H -#include "bignum.h" +#include "main.h" #include "key.h" #include "keystore.h" #include "script.h" @@ -25,6 +25,34 @@ enum WalletFeature FEATURE_LATEST = 60000 }; + +/** A key pool entry */ +class CKeyPool +{ +public: + int64 nTime; + std::vector<unsigned char> vchPubKey; + + CKeyPool() + { + nTime = GetTime(); + } + + CKeyPool(const std::vector<unsigned char>& vchPubKeyIn) + { + nTime = GetTime(); + vchPubKey = vchPubKeyIn; + } + + IMPLEMENT_SERIALIZE + ( + if (!(nType & SER_GETHASH)) + READWRITE(nVersion); + READWRITE(nTime); + READWRITE(vchPubKey); + ) +}; + /** A CWallet is an extension of a keystore, which also maintains a set of transactions and balances, * and provides the ability to create new transactions. */ @@ -196,11 +224,7 @@ public: } return nChange; } - void SetBestChain(const CBlockLocator& loc) - { - CWalletDB walletdb(strWalletFile); - walletdb.WriteBestBlock(loc); - } + void SetBestChain(const CBlockLocator& loc); int LoadWallet(bool& fFirstRunRet); // bool BackupWallet(const std::string& strDest); @@ -402,7 +426,7 @@ public: bool UpdateSpent(const std::vector<char>& vfNewSpent) { bool fReturn = false; - for (int i=0; i < vfNewSpent.size(); i++) + for (unsigned int i = 0; i < vfNewSpent.size(); i++) { if (i == vfSpent.size()) break; @@ -488,7 +512,7 @@ public: return nAvailableCreditCached; int64 nCredit = 0; - for (int i = 0; i < vout.size(); i++) + for (unsigned int i = 0; i < vout.size(); i++) { if (!IsSpent(i)) { @@ -541,7 +565,7 @@ public: std::vector<const CMerkleTx*> vWorkQueue; vWorkQueue.reserve(vtxPrev.size()+1); vWorkQueue.push_back(this); - for (int i = 0; i < vWorkQueue.size(); i++) + for (unsigned int i = 0; i < vWorkQueue.size(); i++) { const CMerkleTx* ptx = vWorkQueue[i]; diff --git a/src/walletdb.cpp b/src/walletdb.cpp new file mode 100644 index 0000000000..709ecac184 --- /dev/null +++ b/src/walletdb.cpp @@ -0,0 +1,428 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file license.txt or http://www.opensource.org/licenses/mit-license.php. + +#include "walletdb.h" +#include "wallet.h" +#include <boost/filesystem.hpp> + +using namespace std; +using namespace boost; + + +static uint64 nAccountingEntryNumber = 0; + +extern CCriticalSection cs_db; +extern map<string, int> mapFileUseCount; +extern void CloseDb(const string& strFile); + +// +// CWalletDB +// + +bool CWalletDB::WriteName(const string& strAddress, const string& strName) +{ + nWalletDBUpdated++; + return Write(make_pair(string("name"), strAddress), strName); +} + +bool CWalletDB::EraseName(const string& strAddress) +{ + // This should only be used for sending addresses, never for receiving addresses, + // receiving addresses must always have an address book entry if they're not change return. + nWalletDBUpdated++; + return Erase(make_pair(string("name"), strAddress)); +} + +bool CWalletDB::ReadAccount(const string& strAccount, CAccount& account) +{ + account.SetNull(); + return Read(make_pair(string("acc"), strAccount), account); +} + +bool CWalletDB::WriteAccount(const string& strAccount, const CAccount& account) +{ + return Write(make_pair(string("acc"), strAccount), account); +} + +bool CWalletDB::WriteAccountingEntry(const CAccountingEntry& acentry) +{ + return Write(boost::make_tuple(string("acentry"), acentry.strAccount, ++nAccountingEntryNumber), acentry); +} + +int64 CWalletDB::GetAccountCreditDebit(const string& strAccount) +{ + list<CAccountingEntry> entries; + ListAccountCreditDebit(strAccount, entries); + + int64 nCreditDebit = 0; + BOOST_FOREACH (const CAccountingEntry& entry, entries) + nCreditDebit += entry.nCreditDebit; + + return nCreditDebit; +} + +void CWalletDB::ListAccountCreditDebit(const string& strAccount, list<CAccountingEntry>& entries) +{ + bool fAllAccounts = (strAccount == "*"); + + Dbc* pcursor = GetCursor(); + if (!pcursor) + throw runtime_error("CWalletDB::ListAccountCreditDebit() : cannot create DB cursor"); + unsigned int fFlags = DB_SET_RANGE; + loop + { + // Read next record + CDataStream ssKey(SER_DISK, CLIENT_VERSION); + if (fFlags == DB_SET_RANGE) + ssKey << boost::make_tuple(string("acentry"), (fAllAccounts? string("") : strAccount), uint64(0)); + CDataStream ssValue(SER_DISK, CLIENT_VERSION); + int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags); + fFlags = DB_NEXT; + if (ret == DB_NOTFOUND) + break; + else if (ret != 0) + { + pcursor->close(); + throw runtime_error("CWalletDB::ListAccountCreditDebit() : error scanning DB"); + } + + // Unserialize + string strType; + ssKey >> strType; + if (strType != "acentry") + break; + CAccountingEntry acentry; + ssKey >> acentry.strAccount; + if (!fAllAccounts && acentry.strAccount != strAccount) + break; + + ssValue >> acentry; + entries.push_back(acentry); + } + + pcursor->close(); +} + + +int CWalletDB::LoadWallet(CWallet* pwallet) +{ + pwallet->vchDefaultKey.clear(); + int nFileVersion = 0; + vector<uint256> vWalletUpgrade; + bool fIsEncrypted = false; + + //// todo: shouldn't we catch exceptions and try to recover and continue? + { + LOCK(pwallet->cs_wallet); + int nMinVersion = 0; + if (Read((string)"minversion", nMinVersion)) + { + if (nMinVersion > CLIENT_VERSION) + return DB_TOO_NEW; + pwallet->LoadMinVersion(nMinVersion); + } + + // Get cursor + Dbc* pcursor = GetCursor(); + if (!pcursor) + { + printf("Error getting wallet database cursor\n"); + return DB_CORRUPT; + } + + loop + { + // Read next record + CDataStream ssKey(SER_DISK, CLIENT_VERSION); + CDataStream ssValue(SER_DISK, CLIENT_VERSION); + int ret = ReadAtCursor(pcursor, ssKey, ssValue); + if (ret == DB_NOTFOUND) + break; + else if (ret != 0) + { + printf("Error reading next record from wallet database\n"); + return DB_CORRUPT; + } + + // Unserialize + // Taking advantage of the fact that pair serialization + // is just the two items serialized one after the other + string strType; + ssKey >> strType; + if (strType == "name") + { + string strAddress; + ssKey >> strAddress; + ssValue >> pwallet->mapAddressBook[strAddress]; + } + else if (strType == "tx") + { + uint256 hash; + ssKey >> hash; + CWalletTx& wtx = pwallet->mapWallet[hash]; + ssValue >> wtx; + wtx.BindWallet(pwallet); + + if (wtx.GetHash() != hash) + printf("Error in wallet.dat, hash mismatch\n"); + + // Undo serialize changes in 31600 + if (31404 <= wtx.fTimeReceivedIsTxTime && wtx.fTimeReceivedIsTxTime <= 31703) + { + if (!ssValue.empty()) + { + char fTmp; + char fUnused; + ssValue >> fTmp >> fUnused >> wtx.strFromAccount; + printf("LoadWallet() upgrading tx ver=%d %d '%s' %s\n", wtx.fTimeReceivedIsTxTime, fTmp, wtx.strFromAccount.c_str(), hash.ToString().c_str()); + wtx.fTimeReceivedIsTxTime = fTmp; + } + else + { + printf("LoadWallet() repairing tx ver=%d %s\n", wtx.fTimeReceivedIsTxTime, hash.ToString().c_str()); + wtx.fTimeReceivedIsTxTime = 0; + } + vWalletUpgrade.push_back(hash); + } + + //// debug print + //printf("LoadWallet %s\n", wtx.GetHash().ToString().c_str()); + //printf(" %12I64d %s %s %s\n", + // wtx.vout[0].nValue, + // DateTimeStrFormat("%x %H:%M:%S", wtx.GetBlockTime()).c_str(), + // wtx.hashBlock.ToString().substr(0,20).c_str(), + // wtx.mapValue["message"].c_str()); + } + else if (strType == "acentry") + { + string strAccount; + ssKey >> strAccount; + uint64 nNumber; + ssKey >> nNumber; + if (nNumber > nAccountingEntryNumber) + nAccountingEntryNumber = nNumber; + } + else if (strType == "key" || strType == "wkey") + { + vector<unsigned char> vchPubKey; + ssKey >> vchPubKey; + CKey key; + if (strType == "key") + { + CPrivKey pkey; + ssValue >> pkey; + key.SetPubKey(vchPubKey); + key.SetPrivKey(pkey); + if (key.GetPubKey() != vchPubKey) + { + printf("Error reading wallet database: CPrivKey pubkey inconsistency\n"); + return DB_CORRUPT; + } + if (!key.IsValid()) + { + printf("Error reading wallet database: invalid CPrivKey\n"); + return DB_CORRUPT; + } + } + else + { + CWalletKey wkey; + ssValue >> wkey; + key.SetPubKey(vchPubKey); + key.SetPrivKey(wkey.vchPrivKey); + if (key.GetPubKey() != vchPubKey) + { + printf("Error reading wallet database: CWalletKey pubkey inconsistency\n"); + return DB_CORRUPT; + } + if (!key.IsValid()) + { + printf("Error reading wallet database: invalid CWalletKey\n"); + return DB_CORRUPT; + } + } + if (!pwallet->LoadKey(key)) + { + printf("Error reading wallet database: LoadKey failed\n"); + return DB_CORRUPT; + } + } + else if (strType == "mkey") + { + unsigned int nID; + ssKey >> nID; + CMasterKey kMasterKey; + ssValue >> kMasterKey; + if(pwallet->mapMasterKeys.count(nID) != 0) + { + printf("Error reading wallet database: duplicate CMasterKey id %u\n", nID); + return DB_CORRUPT; + } + pwallet->mapMasterKeys[nID] = kMasterKey; + if (pwallet->nMasterKeyMaxID < nID) + pwallet->nMasterKeyMaxID = nID; + } + else if (strType == "ckey") + { + vector<unsigned char> vchPubKey; + ssKey >> vchPubKey; + vector<unsigned char> vchPrivKey; + ssValue >> vchPrivKey; + if (!pwallet->LoadCryptedKey(vchPubKey, vchPrivKey)) + { + printf("Error reading wallet database: LoadCryptedKey failed\n"); + return DB_CORRUPT; + } + fIsEncrypted = true; + } + else if (strType == "defaultkey") + { + ssValue >> pwallet->vchDefaultKey; + } + else if (strType == "pool") + { + int64 nIndex; + ssKey >> nIndex; + pwallet->setKeyPool.insert(nIndex); + } + else if (strType == "version") + { + ssValue >> nFileVersion; + if (nFileVersion == 10300) + nFileVersion = 300; + } + else if (strType == "cscript") + { + uint160 hash; + ssKey >> hash; + CScript script; + ssValue >> script; + if (!pwallet->LoadCScript(script)) + { + printf("Error reading wallet database: LoadCScript failed\n"); + return DB_CORRUPT; + } + } + } + pcursor->close(); + } + + BOOST_FOREACH(uint256 hash, vWalletUpgrade) + WriteTx(hash, pwallet->mapWallet[hash]); + + printf("nFileVersion = %d\n", nFileVersion); + + + // Rewrite encrypted wallets of versions 0.4.0 and 0.5.0rc: + if (fIsEncrypted && (nFileVersion == 40000 || nFileVersion == 50000)) + return DB_NEED_REWRITE; + + if (nFileVersion < CLIENT_VERSION) // Update + WriteVersion(CLIENT_VERSION); + + return DB_LOAD_OK; +} + +void ThreadFlushWalletDB(void* parg) +{ + const string& strFile = ((const string*)parg)[0]; + static bool fOneThread; + if (fOneThread) + return; + fOneThread = true; + if (!GetBoolArg("-flushwallet", true)) + return; + + unsigned int nLastSeen = nWalletDBUpdated; + unsigned int nLastFlushed = nWalletDBUpdated; + int64 nLastWalletUpdate = GetTime(); + while (!fShutdown) + { + Sleep(500); + + if (nLastSeen != nWalletDBUpdated) + { + nLastSeen = nWalletDBUpdated; + nLastWalletUpdate = GetTime(); + } + + if (nLastFlushed != nWalletDBUpdated && GetTime() - nLastWalletUpdate >= 2) + { + TRY_LOCK(cs_db,lockDb); + if (lockDb) + { + // Don't do this if any databases are in use + int nRefCount = 0; + map<string, int>::iterator mi = mapFileUseCount.begin(); + while (mi != mapFileUseCount.end()) + { + nRefCount += (*mi).second; + mi++; + } + + if (nRefCount == 0 && !fShutdown) + { + map<string, int>::iterator mi = mapFileUseCount.find(strFile); + if (mi != mapFileUseCount.end()) + { + printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str()); + printf("Flushing wallet.dat\n"); + nLastFlushed = nWalletDBUpdated; + int64 nStart = GetTimeMillis(); + + // Flush wallet.dat so it's self contained + CloseDb(strFile); + dbenv.txn_checkpoint(0, 0, 0); + dbenv.lsn_reset(strFile.c_str(), 0); + + mapFileUseCount.erase(mi++); + printf("Flushed wallet.dat %"PRI64d"ms\n", GetTimeMillis() - nStart); + } + } + } + } + } +} + +bool BackupWallet(const CWallet& wallet, const string& strDest) +{ + if (!wallet.fFileBacked) + return false; + while (!fShutdown) + { + { + LOCK(cs_db); + if (!mapFileUseCount.count(wallet.strWalletFile) || mapFileUseCount[wallet.strWalletFile] == 0) + { + // Flush log data to the dat file + CloseDb(wallet.strWalletFile); + dbenv.txn_checkpoint(0, 0, 0); + dbenv.lsn_reset(wallet.strWalletFile.c_str(), 0); + mapFileUseCount.erase(wallet.strWalletFile); + + // Copy wallet.dat + filesystem::path pathSrc = GetDataDir() / wallet.strWalletFile; + filesystem::path pathDest(strDest); + if (filesystem::is_directory(pathDest)) + pathDest /= wallet.strWalletFile; + + try { +#if BOOST_VERSION >= 104000 + filesystem::copy_file(pathSrc, pathDest, filesystem::copy_option::overwrite_if_exists); +#else + filesystem::copy_file(pathSrc, pathDest); +#endif + printf("copied wallet.dat to %s\n", pathDest.string().c_str()); + return true; + } catch(const filesystem::filesystem_error &e) { + printf("error copying wallet.dat to %s - %s\n", pathDest.string().c_str(), e.what()); + return false; + } + } + } + Sleep(100); + } + return false; +} diff --git a/src/walletdb.h b/src/walletdb.h new file mode 100644 index 0000000000..46ba7967ca --- /dev/null +++ b/src/walletdb.h @@ -0,0 +1,179 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file license.txt or http://www.opensource.org/licenses/mit-license.php. +#ifndef BITCOIN_WALLETDB_H +#define BITCOIN_WALLETDB_H + +#include "db.h" + +class CKeyPool; +class CAccount; +class CAccountingEntry; + +/** Error statuses for the wallet database */ +enum DBErrors +{ + DB_LOAD_OK, + DB_CORRUPT, + DB_TOO_NEW, + DB_LOAD_FAIL, + DB_NEED_REWRITE +}; + +/** Access to the wallet database (wallet.dat) */ +class CWalletDB : public CDB +{ +public: + CWalletDB(std::string strFilename, const char* pszMode="r+") : CDB(strFilename.c_str(), pszMode) + { + } +private: + CWalletDB(const CWalletDB&); + void operator=(const CWalletDB&); +public: + bool ReadName(const std::string& strAddress, std::string& strName) + { + strName = ""; + return Read(std::make_pair(std::string("name"), strAddress), strName); + } + + bool WriteName(const std::string& strAddress, const std::string& strName); + + bool EraseName(const std::string& strAddress); + + bool ReadTx(uint256 hash, CWalletTx& wtx) + { + return Read(std::make_pair(std::string("tx"), hash), wtx); + } + + bool WriteTx(uint256 hash, const CWalletTx& wtx) + { + nWalletDBUpdated++; + return Write(std::make_pair(std::string("tx"), hash), wtx); + } + + bool EraseTx(uint256 hash) + { + nWalletDBUpdated++; + return Erase(std::make_pair(std::string("tx"), hash)); + } + + bool ReadKey(const std::vector<unsigned char>& vchPubKey, CPrivKey& vchPrivKey) + { + vchPrivKey.clear(); + return Read(std::make_pair(std::string("key"), vchPubKey), vchPrivKey); + } + + bool WriteKey(const std::vector<unsigned char>& vchPubKey, const CPrivKey& vchPrivKey) + { + nWalletDBUpdated++; + return Write(std::make_pair(std::string("key"), vchPubKey), vchPrivKey, false); + } + + bool WriteCryptedKey(const std::vector<unsigned char>& vchPubKey, const std::vector<unsigned char>& vchCryptedSecret, bool fEraseUnencryptedKey = true) + { + nWalletDBUpdated++; + if (!Write(std::make_pair(std::string("ckey"), vchPubKey), vchCryptedSecret, false)) + return false; + if (fEraseUnencryptedKey) + { + Erase(std::make_pair(std::string("key"), vchPubKey)); + Erase(std::make_pair(std::string("wkey"), vchPubKey)); + } + return true; + } + + bool WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey) + { + nWalletDBUpdated++; + return Write(std::make_pair(std::string("mkey"), nID), kMasterKey, true); + } + + // Support for BIP 0013 : see https://en.bitcoin.it/wiki/BIP_0013 + bool ReadCScript(const uint160 &hash, CScript& redeemScript) + { + redeemScript.clear(); + return Read(std::make_pair(std::string("cscript"), hash), redeemScript); + } + + bool WriteCScript(const uint160& hash, const CScript& redeemScript) + { + nWalletDBUpdated++; + return Write(std::make_pair(std::string("cscript"), hash), redeemScript, false); + } + + bool WriteBestBlock(const CBlockLocator& locator) + { + nWalletDBUpdated++; + return Write(std::string("bestblock"), locator); + } + + bool ReadBestBlock(CBlockLocator& locator) + { + return Read(std::string("bestblock"), locator); + } + + bool ReadDefaultKey(std::vector<unsigned char>& vchPubKey) + { + vchPubKey.clear(); + return Read(std::string("defaultkey"), vchPubKey); + } + + bool WriteDefaultKey(const std::vector<unsigned char>& vchPubKey) + { + nWalletDBUpdated++; + return Write(std::string("defaultkey"), vchPubKey); + } + + bool ReadPool(int64 nPool, CKeyPool& keypool) + { + return Read(std::make_pair(std::string("pool"), nPool), keypool); + } + + bool WritePool(int64 nPool, const CKeyPool& keypool) + { + nWalletDBUpdated++; + return Write(std::make_pair(std::string("pool"), nPool), keypool); + } + + bool ErasePool(int64 nPool) + { + nWalletDBUpdated++; + return Erase(std::make_pair(std::string("pool"), nPool)); + } + + // Settings are no longer stored in wallet.dat; these are + // used only for backwards compatibility: + template<typename T> + bool ReadSetting(const std::string& strKey, T& value) + { + return Read(std::make_pair(std::string("setting"), strKey), value); + } + template<typename T> + bool WriteSetting(const std::string& strKey, const T& value) + { + nWalletDBUpdated++; + return Write(std::make_pair(std::string("setting"), strKey), value); + } + bool EraseSetting(const std::string& strKey) + { + nWalletDBUpdated++; + return Erase(std::make_pair(std::string("setting"), strKey)); + } + + bool WriteMinVersion(int nVersion) + { + return Write(std::string("minversion"), nVersion); + } + + bool ReadAccount(const std::string& strAccount, CAccount& account); + bool WriteAccount(const std::string& strAccount, const CAccount& account); + bool WriteAccountingEntry(const CAccountingEntry& acentry); + int64 GetAccountCreditDebit(const std::string& strAccount); + void ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& acentries); + + int LoadWallet(CWallet* pwallet); +}; + +#endif // BITCOIN_WALLETDB_H |