Skip to content

Commit 12ec29d

Browse files
committed
Calculate and store the number of bytes required to spend an input
1 parent a34ac6a commit 12ec29d

File tree

8 files changed

+127
-68
lines changed

8 files changed

+127
-68
lines changed

src/consensus/validation.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,5 +101,10 @@ static inline int64_t GetBlockWeight(const CBlock& block)
101101
{
102102
return ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * (WITNESS_SCALE_FACTOR - 1) + ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION);
103103
}
104+
static inline int64_t GetTransationInputWeight(const CTxIn& txin)
105+
{
106+
// scriptWitness size is added here because witnesses and txins are split up in segwit serialization.
107+
return ::GetSerializeSize(txin, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * (WITNESS_SCALE_FACTOR - 1) + ::GetSerializeSize(txin, SER_NETWORK, PROTOCOL_VERSION) + ::GetSerializeSize(txin.scriptWitness.stack, SER_NETWORK, PROTOCOL_VERSION);
108+
}
104109

105110
#endif // BITCOIN_CONSENSUS_VALIDATION_H

src/policy/policy.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,3 +258,8 @@ int64_t GetVirtualTransactionSize(const CTransaction& tx, int64_t nSigOpCost)
258258
{
259259
return GetVirtualTransactionSize(GetTransactionWeight(tx), nSigOpCost);
260260
}
261+
262+
int64_t GetVirtualTransactionInputSize(const CTxIn& txin, int64_t nSigOpCost)
263+
{
264+
return GetVirtualTransactionSize(GetTransationInputWeight(txin), nSigOpCost);
265+
}

src/policy/policy.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,5 +102,6 @@ extern unsigned int nBytesPerSigOp;
102102
/** Compute the virtual transaction size (weight reinterpreted as bytes). */
103103
int64_t GetVirtualTransactionSize(int64_t nWeight, int64_t nSigOpCost);
104104
int64_t GetVirtualTransactionSize(const CTransaction& tx, int64_t nSigOpCost = 0);
105+
int64_t GetVirtualTransactionInputSize(const CTxIn& tx, int64_t nSigOpCost = 0);
105106

106107
#endif // BITCOIN_POLICY_POLICY_H

src/script/sign.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,11 +194,16 @@ SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nI
194194
return data;
195195
}
196196

197+
void UpdateInput(CTxIn& input, const SignatureData& data)
198+
{
199+
input.scriptSig = data.scriptSig;
200+
input.scriptWitness = data.scriptWitness;
201+
}
202+
197203
void UpdateTransaction(CMutableTransaction& tx, unsigned int nIn, const SignatureData& data)
198204
{
199205
assert(tx.vin.size() > nIn);
200-
tx.vin[nIn].scriptSig = data.scriptSig;
201-
tx.vin[nIn].scriptWitness = data.scriptWitness;
206+
UpdateInput(tx.vin[nIn], data);
202207
}
203208

204209
bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, const CAmount& amount, int nHashType)

src/script/sign.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ SignatureData CombineSignatures(const CScript& scriptPubKey, const BaseSignature
8080
/** Extract signature data from a transaction, and insert it. */
8181
SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn);
8282
void UpdateTransaction(CMutableTransaction& tx, unsigned int nIn, const SignatureData& data);
83+
void UpdateInput(CTxIn& input, const SignatureData& data);
8384

8485
/* Check whether we know how to sign for an output like this, assuming we
8586
* have all private keys. While this function does not need private keys, the passed

src/wallet/feebumper.cpp

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -16,33 +16,6 @@
1616
#include <util.h>
1717
#include <net.h>
1818

19-
// Calculate the size of the transaction assuming all signatures are max size
20-
// Use DummySignatureCreator, which inserts 72 byte signatures everywhere.
21-
// TODO: re-use this in CWallet::CreateTransaction (right now
22-
// CreateTransaction uses the constructed dummy-signed tx to do a priority
23-
// calculation, but we should be able to refactor after priority is removed).
24-
// NOTE: this requires that all inputs must be in mapWallet (eg the tx should
25-
// be IsAllFromMe).
26-
static int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet)
27-
{
28-
CMutableTransaction txNew(tx);
29-
std::vector<CInputCoin> vCoins;
30-
// Look up the inputs. We should have already checked that this transaction
31-
// IsAllFromMe(ISMINE_SPENDABLE), so every input should already be in our
32-
// wallet, with a valid index into the vout array.
33-
for (auto& input : tx.vin) {
34-
const auto mi = wallet->mapWallet.find(input.prevout.hash);
35-
assert(mi != wallet->mapWallet.end() && input.prevout.n < mi->second.tx->vout.size());
36-
vCoins.emplace_back(CInputCoin(&(mi->second), input.prevout.n));
37-
}
38-
if (!wallet->DummySignTx(txNew, vCoins)) {
39-
// This should never happen, because IsAllFromMe(ISMINE_SPENDABLE)
40-
// implies that we can sign for every input.
41-
return -1;
42-
}
43-
return GetVirtualTransactionSize(txNew);
44-
}
45-
4619
//! Check whether transaction has descendant in wallet or mempool, or has been
4720
//! mined, or conflicts with a mined transaction. Return a feebumper::Result.
4821
static feebumper::Result PreconditionChecks(const CWallet* wallet, const CWalletTx& wtx, std::vector<std::string>& errors)

src/wallet/wallet.cpp

Lines changed: 76 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1543,6 +1543,79 @@ int CWalletTx::GetRequestCount() const
15431543
return nRequests;
15441544
}
15451545

1546+
// Helper for producing a max-sized low-S signature (eg 72 bytes)
1547+
bool CWallet::DummySignInput(CTxIn &tx_in, const CTxOut &txout) const
1548+
{
1549+
// Fill in dummy signatures for fee calculation.
1550+
const CScript& scriptPubKey = txout.scriptPubKey;
1551+
SignatureData sigdata;
1552+
1553+
if (!ProduceSignature(DummySignatureCreator(this), scriptPubKey, sigdata))
1554+
{
1555+
return false;
1556+
} else {
1557+
UpdateInput(tx_in, sigdata);
1558+
}
1559+
return true;
1560+
}
1561+
1562+
// Helper for producing a bunch of max-sized low-S signatures (eg 72 bytes)
1563+
bool CWallet::DummySignTx(CMutableTransaction &txNew, const std::vector<CTxOut> &txouts) const
1564+
{
1565+
// Fill in dummy signatures for fee calculation.
1566+
int nIn = 0;
1567+
for (const auto& txout : txouts)
1568+
{
1569+
if (!DummySignInput(txNew.vin[nIn], txout)) {
1570+
return false;
1571+
}
1572+
1573+
nIn++;
1574+
}
1575+
return true;
1576+
}
1577+
1578+
int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet)
1579+
{
1580+
std::vector<CTxOut> txouts;
1581+
// Look up the inputs. We should have already checked that this transaction
1582+
// IsAllFromMe(ISMINE_SPENDABLE), so every input should already be in our
1583+
// wallet, with a valid index into the vout array, and the ability to sign.
1584+
for (auto& input : tx.vin) {
1585+
const auto mi = wallet->mapWallet.find(input.prevout.hash);
1586+
if (mi == wallet->mapWallet.end()) {
1587+
return -1;
1588+
}
1589+
assert(input.prevout.n < mi->second.tx->vout.size());
1590+
txouts.emplace_back(mi->second.tx->vout[input.prevout.n]);
1591+
}
1592+
return CalculateMaximumSignedTxSize(tx, wallet, txouts);
1593+
}
1594+
1595+
// txouts needs to be in the order of tx.vin
1596+
int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet, const std::vector<CTxOut>& txouts)
1597+
{
1598+
CMutableTransaction txNew(tx);
1599+
if (!wallet->DummySignTx(txNew, txouts)) {
1600+
// This should never happen, because IsAllFromMe(ISMINE_SPENDABLE)
1601+
// implies that we can sign for every input.
1602+
return -1;
1603+
}
1604+
return GetVirtualTransactionSize(txNew);
1605+
}
1606+
1607+
int CalculateMaximumSignedInputSize(const CTxOut& txout, const CWallet* wallet)
1608+
{
1609+
CMutableTransaction txn;
1610+
txn.vin.push_back(CTxIn(COutPoint()));
1611+
if (!wallet->DummySignInput(txn.vin[0], txout)) {
1612+
// This should never happen, because IsAllFromMe(ISMINE_SPENDABLE)
1613+
// implies that we can sign for every input.
1614+
return -1;
1615+
}
1616+
return GetVirtualTransactionInputSize(txn.vin[0]);
1617+
}
1618+
15461619
void CWalletTx::GetAmounts(std::list<COutputEntry>& listReceived,
15471620
std::list<COutputEntry>& listSent, CAmount& nFee, std::string& strSentAccount, const isminefilter& filter) const
15481621
{
@@ -2752,7 +2825,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
27522825
assert(txNew.nLockTime < LOCKTIME_THRESHOLD);
27532826
FeeCalculation feeCalc;
27542827
CAmount nFeeNeeded;
2755-
unsigned int nBytes;
2828+
int nBytes;
27562829
{
27572830
std::set<CInputCoin> setCoins;
27582831
LOCK2(cs_main, cs_wallet);
@@ -2903,20 +2976,12 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
29032976
txNew.vin.push_back(CTxIn(coin.outpoint,CScript(),
29042977
nSequence));
29052978

2906-
// Fill in dummy signatures for fee calculation.
2907-
if (!DummySignTx(txNew, setCoins)) {
2979+
nBytes = CalculateMaximumSignedTxSize(txNew, this);
2980+
if (nBytes < 0) {
29082981
strFailReason = _("Signing transaction failed");
29092982
return false;
29102983
}
29112984

2912-
nBytes = GetVirtualTransactionSize(txNew);
2913-
2914-
// Remove scriptSigs to eliminate the fee calculation dummy signatures
2915-
for (auto& vin : txNew.vin) {
2916-
vin.scriptSig = CScript();
2917-
vin.scriptWitness.SetNull();
2918-
}
2919-
29202985
nFeeNeeded = GetMinimumFee(nBytes, coin_control, ::mempool, ::feeEstimator, &feeCalc);
29212986
if (feeCalc.reason == FeeReason::FALLBACK && !g_wallet_allow_fallback_fee) {
29222987
// eventually allow a fallback fee

src/wallet/wallet.h

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,9 @@ class CMerkleTx
269269
bool IsCoinBase() const { return tx->IsCoinBase(); }
270270
};
271271

272+
//Get the marginal bytes of spending the specified output
273+
int CalculateMaximumSignedInputSize(const CTxOut& txout, const CWallet* pwallet);
274+
272275
/**
273276
* A transaction with a bunch of additional info that only the owner cares about.
274277
* It includes any unrecorded transactions needed to link it back to the block chain.
@@ -462,6 +465,12 @@ class CWalletTx : public CMerkleTx
462465
CAmount GetAvailableWatchOnlyCredit(const bool fUseCache=true) const;
463466
CAmount GetChange() const;
464467

468+
// Get the marginal bytes if spending the specified output from this transaction
469+
int GetSpendSize(unsigned int out) const
470+
{
471+
return CalculateMaximumSignedInputSize(tx->vout[out], pwallet);
472+
}
473+
465474
void GetAmounts(std::list<COutputEntry>& listReceived,
466475
std::list<COutputEntry>& listSent, CAmount& nFee, std::string& strSentAccount, const isminefilter& filter) const;
467476

@@ -525,6 +534,9 @@ class COutput
525534
int i;
526535
int nDepth;
527536

537+
/** Pre-computed estimated size of this output as a fully-signed input in a transaction. Can be -1 if it could not be calculated */
538+
int nInputBytes;
539+
528540
/** Whether we have the private keys to spend this output */
529541
bool fSpendable;
530542

@@ -540,7 +552,12 @@ class COutput
540552

541553
COutput(const CWalletTx *txIn, int iIn, int nDepthIn, bool fSpendableIn, bool fSolvableIn, bool fSafeIn)
542554
{
543-
tx = txIn; i = iIn; nDepth = nDepthIn; fSpendable = fSpendableIn; fSolvable = fSolvableIn; fSafe = fSafeIn;
555+
tx = txIn; i = iIn; nDepth = nDepthIn; fSpendable = fSpendableIn; fSolvable = fSolvableIn; fSafe = fSafeIn; nInputBytes = -1;
556+
// If known and signable by the given wallet, compute nInputBytes
557+
// Failure will keep this value -1
558+
if (fSpendable && tx) {
559+
nInputBytes = tx->GetSpendSize(i);
560+
}
544561
}
545562

546563
std::string ToString() const;
@@ -981,8 +998,14 @@ class CWallet final : public CCryptoKeyStore, public CValidationInterface
981998
void ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& entries);
982999
bool AddAccountingEntry(const CAccountingEntry&);
9831000
bool AddAccountingEntry(const CAccountingEntry&, CWalletDB *pwalletdb);
984-
template <typename ContainerType>
985-
bool DummySignTx(CMutableTransaction &txNew, const ContainerType &coins) const;
1001+
bool DummySignTx(CMutableTransaction &txNew, const std::set<CTxOut> &txouts) const
1002+
{
1003+
std::vector<CTxOut> v_txouts(txouts.size());
1004+
std::copy(txouts.begin(), txouts.end(), v_txouts.begin());
1005+
return DummySignTx(txNew, v_txouts);
1006+
}
1007+
bool DummySignTx(CMutableTransaction &txNew, const std::vector<CTxOut> &txouts) const;
1008+
bool DummySignInput(CTxIn &tx_in, const CTxOut &txout) const;
9861009

9871010
static CFeeRate minTxFee;
9881011
static CFeeRate fallbackFee;
@@ -1227,31 +1250,6 @@ class CAccount
12271250
}
12281251
};
12291252

1230-
// Helper for producing a bunch of max-sized low-S signatures (eg 72 bytes)
1231-
// ContainerType is meant to hold pair<CWalletTx *, int>, and be iterable
1232-
// so that each entry corresponds to each vIn, in order.
1233-
template <typename ContainerType>
1234-
bool CWallet::DummySignTx(CMutableTransaction &txNew, const ContainerType &coins) const
1235-
{
1236-
// Fill in dummy signatures for fee calculation.
1237-
int nIn = 0;
1238-
for (const auto& coin : coins)
1239-
{
1240-
const CScript& scriptPubKey = coin.txout.scriptPubKey;
1241-
SignatureData sigdata;
1242-
1243-
if (!ProduceSignature(DummySignatureCreator(this), scriptPubKey, sigdata))
1244-
{
1245-
return false;
1246-
} else {
1247-
UpdateTransaction(txNew, nIn, sigdata);
1248-
}
1249-
1250-
nIn++;
1251-
}
1252-
return true;
1253-
}
1254-
12551253
OutputType ParseOutputType(const std::string& str, OutputType default_type = OUTPUT_TYPE_DEFAULT);
12561254
const std::string& FormatOutputType(OutputType type);
12571255

@@ -1299,4 +1297,10 @@ class WalletRescanReserver
12991297
}
13001298
};
13011299

1300+
// Calculate the size of the transaction assuming all signatures are max size
1301+
// Use DummySignatureCreator, which inserts 72 byte signatures everywhere.
1302+
// NOTE: this requires that all inputs must be in mapWallet (eg the tx should
1303+
// be IsAllFromMe).
1304+
int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet);
1305+
int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet, const std::vector<CTxOut>& txouts);
13021306
#endif // BITCOIN_WALLET_WALLET_H

0 commit comments

Comments
 (0)