diff options
-rw-r--r-- | base58.h | 2 | ||||
-rw-r--r-- | db.cpp | 9 | ||||
-rw-r--r-- | db.h | 3 | ||||
-rw-r--r-- | init.cpp | 38 | ||||
-rw-r--r-- | irc.cpp | 4 | ||||
-rw-r--r-- | main.cpp | 102 | ||||
-rw-r--r-- | main.h | 4 | ||||
-rw-r--r-- | net.cpp | 2 | ||||
-rw-r--r-- | net.h | 5 | ||||
-rw-r--r-- | script.cpp | 13 | ||||
-rw-r--r-- | serialize.h | 2 | ||||
-rw-r--r-- | ui.cpp | 1 | ||||
-rw-r--r-- | util.cpp | 27 | ||||
-rw-r--r-- | util.h | 25 |
14 files changed, 155 insertions, 82 deletions
@@ -152,7 +152,7 @@ inline bool DecodeBase58Check(const string& str, vector<unsigned char>& vchRet) -static const unsigned char ADDRESSVERSION = 0; +#define ADDRESSVERSION ((unsigned char)(fTestNet ? 111 : 0)) inline string Hash160ToAddress(uint160 hash160) { @@ -846,10 +846,13 @@ void BackupWallet(const string& strDest) } } + void CWalletDB::ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool) { nIndex = -1; keypool.vchPubKey.clear(); + CRITICAL_BLOCK(cs_main) + CRITICAL_BLOCK(cs_mapWallet) CRITICAL_BLOCK(cs_setKeyPool) { // Top up key pool @@ -881,7 +884,11 @@ void CWalletDB::ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool) void CWalletDB::KeepKey(int64 nIndex) { // Remove from key pool - Erase(make_pair(string("pool"), nIndex)); + CRITICAL_BLOCK(cs_main) + CRITICAL_BLOCK(cs_mapWallet) + { + Erase(make_pair(string("pool"), nIndex)); + } printf("keypool keep %"PRI64d"\n", nIndex); } @@ -455,7 +455,8 @@ public: ~CReserveKey() { - ReturnKey(); + if (!fShutdown) + ReturnKey(); } vector<unsigned char> GetReservedKey() @@ -165,22 +165,22 @@ bool AppInit2(int argc, char* argv[]) " bitcoin [options] help \t\t " + _("List commands\n") + " bitcoin [options] help <command> \t\t " + _("Get help for a command\n") + _("Options:\n") + - " -conf=<file> \t " + _("Specify configuration file (default: bitcoin.conf)\n") + - " -gen \t " + _("Generate coins\n") + - " -gen=0 \t " + _("Don't generate coins\n") + - " -min \t " + _("Start minimized\n") + - " -datadir=<dir> \t " + _("Specify data directory\n") + - " -proxy=<ip:port> \t " + _("Connect through socks4 proxy\n") + - " -addnode=<ip> \t " + _("Add a node to connect to\n") + - " -connect=<ip> \t " + _("Connect only to the specified node\n") + - " -server \t " + _("Accept command line and JSON-RPC commands\n") + - " -daemon \t " + _("Run in the background as a daemon and accept commands\n") + - " -rpcuser=<user> \t " + _("Username for JSON-RPC connections\n") + - " -rpcpassword=<pw>\t " + _("Password for JSON-RPC connections\n") + - " -rpcport=<port> \t " + _("Listen for JSON-RPC connections on <port>\n") + - " -rpcallowip=<ip> \t " + _("Allow JSON-RPC connections from specified IP address\n") + - " -rpcconnect=<ip> \t " + _("Send commands to node running on <ip>\n") + - " -? \t " + _("This help message\n"); + " -conf=<file> \t\t " + _("Specify configuration file (default: bitcoin.conf)\n") + + " -gen \t\t " + _("Generate coins\n") + + " -gen=0 \t\t " + _("Don't generate coins\n") + + " -min \t\t " + _("Start minimized\n") + + " -datadir=<dir> \t\t " + _("Specify data directory\n") + + " -proxy=<ip:port> \t " + _("Connect through socks4 proxy\n") + + " -addnode=<ip> \t " + _("Add a node to connect to\n") + + " -connect=<ip> \t\t " + _("Connect only to the specified node\n") + + " -server \t\t " + _("Accept command line and JSON-RPC commands\n") + + " -daemon \t\t " + _("Run in the background as a daemon and accept commands\n") + + " -testnet \t\t " + _("Use the test network\n") + + " -rpcuser=<user> \t " + _("Username for JSON-RPC connections\n") + + " -rpcpassword=<pw>\t " + _("Password for JSON-RPC connections\n") + + " -rpcport=<port> \t\t " + _("Listen for JSON-RPC connections on <port>\n") + + " -rpcallowip=<ip> \t\t " + _("Allow JSON-RPC connections from specified IP address\n") + + " -rpcconnect=<ip> \t " + _("Send commands to node running on <ip>\n"); #ifdef USE_SSL strUsage += string() + @@ -191,6 +191,9 @@ bool AppInit2(int argc, char* argv[]) " -rpcsslciphers=<ciphers> \t " + _("Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH)\n"); #endif + strUsage += string() + + " -? \t\t " + _("This help message\n"); + #if defined(__WXMSW__) && defined(GUI) // Tabs make the columns line up in the message box wxMessageBox(strUsage, "Bitcoin", wxOK); @@ -208,6 +211,9 @@ bool AppInit2(int argc, char* argv[]) if (mapArgs.count("-printtodebugger")) fPrintToDebugger = true; + if (mapArgs.count("-testnet")) + fTestNet = true; + if (fCommandLine) { int ret = CommandLineRPC(argc, argv); @@ -252,8 +252,8 @@ void ThreadIRCSeed2(void* parg) } Sleep(500); - Send(hSocket, "JOIN #bitcoin\r"); - Send(hSocket, "WHO #bitcoin\r"); + Send(hSocket, fTestNet ? "JOIN #bitcoinTEST\r" : "JOIN #bitcoin\r"); + Send(hSocket, fTestNet ? "WHO #bitcoinTEST\r" : "WHO #bitcoin\r"); int64 nStart = GetTime(); string strLine; @@ -21,7 +21,8 @@ unsigned int nTransactionsUpdated = 0; map<COutPoint, CInPoint> mapNextTx; map<uint256, CBlockIndex*> mapBlockIndex; -const uint256 hashGenesisBlock("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"); +uint256 hashGenesisBlock("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"); +CBigNum bnProofOfWorkLimit(~uint256(0) >> 32); CBlockIndex* pindexGenesisBlock = NULL; int nBestHeight = -1; CBigNum bnBestChainWork = 0; @@ -1487,12 +1488,13 @@ bool CBlock::AcceptBlock() return error("AcceptBlock() : contains a non-final transaction"); // Check that the block chain matches the known block chain up to a checkpoint - if ((nHeight == 11111 && hash != uint256("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d")) || - (nHeight == 33333 && hash != uint256("0x000000002dd5588a74784eaa7ab0507a18ad16a236e7b1ce69f00d7ddfb5d0a6")) || - (nHeight == 68555 && hash != uint256("0x00000000001e1b4903550a0b96e9a9405c8a95f387162e4944e8d9fbe501cd6a")) || - (nHeight == 70567 && hash != uint256("0x00000000006a49b14bcf27462068f1264c961f11fa2e0eddd2be0791e1d4124a")) || - (nHeight == 74000 && hash != uint256("0x0000000000573993a3c9e41ce34471c079dcf5f52a0e824a81e7f953b8661a20"))) - return error("AcceptBlock() : rejected by checkpoint lockin at %d", nHeight); + if (!fTestNet) + if ((nHeight == 11111 && hash != uint256("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d")) || + (nHeight == 33333 && hash != uint256("0x000000002dd5588a74784eaa7ab0507a18ad16a236e7b1ce69f00d7ddfb5d0a6")) || + (nHeight == 68555 && hash != uint256("0x00000000001e1b4903550a0b96e9a9405c8a95f387162e4944e8d9fbe501cd6a")) || + (nHeight == 70567 && hash != uint256("0x00000000006a49b14bcf27462068f1264c961f11fa2e0eddd2be0791e1d4124a")) || + (nHeight == 74000 && hash != uint256("0x0000000000573993a3c9e41ce34471c079dcf5f52a0e824a81e7f953b8661a20"))) + return error("AcceptBlock() : rejected by checkpoint lockin at %d", nHeight); // Write block to history file if (!CheckDiskSpace(::GetSerializeSize(*this, SER_DISK))) @@ -1683,6 +1685,16 @@ FILE* AppendBlockFile(unsigned int& nFileRet) bool LoadBlockIndex(bool fAllowNew) { + if (fTestNet) + { + hashGenesisBlock = uint256("0x0000000224b1593e3ff16a0e3b61285bbc393a39f78c8aa48c456142671f7110"); + bnProofOfWorkLimit = CBigNum(~uint256(0) >> 28); + pchMessageStart[0] = 0xfa; + pchMessageStart[1] = 0xbf; + pchMessageStart[2] = 0xb5; + pchMessageStart[3] = 0xda; + } + // // Load block index // @@ -1723,13 +1735,19 @@ bool LoadBlockIndex(bool fAllowNew) block.nBits = 0x1d00ffff; block.nNonce = 2083236893; - //// debug print - printf("%s\n", block.GetHash().ToString().c_str()); - printf("%s\n", hashGenesisBlock.ToString().c_str()); - printf("%s\n", block.hashMerkleRoot.ToString().c_str()); - assert(block.hashMerkleRoot == uint256("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b")); - block.print(); + if (fTestNet) + { + block.nTime = 1279232055; + block.nBits = 0x1d07fff8; + block.nNonce = 81622180; + } + //// debug print + printf("%s\n", block.GetHash().ToString().c_str()); + printf("%s\n", hashGenesisBlock.ToString().c_str()); + printf("%s\n", block.hashMerkleRoot.ToString().c_str()); + assert(block.hashMerkleRoot == uint256("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b")); + block.print(); assert(block.GetHash() == hashGenesisBlock); // Start new block file @@ -1963,7 +1981,10 @@ bool AlreadyHave(CTxDB& txdb, const CInv& inv) - +// The message start string is designed to be unlikely to occur in normal data. +// The characters are rarely used upper ascii, not valid as UTF-8, and produce +// a large 4-byte int at any alignment. +char pchMessageStart[4] = { 0xf9, 0xbe, 0xb4, 0xd9 }; bool ProcessMessages(CNode* pfrom) @@ -2022,19 +2043,14 @@ bool ProcessMessages(CNode* pfrom) if (nMessageSize > vRecv.size()) { // Rewind and wait for rest of message - ///// need a mechanism to give up waiting for overlong message size error vRecv.insert(vRecv.begin(), vHeaderSave.begin(), vHeaderSave.end()); break; } - // Copy message to its own buffer - CDataStream vMsg(vRecv.begin(), vRecv.begin() + nMessageSize, vRecv.nType, vRecv.nVersion); - vRecv.ignore(nMessageSize); - // Checksum if (vRecv.GetVersion() >= 209) { - uint256 hash = Hash(vMsg.begin(), vMsg.end()); + uint256 hash = Hash(vRecv.begin(), vRecv.begin() + nMessageSize); unsigned int nChecksum = 0; memcpy(&nChecksum, &hash, sizeof(nChecksum)); if (nChecksum != hdr.nChecksum) @@ -2045,6 +2061,10 @@ bool ProcessMessages(CNode* pfrom) } } + // Copy message to its own buffer + CDataStream vMsg(vRecv.begin(), vRecv.begin() + nMessageSize, vRecv.nType, vRecv.nVersion); + vRecv.ignore(nMessageSize); + // Process message bool fRet = false; try @@ -2208,20 +2228,27 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) addr.nTime -= 5 * 24 * 60 * 60; AddAddress(addr); pfrom->AddAddressKnown(addr); - if (!pfrom->fGetAddr && addr.IsRoutable()) + if (!pfrom->fGetAddr && vAddr.size() <= 10 && addr.IsRoutable()) { // Relay to a limited number of other nodes CRITICAL_BLOCK(cs_vNodes) { - // Use deterministic randomness to send to - // the same places for 12 hours at a time + // Use deterministic randomness to send to the same nodes for 24 hours + // at a time so the setAddrKnowns of the chosen nodes prevent repeats static uint256 hashSalt; if (hashSalt == 0) RAND_bytes((unsigned char*)&hashSalt, sizeof(hashSalt)); - uint256 hashRand = addr.ip ^ ((GetTime()+addr.ip)/(12*60*60)) ^ hashSalt; + uint256 hashRand = hashSalt ^ (((int64)addr.ip)<<32) ^ ((GetTime()+addr.ip)/(24*60*60)); + hashRand = Hash(BEGIN(hashRand), END(hashRand)); multimap<uint256, CNode*> mapMix; foreach(CNode* pnode, vNodes) - mapMix.insert(make_pair(hashRand = Hash(BEGIN(hashRand), END(hashRand)), pnode)); + { + unsigned int nPointer; + memcpy(&nPointer, &pnode, sizeof(nPointer)); + uint256 hashKey = hashRand ^ nPointer; + hashKey = Hash(BEGIN(hashKey), END(hashKey)); + mapMix.insert(make_pair(hashKey, pnode)); + } int nRelayNodes = 2; for (multimap<uint256, CNode*>::iterator mi = mapMix.begin(); mi != mapMix.end() && nRelayNodes-- > 0; ++mi) ((*mi).second)->PushAddress(addr); @@ -2446,7 +2473,7 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) foreach(const PAIRTYPE(vector<unsigned char>, CAddress)& item, mapAddresses) { const CAddress& addr = item.second; - if (addr.nTime > nSince && GetRand(nCount) < 2000) + if (addr.nTime > nSince && GetRand(nCount) < 2500) pfrom->PushAddress(addr); } } @@ -2931,10 +2958,12 @@ void BitcoinMiner() f4WaySSE2 = (mapArgs["-4way"] != "0"); CReserveKey reservekey; - CBigNum bnExtraNonce = 0; + unsigned int nExtraNonce = 0; + int64 nPrevTime = 0; while (fGenerateBitcoins) { - Sleep(50); + if (AffinityBugWorkaround(ThreadBitcoinMiner)) + return; if (fShutdown) return; while (vNodes.empty() || IsInitialBlockDownload()) @@ -2957,7 +2986,13 @@ void BitcoinMiner() CTransaction txNew; txNew.vin.resize(1); txNew.vin[0].prevout.SetNull(); - txNew.vin[0].scriptSig << ++bnExtraNonce; + int64 nNow = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); + if (nNow > nPrevTime+1 && ++nExtraNonce >= 0x7f) + { + nExtraNonce = 1; + nPrevTime = nNow; + } + txNew.vin[0].scriptSig << nBits << CBigNum(nExtraNonce); txNew.vout.resize(1); txNew.vout[0].scriptPubKey << reservekey.GetReservedKey() << OP_CHECKSIG; @@ -3045,9 +3080,9 @@ void BitcoinMiner() tmpworkspace& tmp = *(tmpworkspace*)alignup<16>(tmpbuf); tmp.block.nVersion = pblock->nVersion; - tmp.block.hashPrevBlock = pblock->hashPrevBlock = (pindexPrev ? pindexPrev->GetBlockHash() : 0); + tmp.block.hashPrevBlock = pblock->hashPrevBlock = pindexPrev->GetBlockHash(); tmp.block.hashMerkleRoot = pblock->hashMerkleRoot = pblock->BuildMerkleTree(); - tmp.block.nTime = pblock->nTime = max((pindexPrev ? pindexPrev->GetMedianTimePast()+1 : 0), GetAdjustedTime()); + tmp.block.nTime = pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); tmp.block.nBits = pblock->nBits = nBits; tmp.block.nNonce = pblock->nNonce = 0; @@ -3177,10 +3212,7 @@ void BitcoinMiner() break; // Update nTime every few seconds - int64 nNewTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); - if (nNewTime != pblock->nTime && bnExtraNonce > 10) - bnExtraNonce = 0; - pblock->nTime = nNewTime; + pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); tmp.block.nTime = ByteReverse(pblock->nTime); } } @@ -22,7 +22,6 @@ static const int64 CENT = 1000000; static const int64 MAX_MONEY = 21000000 * COIN; inline bool MoneyRange(int64 nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); } static const int COINBASE_MATURITY = 100; -static const CBigNum bnProofOfWorkLimit(~uint256(0) >> 32); @@ -31,7 +30,8 @@ static const CBigNum bnProofOfWorkLimit(~uint256(0) >> 32); extern CCriticalSection cs_main; extern map<uint256, CBlockIndex*> mapBlockIndex; -extern const uint256 hashGenesisBlock; +extern uint256 hashGenesisBlock; +extern CBigNum bnProofOfWorkLimit; extern CBlockIndex* pindexGenesisBlock; extern int nBestHeight; extern CBigNum bnBestChainWork; @@ -937,7 +937,7 @@ void ThreadOpenConnections2(void* parg) // Add seed nodes if IRC isn't working static bool fSeedUsed; bool fTOR = (fUseProxy && addrProxy.port == htons(9050)); - if (mapAddresses.empty() && (GetTime() - nStart > 60 || fTOR)) + if (mapAddresses.empty() && (GetTime() - nStart > 60 || fTOR) && !fTestNet) { for (int i = 0; i < ARRAYLEN(pnSeed); i++) { @@ -48,10 +48,7 @@ bool StopNode(); // (4) size // (4) checksum -// The message start string is designed to be unlikely to occur in normal data. -// The characters are rarely used upper ascii, not valid as UTF-8, and produce -// a large 4-byte int at any alignment. -static const char pchMessageStart[4] = { 0xf9, 0xbe, 0xb4, 0xd9 }; +extern char pchMessageStart[4]; class CMessageHeader { diff --git a/script.cpp b/script.cpp index 730c4986d2..a09031bad5 100644 --- a/script.cpp +++ b/script.cpp @@ -776,16 +776,11 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co return false; int nKeysCount = CastToBigNum(stacktop(-i)).getint(); - if (nKeysCount < 0) + if (nKeysCount < 0 || nKeysCount > 20) + return false; + nOpCount += nKeysCount; + if (nOpCount > 201) return false; - if (nBestHeight > 84000) - { - if (nKeysCount > 20) - return false; - nOpCount += nKeysCount; - if (nOpCount > 201) - return false; - } int ikey = ++i; i += nKeysCount; if (stack.size() < i) diff --git a/serialize.h b/serialize.h index d6e715d468..44b647f1e8 100644 --- a/serialize.h +++ b/serialize.h @@ -22,7 +22,7 @@ class CDataStream; class CAutoFile; static const unsigned int MAX_SIZE = 0x02000000; -static const int VERSION = 31304; +static const int VERSION = 31305; static const char* pszSubVer = ""; @@ -763,6 +763,7 @@ bool CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex) SingleLine(strDescription), FormatMoney(-nValue, true), ""); + nIndex = -1; wtx.nLinesDisplayed++; } } @@ -16,6 +16,7 @@ bool fShutdown = false; bool fDaemon = false; bool fCommandLine = false; string strMiscWarning; +bool fTestNet = false; @@ -649,15 +650,11 @@ string GetDefaultDataDir() void GetDataDir(char* pszDir) { // pszDir must be at least MAX_PATH length. + int nVariation; if (pszSetDataDir[0] != 0) { strlcpy(pszDir, pszSetDataDir, MAX_PATH); - static bool fMkdirDone; - if (!fMkdirDone) - { - fMkdirDone = true; - filesystem::create_directory(pszDir); - } + nVariation = 0; } else { @@ -665,11 +662,23 @@ void GetDataDir(char* pszDir) // value so we don't have to do memory allocations after that. static char pszCachedDir[MAX_PATH]; if (pszCachedDir[0] == 0) - { strlcpy(pszCachedDir, GetDefaultDataDir().c_str(), sizeof(pszCachedDir)); - filesystem::create_directory(pszCachedDir); - } strlcpy(pszDir, pszCachedDir, MAX_PATH); + nVariation = 1; + } + if (fTestNet) + { + char* p = pszDir + strlen(pszDir); + if (p > pszDir && p[-1] != '/' && p[-1] != '\\') + *p++ = '/'; + strcpy(p, "testnet"); + nVariation += 2; + } + static bool pfMkdir[4]; + if (!pfMkdir[nVariation]) + { + pfMkdir[nVariation] = true; + filesystem::create_directory(pszDir); } } @@ -145,6 +145,7 @@ extern bool fShutdown; extern bool fDaemon; extern bool fCommandLine; extern string strMiscWarning; +extern bool fTestNet; void RandAddSeed(); void RandAddSeedPerfmon(); @@ -621,3 +622,27 @@ inline void ExitThread(unsigned int nExitCode) pthread_exit((void*)nExitCode); } #endif + + + + + +inline bool AffinityBugWorkaround(void(*pfn)(void*)) +{ +#ifdef __WXMSW__ + // Sometimes after a few hours affinity gets stuck on one processor + DWORD dwProcessAffinityMask = -1; + DWORD dwSystemAffinityMask = -1; + GetProcessAffinityMask(GetCurrentProcess(), &dwProcessAffinityMask, &dwSystemAffinityMask); + DWORD dwPrev1 = SetThreadAffinityMask(GetCurrentThread(), dwProcessAffinityMask); + DWORD dwPrev2 = SetThreadAffinityMask(GetCurrentThread(), dwProcessAffinityMask); + if (dwPrev2 != dwProcessAffinityMask) + { + printf("AffinityBugWorkaround() : SetThreadAffinityMask=%d, ProcessAffinityMask=%d, restarting thread\n", dwPrev2, dwProcessAffinityMask); + if (!CreateThread(pfn, NULL)) + printf("Error: CreateThread() failed\n"); + return true; + } +#endif + return false; +} |