Skip to content

Commit abdea9f

Browse files
committed
Add maxscriptsize policy option
1 parent cb15ca1 commit abdea9f

File tree

4 files changed

+26
-3
lines changed

4 files changed

+26
-3
lines changed

src/init.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -651,6 +651,7 @@ void SetupServerArgs(ArgsManager& argsman)
651651
strprintf("Maximum size of data in data carrier transactions we relay and mine, in bytes (default: %u)",
652652
MAX_OP_RETURN_RELAY),
653653
ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
654+
argsman.AddArg("-maxscriptsize", strprintf("Maximum size of scripts we relay and mine (default: %s)", DEFAULT_SCRIPT_SIZE_POLICY_LIMIT), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
654655
argsman.AddArg("-mempoolfullrbf", strprintf("Accept transaction replace-by-fee without requiring replaceability signaling (default: %u)", (DEFAULT_MEMPOOL_RBF_POLICY == RBFPolicy::Always)), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
655656
argsman.AddArg("-mempoolreplacement", strprintf("Set to 0 to disable RBF entirely, \"fee,optin\" to honour RBF opt-out signal, or \"fee,-optin\" to always RBF aka full RBF (default: %s)", "fee,-optin"), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
656657
argsman.AddArg("-mempooltruc", strprintf("Behaviour for transactions requesting TRUC limits: \"reject\" the transactions entirely, \"accept\" them just like any other, or \"enforce\" to impose their requested restrictions (default: %s)", "enforce"), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
@@ -1045,6 +1046,8 @@ bool AppInitParameterInteraction(const ArgsManager& args)
10451046
g_weight_per_data_byte = ((*parsed * WITNESS_SCALE_FACTOR) + 99) / 100;
10461047
}
10471048

1049+
g_script_size_policy_limit = args.GetIntArg("-maxscriptsize", g_script_size_policy_limit);
1050+
10481051
nBytesPerSigOp = args.GetIntArg("-bytespersigop", nBytesPerSigOp);
10491052
nBytesPerSigOpStrict = args.GetIntArg("-bytespersigopstrict", nBytesPerSigOpStrict);
10501053

src/policy/policy.cpp

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <consensus/validation.h>
1414
#include <kernel/mempool_options.h>
1515
#include <policy/feerate.h>
16+
#include <policy/settings.h>
1617
#include <primitives/transaction.h>
1718
#include <script/interpreter.h>
1819
#include <script/script.h>
@@ -24,6 +25,8 @@
2425
#include <cstddef>
2526
#include <vector>
2627

28+
unsigned int g_script_size_policy_limit{DEFAULT_SCRIPT_SIZE_POLICY_LIMIT};
29+
2730
CAmount GetDustThreshold(const CTxOut& txout, const CFeeRate& dustRelayFeeIn)
2831
{
2932
// "Dust" is defined in terms of dustRelayFee,
@@ -138,7 +141,7 @@ bool IsStandardTx(const CTransaction& tx, const kernel::MemPoolOptions& opts, st
138141
// some minor future-proofing. That's also enough to spend a
139142
// 20-of-20 CHECKMULTISIG scriptPubKey, though such a scriptPubKey
140143
// is not considered standard.
141-
if (txin.scriptSig.size() > MAX_STANDARD_SCRIPTSIG_SIZE) {
144+
if (txin.scriptSig.size() > std::min(MAX_STANDARD_SCRIPTSIG_SIZE, g_script_size_policy_limit)) {
142145
MaybeReject("scriptsig-size");
143146
}
144147
if (!txin.scriptSig.IsPushOnly()) {
@@ -149,6 +152,10 @@ bool IsStandardTx(const CTransaction& tx, const kernel::MemPoolOptions& opts, st
149152
unsigned int nDataOut = 0;
150153
TxoutType whichType;
151154
for (const CTxOut& txout : tx.vout) {
155+
if (txout.scriptPubKey.size() > g_script_size_policy_limit) {
156+
MaybeReject("scriptpubkey-size");
157+
}
158+
152159
if (!::IsStandard(txout.scriptPubKey, opts.max_datacarrier_bytes, whichType)) {
153160
if (whichType == TxoutType::WITNESS_UNKNOWN) {
154161
MaybeReject("scriptpubkey-unknown-witnessversion");
@@ -207,6 +214,10 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs,
207214
for (unsigned int i = 0; i < tx.vin.size(); i++) {
208215
const CTxOut& prev = mapInputs.AccessCoin(tx.vin[i].prevout).out;
209216

217+
if (prev.scriptPubKey.size() > g_script_size_policy_limit) {
218+
MaybeReject("script-size");
219+
}
220+
210221
std::vector<std::vector<unsigned char> > vSolutions;
211222
TxoutType whichType = Solver(prev.scriptPubKey, vSolutions);
212223
if (whichType == TxoutType::NONSTANDARD) {
@@ -239,6 +250,9 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs,
239250
return false;
240251
}
241252
CScript subscript(stack.back().begin(), stack.back().end());
253+
if (subscript.size() > g_script_size_policy_limit) {
254+
MaybeReject("scriptcheck-size");
255+
}
242256
if (subscript.GetSigOpCount(true) > MAX_P2SH_SIGOPS) {
243257
MaybeReject("scriptcheck-sigops");
244258
}
@@ -302,7 +316,7 @@ bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs,
302316

303317
// Check P2WSH standard limits
304318
if (witnessversion == 0 && witnessprogram.size() == WITNESS_V0_SCRIPTHASH_SIZE) {
305-
if (tx.vin[i].scriptWitness.stack.back().size() > MAX_STANDARD_P2WSH_SCRIPT_SIZE)
319+
if (tx.vin[i].scriptWitness.stack.back().size() > std::min(MAX_STANDARD_P2WSH_SCRIPT_SIZE, g_script_size_policy_limit))
306320
MaybeReject("script-size");
307321
size_t sizeWitnessStack = tx.vin[i].scriptWitness.stack.size() - 1;
308322
if (sizeWitnessStack > MAX_STANDARD_P2WSH_STACK_ITEMS)
@@ -328,12 +342,15 @@ bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs,
328342
if (stack.size() >= 2) {
329343
// Script path spend (2 or more stack elements after removing optional annex)
330344
const auto& control_block = SpanPopBack(stack);
331-
SpanPopBack(stack); // Ignore script
345+
const auto& tapscript = SpanPopBack(stack);
332346
if (control_block.empty()) {
333347
// Empty control block is invalid
334348
out_reason = reason_prefix + "taproot-control-missing";
335349
return false;
336350
}
351+
if (tapscript.size() > g_script_size_policy_limit) {
352+
MaybeReject("script-size");
353+
}
337354
if ((control_block[0] & TAPROOT_LEAF_MASK) == TAPROOT_LEAF_TAPSCRIPT) {
338355
// Leaf version 0xc0 (aka Tapscript, see BIP 342)
339356
if (!ignore_rejects.count(reason_prefix + "taproot-stackitem-size")) {

src/policy/policy.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ static constexpr unsigned int MAX_P2SH_SIGOPS{15};
4444
static constexpr unsigned int MAX_STANDARD_TX_SIGOPS_COST{MAX_BLOCK_SIGOPS_COST/5};
4545
/** Default for -incrementalrelayfee, which sets the minimum feerate increase for mempool limiting or replacement **/
4646
static constexpr unsigned int DEFAULT_INCREMENTAL_RELAY_FEE{1000};
47+
/** Default for -maxscriptsize */
48+
static constexpr unsigned int DEFAULT_SCRIPT_SIZE_POLICY_LIMIT{std::numeric_limits<unsigned int>::max()};
4749
/** Default for -bytespersigop */
4850
static constexpr unsigned int DEFAULT_BYTES_PER_SIGOP{20};
4951
/** Default for -bytespersigopstrict */

src/policy/settings.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#ifndef BITCOIN_POLICY_SETTINGS_H
77
#define BITCOIN_POLICY_SETTINGS_H
88

9+
extern unsigned int g_script_size_policy_limit;
910
extern unsigned int nBytesPerSigOp;
1011
extern unsigned int nBytesPerSigOpStrict;
1112
extern unsigned int g_weight_per_data_byte;

0 commit comments

Comments
 (0)