Skip to content

Commit 486269c

Browse files
authored
Merge pull request #2294 from barton2526/FindAndDelete
refactor: Optimize and Cleanup CScript::FindAndDelete
2 parents 727fcee + 28c2ef2 commit 486269c

File tree

2 files changed

+129
-3
lines changed

2 files changed

+129
-3
lines changed

src/script.h

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -510,17 +510,26 @@ class CScript : public CScriptBase
510510
int nFound = 0;
511511
if (b.empty())
512512
return nFound;
513-
iterator pc = begin();
513+
CScript result;
514+
iterator pc = begin(), pc2 = begin();
514515
opcodetype opcode;
515516
do
516517
{
517-
while (end() - pc >= (long)b.size() && memcmp(&pc[0], &b[0], b.size()) == 0)
518+
result.insert(result.end(), pc2, pc);
519+
while (static_cast<size_t>(end() - pc) >= b.size() && std::equal(b.begin(), b.end(), pc))
518520
{
519-
erase(pc, pc + b.size());
521+
pc = pc + b.size();
520522
++nFound;
521523
}
524+
pc2 = pc;
522525
}
523526
while (GetOp(pc, opcode));
527+
528+
if (nFound > 0) {
529+
result.insert(result.end(), pc2, end());
530+
*this = result;
531+
}
532+
524533
return nFound;
525534
}
526535

src/test/script_tests.cpp

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,4 +425,121 @@ BOOST_AUTO_TEST_CASE(script_combineSigs)
425425
BOOST_CHECK(combined == partial3c);
426426
}
427427

428+
static CScript
429+
ScriptFromHex(const char* hex)
430+
{
431+
std::vector<unsigned char> data = ParseHex(hex);
432+
return CScript(data.begin(), data.end());
433+
}
434+
435+
436+
BOOST_AUTO_TEST_CASE(script_FindAndDelete)
437+
{
438+
// Exercise the FindAndDelete functionality
439+
CScript s;
440+
CScript d;
441+
CScript expect;
442+
443+
s = CScript() << OP_1 << OP_2;
444+
d = CScript(); // delete nothing should be a no-op
445+
expect = s;
446+
BOOST_CHECK_EQUAL(s.FindAndDelete(d), 0);
447+
BOOST_CHECK(s == expect);
448+
449+
s = CScript() << OP_1 << OP_2 << OP_3;
450+
d = CScript() << OP_2;
451+
expect = CScript() << OP_1 << OP_3;
452+
BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1);
453+
BOOST_CHECK(s == expect);
454+
455+
s = CScript() << OP_3 << OP_1 << OP_3 << OP_3 << OP_4 << OP_3;
456+
d = CScript() << OP_3;
457+
expect = CScript() << OP_1 << OP_4;
458+
BOOST_CHECK_EQUAL(s.FindAndDelete(d), 4);
459+
BOOST_CHECK(s == expect);
460+
461+
s = ScriptFromHex("0302ff03"); // PUSH 0x02ff03 onto stack
462+
d = ScriptFromHex("0302ff03");
463+
expect = CScript();
464+
BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1);
465+
BOOST_CHECK(s == expect);
466+
467+
s = ScriptFromHex("0302ff030302ff03"); // PUSH 0x2ff03 PUSH 0x2ff03
468+
d = ScriptFromHex("0302ff03");
469+
expect = CScript();
470+
BOOST_CHECK_EQUAL(s.FindAndDelete(d), 2);
471+
BOOST_CHECK(s == expect);
472+
473+
s = ScriptFromHex("0302ff030302ff03");
474+
d = ScriptFromHex("02");
475+
expect = s; // FindAndDelete matches entire opcodes
476+
BOOST_CHECK_EQUAL(s.FindAndDelete(d), 0);
477+
BOOST_CHECK(s == expect);
478+
479+
s = ScriptFromHex("0302ff030302ff03");
480+
d = ScriptFromHex("ff");
481+
expect = s;
482+
BOOST_CHECK_EQUAL(s.FindAndDelete(d), 0);
483+
BOOST_CHECK(s == expect);
484+
485+
// This is an odd edge case: strip of the push-three-bytes
486+
// prefix, leaving 02ff03 which is push-two-bytes:
487+
s = ScriptFromHex("0302ff030302ff03");
488+
d = ScriptFromHex("03");
489+
expect = CScript() << ParseHex("ff03") << ParseHex("ff03");
490+
BOOST_CHECK_EQUAL(s.FindAndDelete(d), 2);
491+
BOOST_CHECK(s == expect);
492+
493+
// Byte sequence that spans multiple opcodes:
494+
s = ScriptFromHex("02feed5169"); // PUSH(0xfeed) OP_1 OP_VERIFY
495+
d = ScriptFromHex("feed51");
496+
expect = s;
497+
BOOST_CHECK_EQUAL(s.FindAndDelete(d), 0); // doesn't match 'inside' opcodes
498+
BOOST_CHECK(s == expect);
499+
500+
s = ScriptFromHex("02feed5169"); // PUSH(0xfeed) OP_1 OP_VERIFY
501+
d = ScriptFromHex("02feed51");
502+
expect = ScriptFromHex("69");
503+
BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1);
504+
BOOST_CHECK(s == expect);
505+
506+
s = ScriptFromHex("516902feed5169");
507+
d = ScriptFromHex("feed51");
508+
expect = s;
509+
BOOST_CHECK_EQUAL(s.FindAndDelete(d), 0);
510+
BOOST_CHECK(s == expect);
511+
512+
s = ScriptFromHex("516902feed5169");
513+
d = ScriptFromHex("02feed51");
514+
expect = ScriptFromHex("516969");
515+
BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1);
516+
BOOST_CHECK(s == expect);
517+
518+
s = CScript() << OP_0 << OP_0 << OP_1 << OP_1;
519+
d = CScript() << OP_0 << OP_1;
520+
expect = CScript() << OP_0 << OP_1; // FindAndDelete is single-pass
521+
BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1);
522+
BOOST_CHECK(s == expect);
523+
524+
s = CScript() << OP_0 << OP_0 << OP_1 << OP_0 << OP_1 << OP_1;
525+
d = CScript() << OP_0 << OP_1;
526+
expect = CScript() << OP_0 << OP_1; // FindAndDelete is single-pass
527+
BOOST_CHECK_EQUAL(s.FindAndDelete(d), 2);
528+
BOOST_CHECK(s == expect);
529+
530+
// Another weird edge case:
531+
// End with invalid push (not enough data)...
532+
s = ScriptFromHex("0003feed");
533+
d = ScriptFromHex("03feed"); // ... can remove the invalid push
534+
expect = ScriptFromHex("00");
535+
BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1);
536+
BOOST_CHECK(s == expect);
537+
538+
s = ScriptFromHex("0003feed");
539+
d = ScriptFromHex("00");
540+
expect = ScriptFromHex("03feed");
541+
BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1);
542+
BOOST_CHECK(s == expect);
543+
}
544+
428545
BOOST_AUTO_TEST_SUITE_END()

0 commit comments

Comments
 (0)