Skip to content

Commit 5863315

Browse files
committed
policy: make pathological transactions packed with legacy sigops non-standard.
The Consensus Cleanup soft fork proposal includes a limit on the number of legacy signature operations potentially executed when validating a transaction. If this change is to be implemented here and activated by Bitcoin users in the future, we should prevent the ability for someone to broadcast a transaction through the p2p network that is not valid according to the new rules. This is because if it was possible it would be a trivial DoS to potentially unupgraded miners after the soft fork activates. We do not know for sure whether users will activate the Consensus Cleanup. However if they do such transactions must have been made non-standard long in advance, due to the time it takes for most nodes on the network to upgrade. In addition this limit may only be run into by pathological transactions which pad the Script with sigops but do not use actual signatures when spending, as otherwise they would run into the standard transaction size limit.
1 parent 1927432 commit 5863315

File tree

2 files changed

+37
-0
lines changed

2 files changed

+37
-0
lines changed

src/policy/policy.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,35 @@ bool IsStandardTx(const CTransaction& tx, const std::optional<unsigned>& max_dat
163163
return true;
164164
}
165165

166+
/**
167+
* Check the total number of non-witness sigops across the whole transaction, as per BIP54.
168+
*/
169+
static bool CheckSigopsBIP54(const CTransaction& tx, const CCoinsViewCache& inputs)
170+
{
171+
Assert(!tx.IsCoinBase());
172+
173+
unsigned int sigops{0};
174+
for (const auto& txin: tx.vin) {
175+
const auto& prev_txo{inputs.AccessCoin(txin.prevout).out};
176+
177+
// Unlike the existing block wide sigop limit which counts sigops present in the block
178+
// itself (including the scriptPubKey which is not executed until spending later), BIP54
179+
// counts sigops in the block where they are potentially executed (only).
180+
// This means sigops in the spent scriptPubKey count toward the limit.
181+
// `fAccurate` means correctly accounting sigops for CHECKMULTISIGs(VERIFY) with 16 pubkeys
182+
// or fewer. This method of accounting was introduced by BIP16, and BIP54 reuses it.
183+
// The GetSigOpCount call on the previous scriptPubKey counts both bare and P2SH sigops.
184+
sigops += txin.scriptSig.GetSigOpCount(/*fAccurate=*/true);
185+
sigops += prev_txo.scriptPubKey.GetSigOpCount(txin.scriptSig);
186+
187+
if (sigops > MAX_TX_LEGACY_SIGOPS) {
188+
return false;
189+
}
190+
}
191+
192+
return true;
193+
}
194+
166195
/**
167196
* Check transaction inputs.
168197
*
@@ -178,13 +207,19 @@ bool IsStandardTx(const CTransaction& tx, const std::optional<unsigned>& max_dat
178207
* as potential new upgrade hooks.
179208
*
180209
* Note that only the non-witness portion of the transaction is checked here.
210+
*
211+
* We also check the total number of non-witness sigops across the whole transaction, as per BIP54.
181212
*/
182213
bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
183214
{
184215
if (tx.IsCoinBase()) {
185216
return true; // Coinbases don't use vin normally
186217
}
187218

219+
if (!CheckSigopsBIP54(tx, mapInputs)) {
220+
return false;
221+
}
222+
188223
for (unsigned int i = 0; i < tx.vin.size(); i++) {
189224
const CTxOut& prev = mapInputs.AccessCoin(tx.vin[i].prevout).out;
190225

src/policy/policy.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ static constexpr unsigned int MIN_STANDARD_TX_NONWITNESS_SIZE{65};
3838
static constexpr unsigned int MAX_P2SH_SIGOPS{15};
3939
/** The maximum number of sigops we're willing to relay/mine in a single tx */
4040
static constexpr unsigned int MAX_STANDARD_TX_SIGOPS_COST{MAX_BLOCK_SIGOPS_COST/5};
41+
/** The maximum number of potentially executed legacy signature operations in a single standard tx */
42+
static constexpr unsigned int MAX_TX_LEGACY_SIGOPS{2'500};
4143
/** Default for -incrementalrelayfee, which sets the minimum feerate increase for mempool limiting or replacement **/
4244
static constexpr unsigned int DEFAULT_INCREMENTAL_RELAY_FEE{1000};
4345
/** Default for -bytespersigop */

0 commit comments

Comments
 (0)