Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
692b827
Add DummySignatureCreator which just creates zeroed sigs
random-zebra May 26, 2020
ccb18dd
Add FundTransaction method to wallet
random-zebra May 26, 2020
761e60e
Add fundrawtransaction RPC method
random-zebra Jun 1, 2020
a2f8071
[wallet] CreateTransaction: simplify change address check
random-zebra Jun 3, 2020
bc44ba0
[wallet] allow transaction without change if keypool is empty
random-zebra Jun 3, 2020
ab407ff
[Tests] Fix and enable fundrawtransaction functional tests
random-zebra Jun 2, 2020
fab6556
Exempt unspendable transaction outputs from dust checks
random-zebra Jun 3, 2020
12b38b0
Add have-pubkey distinction to ISMINE flags
random-zebra Jun 4, 2020
cbffa80
Add logic to track pubkeys as watch-only, not just scripts
random-zebra Jun 4, 2020
60a20a4
Split up importaddress into helper functions
random-zebra Jun 4, 2020
816dabb
Add p2sh option to importaddress to import redeemScripts
random-zebra Jun 4, 2020
7b4eb6d
Add importpubkey method to import a watch-only pubkey
random-zebra Jun 4, 2020
1b153e5
Update importaddress help to push its use to script-only
random-zebra Jun 4, 2020
134c5d2
Implement watchonly support in fundrawtransaction
random-zebra Jun 4, 2020
76c8d54
[QA] Test watchonly addrs in fundrawtransaction tests
random-zebra Jun 4, 2020
d655b42
Use CCoinControl selection in CWallet::FundTransaction
random-zebra Jun 4, 2020
0c1f7ba
Add strict flag to RPCTypeCheckObj
random-zebra Jun 4, 2020
a3ac191
Add change options to fundrawtransaction
random-zebra Jun 4, 2020
bc9dc67
Add lockUnspents option to fundrawtransaction
random-zebra Jun 4, 2020
87dbdf8
[QA] Test new options in rpc_fundrawtransaction functional test
random-zebra Jun 4, 2020
169bc3b
[RPC] add feerate option to fundrawtransaction
random-zebra Jun 4, 2020
5bca4f4
Add more clear interface for CoinControl.h regarding individual feerate
random-zebra Jun 4, 2020
dd35760
[QA] Add test_option_feerate to rpc_fundrawtransaction functional test
random-zebra Jun 4, 2020
fc81158
[QA] Add test_change_position case to rpc_fundrawtransaction.py
random-zebra Jun 28, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 11 additions & 6 deletions src/coincontrol.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ class CCoinControl
bool fAllowWatchOnly;
//! Minimum absolute fee (not per kilobyte)
CAmount nMinimumTotalFee;
//! Override estimated feerate
bool fOverrideFeeRate;
//! Feerate to use if overrideFeeRate is true
CFeeRate nFeeRate;

CCoinControl()
{
Expand All @@ -36,8 +40,10 @@ class CCoinControl
setSelected.clear();
useSwiftTX = false;
fAllowOtherInputs = false;
fAllowWatchOnly = true;
fAllowWatchOnly = false;
nMinimumTotalFee = 0;
nFeeRate = CFeeRate(0);
fOverrideFeeRate = false;
fSplitBlock = false;
nSplitBlock = 1;
}
Expand All @@ -47,10 +53,9 @@ class CCoinControl
return (!setSelected.empty());
}

bool IsSelected(const uint256& hash, unsigned int n) const
bool IsSelected(const COutPoint& output) const
{
COutPoint outpt(hash, n);
return (setSelected.count(outpt) > 0);
return (setSelected.count(output) > 0);
}

void Select(const COutPoint& output)
Expand All @@ -68,12 +73,12 @@ class CCoinControl
setSelected.clear();
}

void ListSelected(std::vector<COutPoint>& vOutpoints)
void ListSelected(std::vector<COutPoint>& vOutpoints) const
{
vOutpoints.assign(setSelected.begin(), setSelected.end());
}

unsigned int QuantitySelected()
unsigned int QuantitySelected() const
{
return setSelected.size();
}
Expand Down
5 changes: 4 additions & 1 deletion src/crypter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -199,13 +199,16 @@ bool CCryptoKeyStore::GetPubKey(const CKeyID& address, CPubKey& vchPubKeyOut) co
{
LOCK(cs_KeyStore);
if (!IsCrypted())
return CKeyStore::GetPubKey(address, vchPubKeyOut);
return CBasicKeyStore::GetPubKey(address, vchPubKeyOut);

CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
if (mi != mapCryptedKeys.end()) {
vchPubKeyOut = (*mi).second.first;
return true;
}

// Check for watch-only pubkeys
return CBasicKeyStore::GetPubKey(address, vchPubKeyOut);
}
return false;
}
Expand Down
42 changes: 35 additions & 7 deletions src/keystore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,26 @@
#include "util.h"


bool CKeyStore::GetPubKey(const CKeyID& address, CPubKey& vchPubKeyOut) const
bool CKeyStore::AddKey(const CKey& key)
{
return AddKeyPubKey(key, key.GetPubKey());
}

bool CBasicKeyStore::GetPubKey(const CKeyID &address, CPubKey &vchPubKeyOut) const
{
CKey key;
if (!GetKey(address, key))
if (!GetKey(address, key)) {
WatchKeyMap::const_iterator it = mapWatchKeys.find(address);
if (it != mapWatchKeys.end()) {
vchPubKeyOut = it->second;
return true;
}
return false;
}
vchPubKeyOut = key.GetPubKey();
return true;
}

bool CKeyStore::AddKey(const CKey& key)
{
return AddKeyPubKey(key, key.GetPubKey());
}

bool CBasicKeyStore::AddKeyPubKey(const CKey& key, const CPubKey& pubkey)
{
LOCK(cs_KeyStore);
Expand Down Expand Up @@ -61,17 +67,39 @@ bool CBasicKeyStore::GetCScript(const CScriptID& hash, CScript& redeemScriptOut)
return false;
}

static bool ExtractPubKey(const CScript &dest, CPubKey& pubKeyOut)
{
//TODO: Use Solver to extract this?
CScript::const_iterator pc = dest.begin();
opcodetype opcode;
std::vector<unsigned char> vch;
if (!dest.GetOp(pc, opcode, vch) || vch.size() < 33 || vch.size() > 65)
return false;
pubKeyOut = CPubKey(vch);
if (!pubKeyOut.IsFullyValid())
return false;
if (!dest.GetOp(pc, opcode, vch) || opcode != OP_CHECKSIG || dest.GetOp(pc, opcode, vch))
return false;
return true;
}

bool CBasicKeyStore::AddWatchOnly(const CScript& dest)
{
LOCK(cs_KeyStore);
setWatchOnly.insert(dest);
CPubKey pubKey;
if (ExtractPubKey(dest, pubKey))
mapWatchKeys[pubKey.GetID()] = pubKey;
return true;
}

bool CBasicKeyStore::RemoveWatchOnly(const CScript& dest)
{
LOCK(cs_KeyStore);
setWatchOnly.erase(dest);
CPubKey pubKey;
if (ExtractPubKey(dest, pubKey))
mapWatchKeys.erase(pubKey.GetID());
return true;
}

Expand Down
5 changes: 4 additions & 1 deletion src/keystore.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class CKeyStore
virtual bool HaveKey(const CKeyID& address) const = 0;
virtual bool GetKey(const CKeyID& address, CKey& keyOut) const = 0;
virtual void GetKeys(std::set<CKeyID>& setAddress) const = 0;
virtual bool GetPubKey(const CKeyID& address, CPubKey& vchPubKeyOut) const;
virtual bool GetPubKey(const CKeyID& address, CPubKey& vchPubKeyOut) const = 0;

//! Support for BIP 0013 : see https://github.com/bitcoin/bips/blob/master/bip-0013.mediawiki
virtual bool AddCScript(const CScript& redeemScript) = 0;
Expand All @@ -49,6 +49,7 @@ class CKeyStore
};

typedef std::map<CKeyID, CKey> KeyMap;
typedef std::map<CKeyID, CPubKey> WatchKeyMap;
typedef std::map<CScriptID, CScript> ScriptMap;
typedef std::set<CScript> WatchOnlySet;

Expand All @@ -57,11 +58,13 @@ class CBasicKeyStore : public CKeyStore
{
protected:
KeyMap mapKeys;
WatchKeyMap mapWatchKeys;
ScriptMap mapScripts;
WatchOnlySet setWatchOnly;

public:
bool AddKeyPubKey(const CKey& key, const CPubKey& pubkey);
bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const;
bool HaveKey(const CKeyID& address) const;
void GetKeys(std::set<CKeyID>& setAddress) const;
bool GetKey(const CKeyID& address, CKey& keyOut) const;
Expand Down
27 changes: 18 additions & 9 deletions src/primitives/transaction.h
Original file line number Diff line number Diff line change
Expand Up @@ -167,17 +167,26 @@ class CTxOut
uint256 GetHash() const;
bool GetKeyIDFromUTXO(CKeyID& keyIDRet) const;

bool IsDust(CFeeRate minRelayTxFee) const
CAmount GetDustThreshold(const CFeeRate &minRelayTxFee) const
{
// "Dust" is defined in terms of CTransaction::minRelayTxFee, which has units upiv-per-kilobyte.
// If you'd pay more than 1/3 in fees to spend something, then we consider it dust.
// A typical txout is 34 bytes big, and will need a CTxIn of at least 148 bytes to spend
// i.e. total is 148 + 32 = 182 bytes. Default -minrelaytxfee is 10000 upiv per kB
// and that means that fee per txout is 182 * 10000 / 1000 = 1820 upiv.
// So dust is a txout less than 1820 *3 = 5460 upiv
// with default -minrelaytxfee = minRelayTxFee = 10000 upiv per kB.
// "Dust" is defined in terms of CTransaction::minRelayTxFee,
// which has units satoshis-per-kilobyte.
// If you'd pay more than 1/3 in fees
// to spend something, then we consider it dust.
// A typical spendable txout is 34 bytes big, and will
// need a CTxIn of at least 148 bytes to spend:
// so dust is a spendable txout less than 546 satoshis
// with default minRelayTxFee.
if (scriptPubKey.IsUnspendable())
return 0;

size_t nSize = GetSerializeSize(*this, SER_DISK, 0) + 148u;
return (nValue < 3*minRelayTxFee.GetFee(nSize));
return 3 * minRelayTxFee.GetFee(nSize);
}

bool IsDust(CFeeRate minRelayTxFee) const
{
return (nValue < GetDustThreshold(minRelayTxFee));
}

bool IsZerocoinMint() const;
Expand Down
2 changes: 1 addition & 1 deletion src/qt/coincontroldialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -901,7 +901,7 @@ void CoinControlDialog::updateView()
}

// set checkbox
if (coinControl->IsSelected(txhash, out.i))
if (coinControl->IsSelected(COutPoint(txhash, out.i)))
itemOutput->setCheckState(COLUMN_CHECKBOX, Qt::Checked);

// outputs delegated (for cold staking)
Expand Down
4 changes: 2 additions & 2 deletions src/qt/transactiondesc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ QString TransactionDesc::toHTML(CWallet* wallet, CWalletTx& wtx, TransactionReco
}

if (fAllFromMe) {
if (fAllFromMe == ISMINE_WATCH_ONLY)
if (fAllFromMe & ISMINE_WATCH_ONLY)
strHTML += "<b>" + tr("From") + ":</b> " + tr("watch-only") + "<br>";

//
Expand All @@ -200,7 +200,7 @@ QString TransactionDesc::toHTML(CWallet* wallet, CWalletTx& wtx, TransactionReco
strHTML += GUIUtil::HtmlEscape(EncodeDestination(address));
if (toSelf == ISMINE_SPENDABLE)
strHTML += " (own address)";
else if (toSelf == ISMINE_WATCH_ONLY)
else if (toSelf & ISMINE_WATCH_ONLY)
strHTML += " (watch-only)";
strHTML += "<br>";
}
Expand Down
9 changes: 6 additions & 3 deletions src/qt/walletmodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
{
CAmount total = 0;
QList<SendCoinsRecipient> recipients = transaction.getRecipients();
std::vector<std::pair<CScript, CAmount> > vecSend;
std::vector<CRecipient> vecSend;

if (recipients.empty()) {
return OK;
Expand All @@ -413,7 +413,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
subtotal += out.amount();
const unsigned char* scriptStr = (const unsigned char*)out.script().data();
CScript scriptPubKey(scriptStr, scriptStr + out.script().size());
vecSend.push_back(std::pair<CScript, CAmount>(scriptPubKey, out.amount()));
vecSend.push_back(CRecipient{scriptPubKey, static_cast<CAmount>(out.amount()), false});
}
if (subtotal <= 0) {
return InvalidAmount;
Expand Down Expand Up @@ -453,7 +453,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
// Regular P2PK or P2PKH
scriptPubKey = GetScriptForDestination(out);
}
vecSend.push_back(std::pair<CScript, CAmount>(scriptPubKey, rcp.amount));
vecSend.push_back(CRecipient{scriptPubKey, rcp.amount, false});

total += rcp.amount;
}
Expand All @@ -473,6 +473,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact

transaction.newPossibleKeyChange(wallet);
CAmount nFeeRequired = 0;
int nChangePosInOut = -1;
std::string strFailReason;

CWalletTx* newTx = transaction.getTransaction();
Expand All @@ -489,9 +490,11 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
*newTx,
*keyChange,
nFeeRequired,
nChangePosInOut,
strFailReason,
coinControl,
recipients[0].inputType,
true,
recipients[0].useSwiftTX,
0,
fIncludeDelegations);
Expand Down
3 changes: 3 additions & 0 deletions src/rpc/client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{"createrawtransaction", 0},
{"createrawtransaction", 1},
{"createrawtransaction", 2},
{"fundrawtransaction", 1},
{"signrawtransaction", 1},
{"signrawtransaction", 2},
{"sendrawtransaction", 1},
Expand All @@ -111,6 +112,8 @@ static const CRPCConvertParam vRPCConvertParams[] =
{"importprivkey", 2},
{"importprivkey", 3},
{"importaddress", 2},
{"importaddress", 3},
{"importpubkey", 2},
{"verifychain", 0},
{"verifychain", 1},
{"keypoolrefill", 0},
Expand Down
Loading