X-Git-Url: https://git.novaco.in/?a=blobdiff_plain;f=src%2Fbitcoinrpc.cpp;h=a4a1fd4d6b35902f8aed623b4465c9976a07d9e5;hb=91d7e847e051c9aa8be87a72d2763872b6b4f385;hp=3ceaebd77058ee5b943a6cfe32bb4b6b259c479b;hpb=6ccff2cbdebca38e4913b679784a4865edfbb12a;p=novacoin.git diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index 3ceaebd..a4a1fd4 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2011 The Bitcoin developers +// Copyright (c) 2009-2012 The Bitcoin developers // Distributed under the MIT/X11 software license, see the accompanying // file license.txt or http://www.opensource.org/licenses/mit-license.php. @@ -160,10 +160,13 @@ Value stop(const Array& params, bool fHelp) 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 } @@ -311,7 +314,7 @@ Value getinfo(const Array& params, bool fHelp) obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize())); obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee))); if (pwalletMain->IsCrypted()) - obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime)); + obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime / 1000)); obj.push_back(Pair("errors", GetWarnings("statusbar"))); return obj; } @@ -1257,6 +1260,70 @@ Value listaccounts(const Array& params, bool fHelp) 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) @@ -1336,37 +1403,43 @@ void ThreadTopUpKeyPool(void* parg) void ThreadCleanWalletPassphrase(void* parg) { - int64 nMyWakeTime = GetTime() + *((int*)parg); + int64 nMyWakeTime = GetTimeMillis() + *((int64*)parg) * 1000; + + ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime); if (nWalletUnlockTime == 0) { - CRITICAL_BLOCK(cs_nWalletUnlockTime) + nWalletUnlockTime = nMyWakeTime; + + do { - nWalletUnlockTime = nMyWakeTime; - } + if (nWalletUnlockTime==0) + break; + int64 nToSleep = nWalletUnlockTime - GetTimeMillis(); + if (nToSleep <= 0) + break; + + LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime); + Sleep(nToSleep); + ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime); - while (GetTime() < nWalletUnlockTime) - Sleep(GetTime() - nWalletUnlockTime); + } while(1); - CRITICAL_BLOCK(cs_nWalletUnlockTime) + if (nWalletUnlockTime) { nWalletUnlockTime = 0; + pwalletMain->Lock(); } } else { - CRITICAL_BLOCK(cs_nWalletUnlockTime) - { - if (nWalletUnlockTime < nMyWakeTime) - nWalletUnlockTime = nMyWakeTime; - } - free(parg); - return; + if (nWalletUnlockTime < nMyWakeTime) + nWalletUnlockTime = nMyWakeTime; } - pwalletMain->Lock(); + LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime); - delete (int*)parg; + delete (int64*)parg; } Value walletpassphrase(const Array& params, bool fHelp) @@ -1384,21 +1457,16 @@ Value walletpassphrase(const Array& params, bool fHelp) 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( @@ -1406,7 +1474,7 @@ Value walletpassphrase(const Array& params, bool fHelp) "Stores the wallet decryption key in memory for seconds."); CreateThread(ThreadTopUpKeyPool, NULL); - int* pnSleepTime = new int(params[1].get_int()); + int64* pnSleepTime = new int64(params[1].get_int64()); CreateThread(ThreadCleanWalletPassphrase, pnSleepTime); return Value::null; @@ -1424,15 +1492,15 @@ Value walletpassphrasechange(const Array& params, bool fHelp) 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( @@ -1440,17 +1508,7 @@ Value walletpassphrasechange(const Array& params, bool fHelp) "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; } @@ -1469,9 +1527,9 @@ Value walletlock(const Array& params, bool fHelp) if (!pwalletMain->IsCrypted()) throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called."); - pwalletMain->Lock(); CRITICAL_BLOCK(cs_nWalletUnlockTime) { + pwalletMain->Lock(); nWalletUnlockTime = 0; } @@ -1490,10 +1548,16 @@ Value encryptwallet(const Array& params, bool fHelp) 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( @@ -1501,15 +1565,13 @@ Value encryptwallet(const Array& params, bool fHelp) "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"; } @@ -1592,7 +1654,7 @@ Value getwork(const Array& params, bool fHelp) } // Update nTime - pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); + pblock->UpdateTime(pindexPrev); pblock->nNonce = 0; // Update nExtraNonce @@ -1644,6 +1706,93 @@ Value getwork(const Array& params, bool fHelp) } +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->UpdateTime(pindexPrev); + 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); + } +} + + @@ -1697,6 +1846,8 @@ pair pCallTable[] = 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])); @@ -1722,6 +1873,7 @@ string pAllowInSafeMode[] = "walletlock", "validateaddress", "getwork", + "getmemorypool", }; set setAllowInSafeMode(pAllowInSafeMode, pAllowInSafeMode + sizeof(pAllowInSafeMode)/sizeof(pAllowInSafeMode[0])); @@ -1743,6 +1895,7 @@ string HTTPPost(const string& strMsg, const map& mapRequestHeader << "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"; @@ -1783,12 +1936,13 @@ static string HTTPReply(int nStatus, const string& strMsg) "\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" @@ -1799,7 +1953,7 @@ static string HTTPReply(int nStatus, const string& strMsg) "\r\n" "%s", nStatus, - strStatus.c_str(), + cStatus, rfc1123Time().c_str(), strMsg.size(), FormatFullVersion().c_str(), @@ -2013,17 +2167,27 @@ void ThreadRPCServer2(void* parg) if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "") { + unsigned char rand_pwd[32]; + RAND_bytes(rand_pwd, 32); string strWhatAmI = "To use bitcoind"; if (mapArgs.count("-server")) strWhatAmI = strprintf(_("To use the %s option"), "\"-server\""); 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" + ThreadSafeMessageBox(strprintf( + _("Error: %s, you must set a rpcpassword in the configuration file:\n %s\n" + "It is recommended you use the following random password:\n" + "rpcuser=bitcoinrpc\n" + "rpcpassword=%s\n" + "(you do not need to remember this password)\n" "If the file does not exist, create it with owner-readable-only file permissions.\n"), strWhatAmI.c_str(), - GetConfigFile().c_str()); + GetConfigFile().c_str(), + EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()), + _("Error"), wxOK | wxMODAL); +#ifndef QT_GUI CreateThread(Shutdown, NULL); +#endif return; } @@ -2109,12 +2273,14 @@ void ThreadRPCServer2(void* parg) } if (!HTTPAuthorized(mapHeaders)) { - // Deter brute-forcing short passwords - if (mapArgs["-rpcpassword"].size() < 15) - Sleep(50); + printf("ThreadRPCServer incorrect password attempt from %s\n",peer.address().to_string().c_str()); + /* Deter brute-forcing short passwords. + If this results in a DOS the user really + shouldn't have their RPC port exposed.*/ + if (mapArgs["-rpcpassword"].size() < 20) + Sleep(250); stream << HTTPReply(401, "") << std::flush; - printf("ThreadRPCServer incorrect password attempt\n"); continue; } @@ -2137,7 +2303,7 @@ void ThreadRPCServer2(void* parg) 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 @@ -2318,6 +2484,7 @@ int CommandLineRPC(int argc, char *argv[]) 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();