From bbb093652e33c0905d93f9d4bb70dbaf269e0cad Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Fri, 29 Nov 2013 15:48:07 +0100 Subject: [PATCH 1/8] Move HelpExample* from rpcwallet to rpcserver General functions used throughout the RPC framework don't belong in rpcwallet. --- src/rpcserver.cpp | 9 +++++++++ src/rpcwallet.cpp | 9 --------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index c746d8c8f..949e81e07 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -820,4 +820,13 @@ json_spirit::Value CRPCTable::execute(const std::string &strMethod, const json_s } } +std::string HelpExampleCli(string methodname, string args){ + return "> bitcoin-cli " + methodname + " " + args + "\n"; +} + +std::string HelpExampleRpc(string methodname, string args){ + return "> curl --user myusername --data-binary '{\"jsonrpc\": \"1.0\", \"id\":\"curltest\", " + "\"method\": \"" + methodname + "\", \"params\": [" + args + "] }' -H 'content-type: text/plain;' http://127.0.0.1:8332/\n"; +} + const CRPCTable tableRPC; diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp index b4e522de8..77ebc189a 100644 --- a/src/rpcwallet.cpp +++ b/src/rpcwallet.cpp @@ -33,15 +33,6 @@ std::string HelpRequiringPassphrase() : ""; } -std::string HelpExampleCli(string methodname, string args){ - return "> bitcoin-cli " + methodname + " " + args + "\n"; -} - -std::string HelpExampleRpc(string methodname, string args){ - return "> curl --user myusername --data-binary '{\"jsonrpc\": \"1.0\", \"id\":\"curltest\", " - "\"method\": \"" + methodname + "\", \"params\": [" + args + "] }' -H 'content-type: text/plain;' http://127.0.0.1:8332/\n"; -} - void EnsureWalletIsUnlocked() { if (pwalletMain->IsLocked()) From 991685d3dc208cfcbc2f27900a7252fb14c8f7ad Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Fri, 29 Nov 2013 16:00:11 +0100 Subject: [PATCH 2/8] Move getinfo to rpcnet.cpp Where to place `getinfo` is a difficult issue as it shows information from the wallet, net and block chain. However, I moved it out of rpcwallet as the command needs also to be available without wallet. --- src/rpcnet.cpp | 59 +++++++++++++++++++++++++++++++++++++++++++++++ src/rpcwallet.cpp | 58 ---------------------------------------------- 2 files changed, 59 insertions(+), 58 deletions(-) diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp index 99602bd1c..71b55bca1 100644 --- a/src/rpcnet.cpp +++ b/src/rpcnet.cpp @@ -8,6 +8,9 @@ #include "protocol.h" #include "sync.h" #include "util.h" +#include "wallet.h" // for getinfo +#include "init.h" // for getinfo +#include "main.h" // for getinfo #include @@ -329,3 +332,59 @@ Value getnettotals(const Array& params, bool fHelp) obj.push_back(Pair("timemillis", static_cast(GetTimeMillis()))); return obj; } + +Value getinfo(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 0) + throw runtime_error( + "getinfo\n" + "Returns an object containing various state info.\n" + "\nResult:\n" + "{\n" + " \"version\": xxxxx, (numeric) the server version\n" + " \"protocolversion\": xxxxx, (numeric) the protocol version\n" + " \"walletversion\": xxxxx, (numeric) the wallet version\n" + " \"balance\": xxxxxxx, (numeric) the total bitcoin balance of the wallet\n" + " \"blocks\": xxxxxx, (numeric) the current number of blocks processed in the server\n" + " \"timeoffset\": xxxxx, (numeric) the time offset\n" + " \"connections\": xxxxx, (numeric) the number of connections\n" + " \"proxy\": \"host:port\", (string, optional) the proxy used by the server\n" + " \"difficulty\": xxxxxx, (numeric) the current difficulty\n" + " \"testnet\": true|false, (boolean) if the server is using testnet or not\n" + " \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\n" + " \"keypoolsize\": xxxx, (numeric) how many new keys are pre-generated\n" + " \"paytxfee\": x.xxxx, (numeric) the transaction fee set in btc\n" + " \"unlocked_until\": ttt, (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\n" + " \"errors\": \"...\" (string) any error messages\n" + "}\n" + "\nExamples:\n" + + HelpExampleCli("getinfo", "") + + HelpExampleRpc("getinfo", "") + ); + + proxyType proxy; + GetProxy(NET_IPV4, proxy); + + Object obj; + obj.push_back(Pair("version", (int)CLIENT_VERSION)); + obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION)); + if (pwalletMain) { + obj.push_back(Pair("walletversion", pwalletMain->GetVersion())); + obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance()))); + } + obj.push_back(Pair("blocks", (int)chainActive.Height())); + obj.push_back(Pair("timeoffset", (boost::int64_t)GetTimeOffset())); + obj.push_back(Pair("connections", (int)vNodes.size())); + obj.push_back(Pair("proxy", (proxy.first.IsValid() ? proxy.first.ToStringIPPort() : string()))); + obj.push_back(Pair("difficulty", (double)GetDifficulty())); + obj.push_back(Pair("testnet", TestNet())); + if (pwalletMain) { + obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime())); + obj.push_back(Pair("keypoolsize", (int)pwalletMain->GetKeyPoolSize())); + } + obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee))); + if (pwalletMain && pwalletMain->IsCrypted()) + obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime)); + obj.push_back(Pair("errors", GetWarnings("statusbar"))); + return obj; +} diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp index 77ebc189a..bb87afec5 100644 --- a/src/rpcwallet.cpp +++ b/src/rpcwallet.cpp @@ -66,64 +66,6 @@ string AccountFromValue(const Value& value) return strAccount; } -Value getinfo(const Array& params, bool fHelp) -{ - if (fHelp || params.size() != 0) - throw runtime_error( - "getinfo\n" - "Returns an object containing various state info.\n" - "\nResult:\n" - "{\n" - " \"version\": xxxxx, (numeric) the server version\n" - " \"protocolversion\": xxxxx, (numeric) the protocol version\n" - " \"walletversion\": xxxxx, (numeric) the wallet version\n" - " \"balance\": xxxxxxx, (numeric) the total bitcoin balance of the wallet\n" - " \"blocks\": xxxxxx, (numeric) the current number of blocks processed in the server\n" - " \"timeoffset\": xxxxx, (numeric) the time offset\n" - " \"connections\": xxxxx, (numeric) the number of connections\n" - " \"proxy\": \"host:port\", (string, optional) the proxy used by the server\n" - " \"difficulty\": xxxxxx, (numeric) the current difficulty\n" - " \"testnet\": true|false, (boolean) if the server is using testnet or not\n" - " \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\n" - " \"keypoolsize\": xxxx, (numeric) how many new keys are pre-generated\n" - " \"paytxfee\": x.xxxx, (numeric) the transaction fee set in btc\n" - " \"unlocked_until\": ttt, (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\n" - " \"errors\": \"...\" (string) any error messages\n" - "}\n" - "\nExamples:\n" - + HelpExampleCli("getinfo", "") - + HelpExampleRpc("getinfo", "") - ); - - proxyType proxy; - GetProxy(NET_IPV4, proxy); - - Object obj; - obj.push_back(Pair("version", (int)CLIENT_VERSION)); - obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION)); - if (pwalletMain) { - obj.push_back(Pair("walletversion", pwalletMain->GetVersion())); - obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance()))); - } - obj.push_back(Pair("blocks", (int)chainActive.Height())); - obj.push_back(Pair("timeoffset", (boost::int64_t)GetTimeOffset())); - obj.push_back(Pair("connections", (int)vNodes.size())); - obj.push_back(Pair("proxy", (proxy.first.IsValid() ? proxy.first.ToStringIPPort() : string()))); - obj.push_back(Pair("difficulty", (double)GetDifficulty())); - obj.push_back(Pair("testnet", TestNet())); - if (pwalletMain) { - obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime())); - obj.push_back(Pair("keypoolsize", (int)pwalletMain->GetKeyPoolSize())); - } - obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee))); - if (pwalletMain && pwalletMain->IsCrypted()) - obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime)); - obj.push_back(Pair("errors", GetWarnings("statusbar"))); - return obj; -} - - - Value getnewaddress(const Array& params, bool fHelp) { if (fHelp || params.size() > 1) From 48ba56cdfd1f0d2478b0d8cffb828efb6982ed76 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Fri, 29 Nov 2013 16:04:29 +0100 Subject: [PATCH 3/8] Delimit code with #ifdef ENABLE_WALLET Delimit all code that uses the wallet functions in implementation files that conditionally use the wallet. --- src/init.cpp | 41 ++++++++++++++++++++++++++++------- src/rpcnet.cpp | 9 +++++++- src/rpcrawtransaction.cpp | 15 +++++++++++++ src/rpcserver.cpp | 45 +++++++++++++++++++++++++++------------ src/test/rpc_tests.cpp | 5 ++++- src/test/test_bitcoin.cpp | 10 +++++++++ 6 files changed, 101 insertions(+), 24 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 54722743e..fc15df059 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -10,6 +10,7 @@ #include "init.h" #include "addrman.h" +#include "db.h" #include "rpcserver.h" #include "checkpoints.h" #include "miner.h" @@ -17,8 +18,10 @@ #include "txdb.h" #include "ui_interface.h" #include "util.h" +#ifdef ENABLE_WALLET #include "wallet.h" #include "walletdb.h" +#endif #include #include @@ -35,8 +38,10 @@ using namespace std; using namespace boost; +#ifdef ENABLE_WALLET std::string strWalletFile; CWallet* pwalletMain; +#endif #ifdef WIN32 // Win32 LevelDB doesn't use filedescriptors, and the ones used for @@ -108,15 +113,19 @@ void Shutdown() RenameThread("bitcoin-shutoff"); mempool.AddTransactionsUpdated(1); StopRPCThreads(); +#ifdef ENABLE_WALLET ShutdownRPCMining(); if (pwalletMain) bitdb.Flush(false); GenerateBitcoins(false, NULL, 0); +#endif StopNode(); { LOCK(cs_main); +#ifdef ENABLE_WALLET if (pwalletMain) pwalletMain->SetBestChain(chainActive.GetLocator()); +#endif if (pblocktree) pblocktree->Flush(); if (pcoinsTip) @@ -125,12 +134,16 @@ void Shutdown() delete pcoinsdbview; pcoinsdbview = NULL; delete pblocktree; pblocktree = NULL; } +#ifdef ENABLE_WALLET if (pwalletMain) bitdb.Flush(true); +#endif boost::filesystem::remove(GetPidFile()); UnregisterAllWallets(); +#ifdef ENABLE_WALLET if (pwalletMain) delete pwalletMain; +#endif LogPrintf("Shutdown : done\n"); } @@ -479,7 +492,9 @@ bool AppInit2(boost::thread_group& threadGroup, bool fForceServer) fPrintToConsole = GetBoolArg("-printtoconsole", false); fPrintToDebugger = GetBoolArg("-printtodebugger", false); fLogTimestamps = GetBoolArg("-logtimestamps", true); +#ifdef ENABLE_WALLET bool fDisableWallet = GetBoolArg("-disablewallet", false); +#endif if (mapArgs.count("-timeout")) { @@ -525,16 +540,17 @@ bool AppInit2(boost::thread_group& threadGroup, bool fForceServer) InitWarning(_("Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction.")); } +#ifdef ENABLE_WALLET strWalletFile = GetArg("-wallet", "wallet.dat"); - +#endif // ********************************************************* Step 4: application initialization: dir lock, daemonize, pidfile, debug log std::string strDataDir = GetDataDir().string(); - +#ifdef ENABLE_WALLET // Wallet file must be a plain filename without a directory if (strWalletFile != boost::filesystem::basename(strWalletFile) + boost::filesystem::extension(strWalletFile)) return InitError(strprintf(_("Wallet %s resides outside data directory %s"), strWalletFile.c_str(), strDataDir.c_str())); - +#endif // Make sure only a single Bitcoin process is using the data directory. boost::filesystem::path pathLockFile = GetDataDir() / ".lock"; FILE* file = fopen(pathLockFile.string().c_str(), "a"); // empty lock file; created if it doesn't exist. @@ -567,7 +583,7 @@ bool AppInit2(boost::thread_group& threadGroup, bool fForceServer) int64_t nStart; // ********************************************************* Step 5: verify wallet database integrity - +#ifdef ENABLE_WALLET if (!fDisableWallet) { uiInterface.InitMessage(_("Verifying wallet...")); @@ -613,7 +629,7 @@ bool AppInit2(boost::thread_group& threadGroup, bool fForceServer) return InitError(_("wallet.dat corrupt, salvage failed")); } } // (!fDisableWallet) - +#endif // ENABLE_WALLET // ********************************************************* Step 6: network initialization RegisterNodeSignals(GetNodeSignals()); @@ -880,7 +896,7 @@ bool AppInit2(boost::thread_group& threadGroup, bool fForceServer) } // ********************************************************* Step 8: load wallet - +#ifdef ENABLE_WALLET if (fDisableWallet) { pwalletMain = NULL; LogPrintf("Wallet disabled!\n"); @@ -972,7 +988,9 @@ bool AppInit2(boost::thread_group& threadGroup, bool fForceServer) nWalletDBUpdated++; } } // (!fDisableWallet) - +#else // ENABLE_WALLET + LogPrintf("No wallet compiled in!\n"); +#endif // !ENABLE_WALLET // ********************************************************* Step 9: import blocks // scan for better chains in the block chain database, that are not yet connected in the active best chain @@ -1016,25 +1034,31 @@ bool AppInit2(boost::thread_group& threadGroup, bool fForceServer) //// debug print LogPrintf("mapBlockIndex.size() = %"PRIszu"\n", mapBlockIndex.size()); LogPrintf("nBestHeight = %d\n", chainActive.Height()); +#ifdef ENABLE_WALLET LogPrintf("setKeyPool.size() = %"PRIszu"\n", pwalletMain ? pwalletMain->setKeyPool.size() : 0); LogPrintf("mapWallet.size() = %"PRIszu"\n", pwalletMain ? pwalletMain->mapWallet.size() : 0); LogPrintf("mapAddressBook.size() = %"PRIszu"\n", pwalletMain ? pwalletMain->mapAddressBook.size() : 0); +#endif StartNode(threadGroup); - +#ifdef ENABLE_WALLET // InitRPCMining is needed here so getwork/getblocktemplate in the GUI debug console works properly. InitRPCMining(); +#endif if (fServer) StartRPCThreads(); +#ifdef ENABLE_WALLET // Generate coins in the background if (pwalletMain) GenerateBitcoins(GetBoolArg("-gen", false), pwalletMain, GetArg("-genproclimit", -1)); +#endif // ********************************************************* Step 12: finished uiInterface.InitMessage(_("Done loading")); +#ifdef ENABLE_WALLET if (pwalletMain) { // Add wallet transactions that aren't already in a block to mapTransactions pwalletMain->ReacceptWalletTransactions(); @@ -1042,6 +1066,7 @@ bool AppInit2(boost::thread_group& threadGroup, bool fForceServer) // Run a thread to flush wallet periodically threadGroup.create_thread(boost::bind(&ThreadFlushWalletDB, boost::ref(pwalletMain->strWalletFile))); } +#endif return !fRequestShutdown; } diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp index 71b55bca1..89bf53060 100644 --- a/src/rpcnet.cpp +++ b/src/rpcnet.cpp @@ -1,15 +1,16 @@ // Copyright (c) 2009-2013 The Bitcoin developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. - #include "rpcserver.h" #include "net.h" #include "netbase.h" #include "protocol.h" #include "sync.h" #include "util.h" +#ifdef ENABLE_WALLET #include "wallet.h" // for getinfo #include "init.h" // for getinfo +#endif #include "main.h" // for getinfo #include @@ -368,23 +369,29 @@ Value getinfo(const Array& params, bool fHelp) Object obj; obj.push_back(Pair("version", (int)CLIENT_VERSION)); obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION)); +#ifdef ENABLE_WALLET if (pwalletMain) { obj.push_back(Pair("walletversion", pwalletMain->GetVersion())); obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance()))); } +#endif obj.push_back(Pair("blocks", (int)chainActive.Height())); obj.push_back(Pair("timeoffset", (boost::int64_t)GetTimeOffset())); obj.push_back(Pair("connections", (int)vNodes.size())); obj.push_back(Pair("proxy", (proxy.first.IsValid() ? proxy.first.ToStringIPPort() : string()))); obj.push_back(Pair("difficulty", (double)GetDifficulty())); obj.push_back(Pair("testnet", TestNet())); +#ifdef ENABLE_WALLET if (pwalletMain) { obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime())); obj.push_back(Pair("keypoolsize", (int)pwalletMain->GetKeyPoolSize())); } +#endif obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee))); +#ifdef ENABLE_WALLET if (pwalletMain && pwalletMain->IsCrypted()) obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime)); +#endif obj.push_back(Pair("errors", GetWarnings("statusbar"))); return obj; } diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp index 939ca96f7..abbc33cc5 100644 --- a/src/rpcrawtransaction.cpp +++ b/src/rpcrawtransaction.cpp @@ -8,7 +8,12 @@ #include "init.h" #include "net.h" #include "uint256.h" +#include "core.h" +#include "main.h" +#include "keystore.h" +#ifdef ENABLE_WALLET #include "wallet.h" +#endif #include @@ -190,6 +195,7 @@ Value getrawtransaction(const Array& params, bool fHelp) return result; } +#ifdef ENABLE_WALLET Value listunspent(const Array& params, bool fHelp) { if (fHelp || params.size() > 3) @@ -303,6 +309,7 @@ Value listunspent(const Array& params, bool fHelp) return results; } +#endif Value createrawtransaction(const Array& params, bool fHelp) { @@ -508,7 +515,9 @@ Value signrawtransaction(const Array& params, bool fHelp) "this transaction depends on but may not yet be in the block chain.\n" "The third optional argument (may be null) is an array of base58-encoded private\n" "keys that, if given, will be the only keys used to sign the transaction.\n" +#ifdef ENABLE_WALLET + HelpRequiringPassphrase() + "\n" +#endif "\nArguments:\n" "1. \"hexstring\" (string, required) The transaction hex string\n" @@ -605,8 +614,10 @@ Value signrawtransaction(const Array& params, bool fHelp) tempKeystore.AddKey(key); } } +#ifdef ENABLE_WALLET else EnsureWalletIsUnlocked(); +#endif // Add previous txouts given in the RPC call: if (params.size() > 1 && params[1].type() != null_type) @@ -662,7 +673,11 @@ Value signrawtransaction(const Array& params, bool fHelp) } } +#ifdef ENABLE_WALLET const CKeyStore& keystore = ((fGivenKeys || !pwalletMain) ? tempKeystore : *pwalletMain); +#else + const CKeyStore& keystore = tempKeystore; +#endif int nHashType = SIGHASH_ALL; if (params.size() > 3 && params[3].type() != null_type) diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 949e81e07..2dc7b34f8 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -9,7 +9,10 @@ #include "init.h" #include "main.h" #include "util.h" +#include "ui_interface.h" +#ifdef ENABLE_WALLET #include "wallet.h" +#endif #include #include @@ -149,8 +152,10 @@ string CRPCTable::help(string strCommand) const continue; if (strCommand != "" && strMethod != strCommand) continue; +#ifdef ENABLE_WALLET if (pcmd->reqWallet && !pwalletMain) continue; +#endif try { @@ -228,11 +233,26 @@ static const CRPCCommand vRPCCommands[] = { "getaddednodeinfo", &getaddednodeinfo, true, true, false }, { "getnettotals", &getnettotals, true, true, false }, { "getdifficulty", &getdifficulty, true, false, false }, + { "getinfo", &getinfo, true, false, false }, + { "getrawmempool", &getrawmempool, true, false, false }, + { "getblock", &getblock, false, false, false }, + { "getblockhash", &getblockhash, false, false, false }, + { "settxfee", &settxfee, false, false, true }, + { "getrawtransaction", &getrawtransaction, false, false, false }, + { "createrawtransaction", &createrawtransaction, false, false, false }, + { "decoderawtransaction", &decoderawtransaction, false, false, false }, + { "decodescript", &decodescript, false, false, false }, + { "signrawtransaction", &signrawtransaction, false, false, false }, + { "sendrawtransaction", &sendrawtransaction, false, false, false }, + { "gettxoutsetinfo", &gettxoutsetinfo, true, false, false }, + { "gettxout", &gettxout, true, false, false }, + { "verifychain", &verifychain, true, false, false }, + +#ifdef ENABLE_WALLET { "getnetworkhashps", &getnetworkhashps, true, false, false }, { "getgenerate", &getgenerate, true, false, false }, { "setgenerate", &setgenerate, true, true, false }, { "gethashespersec", &gethashespersec, true, false, false }, - { "getinfo", &getinfo, true, false, false }, { "getmininginfo", &getmininginfo, true, false, false }, { "getnewaddress", &getnewaddress, true, false, true }, { "getaccountaddress", &getaccountaddress, true, false, true }, @@ -258,9 +278,6 @@ static const CRPCCommand vRPCCommands[] = { "sendmany", &sendmany, false, false, true }, { "addmultisigaddress", &addmultisigaddress, false, false, true }, { "createmultisig", &createmultisig, true, true , false }, - { "getrawmempool", &getrawmempool, true, false, false }, - { "getblock", &getblock, false, false, false }, - { "getblockhash", &getblockhash, false, false, false }, { "gettransaction", &gettransaction, false, false, true }, { "listtransactions", &listtransactions, false, false, true }, { "listaddressgroupings", &listaddressgroupings, false, false, true }, @@ -268,7 +285,6 @@ static const CRPCCommand vRPCCommands[] = { "verifymessage", &verifymessage, false, false, false }, { "getwork", &getwork, true, false, true }, { "listaccounts", &listaccounts, false, false, true }, - { "settxfee", &settxfee, false, false, true }, { "getblocktemplate", &getblocktemplate, true, false, false }, { "submitblock", &submitblock, false, false, false }, { "listsinceblock", &listsinceblock, false, false, true }, @@ -277,17 +293,9 @@ static const CRPCCommand vRPCCommands[] = { "importprivkey", &importprivkey, false, false, true }, { "importwallet", &importwallet, false, false, true }, { "listunspent", &listunspent, false, false, true }, - { "getrawtransaction", &getrawtransaction, false, false, false }, - { "createrawtransaction", &createrawtransaction, false, false, false }, - { "decoderawtransaction", &decoderawtransaction, false, false, false }, - { "decodescript", &decodescript, false, false, false }, - { "signrawtransaction", &signrawtransaction, false, false, false }, - { "sendrawtransaction", &sendrawtransaction, false, false, false }, - { "gettxoutsetinfo", &gettxoutsetinfo, true, false, false }, - { "gettxout", &gettxout, true, false, false }, { "lockunspent", &lockunspent, false, false, true }, { "listlockunspent", &listlockunspent, false, false, true }, - { "verifychain", &verifychain, true, false, false }, +#endif // ENABLE_WALLET }; CRPCTable::CRPCTable() @@ -788,8 +796,10 @@ json_spirit::Value CRPCTable::execute(const std::string &strMethod, const json_s const CRPCCommand *pcmd = tableRPC[strMethod]; if (!pcmd) throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found"); +#ifdef ENABLE_WALLET if (pcmd->reqWallet && !pwalletMain) throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)"); +#endif // Observe safe mode string strWarning = GetWarnings("rpc"); @@ -804,6 +814,7 @@ json_spirit::Value CRPCTable::execute(const std::string &strMethod, const json_s { if (pcmd->threadSafe) result = pcmd->actor(params, false); +#ifdef ENABLE_WALLET else if (!pwalletMain) { LOCK(cs_main); result = pcmd->actor(params, false); @@ -811,6 +822,12 @@ json_spirit::Value CRPCTable::execute(const std::string &strMethod, const json_s LOCK2(cs_main, pwalletMain->cs_wallet); result = pcmd->actor(params, false); } +#else // ENABLE_WALLET + else { + LOCK(cs_main); + result = pcmd->actor(params, false); + } +#endif // !ENABLE_WALLET } return result; } diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp index 76580bae4..e56aae225 100644 --- a/src/test/rpc_tests.cpp +++ b/src/test/rpc_tests.cpp @@ -23,6 +23,7 @@ createArgs(int nRequired, const char* address1=NULL, const char* address2=NULL) return result; } +#ifdef ENABLE_WALLET BOOST_AUTO_TEST_CASE(rpc_addmultisig) { rpcfn_type addmultisig = tableRPC["addmultisigaddress"]->actor; @@ -59,6 +60,7 @@ BOOST_AUTO_TEST_CASE(rpc_addmultisig) string short2(address1Hex+1, address1Hex+sizeof(address1Hex)); // first byte missing BOOST_CHECK_THROW(addmultisig(createArgs(2, short2.c_str()), false), runtime_error); } +#endif static Value CallRPC(string args) { @@ -79,6 +81,7 @@ static Value CallRPC(string args) } } +#ifdef ENABLE_WALLET BOOST_AUTO_TEST_CASE(rpc_wallet) { // Test RPC calls for various wallet statistics @@ -106,7 +109,7 @@ BOOST_AUTO_TEST_CASE(rpc_wallet) BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount 0 true")); BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount 0 true extra"), runtime_error); } - +#endif BOOST_AUTO_TEST_CASE(rpc_rawparams) { diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index 443e7735d..a804ff380 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -7,7 +7,9 @@ #include "txdb.h" #include "ui_interface.h" #include "util.h" +#ifdef ENABLE_WALLET #include "wallet.h" +#endif #include #include @@ -26,7 +28,9 @@ struct TestingSetup { TestingSetup() { fPrintToDebugger = true; // don't want to write to debug.log file noui_connect(); +#ifdef ENABLE_WALLET bitdb.MakeMock(); +#endif pathTemp = GetTempPath() / strprintf("test_bitcoin_%lu_%i", (unsigned long)GetTime(), (int)(GetRand(100000))); boost::filesystem::create_directories(pathTemp); mapArgs["-datadir"] = pathTemp.string(); @@ -34,10 +38,12 @@ struct TestingSetup { pcoinsdbview = new CCoinsViewDB(1 << 23, true); pcoinsTip = new CCoinsViewCache(*pcoinsdbview); InitBlockIndex(); +#ifdef ENABLE_WALLET bool fFirstRun; pwalletMain = new CWallet("wallet.dat"); pwalletMain->LoadWallet(fFirstRun); RegisterWallet(pwalletMain); +#endif nScriptCheckThreads = 3; for (int i=0; i < nScriptCheckThreads-1; i++) threadGroup.create_thread(&ThreadScriptCheck); @@ -46,12 +52,16 @@ struct TestingSetup { { threadGroup.interrupt_all(); threadGroup.join_all(); +#ifdef ENABLE_WALLET delete pwalletMain; pwalletMain = NULL; +#endif delete pcoinsTip; delete pcoinsdbview; delete pblocktree; +#ifdef ENABLE_WALLET bitdb.Flush(true); +#endif boost::filesystem::remove_all(pathTemp); } }; From d004d7279ff21b7ee90207a850ec26ba044799bb Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Fri, 29 Nov 2013 16:33:34 +0100 Subject: [PATCH 4/8] Move CAddrDB frrom db to net This was a leftover from the times in which peers.dat depended in BDB. Other functions in db.cpp still depend on BerkelyDB, to be able to compile without BDB this (small) functionality needs to be moved to another file. --- src/db.cpp | 110 ---------------------------------------------------- src/db.h | 18 --------- src/net.cpp | 100 +++++++++++++++++++++++++++++++++++++++++++++++ src/net.h | 11 ++++++ 4 files changed, 111 insertions(+), 128 deletions(-) diff --git a/src/db.cpp b/src/db.cpp index a286d9f72..1f2ee1c55 100644 --- a/src/db.cpp +++ b/src/db.cpp @@ -479,113 +479,3 @@ void CDBEnv::Flush(bool fShutdown) } } - - - - - - - - - - -// -// CAddrDB -// - -CAddrDB::CAddrDB() -{ - pathAddr = GetDataDir() / "peers.dat"; -} - -bool CAddrDB::Write(const CAddrMan& addr) -{ - // Generate random temporary filename - unsigned short randv = 0; - RAND_bytes((unsigned char *)&randv, sizeof(randv)); - std::string tmpfn = strprintf("peers.dat.%04x", randv); - - // serialize addresses, checksum data up to that point, then append csum - CDataStream ssPeers(SER_DISK, CLIENT_VERSION); - ssPeers << FLATDATA(Params().MessageStart()); - ssPeers << addr; - uint256 hash = Hash(ssPeers.begin(), ssPeers.end()); - ssPeers << hash; - - // open temp output file, and associate with CAutoFile - boost::filesystem::path pathTmp = GetDataDir() / tmpfn; - FILE *file = fopen(pathTmp.string().c_str(), "wb"); - CAutoFile fileout = CAutoFile(file, SER_DISK, CLIENT_VERSION); - if (!fileout) - return error("CAddrman::Write() : open failed"); - - // Write and commit header, data - try { - fileout << ssPeers; - } - catch (std::exception &e) { - return error("CAddrman::Write() : I/O error"); - } - FileCommit(fileout); - fileout.fclose(); - - // replace existing peers.dat, if any, with new peers.dat.XXXX - if (!RenameOver(pathTmp, pathAddr)) - return error("CAddrman::Write() : Rename-into-place failed"); - - return true; -} - -bool CAddrDB::Read(CAddrMan& addr) -{ - // open input file, and associate with CAutoFile - FILE *file = fopen(pathAddr.string().c_str(), "rb"); - CAutoFile filein = CAutoFile(file, SER_DISK, CLIENT_VERSION); - if (!filein) - return error("CAddrman::Read() : open failed"); - - // use file size to size memory buffer - int fileSize = GetFilesize(filein); - int dataSize = fileSize - sizeof(uint256); - //Don't try to resize to a negative number if file is small - if ( dataSize < 0 ) dataSize = 0; - vector vchData; - vchData.resize(dataSize); - uint256 hashIn; - - // read data and checksum from file - try { - filein.read((char *)&vchData[0], dataSize); - filein >> hashIn; - } - catch (std::exception &e) { - return error("CAddrman::Read() 2 : I/O error or stream data corrupted"); - } - filein.fclose(); - - CDataStream ssPeers(vchData, SER_DISK, CLIENT_VERSION); - - // verify stored checksum matches input data - uint256 hashTmp = Hash(ssPeers.begin(), ssPeers.end()); - if (hashIn != hashTmp) - return error("CAddrman::Read() : checksum mismatch; data corrupted"); - - unsigned char pchMsgTmp[4]; - try { - // de-serialize file header (network specific magic number) and .. - ssPeers >> FLATDATA(pchMsgTmp); - - // ... verify the network matches ours - if (memcmp(pchMsgTmp, Params().MessageStart(), sizeof(pchMsgTmp))) - return error("CAddrman::Read() : invalid network magic number"); - - // de-serialize address data into one CAddrMan object - ssPeers >> addr; - } - catch (std::exception &e) { - return error("CAddrman::Read() : I/O error or stream data corrupted"); - } - - return true; -} - diff --git a/src/db.h b/src/db.h index e041a5930..66d7f3191 100644 --- a/src/db.h +++ b/src/db.h @@ -305,22 +305,4 @@ public: bool static Rewrite(const std::string& strFile, const char* pszSkip = NULL); }; - - - - - - - -/** Access to the (IP) address database (peers.dat) */ -class CAddrDB -{ -private: - boost::filesystem::path pathAddr; -public: - CAddrDB(); - bool Write(const CAddrMan& addr); - bool Read(CAddrMan& addr); -}; - #endif // BITCOIN_DB_H diff --git a/src/net.cpp b/src/net.cpp index fcef9feea..afffbdf1d 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1942,3 +1942,103 @@ void CNode::Fuzz(int nChance) // (more changes exponentially less likely): Fuzz(2); } + +// +// CAddrDB +// + +CAddrDB::CAddrDB() +{ + pathAddr = GetDataDir() / "peers.dat"; +} + +bool CAddrDB::Write(const CAddrMan& addr) +{ + // Generate random temporary filename + unsigned short randv = 0; + RAND_bytes((unsigned char *)&randv, sizeof(randv)); + std::string tmpfn = strprintf("peers.dat.%04x", randv); + + // serialize addresses, checksum data up to that point, then append csum + CDataStream ssPeers(SER_DISK, CLIENT_VERSION); + ssPeers << FLATDATA(Params().MessageStart()); + ssPeers << addr; + uint256 hash = Hash(ssPeers.begin(), ssPeers.end()); + ssPeers << hash; + + // open temp output file, and associate with CAutoFile + boost::filesystem::path pathTmp = GetDataDir() / tmpfn; + FILE *file = fopen(pathTmp.string().c_str(), "wb"); + CAutoFile fileout = CAutoFile(file, SER_DISK, CLIENT_VERSION); + if (!fileout) + return error("CAddrman::Write() : open failed"); + + // Write and commit header, data + try { + fileout << ssPeers; + } + catch (std::exception &e) { + return error("CAddrman::Write() : I/O error"); + } + FileCommit(fileout); + fileout.fclose(); + + // replace existing peers.dat, if any, with new peers.dat.XXXX + if (!RenameOver(pathTmp, pathAddr)) + return error("CAddrman::Write() : Rename-into-place failed"); + + return true; +} + +bool CAddrDB::Read(CAddrMan& addr) +{ + // open input file, and associate with CAutoFile + FILE *file = fopen(pathAddr.string().c_str(), "rb"); + CAutoFile filein = CAutoFile(file, SER_DISK, CLIENT_VERSION); + if (!filein) + return error("CAddrman::Read() : open failed"); + + // use file size to size memory buffer + int fileSize = GetFilesize(filein); + int dataSize = fileSize - sizeof(uint256); + //Don't try to resize to a negative number if file is small + if ( dataSize < 0 ) dataSize = 0; + vector vchData; + vchData.resize(dataSize); + uint256 hashIn; + + // read data and checksum from file + try { + filein.read((char *)&vchData[0], dataSize); + filein >> hashIn; + } + catch (std::exception &e) { + return error("CAddrman::Read() 2 : I/O error or stream data corrupted"); + } + filein.fclose(); + + CDataStream ssPeers(vchData, SER_DISK, CLIENT_VERSION); + + // verify stored checksum matches input data + uint256 hashTmp = Hash(ssPeers.begin(), ssPeers.end()); + if (hashIn != hashTmp) + return error("CAddrman::Read() : checksum mismatch; data corrupted"); + + unsigned char pchMsgTmp[4]; + try { + // de-serialize file header (network specific magic number) and .. + ssPeers >> FLATDATA(pchMsgTmp); + + // ... verify the network matches ours + if (memcmp(pchMsgTmp, Params().MessageStart(), sizeof(pchMsgTmp))) + return error("CAddrman::Read() : invalid network magic number"); + + // de-serialize address data into one CAddrMan object + ssPeers >> addr; + } + catch (std::exception &e) { + return error("CAddrman::Read() : I/O error or stream data corrupted"); + } + + return true; +} diff --git a/src/net.h b/src/net.h index effce35dc..28359ea12 100644 --- a/src/net.h +++ b/src/net.h @@ -690,4 +690,15 @@ class CTransaction; void RelayTransaction(const CTransaction& tx, const uint256& hash); void RelayTransaction(const CTransaction& tx, const uint256& hash, const CDataStream& ss); +/** Access to the (IP) address database (peers.dat) */ +class CAddrDB +{ +private: + boost::filesystem::path pathAddr; +public: + CAddrDB(); + bool Write(const CAddrMan& addr); + bool Read(CAddrMan& addr); +}; + #endif From 4f9e993bc9beb8261022aad6668d675dccb1e6c4 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Fri, 29 Nov 2013 16:50:11 +0100 Subject: [PATCH 5/8] Add --disable-wallet option to build system Make it possible to build Bitcoin without wallet (and thus without BDB) so that it only functions as node. --- configure.ac | 28 ++++++++++++++++++++++++++-- src/Makefile.am | 41 +++++++++++++++++++++++++++++++++++------ src/Makefile.include | 1 + src/qt/Makefile.am | 2 +- src/qt/test/Makefile.am | 2 +- src/test/Makefile.am | 17 +++++++++++++---- 6 files changed, 77 insertions(+), 14 deletions(-) diff --git a/configure.ac b/configure.ac index df9443895..0f99675fb 100644 --- a/configure.ac +++ b/configure.ac @@ -37,6 +37,13 @@ AM_MAINTAINER_MODE([enable]) dnl make the compilation flags quiet unless V=1 is used m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) +# Enable wallet +AC_ARG_ENABLE([wallet], + [AS_HELP_STRING([--enable-wallet], + [enable wallet (default is yes)])], + [enable_wallet=$enableval], + [enable_wallet=yes]) + AC_ARG_WITH([miniupnpc], [AS_HELP_STRING([--with-miniupnpc], [enable UPNP (default is yes if libminiupnpc is found)])], @@ -362,8 +369,10 @@ AC_TRY_COMPILE([#include ], [ AC_MSG_RESULT(no)] ) -dnl Check for libdb_cxx -BITCOIN_FIND_BDB48 +if test x$enable_wallet != xno; then + dnl Check for libdb_cxx only if wallet enabled + BITCOIN_FIND_BDB48 +fi dnl Check for libminiupnpc (optional) if test x$use_upnp != xno; then @@ -593,6 +602,20 @@ if test "x$use_ccache" != "xno"; then AC_MSG_RESULT($use_ccache) fi +dnl enable wallet +AC_MSG_CHECKING([if wallet should be enabled]) +if test x$enable_wallet != xno; then + AC_MSG_RESULT(yes) + AC_DEFINE_UNQUOTED([ENABLE_WALLET],[1],[Define to 1 to enable wallet functions]) + +else + AC_MSG_RESULT(no) + + if test "x$use_qt" != "xno"; then + AC_MSG_ERROR([Cannot currently build Qt GUI with wallet disabled. Use --without-qt.]) + fi +fi + dnl enable ipv6 support AC_MSG_CHECKING([if ipv6 should be enabled]) if test x$have_ipv6 = xno; then @@ -705,6 +728,7 @@ fi AM_CONDITIONAL([TARGET_DARWIN], [test x$TARGET_OS = xdarwin]) AM_CONDITIONAL([TARGET_WINDOWS], [test x$TARGET_OS = xwindows]) +AM_CONDITIONAL([ENABLE_WALLET],[test x$enable_wallet == xyes]) AM_CONDITIONAL([USE_QRCODE], [test x$use_qr = xyes]) AM_CONDITIONAL([USE_LCOV],[test x$use_lcov == xyes]) AM_CONDITIONAL([USE_COMPARISON_TOOL],[test x$use_comparison_tool != xno]) diff --git a/src/Makefile.am b/src/Makefile.am index 9d3365fd6..5daf62569 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -4,6 +4,9 @@ AM_CPPFLAGS += -I$(top_srcdir)/src/leveldb/helpers/memenv \ -I$(builddir) noinst_LIBRARIES = libbitcoin_server.a libbitcoin_common.a libbitcoin_cli.a +if ENABLE_WALLET +noinst_LIBRARIES += libbitcoin_wallet.a +endif bin_PROGRAMS = bitcoind bitcoin-cli @@ -33,14 +36,37 @@ obj/build.h: FORCE $(abs_top_srcdir) version.o: obj/build.h -libbitcoin_server_a_SOURCES = addrman.cpp alert.cpp \ +libbitcoin_server_a_SOURCES = \ + addrman.cpp \ + alert.cpp \ + crypter.cpp \ rpcserver.cpp \ bloom.cpp \ - chainparams.cpp checkpoints.cpp coins.cpp crypter.cpp db.cpp \ - init.cpp keystore.cpp leveldbwrapper.cpp main.cpp miner.cpp \ - net.cpp noui.cpp rpcblockchain.cpp rpcdump.cpp \ - rpcmining.cpp rpcnet.cpp rpcrawtransaction.cpp rpcwallet.cpp \ - txdb.cpp txmempool.cpp wallet.cpp walletdb.cpp $(JSON_H) \ + chainparams.cpp \ + checkpoints.cpp \ + coins.cpp \ + init.cpp \ + keystore.cpp \ + leveldbwrapper.cpp \ + main.cpp \ + net.cpp \ + noui.cpp \ + rpcblockchain.cpp \ + rpcnet.cpp \ + rpcrawtransaction.cpp \ + txdb.cpp \ + txmempool.cpp \ + $(JSON_H) \ + $(BITCOIN_CORE_H) + +libbitcoin_wallet_a_SOURCES = \ + db.cpp \ + miner.cpp \ + rpcdump.cpp \ + rpcmining.cpp \ + rpcwallet.cpp \ + wallet.cpp \ + walletdb.cpp \ $(BITCOIN_CORE_H) libbitcoin_common_a_SOURCES = \ @@ -68,6 +94,9 @@ nodist_libbitcoin_common_a_SOURCES = $(top_srcdir)/src/obj/build.h # bitcoind binary # bitcoind_LDADD = libbitcoin_server.a libbitcoin_cli.a libbitcoin_common.a leveldb/libleveldb.a leveldb/libmemenv.a \ $(BOOST_LIBS) +if ENABLE_WALLET +bitcoind_LDADD += libbitcoin_wallet.a +endif bitcoind_SOURCES = bitcoind.cpp # diff --git a/src/Makefile.include b/src/Makefile.include index 2e96a6b7d..13cffd29b 100644 --- a/src/Makefile.include +++ b/src/Makefile.include @@ -6,6 +6,7 @@ AM_CPPFLAGS = $(INCLUDES) \ AM_LDFLAGS = $(PTHREAD_CFLAGS) LIBBITCOIN_SERVER=$(top_builddir)/src/libbitcoin_server.a +LIBBITCOIN_WALLET=$(top_builddir)/src/libbitcoin_wallet.a LIBBITCOIN_COMMON=$(top_builddir)/src/libbitcoin_common.a LIBBITCOIN_CLI=$(top_builddir)/src/libbitcoin_cli.a LIBLEVELDB=$(top_builddir)/src/leveldb/libleveldb.a diff --git a/src/qt/Makefile.am b/src/qt/Makefile.am index e302adc89..08846604e 100644 --- a/src/qt/Makefile.am +++ b/src/qt/Makefile.am @@ -197,7 +197,7 @@ endif bitcoin_qt_CPPFLAGS = $(AM_CPPFLAGS) $(QT_INCLUDES) \ -I$(top_srcdir)/src/qt/forms bitcoin_qt_SOURCES = bitcoin.cpp -bitcoin_qt_LDADD = libbitcoinqt.a $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBLEVELDB) $(LIBMEMENV) \ +bitcoin_qt_LDADD = libbitcoinqt.a $(LIBBITCOIN_SERVER) $(LIBBITCOIN_WALLET) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBLEVELDB) $(LIBMEMENV) \ $(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) # forms/foo.h -> forms/ui_foo.h diff --git a/src/qt/test/Makefile.am b/src/qt/test/Makefile.am index 29247a79a..cb6874700 100644 --- a/src/qt/test/Makefile.am +++ b/src/qt/test/Makefile.am @@ -17,7 +17,7 @@ BUILT_SOURCES = $(TEST_QT_MOC_CPP) test_bitcoin_qt_CPPFLAGS = $(AM_CPPFLAGS) $(QT_INCLUDES) $(QT_TEST_INCLUDES) test_bitcoin_qt_SOURCES = test_main.cpp uritests.cpp paymentservertests.cpp $(TEST_QT_H) nodist_test_bitcoin_qt_SOURCES = $(TEST_QT_MOC_CPP) -test_bitcoin_qt_LDADD = $(LIBBITCOINQT) $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBLEVELDB) \ +test_bitcoin_qt_LDADD = $(LIBBITCOINQT) $(LIBBITCOIN_SERVER) $(LIBBITCOIN_WALLET) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBLEVELDB) \ $(LIBMEMENV) $(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QT_TEST_LIBS) \ $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) diff --git a/src/test/Makefile.am b/src/test/Makefile.am index 39f2c6a38..715020a98 100644 --- a/src/test/Makefile.am +++ b/src/test/Makefile.am @@ -21,16 +21,25 @@ BUILT_SOURCES = $(JSON_TEST_FILES:.json=.json.h) $(RAW_TEST_FILES:.raw=.raw.h) # test_bitcoin binary # test_bitcoin_CPPFLAGS = $(AM_CPPFLAGS) $(TESTDEFS) test_bitcoin_LDADD = $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBLEVELDB) $(LIBMEMENV) \ - $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(BDB_LIBS) -test_bitcoin_SOURCES = accounting_tests.cpp alert_tests.cpp \ + $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) +if ENABLE_WALLET +test_bitcoin_LDADD += $(LIBBITCOIN_WALLET) +endif +test_bitcoin_LDADD += $(BDB_LIBS) + +test_bitcoin_SOURCES = alert_tests.cpp \ allocator_tests.cpp base32_tests.cpp base58_tests.cpp base64_tests.cpp \ bignum_tests.cpp bloom_tests.cpp canonical_tests.cpp checkblock_tests.cpp \ Checkpoints_tests.cpp compress_tests.cpp DoS_tests.cpp getarg_tests.cpp \ - key_tests.cpp miner_tests.cpp mruset_tests.cpp multisig_tests.cpp \ + key_tests.cpp mruset_tests.cpp multisig_tests.cpp \ netbase_tests.cpp pmt_tests.cpp rpc_tests.cpp script_P2SH_tests.cpp \ script_tests.cpp serialize_tests.cpp sigopcount_tests.cpp test_bitcoin.cpp \ transaction_tests.cpp uint160_tests.cpp uint256_tests.cpp util_tests.cpp \ - wallet_tests.cpp sighash_tests.cpp $(JSON_TEST_FILES) $(RAW_TEST_FILES) + sighash_tests.cpp $(JSON_TEST_FILES) $(RAW_TEST_FILES) + +if ENABLE_WALLET +test_bitcoin_SOURCES += accounting_tests.cpp wallet_tests.cpp miner_tests.cpp +endif nodist_test_bitcoin_SOURCES = $(BUILT_SOURCES) From ae6ea5a6fa4a674fc1c989df6f4ec945df1aa534 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Fri, 29 Nov 2013 18:37:29 +0100 Subject: [PATCH 6/8] Update build-unix.md to mention --disable-wallet Mention the new --disable-wallet mode. Also, correct the BDB entry in the dependencies table. --- doc/build-unix.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/doc/build-unix.md b/doc/build-unix.md index 27228cdc1..1d9d96a1c 100644 --- a/doc/build-unix.md +++ b/doc/build-unix.md @@ -22,7 +22,7 @@ Dependencies Library Purpose Description ------- ------- ----------- libssl SSL Support Secure communications - libdb4.8 Berkeley DB Blockchain & wallet storage + libdb4.8 Berkeley DB Wallet storage libboost Boost C++ Library miniupnpc UPnP Support Optional firewall-jumping support qt GUI GUI toolkit @@ -178,3 +178,12 @@ Hardening enables the following features: RW- R-- RW- The STK RW- means that the stack is readable and writeable but not executable. + +Disable-wallet mode +-------------------- +When the intention is to run only a P2P node without a wallet, bitcoin may be compiled in +disable-wallet mode with: + + ./configure --disable-wallet + +In this case there is no dependency on Berkeley DB 4.8. From 829c9203874277265613185c73f96760ae4b9356 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Sat, 30 Nov 2013 06:09:32 +0100 Subject: [PATCH 7/8] Move CCryptoKeyStore to crypter.cpp This breaks the dependency on crypter for disable-wallet builds. --- src/Makefile.am | 2 +- src/crypter.cpp | 157 ++++++++++++++++++++++++++++++++++++++++++++++- src/crypter.h | 83 +++++++++++++++++++++++++ src/keystore.cpp | 152 --------------------------------------------- src/keystore.h | 83 ------------------------- 5 files changed, 240 insertions(+), 237 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 5daf62569..89879d5cd 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -39,7 +39,6 @@ version.o: obj/build.h libbitcoin_server_a_SOURCES = \ addrman.cpp \ alert.cpp \ - crypter.cpp \ rpcserver.cpp \ bloom.cpp \ chainparams.cpp \ @@ -61,6 +60,7 @@ libbitcoin_server_a_SOURCES = \ libbitcoin_wallet_a_SOURCES = \ db.cpp \ + crypter.cpp \ miner.cpp \ rpcdump.cpp \ rpcmining.cpp \ diff --git a/src/crypter.cpp b/src/crypter.cpp index 10a34ae24..4c43e3a79 100644 --- a/src/crypter.cpp +++ b/src/crypter.cpp @@ -4,9 +4,11 @@ #include "crypter.h" +#include "script.h" + #include #include - +#include #include #include @@ -117,3 +119,156 @@ bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector &vchCryptedSecret = (*mi).second.second; + CKeyingMaterial vchSecret; + if(!DecryptSecret(vMasterKeyIn, vchCryptedSecret, vchPubKey.GetHash(), vchSecret)) + return false; + if (vchSecret.size() != 32) + return false; + CKey key; + key.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed()); + if (key.GetPubKey() == vchPubKey) + break; + return false; + } + vMasterKey = vMasterKeyIn; + } + NotifyStatusChanged(this); + return true; +} + +bool CCryptoKeyStore::AddKeyPubKey(const CKey& key, const CPubKey &pubkey) +{ + { + LOCK(cs_KeyStore); + if (!IsCrypted()) + return CBasicKeyStore::AddKeyPubKey(key, pubkey); + + if (IsLocked()) + return false; + + std::vector vchCryptedSecret; + CKeyingMaterial vchSecret(key.begin(), key.end()); + if (!EncryptSecret(vMasterKey, vchSecret, pubkey.GetHash(), vchCryptedSecret)) + return false; + + if (!AddCryptedKey(pubkey, vchCryptedSecret)) + return false; + } + return true; +} + + +bool CCryptoKeyStore::AddCryptedKey(const CPubKey &vchPubKey, const std::vector &vchCryptedSecret) +{ + { + LOCK(cs_KeyStore); + if (!SetCrypted()) + return false; + + mapCryptedKeys[vchPubKey.GetID()] = make_pair(vchPubKey, vchCryptedSecret); + } + return true; +} + +bool CCryptoKeyStore::GetKey(const CKeyID &address, CKey& keyOut) const +{ + { + LOCK(cs_KeyStore); + if (!IsCrypted()) + return CBasicKeyStore::GetKey(address, keyOut); + + CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address); + if (mi != mapCryptedKeys.end()) + { + const CPubKey &vchPubKey = (*mi).second.first; + const std::vector &vchCryptedSecret = (*mi).second.second; + CKeyingMaterial vchSecret; + if (!DecryptSecret(vMasterKey, vchCryptedSecret, vchPubKey.GetHash(), vchSecret)) + return false; + if (vchSecret.size() != 32) + return false; + keyOut.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed()); + return true; + } + } + return false; +} + +bool CCryptoKeyStore::GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const +{ + { + LOCK(cs_KeyStore); + if (!IsCrypted()) + return CKeyStore::GetPubKey(address, vchPubKeyOut); + + CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address); + if (mi != mapCryptedKeys.end()) + { + vchPubKeyOut = (*mi).second.first; + return true; + } + } + return false; +} + +bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn) +{ + { + LOCK(cs_KeyStore); + if (!mapCryptedKeys.empty() || IsCrypted()) + return false; + + fUseCrypto = true; + BOOST_FOREACH(KeyMap::value_type& mKey, mapKeys) + { + const CKey &key = mKey.second; + CPubKey vchPubKey = key.GetPubKey(); + CKeyingMaterial vchSecret(key.begin(), key.end()); + std::vector vchCryptedSecret; + if (!EncryptSecret(vMasterKeyIn, vchSecret, vchPubKey.GetHash(), vchCryptedSecret)) + return false; + if (!AddCryptedKey(vchPubKey, vchCryptedSecret)) + return false; + } + mapKeys.clear(); + } + return true; +} diff --git a/src/crypter.h b/src/crypter.h index 861c4f944..4791428b4 100644 --- a/src/crypter.h +++ b/src/crypter.h @@ -7,6 +7,7 @@ #include "allocators.h" #include "serialize.h" +#include "keystore.h" class uint256; @@ -106,4 +107,86 @@ public: bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector &vchCiphertext); bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext); +/** Keystore which keeps the private keys encrypted. + * It derives from the basic key store, which is used if no encryption is active. + */ +class CCryptoKeyStore : public CBasicKeyStore +{ +private: + CryptedKeyMap mapCryptedKeys; + + CKeyingMaterial vMasterKey; + + // if fUseCrypto is true, mapKeys must be empty + // if fUseCrypto is false, vMasterKey must be empty + bool fUseCrypto; + +protected: + bool SetCrypted(); + + // will encrypt previously unencrypted keys + bool EncryptKeys(CKeyingMaterial& vMasterKeyIn); + + bool Unlock(const CKeyingMaterial& vMasterKeyIn); + +public: + CCryptoKeyStore() : fUseCrypto(false) + { + } + + bool IsCrypted() const + { + return fUseCrypto; + } + + bool IsLocked() const + { + if (!IsCrypted()) + return false; + bool result; + { + LOCK(cs_KeyStore); + result = vMasterKey.empty(); + } + return result; + } + + bool Lock(); + + virtual bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector &vchCryptedSecret); + bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey); + bool HaveKey(const CKeyID &address) const + { + { + LOCK(cs_KeyStore); + if (!IsCrypted()) + return CBasicKeyStore::HaveKey(address); + return mapCryptedKeys.count(address) > 0; + } + return false; + } + bool GetKey(const CKeyID &address, CKey& keyOut) const; + bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const; + void GetKeys(std::set &setAddress) const + { + if (!IsCrypted()) + { + CBasicKeyStore::GetKeys(setAddress); + return; + } + setAddress.clear(); + CryptedKeyMap::const_iterator mi = mapCryptedKeys.begin(); + while (mi != mapCryptedKeys.end()) + { + setAddress.insert((*mi).first); + mi++; + } + } + + /* Wallet status (encrypted, locked) changed. + * Note: Called without locks held. + */ + boost::signals2::signal NotifyStatusChanged; +}; + #endif diff --git a/src/keystore.cpp b/src/keystore.cpp index 05427291e..46402ea25 100644 --- a/src/keystore.cpp +++ b/src/keystore.cpp @@ -56,155 +56,3 @@ bool CBasicKeyStore::GetCScript(const CScriptID &hash, CScript& redeemScriptOut) return false; } -bool CCryptoKeyStore::SetCrypted() -{ - LOCK(cs_KeyStore); - if (fUseCrypto) - return true; - if (!mapKeys.empty()) - return false; - fUseCrypto = true; - return true; -} - -bool CCryptoKeyStore::Lock() -{ - if (!SetCrypted()) - return false; - - { - LOCK(cs_KeyStore); - vMasterKey.clear(); - } - - NotifyStatusChanged(this); - return true; -} - -bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn) -{ - { - LOCK(cs_KeyStore); - if (!SetCrypted()) - return false; - - CryptedKeyMap::const_iterator mi = mapCryptedKeys.begin(); - for (; mi != mapCryptedKeys.end(); ++mi) - { - const CPubKey &vchPubKey = (*mi).second.first; - const std::vector &vchCryptedSecret = (*mi).second.second; - CKeyingMaterial vchSecret; - if(!DecryptSecret(vMasterKeyIn, vchCryptedSecret, vchPubKey.GetHash(), vchSecret)) - return false; - if (vchSecret.size() != 32) - return false; - CKey key; - key.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed()); - if (key.GetPubKey() == vchPubKey) - break; - return false; - } - vMasterKey = vMasterKeyIn; - } - NotifyStatusChanged(this); - return true; -} - -bool CCryptoKeyStore::AddKeyPubKey(const CKey& key, const CPubKey &pubkey) -{ - { - LOCK(cs_KeyStore); - if (!IsCrypted()) - return CBasicKeyStore::AddKeyPubKey(key, pubkey); - - if (IsLocked()) - return false; - - std::vector vchCryptedSecret; - CKeyingMaterial vchSecret(key.begin(), key.end()); - if (!EncryptSecret(vMasterKey, vchSecret, pubkey.GetHash(), vchCryptedSecret)) - return false; - - if (!AddCryptedKey(pubkey, vchCryptedSecret)) - return false; - } - return true; -} - - -bool CCryptoKeyStore::AddCryptedKey(const CPubKey &vchPubKey, const std::vector &vchCryptedSecret) -{ - { - LOCK(cs_KeyStore); - if (!SetCrypted()) - return false; - - mapCryptedKeys[vchPubKey.GetID()] = make_pair(vchPubKey, vchCryptedSecret); - } - return true; -} - -bool CCryptoKeyStore::GetKey(const CKeyID &address, CKey& keyOut) const -{ - { - LOCK(cs_KeyStore); - if (!IsCrypted()) - return CBasicKeyStore::GetKey(address, keyOut); - - CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address); - if (mi != mapCryptedKeys.end()) - { - const CPubKey &vchPubKey = (*mi).second.first; - const std::vector &vchCryptedSecret = (*mi).second.second; - CKeyingMaterial vchSecret; - if (!DecryptSecret(vMasterKey, vchCryptedSecret, vchPubKey.GetHash(), vchSecret)) - return false; - if (vchSecret.size() != 32) - return false; - keyOut.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed()); - return true; - } - } - return false; -} - -bool CCryptoKeyStore::GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const -{ - { - LOCK(cs_KeyStore); - if (!IsCrypted()) - return CKeyStore::GetPubKey(address, vchPubKeyOut); - - CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address); - if (mi != mapCryptedKeys.end()) - { - vchPubKeyOut = (*mi).second.first; - return true; - } - } - return false; -} - -bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn) -{ - { - LOCK(cs_KeyStore); - if (!mapCryptedKeys.empty() || IsCrypted()) - return false; - - fUseCrypto = true; - BOOST_FOREACH(KeyMap::value_type& mKey, mapKeys) - { - const CKey &key = mKey.second; - CPubKey vchPubKey = key.GetPubKey(); - CKeyingMaterial vchSecret(key.begin(), key.end()); - std::vector vchCryptedSecret; - if (!EncryptSecret(vMasterKeyIn, vchSecret, vchPubKey.GetHash(), vchCryptedSecret)) - return false; - if (!AddCryptedKey(vchPubKey, vchCryptedSecret)) - return false; - } - mapKeys.clear(); - } - return true; -} diff --git a/src/keystore.h b/src/keystore.h index 8d936bcab..0d55e6c81 100644 --- a/src/keystore.h +++ b/src/keystore.h @@ -93,87 +93,4 @@ public: typedef std::vector > CKeyingMaterial; typedef std::map > > CryptedKeyMap; - -/** Keystore which keeps the private keys encrypted. - * It derives from the basic key store, which is used if no encryption is active. - */ -class CCryptoKeyStore : public CBasicKeyStore -{ -private: - CryptedKeyMap mapCryptedKeys; - - CKeyingMaterial vMasterKey; - - // if fUseCrypto is true, mapKeys must be empty - // if fUseCrypto is false, vMasterKey must be empty - bool fUseCrypto; - -protected: - bool SetCrypted(); - - // will encrypt previously unencrypted keys - bool EncryptKeys(CKeyingMaterial& vMasterKeyIn); - - bool Unlock(const CKeyingMaterial& vMasterKeyIn); - -public: - CCryptoKeyStore() : fUseCrypto(false) - { - } - - bool IsCrypted() const - { - return fUseCrypto; - } - - bool IsLocked() const - { - if (!IsCrypted()) - return false; - bool result; - { - LOCK(cs_KeyStore); - result = vMasterKey.empty(); - } - return result; - } - - bool Lock(); - - virtual bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector &vchCryptedSecret); - bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey); - bool HaveKey(const CKeyID &address) const - { - { - LOCK(cs_KeyStore); - if (!IsCrypted()) - return CBasicKeyStore::HaveKey(address); - return mapCryptedKeys.count(address) > 0; - } - return false; - } - bool GetKey(const CKeyID &address, CKey& keyOut) const; - bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const; - void GetKeys(std::set &setAddress) const - { - if (!IsCrypted()) - { - CBasicKeyStore::GetKeys(setAddress); - return; - } - setAddress.clear(); - CryptedKeyMap::const_iterator mi = mapCryptedKeys.begin(); - while (mi != mapCryptedKeys.end()) - { - setAddress.insert((*mi).first); - mi++; - } - } - - /* Wallet status (encrypted, locked) changed. - * Note: Called without locks held. - */ - boost::signals2::signal NotifyStatusChanged; -}; - #endif From 5094f8d46fe3a0f0bcee913d6f1586dcef35749e Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Sat, 30 Nov 2013 11:10:35 +0100 Subject: [PATCH 8/8] Split off rpc_wallet_tests Split wallet tests from other RPC tests. Now no #ifdef ENABLE_WALLET are needed anymore in either file. --- src/test/Makefile.am | 2 +- src/test/rpc_tests.cpp | 74 ++----------------------------- src/test/rpc_wallet_tests.cpp | 82 +++++++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 72 deletions(-) create mode 100644 src/test/rpc_wallet_tests.cpp diff --git a/src/test/Makefile.am b/src/test/Makefile.am index 715020a98..dccd264e5 100644 --- a/src/test/Makefile.am +++ b/src/test/Makefile.am @@ -38,7 +38,7 @@ test_bitcoin_SOURCES = alert_tests.cpp \ sighash_tests.cpp $(JSON_TEST_FILES) $(RAW_TEST_FILES) if ENABLE_WALLET -test_bitcoin_SOURCES += accounting_tests.cpp wallet_tests.cpp miner_tests.cpp +test_bitcoin_SOURCES += accounting_tests.cpp wallet_tests.cpp miner_tests.cpp rpc_wallet_tests.cpp endif nodist_test_bitcoin_SOURCES = $(BUILT_SOURCES) diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp index e56aae225..29195545d 100644 --- a/src/test/rpc_tests.cpp +++ b/src/test/rpc_tests.cpp @@ -9,9 +9,7 @@ using namespace std; using namespace json_spirit; -BOOST_AUTO_TEST_SUITE(rpc_tests) - -static Array +Array createArgs(int nRequired, const char* address1=NULL, const char* address2=NULL) { Array result; @@ -23,46 +21,7 @@ createArgs(int nRequired, const char* address1=NULL, const char* address2=NULL) return result; } -#ifdef ENABLE_WALLET -BOOST_AUTO_TEST_CASE(rpc_addmultisig) -{ - rpcfn_type addmultisig = tableRPC["addmultisigaddress"]->actor; - - // old, 65-byte-long: - const char address1Hex[] = "0434e3e09f49ea168c5bbf53f877ff4206923858aab7c7e1df25bc263978107c95e35065a27ef6f1b27222db0ec97e0e895eaca603d3ee0d4c060ce3d8a00286c8"; - // new, compressed: - const char address2Hex[] = "0388c2037017c62240b6b72ac1a2a5f94da790596ebd06177c8572752922165cb4"; - - Value v; - CBitcoinAddress address; - BOOST_CHECK_NO_THROW(v = addmultisig(createArgs(1, address1Hex), false)); - address.SetString(v.get_str()); - BOOST_CHECK(address.IsValid() && address.IsScript()); - - BOOST_CHECK_NO_THROW(v = addmultisig(createArgs(1, address1Hex, address2Hex), false)); - address.SetString(v.get_str()); - BOOST_CHECK(address.IsValid() && address.IsScript()); - - BOOST_CHECK_NO_THROW(v = addmultisig(createArgs(2, address1Hex, address2Hex), false)); - address.SetString(v.get_str()); - BOOST_CHECK(address.IsValid() && address.IsScript()); - - BOOST_CHECK_THROW(addmultisig(createArgs(0), false), runtime_error); - BOOST_CHECK_THROW(addmultisig(createArgs(1), false), runtime_error); - BOOST_CHECK_THROW(addmultisig(createArgs(2, address1Hex), false), runtime_error); - - BOOST_CHECK_THROW(addmultisig(createArgs(1, ""), false), runtime_error); - BOOST_CHECK_THROW(addmultisig(createArgs(1, "NotAValidPubkey"), false), runtime_error); - - string short1(address1Hex, address1Hex+sizeof(address1Hex)-2); // last byte missing - BOOST_CHECK_THROW(addmultisig(createArgs(2, short1.c_str()), false), runtime_error); - - string short2(address1Hex+1, address1Hex+sizeof(address1Hex)); // first byte missing - BOOST_CHECK_THROW(addmultisig(createArgs(2, short2.c_str()), false), runtime_error); -} -#endif - -static Value CallRPC(string args) +Value CallRPC(string args) { vector vArgs; boost::split(vArgs, args, boost::is_any_of(" \t")); @@ -81,35 +40,8 @@ static Value CallRPC(string args) } } -#ifdef ENABLE_WALLET -BOOST_AUTO_TEST_CASE(rpc_wallet) -{ - // Test RPC calls for various wallet statistics - Value r; - BOOST_CHECK_NO_THROW(CallRPC("listunspent")); - BOOST_CHECK_THROW(CallRPC("listunspent string"), runtime_error); - BOOST_CHECK_THROW(CallRPC("listunspent 0 string"), runtime_error); - BOOST_CHECK_THROW(CallRPC("listunspent 0 1 not_array"), runtime_error); - BOOST_CHECK_THROW(CallRPC("listunspent 0 1 [] extra"), runtime_error); - BOOST_CHECK_NO_THROW(r=CallRPC("listunspent 0 1 []")); - BOOST_CHECK(r.get_array().empty()); - - BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaddress")); - BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaddress 0")); - BOOST_CHECK_THROW(CallRPC("listreceivedbyaddress not_int"), runtime_error); - BOOST_CHECK_THROW(CallRPC("listreceivedbyaddress 0 not_bool"), runtime_error); - BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaddress 0 true")); - BOOST_CHECK_THROW(CallRPC("listreceivedbyaddress 0 true extra"), runtime_error); - - BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount")); - BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount 0")); - BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount not_int"), runtime_error); - BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount 0 not_bool"), runtime_error); - BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount 0 true")); - BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount 0 true extra"), runtime_error); -} -#endif +BOOST_AUTO_TEST_SUITE(rpc_tests) BOOST_AUTO_TEST_CASE(rpc_rawparams) { diff --git a/src/test/rpc_wallet_tests.cpp b/src/test/rpc_wallet_tests.cpp new file mode 100644 index 000000000..2cf0fb350 --- /dev/null +++ b/src/test/rpc_wallet_tests.cpp @@ -0,0 +1,82 @@ +#include "rpcserver.h" +#include "rpcclient.h" + +#include "base58.h" + +#include +#include + +using namespace std; +using namespace json_spirit; + +extern Array createArgs(int nRequired, const char* address1=NULL, const char* address2=NULL); +extern Value CallRPC(string args); + +BOOST_AUTO_TEST_SUITE(rpc_wallet_tests) + +BOOST_AUTO_TEST_CASE(rpc_addmultisig) +{ + rpcfn_type addmultisig = tableRPC["addmultisigaddress"]->actor; + + // old, 65-byte-long: + const char address1Hex[] = "0434e3e09f49ea168c5bbf53f877ff4206923858aab7c7e1df25bc263978107c95e35065a27ef6f1b27222db0ec97e0e895eaca603d3ee0d4c060ce3d8a00286c8"; + // new, compressed: + const char address2Hex[] = "0388c2037017c62240b6b72ac1a2a5f94da790596ebd06177c8572752922165cb4"; + + Value v; + CBitcoinAddress address; + BOOST_CHECK_NO_THROW(v = addmultisig(createArgs(1, address1Hex), false)); + address.SetString(v.get_str()); + BOOST_CHECK(address.IsValid() && address.IsScript()); + + BOOST_CHECK_NO_THROW(v = addmultisig(createArgs(1, address1Hex, address2Hex), false)); + address.SetString(v.get_str()); + BOOST_CHECK(address.IsValid() && address.IsScript()); + + BOOST_CHECK_NO_THROW(v = addmultisig(createArgs(2, address1Hex, address2Hex), false)); + address.SetString(v.get_str()); + BOOST_CHECK(address.IsValid() && address.IsScript()); + + BOOST_CHECK_THROW(addmultisig(createArgs(0), false), runtime_error); + BOOST_CHECK_THROW(addmultisig(createArgs(1), false), runtime_error); + BOOST_CHECK_THROW(addmultisig(createArgs(2, address1Hex), false), runtime_error); + + BOOST_CHECK_THROW(addmultisig(createArgs(1, ""), false), runtime_error); + BOOST_CHECK_THROW(addmultisig(createArgs(1, "NotAValidPubkey"), false), runtime_error); + + string short1(address1Hex, address1Hex+sizeof(address1Hex)-2); // last byte missing + BOOST_CHECK_THROW(addmultisig(createArgs(2, short1.c_str()), false), runtime_error); + + string short2(address1Hex+1, address1Hex+sizeof(address1Hex)); // first byte missing + BOOST_CHECK_THROW(addmultisig(createArgs(2, short2.c_str()), false), runtime_error); +} + +BOOST_AUTO_TEST_CASE(rpc_wallet) +{ + // Test RPC calls for various wallet statistics + Value r; + + BOOST_CHECK_NO_THROW(CallRPC("listunspent")); + BOOST_CHECK_THROW(CallRPC("listunspent string"), runtime_error); + BOOST_CHECK_THROW(CallRPC("listunspent 0 string"), runtime_error); + BOOST_CHECK_THROW(CallRPC("listunspent 0 1 not_array"), runtime_error); + BOOST_CHECK_THROW(CallRPC("listunspent 0 1 [] extra"), runtime_error); + BOOST_CHECK_NO_THROW(r=CallRPC("listunspent 0 1 []")); + BOOST_CHECK(r.get_array().empty()); + + BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaddress")); + BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaddress 0")); + BOOST_CHECK_THROW(CallRPC("listreceivedbyaddress not_int"), runtime_error); + BOOST_CHECK_THROW(CallRPC("listreceivedbyaddress 0 not_bool"), runtime_error); + BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaddress 0 true")); + BOOST_CHECK_THROW(CallRPC("listreceivedbyaddress 0 true extra"), runtime_error); + + BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount")); + BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount 0")); + BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount not_int"), runtime_error); + BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount 0 not_bool"), runtime_error); + BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount 0 true")); + BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount 0 true extra"), runtime_error); +} + +BOOST_AUTO_TEST_SUITE_END()