From: Gavin Andresen Date: Thu, 12 Apr 2012 19:20:51 +0000 (-0700) Subject: Merge pull request #1041 from gavinandresen/listtransactionsfix X-Git-Tag: v0.4.0-unstable~129^2~82 X-Git-Url: https://git.novaco.in/?p=novacoin.git;a=commitdiff_plain;h=b7dc02381f0afe3ee3a542d06a44a64b2cde3812;hp=-c Merge pull request #1041 from gavinandresen/listtransactionsfix Bug fix listtransactions from/count handling. --- b7dc02381f0afe3ee3a542d06a44a64b2cde3812 diff --combined src/bitcoinrpc.cpp index 2525c2d,115164d..7c99114 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@@ -14,10 -14,12 +14,10 @@@ #include #include #include -#ifdef USE_SSL #include -#include #include typedef boost::asio::ssl::stream SSLStream; -#endif + #include "json/json_spirit_reader_template.h" #include "json/json_spirit_writer_template.h" #include "json/json_spirit_utils.h" @@@ -984,6 -986,8 +984,6 @@@ Value addmultisigaddress(const Array& p "If [account] is specified, assign address to [account]."; throw runtime_error(msg); } - if (!fTestNet) - throw runtime_error("addmultisigaddress available only when running -testnet\n"); int nRequired = params[0].get_int(); const Array& keys = params[1].get_array(); @@@ -1281,14 -1285,21 +1281,21 @@@ Value listtransactions(const Array& par if (params.size() > 2) nFrom = params[2].get_int(); + if (nCount < 0) + throw JSONRPCError(-8, "Negative count"); + if (nFrom < 0) + throw JSONRPCError(-8, "Negative from"); + Array ret; CWalletDB walletdb(pwalletMain->strWalletFile); - // Firs: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap: + // First: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap. typedef pair TxPair; typedef multimap TxItems; TxItems txByTime; + // Note: maintaining indices in the database of (account,time) --> txid and (account, time) --> acentry + // would make this much faster for applications that do this a lot. for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { CWalletTx* wtx = &((*it).second); @@@ -1301,10 -1312,8 +1308,8 @@@ txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry))); } - // Now: iterate backwards until we have nCount items to return: - TxItems::reverse_iterator it = txByTime.rbegin(); - if (txByTime.size() > nFrom) std::advance(it, nFrom); - for (; it != txByTime.rend(); ++it) + // iterate backwards until we have nCount items to return: + for (TxItems::reverse_iterator it = txByTime.rbegin(); it != txByTime.rend(); ++it) { CWalletTx *const pwtx = (*it).second.first; if (pwtx != 0) @@@ -1313,18 -1322,21 +1318,21 @@@ if (pacentry != 0) AcentryToJSON(*pacentry, strAccount, ret); - if (ret.size() >= nCount) break; + if (ret.size() >= (nCount+nFrom)) break; } - // ret is now newest to oldest + // ret is newest to oldest - // Make sure we return only last nCount items (sends-to-self might give us an extra): - if (ret.size() > nCount) - { - Array::iterator last = ret.begin(); - std::advance(last, nCount); - ret.erase(last, ret.end()); - } - std::reverse(ret.begin(), ret.end()); // oldest to newest + if (nFrom > ret.size()) nFrom = ret.size(); + if (nFrom+nCount > ret.size()) nCount = ret.size()-nFrom; + Array::iterator first = ret.begin(); + std::advance(first, nFrom); + Array::iterator last = ret.begin(); + std::advance(last, nFrom+nCount); + + if (last != ret.end()) ret.erase(last, ret.end()); + if (first != ret.begin()) ret.erase(ret.begin(), first); + + std::reverse(ret.begin(), ret.end()); // Return oldest to newest return ret; } @@@ -1647,8 -1659,8 +1655,8 @@@ Value walletlock(const Array& params, b if (!pwalletMain->IsCrypted()) throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called."); - CRITICAL_BLOCK(cs_nWalletUnlockTime) { + LOCK(cs_nWalletUnlockTime); pwalletMain->Lock(); nWalletUnlockTime = 0; } @@@ -2271,6 -2283,7 +2279,6 @@@ bool ClientAllowed(const string& strAdd return false; } -#ifdef USE_SSL // // IOStream device that speaks SSL but can also speak non-SSL // @@@ -2322,6 -2335,7 +2330,6 @@@ private bool fUseSSL; SSLStream& stream; }; -#endif void ThreadRPCServer(void* parg) { @@@ -2364,7 -2378,7 +2372,7 @@@ void ThreadRPCServer2(void* parg "(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().string().c_str(), EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()), _("Error"), wxOK | wxMODAL); QueueShutdown(); @@@ -2376,51 -2390,51 +2384,51 @@@ asio::io_service io_service; ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 8332)); - ip::tcp::acceptor acceptor(io_service, endpoint); - - acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true)); + ip::tcp::acceptor acceptor(io_service); + try + { + acceptor.open(endpoint.protocol()); + acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true)); + acceptor.bind(endpoint); + acceptor.listen(socket_base::max_connections); + } + catch(boost::system::system_error &e) + { + ThreadSafeMessageBox(strprintf(_("An error occured while setting up the RPC port %i for listening: %s"), endpoint.port(), e.what()), + _("Error"), wxOK | wxMODAL); + QueueShutdown(); + return; + } -#ifdef USE_SSL ssl::context context(io_service, ssl::context::sslv23); if (fUseSSL) { context.set_options(ssl::context::no_sslv2); - filesystem::path certfile = GetArg("-rpcsslcertificatechainfile", "server.cert"); - if (!certfile.is_complete()) certfile = filesystem::path(GetDataDir()) / certfile; - if (filesystem::exists(certfile)) context.use_certificate_chain_file(certfile.string().c_str()); - else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", certfile.string().c_str()); - filesystem::path pkfile = GetArg("-rpcsslprivatekeyfile", "server.pem"); - if (!pkfile.is_complete()) pkfile = filesystem::path(GetDataDir()) / pkfile; - if (filesystem::exists(pkfile)) context.use_private_key_file(pkfile.string().c_str(), ssl::context::pem); - else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pkfile.string().c_str()); - - string ciphers = GetArg("-rpcsslciphers", - "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH"); - SSL_CTX_set_cipher_list(context.impl(), ciphers.c_str()); + + filesystem::path pathCertFile(GetArg("-rpcsslcertificatechainfile", "server.cert")); + if (!pathCertFile.is_complete()) pathCertFile = filesystem::path(GetDataDir()) / pathCertFile; + if (filesystem::exists(pathCertFile)) context.use_certificate_chain_file(pathCertFile.string()); + else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", pathCertFile.string().c_str()); + + filesystem::path pathPKFile(GetArg("-rpcsslprivatekeyfile", "server.pem")); + if (!pathPKFile.is_complete()) pathPKFile = filesystem::path(GetDataDir()) / pathPKFile; + if (filesystem::exists(pathPKFile)) context.use_private_key_file(pathPKFile.string(), ssl::context::pem); + else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pathPKFile.string().c_str()); + + string strCiphers = GetArg("-rpcsslciphers", "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH"); + SSL_CTX_set_cipher_list(context.impl(), strCiphers.c_str()); } -#else - if (fUseSSL) - throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries."); -#endif loop { // Accept connection SSLStream sslStream(io_service, context); SSLIOStreamDevice d(sslStream, fUseSSL); iostreams::stream stream(d); ip::tcp::endpoint peer; vnThreadsRunning[THREAD_RPCSERVER]--; -#ifdef USE_SSL acceptor.accept(sslStream.lowest_layer(), peer); -#else - acceptor.accept(*stream.rdbuf(), peer); -#endif vnThreadsRunning[4]++; if (fShutdown) return; @@@ -2510,10 -2524,9 +2518,10 @@@ { // Execute Value result; - CRITICAL_BLOCK(cs_main) - CRITICAL_BLOCK(pwalletMain->cs_wallet) + { + LOCK2(cs_main, pwalletMain->cs_wallet); result = (*(*mi).second)(params, false); + } // Send reply string strReply = JSONRPCReply(result, Value::null, id); @@@ -2544,10 -2557,11 +2552,10 @@@ Object CallRPC(const string& strMethod throw runtime_error(strprintf( _("You must set rpcpassword= in the configuration file:\n%s\n" "If the file does not exist, create it with owner-readable-only file permissions."), - GetConfigFile().c_str())); + GetConfigFile().string().c_str())); // Connect to localhost bool fUseSSL = GetBoolArg("-rpcssl"); -#ifdef USE_SSL asio::io_service io_service; ssl::context context(io_service, ssl::context::sslv23); context.set_options(ssl::context::no_sslv2); @@@ -2556,6 -2570,15 +2564,6 @@@ iostreams::stream stream(d); if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332"))) throw runtime_error("couldn't connect to server"); -#else - if (fUseSSL) - throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries."); - - ip::tcp::iostream stream(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332")); - if (stream.fail()) - throw runtime_error("couldn't connect to server"); -#endif - // HTTP basic authentication string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);