diff options
Diffstat (limited to 'src/wallet/rpcwallet.cpp')
-rw-r--r-- | src/wallet/rpcwallet.cpp | 638 |
1 files changed, 372 insertions, 266 deletions
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index d785c95ae0..5ef93ac532 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -29,20 +29,21 @@ using namespace std; -int64_t nWalletUnlockTime; -static CCriticalSection cs_nWalletUnlockTime; +CWallet *GetWalletForJSONRPCRequest(const JSONRPCRequest& request) +{ + return pwalletMain; +} -std::string HelpRequiringPassphrase() +std::string HelpRequiringPassphrase(CWallet * const pwallet) { - return pwalletMain && pwalletMain->IsCrypted() + return pwallet && pwallet->IsCrypted() ? "\nRequires wallet passphrase to be set with walletpassphrase call." : ""; } -bool EnsureWalletIsAvailable(bool avoidException) +bool EnsureWalletIsAvailable(CWallet * const pwallet, bool avoidException) { - if (!pwalletMain) - { + if (!pwallet) { if (!avoidException) throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)"); else @@ -51,10 +52,11 @@ bool EnsureWalletIsAvailable(bool avoidException) return true; } -void EnsureWalletIsUnlocked() +void EnsureWalletIsUnlocked(CWallet * const pwallet) { - if (pwalletMain->IsLocked()) + if (pwallet->IsLocked()) { throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first."); + } } void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry) @@ -106,8 +108,10 @@ string AccountFromValue(const UniValue& value) UniValue getnewaddress(const JSONRPCRequest& request) { - if (!EnsureWalletIsAvailable(request.fHelp)) + CWallet * const pwallet = GetWalletForJSONRPCRequest(request); + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; + } if (request.fHelp || request.params.size() > 1) throw runtime_error( @@ -124,32 +128,34 @@ UniValue getnewaddress(const JSONRPCRequest& request) + HelpExampleRpc("getnewaddress", "") ); - LOCK2(cs_main, pwalletMain->cs_wallet); + LOCK2(cs_main, pwallet->cs_wallet); // Parse the account first so we don't generate a key if there's an error string strAccount; if (request.params.size() > 0) strAccount = AccountFromValue(request.params[0]); - if (!pwalletMain->IsLocked()) - pwalletMain->TopUpKeyPool(); + if (!pwallet->IsLocked()) { + pwallet->TopUpKeyPool(); + } // Generate a new key that is added to wallet CPubKey newKey; - if (!pwalletMain->GetKeyFromPool(newKey)) + if (!pwallet->GetKeyFromPool(newKey)) { throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first"); + } CKeyID keyID = newKey.GetID(); - pwalletMain->SetAddressBook(keyID, strAccount, "receive"); + pwallet->SetAddressBook(keyID, strAccount, "receive"); return CBitcoinAddress(keyID).ToString(); } -CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false) +CBitcoinAddress GetAccountAddress(CWallet * const pwallet, string strAccount, bool bForceNew=false) { CPubKey pubKey; - if (!pwalletMain->GetAccountPubkey(pubKey, strAccount, bForceNew)) { + if (!pwallet->GetAccountPubkey(pubKey, strAccount, bForceNew)) { throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first"); } @@ -158,8 +164,10 @@ CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false) UniValue getaccountaddress(const JSONRPCRequest& request) { - if (!EnsureWalletIsAvailable(request.fHelp)) + CWallet * const pwallet = GetWalletForJSONRPCRequest(request); + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; + } if (request.fHelp || request.params.size() != 1) throw runtime_error( @@ -176,22 +184,24 @@ UniValue getaccountaddress(const JSONRPCRequest& request) + HelpExampleRpc("getaccountaddress", "\"myaccount\"") ); - LOCK2(cs_main, pwalletMain->cs_wallet); + LOCK2(cs_main, pwallet->cs_wallet); // Parse the account first so we don't generate a key if there's an error string strAccount = AccountFromValue(request.params[0]); UniValue ret(UniValue::VSTR); - ret = GetAccountAddress(strAccount).ToString(); + ret = GetAccountAddress(pwallet, strAccount).ToString(); return ret; } UniValue getrawchangeaddress(const JSONRPCRequest& request) { - if (!EnsureWalletIsAvailable(request.fHelp)) + CWallet * const pwallet = GetWalletForJSONRPCRequest(request); + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; + } if (request.fHelp || request.params.size() > 1) throw runtime_error( @@ -205,12 +215,13 @@ UniValue getrawchangeaddress(const JSONRPCRequest& request) + HelpExampleRpc("getrawchangeaddress", "") ); - LOCK2(cs_main, pwalletMain->cs_wallet); + LOCK2(cs_main, pwallet->cs_wallet); - if (!pwalletMain->IsLocked()) - pwalletMain->TopUpKeyPool(); + if (!pwallet->IsLocked()) { + pwallet->TopUpKeyPool(); + } - CReserveKey reservekey(pwalletMain); + CReserveKey reservekey(pwallet); CPubKey vchPubKey; if (!reservekey.GetReservedKey(vchPubKey)) throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first"); @@ -225,8 +236,10 @@ UniValue getrawchangeaddress(const JSONRPCRequest& request) UniValue setaccount(const JSONRPCRequest& request) { - if (!EnsureWalletIsAvailable(request.fHelp)) + CWallet * const pwallet = GetWalletForJSONRPCRequest(request); + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; + } if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) throw runtime_error( @@ -240,7 +253,7 @@ UniValue setaccount(const JSONRPCRequest& request) + HelpExampleRpc("setaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", \"tabby\"") ); - LOCK2(cs_main, pwalletMain->cs_wallet); + LOCK2(cs_main, pwallet->cs_wallet); CBitcoinAddress address(request.params[0].get_str()); if (!address.IsValid()) @@ -251,16 +264,15 @@ UniValue setaccount(const JSONRPCRequest& request) strAccount = AccountFromValue(request.params[1]); // Only add the account if the address is yours. - if (IsMine(*pwalletMain, address.Get())) - { + if (IsMine(*pwallet, address.Get())) { // Detect when changing the account of an address that is the 'unused current key' of another account: - if (pwalletMain->mapAddressBook.count(address.Get())) - { - string strOldAccount = pwalletMain->mapAddressBook[address.Get()].name; - if (address == GetAccountAddress(strOldAccount)) - GetAccountAddress(strOldAccount, true); + if (pwallet->mapAddressBook.count(address.Get())) { + string strOldAccount = pwallet->mapAddressBook[address.Get()].name; + if (address == GetAccountAddress(pwallet, strOldAccount)) { + GetAccountAddress(pwallet, strOldAccount, true); + } } - pwalletMain->SetAddressBook(address.Get(), strAccount, "receive"); + pwallet->SetAddressBook(address.Get(), strAccount, "receive"); } else throw JSONRPCError(RPC_MISC_ERROR, "setaccount can only be used with own address"); @@ -271,8 +283,10 @@ UniValue setaccount(const JSONRPCRequest& request) UniValue getaccount(const JSONRPCRequest& request) { - if (!EnsureWalletIsAvailable(request.fHelp)) + CWallet * const pwallet = GetWalletForJSONRPCRequest(request); + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; + } if (request.fHelp || request.params.size() != 1) throw runtime_error( @@ -287,24 +301,27 @@ UniValue getaccount(const JSONRPCRequest& request) + HelpExampleRpc("getaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\"") ); - LOCK2(cs_main, pwalletMain->cs_wallet); + LOCK2(cs_main, pwallet->cs_wallet); CBitcoinAddress address(request.params[0].get_str()); if (!address.IsValid()) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address"); string strAccount; - map<CTxDestination, CAddressBookData>::iterator mi = pwalletMain->mapAddressBook.find(address.Get()); - if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.name.empty()) + map<CTxDestination, CAddressBookData>::iterator mi = pwallet->mapAddressBook.find(address.Get()); + if (mi != pwallet->mapAddressBook.end() && !(*mi).second.name.empty()) { strAccount = (*mi).second.name; + } return strAccount; } UniValue getaddressesbyaccount(const JSONRPCRequest& request) { - if (!EnsureWalletIsAvailable(request.fHelp)) + CWallet * const pwallet = GetWalletForJSONRPCRequest(request); + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; + } if (request.fHelp || request.params.size() != 1) throw runtime_error( @@ -322,14 +339,13 @@ UniValue getaddressesbyaccount(const JSONRPCRequest& request) + HelpExampleRpc("getaddressesbyaccount", "\"tabby\"") ); - LOCK2(cs_main, pwalletMain->cs_wallet); + LOCK2(cs_main, pwallet->cs_wallet); string strAccount = AccountFromValue(request.params[0]); // Find all addresses that have the given account UniValue ret(UniValue::VARR); - BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, CAddressBookData)& item, pwalletMain->mapAddressBook) - { + for (const std::pair<CBitcoinAddress, CAddressBookData>& item : pwallet->mapAddressBook) { const CBitcoinAddress& address = item.first; const string& strName = item.second.name; if (strName == strAccount) @@ -338,9 +354,9 @@ UniValue getaddressesbyaccount(const JSONRPCRequest& request) return ret; } -static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtractFeeFromAmount, CWalletTx& wtxNew) +static void SendMoney(CWallet * const pwallet, const CTxDestination &address, CAmount nValue, bool fSubtractFeeFromAmount, CWalletTx& wtxNew) { - CAmount curBalance = pwalletMain->GetBalance(); + CAmount curBalance = pwallet->GetBalance(); // Check amount if (nValue <= 0) @@ -349,27 +365,28 @@ static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtr if (nValue > curBalance) throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds"); - if (pwalletMain->GetBroadcastTransactions() && !g_connman) + if (pwallet->GetBroadcastTransactions() && !g_connman) { throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); + } // Parse Bitcoin address CScript scriptPubKey = GetScriptForDestination(address); // Create and send the transaction - CReserveKey reservekey(pwalletMain); + CReserveKey reservekey(pwallet); CAmount nFeeRequired; std::string strError; vector<CRecipient> vecSend; int nChangePosRet = -1; CRecipient recipient = {scriptPubKey, nValue, fSubtractFeeFromAmount}; vecSend.push_back(recipient); - if (!pwalletMain->CreateTransaction(vecSend, wtxNew, reservekey, nFeeRequired, nChangePosRet, strError)) { + if (!pwallet->CreateTransaction(vecSend, wtxNew, reservekey, nFeeRequired, nChangePosRet, strError)) { if (!fSubtractFeeFromAmount && nValue + nFeeRequired > curBalance) strError = strprintf("Error: This transaction requires a transaction fee of at least %s", FormatMoney(nFeeRequired)); throw JSONRPCError(RPC_WALLET_ERROR, strError); } CValidationState state; - if (!pwalletMain->CommitTransaction(wtxNew, reservekey, g_connman.get(), state)) { + if (!pwallet->CommitTransaction(wtxNew, reservekey, g_connman.get(), state)) { strError = strprintf("Error: The transaction was rejected! Reason given: %s", state.GetRejectReason()); throw JSONRPCError(RPC_WALLET_ERROR, strError); } @@ -377,14 +394,16 @@ static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtr UniValue sendtoaddress(const JSONRPCRequest& request) { - if (!EnsureWalletIsAvailable(request.fHelp)) + CWallet * const pwallet = GetWalletForJSONRPCRequest(request); + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; + } if (request.fHelp || request.params.size() < 2 || request.params.size() > 5) throw runtime_error( "sendtoaddress \"address\" amount ( \"comment\" \"comment_to\" subtractfeefromamount )\n" "\nSend an amount to a given address.\n" - + HelpRequiringPassphrase() + + + HelpRequiringPassphrase(pwallet) + "\nArguments:\n" "1. \"address\" (string, required) The bitcoin address to send to.\n" "2. \"amount\" (numeric or string, required) The amount in " + CURRENCY_UNIT + " to send. eg 0.1\n" @@ -404,7 +423,7 @@ UniValue sendtoaddress(const JSONRPCRequest& request) + HelpExampleRpc("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", 0.1, \"donation\", \"seans outpost\"") ); - LOCK2(cs_main, pwalletMain->cs_wallet); + LOCK2(cs_main, pwallet->cs_wallet); CBitcoinAddress address(request.params[0].get_str()); if (!address.IsValid()) @@ -426,17 +445,19 @@ UniValue sendtoaddress(const JSONRPCRequest& request) if (request.params.size() > 4) fSubtractFeeFromAmount = request.params[4].get_bool(); - EnsureWalletIsUnlocked(); + EnsureWalletIsUnlocked(pwallet); - SendMoney(address.Get(), nAmount, fSubtractFeeFromAmount, wtx); + SendMoney(pwallet, address.Get(), nAmount, fSubtractFeeFromAmount, wtx); return wtx.GetHash().GetHex(); } UniValue listaddressgroupings(const JSONRPCRequest& request) { - if (!EnsureWalletIsAvailable(request.fHelp)) + CWallet * const pwallet = GetWalletForJSONRPCRequest(request); + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; + } if (request.fHelp) throw runtime_error( @@ -461,12 +482,11 @@ UniValue listaddressgroupings(const JSONRPCRequest& request) + HelpExampleRpc("listaddressgroupings", "") ); - LOCK2(cs_main, pwalletMain->cs_wallet); + LOCK2(cs_main, pwallet->cs_wallet); UniValue jsonGroupings(UniValue::VARR); - map<CTxDestination, CAmount> balances = pwalletMain->GetAddressBalances(); - BOOST_FOREACH(set<CTxDestination> grouping, pwalletMain->GetAddressGroupings()) - { + map<CTxDestination, CAmount> balances = pwallet->GetAddressBalances(); + for (set<CTxDestination> grouping : pwallet->GetAddressGroupings()) { UniValue jsonGrouping(UniValue::VARR); BOOST_FOREACH(CTxDestination address, grouping) { @@ -474,8 +494,9 @@ UniValue listaddressgroupings(const JSONRPCRequest& request) addressInfo.push_back(CBitcoinAddress(address).ToString()); addressInfo.push_back(ValueFromAmount(balances[address])); { - if (pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get()) != pwalletMain->mapAddressBook.end()) - addressInfo.push_back(pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get())->second.name); + if (pwallet->mapAddressBook.find(CBitcoinAddress(address).Get()) != pwallet->mapAddressBook.end()) { + addressInfo.push_back(pwallet->mapAddressBook.find(CBitcoinAddress(address).Get())->second.name); + } } jsonGrouping.push_back(addressInfo); } @@ -486,14 +507,16 @@ UniValue listaddressgroupings(const JSONRPCRequest& request) UniValue signmessage(const JSONRPCRequest& request) { - if (!EnsureWalletIsAvailable(request.fHelp)) + CWallet * const pwallet = GetWalletForJSONRPCRequest(request); + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; + } if (request.fHelp || request.params.size() != 2) throw runtime_error( "signmessage \"address\" \"message\"\n" "\nSign a message with the private key of an address" - + HelpRequiringPassphrase() + "\n" + + HelpRequiringPassphrase(pwallet) + "\n" "\nArguments:\n" "1. \"address\" (string, required) The bitcoin address to use for the private key.\n" "2. \"message\" (string, required) The message to create a signature of.\n" @@ -510,9 +533,9 @@ UniValue signmessage(const JSONRPCRequest& request) + HelpExampleRpc("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", \"my message\"") ); - LOCK2(cs_main, pwalletMain->cs_wallet); + LOCK2(cs_main, pwallet->cs_wallet); - EnsureWalletIsUnlocked(); + EnsureWalletIsUnlocked(pwallet); string strAddress = request.params[0].get_str(); string strMessage = request.params[1].get_str(); @@ -526,8 +549,9 @@ UniValue signmessage(const JSONRPCRequest& request) throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key"); CKey key; - if (!pwalletMain->GetKey(keyID, key)) + if (!pwallet->GetKey(keyID, key)) { throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available"); + } CHashWriter ss(SER_GETHASH, 0); ss << strMessageMagic; @@ -542,8 +566,10 @@ UniValue signmessage(const JSONRPCRequest& request) UniValue getreceivedbyaddress(const JSONRPCRequest& request) { - if (!EnsureWalletIsAvailable(request.fHelp)) + CWallet * const pwallet = GetWalletForJSONRPCRequest(request); + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; + } if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) throw runtime_error( @@ -565,15 +591,16 @@ UniValue getreceivedbyaddress(const JSONRPCRequest& request) + HelpExampleRpc("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", 6") ); - LOCK2(cs_main, pwalletMain->cs_wallet); + LOCK2(cs_main, pwallet->cs_wallet); // Bitcoin address CBitcoinAddress address = CBitcoinAddress(request.params[0].get_str()); if (!address.IsValid()) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address"); CScript scriptPubKey = GetScriptForDestination(address.Get()); - if (!IsMine(*pwalletMain, scriptPubKey)) + if (!IsMine(*pwallet, scriptPubKey)) { return ValueFromAmount(0); + } // Minimum confirmations int nMinDepth = 1; @@ -582,9 +609,8 @@ UniValue getreceivedbyaddress(const JSONRPCRequest& request) // Tally CAmount nAmount = 0; - for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) - { - const CWalletTx& wtx = (*it).second; + for (const std::pair<uint256, CWalletTx>& pairWtx : pwallet->mapWallet) { + const CWalletTx& wtx = pairWtx.second; if (wtx.IsCoinBase() || !CheckFinalTx(*wtx.tx)) continue; @@ -600,8 +626,10 @@ UniValue getreceivedbyaddress(const JSONRPCRequest& request) UniValue getreceivedbyaccount(const JSONRPCRequest& request) { - if (!EnsureWalletIsAvailable(request.fHelp)) + CWallet * const pwallet = GetWalletForJSONRPCRequest(request); + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; + } if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) throw runtime_error( @@ -623,7 +651,7 @@ UniValue getreceivedbyaccount(const JSONRPCRequest& request) + HelpExampleRpc("getreceivedbyaccount", "\"tabby\", 6") ); - LOCK2(cs_main, pwalletMain->cs_wallet); + LOCK2(cs_main, pwallet->cs_wallet); // Minimum confirmations int nMinDepth = 1; @@ -632,22 +660,22 @@ UniValue getreceivedbyaccount(const JSONRPCRequest& request) // Get the set of pub keys assigned to account string strAccount = AccountFromValue(request.params[0]); - set<CTxDestination> setAddress = pwalletMain->GetAccountAddresses(strAccount); + set<CTxDestination> setAddress = pwallet->GetAccountAddresses(strAccount); // Tally CAmount nAmount = 0; - for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) - { - const CWalletTx& wtx = (*it).second; + for (const std::pair<uint256, CWalletTx>& pairWtx : pwallet->mapWallet) { + const CWalletTx& wtx = pairWtx.second; if (wtx.IsCoinBase() || !CheckFinalTx(*wtx.tx)) continue; BOOST_FOREACH(const CTxOut& txout, wtx.tx->vout) { CTxDestination address; - if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*pwalletMain, address) && setAddress.count(address)) + if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*pwallet, address) && setAddress.count(address)) { if (wtx.GetDepthInMainChain() >= nMinDepth) nAmount += txout.nValue; + } } } @@ -657,8 +685,10 @@ UniValue getreceivedbyaccount(const JSONRPCRequest& request) UniValue getbalance(const JSONRPCRequest& request) { - if (!EnsureWalletIsAvailable(request.fHelp)) + CWallet * const pwallet = GetWalletForJSONRPCRequest(request); + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; + } if (request.fHelp || request.params.size() > 3) throw runtime_error( @@ -693,10 +723,10 @@ UniValue getbalance(const JSONRPCRequest& request) + HelpExampleRpc("getbalance", "\"*\", 6") ); - LOCK2(cs_main, pwalletMain->cs_wallet); + LOCK2(cs_main, pwallet->cs_wallet); if (request.params.size() == 0) - return ValueFromAmount(pwalletMain->GetBalance()); + return ValueFromAmount(pwallet->GetBalance()); int nMinDepth = 1; if (request.params.size() > 1) @@ -714,9 +744,8 @@ UniValue getbalance(const JSONRPCRequest& request) // TxIns spending from the wallet. This also has fewer restrictions on // which unconfirmed transactions are considered trusted. CAmount nBalance = 0; - for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) - { - const CWalletTx& wtx = (*it).second; + for (const std::pair<uint256, CWalletTx>& pairWtx : pwallet->mapWallet) { + const CWalletTx& wtx = pairWtx.second; if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0) continue; @@ -739,31 +768,35 @@ UniValue getbalance(const JSONRPCRequest& request) string strAccount = AccountFromValue(request.params[0]); - CAmount nBalance = pwalletMain->GetAccountBalance(strAccount, nMinDepth, filter); + CAmount nBalance = pwallet->GetAccountBalance(strAccount, nMinDepth, filter); return ValueFromAmount(nBalance); } UniValue getunconfirmedbalance(const JSONRPCRequest &request) { - if (!EnsureWalletIsAvailable(request.fHelp)) + CWallet * const pwallet = GetWalletForJSONRPCRequest(request); + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; + } if (request.fHelp || request.params.size() > 0) throw runtime_error( "getunconfirmedbalance\n" "Returns the server's total unconfirmed balance\n"); - LOCK2(cs_main, pwalletMain->cs_wallet); + LOCK2(cs_main, pwallet->cs_wallet); - return ValueFromAmount(pwalletMain->GetUnconfirmedBalance()); + return ValueFromAmount(pwallet->GetUnconfirmedBalance()); } UniValue movecmd(const JSONRPCRequest& request) { - if (!EnsureWalletIsAvailable(request.fHelp)) + CWallet * const pwallet = GetWalletForJSONRPCRequest(request); + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; + } if (request.fHelp || request.params.size() < 3 || request.params.size() > 5) throw runtime_error( @@ -786,7 +819,7 @@ UniValue movecmd(const JSONRPCRequest& request) + HelpExampleRpc("move", "\"timotei\", \"akiko\", 0.01, 6, \"happy birthday!\"") ); - LOCK2(cs_main, pwalletMain->cs_wallet); + LOCK2(cs_main, pwallet->cs_wallet); string strFrom = AccountFromValue(request.params[0]); string strTo = AccountFromValue(request.params[1]); @@ -800,8 +833,9 @@ UniValue movecmd(const JSONRPCRequest& request) if (request.params.size() > 4) strComment = request.params[4].get_str(); - if (!pwalletMain->AccountMove(strFrom, strTo, nAmount, strComment)) + if (!pwallet->AccountMove(strFrom, strTo, nAmount, strComment)) { throw JSONRPCError(RPC_DATABASE_ERROR, "database error"); + } return true; } @@ -809,14 +843,16 @@ UniValue movecmd(const JSONRPCRequest& request) UniValue sendfrom(const JSONRPCRequest& request) { - if (!EnsureWalletIsAvailable(request.fHelp)) + CWallet * const pwallet = GetWalletForJSONRPCRequest(request); + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; + } if (request.fHelp || request.params.size() < 3 || request.params.size() > 6) throw runtime_error( "sendfrom \"fromaccount\" \"toaddress\" amount ( minconf \"comment\" \"comment_to\" )\n" "\nDEPRECATED (use sendtoaddress). Sent an amount from an account to a bitcoin address." - + HelpRequiringPassphrase() + "\n" + + HelpRequiringPassphrase(pwallet) + "\n" "\nArguments:\n" "1. \"fromaccount\" (string, required) The name of the account to send funds from. May be the default account using \"\".\n" " Specifying an account does not influence coin selection, but it does associate the newly created\n" @@ -841,7 +877,7 @@ UniValue sendfrom(const JSONRPCRequest& request) + HelpExampleRpc("sendfrom", "\"tabby\", \"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", 0.01, 6, \"donation\", \"seans outpost\"") ); - LOCK2(cs_main, pwalletMain->cs_wallet); + LOCK2(cs_main, pwallet->cs_wallet); string strAccount = AccountFromValue(request.params[0]); CBitcoinAddress address(request.params[1].get_str()); @@ -861,14 +897,14 @@ UniValue sendfrom(const JSONRPCRequest& request) if (request.params.size() > 5 && !request.params[5].isNull() && !request.params[5].get_str().empty()) wtx.mapValue["to"] = request.params[5].get_str(); - EnsureWalletIsUnlocked(); + EnsureWalletIsUnlocked(pwallet); // Check funds - CAmount nBalance = pwalletMain->GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE); + CAmount nBalance = pwallet->GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE); if (nAmount > nBalance) throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds"); - SendMoney(address.Get(), nAmount, false, wtx); + SendMoney(pwallet, address.Get(), nAmount, false, wtx); return wtx.GetHash().GetHex(); } @@ -876,14 +912,16 @@ UniValue sendfrom(const JSONRPCRequest& request) UniValue sendmany(const JSONRPCRequest& request) { - if (!EnsureWalletIsAvailable(request.fHelp)) + CWallet * const pwallet = GetWalletForJSONRPCRequest(request); + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; + } if (request.fHelp || request.params.size() < 2 || request.params.size() > 5) throw runtime_error( "sendmany \"fromaccount\" {\"address\":amount,...} ( minconf \"comment\" [\"address\",...] )\n" "\nSend multiple times. Amounts are double-precision floating point numbers." - + HelpRequiringPassphrase() + "\n" + + HelpRequiringPassphrase(pwallet) + "\n" "\nArguments:\n" "1. \"fromaccount\" (string, required) DEPRECATED. The account to send the funds from. Should be \"\" for the default account\n" "2. \"amounts\" (string, required) A json object with addresses and amounts\n" @@ -915,10 +953,11 @@ UniValue sendmany(const JSONRPCRequest& request) + HelpExampleRpc("sendmany", "\"\", \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\", 6, \"testing\"") ); - LOCK2(cs_main, pwalletMain->cs_wallet); + LOCK2(cs_main, pwallet->cs_wallet); - if (pwalletMain->GetBroadcastTransactions() && !g_connman) + if (pwallet->GetBroadcastTransactions() && !g_connman) { throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); + } string strAccount = AccountFromValue(request.params[0]); UniValue sendTo = request.params[1].get_obj(); @@ -967,23 +1006,23 @@ UniValue sendmany(const JSONRPCRequest& request) vecSend.push_back(recipient); } - EnsureWalletIsUnlocked(); + EnsureWalletIsUnlocked(pwallet); // Check funds - CAmount nBalance = pwalletMain->GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE); + CAmount nBalance = pwallet->GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE); if (totalAmount > nBalance) throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds"); // Send - CReserveKey keyChange(pwalletMain); + CReserveKey keyChange(pwallet); CAmount nFeeRequired = 0; int nChangePosRet = -1; string strFailReason; - bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, nChangePosRet, strFailReason); + bool fCreated = pwallet->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, nChangePosRet, strFailReason); if (!fCreated) throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason); CValidationState state; - if (!pwalletMain->CommitTransaction(wtx, keyChange, g_connman.get(), state)) { + if (!pwallet->CommitTransaction(wtx, keyChange, g_connman.get(), state)) { strFailReason = strprintf("Transaction commit failed:: %s", state.GetRejectReason()); throw JSONRPCError(RPC_WALLET_ERROR, strFailReason); } @@ -992,12 +1031,14 @@ UniValue sendmany(const JSONRPCRequest& request) } // Defined in rpc/misc.cpp -extern CScript _createmultisig_redeemScript(const UniValue& params); +extern CScript _createmultisig_redeemScript(CWallet * const pwallet, const UniValue& params); UniValue addmultisigaddress(const JSONRPCRequest& request) { - if (!EnsureWalletIsAvailable(request.fHelp)) + CWallet * const pwallet = GetWalletForJSONRPCRequest(request); + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; + } if (request.fHelp || request.params.size() < 2 || request.params.size() > 3) { @@ -1027,38 +1068,41 @@ UniValue addmultisigaddress(const JSONRPCRequest& request) throw runtime_error(msg); } - LOCK2(cs_main, pwalletMain->cs_wallet); + LOCK2(cs_main, pwallet->cs_wallet); string strAccount; if (request.params.size() > 2) strAccount = AccountFromValue(request.params[2]); // Construct using pay-to-script-hash: - CScript inner = _createmultisig_redeemScript(request.params); + CScript inner = _createmultisig_redeemScript(pwallet, request.params); CScriptID innerID(inner); - pwalletMain->AddCScript(inner); + pwallet->AddCScript(inner); - pwalletMain->SetAddressBook(innerID, strAccount, "send"); + pwallet->SetAddressBook(innerID, strAccount, "send"); return CBitcoinAddress(innerID).ToString(); } class Witnessifier : public boost::static_visitor<bool> { public: + CWallet * const pwallet; CScriptID result; + Witnessifier(CWallet *_pwallet) : pwallet(_pwallet) {} + bool operator()(const CNoDestination &dest) const { return false; } bool operator()(const CKeyID &keyID) { CPubKey pubkey; - if (pwalletMain) { + if (pwallet) { CScript basescript = GetScriptForDestination(keyID); isminetype typ; - typ = IsMine(*pwalletMain, basescript, SIGVERSION_WITNESS_V0); + typ = IsMine(*pwallet, basescript, SIGVERSION_WITNESS_V0); if (typ != ISMINE_SPENDABLE && typ != ISMINE_WATCH_SOLVABLE) return false; CScript witscript = GetScriptForWitness(basescript); - pwalletMain->AddCScript(witscript); + pwallet->AddCScript(witscript); result = CScriptID(witscript); return true; } @@ -1067,7 +1111,7 @@ public: bool operator()(const CScriptID &scriptID) { CScript subscript; - if (pwalletMain && pwalletMain->GetCScript(scriptID, subscript)) { + if (pwallet && pwallet->GetCScript(scriptID, subscript)) { int witnessversion; std::vector<unsigned char> witprog; if (subscript.IsWitnessProgram(witnessversion, witprog)) { @@ -1075,11 +1119,11 @@ public: return true; } isminetype typ; - typ = IsMine(*pwalletMain, subscript, SIGVERSION_WITNESS_V0); + typ = IsMine(*pwallet, subscript, SIGVERSION_WITNESS_V0); if (typ != ISMINE_SPENDABLE && typ != ISMINE_WATCH_SOLVABLE) return false; CScript witscript = GetScriptForWitness(subscript); - pwalletMain->AddCScript(witscript); + pwallet->AddCScript(witscript); result = CScriptID(witscript); return true; } @@ -1089,8 +1133,10 @@ public: UniValue addwitnessaddress(const JSONRPCRequest& request) { - if (!EnsureWalletIsAvailable(request.fHelp)) + CWallet * const pwallet = GetWalletForJSONRPCRequest(request); + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; + } if (request.fHelp || request.params.size() < 1 || request.params.size() > 1) { @@ -1119,14 +1165,14 @@ UniValue addwitnessaddress(const JSONRPCRequest& request) if (!address.IsValid()) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address"); - Witnessifier w; + Witnessifier w(pwallet); CTxDestination dest = address.Get(); bool ret = boost::apply_visitor(w, dest); if (!ret) { throw JSONRPCError(RPC_WALLET_ERROR, "Public key or redeemscript not known to wallet, or the key is uncompressed"); } - pwalletMain->SetAddressBook(w.result, "", "receive"); + pwallet->SetAddressBook(w.result, "", "receive"); return CBitcoinAddress(w.result).ToString(); } @@ -1145,7 +1191,7 @@ struct tallyitem } }; -UniValue ListReceived(const UniValue& params, bool fByAccounts) +UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByAccounts) { // Minimum confirmations int nMinDepth = 1; @@ -1164,9 +1210,8 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts) // Tally map<CBitcoinAddress, tallyitem> mapTally; - for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) - { - const CWalletTx& wtx = (*it).second; + for (const std::pair<uint256, CWalletTx>& pairWtx : pwallet->mapWallet) { + const CWalletTx& wtx = pairWtx.second; if (wtx.IsCoinBase() || !CheckFinalTx(*wtx.tx)) continue; @@ -1181,7 +1226,7 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts) if (!ExtractDestination(txout.scriptPubKey, address)) continue; - isminefilter mine = IsMine(*pwalletMain, address); + isminefilter mine = IsMine(*pwallet, address); if(!(mine & filter)) continue; @@ -1197,8 +1242,7 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts) // Reply UniValue ret(UniValue::VARR); map<string, tallyitem> mapAccountTally; - BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, CAddressBookData)& item, pwalletMain->mapAddressBook) - { + for (const std::pair<CBitcoinAddress, CAddressBookData>& item : pwallet->mapAddressBook) { const CBitcoinAddress& address = item.first; const string& strAccount = item.second.name; map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address); @@ -1267,8 +1311,10 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts) UniValue listreceivedbyaddress(const JSONRPCRequest& request) { - if (!EnsureWalletIsAvailable(request.fHelp)) + CWallet * const pwallet = GetWalletForJSONRPCRequest(request); + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; + } if (request.fHelp || request.params.size() > 3) throw runtime_error( @@ -1302,15 +1348,17 @@ UniValue listreceivedbyaddress(const JSONRPCRequest& request) + HelpExampleRpc("listreceivedbyaddress", "6, true, true") ); - LOCK2(cs_main, pwalletMain->cs_wallet); + LOCK2(cs_main, pwallet->cs_wallet); - return ListReceived(request.params, false); + return ListReceived(pwallet, request.params, false); } UniValue listreceivedbyaccount(const JSONRPCRequest& request) { - if (!EnsureWalletIsAvailable(request.fHelp)) + CWallet * const pwallet = GetWalletForJSONRPCRequest(request); + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; + } if (request.fHelp || request.params.size() > 3) throw runtime_error( @@ -1339,9 +1387,9 @@ UniValue listreceivedbyaccount(const JSONRPCRequest& request) + HelpExampleRpc("listreceivedbyaccount", "6, true, true") ); - LOCK2(cs_main, pwalletMain->cs_wallet); + LOCK2(cs_main, pwallet->cs_wallet); - return ListReceived(request.params, true); + return ListReceived(pwallet, request.params, true); } static void MaybePushAddress(UniValue & entry, const CTxDestination &dest) @@ -1351,7 +1399,7 @@ static void MaybePushAddress(UniValue & entry, const CTxDestination &dest) entry.push_back(Pair("address", addr.ToString())); } -void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter) +void ListTransactions(CWallet * const pwallet, const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter) { CAmount nFee; string strSentAccount; @@ -1369,14 +1417,16 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe BOOST_FOREACH(const COutputEntry& s, listSent) { UniValue entry(UniValue::VOBJ); - if(involvesWatchonly || (::IsMine(*pwalletMain, s.destination) & ISMINE_WATCH_ONLY)) + if (involvesWatchonly || (::IsMine(*pwallet, s.destination) & ISMINE_WATCH_ONLY)) { entry.push_back(Pair("involvesWatchonly", true)); + } entry.push_back(Pair("account", strSentAccount)); MaybePushAddress(entry, s.destination); entry.push_back(Pair("category", "send")); entry.push_back(Pair("amount", ValueFromAmount(-s.amount))); - if (pwalletMain->mapAddressBook.count(s.destination)) - entry.push_back(Pair("label", pwalletMain->mapAddressBook[s.destination].name)); + if (pwallet->mapAddressBook.count(s.destination)) { + entry.push_back(Pair("label", pwallet->mapAddressBook[s.destination].name)); + } entry.push_back(Pair("vout", s.vout)); entry.push_back(Pair("fee", ValueFromAmount(-nFee))); if (fLong) @@ -1392,13 +1442,15 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe BOOST_FOREACH(const COutputEntry& r, listReceived) { string account; - if (pwalletMain->mapAddressBook.count(r.destination)) - account = pwalletMain->mapAddressBook[r.destination].name; + if (pwallet->mapAddressBook.count(r.destination)) { + account = pwallet->mapAddressBook[r.destination].name; + } if (fAllAccounts || (account == strAccount)) { UniValue entry(UniValue::VOBJ); - if(involvesWatchonly || (::IsMine(*pwalletMain, r.destination) & ISMINE_WATCH_ONLY)) + if (involvesWatchonly || (::IsMine(*pwallet, r.destination) & ISMINE_WATCH_ONLY)) { entry.push_back(Pair("involvesWatchonly", true)); + } entry.push_back(Pair("account", account)); MaybePushAddress(entry, r.destination); if (wtx.IsCoinBase()) @@ -1415,8 +1467,9 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe entry.push_back(Pair("category", "receive")); } entry.push_back(Pair("amount", ValueFromAmount(r.amount))); - if (pwalletMain->mapAddressBook.count(r.destination)) + if (pwallet->mapAddressBook.count(r.destination)) { entry.push_back(Pair("label", account)); + } entry.push_back(Pair("vout", r.vout)); if (fLong) WalletTxToJSON(wtx, entry); @@ -1445,8 +1498,10 @@ void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Un UniValue listtransactions(const JSONRPCRequest& request) { - if (!EnsureWalletIsAvailable(request.fHelp)) + CWallet * const pwallet = GetWalletForJSONRPCRequest(request); + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; + } if (request.fHelp || request.params.size() > 4) throw runtime_error( @@ -1508,7 +1563,7 @@ UniValue listtransactions(const JSONRPCRequest& request) + HelpExampleRpc("listtransactions", "\"*\", 20, 100") ); - LOCK2(cs_main, pwalletMain->cs_wallet); + LOCK2(cs_main, pwallet->cs_wallet); string strAccount = "*"; if (request.params.size() > 0) @@ -1531,14 +1586,14 @@ UniValue listtransactions(const JSONRPCRequest& request) UniValue ret(UniValue::VARR); - const CWallet::TxItems & txOrdered = pwalletMain->wtxOrdered; + const CWallet::TxItems & txOrdered = pwallet->wtxOrdered; // iterate backwards until we have nCount items to return: for (CWallet::TxItems::const_reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) { CWalletTx *const pwtx = (*it).second.first; if (pwtx != 0) - ListTransactions(*pwtx, strAccount, 0, true, ret, filter); + ListTransactions(pwallet, *pwtx, strAccount, 0, true, ret, filter); CAccountingEntry *const pacentry = (*it).second.second; if (pacentry != 0) AcentryToJSON(*pacentry, strAccount, ret); @@ -1573,8 +1628,10 @@ UniValue listtransactions(const JSONRPCRequest& request) UniValue listaccounts(const JSONRPCRequest& request) { - if (!EnsureWalletIsAvailable(request.fHelp)) + CWallet * const pwallet = GetWalletForJSONRPCRequest(request); + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; + } if (request.fHelp || request.params.size() > 2) throw runtime_error( @@ -1599,7 +1656,7 @@ UniValue listaccounts(const JSONRPCRequest& request) + HelpExampleRpc("listaccounts", "6") ); - LOCK2(cs_main, pwalletMain->cs_wallet); + LOCK2(cs_main, pwallet->cs_wallet); int nMinDepth = 1; if (request.params.size() > 0) @@ -1610,14 +1667,14 @@ UniValue listaccounts(const JSONRPCRequest& request) includeWatchonly = includeWatchonly | ISMINE_WATCH_ONLY; map<string, CAmount> mapAccountBalances; - BOOST_FOREACH(const PAIRTYPE(CTxDestination, CAddressBookData)& entry, pwalletMain->mapAddressBook) { - if (IsMine(*pwalletMain, entry.first) & includeWatchonly) // This address belongs to me + for (const std::pair<CTxDestination, CAddressBookData>& entry : pwallet->mapAddressBook) { + if (IsMine(*pwallet, entry.first) & includeWatchonly) { // This address belongs to me mapAccountBalances[entry.second.name] = 0; + } } - for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) - { - const CWalletTx& wtx = (*it).second; + for (const std::pair<uint256, CWalletTx>& pairWtx : pwallet->mapWallet) { + const CWalletTx& wtx = pairWtx.second; CAmount nFee; string strSentAccount; list<COutputEntry> listReceived; @@ -1632,14 +1689,15 @@ UniValue listaccounts(const JSONRPCRequest& request) if (nDepth >= nMinDepth) { BOOST_FOREACH(const COutputEntry& r, listReceived) - if (pwalletMain->mapAddressBook.count(r.destination)) - mapAccountBalances[pwalletMain->mapAddressBook[r.destination].name] += r.amount; + if (pwallet->mapAddressBook.count(r.destination)) { + mapAccountBalances[pwallet->mapAddressBook[r.destination].name] += r.amount; + } else mapAccountBalances[""] += r.amount; } } - const list<CAccountingEntry> & acentries = pwalletMain->laccentries; + const list<CAccountingEntry> & acentries = pwallet->laccentries; BOOST_FOREACH(const CAccountingEntry& entry, acentries) mapAccountBalances[entry.strAccount] += entry.nCreditDebit; @@ -1652,8 +1710,10 @@ UniValue listaccounts(const JSONRPCRequest& request) UniValue listsinceblock(const JSONRPCRequest& request) { - if (!EnsureWalletIsAvailable(request.fHelp)) + CWallet * const pwallet = GetWalletForJSONRPCRequest(request); + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; + } if (request.fHelp) throw runtime_error( @@ -1696,7 +1756,7 @@ UniValue listsinceblock(const JSONRPCRequest& request) + HelpExampleRpc("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\", 6") ); - LOCK2(cs_main, pwalletMain->cs_wallet); + LOCK2(cs_main, pwallet->cs_wallet); const CBlockIndex *pindex = NULL; int target_confirms = 1; @@ -1738,12 +1798,11 @@ UniValue listsinceblock(const JSONRPCRequest& request) UniValue transactions(UniValue::VARR); - for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++) - { - CWalletTx tx = (*it).second; + for (const std::pair<uint256, CWalletTx>& pairWtx : pwallet->mapWallet) { + CWalletTx tx = pairWtx.second; if (depth == -1 || tx.GetDepthInMainChain() < depth) - ListTransactions(tx, "*", 0, true, transactions, filter); + ListTransactions(pwallet, tx, "*", 0, true, transactions, filter); } CBlockIndex *pblockLast = chainActive[chainActive.Height() + 1 - target_confirms]; @@ -1758,8 +1817,10 @@ UniValue listsinceblock(const JSONRPCRequest& request) UniValue gettransaction(const JSONRPCRequest& request) { - if (!EnsureWalletIsAvailable(request.fHelp)) + CWallet * const pwallet = GetWalletForJSONRPCRequest(request); + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; + } if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) throw runtime_error( @@ -1806,7 +1867,7 @@ UniValue gettransaction(const JSONRPCRequest& request) + HelpExampleRpc("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"") ); - LOCK2(cs_main, pwalletMain->cs_wallet); + LOCK2(cs_main, pwallet->cs_wallet); uint256 hash; hash.SetHex(request.params[0].get_str()); @@ -1817,9 +1878,10 @@ UniValue gettransaction(const JSONRPCRequest& request) filter = filter | ISMINE_WATCH_ONLY; UniValue entry(UniValue::VOBJ); - if (!pwalletMain->mapWallet.count(hash)) + if (!pwallet->mapWallet.count(hash)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id"); - const CWalletTx& wtx = pwalletMain->mapWallet[hash]; + } + const CWalletTx& wtx = pwallet->mapWallet[hash]; CAmount nCredit = wtx.GetCredit(filter); CAmount nDebit = wtx.GetDebit(filter); @@ -1833,7 +1895,7 @@ UniValue gettransaction(const JSONRPCRequest& request) WalletTxToJSON(wtx, entry); UniValue details(UniValue::VARR); - ListTransactions(wtx, "*", 0, false, details, filter); + ListTransactions(pwallet, wtx, "*", 0, false, details, filter); entry.push_back(Pair("details", details)); string strHex = EncodeHexTx(static_cast<CTransaction>(wtx), RPCSerializationFlags()); @@ -1844,8 +1906,10 @@ UniValue gettransaction(const JSONRPCRequest& request) UniValue abandontransaction(const JSONRPCRequest& request) { - if (!EnsureWalletIsAvailable(request.fHelp)) + CWallet * const pwallet = GetWalletForJSONRPCRequest(request); + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; + } if (request.fHelp || request.params.size() != 1) throw runtime_error( @@ -1863,15 +1927,17 @@ UniValue abandontransaction(const JSONRPCRequest& request) + HelpExampleRpc("abandontransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"") ); - LOCK2(cs_main, pwalletMain->cs_wallet); + LOCK2(cs_main, pwallet->cs_wallet); uint256 hash; hash.SetHex(request.params[0].get_str()); - if (!pwalletMain->mapWallet.count(hash)) + if (!pwallet->mapWallet.count(hash)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id"); - if (!pwalletMain->AbandonTransaction(hash)) + } + if (!pwallet->AbandonTransaction(hash)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not eligible for abandonment"); + } return NullUniValue; } @@ -1879,8 +1945,10 @@ UniValue abandontransaction(const JSONRPCRequest& request) UniValue backupwallet(const JSONRPCRequest& request) { - if (!EnsureWalletIsAvailable(request.fHelp)) + CWallet * const pwallet = GetWalletForJSONRPCRequest(request); + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; + } if (request.fHelp || request.params.size() != 1) throw runtime_error( @@ -1893,11 +1961,12 @@ UniValue backupwallet(const JSONRPCRequest& request) + HelpExampleRpc("backupwallet", "\"backup.dat\"") ); - LOCK2(cs_main, pwalletMain->cs_wallet); + LOCK2(cs_main, pwallet->cs_wallet); string strDest = request.params[0].get_str(); - if (!pwalletMain->BackupWallet(strDest)) + if (!pwallet->BackupWallet(strDest)) { throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!"); + } return NullUniValue; } @@ -1905,14 +1974,16 @@ UniValue backupwallet(const JSONRPCRequest& request) UniValue keypoolrefill(const JSONRPCRequest& request) { - if (!EnsureWalletIsAvailable(request.fHelp)) + CWallet * const pwallet = GetWalletForJSONRPCRequest(request); + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; + } if (request.fHelp || request.params.size() > 1) throw runtime_error( "keypoolrefill ( newsize )\n" "\nFills the keypool." - + HelpRequiringPassphrase() + "\n" + + HelpRequiringPassphrase(pwallet) + "\n" "\nArguments\n" "1. newsize (numeric, optional, default=100) The new keypool size\n" "\nExamples:\n" @@ -1920,7 +1991,7 @@ UniValue keypoolrefill(const JSONRPCRequest& request) + HelpExampleRpc("keypoolrefill", "") ); - LOCK2(cs_main, pwalletMain->cs_wallet); + LOCK2(cs_main, pwallet->cs_wallet); // 0 is interpreted by TopUpKeyPool() as the default keypool size given by -keypool unsigned int kpSize = 0; @@ -1930,11 +2001,12 @@ UniValue keypoolrefill(const JSONRPCRequest& request) kpSize = (unsigned int)request.params[0].get_int(); } - EnsureWalletIsUnlocked(); - pwalletMain->TopUpKeyPool(kpSize); + EnsureWalletIsUnlocked(pwallet); + pwallet->TopUpKeyPool(kpSize); - if (pwalletMain->GetKeyPoolSize() < kpSize) + if (pwallet->GetKeyPoolSize() < kpSize) { throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool."); + } return NullUniValue; } @@ -1942,17 +2014,19 @@ UniValue keypoolrefill(const JSONRPCRequest& request) static void LockWallet(CWallet* pWallet) { - LOCK(cs_nWalletUnlockTime); - nWalletUnlockTime = 0; + LOCK(pWallet->cs_wallet); + pWallet->nRelockTime = 0; pWallet->Lock(); } UniValue walletpassphrase(const JSONRPCRequest& request) { - if (!EnsureWalletIsAvailable(request.fHelp)) + CWallet * const pwallet = GetWalletForJSONRPCRequest(request); + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; + } - if (pwalletMain->IsCrypted() && (request.fHelp || request.params.size() != 2)) + if (pwallet->IsCrypted() && (request.fHelp || request.params.size() != 2)) { throw runtime_error( "walletpassphrase \"passphrase\" timeout\n" "\nStores the wallet decryption key in memory for 'timeout' seconds.\n" @@ -1971,13 +2045,15 @@ UniValue walletpassphrase(const JSONRPCRequest& request) "\nAs json rpc call\n" + HelpExampleRpc("walletpassphrase", "\"my pass phrase\", 60") ); + } - LOCK2(cs_main, pwalletMain->cs_wallet); + LOCK2(cs_main, pwallet->cs_wallet); if (request.fHelp) return true; - if (!pwalletMain->IsCrypted()) + if (!pwallet->IsCrypted()) { throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called."); + } // Note that the walletpassphrase is stored in request.params[0] which is not mlock()ed SecureString strWalletPass; @@ -1988,20 +2064,20 @@ UniValue walletpassphrase(const JSONRPCRequest& request) if (strWalletPass.length() > 0) { - if (!pwalletMain->Unlock(strWalletPass)) + if (!pwallet->Unlock(strWalletPass)) { throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect."); + } } else throw runtime_error( "walletpassphrase <passphrase> <timeout>\n" "Stores the wallet decryption key in memory for <timeout> seconds."); - pwalletMain->TopUpKeyPool(); + pwallet->TopUpKeyPool(); int64_t nSleepTime = request.params[1].get_int64(); - LOCK(cs_nWalletUnlockTime); - nWalletUnlockTime = GetTime() + nSleepTime; - RPCRunLater("lockwallet", boost::bind(LockWallet, pwalletMain), nSleepTime); + pwallet->nRelockTime = GetTime() + nSleepTime; + RPCRunLater(strprintf("lockwallet(%s)", pwallet->strWalletFile), boost::bind(LockWallet, pwallet), nSleepTime); return NullUniValue; } @@ -2009,10 +2085,12 @@ UniValue walletpassphrase(const JSONRPCRequest& request) UniValue walletpassphrasechange(const JSONRPCRequest& request) { - if (!EnsureWalletIsAvailable(request.fHelp)) + CWallet * const pwallet = GetWalletForJSONRPCRequest(request); + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; + } - if (pwalletMain->IsCrypted() && (request.fHelp || request.params.size() != 2)) + if (pwallet->IsCrypted() && (request.fHelp || request.params.size() != 2)) { throw runtime_error( "walletpassphrasechange \"oldpassphrase\" \"newpassphrase\"\n" "\nChanges the wallet passphrase from 'oldpassphrase' to 'newpassphrase'.\n" @@ -2023,13 +2101,15 @@ UniValue walletpassphrasechange(const JSONRPCRequest& request) + HelpExampleCli("walletpassphrasechange", "\"old one\" \"new one\"") + HelpExampleRpc("walletpassphrasechange", "\"old one\", \"new one\"") ); + } - LOCK2(cs_main, pwalletMain->cs_wallet); + LOCK2(cs_main, pwallet->cs_wallet); if (request.fHelp) return true; - if (!pwalletMain->IsCrypted()) + if (!pwallet->IsCrypted()) { throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called."); + } // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string) // Alternately, find a way to make request.params[0] mlock()'d to begin with. @@ -2046,8 +2126,9 @@ UniValue walletpassphrasechange(const JSONRPCRequest& request) "walletpassphrasechange <oldpassphrase> <newpassphrase>\n" "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>."); - if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass)) + if (!pwallet->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass)) { throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect."); + } return NullUniValue; } @@ -2055,10 +2136,12 @@ UniValue walletpassphrasechange(const JSONRPCRequest& request) UniValue walletlock(const JSONRPCRequest& request) { - if (!EnsureWalletIsAvailable(request.fHelp)) + CWallet * const pwallet = GetWalletForJSONRPCRequest(request); + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; + } - if (pwalletMain->IsCrypted() && (request.fHelp || request.params.size() != 0)) + if (pwallet->IsCrypted() && (request.fHelp || request.params.size() != 0)) { throw runtime_error( "walletlock\n" "\nRemoves the wallet encryption key from memory, locking the wallet.\n" @@ -2074,30 +2157,31 @@ UniValue walletlock(const JSONRPCRequest& request) "\nAs json rpc call\n" + HelpExampleRpc("walletlock", "") ); + } - LOCK2(cs_main, pwalletMain->cs_wallet); + LOCK2(cs_main, pwallet->cs_wallet); if (request.fHelp) return true; - if (!pwalletMain->IsCrypted()) + if (!pwallet->IsCrypted()) { throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called."); - - { - LOCK(cs_nWalletUnlockTime); - pwalletMain->Lock(); - nWalletUnlockTime = 0; } + pwallet->Lock(); + pwallet->nRelockTime = 0; + return NullUniValue; } UniValue encryptwallet(const JSONRPCRequest& request) { - if (!EnsureWalletIsAvailable(request.fHelp)) + CWallet * const pwallet = GetWalletForJSONRPCRequest(request); + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; + } - if (!pwalletMain->IsCrypted() && (request.fHelp || request.params.size() != 1)) + if (!pwallet->IsCrypted() && (request.fHelp || request.params.size() != 1)) { throw runtime_error( "encryptwallet \"passphrase\"\n" "\nEncrypts the wallet with 'passphrase'. This is for first time encryption.\n" @@ -2120,13 +2204,15 @@ UniValue encryptwallet(const JSONRPCRequest& request) "\nAs a json rpc call\n" + HelpExampleRpc("encryptwallet", "\"my pass phrase\"") ); + } - LOCK2(cs_main, pwalletMain->cs_wallet); + LOCK2(cs_main, pwallet->cs_wallet); if (request.fHelp) return true; - if (pwalletMain->IsCrypted()) + if (pwallet->IsCrypted()) { throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called."); + } // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string) // Alternately, find a way to make request.params[0] mlock()'d to begin with. @@ -2139,8 +2225,9 @@ UniValue encryptwallet(const JSONRPCRequest& request) "encryptwallet <passphrase>\n" "Encrypts the wallet with <passphrase>."); - if (!pwalletMain->EncryptWallet(strWalletPass)) + if (!pwallet->EncryptWallet(strWalletPass)) { throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Failed to encrypt the wallet."); + } // 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 @@ -2151,8 +2238,10 @@ UniValue encryptwallet(const JSONRPCRequest& request) UniValue lockunspent(const JSONRPCRequest& request) { - if (!EnsureWalletIsAvailable(request.fHelp)) + CWallet * const pwallet = GetWalletForJSONRPCRequest(request); + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; + } if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) throw runtime_error( @@ -2191,7 +2280,7 @@ UniValue lockunspent(const JSONRPCRequest& request) + HelpExampleRpc("lockunspent", "false, \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") ); - LOCK2(cs_main, pwalletMain->cs_wallet); + LOCK2(cs_main, pwallet->cs_wallet); if (request.params.size() == 1) RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VBOOL)); @@ -2202,7 +2291,7 @@ UniValue lockunspent(const JSONRPCRequest& request) if (request.params.size() == 1) { if (fUnlock) - pwalletMain->UnlockAllCoins(); + pwallet->UnlockAllCoins(); return true; } @@ -2230,9 +2319,9 @@ UniValue lockunspent(const JSONRPCRequest& request) COutPoint outpt(uint256S(txid), nOutput); if (fUnlock) - pwalletMain->UnlockCoin(outpt); + pwallet->UnlockCoin(outpt); else - pwalletMain->LockCoin(outpt); + pwallet->LockCoin(outpt); } return true; @@ -2240,8 +2329,10 @@ UniValue lockunspent(const JSONRPCRequest& request) UniValue listlockunspent(const JSONRPCRequest& request) { - if (!EnsureWalletIsAvailable(request.fHelp)) + CWallet * const pwallet = GetWalletForJSONRPCRequest(request); + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; + } if (request.fHelp || request.params.size() > 0) throw runtime_error( @@ -2269,10 +2360,10 @@ UniValue listlockunspent(const JSONRPCRequest& request) + HelpExampleRpc("listlockunspent", "") ); - LOCK2(cs_main, pwalletMain->cs_wallet); + LOCK2(cs_main, pwallet->cs_wallet); vector<COutPoint> vOutpts; - pwalletMain->ListLockedCoins(vOutpts); + pwallet->ListLockedCoins(vOutpts); UniValue ret(UniValue::VARR); @@ -2289,8 +2380,10 @@ UniValue listlockunspent(const JSONRPCRequest& request) UniValue settxfee(const JSONRPCRequest& request) { - if (!EnsureWalletIsAvailable(request.fHelp)) + CWallet * const pwallet = GetWalletForJSONRPCRequest(request); + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; + } if (request.fHelp || request.params.size() < 1 || request.params.size() > 1) throw runtime_error( @@ -2305,7 +2398,7 @@ UniValue settxfee(const JSONRPCRequest& request) + HelpExampleRpc("settxfee", "0.00001") ); - LOCK2(cs_main, pwalletMain->cs_wallet); + LOCK2(cs_main, pwallet->cs_wallet); // Amount CAmount nAmount = AmountFromValue(request.params[0]); @@ -2316,8 +2409,10 @@ UniValue settxfee(const JSONRPCRequest& request) UniValue getwalletinfo(const JSONRPCRequest& request) { - if (!EnsureWalletIsAvailable(request.fHelp)) + CWallet * const pwallet = GetWalletForJSONRPCRequest(request); + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; + } if (request.fHelp || request.params.size() != 0) throw runtime_error( @@ -2341,20 +2436,21 @@ UniValue getwalletinfo(const JSONRPCRequest& request) + HelpExampleRpc("getwalletinfo", "") ); - LOCK2(cs_main, pwalletMain->cs_wallet); + LOCK2(cs_main, pwallet->cs_wallet); UniValue obj(UniValue::VOBJ); - obj.push_back(Pair("walletversion", pwalletMain->GetVersion())); - obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance()))); - obj.push_back(Pair("unconfirmed_balance", ValueFromAmount(pwalletMain->GetUnconfirmedBalance()))); - obj.push_back(Pair("immature_balance", ValueFromAmount(pwalletMain->GetImmatureBalance()))); - obj.push_back(Pair("txcount", (int)pwalletMain->mapWallet.size())); - obj.push_back(Pair("keypoololdest", pwalletMain->GetOldestKeyPoolTime())); - obj.push_back(Pair("keypoolsize", (int)pwalletMain->GetKeyPoolSize())); - if (pwalletMain->IsCrypted()) - obj.push_back(Pair("unlocked_until", nWalletUnlockTime)); + obj.push_back(Pair("walletversion", pwallet->GetVersion())); + obj.push_back(Pair("balance", ValueFromAmount(pwallet->GetBalance()))); + obj.push_back(Pair("unconfirmed_balance", ValueFromAmount(pwallet->GetUnconfirmedBalance()))); + obj.push_back(Pair("immature_balance", ValueFromAmount(pwallet->GetImmatureBalance()))); + obj.push_back(Pair("txcount", (int)pwallet->mapWallet.size())); + obj.push_back(Pair("keypoololdest", pwallet->GetOldestKeyPoolTime())); + obj.push_back(Pair("keypoolsize", (int)pwallet->GetKeyPoolSize())); + if (pwallet->IsCrypted()) { + obj.push_back(Pair("unlocked_until", pwallet->nRelockTime)); + } obj.push_back(Pair("paytxfee", ValueFromAmount(payTxFee.GetFeePerK()))); - CKeyID masterKeyID = pwalletMain->GetHDChain().masterKeyID; + CKeyID masterKeyID = pwallet->GetHDChain().masterKeyID; if (!masterKeyID.IsNull()) obj.push_back(Pair("hdmasterkeyid", masterKeyID.GetHex())); return obj; @@ -2362,8 +2458,10 @@ UniValue getwalletinfo(const JSONRPCRequest& request) UniValue resendwallettransactions(const JSONRPCRequest& request) { - if (!EnsureWalletIsAvailable(request.fHelp)) + CWallet * const pwallet = GetWalletForJSONRPCRequest(request); + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; + } if (request.fHelp || request.params.size() != 0) throw runtime_error( @@ -2377,9 +2475,9 @@ UniValue resendwallettransactions(const JSONRPCRequest& request) if (!g_connman) throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); - LOCK2(cs_main, pwalletMain->cs_wallet); + LOCK2(cs_main, pwallet->cs_wallet); - std::vector<uint256> txids = pwalletMain->ResendWalletTransactionsBefore(GetTime(), g_connman.get()); + std::vector<uint256> txids = pwallet->ResendWalletTransactionsBefore(GetTime(), g_connman.get()); UniValue result(UniValue::VARR); BOOST_FOREACH(const uint256& txid, txids) { @@ -2390,8 +2488,10 @@ UniValue resendwallettransactions(const JSONRPCRequest& request) UniValue listunspent(const JSONRPCRequest& request) { - if (!EnsureWalletIsAvailable(request.fHelp)) + CWallet * const pwallet = GetWalletForJSONRPCRequest(request); + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; + } if (request.fHelp || request.params.size() > 4) throw runtime_error( @@ -2469,9 +2569,9 @@ UniValue listunspent(const JSONRPCRequest& request) UniValue results(UniValue::VARR); vector<COutput> vecOutputs; - assert(pwalletMain != NULL); - LOCK2(cs_main, pwalletMain->cs_wallet); - pwalletMain->AvailableCoins(vecOutputs, !include_unsafe, NULL, true); + assert(pwallet != NULL); + LOCK2(cs_main, pwallet->cs_wallet); + pwallet->AvailableCoins(vecOutputs, !include_unsafe, NULL, true); BOOST_FOREACH(const COutput& out, vecOutputs) { if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth) continue; @@ -2490,14 +2590,16 @@ UniValue listunspent(const JSONRPCRequest& request) if (fValidAddress) { entry.push_back(Pair("address", CBitcoinAddress(address).ToString())); - if (pwalletMain->mapAddressBook.count(address)) - entry.push_back(Pair("account", pwalletMain->mapAddressBook[address].name)); + if (pwallet->mapAddressBook.count(address)) { + entry.push_back(Pair("account", pwallet->mapAddressBook[address].name)); + } if (scriptPubKey.IsPayToScriptHash()) { const CScriptID& hash = boost::get<CScriptID>(address); CScript redeemScript; - if (pwalletMain->GetCScript(hash, redeemScript)) + if (pwallet->GetCScript(hash, redeemScript)) { entry.push_back(Pair("redeemScript", HexStr(redeemScript.begin(), redeemScript.end()))); + } } } @@ -2514,8 +2616,10 @@ UniValue listunspent(const JSONRPCRequest& request) UniValue fundrawtransaction(const JSONRPCRequest& request) { - if (!EnsureWalletIsAvailable(request.fHelp)) + CWallet * const pwallet = GetWalletForJSONRPCRequest(request); + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; + } if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) throw runtime_error( @@ -2656,8 +2760,9 @@ UniValue fundrawtransaction(const JSONRPCRequest& request) CAmount nFeeOut; string strFailReason; - if(!pwalletMain->FundTransaction(tx, nFeeOut, overrideEstimatedFeerate, feeRate, changePosition, strFailReason, includeWatching, lockUnspents, setSubtractFeeFromOutputs, reserveChangeKey, changeAddress)) + if (!pwallet->FundTransaction(tx, nFeeOut, overrideEstimatedFeerate, feeRate, changePosition, strFailReason, includeWatching, lockUnspents, setSubtractFeeFromOutputs, reserveChangeKey, changeAddress)) { throw JSONRPCError(RPC_INTERNAL_ERROR, strFailReason); + } UniValue result(UniValue::VOBJ); result.push_back(Pair("hex", EncodeHexTx(tx))); @@ -2674,7 +2779,7 @@ UniValue fundrawtransaction(const JSONRPCRequest& request) // calculation, but we should be able to refactor after priority is removed). // NOTE: this requires that all inputs must be in mapWallet (eg the tx should // be IsAllFromMe). -int64_t CalculateMaximumSignedTxSize(const CTransaction &tx) +int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, CWallet &wallet) { CMutableTransaction txNew(tx); std::vector<pair<CWalletTx *, unsigned int>> vCoins; @@ -2682,11 +2787,11 @@ int64_t CalculateMaximumSignedTxSize(const CTransaction &tx) // IsAllFromMe(ISMINE_SPENDABLE), so every input should already be in our // wallet, with a valid index into the vout array. for (auto& input : tx.vin) { - const auto mi = pwalletMain->mapWallet.find(input.prevout.hash); - assert(mi != pwalletMain->mapWallet.end() && input.prevout.n < mi->second.tx->vout.size()); + const auto mi = wallet.mapWallet.find(input.prevout.hash); + assert(mi != wallet.mapWallet.end() && input.prevout.n < mi->second.tx->vout.size()); vCoins.emplace_back(make_pair(&(mi->second), input.prevout.n)); } - if (!pwalletMain->DummySignTx(txNew, vCoins)) { + if (!wallet.DummySignTx(txNew, vCoins)) { // This should never happen, because IsAllFromMe(ISMINE_SPENDABLE) // implies that we can sign for every input. throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction contains inputs that cannot be signed"); @@ -2696,9 +2801,10 @@ int64_t CalculateMaximumSignedTxSize(const CTransaction &tx) UniValue bumpfee(const JSONRPCRequest& request) { - if (!EnsureWalletIsAvailable(request.fHelp)) { + CWallet * const pwallet = GetWalletForJSONRPCRequest(request); + + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) return NullUniValue; - } if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) { throw runtime_error( @@ -2748,14 +2854,14 @@ UniValue bumpfee(const JSONRPCRequest& request) hash.SetHex(request.params[0].get_str()); // retrieve the original tx from the wallet - LOCK2(cs_main, pwalletMain->cs_wallet); - EnsureWalletIsUnlocked(); - if (!pwalletMain->mapWallet.count(hash)) { + LOCK2(cs_main, pwallet->cs_wallet); + EnsureWalletIsUnlocked(pwallet); + if (!pwallet->mapWallet.count(hash)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id"); } - CWalletTx& wtx = pwalletMain->mapWallet[hash]; + CWalletTx& wtx = pwallet->mapWallet[hash]; - if (pwalletMain->HasWalletSpend(hash)) { + if (pwallet->HasWalletSpend(hash)) { throw JSONRPCError(RPC_MISC_ERROR, "Transaction has descendants in the wallet"); } @@ -2781,7 +2887,7 @@ UniValue bumpfee(const JSONRPCRequest& request) // check that original tx consists entirely of our inputs // if not, we can't bump the fee, because the wallet has no way of knowing the value of the other inputs (thus the fee) - if (!pwalletMain->IsAllFromMe(wtx, ISMINE_SPENDABLE)) { + if (!pwallet->IsAllFromMe(wtx, ISMINE_SPENDABLE)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction contains inputs that don't belong to this wallet"); } @@ -2789,7 +2895,7 @@ UniValue bumpfee(const JSONRPCRequest& request) // if there was no change output or multiple change outputs, fail int nOutput = -1; for (size_t i = 0; i < wtx.tx->vout.size(); ++i) { - if (pwalletMain->IsChange(wtx.tx->vout[i])) { + if (pwallet->IsChange(wtx.tx->vout[i])) { if (nOutput != -1) { throw JSONRPCError(RPC_MISC_ERROR, "Transaction has multiple change outputs"); } @@ -2802,7 +2908,7 @@ UniValue bumpfee(const JSONRPCRequest& request) // Calculate the expected size of the new transaction. int64_t txSize = GetVirtualTransactionSize(*(wtx.tx)); - const int64_t maxNewTxSize = CalculateMaximumSignedTxSize(*wtx.tx); + const int64_t maxNewTxSize = CalculateMaximumSignedTxSize(*wtx.tx, *pwallet); // optional parameters bool specifiedConfirmTarget = false; @@ -2932,12 +3038,12 @@ UniValue bumpfee(const JSONRPCRequest& request) CTransaction txNewConst(tx); int nIn = 0; for (auto& input : tx.vin) { - std::map<uint256, CWalletTx>::const_iterator mi = pwalletMain->mapWallet.find(input.prevout.hash); - assert(mi != pwalletMain->mapWallet.end() && input.prevout.n < mi->second.tx->vout.size()); + std::map<uint256, CWalletTx>::const_iterator mi = pwallet->mapWallet.find(input.prevout.hash); + assert(mi != pwallet->mapWallet.end() && input.prevout.n < mi->second.tx->vout.size()); const CScript& scriptPubKey = mi->second.tx->vout[input.prevout.n].scriptPubKey; const CAmount& amount = mi->second.tx->vout[input.prevout.n].nValue; SignatureData sigdata; - if (!ProduceSignature(TransactionSignatureCreator(pwalletMain, &txNewConst, nIn, amount, SIGHASH_ALL), scriptPubKey, sigdata)) { + if (!ProduceSignature(TransactionSignatureCreator(pwallet, &txNewConst, nIn, amount, SIGHASH_ALL), scriptPubKey, sigdata)) { throw JSONRPCError(RPC_WALLET_ERROR, "Can't sign transaction."); } UpdateTransaction(tx, nIn, sigdata); @@ -2945,8 +3051,8 @@ UniValue bumpfee(const JSONRPCRequest& request) } // commit/broadcast the tx - CReserveKey reservekey(pwalletMain); - CWalletTx wtxBumped(pwalletMain, MakeTransactionRef(std::move(tx))); + CReserveKey reservekey(pwallet); + CWalletTx wtxBumped(pwallet, MakeTransactionRef(std::move(tx))); wtxBumped.mapValue = wtx.mapValue; wtxBumped.mapValue["replaces_txid"] = hash.ToString(); wtxBumped.vOrderForm = wtx.vOrderForm; @@ -2954,7 +3060,7 @@ UniValue bumpfee(const JSONRPCRequest& request) wtxBumped.fTimeReceivedIsTxTime = true; wtxBumped.fFromMe = true; CValidationState state; - if (!pwalletMain->CommitTransaction(wtxBumped, reservekey, g_connman.get(), state)) { + if (!pwallet->CommitTransaction(wtxBumped, reservekey, g_connman.get(), state)) { // NOTE: CommitTransaction never returns false, so this should never happen. throw JSONRPCError(RPC_WALLET_ERROR, strprintf("Error: The transaction was rejected! Reason given: %s", state.GetRejectReason())); } @@ -2967,7 +3073,7 @@ UniValue bumpfee(const JSONRPCRequest& request) } // mark the original tx as bumped - if (!pwalletMain->MarkReplaced(wtx.GetHash(), wtxBumped.GetHash())) { + if (!pwallet->MarkReplaced(wtx.GetHash(), wtxBumped.GetHash())) { // TODO: see if JSON-RPC has a standard way of returning a response // along with an exception. It would be good to return information about // wtxBumped to the caller even if marking the original transaction |