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:
parent
48b1473c89
commit
e306be7429
4 changed files with 45 additions and 37 deletions
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Add table
Reference in a new issue