Skip to content
Bitcoin Roots

v29.4-roots.2 · Commit 3: [PATCH 03/21] policy: restore conservative relay and network controls

src/script/script.cpp

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

File metadata
index d650db9a0d6584d0a8f8d3c2a83aca3a5af3b78e..fbb52fee7f9b265e8f7f50595fbac1f321c8ff56 100644

Download original patch · Release notes

Diff rows 1–125 of 125. 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/script/script.cpp CHANGED
@@ -8,6 +8,7 @@
8
8
  #include <crypto/common.h>
9
9
  #include <crypto/hex_base.h>
10
10
  #include <hash.h>
11
+ #include <script/interpreter.h>
11
12
  #include <uint256.h>
12
13
  #include <util/hash_type.h>
13
14
 
@@ -303,6 +304,118 @@ bool CScript::HasValidOps() const
303
304
  return true;
304
305
  }
305
306
 
307
+ size_t CScript::IsOLGA(const size_t remaining_outputs) const
308
+ {
309
+ if (!IsPayToWitnessScriptHash()) {
310
+ return 0;
311
+ }
312
+
313
+ const size_t olga_payload_size{(size_t{(*this)[2]} << 8) | (*this)[3]};
314
+ const size_t olga_outputs{(olga_payload_size + 1) / WITNESS_V0_SCRIPTHASH_SIZE + 1};
315
+ if (remaining_outputs < olga_outputs) {
316
+ return 0;
317
+ }
318
+
319
+ if (((*this)[4] | 0x20) != 's') return 0;
320
+ if (((*this)[5] | 0x20) != 't') return 0;
321
+ if (((*this)[6] | 0x20) != 'a') return 0;
322
+ if (((*this)[7] | 0x20) != 'm') return 0;
323
+ if (((*this)[8] | 0x20) != 'p') return 0;
324
+ if ((*this)[9] != ':') return 0;
325
+
326
+ return olga_outputs * (WITNESS_V0_SCRIPTHASH_SIZE + /* script length */ 1 + /* amount */ 8);
327
+ }
328
+
329
+ size_t CScript::OPNetWitnessSize(const CScriptWitness& witness) const
330
+ {
331
+ const auto& stack = witness.stack;
332
+
333
+ if (stack.size() != 5) return 0;
334
+ if (stack[4].size() != 65) return 0;
335
+
336
+ const CScript tapscript{stack[3].begin(), stack[3].end()};
337
+ bool found_opnet{false};
338
+ size_t deduct{0};
339
+
340
+ CScript::const_iterator pc = tapscript.begin();
341
+ opcodetype opcode{OP_INVALIDOPCODE}, last_opcode{OP_INVALIDOPCODE};
342
+ std::vector<unsigned char> data;
343
+ while (pc < tapscript.end()) {
344
+ last_opcode = opcode;
345
+ if (!tapscript.GetOp(pc, opcode, data)) break;
346
+
347
+ if (data.size() == 2 && data[0] == 0x6f && data[1] == 0x70) {
348
+ found_opnet = true;
349
+ }
350
+ if (opcode == OP_CHECKSIGVERIFY && last_opcode == 0x20) {
351
+ deduct += 34;
352
+ }
353
+ }
354
+
355
+ if (!found_opnet) return 0;
356
+ return stack[0].size() + stack[3].size() - deduct;
357
+ }
358
+
359
+ std::pair<size_t, size_t> CScript::DatacarrierBytes(const size_t remaining_outputs, const CScriptWitness* witness) const
360
+ {
361
+ if (size_t olga_bytes = IsOLGA(remaining_outputs); olga_bytes) {
362
+ return {0, olga_bytes};
363
+ }
364
+
365
+ if (witness) {
366
+ if (uint32_t opnet_bytes = OPNetWitnessSize(*witness); opnet_bytes) {
367
+ return {0, opnet_bytes};
368
+ }
369
+ }
370
+
371
+ size_t counted{0};
372
+ opcodetype opcode, last_opcode{OP_INVALIDOPCODE};
373
+ std::vector<unsigned char> push_data;
374
+ unsigned int inside_noop{0}, inside_conditional{0};
375
+ CScript::const_iterator opcode_it = begin(), data_began = begin();
376
+ for (CScript::const_iterator it = begin(); it < end(); last_opcode = opcode) {
377
+ opcode_it = it;
378
+ if (!GetOp(it, opcode, push_data)) {
379
+ // Invalid scripts are necessarily all data
380
+ return {0, size()};
381
+ }
382
+
383
+ if (opcode == OP_IF || opcode == OP_NOTIF) {
384
+ ++inside_conditional;
385
+ } else if (opcode == OP_ENDIF) {
386
+ if (!inside_conditional) return {0, size()}; // invalid
387
+ --inside_conditional;
388
+ } else if (opcode == OP_RETURN && !inside_conditional) {
389
+ // unconditional OP_RETURN is unspendable
390
+ return {size(), 0};
391
+ }
392
+
393
+ // Match OP_FALSE OP_IF
394
+ if (inside_noop) {
395
+ switch (opcode) {
396
+ case OP_IF: case OP_NOTIF:
397
+ ++inside_noop;
398
+ break;
399
+ case OP_ENDIF:
400
+ if (0 == --inside_noop) {
401
+ counted += it - data_began + 1;
402
+ }
403
+ break;
404
+ default: /* do nothing */;
405
+ }
406
+ } else if (opcode == OP_IF && last_opcode == OP_FALSE) {
407
+ inside_noop = 1;
408
+ data_began = opcode_it;
409
+ // Match <data> OP_DROP
410
+ } else if (opcode <= OP_PUSHDATA4) {
411
+ data_began = opcode_it;
412
+ } else if (opcode == OP_DROP && last_opcode <= OP_PUSHDATA4) {
413
+ counted += it - data_began;
414
+ }
415
+ }
416
+ return {0, counted};
417
+ }
418
+
306
419
  bool GetScriptOp(CScriptBase::const_iterator& pc, CScriptBase::const_iterator end, opcodetype& opcodeRet, std::vector<unsigned char>* pvchRet)
307
420
  {
308
421
  opcodeRet = OP_INVALIDOPCODE;