From a8db31c83d6a43e07f741f7f61b1bf0df87621c7 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Fri, 17 Jan 2014 16:32:35 +0100 Subject: qt: allow `walletpassphrase` in debug console without -server Currently it is only possible to use `walletpassphrase` to unlock the wallet when bitcoin is started in server mode. Almost everything that manipulates the wallet in the RPC console needs the wallet to be unlocked and is thus unusable without -server. This is pretty unintuitive to me, and I'm sure it's even more confusing to users. Solve this with a very minimal change: by making the GUI start a dummy RPC thread just to handle timeouts. --- src/qt/bitcoin.cpp | 8 ++++++++ src/rpcprotocol.h | 1 - src/rpcserver.cpp | 15 +++++++++++++++ src/rpcserver.h | 7 +++++++ src/rpcwallet.cpp | 2 -- 5 files changed, 30 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 3cf7e53c02..9b0b1d6e43 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -21,6 +21,7 @@ #include "init.h" #include "main.h" +#include "rpcserver.h" #include "ui_interface.h" #include "util.h" #include "wallet.h" @@ -227,6 +228,13 @@ void BitcoinCore::initialize() { LogPrintf("Running AppInit2 in thread\n"); int rv = AppInit2(threadGroup); + if(rv) + { + /* Start a dummy RPC thread if no RPC thread is active yet + * to handle timeouts. + */ + StartDummyRPCThread(); + } emit initializeResult(rv); } catch (std::exception& e) { handleRunawayException(&e); diff --git a/src/rpcprotocol.h b/src/rpcprotocol.h index 6bf371e759..d3ed48525f 100644 --- a/src/rpcprotocol.h +++ b/src/rpcprotocol.h @@ -49,7 +49,6 @@ enum RPCErrorCode RPC_INVALID_PARAMETER = -8, // Invalid, missing or duplicate parameter RPC_DATABASE_ERROR = -20, // Database error RPC_DESERIALIZATION_ERROR = -22, // Error parsing or validating structure in raw format - RPC_SERVER_NOT_STARTED = -18, // RPC server was not started (StartRPCThreads() not called) // P2P client errors RPC_CLIENT_NOT_CONNECTED = -9, // Bitcoin is not connected diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 9d34a900ff..0d9e95402b 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -38,6 +38,7 @@ static asio::io_service* rpc_io_service = NULL; static map > deadlineTimers; static ssl::context* rpc_ssl_context = NULL; static boost::thread_group* rpc_worker_group = NULL; +static boost::asio::io_service::work *rpc_dummy_work = NULL; void RPCTypeCheck(const Array& params, const list& typesExpected, @@ -607,6 +608,19 @@ void StartRPCThreads() rpc_worker_group->create_thread(boost::bind(&asio::io_service::run, rpc_io_service)); } +void StartDummyRPCThread() +{ + if(rpc_io_service == NULL) + { + rpc_io_service = new asio::io_service(); + /* Create dummy "work" to keep the thread from exiting when no timeouts active, + * see http://www.boost.org/doc/libs/1_51_0/doc/html/boost_asio/reference/io_service.html#boost_asio.reference.io_service.stopping_the_io_service_from_running_out_of_work */ + rpc_dummy_work = new asio::io_service::work(*rpc_io_service); + rpc_worker_group = new boost::thread_group(); + rpc_worker_group->create_thread(boost::bind(&asio::io_service::run, rpc_io_service)); + } +} + void StopRPCThreads() { if (rpc_io_service == NULL) return; @@ -615,6 +629,7 @@ void StopRPCThreads() rpc_io_service->stop(); if (rpc_worker_group != NULL) rpc_worker_group->join_all(); + delete rpc_dummy_work; rpc_dummy_work = NULL; delete rpc_worker_group; rpc_worker_group = NULL; delete rpc_ssl_context; rpc_ssl_context = NULL; delete rpc_io_service; rpc_io_service = NULL; diff --git a/src/rpcserver.h b/src/rpcserver.h index 9087be9e88..9008c32810 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -20,7 +20,14 @@ class CBlockIndex; +/* Start RPC threads */ void StartRPCThreads(); +/* Alternative to StartRPCThreads for the GUI, when no server is + * used. The RPC thread in this case is only used to handle timeouts. + * If real RPC threads have already been started this is a no-op. + */ +void StartDummyRPCThread(); +/* Stop RPC threads */ void StopRPCThreads(); /* diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp index 8ad5c9c51d..68f5fe525a 100644 --- a/src/rpcwallet.cpp +++ b/src/rpcwallet.cpp @@ -1562,8 +1562,6 @@ Value walletpassphrase(const Array& params, bool fHelp) if (fHelp) return true; - if (!fServer) - throw JSONRPCError(RPC_SERVER_NOT_STARTED, "Error: RPC server was not started, use server=1 to change this."); if (!pwalletMain->IsCrypted()) throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called."); -- cgit v1.2.3