Skip to content

Commit

Permalink
Merge pull request #1861 from jgarzik/coinlock
Browse files Browse the repository at this point in the history
Add new RPC "lockunspent", to prevent spending of selected outputs
  • Loading branch information
gavinandresen committed Dec 12, 2012
2 parents 043a8fb + fdbb537 commit 78504bb
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 3 deletions.
4 changes: 4 additions & 0 deletions src/bitcoinrpc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -1215,6 +1217,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;
}
Expand Down
2 changes: 2 additions & 0 deletions src/bitcoinrpc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
77 changes: 76 additions & 1 deletion src/rpcwallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -1497,3 +1501,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;
}

38 changes: 36 additions & 2 deletions src/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -957,9 +957,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()));
}
}
}
}
Expand Down Expand Up @@ -1770,3 +1772,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);
}
}

7 changes: 7 additions & 0 deletions src/wallet.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,11 +119,18 @@ class CWallet : public CCryptoKeyStore

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
Expand Down

0 comments on commit 78504bb

Please sign in to comment.