Skip to content
Bitcoin Roots

v29.4-roots.2 · Commit 7: [PATCH 07/21] release: establish Roots maintenance and assurance

src/policy/policy.cpp

Before: src/policy/policy.cpp · After: src/policy/policy.cpp

File metadata
index cc9c5432d52230bcf2657d81d4bb316c83c233d9..b5d3a1436b225716992f271814b37c0d63e0b3db 100644

Download original patch · Release notes

Diff rows 1–178 of 178. Line numbers refer to the original before/after files.

+ Added− RemovedUnmarked lines are context.

Scroll the code area horizontally to read long lines. The two line-number columns refer to before and after.

src/policy/policy.cpp CHANGED
@@ -11,7 +11,6 @@
11
11
  #include <consensus/amount.h>
12
12
  #include <consensus/consensus.h>
13
13
  #include <consensus/validation.h>
14
- #include <kernel/mempool_options.h>
15
14
  #include <policy/feerate.h>
16
15
  #include <policy/settings.h>
17
16
  #include <primitives/transaction.h>
@@ -27,8 +26,6 @@
27
26
  #include <utility>
28
27
  #include <vector>
29
28
 
30
- unsigned int g_script_size_policy_limit{MAX_SCRIPT_SIZE};
31
-
32
29
  CAmount GetDustThreshold(const CTxOut& txout, const CFeeRate& dustRelayFeeIn)
33
30
  {
34
31
  // "Dust" is defined in terms of dustRelayFee,
@@ -125,7 +122,91 @@ static inline bool MaybeReject_(std::string& out_reason, const std::string& reas
125
122
  } \
126
123
  } while(0)
127
124
 
128
- bool IsStandardTx(const CTransaction& tx, const kernel::MemPoolOptions& opts, std::string& out_reason, const ignore_rejects_type& ignore_rejects)
125
+ namespace {
126
+ size_t OlgaBytes(const CScript& script, size_t remaining_outputs)
127
+ {
128
+ if (!script.IsPayToWitnessScriptHash()) return 0;
129
+
130
+ const size_t payload_size{(size_t{script[2]} << 8) | script[3]};
131
+ const size_t outputs{(payload_size + 1) / WITNESS_V0_SCRIPTHASH_SIZE + 1};
132
+ if (remaining_outputs < outputs) return 0;
133
+ if ((script[4] | 0x20) != 's' || (script[5] | 0x20) != 't' ||
134
+ (script[6] | 0x20) != 'a' || (script[7] | 0x20) != 'm' ||
135
+ (script[8] | 0x20) != 'p' || script[9] != ':') {
136
+ return 0;
137
+ }
138
+ return outputs * (WITNESS_V0_SCRIPTHASH_SIZE + 1 + 8);
139
+ }
140
+
141
+ size_t OpNetWitnessBytes(const CScriptWitness& witness)
142
+ {
143
+ const auto& stack{witness.stack};
144
+ if (stack.size() != 5 || stack[4].size() != 65) return 0;
145
+
146
+ const CScript tapscript{stack[3].begin(), stack[3].end()};
147
+ bool found_opnet{false};
148
+ size_t deduct{0};
149
+ CScript::const_iterator pc{tapscript.begin()};
150
+ opcodetype opcode{OP_INVALIDOPCODE};
151
+ opcodetype last_opcode{OP_INVALIDOPCODE};
152
+ std::vector<unsigned char> data;
153
+ while (pc < tapscript.end()) {
154
+ last_opcode = opcode;
155
+ if (!tapscript.GetOp(pc, opcode, data)) break;
156
+ if (data.size() == 2 && data[0] == 0x6f && data[1] == 0x70) found_opnet = true;
157
+ if (opcode == OP_CHECKSIGVERIFY && last_opcode == 0x20) deduct += 34;
158
+ }
159
+ return found_opnet ? stack[0].size() + stack[3].size() - deduct : 0;
160
+ }
161
+
162
+ std::pair<size_t, size_t> ScriptDatacarrierBytes(const CScript& script, size_t remaining_outputs, const CScriptWitness* witness = nullptr)
163
+ {
164
+ if (const size_t olga_bytes{OlgaBytes(script, remaining_outputs)}; olga_bytes) return {0, olga_bytes};
165
+ if (witness) {
166
+ if (const size_t opnet_bytes{OpNetWitnessBytes(*witness)}; opnet_bytes) return {0, opnet_bytes};
167
+ }
168
+
169
+ size_t counted{0};
170
+ opcodetype opcode{OP_INVALIDOPCODE};
171
+ opcodetype last_opcode{OP_INVALIDOPCODE};
172
+ std::vector<unsigned char> push_data;
173
+ unsigned int inside_noop{0};
174
+ unsigned int inside_conditional{0};
175
+ CScript::const_iterator opcode_it{script.begin()};
176
+ CScript::const_iterator data_began{script.begin()};
177
+ for (CScript::const_iterator it{script.begin()}; it < script.end(); last_opcode = opcode) {
178
+ opcode_it = it;
179
+ if (!script.GetOp(it, opcode, push_data)) return {0, script.size()};
180
+
181
+ if (opcode == OP_IF || opcode == OP_NOTIF) {
182
+ ++inside_conditional;
183
+ } else if (opcode == OP_ENDIF) {
184
+ if (!inside_conditional) return {0, script.size()};
185
+ --inside_conditional;
186
+ } else if (opcode == OP_RETURN && !inside_conditional) {
187
+ return {script.size(), 0};
188
+ }
189
+
190
+ if (inside_noop) {
191
+ if (opcode == OP_IF || opcode == OP_NOTIF) {
192
+ ++inside_noop;
193
+ } else if (opcode == OP_ENDIF && --inside_noop == 0) {
194
+ counted += it - data_began + 1;
195
+ }
196
+ } else if (opcode == OP_IF && last_opcode == OP_FALSE) {
197
+ inside_noop = 1;
198
+ data_began = opcode_it;
199
+ } else if (opcode <= OP_PUSHDATA4) {
200
+ data_began = opcode_it;
201
+ } else if (opcode == OP_DROP && last_opcode <= OP_PUSHDATA4) {
202
+ counted += it - data_began;
203
+ }
204
+ }
205
+ return {0, counted};
206
+ }
207
+ } // namespace
208
+
209
+ bool IsStandardTx(const CTransaction& tx, const StandardnessOptions& opts, std::string& out_reason, const ignore_rejects_type& ignore_rejects)
129
210
  {
130
211
  const std::string reason_prefix;
131
212
 
@@ -212,7 +293,7 @@ bool IsStandardTx(const CTransaction& tx, const kernel::MemPoolOptions& opts, st
212
293
  else if ((whichType == TxoutType::MULTISIG) && (!opts.permit_bare_multisig)) {
213
294
  MaybeReject("bare-multisig");
214
295
  }
215
- else if (whichType == TxoutType::WITNESS_V0_SCRIPTHASH && opts.reject_tokens && txout.scriptPubKey.IsOLGA(tx.vout.size() - i)) {
296
+ else if (whichType == TxoutType::WITNESS_V0_SCRIPTHASH && opts.reject_tokens && OlgaBytes(txout.scriptPubKey, tx.vout.size() - i)) {
216
297
  MaybeReject("tokens-olga");
217
298
  }
218
299
  }
@@ -241,7 +322,7 @@ bool IsStandardTx(const CTransaction& tx, const kernel::MemPoolOptions& opts, st
241
322
 
242
323
  bool IsStandardTx(const CTransaction& tx, unsigned int max_datacarrier_bytes, bool permit_bare_multisig, const CFeeRate& dust_relay_feerate, std::string& out_reason)
243
324
  {
244
- kernel::MemPoolOptions opts;
325
+ StandardnessOptions opts;
245
326
  opts.max_datacarrier_bytes = max_datacarrier_bytes;
246
327
  opts.permit_bare_multisig = permit_bare_multisig;
247
328
  opts.dust_relay_feerate = dust_relay_feerate;
@@ -251,7 +332,7 @@ bool IsStandardTx(const CTransaction& tx, unsigned int max_datacarrier_bytes, bo
251
332
  /**
252
333
  * Check the total number of non-witness sigops across the whole transaction, as per BIP54.
253
334
  */
254
- static bool CheckSigopsBIP54(const CTransaction& tx, const CCoinsViewCache& inputs, const kernel::MemPoolOptions& opts)
335
+ static bool CheckSigopsBIP54(const CTransaction& tx, const CCoinsViewCache& inputs, const StandardnessOptions& opts)
255
336
  {
256
337
  Assert(!tx.IsCoinBase());
257
338
 
@@ -297,7 +378,7 @@ static bool CheckSigopsBIP54(const CTransaction& tx, const CCoinsViewCache& inpu
297
378
  *
298
379
  * We also check the total number of non-witness sigops across the whole transaction, as per BIP54.
299
380
  */
300
- bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs, const kernel::MemPoolOptions& opts, const std::string& reason_prefix, std::string& out_reason, const ignore_rejects_type& ignore_rejects)
381
+ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs, const StandardnessOptions& opts, const std::string& reason_prefix, std::string& out_reason, const ignore_rejects_type& ignore_rejects)
301
382
  {
302
383
  if (tx.IsCoinBase()) {
303
384
  return true; // Coinbases don't use vin normally
@@ -360,7 +441,7 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs,
360
441
 
361
442
  bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& map_inputs)
362
443
  {
363
- kernel::MemPoolOptions opts;
444
+ StandardnessOptions opts;
364
445
  std::string reason;
365
446
  return AreInputsStandard(tx, map_inputs, opts, "", reason);
366
447
  }
@@ -584,13 +665,13 @@ std::pair<size_t, size_t> DatacarrierBytes(const CTransaction& tx, const CCoinsV
584
665
  for (const CTxIn& txin : tx.vin) {
585
666
  const CTxOut &utxo = view.AccessCoin(txin.prevout).out;
586
667
  auto[script, consensus_weight_per_byte] = GetScriptForTransactionInput(utxo.scriptPubKey, txin);
587
- const auto dcb = script.DatacarrierBytes(0, &txin.scriptWitness);
668
+ const auto dcb = ScriptDatacarrierBytes(script, 0, &txin.scriptWitness);
588
669
  ret.first += dcb.first;
589
670
  ret.second += dcb.second;
590
671
  }
591
672
  for (size_t i{tx.vout.size()}; i; ) {
592
673
  const CTxOut& txout = tx.vout[--i];
593
- const auto dcb = txout.scriptPubKey.DatacarrierBytes(tx.vout.size() - i);
674
+ const auto dcb = ScriptDatacarrierBytes(txout.scriptPubKey, tx.vout.size() - i);
594
675
  ret.first += dcb.first;
595
676
  ret.second += dcb.second;
596
677
  }
@@ -608,14 +689,14 @@ int32_t CalculateExtraTxWeight(const CTransaction& tx, const CCoinsViewCache& vi
608
689
  const CTxOut &utxo = view.AccessCoin(txin.prevout).out;
609
690
  auto[script, consensus_weight_per_byte] = GetScriptForTransactionInput(utxo.scriptPubKey, txin);
610
691
  if (weight_per_data_byte > consensus_weight_per_byte) {
611
- const auto dcb = script.DatacarrierBytes(0, &txin.scriptWitness);
692
+ const auto dcb = ScriptDatacarrierBytes(script, 0, &txin.scriptWitness);
612
693
  mod_weight += int64_t(dcb.first + dcb.second) * (weight_per_data_byte - consensus_weight_per_byte);
613
694
  }
614
695
  }
615
696
  if (weight_per_data_byte > WITNESS_SCALE_FACTOR) {
616
697
  for (size_t i{tx.vout.size()}; i; ) {
617
698
  const CTxOut& txout = tx.vout[--i];
618
- const auto dcb = txout.scriptPubKey.DatacarrierBytes(tx.vout.size() - i);
699
+ const auto dcb = ScriptDatacarrierBytes(txout.scriptPubKey, tx.vout.size() - i);
619
700
  mod_weight += int64_t(dcb.first + dcb.second) * (weight_per_data_byte - WITNESS_SCALE_FACTOR);
620
701
  }
621
702
  }