Use 72 byte dummy signatures when watching only inputs may be used

With watching only inputs, we do not know how large the signatures
for those inputs will be as their signers may not have implemented
71 byte signatures. Thus we estimate their fees using the 72 byte
dummy signature to ensure that we pay enough fees.

This only effects fundrawtransaction when includeWatching is true.
This commit is contained in:
Andrew Chow 2018-08-07 16:59:53 -07:00
parent 48b1473c89
commit e306be7429
4 changed files with 45 additions and 37 deletions

View file

@ -417,22 +417,25 @@ public:
const DummySignatureChecker DUMMY_CHECKER; const DummySignatureChecker DUMMY_CHECKER;
class DummySignatureCreator final : public BaseSignatureCreator { class DummySignatureCreator final : public BaseSignatureCreator {
private:
char m_r_len = 32;
char m_s_len = 32;
public: public:
DummySignatureCreator() {} DummySignatureCreator(char r_len, char s_len) : m_r_len(r_len), m_s_len(s_len) {}
const BaseSignatureChecker& Checker() const override { return DUMMY_CHECKER; } const BaseSignatureChecker& Checker() const override { return DUMMY_CHECKER; }
bool CreateSig(const SigningProvider& provider, std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const override bool CreateSig(const SigningProvider& provider, std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const override
{ {
// Create a dummy signature that is a valid DER-encoding // Create a dummy signature that is a valid DER-encoding
vchSig.assign(71, '\000'); vchSig.assign(m_r_len + m_s_len + 7, '\000');
vchSig[0] = 0x30; vchSig[0] = 0x30;
vchSig[1] = 68; vchSig[1] = m_r_len + m_s_len + 4;
vchSig[2] = 0x02; vchSig[2] = 0x02;
vchSig[3] = 32; vchSig[3] = m_r_len;
vchSig[4] = 0x01; vchSig[4] = 0x01;
vchSig[4 + 32] = 0x02; vchSig[4 + m_r_len] = 0x02;
vchSig[5 + 32] = 32; vchSig[5 + m_r_len] = m_s_len;
vchSig[6 + 32] = 0x01; vchSig[6 + m_r_len] = 0x01;
vchSig[6 + 32 + 32] = SIGHASH_ALL; vchSig[6 + m_r_len + m_s_len] = SIGHASH_ALL;
return true; return true;
} }
}; };
@ -450,7 +453,8 @@ bool LookupHelper(const M& map, const K& key, V& value)
} }
const BaseSignatureCreator& DUMMY_SIGNATURE_CREATOR = DummySignatureCreator(); const BaseSignatureCreator& DUMMY_SIGNATURE_CREATOR = DummySignatureCreator(32, 32);
const BaseSignatureCreator& DUMMY_MAXIMUM_SIGNATURE_CREATOR = DummySignatureCreator(33, 32);
const SigningProvider& DUMMY_SIGNING_PROVIDER = SigningProvider(); const SigningProvider& DUMMY_SIGNING_PROVIDER = SigningProvider();
bool IsSolvable(const SigningProvider& provider, const CScript& script) bool IsSolvable(const SigningProvider& provider, const CScript& script)

View file

@ -80,8 +80,10 @@ public:
bool CreateSig(const SigningProvider& provider, std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const override; bool CreateSig(const SigningProvider& provider, std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const override;
}; };
/** A signature creator that just produces 72-byte empty signatures. */ /** A signature creator that just produces 71-byte empty signatures. */
extern const BaseSignatureCreator& DUMMY_SIGNATURE_CREATOR; extern const BaseSignatureCreator& DUMMY_SIGNATURE_CREATOR;
/** A signature creator that just produces 72-byte empty signatures. */
extern const BaseSignatureCreator& DUMMY_MAXIMUM_SIGNATURE_CREATOR;
typedef std::pair<CPubKey, std::vector<unsigned char>> SigPair; typedef std::pair<CPubKey, std::vector<unsigned char>> SigPair;

View file

@ -1541,29 +1541,28 @@ int64_t CWalletTx::GetTxTime() const
} }
// Helper for producing a max-sized low-S low-R signature (eg 71 bytes) // Helper for producing a max-sized low-S low-R signature (eg 71 bytes)
bool CWallet::DummySignInput(CTxIn &tx_in, const CTxOut &txout) const // or a max-sized low-S signature (e.g. 72 bytes) if use_max_sig is true
bool CWallet::DummySignInput(CTxIn &tx_in, const CTxOut &txout, bool use_max_sig) const
{ {
// Fill in dummy signatures for fee calculation. // Fill in dummy signatures for fee calculation.
const CScript& scriptPubKey = txout.scriptPubKey; const CScript& scriptPubKey = txout.scriptPubKey;
SignatureData sigdata; SignatureData sigdata;
if (!ProduceSignature(*this, DUMMY_SIGNATURE_CREATOR, scriptPubKey, sigdata)) if (!ProduceSignature(*this, use_max_sig ? DUMMY_MAXIMUM_SIGNATURE_CREATOR : DUMMY_SIGNATURE_CREATOR, scriptPubKey, sigdata)) {
{
return false; return false;
} else {
UpdateInput(tx_in, sigdata);
} }
UpdateInput(tx_in, sigdata);
return true; return true;
} }
// Helper for producing a bunch of max-sized low-S low-R signatures (eg 71 bytes) // Helper for producing a bunch of max-sized low-S low-R signatures (eg 71 bytes)
bool CWallet::DummySignTx(CMutableTransaction &txNew, const std::vector<CTxOut> &txouts) const bool CWallet::DummySignTx(CMutableTransaction &txNew, const std::vector<CTxOut> &txouts, bool use_max_sig) const
{ {
// Fill in dummy signatures for fee calculation. // Fill in dummy signatures for fee calculation.
int nIn = 0; int nIn = 0;
for (const auto& txout : txouts) for (const auto& txout : txouts)
{ {
if (!DummySignInput(txNew.vin[nIn], txout)) { if (!DummySignInput(txNew.vin[nIn], txout, use_max_sig)) {
return false; return false;
} }
@ -1572,7 +1571,7 @@ bool CWallet::DummySignTx(CMutableTransaction &txNew, const std::vector<CTxOut>
return true; return true;
} }
int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet) int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet, bool use_max_sig)
{ {
std::vector<CTxOut> txouts; std::vector<CTxOut> txouts;
// Look up the inputs. We should have already checked that this transaction // Look up the inputs. We should have already checked that this transaction
@ -1586,14 +1585,14 @@ int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wall
assert(input.prevout.n < mi->second.tx->vout.size()); assert(input.prevout.n < mi->second.tx->vout.size());
txouts.emplace_back(mi->second.tx->vout[input.prevout.n]); txouts.emplace_back(mi->second.tx->vout[input.prevout.n]);
} }
return CalculateMaximumSignedTxSize(tx, wallet, txouts); return CalculateMaximumSignedTxSize(tx, wallet, txouts, use_max_sig);
} }
// txouts needs to be in the order of tx.vin // txouts needs to be in the order of tx.vin
int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet, const std::vector<CTxOut>& txouts) int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet, const std::vector<CTxOut>& txouts, bool use_max_sig)
{ {
CMutableTransaction txNew(tx); CMutableTransaction txNew(tx);
if (!wallet->DummySignTx(txNew, txouts)) { if (!wallet->DummySignTx(txNew, txouts, use_max_sig)) {
// This should never happen, because IsAllFromMe(ISMINE_SPENDABLE) // This should never happen, because IsAllFromMe(ISMINE_SPENDABLE)
// implies that we can sign for every input. // implies that we can sign for every input.
return -1; return -1;
@ -1601,11 +1600,11 @@ int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wall
return GetVirtualTransactionSize(txNew); return GetVirtualTransactionSize(txNew);
} }
int CalculateMaximumSignedInputSize(const CTxOut& txout, const CWallet* wallet) int CalculateMaximumSignedInputSize(const CTxOut& txout, const CWallet* wallet, bool use_max_sig)
{ {
CMutableTransaction txn; CMutableTransaction txn;
txn.vin.push_back(CTxIn(COutPoint())); txn.vin.push_back(CTxIn(COutPoint()));
if (!wallet->DummySignInput(txn.vin[0], txout)) { if (!wallet->DummySignInput(txn.vin[0], txout, use_max_sig)) {
// This should never happen, because IsAllFromMe(ISMINE_SPENDABLE) // This should never happen, because IsAllFromMe(ISMINE_SPENDABLE)
// implies that we can sign for every input. // implies that we can sign for every input.
return -1; return -1;
@ -2332,7 +2331,7 @@ void CWallet::AvailableCoins(std::vector<COutput> &vCoins, bool fOnlySafe, const
bool solvable = IsSolvable(*this, pcoin->tx->vout[i].scriptPubKey); bool solvable = IsSolvable(*this, pcoin->tx->vout[i].scriptPubKey);
bool spendable = ((mine & ISMINE_SPENDABLE) != ISMINE_NO) || (((mine & ISMINE_WATCH_ONLY) != ISMINE_NO) && (coinControl && coinControl->fAllowWatchOnly && solvable)); bool spendable = ((mine & ISMINE_SPENDABLE) != ISMINE_NO) || (((mine & ISMINE_WATCH_ONLY) != ISMINE_NO) && (coinControl && coinControl->fAllowWatchOnly && solvable));
vCoins.push_back(COutput(pcoin, i, nDepth, spendable, solvable, safeTx)); vCoins.push_back(COutput(pcoin, i, nDepth, spendable, solvable, safeTx, (coinControl && coinControl->fAllowWatchOnly)));
// Checks the sum amount of all UTXO's. // Checks the sum amount of all UTXO's.
if (nMinimumSumAmount != MAX_MONEY) { if (nMinimumSumAmount != MAX_MONEY) {
@ -2881,7 +2880,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac
txNew.vin.push_back(CTxIn(coin.outpoint,CScript())); txNew.vin.push_back(CTxIn(coin.outpoint,CScript()));
} }
nBytes = CalculateMaximumSignedTxSize(txNew, this); nBytes = CalculateMaximumSignedTxSize(txNew, this, coin_control.fAllowWatchOnly);
if (nBytes < 0) { if (nBytes < 0) {
strFailReason = _("Signing transaction failed"); strFailReason = _("Signing transaction failed");
return false; return false;

View file

@ -276,7 +276,7 @@ public:
}; };
//Get the marginal bytes of spending the specified output //Get the marginal bytes of spending the specified output
int CalculateMaximumSignedInputSize(const CTxOut& txout, const CWallet* pwallet); int CalculateMaximumSignedInputSize(const CTxOut& txout, const CWallet* pwallet, bool use_max_sig = false);
/** /**
* A transaction with a bunch of additional info that only the owner cares about. * A transaction with a bunch of additional info that only the owner cares about.
@ -461,9 +461,9 @@ public:
CAmount GetChange() const; CAmount GetChange() const;
// Get the marginal bytes if spending the specified output from this transaction // Get the marginal bytes if spending the specified output from this transaction
int GetSpendSize(unsigned int out) const int GetSpendSize(unsigned int out, bool use_max_sig = false) const
{ {
return CalculateMaximumSignedInputSize(tx->vout[out], pwallet); return CalculateMaximumSignedInputSize(tx->vout[out], pwallet, use_max_sig);
} }
void GetAmounts(std::list<COutputEntry>& listReceived, void GetAmounts(std::list<COutputEntry>& listReceived,
@ -507,6 +507,9 @@ public:
/** Whether we know how to spend this output, ignoring the lack of keys */ /** Whether we know how to spend this output, ignoring the lack of keys */
bool fSolvable; bool fSolvable;
/** Whether to use the maximum sized, 72 byte signature when calculating the size of the input spend. This should only be set when watch-only outputs are allowed */
bool use_max_sig;
/** /**
* Whether this output is considered safe to spend. Unconfirmed transactions * Whether this output is considered safe to spend. Unconfirmed transactions
* from outside keys and unconfirmed replacement transactions are considered * from outside keys and unconfirmed replacement transactions are considered
@ -514,13 +517,13 @@ public:
*/ */
bool fSafe; bool fSafe;
COutput(const CWalletTx *txIn, int iIn, int nDepthIn, bool fSpendableIn, bool fSolvableIn, bool fSafeIn) COutput(const CWalletTx *txIn, int iIn, int nDepthIn, bool fSpendableIn, bool fSolvableIn, bool fSafeIn, bool use_max_sig_in = false)
{ {
tx = txIn; i = iIn; nDepth = nDepthIn; fSpendable = fSpendableIn; fSolvable = fSolvableIn; fSafe = fSafeIn; nInputBytes = -1; tx = txIn; i = iIn; nDepth = nDepthIn; fSpendable = fSpendableIn; fSolvable = fSolvableIn; fSafe = fSafeIn; nInputBytes = -1; use_max_sig = use_max_sig_in;
// If known and signable by the given wallet, compute nInputBytes // If known and signable by the given wallet, compute nInputBytes
// Failure will keep this value -1 // Failure will keep this value -1
if (fSpendable && tx) { if (fSpendable && tx) {
nInputBytes = tx->GetSpendSize(i); nInputBytes = tx->GetSpendSize(i, use_max_sig);
} }
} }
@ -976,14 +979,14 @@ public:
void ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& entries); void ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& entries);
bool AddAccountingEntry(const CAccountingEntry&); bool AddAccountingEntry(const CAccountingEntry&);
bool AddAccountingEntry(const CAccountingEntry&, WalletBatch *batch); bool AddAccountingEntry(const CAccountingEntry&, WalletBatch *batch);
bool DummySignTx(CMutableTransaction &txNew, const std::set<CTxOut> &txouts) const bool DummySignTx(CMutableTransaction &txNew, const std::set<CTxOut> &txouts, bool use_max_sig = false) const
{ {
std::vector<CTxOut> v_txouts(txouts.size()); std::vector<CTxOut> v_txouts(txouts.size());
std::copy(txouts.begin(), txouts.end(), v_txouts.begin()); std::copy(txouts.begin(), txouts.end(), v_txouts.begin());
return DummySignTx(txNew, v_txouts); return DummySignTx(txNew, v_txouts, use_max_sig);
} }
bool DummySignTx(CMutableTransaction &txNew, const std::vector<CTxOut> &txouts) const; bool DummySignTx(CMutableTransaction &txNew, const std::vector<CTxOut> &txouts, bool use_max_sig = false) const;
bool DummySignInput(CTxIn &tx_in, const CTxOut &txout) const; bool DummySignInput(CTxIn &tx_in, const CTxOut &txout, bool use_max_sig = false) const;
CFeeRate m_pay_tx_fee{DEFAULT_PAY_TX_FEE}; CFeeRate m_pay_tx_fee{DEFAULT_PAY_TX_FEE};
unsigned int m_confirm_target{DEFAULT_TX_CONFIRM_TARGET}; unsigned int m_confirm_target{DEFAULT_TX_CONFIRM_TARGET};
@ -1311,6 +1314,6 @@ public:
// Use DummySignatureCreator, which inserts 71 byte signatures everywhere. // Use DummySignatureCreator, which inserts 71 byte signatures everywhere.
// NOTE: this requires that all inputs must be in mapWallet (eg the tx should // NOTE: this requires that all inputs must be in mapWallet (eg the tx should
// be IsAllFromMe). // be IsAllFromMe).
int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet); int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet, bool use_max_sig = false);
int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet, const std::vector<CTxOut>& txouts); int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet, const std::vector<CTxOut>& txouts, bool use_max_sig = false);
#endif // BITCOIN_WALLET_WALLET_H #endif // BITCOIN_WALLET_WALLET_H