From: Sunny King Date: Tue, 20 Dec 2011 19:07:42 +0000 (+0000) Subject: Merge bitcoin v0.5.1 into ppcoin X-Git-Tag: v0.4.0-unstable~226 X-Git-Url: https://git.novaco.in/?a=commitdiff_plain;h=de71734ac41eebfe8763ce34e0443d64ea4aacc9;hp=-c;p=novacoin.git Merge bitcoin v0.5.1 into ppcoin --- de71734ac41eebfe8763ce34e0443d64ea4aacc9 diff --combined src/bitcoinrpc.cpp index 829cd17,bb8d8e2..3ff5c60 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@@ -4,7 -4,6 +4,6 @@@ // file license.txt or http://www.opensource.org/licenses/mit-license.php. #include "headers.h" - #include "cryptopp/sha.h" #include "db.h" #include "net.h" #include "init.h" @@@ -37,6 -36,8 +36,8 @@@ void ThreadRPCServer2(void* parg) typedef Value(*rpcfn_type)(const Array& params, bool fHelp); extern map mapCallTable; + static std::string strRPCUserColonPass; + static int64 nWalletUnlockTime; static CCriticalSection cs_nWalletUnlockTime; @@@ -50,13 -51,13 +51,13 @@@ Object JSONRPCError(int code, const str } - void PrintConsole(const char* format, ...) + void PrintConsole(const std::string &format, ...) { char buffer[50000]; int limit = sizeof(buffer); va_list arg_ptr; va_start(arg_ptr, format); - int ret = _vsnprintf(buffer, limit, format, arg_ptr); + int ret = _vsnprintf(buffer, limit, format.c_str(), arg_ptr); va_end(arg_ptr); if (ret < 0 || ret >= limit) { @@@ -64,18 -65,14 +65,14 @@@ buffer[limit-1] = 0; } printf("%s", buffer); - #if defined(__WXMSW__) && defined(GUI) - MyMessageBox(buffer, "Bitcoin", wxOK | wxICON_EXCLAMATION); - #else fprintf(stdout, "%s", buffer); - #endif } int64 AmountFromValue(const Value& value) { double dAmount = value.get_real(); - if (dAmount <= 0.0 || dAmount > 21000000.0) + if (dAmount <= 0.0 || dAmount > MAX_MONEY) throw JSONRPCError(-3, "Invalid amount"); int64 nAmount = roundint64(dAmount * COIN); if (!MoneyRange(nAmount)) @@@ -131,6 -128,7 +128,7 @@@ Value help(const Array& params, bool fH // We already filter duplicates, but these deprecated screw up the sort order if (strMethod == "getamountreceived" || strMethod == "getallreceived" || + strMethod == "getblocknumber" || // deprecated (strMethod.find("label") != string::npos)) continue; if (strCommand != "" && strMethod != strCommand) @@@ -165,10 -163,13 +163,13 @@@ Value stop(const Array& params, bool fH throw runtime_error( "stop\n" "Stop bitcoin server."); - + #ifndef QT_GUI // Shutdown will take long enough that the response should get back CreateThread(Shutdown, NULL); return "bitcoin server stopping"; + #else + throw runtime_error("NYI: cannot shut down GUI with RPC command"); + #endif } @@@ -183,12 -184,13 +184,13 @@@ Value getblockcount(const Array& params } + // deprecated Value getblocknumber(const Array& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( "getblocknumber\n" - "Returns the block number of the latest block in the longest block chain."); + "Deprecated. Use getblockcount."); return nBestHeight; } @@@ -483,13 -485,12 +485,13 @@@ Value settxfee(const Array& params, boo if (fHelp || params.size() < 1 || params.size() > 1) throw runtime_error( "settxfee \n" - " is a real and is rounded to the nearest 0.00000001"); + " is a real and is rounded to the nearest 0.0001\n" + "Minimum and default transaction fee is 1 coin"); // Amount - int64 nAmount = 0; - if (params[0].get_real() != 0.0) - nAmount = AmountFromValue(params[0]); // rejects 0.0 amounts + int64 nAmount = MIN_TX_FEE; + if (params[0].get_real() != 0.0) // rejects 0.0 amounts + nAmount = max(nAmount, AmountFromValue(params[0])); nTransactionFee = nAmount; return true; @@@ -531,6 -532,72 +533,72 @@@ Value sendtoaddress(const Array& params return wtx.GetHash().GetHex(); } + static const string strMessageMagic = "Bitcoin Signed Message:\n"; + + Value signmessage(const Array& params, bool fHelp) + { + if (fHelp || params.size() != 2) + throw runtime_error( + "signmessage \n" + "Sign a message with the private key of an address"); + + if (pwalletMain->IsLocked()) + throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first."); + + string strAddress = params[0].get_str(); + string strMessage = params[1].get_str(); + + CBitcoinAddress addr(strAddress); + if (!addr.IsValid()) + throw JSONRPCError(-3, "Invalid address"); + + CKey key; + if (!pwalletMain->GetKey(addr, key)) + throw JSONRPCError(-4, "Private key not available"); + + CDataStream ss(SER_GETHASH); + ss << strMessageMagic; + ss << strMessage; + + vector vchSig; + if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig)) + throw JSONRPCError(-5, "Sign failed"); + + return EncodeBase64(&vchSig[0], vchSig.size()); + } + + Value verifymessage(const Array& params, bool fHelp) + { + if (fHelp || params.size() != 3) + throw runtime_error( + "verifymessage \n" + "Verify a signed message"); + + string strAddress = params[0].get_str(); + string strSign = params[1].get_str(); + string strMessage = params[2].get_str(); + + CBitcoinAddress addr(strAddress); + if (!addr.IsValid()) + throw JSONRPCError(-3, "Invalid address"); + + bool fInvalid = false; + vector vchSig = DecodeBase64(strSign.c_str(), &fInvalid); + + if (fInvalid) + throw JSONRPCError(-5, "Malformed base64 encoding"); + + CDataStream ss(SER_GETHASH); + ss << strMessageMagic; + ss << strMessage; + + CKey key; + if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig)) + return false; + + return (key.GetAddress() == addr); + } + Value getreceivedbyaddress(const Array& params, bool fHelp) { @@@ -942,7 -1009,6 +1010,6 @@@ Value ListReceived(const Array& params Object obj; obj.push_back(Pair("address", address.ToString())); obj.push_back(Pair("account", strAccount)); - obj.push_back(Pair("label", strAccount)); // deprecated obj.push_back(Pair("amount", ValueFromAmount(nAmount))); obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf))); ret.push_back(obj); @@@ -957,7 -1023,6 +1024,6 @@@ int nConf = (*it).second.nConf; Object obj; obj.push_back(Pair("account", (*it).first)); - obj.push_back(Pair("label", (*it).first)); // deprecated obj.push_back(Pair("amount", ValueFromAmount(nAmount))); obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf))); ret.push_back(obj); @@@ -1199,6 -1264,70 +1265,70 @@@ Value listaccounts(const Array& params return ret; } + Value listsinceblock(const Array& params, bool fHelp) + { + if (fHelp) + throw runtime_error( + "listsinceblock [blockid] [target-confirmations]\n" + "Get all transactions in blocks since block [blockid], or all transactions if omitted"); + + CBlockIndex *pindex = NULL; + int target_confirms = 1; + + if (params.size() > 0) + { + uint256 blockId = 0; + + blockId.SetHex(params[0].get_str()); + pindex = CBlockLocator(blockId).GetBlockIndex(); + } + + if (params.size() > 1) + { + target_confirms = params[1].get_int(); + + if (target_confirms < 1) + throw JSONRPCError(-8, "Invalid parameter"); + } + + int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1; + + Array transactions; + + for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++) + { + CWalletTx tx = (*it).second; + + if (depth == -1 || tx.GetDepthInMainChain() < depth) + ListTransactions(tx, "*", 0, true, transactions); + } + + uint256 lastblock; + + if (target_confirms == 1) + { + printf("oops!\n"); + lastblock = hashBestChain; + } + else + { + int target_height = pindexBest->nHeight + 1 - target_confirms; + + CBlockIndex *block; + for (block = pindexBest; + block && block->nHeight > target_height; + block = block->pprev); + + lastblock = block ? block->GetBlockHash() : 0; + } + + Object ret; + ret.push_back(Pair("transactions", transactions)); + ret.push_back(Pair("lastblock", lastblock.GetHex())); + + return ret; + } + Value gettransaction(const Array& params, bool fHelp) { if (fHelp || params.size() != 1) @@@ -1326,21 -1455,16 +1456,16 @@@ Value walletpassphrase(const Array& par throw JSONRPCError(-17, "Error: Wallet is already unlocked."); // Note that the walletpassphrase is stored in params[0] which is not mlock()ed - string strWalletPass; + SecureString strWalletPass; strWalletPass.reserve(100); - mlock(&strWalletPass[0], strWalletPass.capacity()); - strWalletPass = params[0].get_str(); + // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string) + // Alternately, find a way to make params[0] mlock()'d to begin with. + strWalletPass = params[0].get_str().c_str(); if (strWalletPass.length() > 0) { if (!pwalletMain->Unlock(strWalletPass)) - { - fill(strWalletPass.begin(), strWalletPass.end(), '\0'); - munlock(&strWalletPass[0], strWalletPass.capacity()); throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect."); - } - fill(strWalletPass.begin(), strWalletPass.end(), '\0'); - munlock(&strWalletPass[0], strWalletPass.capacity()); } else throw runtime_error( @@@ -1366,15 -1490,15 +1491,15 @@@ Value walletpassphrasechange(const Arra if (!pwalletMain->IsCrypted()) throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called."); - string strOldWalletPass; + // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string) + // Alternately, find a way to make params[0] mlock()'d to begin with. + SecureString strOldWalletPass; strOldWalletPass.reserve(100); - mlock(&strOldWalletPass[0], strOldWalletPass.capacity()); - strOldWalletPass = params[0].get_str(); + strOldWalletPass = params[0].get_str().c_str(); - string strNewWalletPass; + SecureString strNewWalletPass; strNewWalletPass.reserve(100); - mlock(&strNewWalletPass[0], strNewWalletPass.capacity()); - strNewWalletPass = params[1].get_str(); + strNewWalletPass = params[1].get_str().c_str(); if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1) throw runtime_error( @@@ -1382,17 -1506,7 +1507,7 @@@ "Changes the wallet passphrase from to ."); if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass)) - { - fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0'); - fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0'); - munlock(&strOldWalletPass[0], strOldWalletPass.capacity()); - munlock(&strNewWalletPass[0], strNewWalletPass.capacity()); throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect."); - } - fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0'); - fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0'); - munlock(&strOldWalletPass[0], strOldWalletPass.capacity()); - munlock(&strNewWalletPass[0], strNewWalletPass.capacity()); return Value::null; } @@@ -1432,10 -1546,16 +1547,16 @@@ Value encryptwallet(const Array& params if (pwalletMain->IsCrypted()) throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called."); - string strWalletPass; + #ifdef QT_GUI + // shutting down via RPC while the GUI is running does not work (yet): + throw runtime_error("Not Yet Implemented: use GUI to encrypt wallet, not RPC command"); + #endif + + // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string) + // Alternately, find a way to make params[0] mlock()'d to begin with. + SecureString strWalletPass; strWalletPass.reserve(100); - mlock(&strWalletPass[0], strWalletPass.capacity()); - strWalletPass = params[0].get_str(); + strWalletPass = params[0].get_str().c_str(); if (strWalletPass.length() < 1) throw runtime_error( @@@ -1443,15 -1563,13 +1564,13 @@@ "Encrypts the wallet with ."); if (!pwalletMain->EncryptWallet(strWalletPass)) - { - fill(strWalletPass.begin(), strWalletPass.end(), '\0'); - munlock(&strWalletPass[0], strWalletPass.capacity()); throw JSONRPCError(-16, "Error: Failed to encrypt the wallet."); - } - fill(strWalletPass.begin(), strWalletPass.end(), '\0'); - munlock(&strWalletPass[0], strWalletPass.capacity()); - return Value::null; + // BDB seems to have a bad habit of writing old data into + // slack space in .dat files; that is bad if the old data is + // unencrypted private keys. So: + CreateThread(Shutdown, NULL); + return "wallet encrypted; bitcoin server stopping, restart to run with encrypted wallet"; } @@@ -1487,9 -1605,9 +1606,9 @@@ Value getwork(const Array& params, boo throw runtime_error( "getwork [data]\n" "If [data] is not specified, returns formatted hash data to work on:\n" - " \"midstate\" : precomputed hash state after hashing the first half of the data\n" + " \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated " \"data\" : block data\n" - " \"hash1\" : formatted hash buffer for second hash\n" + " \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated " \"target\" : little endian hash target\n" "If [data] is specified, tries to solve the block and returns true if it was successful."); @@@ -1553,9 -1671,9 +1672,9 @@@ uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256(); Object result; - result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); + result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata)))); - result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1)))); + result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1)))); // deprecated result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget)))); return result; } @@@ -1569,7 -1687,7 +1688,7 @@@ // Byte reverse for (int i = 0; i < 128/4; i++) - ((unsigned int*)pdata)[i] = CryptoPP::ByteReverse(((unsigned int*)pdata)[i]); + ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]); // Get saved block if (!mapNewBlock.count(pdata->hashMerkleRoot)) @@@ -1586,6 -1704,93 +1705,93 @@@ } + Value getmemorypool(const Array& params, bool fHelp) + { + if (fHelp || params.size() > 1) + throw runtime_error( + "getmemorypool [data]\n" + "If [data] is not specified, returns data needed to construct a block to work on:\n" + " \"version\" : block version\n" + " \"previousblockhash\" : hash of current highest block\n" + " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n" + " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n" + " \"time\" : timestamp appropriate for next block\n" + " \"bits\" : compressed target of next block\n" + "If [data] is specified, tries to solve the block and returns true if it was successful."); + + if (params.size() == 0) + { + if (vNodes.empty()) + throw JSONRPCError(-9, "Bitcoin is not connected!"); + + if (IsInitialBlockDownload()) + throw JSONRPCError(-10, "Bitcoin is downloading blocks..."); + + static CReserveKey reservekey(pwalletMain); + + // Update block + static unsigned int nTransactionsUpdatedLast; + static CBlockIndex* pindexPrev; + static int64 nStart; + static CBlock* pblock; + if (pindexPrev != pindexBest || + (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5)) + { + nTransactionsUpdatedLast = nTransactionsUpdated; + pindexPrev = pindexBest; + nStart = GetTime(); + + // Create new block + if(pblock) + delete pblock; + pblock = CreateNewBlock(reservekey); + if (!pblock) + throw JSONRPCError(-7, "Out of memory"); + } + + // Update nTime + pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); + pblock->nNonce = 0; + + Array transactions; + BOOST_FOREACH(CTransaction tx, pblock->vtx) { + if(tx.IsCoinBase()) + continue; + + CDataStream ssTx; + ssTx << tx; + + transactions.push_back(HexStr(ssTx.begin(), ssTx.end())); + } + + Object result; + result.push_back(Pair("version", pblock->nVersion)); + result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex())); + result.push_back(Pair("transactions", transactions)); + result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue)); + result.push_back(Pair("time", (int64_t)pblock->nTime)); + + union { + int32_t nBits; + char cBits[4]; + } uBits; + uBits.nBits = htonl((int32_t)pblock->nBits); + result.push_back(Pair("bits", HexStr(BEGIN(uBits.cBits), END(uBits.cBits)))); + + return result; + } + else + { + // Parse parameters + CDataStream ssBlock(ParseHex(params[0].get_str())); + CBlock pblock; + ssBlock >> pblock; + + return ProcessBlock(NULL, &pblock); + } + } + + @@@ -1614,20 -1819,13 +1820,13 @@@ pair pCallTable[] make_pair("getnewaddress", &getnewaddress), make_pair("getaccountaddress", &getaccountaddress), make_pair("setaccount", &setaccount), - make_pair("setlabel", &setaccount), // deprecated make_pair("getaccount", &getaccount), - make_pair("getlabel", &getaccount), // deprecated make_pair("getaddressesbyaccount", &getaddressesbyaccount), - make_pair("getaddressesbylabel", &getaddressesbyaccount), // deprecated make_pair("sendtoaddress", &sendtoaddress), - make_pair("getamountreceived", &getreceivedbyaddress), // deprecated, renamed to getreceivedbyaddress - make_pair("getallreceived", &listreceivedbyaddress), // deprecated, renamed to listreceivedbyaddress make_pair("getreceivedbyaddress", &getreceivedbyaddress), make_pair("getreceivedbyaccount", &getreceivedbyaccount), - make_pair("getreceivedbylabel", &getreceivedbyaccount), // deprecated make_pair("listreceivedbyaddress", &listreceivedbyaddress), make_pair("listreceivedbyaccount", &listreceivedbyaccount), - make_pair("listreceivedbylabel", &listreceivedbyaccount), // deprecated make_pair("backupwallet", &backupwallet), make_pair("keypoolrefill", &keypoolrefill), make_pair("walletpassphrase", &walletpassphrase), @@@ -1641,9 -1839,13 +1840,13 @@@ make_pair("sendmany", &sendmany), make_pair("gettransaction", &gettransaction), make_pair("listtransactions", &listtransactions), + make_pair("signmessage", &signmessage), + make_pair("verifymessage", &verifymessage), make_pair("getwork", &getwork), make_pair("listaccounts", &listaccounts), make_pair("settxfee", &settxfee), + make_pair("getmemorypool", &getmemorypool), + make_pair("listsinceblock", &listsinceblock), }; map mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0])); @@@ -1652,7 -1854,7 +1855,7 @@@ string pAllowInSafeMode[] "help", "stop", "getblockcount", - "getblocknumber", + "getblocknumber", // deprecated "getconnectioncount", "getdifficulty", "getgenerate", @@@ -1661,17 -1863,15 +1864,15 @@@ "getinfo", "getnewaddress", "getaccountaddress", - "setlabel", // deprecated "getaccount", - "getlabel", // deprecated "getaddressesbyaccount", - "getaddressesbylabel", // deprecated "backupwallet", "keypoolrefill", "walletpassphrase", "walletlock", "validateaddress", "getwork", + "getmemorypool", }; set setAllowInSafeMode(pAllowInSafeMode, pAllowInSafeMode + sizeof(pAllowInSafeMode)/sizeof(pAllowInSafeMode[0])); @@@ -1693,6 -1893,7 +1894,7 @@@ string HTTPPost(const string& strMsg, c << "Host: 127.0.0.1\r\n" << "Content-Type: application/json\r\n" << "Content-Length: " << strMsg.size() << "\r\n" + << "Connection: close\r\n" << "Accept: application/json\r\n"; BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders) s << item.first << ": " << item.second << "\r\n"; @@@ -1733,12 -1934,13 +1935,13 @@@ static string HTTPReply(int nStatus, co "\r\n" "

401 Unauthorized.

\r\n" "\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str()); - string strStatus; - if (nStatus == 200) strStatus = "OK"; - else if (nStatus == 400) strStatus = "Bad Request"; - else if (nStatus == 403) strStatus = "Forbidden"; - else if (nStatus == 404) strStatus = "Not Found"; - else if (nStatus == 500) strStatus = "Internal Server Error"; + const char *cStatus; + if (nStatus == 200) cStatus = "OK"; + else if (nStatus == 400) cStatus = "Bad Request"; + else if (nStatus == 403) cStatus = "Forbidden"; + else if (nStatus == 404) cStatus = "Not Found"; + else if (nStatus == 500) cStatus = "Internal Server Error"; + else cStatus = ""; return strprintf( "HTTP/1.1 %d %s\r\n" "Date: %s\r\n" @@@ -1749,7 -1951,7 +1952,7 @@@ "\r\n" "%s", nStatus, - strStatus.c_str(), + cStatus, rfc1123Time().c_str(), strMsg.size(), FormatFullVersion().c_str(), @@@ -1816,43 -2018,6 +2019,6 @@@ int ReadHTTP(std::basic_istream& return nStatus; } - string EncodeBase64(string s) - { - BIO *b64, *bmem; - BUF_MEM *bptr; - - b64 = BIO_new(BIO_f_base64()); - BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); - bmem = BIO_new(BIO_s_mem()); - b64 = BIO_push(b64, bmem); - BIO_write(b64, s.c_str(), s.size()); - BIO_flush(b64); - BIO_get_mem_ptr(b64, &bptr); - - string result(bptr->data, bptr->length); - BIO_free_all(b64); - - return result; - } - - string DecodeBase64(string s) - { - BIO *b64, *bmem; - - char* buffer = static_cast(calloc(s.size(), sizeof(char))); - - b64 = BIO_new(BIO_f_base64()); - BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); - bmem = BIO_new_mem_buf(const_cast(s.c_str()), s.size()); - bmem = BIO_push(b64, bmem); - BIO_read(bmem, buffer, s.size()); - BIO_free_all(bmem); - - string result(buffer); - free(buffer); - return result; - } - bool HTTPAuthorized(map& mapHeaders) { string strAuth = mapHeaders["authorization"]; @@@ -1860,12 -2025,7 +2026,7 @@@ return false; string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64); string strUserPass = DecodeBase64(strUserPass64); - string::size_type nColon = strUserPass.find(":"); - if (nColon == string::npos) - return false; - string strUser = strUserPass.substr(0, nColon); - string strPassword = strUserPass.substr(nColon+1); - return (strUser == mapArgs["-rpcuser"] && strPassword == mapArgs["-rpcpassword"]); + return strUserPass == strRPCUserColonPass; } // @@@ -1998,7 -2158,8 +2159,8 @@@ void ThreadRPCServer2(void* parg { printf("ThreadRPCServer started\n"); - if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "") + strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]; + if (strRPCUserColonPass == ":") { string strWhatAmI = "To use bitcoind"; if (mapArgs.count("-server")) @@@ -2006,11 -2167,13 +2168,13 @@@ else if (mapArgs.count("-daemon")) strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\""); PrintConsole( - _("Warning: %s, you must set rpcpassword=\nin the configuration file: %s\n" + _("Error: %s, you must set rpcpassword=\nin the configuration file: %s\n" "If the file does not exist, create it with owner-readable-only file permissions.\n"), strWhatAmI.c_str(), GetConfigFile().c_str()); + #ifndef QT_GUI CreateThread(Shutdown, NULL); + #endif return; } @@@ -2124,7 -2287,7 +2288,7 @@@ if (valMethod.type() != str_type) throw JSONRPCError(-32600, "Method must be a string"); string strMethod = valMethod.get_str(); - if (strMethod != "getwork") + if (strMethod != "getwork" && strMethod != "getmemorypool") printf("ThreadRPCServer method=%s\n", strMethod.c_str()); // Parse params @@@ -2290,18 -2453,12 +2454,12 @@@ int CommandLineRPC(int argc, char *argv if (strMethod == "setgenerate" && n > 1) ConvertTo(params[1]); if (strMethod == "sendtoaddress" && n > 1) ConvertTo(params[1]); if (strMethod == "settxfee" && n > 0) ConvertTo(params[0]); - if (strMethod == "getamountreceived" && n > 1) ConvertTo(params[1]); // deprecated if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo(params[1]); if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo(params[1]); - if (strMethod == "getreceivedbylabel" && n > 1) ConvertTo(params[1]); // deprecated - if (strMethod == "getallreceived" && n > 0) ConvertTo(params[0]); // deprecated - if (strMethod == "getallreceived" && n > 1) ConvertTo(params[1]); // deprecated if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo(params[0]); if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo(params[1]); if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo(params[0]); if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo(params[1]); - if (strMethod == "listreceivedbylabel" && n > 0) ConvertTo(params[0]); // deprecated - if (strMethod == "listreceivedbylabel" && n > 1) ConvertTo(params[1]); // deprecated if (strMethod == "getbalance" && n > 1) ConvertTo(params[1]); if (strMethod == "move" && n > 2) ConvertTo(params[2]); if (strMethod == "move" && n > 3) ConvertTo(params[3]); @@@ -2311,6 -2468,7 +2469,7 @@@ if (strMethod == "listtransactions" && n > 2) ConvertTo(params[2]); if (strMethod == "listaccounts" && n > 0) ConvertTo(params[0]); if (strMethod == "walletpassphrase" && n > 1) ConvertTo(params[1]); + if (strMethod == "listsinceblock" && n > 1) ConvertTo(params[1]); if (strMethod == "sendmany" && n > 1) { string s = params[1].get_str(); @@@ -2358,13 -2516,7 +2517,7 @@@ if (strPrint != "") { - #if defined(__WXMSW__) && defined(GUI) - // Windows GUI apps can't print to command line, - // so settle for a message box yuck - MyMessageBox(strPrint, "Bitcoin", wxOK); - #else fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str()); - #endif } return nRet; } diff --combined src/checkpoints.cpp index 0000000,c7e054d..d20fe24 mode 000000,100644..100644 --- a/src/checkpoints.cpp +++ b/src/checkpoints.cpp @@@ -1,0 -1,65 +1,57 @@@ + // Copyright (c) 2011 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 // for 'map_list_of()' + #include + + #include "headers.h" + #include "checkpoints.h" + + namespace Checkpoints + { + typedef std::map MapCheckpoints; + + // + // What makes a good checkpoint block? + // + Is surrounded by blocks with reasonable timestamps + // (no blocks before with a timestamp after, none after with + // timestamp before) + // + Contains no strange transactions + // + static MapCheckpoints mapCheckpoints = + boost::assign::map_list_of - ( 11111, uint256("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d")) - ( 33333, uint256("0x000000002dd5588a74784eaa7ab0507a18ad16a236e7b1ce69f00d7ddfb5d0a6")) - ( 68555, uint256("0x00000000001e1b4903550a0b96e9a9405c8a95f387162e4944e8d9fbe501cd6a")) - ( 70567, uint256("0x00000000006a49b14bcf27462068f1264c961f11fa2e0eddd2be0791e1d4124a")) - ( 74000, uint256("0x0000000000573993a3c9e41ce34471c079dcf5f52a0e824a81e7f953b8661a20")) - (105000, uint256("0x00000000000291ce28027faea320c8d2b054b2e0fe44a773f3eefb151d6bdc97")) - (118000, uint256("0x000000000000774a7f8a7a12dc906ddb9e17e75d684f15e00f8767f9e8f36553")) - (134444, uint256("0x00000000000005b12ffd4cd315cd34ffd4a594f430ac814c91184a0d42d2b0fe")) - (140700, uint256("0x000000000000033b512028abb90e1626d8b346fd0ed598ac0a3c371138dce2bd")) - ; ++ ( 0, hashGenesisBlock ) ++ ; // ppcoin: no checkpoint yet; to be created in future releases + + bool CheckBlock(int nHeight, const uint256& hash) + { + if (fTestNet) return true; // Testnet has no checkpoints + + MapCheckpoints::const_iterator i = mapCheckpoints.find(nHeight); + if (i == mapCheckpoints.end()) return true; + return hash == i->second; + } + + int GetTotalBlocksEstimate() + { + if (fTestNet) return 0; + + return mapCheckpoints.rbegin()->first; + } + + CBlockIndex* GetLastCheckpoint(const std::map& mapBlockIndex) + { + if (fTestNet) return NULL; + + int64 nResult; + BOOST_REVERSE_FOREACH(const MapCheckpoints::value_type& i, mapCheckpoints) + { + const uint256& hash = i.second; + std::map::const_iterator t = mapBlockIndex.find(hash); + if (t != mapBlockIndex.end()) + return t->second; + } + return NULL; + } + } diff --combined src/init.cpp index 9d845a6,dd8bdf5..d36f1dd --- a/src/init.cpp +++ b/src/init.cpp @@@ -1,11 -1,10 +1,11 @@@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2011 The Bitcoin developers +// Copyright (c) 2011 The PPCoin 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 "rpc.h" + #include "bitcoinrpc.h" #include "net.h" #include "init.h" #include "strlcpy.h" @@@ -13,6 -12,16 +13,16 @@@ #include #include + #if defined(BITCOIN_NEED_QT_PLUGINS) && !defined(_BITCOIN_QT_PLUGINS_INCLUDED) + #define _BITCOIN_QT_PLUGINS_INCLUDED + #define __INSURE__ + #include + Q_IMPORT_PLUGIN(qcncodecs) + Q_IMPORT_PLUGIN(qjpcodecs) + Q_IMPORT_PLUGIN(qtwcodecs) + Q_IMPORT_PLUGIN(qkrcodecs) + #endif + using namespace std; using namespace boost; @@@ -25,7 -34,7 +35,7 @@@ CWallet* pwalletMain void ExitTimeout(void* parg) { - #ifdef __WXMSW__ + #ifdef WIN32 Sleep(5000); ExitProcess(0); #endif @@@ -35,8 -44,8 +45,8 @@@ void Shutdown(void* parg { static CCriticalSection cs_Shutdown; static bool fTaken; - bool fFirstThread; - CRITICAL_BLOCK(cs_Shutdown) + bool fFirstThread = false; + TRY_CRITICAL_BLOCK(cs_Shutdown) { fFirstThread = !fTaken; fTaken = true; @@@ -81,8 -90,7 +91,8 @@@ void HandleSIGTERM(int // // Start // - #ifndef GUI + #if !defined(QT_GUI) +#if !defined(PPCOIN_GENESIS) int main(int argc, char* argv[]) { bool fRet = false; @@@ -94,7 -102,6 +104,7 @@@ return 1; } #endif +#endif bool AppInit(int argc, char* argv[]) { @@@ -124,10 -131,10 +134,10 @@@ bool AppInit2(int argc, char* argv[] // Disable confusing "helpful" text message on abort, ctrl-c _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT); #endif - #ifndef __WXMSW__ + #ifndef WIN32 umask(077); #endif - #ifndef __WXMSW__ + #ifndef WIN32 // Clean shutdown on SIGTERM struct sigaction sa; sa.sa_handler = HandleSIGTERM; @@@ -165,13 -172,13 +175,13 @@@ string strUsage = string() + _("Bitcoin version") + " " + FormatFullVersion() + "\n\n" + _("Usage:") + "\t\t\t\t\t\t\t\t\t\t\n" + - " bitcoin [options] \t " + "\n" + - " bitcoin [options] [params]\t " + _("Send command to -server or bitcoind\n") + - " bitcoin [options] help \t\t " + _("List commands\n") + - " bitcoin [options] help \t\t " + _("Get help for a command\n") + + " bitcoind [options] \t " + "\n" + + " bitcoind [options] [params]\t " + _("Send command to -server or bitcoind\n") + + " bitcoind [options] help \t\t " + _("List commands\n") + + " bitcoind [options] help \t\t " + _("Get help for a command\n") + _("Options:\n") + - " -conf= \t\t " + _("Specify configuration file (default: bitcoin.conf)\n") + - " -pid= \t\t " + _("Specify pid file (default: bitcoind.pid)\n") + + " -conf= \t\t " + _("Specify configuration file (default: ppcoin.conf)\n") + + " -pid= \t\t " + _("Specify pid file (default: ppcoind.pid)\n") + " -gen \t\t " + _("Generate coins\n") + " -gen=0 \t\t " + _("Don't generate coins\n") + " -min \t\t " + _("Start minimized\n") + @@@ -179,9 -186,16 +189,16 @@@ " -timeout= \t " + _("Specify connection timeout (in milliseconds)\n") + " -proxy= \t " + _("Connect through socks4 proxy\n") + " -dns \t " + _("Allow DNS lookups for addnode and connect\n") + + " -port= \t\t " + _("Listen for connections on (default: 8333 or testnet: 18333)\n") + + " -maxconnections=\t " + _("Maintain at most connections to peers (default: 125)\n") + " -addnode= \t " + _("Add a node to connect to\n") + " -connect= \t\t " + _("Connect only to the specified node\n") + " -nolisten \t " + _("Don't accept connections from outside\n") + + " -nodnsseed \t " + _("Don't bootstrap list of peers using DNS\n") + + " -banscore= \t " + _("Threshold for disconnecting misbehaving peers (default: 100)\n") + + " -bantime= \t " + _("Number of seconds to keep misbehaving peers from reconnecting (default: 86400)\n") + + " -maxreceivebuffer=\t " + _("Maximum per-connection receive buffer, *1000 bytes (default: 10000)\n") + + " -maxsendbuffer=\t " + _("Maximum per-connection send buffer, *1000 bytes (default: 10000)\n") + #ifdef USE_UPNP #if USE_UPNP " -noupnp \t " + _("Don't attempt to use UPnP to map the listening port\n") + @@@ -193,10 -207,16 +210,16 @@@ #ifdef GUI " -server \t\t " + _("Accept command line and JSON-RPC commands\n") + #endif - #ifndef __WXMSW__ + #ifndef WIN32 " -daemon \t\t " + _("Run in the background as a daemon and accept commands\n") + #endif " -testnet \t\t " + _("Use the test network\n") + + " -debug \t\t " + _("Output extra debugging information\n") + + " -logtimestamps \t " + _("Prepend debug output with timestamp\n") + + " -printtoconsole \t " + _("Send trace/debug info to console instead of debug.log file\n") + + #ifdef WIN32 + " -printtodebugger \t " + _("Send trace/debug info to debugger\n") + + #endif " -rpcuser= \t " + _("Username for JSON-RPC connections\n") + " -rpcpassword=\t " + _("Password for JSON-RPC connections\n") + " -rpcport= \t\t " + _("Listen for JSON-RPC connections on (default: 8332)\n") + @@@ -217,21 -237,16 +240,16 @@@ strUsage += string() + " -? \t\t " + _("This help message\n"); // Remove tabs strUsage.erase(std::remove(strUsage.begin(), strUsage.end(), '\t'), strUsage.end()); fprintf(stderr, "%s", strUsage.c_str()); - #endif return false; } fDebug = GetBoolArg("-debug"); fAllowDNS = GetBoolArg("-dns"); - #ifndef __WXMSW__ + #ifndef WIN32 fDaemon = GetBoolArg("-daemon"); #else fDaemon = false; @@@ -243,10 -258,9 +261,9 @@@ fServer = GetBoolArg("-server"); /* force fServer when running without GUI */ - #ifndef GUI + #if !defined(QT_GUI) fServer = true; #endif - fPrintToConsole = GetBoolArg("-printtoconsole"); fPrintToDebugger = GetBoolArg("-printtodebugger"); @@@ -255,6 -269,7 +272,7 @@@ fNoListen = GetBoolArg("-nolisten") || fTOR; fLogTimestamps = GetBoolArg("-logtimestamps"); + #ifndef QT_GUI for (int i = 1; i < argc; i++) if (!IsSwitchChar(argv[i][0])) fCommandLine = true; @@@ -264,8 -279,9 +282,9 @@@ int ret = CommandLineRPC(argc, argv); exit(ret); } + #endif - #ifndef __WXMSW__ + #ifndef WIN32 if (fDaemon) { // Daemonize @@@ -291,11 -307,6 +310,6 @@@ ShrinkDebugFile(); printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); printf("Bitcoin version %s\n", FormatFullVersion().c_str()); - #ifdef GUI - printf("OS version %s\n", ((string)wxGetOsDescription()).c_str()); - printf("System default language is %d %s\n", g_locale.GetSystemLanguage(), ((string)g_locale.GetSysName()).c_str()); - printf("Language file %s (%s)\n", (string("locale/") + (string)g_locale.GetCanonicalName() + "/LC_MESSAGES/bitcoin.mo").c_str(), ((string)g_locale.GetLocale()).c_str()); - #endif printf("Default data directory %s\n", GetDefaultDataDir().c_str()); if (GetBoolArg("-loadblockindextest")) @@@ -306,46 -317,6 +320,6 @@@ return false; } - // - // Limit to single instance per user - // Required to protect the database files if we're going to keep deleting log.* - // - #if defined(__WXMSW__) && defined(GUI) - // wxSingleInstanceChecker doesn't work on Linux - wxString strMutexName = wxString("bitcoin_running.") + getenv("HOMEPATH"); - for (int i = 0; i < strMutexName.size(); i++) - if (!isalnum(strMutexName[i])) - strMutexName[i] = '.'; - wxSingleInstanceChecker* psingleinstancechecker = new wxSingleInstanceChecker(strMutexName); - if (psingleinstancechecker->IsAnotherRunning()) - { - printf("Existing instance found\n"); - unsigned int nStart = GetTime(); - loop - { - // Show the previous instance and exit - HWND hwndPrev = FindWindowA("wxWindowClassNR", "Bitcoin"); - if (hwndPrev) - { - if (IsIconic(hwndPrev)) - ShowWindow(hwndPrev, SW_RESTORE); - SetForegroundWindow(hwndPrev); - return false; - } - - if (GetTime() > nStart + 60) - return false; - - // Resume this instance if the other exits - delete psingleinstancechecker; - Sleep(1000); - psingleinstancechecker = new wxSingleInstanceChecker(strMutexName); - if (!psingleinstancechecker->IsAnotherRunning()) - break; - } - } - #endif - // Make sure only a single bitcoin process is using the data directory. string strLockFile = GetDataDir() + "/.lock"; FILE* file = fopen(strLockFile.c_str(), "a"); // empty lock file; created if it doesn't exist. @@@ -376,18 -347,21 +350,21 @@@ strErrors = ""; int64 nStart; + InitMessage(_("Loading addresses...")); printf("Loading addresses...\n"); nStart = GetTimeMillis(); if (!LoadAddresses()) strErrors += _("Error loading addr.dat \n"); printf(" addresses %15"PRI64d"ms\n", GetTimeMillis() - nStart); + InitMessage(_("Loading block index...")); printf("Loading block index...\n"); nStart = GetTimeMillis(); if (!LoadBlockIndex()) strErrors += _("Error loading blkindex.dat \n"); printf(" block index %15"PRI64d"ms\n", GetTimeMillis() - nStart); + InitMessage(_("Loading wallet...")); printf("Loading wallet...\n"); nStart = GetTimeMillis(); bool fFirstRun; @@@ -399,6 -373,12 +376,12 @@@ strErrors += _("Error loading wallet.dat: Wallet corrupted \n"); else if (nLoadWalletRet == DB_TOO_NEW) strErrors += _("Error loading wallet.dat: Wallet requires newer version of Bitcoin \n"); + else if (nLoadWalletRet == DB_NEED_REWRITE) + { + strErrors += _("Wallet needed to be rewritten: restart Bitcoin to complete \n"); + wxMessageBox(strErrors, "Bitcoin", wxOK | wxICON_ERROR); + return false; + } else strErrors += _("Error loading wallet.dat \n"); } @@@ -418,12 -398,14 +401,14 @@@ } if (pindexBest != pindexRescan) { + InitMessage(_("Rescanning...")); printf("Rescanning last %i blocks (from block %i)...\n", pindexBest->nHeight - pindexRescan->nHeight, pindexRescan->nHeight); nStart = GetTimeMillis(); pwalletMain->ScanForWalletTransactions(pindexRescan, true); printf(" rescan %15"PRI64d"ms\n", GetTimeMillis() - nStart); } + InitMessage(_("Done loading")); printf("Done loading\n"); //// debug print @@@ -505,11 -487,6 +490,6 @@@ } } - if (GetBoolArg("-nodnsseed")) - printf("DNS seeding disabled\n"); - else - DNSAddressSeed(); - if (mapArgs.count("-paytxfee")) { if (!ParseMoney(mapArgs["-paytxfee"], nTransactionFee)) @@@ -517,7 -494,7 +497,7 @@@ wxMessageBox(_("Invalid amount for -paytxfee="), "Bitcoin"); return false; } - if (nTransactionFee > 0.25 * COIN) + if (nTransactionFee >= 10 * COIN) wxMessageBox(_("Warning: -paytxfee is set very high. This is the transaction fee you will pay if you send a transaction."), "Bitcoin", wxOK | wxICON_EXCLAMATION); } @@@ -533,30 -510,20 +513,20 @@@ } // - // Create the main window and start the node + // Start the node // - #ifdef GUI - if (!fDaemon) - CreateMainWindow(); - #endif - if (!CheckDiskSpace()) return false; RandAddSeedPerfmon(); if (!CreateThread(StartNode, NULL)) - wxMessageBox("Error: CreateThread(StartNode) failed", "Bitcoin"); + wxMessageBox(_("Error: CreateThread(StartNode) failed"), "Bitcoin"); if (fServer) CreateThread(ThreadRPCServer, NULL); - #if defined(__WXMSW__) && defined(GUI) - if (fFirstRun) - SetStartOnSystemStartup(true); - #endif - - #ifndef GUI + #if !defined(QT_GUI) while (1) Sleep(5000); #endif diff --combined src/main.cpp index d528612,a7871fc..24a7fd0 --- a/src/main.cpp +++ b/src/main.cpp @@@ -1,13 -1,12 +1,13 @@@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2011 The Bitcoin developers +// Copyright (c) 2011 The PPCoin 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 "cryptopp/sha.h" #include #include @@@ -29,9 -28,8 +29,8 @@@ unsigned int nTransactionsUpdated = 0 map mapNextTx; map mapBlockIndex; -uint256 hashGenesisBlock("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"); +uint256 hashGenesisBlock("0x00000000e74ef41733382f8a94d41bf29f20c6c48a7ab489e1fab0ab719bf676"); static CBigNum bnProofOfWorkLimit(~uint256(0) >> 32); - const int nTotalBlocksEstimate = 0; // Conservative estimate of total nr of blocks on main chain const int nInitialBlockThreshold = 120; // Regard blocks up until N-threshold as "initial download" CBlockIndex* pindexGenesisBlock = NULL; int nBestHeight = -1; @@@ -41,6 -39,8 +40,8 @@@ uint256 hashBestChain = 0 CBlockIndex* pindexBest = NULL; int64 nTimeBestReceived = 0; + CMedianFilter cPeerBlockCounts(5, 0); // Amount of blocks that other nodes claim to have + map mapOrphanBlocks; multimap mapOrphanBlocksByPrev; @@@ -53,7 -53,7 +54,7 @@@ int64 nHPSTimerStart // Settings int fGenerateBitcoins = false; -int64 nTransactionFee = 0; +int64 nTransactionFee = MIN_TX_FEE; int fLimitProcessors = false; int nLimitProcessors = 1; int fMinimizeToTray = true; @@@ -65,16 -65,14 +66,14 @@@ int fUseUPnP = false #endif - - - - - ////////////////////////////////////////////////////////////////////////////// // // dispatching functions // + // These functions dispatch to one or all registered wallets + + void RegisterWallet(CWallet* pwalletIn) { CRITICAL_BLOCK(cs_setpwalletRegistered) @@@ -91,6 -89,7 +90,7 @@@ void UnregisterWallet(CWallet* pwalletI } } + // check whether the passed transaction is from us bool static IsFromMe(CTransaction& tx) { BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) @@@ -99,6 -98,7 +99,7 @@@ return false; } + // get the wallet transaction with the given hash (if it exists) bool static GetTransaction(const uint256& hashTx, CWalletTx& wtx) { BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) @@@ -107,42 -107,49 +108,49 @@@ return false; } + // erases transaction with the given hash from all wallets void static EraseFromWallets(uint256 hash) { BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) pwallet->EraseFromWallet(hash); } + // make sure all wallets know about the given transaction, in the given block void static SyncWithWallets(const CTransaction& tx, const CBlock* pblock = NULL, bool fUpdate = false) { BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) pwallet->AddToWalletIfInvolvingMe(tx, pblock, fUpdate); } + // notify wallets about a new best chain void static SetBestChain(const CBlockLocator& loc) { BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) pwallet->SetBestChain(loc); } + // notify wallets about an updated transaction void static UpdatedTransaction(const uint256& hashTx) { BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) pwallet->UpdatedTransaction(hashTx); } + // dump all wallets void static PrintWallets(const CBlock& block) { BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) pwallet->PrintWallet(block); } + // notify wallets about an incoming inventory (for request counts) void static Inventory(const uint256& hash) { BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) pwallet->Inventory(hash); } + // ask wallets to resend their transactions void static ResendWalletTransactions() { BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) @@@ -297,24 -304,24 +305,24 @@@ bool CTransaction::CheckTransaction() c { // Basic checks that don't depend on any context if (vin.empty()) - return error("CTransaction::CheckTransaction() : vin empty"); + return DoS(10, error("CTransaction::CheckTransaction() : vin empty")); if (vout.empty()) - return error("CTransaction::CheckTransaction() : vout empty"); + return DoS(10, error("CTransaction::CheckTransaction() : vout empty")); // Size limits if (::GetSerializeSize(*this, SER_NETWORK) > MAX_BLOCK_SIZE) - return error("CTransaction::CheckTransaction() : size limits failed"); + return DoS(100, error("CTransaction::CheckTransaction() : size limits failed")); // Check for negative or overflow output values int64 nValueOut = 0; BOOST_FOREACH(const CTxOut& txout, vout) { if (txout.nValue < 0) - return error("CTransaction::CheckTransaction() : txout.nValue negative"); + return DoS(100, error("CTransaction::CheckTransaction() : txout.nValue negative")); if (txout.nValue > MAX_MONEY) - return error("CTransaction::CheckTransaction() : txout.nValue too high"); + return DoS(100, error("CTransaction::CheckTransaction() : txout.nValue too high")); nValueOut += txout.nValue; if (!MoneyRange(nValueOut)) - return error("CTransaction::CheckTransaction() : txout total out of range"); + return DoS(100, error("CTransaction::CheckTransaction() : txout total out of range")); } // Check for duplicate inputs @@@ -329,13 -336,13 +337,13 @@@ if (IsCoinBase()) { if (vin[0].scriptSig.size() < 2 || vin[0].scriptSig.size() > 100) - return error("CTransaction::CheckTransaction() : coinbase script size"); + return DoS(100, error("CTransaction::CheckTransaction() : coinbase script size")); } else { BOOST_FOREACH(const CTxIn& txin, vin) if (txin.prevout.IsNull()) - return error("CTransaction::CheckTransaction() : prevout is null"); + return DoS(10, error("CTransaction::CheckTransaction() : prevout is null")); } return true; @@@ -351,7 -358,7 +359,7 @@@ bool CTransaction::AcceptToMemoryPool(C // Coinbase is only valid in a block, not as a loose transaction if (IsCoinBase()) - return error("AcceptToMemoryPool() : coinbase as individual tx"); + return DoS(100, error("AcceptToMemoryPool() : coinbase as individual tx")); // To help v0.1.5 clients who would see it as a negative number if ((int64)nLockTime > INT_MAX) @@@ -364,7 -371,7 +372,7 @@@ // 34 bytes because a TxOut is: // 20-byte address + 8 byte bitcoin amount + 5 bytes of ops + 1 byte script length if (GetSigOpCount() > nSize / 34 || nSize < 100) - return error("AcceptToMemoryPool() : nonstandard transaction"); + return error("AcceptToMemoryPool() : transaction with out-of-bounds SigOpCount"); // Rather not work on nonstandard transactions (unless -testnet) if (!fTestNet && !IsStandard()) @@@ -420,7 -427,7 +428,7 @@@ } // Don't accept it if it can't get into a block - if (nFees < GetMinFee(1000, true, true)) + if (nFees < GetMinFee(1000, false, true)) return error("AcceptToMemoryPool() : not enough fees"); // Continuously rate-limit free transactions @@@ -652,28 -659,70 +660,48 @@@ int64 static GetBlockValue(int nHeight return nSubsidy + nFees; } - unsigned int static GetNextWorkRequired(const CBlockIndex* pindexLast) -static const int64 nTargetTimespan = 14 * 24 * 60 * 60; // two weeks ++static const int64 nTargetTimespan = 7 * 24 * 60 * 60; // one week + static const int64 nTargetSpacing = 10 * 60; + static const int64 nInterval = nTargetTimespan / nTargetSpacing; + + // + // minimum amount of work that could possibly be required nTime after + // minimum work required was nBase + // + unsigned int ComputeMinWork(unsigned int nBase, int64 nTime) { - const int64 nTargetTimespan = 7 * 24 * 60 * 60; // one week - const int64 nTargetSpacing = 10 * 60; - const int64 nInterval = nTargetTimespan / nTargetSpacing; + CBigNum bnResult; + bnResult.SetCompact(nBase); + while (nTime > 0 && bnResult < bnProofOfWorkLimit) + { + // Maximum 400% adjustment... + bnResult *= 4; + // ... in best-case exactly 4-times-normal target time + nTime -= nTargetTimespan*4; + } + if (bnResult > bnProofOfWorkLimit) + bnResult = bnProofOfWorkLimit; + return bnResult.GetCompact(); + } + unsigned int static GetNextWorkRequired(const CBlockIndex* pindexLast) + { - - // Genesis block - if (pindexLast == NULL) + // Genesis block and first block + if (pindexLast == NULL || pindexLast->pprev == NULL) return bnProofOfWorkLimit.GetCompact(); - // Only change once per interval - if ((pindexLast->nHeight+1) % nInterval != 0) - return pindexLast->nBits; - - // Go back by what we want to be 14 days worth of blocks - const CBlockIndex* pindexFirst = pindexLast; - for (int i = 0; pindexFirst && i < nInterval-1; i++) - pindexFirst = pindexFirst->pprev; - assert(pindexFirst); - - // Limit adjustment step - int64 nActualTimespan = pindexLast->GetBlockTime() - pindexFirst->GetBlockTime(); - printf(" nActualTimespan = %"PRI64d" before bounds\n", nActualTimespan); - if (nActualTimespan < nTargetTimespan/4) - nActualTimespan = nTargetTimespan/4; - if (nActualTimespan > nTargetTimespan*4) - nActualTimespan = nTargetTimespan*4; - - // Retarget + int64 nActualSpacing = pindexLast->GetBlockTime() - pindexLast->pprev->GetBlockTime(); + + // ppcoin: target change every block + // ppcoin: retarget with exponential moving toward target spacing CBigNum bnNew; bnNew.SetCompact(pindexLast->nBits); - bnNew *= nActualTimespan; - bnNew /= nTargetTimespan; + bnNew *= ((nInterval - 1) * nTargetSpacing + nActualSpacing + nActualSpacing); + bnNew /= ((nInterval + 1) * nTargetSpacing); if (bnNew > bnProofOfWorkLimit) bnNew = bnProofOfWorkLimit; - /// debug print - printf("GetNextWorkRequired RETARGET\n"); - printf("nTargetTimespan = %"PRI64d" nActualTimespan = %"PRI64d"\n", nTargetTimespan, nActualTimespan); - printf("Before: %08x %s\n", pindexLast->nBits, CBigNum().SetCompact(pindexLast->nBits).getuint256().ToString().c_str()); - printf("After: %08x %s\n", bnNew.GetCompact(), bnNew.getuint256().ToString().c_str()); - return bnNew.GetCompact(); } @@@ -693,22 -742,15 +721,15 @@@ bool CheckProofOfWork(uint256 hash, uns return true; } - // Return conservative estimate of total number of blocks, 0 if unknown - int GetTotalBlocksEstimate() + // Return maximum amount of blocks that other nodes claim to have + int GetNumBlocksOfPeers() { - if(fTestNet) - { - return 0; - } - else - { - return nTotalBlocksEstimate; - } + return std::max(cPeerBlockCounts.median(), Checkpoints::GetTotalBlocksEstimate()); } bool IsInitialBlockDownload() { - if (pindexBest == NULL || nBestHeight < (GetTotalBlocksEstimate()-nInitialBlockThreshold)) + if (pindexBest == NULL || nBestHeight < (Checkpoints::GetTotalBlocksEstimate()-nInitialBlockThreshold)) return true; static int64 nLastUpdate; static CBlockIndex* pindexLastBest; @@@ -783,6 -825,9 +804,9 @@@ bool CTransaction::ConnectInputs(CTxDB CBlockIndex* pindexBlock, int64& nFees, bool fBlock, bool fMiner, int64 nMinFee) { // Take over previous transactions' spent pointers + // fBlock is true when this is called from AcceptBlock when a new best-block is added to the blockchain + // fMiner is true when called from the internal bitcoin miner + // ... both are false when called from CTransaction::AcceptToMemoryPool if (!IsCoinBase()) { int64 nValueIn = 0; @@@ -828,7 -873,7 +852,7 @@@ } if (prevout.n >= txPrev.vout.size() || prevout.n >= txindex.vSpent.size()) - return error("ConnectInputs() : %s prevout.n out of range %d %d %d prev tx %s\n%s", GetHash().ToString().substr(0,10).c_str(), prevout.n, txPrev.vout.size(), txindex.vSpent.size(), prevout.hash.ToString().substr(0,10).c_str(), txPrev.ToString().c_str()); + return DoS(100, error("ConnectInputs() : %s prevout.n out of range %d %d %d prev tx %s\n%s", GetHash().ToString().substr(0,10).c_str(), prevout.n, txPrev.vout.size(), txindex.vSpent.size(), prevout.hash.ToString().substr(0,10).c_str(), txPrev.ToString().c_str())); // If prev is coinbase, check that it's matured if (txPrev.IsCoinBase()) @@@ -836,18 -881,24 +860,24 @@@ if (pindex->nBlockPos == txindex.pos.nBlockPos && pindex->nFile == txindex.pos.nFile) return error("ConnectInputs() : tried to spend coinbase at depth %d", pindexBlock->nHeight - pindex->nHeight); - // Verify signature - if (!VerifySignature(txPrev, *this, i)) - return error("ConnectInputs() : %s VerifySignature failed", GetHash().ToString().substr(0,10).c_str()); - - // Check for conflicts + // Skip ECDSA signature verification when connecting blocks (fBlock=true) during initial download + // (before the last blockchain checkpoint). This is safe because block merkle hashes are + // still computed and checked, and any change will be caught at the next checkpoint. + if (!(fBlock && IsInitialBlockDownload())) + // Verify signature + if (!VerifySignature(txPrev, *this, i)) + return DoS(100,error("ConnectInputs() : %s VerifySignature failed", GetHash().ToString().substr(0,10).c_str())); + + // Check for conflicts (double-spend) + // This doesn't trigger the DoS code on purpose; if it did, it would make it easier + // for an attacker to attempt to split the network. if (!txindex.vSpent[prevout.n].IsNull()) return fMiner ? false : error("ConnectInputs() : %s prev tx already used at %s", GetHash().ToString().substr(0,10).c_str(), txindex.vSpent[prevout.n].ToString().c_str()); // Check for negative or overflow input values nValueIn += txPrev.vout[prevout.n].nValue; if (!MoneyRange(txPrev.vout[prevout.n].nValue) || !MoneyRange(nValueIn)) - return error("ConnectInputs() : txin values out of range"); + return DoS(100, error("ConnectInputs() : txin values out of range")); // Mark outpoints as spent txindex.vSpent[prevout.n] = posThisTx; @@@ -860,17 -911,17 +890,17 @@@ } if (nValueIn < GetValueOut()) - return error("ConnectInputs() : %s value in < value out", GetHash().ToString().substr(0,10).c_str()); + return DoS(100, error("ConnectInputs() : %s value in < value out", GetHash().ToString().substr(0,10).c_str())); // Tally transaction fees int64 nTxFee = nValueIn - GetValueOut(); if (nTxFee < 0) - return error("ConnectInputs() : %s nTxFee < 0", GetHash().ToString().substr(0,10).c_str()); + return DoS(100, error("ConnectInputs() : %s nTxFee < 0", GetHash().ToString().substr(0,10).c_str())); if (nTxFee < nMinFee) return false; nFees += nTxFee; if (!MoneyRange(nFees)) - return error("ConnectInputs() : nFees out of range"); + return DoS(100, error("ConnectInputs() : nFees out of range")); } if (fBlock) @@@ -1213,11 -1264,11 +1243,11 @@@ bool CBlock::CheckBlock() cons // Size limits if (vtx.empty() || vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(*this, SER_NETWORK) > MAX_BLOCK_SIZE) - return error("CheckBlock() : size limits failed"); + return DoS(100, error("CheckBlock() : size limits failed")); // Check proof of work matches claimed amount if (!CheckProofOfWork(GetHash(), nBits)) - return error("CheckBlock() : proof of work failed"); + return DoS(50, error("CheckBlock() : proof of work failed")); // Check timestamp if (GetBlockTime() > GetAdjustedTime() + 2 * 60 * 60) @@@ -1225,23 -1276,23 +1255,23 @@@ // First transaction must be coinbase, the rest must not be if (vtx.empty() || !vtx[0].IsCoinBase()) - return error("CheckBlock() : first tx is not coinbase"); + return DoS(100, error("CheckBlock() : first tx is not coinbase")); for (int i = 1; i < vtx.size(); i++) if (vtx[i].IsCoinBase()) - return error("CheckBlock() : more than one coinbase"); + return DoS(100, error("CheckBlock() : more than one coinbase")); // Check transactions BOOST_FOREACH(const CTransaction& tx, vtx) if (!tx.CheckTransaction()) - return error("CheckBlock() : CheckTransaction failed"); + return DoS(tx.nDoS, error("CheckBlock() : CheckTransaction failed")); // Check that it's not full of nonstandard transactions if (GetSigOpCount() > MAX_BLOCK_SIGOPS) - return error("CheckBlock() : too many nonstandard transactions"); + return DoS(100, error("CheckBlock() : out-of-bounds SigOpCount")); // Check merkleroot if (hashMerkleRoot != BuildMerkleTree()) - return error("CheckBlock() : hashMerkleRoot mismatch"); + return DoS(100, error("CheckBlock() : hashMerkleRoot mismatch")); return true; } @@@ -1256,13 -1307,13 +1286,13 @@@ bool CBlock::AcceptBlock( // Get prev block index map::iterator mi = mapBlockIndex.find(hashPrevBlock); if (mi == mapBlockIndex.end()) - return error("AcceptBlock() : prev block not found"); + return DoS(10, error("AcceptBlock() : prev block not found")); CBlockIndex* pindexPrev = (*mi).second; int nHeight = pindexPrev->nHeight+1; // Check proof of work if (nBits != GetNextWorkRequired(pindexPrev)) - return error("AcceptBlock() : incorrect proof of work"); + return DoS(100, error("AcceptBlock() : incorrect proof of work")); // Check timestamp against prev if (GetBlockTime() <= pindexPrev->GetMedianTimePast()) @@@ -1271,13 -1322,11 +1301,11 @@@ // Check that all transactions are finalized BOOST_FOREACH(const CTransaction& tx, vtx) if (!tx.IsFinal(nHeight, GetBlockTime())) - return error("AcceptBlock() : contains a non-final transaction"); + return DoS(10, error("AcceptBlock() : contains a non-final transaction")); // Check that the block chain matches the known block chain up to a checkpoint - if (!fTestNet) - // ppcoin: no checkpoint yet; to be created after beta - if ((nHeight == -1 && hash != uint256("0x83f760b87b13d7002eaccc4a5a154aaea0f861e52b6eb481d30a344f55605c01"))) - return error("AcceptBlock() : rejected by checkpoint lockin at %d", nHeight); + if (!Checkpoints::CheckBlock(nHeight, hash)) + return DoS(100, error("AcceptBlock() : rejected by checkpoint lockin at %d", nHeight)); // Write block to history file if (!CheckDiskSpace(::GetSerializeSize(*this, SER_DISK))) @@@ -1299,7 -1348,7 +1327,7 @@@ return true; } - bool static ProcessBlock(CNode* pfrom, CBlock* pblock) + bool ProcessBlock(CNode* pfrom, CBlock* pblock) { // Check for duplicate uint256 hash = pblock->GetHash(); @@@ -1312,6 -1361,28 +1340,28 @@@ if (!pblock->CheckBlock()) return error("ProcessBlock() : CheckBlock FAILED"); + CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(mapBlockIndex); + if (pcheckpoint && pblock->hashPrevBlock != hashBestChain) + { + // Extra checks to prevent "fill up memory by spamming with bogus blocks" + int64 deltaTime = pblock->GetBlockTime() - pcheckpoint->nTime; + if (deltaTime < 0) + { + pfrom->Misbehaving(100); + return error("ProcessBlock() : block with timestamp before last checkpoint"); + } + CBigNum bnNewBlock; + bnNewBlock.SetCompact(pblock->nBits); + CBigNum bnRequired; + bnRequired.SetCompact(ComputeMinWork(pcheckpoint->nBits, deltaTime)); + if (bnNewBlock > bnRequired) + { + pfrom->Misbehaving(100); + return error("ProcessBlock() : block with too little proof-of-work"); + } + } + + // If don't already have its previous block, shunt it off to holding area until we get it if (!mapBlockIndex.count(pblock->hashPrevBlock)) { @@@ -1455,7 -1526,7 +1505,7 @@@ bool LoadBlockIndex(bool fAllowNew // vMerkleTree: 4a5e1e // Genesis block - const char* pszTimestamp = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks"; + const char* pszTimestamp = "MarketWatch 07/Nov/2011 Gold tops $1,790 to end at over six-week high"; CTransaction txNew; txNew.vin.resize(1); txNew.vout.resize(1); @@@ -1467,9 -1538,9 +1517,9 @@@ block.hashPrevBlock = 0; block.hashMerkleRoot = block.BuildMerkleTree(); block.nVersion = 1; - block.nTime = 1231006505; + block.nTime = 1320941849; block.nBits = 0x1d00ffff; - block.nNonce = 2083236893; + block.nNonce = 725069208; if (fTestNet) { @@@ -1482,7 -1553,7 +1532,7 @@@ 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")); + assert(block.hashMerkleRoot == uint256("0x09cc647316c90e7e14f225113eec3539e80284695c91e7262a65c72c5d75a868")); block.print(); assert(block.GetHash() == hashGenesisBlock); @@@ -1735,7 -1806,10 +1785,10 @@@ bool static ProcessMessage(CNode* pfrom { // Each connection can only send one version message if (pfrom->nVersion != 0) + { + pfrom->Misbehaving(1); return false; + } int64 nTime; CAddress addrMe; @@@ -1813,12 -1887,15 +1866,15 @@@ pfrom->fSuccessfullyConnected = true; printf("version message: version %d, blocks=%d\n", pfrom->nVersion, pfrom->nStartingHeight); + + cPeerBlockCounts.input(pfrom->nStartingHeight); } else if (pfrom->nVersion == 0) { // Must have a version message before anything else + pfrom->Misbehaving(1); return false; } @@@ -1840,7 -1917,10 +1896,10 @@@ if (pfrom->nVersion < 31402 && mapAddresses.size() > 1000) return true; if (vAddr.size() > 1000) + { + pfrom->Misbehaving(20); return error("message addr size() = %d", vAddr.size()); + } // Store the new addresses CAddrDB addrDB; @@@ -1898,7 -1978,10 +1957,10 @@@ vector vInv; vRecv >> vInv; if (vInv.size() > 50000) + { + pfrom->Misbehaving(20); return error("message inv size() = %d", vInv.size()); + } CTxDB txdb("r"); BOOST_FOREACH(const CInv& inv, vInv) @@@ -1927,7 -2010,10 +1989,10 @@@ vector vInv; vRecv >> vInv; if (vInv.size() > 50000) + { + pfrom->Misbehaving(20); return error("message getdata size() = %d", vInv.size()); + } BOOST_FOREACH(const CInv& inv, vInv) { @@@ -2099,6 -2185,7 +2164,7 @@@ printf("storing orphan tx %s\n", inv.hash.ToString().substr(0,10).c_str()); AddOrphanTx(vMsg); } + if (tx.nDoS) pfrom->Misbehaving(tx.nDoS); } @@@ -2115,6 -2202,7 +2181,7 @@@ if (ProcessBlock(pfrom, &block)) mapAlreadyAskedFor.erase(inv); + if (block.nDoS) pfrom->Misbehaving(block.nDoS); } @@@ -2558,15 -2646,25 +2625,25 @@@ int static FormatHashBlocks(void* pbuff return blocks; } static const unsigned int pSHA256InitState[8] = {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19}; - inline void SHA256Transform(void* pstate, void* pinput, const void* pinit) + void SHA256Transform(void* pstate, void* pinput, const void* pinit) { - memcpy(pstate, pinit, 32); - CryptoPP::SHA256::Transform((CryptoPP::word32*)pstate, (CryptoPP::word32*)pinput); + SHA256_CTX ctx; + unsigned char data[64]; + + SHA256_Init(&ctx); + + for (int i = 0; i < 16; i++) + ((uint32_t*)data)[i] = ByteReverse(((uint32_t*)pinput)[i]); + + for (int i = 0; i < 8; i++) + ctx.h[i] = ((uint32_t*)pinit)[i]; + + SHA256_Update(&ctx, data, sizeof(data)); + for (int i = 0; i < 8; i++) + ((uint32_t*)pstate)[i] = ctx.h[i]; } // @@@ -2728,8 -2826,9 +2805,8 @@@ CBlock* CreateNewBlock(CReserveKey& res if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS) continue; - // Transaction fee required depends on block size - bool fAllowFree = (nBlockSize + nTxSize < 4000 || CTransaction::AllowFree(dPriority)); - int64 nMinFee = tx.GetMinFee(nBlockSize, fAllowFree, true); + // ppcoin: simplify transaction fee - allow free = false + int64 nMinFee = tx.GetMinFee(nBlockSize, false, true); // Connecting shouldn't fail due to dependency on other memory pool transactions // because we're already processing them in order of dependency @@@ -2866,7 -2965,6 +2943,6 @@@ bool CheckWork(CBlock* pblock, CWallet return error("BitcoinMiner : ProcessBlock, block not accepted"); } - Sleep(2000); return true; } diff --combined src/main.h index 6c53c76,3870cee..13974f9 --- a/src/main.h +++ b/src/main.h @@@ -1,6 -1,5 +1,6 @@@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2011 The Bitcoin developers +// Copyright (c) 2011 The PPCoin 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_MAIN_H @@@ -31,11 -30,11 +31,11 @@@ class CBlockIndex 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 int64 COIN = 100000000; -static const int64 CENT = 1000000; -static const int64 MIN_TX_FEE = 50000; +static const int64 COIN = 10000; +static const int64 CENT = 100; +static const int64 MIN_TX_FEE = 10000; static const int64 MIN_RELAY_TX_FEE = 10000; -static const int64 MAX_MONEY = 21000000 * COIN; +static const int64 MAX_MONEY = 800000000000000 * COIN; inline bool MoneyRange(int64 nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); } static const int COINBASE_MATURITY = 100; // Threshold for nLockTime: below this value it is interpreted as block number, otherwise as UNIX timestamp. @@@ -86,6 -85,7 +86,7 @@@ class CTxIndex void RegisterWallet(CWallet* pwalletIn); void UnregisterWallet(CWallet* pwalletIn); + bool ProcessBlock(CNode* pfrom, CBlock* pblock); bool CheckDiskSpace(uint64 nAdditionalBytes=0); FILE* OpenBlockFile(unsigned int nFile, unsigned int nBlockPos, const char* pszMode="rb"); FILE* AppendBlockFile(unsigned int& nFileRet); @@@ -99,7 -99,8 +100,8 @@@ void IncrementExtraNonce(CBlock* pblock void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash1); bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey); bool CheckProofOfWork(uint256 hash, unsigned int nBits); - int GetTotalBlocksEstimate(); + unsigned int ComputeMinWork(unsigned int nBase, int64 nTime); + int GetNumBlocksOfPeers(); bool IsInitialBlockDownload(); std::string GetWarnings(std::string strFor); @@@ -376,7 -377,7 +378,7 @@@ public { if (scriptPubKey.size() < 6) return "CTxOut(error)"; - return strprintf("CTxOut(nValue=%"PRI64d".%08"PRI64d", scriptPubKey=%s)", nValue / COIN, nValue % COIN, scriptPubKey.ToString().substr(0,30).c_str()); + return strprintf("CTxOut(nValue=%s, scriptPubKey=%s)", FormatMoney(nValue).c_str(), scriptPubKey.ToString().substr(0,30).c_str()); } void print() const @@@ -400,6 -401,9 +402,9 @@@ public std::vector vout; unsigned int nLockTime; + // Denial-of-service detection: + mutable int nDoS; + bool DoS(int nDoSIn, bool fIn) const { nDoS += nDoSIn; return fIn; } CTransaction() { @@@ -421,6 -425,7 +426,7 @@@ vin.clear(); vout.clear(); nLockTime = 0; + nDoS = 0; // Denial-of-service prevention } bool IsNull() const @@@ -531,7 -536,7 +537,7 @@@ unsigned int nBytes = ::GetSerializeSize(*this, SER_NETWORK); unsigned int nNewBlockSize = nBlockSize + nBytes; - int64 nMinFee = (1 + (int64)nBytes / 1000) * nBaseFee; + int64 nMinFee = nBaseFee; // ppcoin: simplify transaction fee if (fAllowFree) { @@@ -787,6 -792,9 +793,9 @@@ public // memory only mutable std::vector vMerkleTree; + // Denial-of-service detection: + mutable int nDoS; + bool DoS(int nDoSIn, bool fIn) const { nDoS += nDoSIn; return fIn; } CBlock() { @@@ -820,6 -828,7 +829,7 @@@ nNonce = 0; vtx.clear(); vMerkleTree.clear(); + nDoS = 0; } bool IsNull() const @@@ -918,7 -927,7 +928,7 @@@ fflush(fileout); if (!IsInitialBlockDownload() || (nBestHeight+1) % 500 == 0) { - #ifdef __WXMSW__ + #ifdef WIN32 _commit(_fileno(fileout)); #else fsync(fileno(fileout)); diff --combined src/makefile.unix index 5dbde3a,6c48199..b751e3f --- a/src/makefile.unix +++ b/src/makefile.unix @@@ -1,47 -1,93 +1,94 @@@ # Copyright (c) 2009-2010 Satoshi Nakamoto +# Copyright (c) 2011 The PPCoin developers # Distributed under the MIT/X11 software license, see the accompanying # file license.txt or http://www.opensource.org/licenses/mit-license.php. - CXX=g++ - - WXINCLUDEPATHS=$(shell wx-config --cxxflags) + USE_UPNP:=0 - WXLIBS=$(shell wx-config --libs) + DEFS=-DNOPCH - USE_UPNP:=0 + DEFS += $(addprefix -I,$(BOOST_INCLUDE_PATH) $(BDB_INCLUDE_PATH) $(OPENSSL_INCLUDE_PATH)) + LIBS += $(addprefix -l,$(BOOST_LIB_PATH) $(BDB_LIB_PATH) $(OPENSSL_LIB_PATH)) - DEFS=-DNOPCH -DUSE_SSL + LMODE = dynamic + LMODE2 = dynamic + ifdef STATIC + LMODE = static + ifeq (${STATIC}, all) + LMODE2 = static + endif + endif # for boost 1.37, add -mt to the boost libraries LIBS= \ - -Wl,-Bstatic \ - -l boost_system \ - -l boost_filesystem \ - -l boost_program_options \ - -l boost_thread \ - -l db_cxx \ + -Wl,-B$(LMODE) \ + -l boost_system$(BOOST_LIB_SUFFIX) \ + -l boost_filesystem$(BOOST_LIB_SUFFIX) \ + -l boost_program_options$(BOOST_LIB_SUFFIX) \ + -l boost_thread$(BOOST_LIB_SUFFIX) \ + -l db_cxx$(BDB_LIB_SUFFIX) \ -l ssl \ -l crypto - ifdef USE_UPNP + ifndef USE_UPNP + override USE_UPNP = - + endif + ifneq (${USE_UPNP}, -) LIBS += -l miniupnpc DEFS += -DUSE_UPNP=$(USE_UPNP) endif + ifneq (${USE_SSL}, 0) + DEFS += -DUSE_SSL + endif + LIBS+= \ - -Wl,-Bdynamic \ - -l gthread-2.0 \ + -Wl,-B$(LMODE2) \ -l z \ -l dl \ -l pthread - DEBUGFLAGS=-g -D__WXDEBUG__ - CXXFLAGS=-O2 -Wno-invalid-offsetof -Wformat $(DEBUGFLAGS) $(DEFS) + # Hardening + # Make some classes of vulnerabilities unexploitable in case one is discovered. + # + # This is a workaround for Ubuntu bug #691722, the default -fstack-protector causes + # -fstack-protector-all to be ignored unless -fno-stack-protector is used first. + # see: https://bugs.launchpad.net/ubuntu/+source/gcc-4.5/+bug/691722 + HARDENING=-fno-stack-protector + + # Stack Canaries + # Put numbers at the beginning of each stack frame and check that they are the same. + # If a stack buffer if overflowed, it writes over the canary number and then on return + # when that number is checked, it won't be the same and the program will exit with + # a "Stack smashing detected" error instead of being exploited. + HARDENING+=-fstack-protector-all -Wstack-protector + + # Make some important things such as the global offset table read only as soon as + # the dynamic linker is finished building it. This will prevent overwriting of addresses + # which would later be jumped to. + HARDENING+=-Wl,-z,relro -Wl,-z,now + + # Build position independent code to take advantage of Address Space Layout Randomization + # offered by some kernels. + # see doc/build-unix.txt for more information. + ifdef PIE + HARDENING+=-fPIE -pie + endif + + # -D_FORTIFY_SOURCE=2 does some checking for potentially exploitable code patterns in + # the source such overflowing a statically defined buffer. + HARDENING+=-D_FORTIFY_SOURCE=2 + # + + + DEBUGFLAGS=-g + CXXFLAGS=-O2 + xCXXFLAGS=-pthread -Wno-invalid-offsetof -Wformat $(DEBUGFLAGS) $(DEFS) $(HARDENING) $(CXXFLAGS) HEADERS = \ base58.h \ bignum.h \ + checkpoints.h \ crypter.h \ db.h \ headers.h \ @@@ -53,17 -99,16 +100,16 @@@ net.h \ noui.h \ protocol.h \ - rpc.h \ + bitcoinrpc.h \ script.h \ serialize.h \ strlcpy.h \ - ui.h \ - uibase.h \ uint256.h \ util.h \ wallet.h OBJS= \ + obj/checkpoints.o \ obj/crypter.o \ obj/db.o \ obj/init.o \ @@@ -72,52 -117,43 +118,52 @@@ obj/main.o \ obj/net.o \ obj/protocol.o \ - obj/rpc.o \ + obj/bitcoinrpc.o \ obj/script.o \ obj/util.o \ - obj/wallet.o \ - cryptopp/obj/sha.o \ - cryptopp/obj/cpu.o + obj/wallet.o - all: bitcoin + all: bitcoind + # auto-generated dependencies: + -include obj/nogui/*.P + -include obj/test/*.P - obj/%.o: %.cpp $(HEADERS) - $(CXX) -c $(CXXFLAGS) $(WXINCLUDEPATHS) -DGUI -o $@ $< - - cryptopp/obj/%.o: cryptopp/%.cpp - $(CXX) -c $(CXXFLAGS) -O3 -o $@ $< - - bitcoin: $(OBJS) obj/ui.o obj/uibase.o - $(CXX) $(CXXFLAGS) -o $@ $^ $(WXLIBS) $(LIBS) - - - obj/nogui/%.o: %.cpp $(HEADERS) - $(CXX) -c $(CXXFLAGS) -o $@ $< + obj/nogui/%.o: %.cpp + $(CXX) -c $(xCXXFLAGS) -MMD -o $@ $< + @cp $(@:%.o=%.d) $(@:%.o=%.P); \ + sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \ + -e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \ + rm -f $(@:%.o=%.d) bitcoind: $(OBJS:obj/%=obj/nogui/%) - $(CXX) $(CXXFLAGS) -o $@ $^ $(LIBS) + $(CXX) $(xCXXFLAGS) -o $@ $^ $(LDFLAGS) $(LIBS) - obj/test/test_bitcoin.o: $(wildcard test/*.cpp) $(HEADERS) - $(CXX) -c $(CFLAGS) -o $@ test/test_bitcoin.cpp + obj/test/%.o: test/%.cpp + $(CXX) -c $(xCXXFLAGS) -MMD -o $@ $< + @cp $(@:%.o=%.d) $(@:%.o=%.P); \ + sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \ + -e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \ + rm -f $(@:%.o=%.d) test_bitcoin: obj/test/test_bitcoin.o $(filter-out obj/nogui/init.o,$(OBJS:obj/%=obj/nogui/%)) - $(CXX) $(CXXFLAGS) -o $@ $(LIBPATHS) $^ -Wl,-Bstatic -lboost_unit_test_framework $(LIBS) + $(CXX) $(xCXXFLAGS) -o $@ $(LIBPATHS) $^ -Wl,-Bstatic -lboost_unit_test_framework $(LDFLAGS) $(LIBS) clean: - -rm -f bitcoin bitcoind test_bitcoin genesis - -rm -f bitcoind test_bitcoin ++ -rm -f bitcoind test_bitcoin genesis -rm -f obj/*.o -rm -f obj/nogui/*.o -rm -f obj/test/*.o - -rm -f cryptopp/obj/*.o - -rm -f headers.h.gch + -rm -f obj/*.P + -rm -f obj/nogui/*.P + -rm -f obj/test/*.P + -rm -f ppcoin/obj/*.o + +ppcoin/obj/genesis.o: ppcoin/genesis.cpp + $(CXX) -c $(CXXFLAGS) -o $@ $< + $(CXX) -c $(CXXFLAGS) -DPPCOIN_GENESIS -o obj/nogui/init.o init.cpp + +genesis: ppcoin/obj/genesis.o $(OBJS:obj/%=obj/nogui/%) + $(CXX) $(CXXFLAGS) -o $@ $^ $(LIBS) + -rm -f obj/nogui/init.o diff --combined src/net.cpp index 0656c65,e0ac2ab..b968d5a --- a/src/net.cpp +++ b/src/net.cpp @@@ -1,6 -1,5 +1,6 @@@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2011 The Bitcoin developers +// Copyright (c) 2011 The PPCoin developers // Distributed under the MIT/X11 software license, see the accompanying // file license.txt or http://www.opensource.org/licenses/mit-license.php. @@@ -11,7 -10,7 +11,7 @@@ #include "init.h" #include "strlcpy.h" - #ifdef __WXMSW__ + #ifdef WIN32 #include #endif @@@ -33,6 -32,7 +33,7 @@@ void ThreadOpenConnections2(void* parg) #ifdef USE_UPNP void ThreadMapPort2(void* parg); #endif + void ThreadDNSAddressSeed2(void* parg); bool OpenNetworkConnection(const CAddress& addrConnect); @@@ -103,7 -103,7 +104,7 @@@ bool ConnectSocket(const CAddress& addr bool fProxy = (fUseProxy && addrConnect.IsRoutable()); struct sockaddr_in sockaddr = (fProxy ? addrProxy.GetSockAddr() : addrConnect.GetSockAddr()); - #ifdef __WXMSW__ + #ifdef WIN32 u_long fNonblock = 1; if (ioctlsocket(hSocket, FIONBIO, &fNonblock) == SOCKET_ERROR) #else @@@ -142,7 -142,7 +143,7 @@@ return false; } socklen_t nRetSize = sizeof(nRet); - #ifdef __WXMSW__ + #ifdef WIN32 if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, (char*)(&nRet), &nRetSize) == SOCKET_ERROR) #else if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, &nRet, &nRetSize) == SOCKET_ERROR) @@@ -159,7 -159,7 +160,7 @@@ return false; } } - #ifdef __WXMSW__ + #ifdef WIN32 else if (WSAGetLastError() != WSAEISCONN) #else else @@@ -176,7 -176,7 +177,7 @@@ CNode::ConnectNode immediately turns the socket back to non-blocking but we'll turn it back to blocking just in case */ - #ifdef __WXMSW__ + #ifdef WIN32 fNonblock = 0; if (ioctlsocket(hSocket, FIONBIO, &fNonblock) == SOCKET_ERROR) #else @@@ -675,7 -675,7 +676,7 @@@ CNode* ConnectNode(CAddress addrConnect printf("connected %s\n", addrConnect.ToString().c_str()); // Set to nonblocking - #ifdef __WXMSW__ + #ifdef WIN32 u_long nOne = 1; if (ioctlsocket(hSocket, FIONBIO, &nOne) == SOCKET_ERROR) printf("ConnectSocket() : ioctlsocket nonblocking setting failed, error %d\n", WSAGetLastError()); @@@ -727,6 -727,52 +728,52 @@@ void CNode::Cleanup( } + std::map CNode::setBanned; + CCriticalSection CNode::cs_setBanned; + + void CNode::ClearBanned() + { + setBanned.clear(); + } + + bool CNode::IsBanned(unsigned int ip) + { + bool fResult = false; + CRITICAL_BLOCK(cs_setBanned) + { + std::map::iterator i = setBanned.find(ip); + if (i != setBanned.end()) + { + int64 t = (*i).second; + if (GetTime() < t) + fResult = true; + } + } + return fResult; + } + + bool CNode::Misbehaving(int howmuch) + { + if (addr.IsLocal()) + { + printf("Warning: local node %s misbehaving\n", addr.ToString().c_str()); + return false; + } + + nMisbehavior += howmuch; + if (nMisbehavior >= GetArg("-banscore", 100)) + { + int64 banTime = GetTime()+GetArg("-bantime", 60*60*24); // Default 24-hour ban + CRITICAL_BLOCK(cs_setBanned) + if (setBanned[addr.ip] < banTime) + setBanned[addr.ip] = banTime; + CloseSocketDisconnect(); + printf("Disconnected %s for misbehavior (score=%d)\n", addr.ToString().c_str(), nMisbehavior); + return true; + } + return false; + } + @@@ -897,6 -943,11 +944,11 @@@ void ThreadSocketHandler2(void* parg { closesocket(hSocket); } + else if (CNode::IsBanned(addr.ip)) + { + printf("connetion from %s dropped (banned)\n", addr.ToString().c_str()); + closesocket(hSocket); + } else { printf("accepted connection %s\n", addr.ToString().c_str()); @@@ -1081,11 -1132,17 +1133,17 @@@ void ThreadMapPort2(void* parg const char * rootdescurl = 0; const char * multicastif = 0; const char * minissdpdpath = 0; struct UPNPDev * devlist = 0; char lanaddr[64]; + #ifndef UPNPDISCOVER_SUCCESS + /* miniupnpc 1.5 */ + devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0); + #else + /* miniupnpc 1.6 */ + int error = 0; devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0, 0, &error); + #endif struct UPNPUrls urls; struct IGDdatas data; @@@ -1097,8 -1154,15 +1155,15 @@@ char intClient[16]; char intPort[6]; string strDesc = "Bitcoin " + FormatFullVersion(); + #ifndef UPNPDISCOVER_SUCCESS + /* miniupnpc 1.5 */ + r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, + port, port, lanaddr, strDesc.c_str(), "TCP", 0); + #else + /* miniupnpc 1.6 */ r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, port, port, lanaddr, strDesc.c_str(), "TCP", 0, "0"); + #endif if(r!=UPNPCOMMAND_SUCCESS) printf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n", @@@ -1159,11 -1223,32 +1224,31 @@@ void MapPort(bool /* unused fMapPort */ static const char *strDNSSeed[] = { - "bitseed.xf2.org", - "dnsseed.bluematt.me", + // "seeds.ppcoin.org" }; - void DNSAddressSeed() + void ThreadDNSAddressSeed(void* parg) { + IMPLEMENT_RANDOMIZE_STACK(ThreadDNSAddressSeed(parg)); + try + { + vnThreadsRunning[6]++; + ThreadDNSAddressSeed2(parg); + vnThreadsRunning[6]--; + } + catch (std::exception& e) { + vnThreadsRunning[6]--; + PrintException(&e, "ThreadDNSAddressSeed()"); + } catch (...) { + vnThreadsRunning[6]--; + throw; // support pthread_cancel() + } + printf("ThreadDNSAddressSeed exiting\n"); + } + + void ThreadDNSAddressSeed2(void* parg) + { + printf("ThreadDNSAddressSeed started\n"); int found = 0; if (!fTestNet) @@@ -1196,9 -1281,81 +1281,18 @@@ + + + + + + + + + unsigned int pnSeed[] = { - 0x6884ac63, 0x3ffecead, 0x2919b953, 0x0942fe50, 0x7a1d922e, 0xcdd6734a, 0x953a5bb6, 0x2c46922e, - 0xe2a5f143, 0xaa39103a, 0xa06afa5c, 0x135ffd59, 0xe8e82863, 0xf61ef029, 0xf75f042e, 0x2b363532, - 0x29b2df42, 0x16b1f64e, 0xd46e281b, 0x5280bf58, 0x60372229, 0x1be58e4f, 0xa8496f45, 0x1fb1a057, - 0x756b3844, 0x3bb79445, 0x0b375518, 0xcccb0102, 0xb682bf2e, 0x46431c02, 0x3a81073a, 0xa3771f1f, - 0x213a121f, 0x85dc2c1b, 0x56b4323b, 0xb34e8945, 0x3c40b33d, 0xfa276418, 0x1f818d29, 0xebe1e344, - 0xf6160a18, 0xf4fa384a, 0x34b09558, 0xb882b543, 0xe3ce2253, 0x6abf56d8, 0xe91b1155, 0x688ee6ad, - 0x2efc6058, 0x4792cd47, 0x0c32f757, 0x4c813a46, 0x8c93644a, 0x37507444, 0x813ad218, 0xdac06d4a, - 0xe4c63e4b, 0x21a1ea3c, 0x8d88556f, 0x30e9173a, 0x041f681b, 0xdc77ba50, 0xc0072753, 0xceddd44f, - 0x052d1743, 0xe3c77a4a, 0x13981c3a, 0x5685d918, 0x3c0e4e70, 0x3e56fb54, 0xb676ae0c, 0xac93c859, - 0x22279f43, 0x975a4542, 0xe527f071, 0xea162f2e, 0x3c65a32e, 0x5be5713b, 0x961ec418, 0xb202922e, - 0x5ef7be50, 0xce49f53e, 0x05803b47, 0x8463b055, 0x78576153, 0x3ec2ae3a, 0x4bbd7118, 0xafcee043, - 0x56a3e8ba, 0x6174de4d, 0x8d01ba4b, 0xc9af564e, 0xdbc9c547, 0xa627474d, 0xdada9244, 0xd3b3083a, - 0x523e071f, 0xd6b96f18, 0xbd527c46, 0xdf2bbb4d, 0xd37b4a4b, 0x3a6a2158, 0xc064b055, 0x18a8e055, - 0xec4dae3b, 0x0540416c, 0x475b4fbe, 0x064803b2, 0x48e9f062, 0x2898524b, 0xd315ff43, 0xf786d247, - 0xc7ea2f3e, 0xc087f043, 0xc163354b, 0x8250284d, 0xed300029, 0xbf36e05c, 0x8eb3ae4c, 0xe7aa623e, - 0x7ced0274, 0xdd362c1b, 0x362b995a, 0xca26b629, 0x3fc41618, 0xb97b364e, 0xa05b8729, 0x0f5e3c43, - 0xdf942618, 0x6aeb9b5b, 0xbf04762e, 0xfaaeb118, 0x87579958, 0x76520044, 0xc2660c5b, 0x628b201b, - 0xf193932e, 0x1c0ad045, 0xff908346, 0x8da9d4da, 0xed201c1f, 0xa47a2b1b, 0x330007d4, 0x8ba1ed47, - 0xb2f02d44, 0x7db62c1b, 0x781c454b, 0xc0300029, 0xb7062a45, 0x88b52e3a, 0x78dd6b63, 0x1cb9b718, - 0x5d358e47, 0x59912c3b, 0x79607544, 0x5197f759, 0xc023be48, 0xd1013743, 0x0f354057, 0x8e3aac3b, - 0x4114693e, 0x22316318, 0xe27dda50, 0x878eac3b, 0x4948a21f, 0x5db7f24c, 0x8ccb6157, 0x26a5de18, - 0x0a11bd43, 0x27bb1e41, 0x60a7a951, 0x3e16b35e, 0x07888b53, 0x5648a853, 0x0149fe50, 0xd070a34f, - 0x6454c96d, 0xd6e54758, 0xa96dc152, 0x65447861, 0xf6bdf95e, 0x10400202, 0x2c29d483, 0x18174732, - 0x1d840618, 0x12e61818, 0x089d3f3c, 0x917e931f, 0xd1b0c90e, 0x25bd3c42, 0xeb05775b, 0x7d550c59, - 0x6cfacb01, 0xe4224444, 0xa41dd943, 0x0f5aa643, 0x5e33731b, 0x81036d50, 0x6f46a0d1, 0x7731be43, - 0x14840e18, 0xf1e8d059, 0x661d2b1f, 0x40a3201b, 0x9407b843, 0xedf0254d, 0x7bd1a5bc, 0x073dbe51, - 0xe864a97b, 0x2efd947b, 0xb9ca0e45, 0x4e2113ad, 0xcc305731, 0xd39ca63c, 0x733df918, 0xda172b1f, - 0xaa03b34d, 0x7230fd4d, 0xf1ce6e3a, 0x2e9fab43, 0xa4010750, 0xa928bd18, 0x6809be42, 0xb19de348, - 0xff956270, 0x0d795f51, 0xd2dec247, 0x6df5774b, 0xbac11f79, 0xdfb05c75, 0x887683d8, 0xa1e83632, - 0x2c0f7671, 0x28bcb65d, 0xac2a7545, 0x3eebfc60, 0x304ad7c4, 0xa215a462, 0xc86f0f58, 0xcfb92ebe, - 0x5e23ed82, 0xf506184b, 0xec0f19b7, 0x060c59ad, 0x86ee3174, 0x85380774, 0xa199a562, 0x02b507ae, - 0x33eb2163, 0xf2112b1f, 0xb702ba50, 0x131b9618, 0x90ccd04a, 0x08f3273b, 0xecb61718, 0x64b8b44d, - 0x182bf4dc, 0xc7b68286, 0x6e318d5f, 0xfdb03654, 0xb3272e54, 0xe014ad4b, 0x274e4a31, 0x7806375c, - 0xbc34a748, 0x1b5ad94a, 0x6b54d10e, 0x73e2ae6e, 0x5529d483, 0x8455a76d, 0x99c13f47, 0x1d811741, - 0xa9782a78, 0x0b00464d, 0x7266ea50, 0x532dab46, 0x33e1413e, 0x780d0c18, 0x0fb0854e, 0x03370155, - 0x2693042e, 0xfa3d824a, 0x2bb1681b, 0x37ea2a18, 0x7fb8414b, 0x32e0713b, 0xacf38d3f, 0xa282716f, - 0xb1a09d7b, 0xa04b764b, 0x83c94d18, 0x05ee4c6d, 0x0e795f51, 0x46984352, 0xf80fc247, 0x3fccb946, - 0xd7ae244b, 0x0a8e0a4c, 0x57b141bc, 0x3647bed1, 0x1431b052, 0x803a8bbb, 0xfc69056b, 0xf5991862, - 0x14963b2e, 0xd35d5dda, 0xc6c73574, 0xc8f1405b, 0x0ca4224d, 0xecd36071, 0xa9461754, 0xe7a0ed72, - 0x559e8346, 0x1c9beec1, 0xc786ea4a, 0x9561b44d, 0x9788074d, 0x1a69934f, 0x23c5614c, 0x07c79d4b, - 0xc7ee52db, 0xc72df351, 0xcb135e44, 0xa0988346, 0xc211fc4c, 0x87dec34b, 0x1381074d, 0x04a65cb7, - 0x4409083a, 0x4a407a4c, 0x92b8d37d, 0xacf50b4d, 0xa58aa5bc, 0x448f801f, 0x9c83762e, 0x6fd5734a, - 0xfe2d454b, 0x84144c55, 0x05190e4c, 0xb2151448, 0x63867a3e, 0x16099018, 0x9c010d3c, 0x962d8f3d, - 0xd51ee453, 0x9d86801f, 0x68e87b47, 0x6bf7bb73, 0x5fc7910e, 0x10d90118, 0x3db04442, 0x729d3e4b, - 0xc397d842, 0x57bb15ad, 0x72f31f4e, 0xc9380043, 0x2bb24e18, 0xd9b8ab50, 0xb786801f, 0xf4dc4847, - 0x85f4bb51, 0x4435995b, 0x5ba07e40, 0x2c57392e, 0x3628124b, 0x9839b64b, 0x6fe8b24d, 0xaddce847, - 0x75260e45, 0x0c572a43, 0xfea21902, 0xb9f9742e, 0x5a70d443, 0x8fc5910e, 0x868d4744, 0x56245e02, - 0xd7eb5f02, 0x35c12c1b, 0x4373034b, 0x8786554c, 0xa6facf18, 0x4b11a31f, 0x3570664e, 0x5a64bc42, - 0x0b03983f, 0x8f457e4c, 0x0fd874c3, 0xb6cf31b2, 0x2bbc2d4e, 0x146ca5b2, 0x9d00b150, 0x048a4153, - 0xca4dcd43, 0xc1607cca, 0x8234cf57, 0x9c7daead, 0x3dc07658, 0xea5c6e4c, 0xf1a0084e, 0x16d2ee53, - 0x1b849418, 0xfe913a47, 0x1e988f62, 0x208b644c, 0xc55ee980, 0xbdbce747, 0xf59a384e, 0x0f56091b, - 0x7417b745, 0x0c37344e, 0x2c62ab47, 0xf8533a4d, 0x8030084d, 0x76b93c4b, 0xda6ea0ad, 0x3c54f618, - 0x63b0de1f, 0x7370d858, 0x1a70bb4c, 0xdda63b2e, 0x60b2ba50, 0x1ba7d048, 0xbe1b2c1b, 0xabea5747, - 0x29ad2e4d, 0xe8cd7642, 0x66c80e18, 0x138bf34a, 0xc6145e44, 0x2586794c, 0x07bc5478, 0x0da0b14d, - 0x8f95354e, 0x9eb11c62, 0xa1545e46, 0x2e7a2602, 0x408c9c3d, 0x59065d55, 0xf51d1a4c, 0x3bbc6a4e, - 0xc71b2a2e, 0xcdaaa545, 0x17d659d0, 0x5202e7ad, 0xf1b68445, 0x93375961, 0xbd88a043, 0x066ad655, - 0x890f6318, 0x7b7dca47, 0x99bdd662, 0x3bb4fc53, 0x1231efdc, 0xc0a99444, 0x96bbea47, 0x61ed8748, - 0x27dfa73b, 0x8d4d1754, 0x3460042e, 0x551f0c4c, 0x8d0e0718, 0x162ddc53, 0x53231718, 0x1ecd65d0, - 0x944d28bc, 0x3b79d058, 0xaff97fbc, 0x4860006c, 0xc101c90e, 0xace41743, 0xa5975d4c, 0x5cc2703e, - 0xb55a4450, 0x02d18840, 0xee2765ae, 0xd6012fd5, 0x24c94d7d, 0x8c6eec47, 0x7520ba5d, 0x9e15e460, - 0x8510b04c, 0x75ec3847, 0x1dfa6661, 0xe172b3ad, 0x5744c90e, 0x52a0a152, 0x8d6fad18, 0x67b74b6d, - 0x93a089b2, 0x0f3ac5d5, 0xe5de1855, 0x43d25747, 0x4bad804a, 0x55b408d8, 0x60a36441, 0xf553e860, - 0xdb2fa2c8, 0x03152b32, 0xdd27a7d5, 0x3116a8b8, 0x0a1d708c, 0xeee2f13c, 0x6acf436f, 0xce6eb4ca, - 0x101cd3d9, 0x1c48a6b8, 0xe57d6f44, 0x93dcf562, + 0xfc01a8c0 }; @@@ -1323,6 -1480,8 +1417,8 @@@ void ThreadOpenConnections2(void* parg BOOST_FOREACH(CNode* pnode, vNodes) setConnected.insert(pnode->addr.ip & 0x0000ffff); + int64 nANow = GetAdjustedTime(); + CRITICAL_BLOCK(cs_mapAddresses) { BOOST_FOREACH(const PAIRTYPE(vector, CAddress)& item, mapAddresses) @@@ -1330,8 -1489,8 +1426,8 @@@ const CAddress& addr = item.second; if (!addr.IsIPv4() || !addr.IsValid() || setConnected.count(addr.ip & 0x0000ffff)) continue; - int64 nSinceLastSeen = GetAdjustedTime() - addr.nTime; - int64 nSinceLastTry = GetAdjustedTime() - addr.nLastTry; + int64 nSinceLastSeen = nANow - addr.nTime; + int64 nSinceLastTry = nANow - addr.nLastTry; // Randomize the order in a deterministic way, putting the standard port first int64 nRandomizer = (uint64)(nStart * 4951 + addr.nLastTry * 9567851 + addr.ip * 7789) % (2 * 60 * 60); @@@ -1390,7 -1549,8 +1486,8 @@@ bool OpenNetworkConnection(const CAddre // if (fShutdown) return false; - if (addrConnect.ip == addrLocalHost.ip || !addrConnect.IsIPv4() || FindNode(addrConnect.ip)) + if (addrConnect.ip == addrLocalHost.ip || !addrConnect.IsIPv4() || + FindNode(addrConnect.ip) || CNode::IsBanned(addrConnect.ip)) return false; vnThreadsRunning[1]--; @@@ -1494,7 -1654,7 +1591,7 @@@ bool BindListenPort(string& strError int nOne = 1; addrLocalHost.port = htons(GetListenPort()); - #ifdef __WXMSW__ + #ifdef WIN32 // Initialize Windows Sockets WSADATA wsadata; int ret = WSAStartup(MAKEWORD(2,2), &wsadata); @@@ -1520,13 -1680,13 +1617,13 @@@ setsockopt(hListenSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&nOne, sizeof(int)); #endif - #ifndef __WXMSW__ + #ifndef WIN32 // Allow binding if the port is still in TIME_WAIT state after // the program was closed and restarted. Not an issue on windows. setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (void*)&nOne, sizeof(int)); #endif - #ifdef __WXMSW__ + #ifdef WIN32 // Set to nonblocking, incoming connections will also inherit this if (ioctlsocket(hListenSocket, FIONBIO, (u_long*)&nOne) == SOCKET_ERROR) #else @@@ -1573,7 -1733,7 +1670,7 @@@ void StartNode(void* parg if (pnodeLocalHost == NULL) pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress("127.0.0.1", 0, false, nLocalServices)); - #ifdef __WXMSW__ + #ifdef WIN32 // Get local host ip char pszHostName[1000] = ""; if (gethostname(pszHostName, sizeof(pszHostName)) != SOCKET_ERROR) @@@ -1640,6 -1800,12 +1737,12 @@@ // Start threads // + if (GetBoolArg("-nodnsseed")) + printf("DNS seeding disabled\n"); + else + if (!CreateThread(ThreadDNSAddressSeed, NULL)) + printf("Error: CreateThread(ThreadDNSAddressSeed) failed\n"); + // Map ports with UPnP if (fHaveUPnP) MapPort(fUseUPnP); @@@ -1649,7 -1815,8 +1752,8 @@@ printf("Error: CreateThread(ThreadIRCSeed) failed\n"); // Send and receive from sockets, accept connections - CreateThread(ThreadSocketHandler, NULL); + if (!CreateThread(ThreadSocketHandler, NULL)) + printf("Error: CreateThread(ThreadSocketHandler) failed\n"); // Initiate outbound connections if (!CreateThread(ThreadOpenConnections, NULL)) @@@ -1685,6 -1852,7 +1789,7 @@@ bool StopNode( if (vnThreadsRunning[3] > 0) printf("ThreadBitcoinMiner still running\n"); if (vnThreadsRunning[4] > 0) printf("ThreadRPCServer still running\n"); if (fHaveUPnP && vnThreadsRunning[5] > 0) printf("ThreadMapPort still running\n"); + if (vnThreadsRunning[6] > 0) printf("ThreadDNSAddressSeed still running\n"); while (vnThreadsRunning[2] > 0 || vnThreadsRunning[4] > 0) Sleep(20); Sleep(50); @@@ -1708,7 -1876,7 +1813,7 @@@ public if (closesocket(hListenSocket) == SOCKET_ERROR) printf("closesocket(hListenSocket) failed with error %d\n", WSAGetLastError()); - #ifdef __WXMSW__ + #ifdef WIN32 // Shutdown Windows Sockets WSACleanup(); #endif diff --combined src/util.cpp index 6bd52ed,236c7f7..7fb3cd6 --- a/src/util.cpp +++ b/src/util.cpp @@@ -1,6 -1,5 +1,6 @@@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2011 The Bitcoin developers +// Copyright (c) 2011 The PPCoin 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" @@@ -65,7 -64,7 +65,7 @@@ public ppmutexOpenSSL[i] = new boost::interprocess::interprocess_mutex(); CRYPTO_set_locking_callback(locking_callback); - #ifdef __WXMSW__ + #ifdef WIN32 // Seed random number generator with screen scrape and other hardware sources RAND_screen(); #endif @@@ -109,7 -108,7 +109,7 @@@ void RandAddSeedPerfmon( return; nLastPerfmon = GetTime(); - #ifdef __WXMSW__ + #ifdef WIN32 // Don't need this on Linux, OpenSSL automatically uses /dev/urandom // Seed with the entire set of perfmon data unsigned char pdata[250000]; @@@ -199,7 -198,7 +199,7 @@@ inline int OutputDebugStringF(const cha } } - #ifdef __WXMSW__ + #ifdef WIN32 if (fPrintToDebugger) { static CCriticalSection cs_OutputDebugStringF; @@@ -265,8 -264,7 +265,7 @@@ int my_snprintf(char* buffer, size_t li return ret; } - - string strprintf(const char* format, ...) + string strprintf(const std::string &format, ...) { char buffer[50000]; char* p = buffer; @@@ -276,7 -274,7 +275,7 @@@ { va_list arg_ptr; va_start(arg_ptr, format); - ret = _vsnprintf(p, limit, format, arg_ptr); + ret = _vsnprintf(p, limit, format.c_str(), arg_ptr); va_end(arg_ptr); if (ret >= 0 && ret < limit) break; @@@ -293,14 -291,13 +292,13 @@@ return str; } - - bool error(const char* format, ...) + bool error(const std::string &format, ...) { char buffer[50000]; int limit = sizeof(buffer); va_list arg_ptr; va_start(arg_ptr, format); - int ret = _vsnprintf(buffer, limit, format, arg_ptr); + int ret = _vsnprintf(buffer, limit, format.c_str(), arg_ptr); va_end(arg_ptr); if (ret < 0 || ret >= limit) { @@@ -339,7 -336,7 +337,7 @@@ string FormatMoney(int64 n, bool fPlus int64 n_abs = (n > 0 ? n : -n); int64 quotient = n_abs/COIN; int64 remainder = n_abs%COIN; - string str = strprintf("%"PRI64d".%08"PRI64d, quotient, remainder); + string str = strprintf("%"PRI64d".%04"PRI64d, quotient, remainder); // Right-trim excess 0's before the decimal point: int nTrim = 0; @@@ -390,7 -387,7 +388,7 @@@ bool ParseMoney(const char* pszIn, int6 for (; *p; p++) if (!isspace(*p)) return false; - if (strWhole.size() > 14) + if (strWhole.size() > 10) // guard against 63 bit overflow return false; if (nUnits < 0 || nUnits > COIN) return false; @@@ -446,7 -443,6 +444,6 @@@ vector ParseHex(const st return ParseHex(str.c_str()); } - void ParseParameters(int argc, char* argv[]) { mapArgs.clear(); @@@ -461,7 -457,7 +458,7 @@@ pszValue = strchr(psz, '='); *pszValue++ = '\0'; } - #ifdef __WXMSW__ + #ifdef WIN32 _strlwr(psz); if (psz[0] == '/') psz[0] = '-'; @@@ -473,39 -469,144 +470,144 @@@ } } + string EncodeBase64(const unsigned char* pch, size_t len) + { + static const char *pbase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + string strRet=""; + strRet.reserve((len+2)/3*4); + + int mode=0, left=0; + const unsigned char *pchEnd = pch+len; - const char* wxGetTranslation(const char* pszEnglish) + while (pch> 2]; + left = (enc & 3) << 4; + mode = 1; + break; + + case 1: // we have two bits + strRet += pbase64[left | (enc >> 4)]; + left = (enc & 15) << 2; + mode = 2; + break; + + case 2: // we have four bits + strRet += pbase64[left | (enc >> 6)]; + strRet += pbase64[enc & 63]; + mode = 0; + break; + } + } + + if (mode) + { + strRet += pbase64[left]; + strRet += '='; + if (mode == 1) + strRet += '='; + } + + return strRet; + } + + string EncodeBase64(const string& str) { - #ifdef GUI - // Wrapper of wxGetTranslation returning the same const char* type as was passed in - static CCriticalSection cs; - CRITICAL_BLOCK(cs) + return EncodeBase64((const unsigned char*)str.c_str(), str.size()); + } + + vector DecodeBase64(const char* p, bool* pfInvalid) + { + static const int decode64_table[256] = + { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, + -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 + }; + + if (pfInvalid) + *pfInvalid = false; + + vector vchRet; + vchRet.reserve(strlen(p)*3/4); + + int mode = 0; + int left = 0; + + while (1) { - // Look in cache - static map mapCache; - map::iterator mi = mapCache.find(pszEnglish); - if (mi != mapCache.end()) - return (*mi).second; - - // wxWidgets translation - wxString strTranslated = wxGetTranslation(wxString(pszEnglish, wxConvUTF8)); - - // We don't cache unknown strings because caller might be passing in a - // dynamic string and we would keep allocating memory for each variation. - if (strcmp(pszEnglish, strTranslated.utf8_str()) == 0) - return pszEnglish; - - // Add to cache, memory doesn't need to be freed. We only cache because - // we must pass back a pointer to permanently allocated memory. - char* pszCached = new char[strlen(strTranslated.utf8_str())+1]; - strcpy(pszCached, strTranslated.utf8_str()); - mapCache[pszEnglish] = pszCached; - return pszCached; + int dec = decode64_table[*p]; + if (dec == -1) break; + p++; + switch (mode) + { + case 0: // we have no bits and get 6 + left = dec; + mode = 1; + break; + + case 1: // we have 6 bits and keep 4 + vchRet.push_back((left<<2) | (dec>>4)); + left = dec & 15; + mode = 2; + break; + + case 2: // we have 4 bits and get 6, we keep 2 + vchRet.push_back((left<<4) | (dec>>2)); + left = dec & 3; + mode = 3; + break; + + case 3: // we have 2 bits and get 6 + vchRet.push_back((left<<6) | dec); + mode = 0; + break; + } } - return NULL; - #else - return pszEnglish; - #endif + + if (pfInvalid) + switch (mode) + { + case 0: // 4n base64 characters processed: ok + break; + + case 1: // 4n+1 base64 character processed: impossible + *pfInvalid = true; + break; + + case 2: // 4n+2 base64 characters processed: require '==' + if (left || p[0] != '=' || p[1] != '=' || decode64_table[p[2]] != -1) + *pfInvalid = true; + break; + + case 3: // 4n+3 base64 characters processed: require '=' + if (left || p[0] != '=' || decode64_table[p[1]] != -1) + *pfInvalid = true; + break; + } + + return vchRet; + } + + string DecodeBase64(const string& str) + { + vector vchRet = DecodeBase64(str.c_str()); + return string((const char*)&vchRet[0], vchRet.size()); } @@@ -547,7 -648,7 +649,7 @@@ bool WildcardMatch(const string& str, c void FormatException(char* pszMessage, std::exception* pex, const char* pszThread) { - #ifdef __WXMSW__ + #ifdef WIN32 char pszModule[MAX_PATH]; pszModule[0] = '\0'; GetModuleFileNameA(NULL, pszModule, sizeof(pszModule)); @@@ -576,10 -677,6 +678,6 @@@ void PrintException(std::exception* pex printf("\n\n************************\n%s\n", pszMessage); fprintf(stderr, "\n\n************************\n%s\n", pszMessage); strMiscWarning = pszMessage; - #ifdef GUI - if (wxTheApp && !fDaemon) - MyMessageBox(pszMessage, "Bitcoin", wxOK | wxICON_ERROR); - #endif throw; } @@@ -601,10 -698,6 +699,6 @@@ void PrintExceptionContinue(std::except printf("\n\n************************\n%s\n", pszMessage); fprintf(stderr, "\n\n************************\n%s\n", pszMessage); strMiscWarning = pszMessage; - #ifdef GUI - if (wxTheApp && !fDaemon) - boost::thread(boost::bind(ThreadOneMessageBox, string(pszMessage))); - #endif } @@@ -614,7 -707,7 +708,7 @@@ - #ifdef __WXMSW__ + #ifdef WIN32 typedef WINSHELLAPI BOOL (WINAPI *PSHGETSPECIALFOLDERPATHA)(HWND hwndOwner, LPSTR lpszPath, int nFolder, BOOL fCreate); string MyGetSpecialFolderPath(int nFolder, bool fCreate) @@@ -652,12 -745,12 +746,12 @@@ string GetDefaultDataDir() { - // Windows: C:\Documents and Settings\username\Application Data\Bitcoin - // Mac: ~/Library/Application Support/Bitcoin - // Unix: ~/.bitcoin + // Windows: C:\Documents and Settings\username\Application Data\PPCoin + // Mac: ~/Library/Application Support/PPCoin + // Unix: ~/.ppcoin - #ifdef __WXMSW__ + #ifdef WIN32 // Windows - return MyGetSpecialFolderPath(CSIDL_APPDATA, true) + "\\Bitcoin"; + return MyGetSpecialFolderPath(CSIDL_APPDATA, true) + "\\PPCoin"; #else char* pszHome = getenv("HOME"); if (pszHome == NULL || strlen(pszHome) == 0) @@@ -665,14 -758,14 +759,14 @@@ string strHome = pszHome; if (strHome[strHome.size()-1] != '/') strHome += '/'; - #ifdef __WXMAC_OSX__ + #ifdef MAC_OSX // Mac strHome += "Library/Application Support/"; filesystem::create_directory(strHome.c_str()); - return strHome + "Bitcoin"; + return strHome + "PPCoin"; #else // Unix - return strHome + ".bitcoin"; + return strHome + ".ppcoin"; #endif #endif } @@@ -722,7 -815,7 +816,7 @@@ string GetDataDir( string GetConfigFile() { namespace fs = boost::filesystem; - fs::path pathConfig(GetArg("-conf", "bitcoin.conf")); + fs::path pathConfig(GetArg("-conf", "ppcoin.conf")); if (!pathConfig.is_complete()) pathConfig = fs::path(GetDataDir()) / pathConfig; return pathConfig.string(); @@@ -754,7 -847,7 +848,7 @@@ void ReadConfigFile(map string GetPidFile() { namespace fs = boost::filesystem; - fs::path pathConfig(GetArg("-pid", "bitcoind.pid")); + fs::path pathConfig(GetArg("-pid", "ppcoind.pid")); if (!pathConfig.is_complete()) pathConfig = fs::path(GetDataDir()) / pathConfig; return pathConfig.string(); @@@ -816,11 -909,20 +910,20 @@@ void ShrinkDebugFile( // - Median of other nodes's clocks // - The user (asking the user to fix the system clock if the first two disagree) // + static int64 nMockTime = 0; // For unit testing + int64 GetTime() { + if (nMockTime) return nMockTime; + return time(NULL); } + void SetMockTime(int64 nMockTimeIn) + { + nMockTime = nMockTimeIn; + } + static int64 nTimeOffset = 0; int64 GetAdjustedTime() diff --combined src/wallet.cpp index 652d9fa,28babdb..d605b2c --- a/src/wallet.cpp +++ b/src/wallet.cpp @@@ -1,12 -1,10 +1,11 @@@ -// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2011 Satoshi Nakamoto // Copyright (c) 2011 The Bitcoin developers +// Copyright (c) 2011 The PPCoin 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 "cryptopp/sha.h" #include "crypter.h" using namespace std; @@@ -41,9 -39,10 +40,10 @@@ bool CWallet::AddCryptedKey(const vecto else return CWalletDB(strWalletFile).WriteCryptedKey(vchPubKey, vchCryptedSecret); } + return false; } - bool CWallet::Unlock(const string& strWalletPassphrase) + bool CWallet::Unlock(const SecureString& strWalletPassphrase) { if (!IsLocked()) return false; @@@ -64,7 -63,7 +64,7 @@@ return false; } - bool CWallet::ChangeWalletPassphrase(const string& strOldWalletPassphrase, const string& strNewWalletPassphrase) + bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase) { bool fWasLocked = IsLocked(); @@@ -123,7 -122,7 +123,7 @@@ public ) }; - bool CWallet::EncryptWallet(const string& strWalletPassphrase) + bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase) { if (IsCrypted()) return false; @@@ -188,6 -187,13 +188,13 @@@ } Lock(); + Unlock(strWalletPassphrase); + NewKeyPool(); + Lock(); + + // Need to completely rewrite the wallet file; if we don't, bdb might keep + // bits of the unencrypted private key in slack space in the database file. + CDB::Rewrite(strWalletFile); } return true; @@@ -261,7 -267,7 +268,7 @@@ bool CWallet::AddToWallet(const CWallet if (fInsertedNew || fUpdated) if (!wtx.WriteToDisk()) return false; - + #ifndef QT_GUI // If default receiving address gets used, replace it with a new one CScript scriptDefaultKey; scriptDefaultKey.SetBitcoinAddress(vchDefaultKey); @@@ -277,7 -283,7 +284,7 @@@ } } } - + #endif // Notify UI vWalletUpdated.push_back(hash); @@@ -290,6 -296,9 +297,9 @@@ return true; } + // Add a transaction to the wallet, or update it. + // pblock is optional, but should be provided if the transaction is known to be in a block. + // If fUpdate is true, existing transactions will be updated. bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate) { uint256 hash = tx.GetHash(); @@@ -552,6 -561,9 +562,9 @@@ bool CWalletTx::WriteToDisk( return CWalletDB(pwallet->strWalletFile).WriteTx(GetHash(), *this); } + // Scan the block chain (starting in pindexStart) for transactions + // from or to us. If fUpdate is true, found transactions that already + // exist in the wallet will be updated. int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) { int ret = 0; @@@ -729,6 -741,21 +742,21 @@@ int64 CWallet::GetBalance() cons return nTotal; } + int64 CWallet::GetUnconfirmedBalance() const + { + int64 nTotal = 0; + CRITICAL_BLOCK(cs_wallet) + { + for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + { + const CWalletTx* pcoin = &(*it).second; + if (pcoin->IsFinal() && pcoin->IsConfirmed()) + continue; + nTotal += pcoin->GetAvailableCredit(); + } + } + return nTotal; + } bool CWallet::SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, set >& setCoinsRet, int64& nValueRet) const { @@@ -983,8 -1010,9 +1011,8 @@@ bool CWallet::CreateTransaction(const v dPriority /= nBytes; // Check that enough fee is included - int64 nPayFee = nTransactionFee * (1 + (int64)nBytes / 1000); - bool fAllowFree = CTransaction::AllowFree(dPriority); - int64 nMinFee = wtxNew.GetMinFee(1, fAllowFree); + int64 nPayFee = nTransactionFee; // ppcoin: simplify tx fee + int64 nMinFee = wtxNew.GetMinFee(1, false); if (nFeeRet < max(nPayFee, nMinFee)) { nFeeRet = max(nPayFee, nMinFee); @@@ -1121,6 -1149,18 +1149,18 @@@ int CWallet::LoadWallet(bool& fFirstRun return false; fFirstRunRet = false; int nLoadWalletRet = CWalletDB(strWalletFile,"cr+").LoadWallet(this); + if (nLoadWalletRet == DB_NEED_REWRITE) + { + if (CDB::Rewrite(strWalletFile, "\x04pool")) + { + setKeyPool.clear(); + // Note: can't top-up keypool here, because wallet is locked. + // User will be prompted to unlock wallet the next operation + // the requires a new key. + } + nLoadWalletRet = DB_NEED_REWRITE; + } + if (nLoadWalletRet != DB_LOAD_OK) return nLoadWalletRet; fFirstRunRet = vchDefaultKey.empty(); @@@ -1206,6 -1246,34 +1246,34 @@@ bool GetWalletFile(CWallet* pwallet, st return true; } + // + // Mark old keypool keys as used, + // and generate all new keys + // + bool CWallet::NewKeyPool() + { + CRITICAL_BLOCK(cs_wallet) + { + CWalletDB walletdb(strWalletFile); + BOOST_FOREACH(int64 nIndex, setKeyPool) + walletdb.ErasePool(nIndex); + setKeyPool.clear(); + + if (IsLocked()) + return false; + + int64 nKeys = max(GetArg("-keypool", 100), (int64)0); + for (int i = 0; i < nKeys; i++) + { + int64 nIndex = i+1; + walletdb.WritePool(nIndex, CKeyPool(GenerateNewKey())); + setKeyPool.insert(nIndex); + } + printf("CWallet::NewKeyPool wrote %"PRI64d" new keys\n", nKeys); + } + return true; + } + bool CWallet::TopUpKeyPool() { CRITICAL_BLOCK(cs_wallet)