diff options
author | Jeff Garzik <jgarzik@exmulti.com> | 2012-09-27 13:52:09 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@redhat.com> | 2012-11-15 21:11:30 -0500 |
commit | fdbb537d263497529c8f9deb0bb98371530839c3 (patch) | |
tree | a18245d2f8858efde12448d67c3db2c63d175f1a | |
parent | 6caffb5358b1e403b293846b3c832433fa928e46 (diff) |
Add new RPC "lockunspent", to prevent spending of selected outputs
and associated RPC "listlockunspent".
This is a memory-only filter, which is empty when a node restarts.
-rw-r--r-- | src/bitcoinrpc.cpp | 4 | ||||
-rw-r--r-- | src/bitcoinrpc.h | 2 | ||||
-rw-r--r-- | src/rpcwallet.cpp | 77 | ||||
-rw-r--r-- | src/wallet.cpp | 38 | ||||
-rw-r--r-- | src/wallet.h | 7 |
5 files changed, 125 insertions, 3 deletions
diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index 8c04f577d1..c032c66d7f 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -254,6 +254,8 @@ static const CRPCCommand vRPCCommands[] = { "sendrawtransaction", &sendrawtransaction, false, false }, { "gettxoutsetinfo", &gettxoutsetinfo, true, false }, { "gettxout", &gettxout, true, false }, + { "lockunspent", &lockunspent, false, false }, + { "listlockunspent", &listlockunspent, false, false }, }; CRPCTable::CRPCTable() @@ -1213,6 +1215,8 @@ Array RPCConvertValues(const std::string &strMethod, const std::vector<std::stri if (strMethod == "signrawtransaction" && n > 2) ConvertTo<Array>(params[2], true); if (strMethod == "gettxout" && n > 1) ConvertTo<boost::int64_t>(params[1]); if (strMethod == "gettxout" && n > 2) ConvertTo<bool>(params[2]); + if (strMethod == "lockunspent" && n > 0) ConvertTo<bool>(params[0]); + if (strMethod == "lockunspent" && n > 1) ConvertTo<Array>(params[1]); return params; } diff --git a/src/bitcoinrpc.h b/src/bitcoinrpc.h index dc4dc303a8..44050ae1bb 100644 --- a/src/bitcoinrpc.h +++ b/src/bitcoinrpc.h @@ -177,6 +177,8 @@ extern json_spirit::Value getinfo(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getrawtransaction(const json_spirit::Array& params, bool fHelp); // in rcprawtransaction.cpp extern json_spirit::Value listunspent(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value lockunspent(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value listlockunspent(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value createrawtransaction(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value decoderawtransaction(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value signrawtransaction(const json_spirit::Array& params, bool fHelp); diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp index 29b3298b99..dc80d84a7d 100644 --- a/src/rpcwallet.cpp +++ b/src/rpcwallet.cpp @@ -3,14 +3,18 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include <boost/assign/list_of.hpp> + #include "wallet.h" #include "walletdb.h" #include "bitcoinrpc.h" #include "init.h" #include "base58.h" -using namespace json_spirit; using namespace std; +using namespace boost; +using namespace boost::assign; +using namespace json_spirit; int64 nWalletUnlockTime; static CCriticalSection cs_nWalletUnlockTime; @@ -1496,3 +1500,74 @@ Value validateaddress(const Array& params, bool fHelp) return ret; } +Value lockunspent(const Array& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 2) + throw runtime_error( + "lockunspent unlock? [array-of-Objects]\n" + "Updates list of temporarily unspendable outputs."); + + if (params.size() == 1) + RPCTypeCheck(params, list_of(bool_type)); + else + RPCTypeCheck(params, list_of(bool_type)(array_type)); + + bool fUnlock = params[0].get_bool(); + + if (params.size() == 1) { + if (fUnlock) + pwalletMain->UnlockAllCoins(); + return true; + } + + Array outputs = params[1].get_array(); + BOOST_FOREACH(Value& output, outputs) + { + if (output.type() != obj_type) + throw JSONRPCError(-8, "Invalid parameter, expected object"); + const Object& o = output.get_obj(); + + RPCTypeCheck(o, map_list_of("txid", str_type)("vout", int_type)); + + string txid = find_value(o, "txid").get_str(); + if (!IsHex(txid)) + throw JSONRPCError(-8, "Invalid parameter, expected hex txid"); + + int nOutput = find_value(o, "vout").get_int(); + if (nOutput < 0) + throw JSONRPCError(-8, "Invalid parameter, vout must be positive"); + + COutPoint outpt(uint256(txid), nOutput); + + if (fUnlock) + pwalletMain->UnlockCoin(outpt); + else + pwalletMain->LockCoin(outpt); + } + + return true; +} + +Value listlockunspent(const Array& params, bool fHelp) +{ + if (fHelp || params.size() > 0) + throw runtime_error( + "listlockunspent\n" + "Returns list of temporarily unspendable outputs."); + + vector<COutPoint> vOutpts; + pwalletMain->ListLockedCoins(vOutpts); + + Array ret; + + BOOST_FOREACH(COutPoint &outpt, vOutpts) { + Object o; + + o.push_back(Pair("txid", outpt.hash.GetHex())); + o.push_back(Pair("vout", (int)outpt.n)); + ret.push_back(o); + } + + return ret; +} + diff --git a/src/wallet.cpp b/src/wallet.cpp index 0115e56b8e..af3612d435 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -953,9 +953,11 @@ void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed) const if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0) continue; - for (unsigned int i = 0; i < pcoin->vout.size(); i++) - if (!(pcoin->IsSpent(i)) && IsMine(pcoin->vout[i]) && pcoin->vout[i].nValue > 0) + for (unsigned int i = 0; i < pcoin->vout.size(); i++) { + if (!(pcoin->IsSpent(i)) && IsMine(pcoin->vout[i]) && + !IsLockedCoin((*it).first, i) && pcoin->vout[i].nValue > 0) vCoins.push_back(COutput(pcoin, i, pcoin->GetDepthInMainChain())); + } } } } @@ -1766,3 +1768,35 @@ void CWallet::UpdatedTransaction(const uint256 &hashTx) NotifyTransactionChanged(this, hashTx, CT_UPDATED); } } + +void CWallet::LockCoin(COutPoint& output) +{ + setLockedCoins.insert(output); +} + +void CWallet::UnlockCoin(COutPoint& output) +{ + setLockedCoins.erase(output); +} + +void CWallet::UnlockAllCoins() +{ + setLockedCoins.clear(); +} + +bool CWallet::IsLockedCoin(uint256 hash, unsigned int n) const +{ + COutPoint outpt(hash, n); + + return (setLockedCoins.count(outpt) > 0); +} + +void CWallet::ListLockedCoins(std::vector<COutPoint>& vOutpts) +{ + for (std::set<COutPoint>::iterator it = setLockedCoins.begin(); + it != setLockedCoins.end(); it++) { + COutPoint outpt = (*it); + vOutpts.push_back(outpt); + } +} + diff --git a/src/wallet.h b/src/wallet.h index 5e2f8e0ba1..3a9fdc64d5 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -119,11 +119,18 @@ public: CPubKey vchDefaultKey; + std::set<COutPoint> setLockedCoins; + // check whether we are allowed to upgrade (or already support) to the named feature bool CanSupportFeature(enum WalletFeature wf) { return nWalletMaxVersion >= wf; } void AvailableCoins(std::vector<COutput>& vCoins, bool fOnlyConfirmed=true) const; bool SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, std::vector<COutput> vCoins, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const; + bool IsLockedCoin(uint256 hash, unsigned int n) const; + void LockCoin(COutPoint& output); + void UnlockCoin(COutPoint& output); + void UnlockAllCoins(); + void ListLockedCoins(std::vector<COutPoint>& vOutpts); // keystore implementation // Generate a new key |