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.
This commit is contained in:
parent
6caffb5358
commit
fdbb537d26
5 changed files with 125 additions and 3 deletions
|
@ -254,6 +254,8 @@ static const CRPCCommand vRPCCommands[] =
|
||||||
{ "sendrawtransaction", &sendrawtransaction, false, false },
|
{ "sendrawtransaction", &sendrawtransaction, false, false },
|
||||||
{ "gettxoutsetinfo", &gettxoutsetinfo, true, false },
|
{ "gettxoutsetinfo", &gettxoutsetinfo, true, false },
|
||||||
{ "gettxout", &gettxout, true, false },
|
{ "gettxout", &gettxout, true, false },
|
||||||
|
{ "lockunspent", &lockunspent, false, false },
|
||||||
|
{ "listlockunspent", &listlockunspent, false, false },
|
||||||
};
|
};
|
||||||
|
|
||||||
CRPCTable::CRPCTable()
|
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 == "signrawtransaction" && n > 2) ConvertTo<Array>(params[2], true);
|
||||||
if (strMethod == "gettxout" && n > 1) ConvertTo<boost::int64_t>(params[1]);
|
if (strMethod == "gettxout" && n > 1) ConvertTo<boost::int64_t>(params[1]);
|
||||||
if (strMethod == "gettxout" && n > 2) ConvertTo<bool>(params[2]);
|
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;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 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 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 createrawtransaction(const json_spirit::Array& params, bool fHelp);
|
||||||
extern json_spirit::Value decoderawtransaction(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);
|
extern json_spirit::Value signrawtransaction(const json_spirit::Array& params, bool fHelp);
|
||||||
|
|
|
@ -3,14 +3,18 @@
|
||||||
// Distributed under the MIT/X11 software license, see the accompanying
|
// Distributed under the MIT/X11 software license, see the accompanying
|
||||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#include <boost/assign/list_of.hpp>
|
||||||
|
|
||||||
#include "wallet.h"
|
#include "wallet.h"
|
||||||
#include "walletdb.h"
|
#include "walletdb.h"
|
||||||
#include "bitcoinrpc.h"
|
#include "bitcoinrpc.h"
|
||||||
#include "init.h"
|
#include "init.h"
|
||||||
#include "base58.h"
|
#include "base58.h"
|
||||||
|
|
||||||
using namespace json_spirit;
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
using namespace boost;
|
||||||
|
using namespace boost::assign;
|
||||||
|
using namespace json_spirit;
|
||||||
|
|
||||||
int64 nWalletUnlockTime;
|
int64 nWalletUnlockTime;
|
||||||
static CCriticalSection cs_nWalletUnlockTime;
|
static CCriticalSection cs_nWalletUnlockTime;
|
||||||
|
@ -1496,3 +1500,74 @@ Value validateaddress(const Array& params, bool fHelp)
|
||||||
return ret;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -953,11 +953,13 @@ void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed) const
|
||||||
if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)
|
if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (unsigned int i = 0; i < pcoin->vout.size(); i++)
|
for (unsigned int i = 0; i < pcoin->vout.size(); i++) {
|
||||||
if (!(pcoin->IsSpent(i)) && IsMine(pcoin->vout[i]) && pcoin->vout[i].nValue > 0)
|
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()));
|
vCoins.push_back(COutput(pcoin, i, pcoin->GetDepthInMainChain()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ApproximateBestSubset(vector<pair<int64, pair<const CWalletTx*,unsigned int> > >vValue, int64 nTotalLower, int64 nTargetValue,
|
static void ApproximateBestSubset(vector<pair<int64, pair<const CWalletTx*,unsigned int> > >vValue, int64 nTotalLower, int64 nTargetValue,
|
||||||
|
@ -1766,3 +1768,35 @@ void CWallet::UpdatedTransaction(const uint256 &hashTx)
|
||||||
NotifyTransactionChanged(this, hashTx, CT_UPDATED);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -119,11 +119,18 @@ public:
|
||||||
|
|
||||||
CPubKey vchDefaultKey;
|
CPubKey vchDefaultKey;
|
||||||
|
|
||||||
|
std::set<COutPoint> setLockedCoins;
|
||||||
|
|
||||||
// check whether we are allowed to upgrade (or already support) to the named feature
|
// check whether we are allowed to upgrade (or already support) to the named feature
|
||||||
bool CanSupportFeature(enum WalletFeature wf) { return nWalletMaxVersion >= wf; }
|
bool CanSupportFeature(enum WalletFeature wf) { return nWalletMaxVersion >= wf; }
|
||||||
|
|
||||||
void AvailableCoins(std::vector<COutput>& vCoins, bool fOnlyConfirmed=true) const;
|
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 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
|
// keystore implementation
|
||||||
// Generate a new key
|
// Generate a new key
|
||||||
|
|
Loading…
Reference in a new issue