aboutsummaryrefslogtreecommitdiff
path: root/src/wallet.cpp
diff options
context:
space:
mode:
authorCozz Lovan <cozzlovan@yahoo.com>2013-08-12 17:03:03 +0200
committerWladimir J. van der Laan <laanwj@gmail.com>2013-11-14 14:25:10 +0100
commit6a86c24db146d9ca5d1d5c83099d935c3feb63bb (patch)
tree84ea08401061e81d178a4c2caf34233281227da4 /src/wallet.cpp
parent8dfd8c62dccac96afbda5ad0e66e68ee4820481f (diff)
Coin Control Features
Diffstat (limited to 'src/wallet.cpp')
-rw-r--r--src/wallet.cpp64
1 files changed, 43 insertions, 21 deletions
diff --git a/src/wallet.cpp b/src/wallet.cpp
index 868716cb2c..3e684a7879 100644
--- a/src/wallet.cpp
+++ b/src/wallet.cpp
@@ -7,6 +7,7 @@
#include "base58.h"
#include "net.h"
+#include "coincontrol.h"
#include <inttypes.h>
#include <stdint.h>
@@ -1004,7 +1005,7 @@ int64_t CWallet::GetImmatureBalance() const
}
// populate vCoins with vector of spendable COutputs
-void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed) const
+void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const CCoinControl *coinControl) const
{
vCoins.clear();
@@ -1025,8 +1026,9 @@ void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed) const
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()));
+ !IsLockedCoin((*it).first, i) && pcoin->vout[i].nValue > 0 &&
+ (!coinControl || !coinControl->HasSelected() || coinControl->IsSelected((*it).first, i)))
+ vCoins.push_back(COutput(pcoin, i, pcoin->GetDepthInMainChain()));
}
}
}
@@ -1176,10 +1178,21 @@ bool CWallet::SelectCoinsMinConf(int64_t nTargetValue, int nConfMine, int nConfT
return true;
}
-bool CWallet::SelectCoins(int64_t nTargetValue, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64_t& nValueRet) const
+bool CWallet::SelectCoins(int64_t nTargetValue, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64_t& nValueRet, const CCoinControl* coinControl) const
{
vector<COutput> vCoins;
- AvailableCoins(vCoins);
+ AvailableCoins(vCoins, true, coinControl);
+
+ // coin control -> return all selected outputs (we want all selected to go into the transaction for sure)
+ if (coinControl && coinControl->HasSelected())
+ {
+ BOOST_FOREACH(const COutput& out, vCoins)
+ {
+ nValueRet += out.tx->vout[out.i].nValue;
+ setCoinsRet.insert(make_pair(out.tx, out.i));
+ }
+ return (nValueRet >= nTargetValue);
+ }
return (SelectCoinsMinConf(nTargetValue, 1, 6, vCoins, setCoinsRet, nValueRet) ||
SelectCoinsMinConf(nTargetValue, 1, 1, vCoins, setCoinsRet, nValueRet) ||
@@ -1190,7 +1203,7 @@ bool CWallet::SelectCoins(int64_t nTargetValue, set<pair<const CWalletTx*,unsign
bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend,
- CWalletTx& wtxNew, CReserveKey& reservekey, int64_t& nFeeRet, std::string& strFailReason)
+ CWalletTx& wtxNew, CReserveKey& reservekey, int64_t& nFeeRet, std::string& strFailReason, const CCoinControl* coinControl)
{
int64_t nValue = 0;
BOOST_FOREACH (const PAIRTYPE(CScript, int64_t)& s, vecSend)
@@ -1237,7 +1250,7 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend,
// Choose coins to use
set<pair<const CWalletTx*,unsigned int> > setCoins;
int64_t nValueIn = 0;
- if (!SelectCoins(nTotalValue, setCoins, nValueIn))
+ if (!SelectCoins(nTotalValue, setCoins, nValueIn, coinControl))
{
strFailReason = _("Insufficient funds");
return false;
@@ -1265,22 +1278,31 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend,
if (nChange > 0)
{
- // Note: We use a new key here to keep it from being obvious which side is the change.
- // The drawback is that by not reusing a previous key, the change may be lost if a
- // backup is restored, if the backup doesn't have the new private key for the change.
- // If we reused the old key, it would be possible to add code to look for and
- // rediscover unknown transactions that were written with keys of ours to recover
- // post-backup change.
-
- // Reserve a new key pair from key pool
- CPubKey vchPubKey;
- assert(reservekey.GetReservedKey(vchPubKey)); // should never fail, as we just unlocked
-
// Fill a vout to ourself
// TODO: pass in scriptChange instead of reservekey so
// change transaction isn't always pay-to-bitcoin-address
CScript scriptChange;
- scriptChange.SetDestination(vchPubKey.GetID());
+
+ // coin control: send change to custom address
+ if (coinControl && !boost::get<CNoDestination>(&coinControl->destChange))
+ scriptChange.SetDestination(coinControl->destChange);
+
+ // no coin control: send change to newly generated address
+ else
+ {
+ // Note: We use a new key here to keep it from being obvious which side is the change.
+ // The drawback is that by not reusing a previous key, the change may be lost if a
+ // backup is restored, if the backup doesn't have the new private key for the change.
+ // If we reused the old key, it would be possible to add code to look for and
+ // rediscover unknown transactions that were written with keys of ours to recover
+ // post-backup change.
+
+ // Reserve a new key pair from key pool
+ CPubKey vchPubKey;
+ assert(reservekey.GetReservedKey(vchPubKey)); // should never fail, as we just unlocked
+
+ scriptChange.SetDestination(vchPubKey.GetID());
+ }
CTxOut newTxOut(nChange, scriptChange);
@@ -1353,11 +1375,11 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend,
}
bool CWallet::CreateTransaction(CScript scriptPubKey, int64_t nValue,
- CWalletTx& wtxNew, CReserveKey& reservekey, int64_t& nFeeRet, std::string& strFailReason)
+ CWalletTx& wtxNew, CReserveKey& reservekey, int64_t& nFeeRet, std::string& strFailReason, const CCoinControl* coinControl)
{
vector< pair<CScript, int64_t> > vecSend;
vecSend.push_back(make_pair(scriptPubKey, nValue));
- return CreateTransaction(vecSend, wtxNew, reservekey, nFeeRet, strFailReason);
+ return CreateTransaction(vecSend, wtxNew, reservekey, nFeeRet, strFailReason, coinControl);
}
// Call after CreateTransaction unless you want to abort