aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core_write.cpp2
-rw-r--r--src/script/interpreter.cpp32
-rw-r--r--src/script/interpreter.h2
-rw-r--r--src/script/script.cpp52
-rw-r--r--src/script/script.h102
-rw-r--r--src/test/script_tests.cpp32
-rw-r--r--src/test/sighash_tests.cpp2
7 files changed, 106 insertions, 118 deletions
diff --git a/src/core_write.cpp b/src/core_write.cpp
index 929498ff28..ee6737201b 100644
--- a/src/core_write.cpp
+++ b/src/core_write.cpp
@@ -34,7 +34,7 @@ std::string FormatScript(const CScript& script)
while (it != script.end()) {
CScript::const_iterator it2 = it;
std::vector<unsigned char> vch;
- if (script.GetOp2(it, op, &vch)) {
+ if (script.GetOp(it, op, vch)) {
if (op == OP_0) {
ret += "0 ";
continue;
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp
index 338e07e24e..e0d193fa38 100644
--- a/src/script/interpreter.cpp
+++ b/src/script/interpreter.cpp
@@ -250,6 +250,34 @@ bool static CheckMinimalPush(const valtype& data, opcodetype opcode) {
return true;
}
+int FindAndDelete(CScript& script, const CScript& b)
+{
+ int nFound = 0;
+ if (b.empty())
+ return nFound;
+ CScript result;
+ CScript::const_iterator pc = script.begin(), pc2 = script.begin(), end = script.end();
+ opcodetype opcode;
+ do
+ {
+ result.insert(result.end(), pc2, pc);
+ while (static_cast<size_t>(end - pc) >= b.size() && std::equal(b.begin(), b.end(), pc))
+ {
+ pc = pc + b.size();
+ ++nFound;
+ }
+ pc2 = pc;
+ }
+ while (script.GetOp(pc, opcode));
+
+ if (nFound > 0) {
+ result.insert(result.end(), pc2, end);
+ script = std::move(result);
+ }
+
+ return nFound;
+}
+
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror)
{
static const CScriptNum bnZero(0);
@@ -891,7 +919,7 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
// Drop the signature in pre-segwit scripts but not segwit scripts
if (sigversion == SigVersion::BASE) {
- scriptCode.FindAndDelete(CScript(vchSig));
+ FindAndDelete(scriptCode, CScript(vchSig));
}
if (!CheckSignatureEncoding(vchSig, flags, serror) || !CheckPubKeyEncoding(vchPubKey, flags, sigversion, serror)) {
@@ -955,7 +983,7 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
{
valtype& vchSig = stacktop(-isig-k);
if (sigversion == SigVersion::BASE) {
- scriptCode.FindAndDelete(CScript(vchSig));
+ FindAndDelete(scriptCode, CScript(vchSig));
}
}
diff --git a/src/script/interpreter.h b/src/script/interpreter.h
index 601a4a866d..50c747900a 100644
--- a/src/script/interpreter.h
+++ b/src/script/interpreter.h
@@ -189,4 +189,6 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const C
size_t CountWitnessSigOps(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, unsigned int flags);
+int FindAndDelete(CScript& script, const CScript& b);
+
#endif // BITCOIN_SCRIPT_INTERPRETER_H
diff --git a/src/script/script.cpp b/src/script/script.cpp
index 65e5405ebd..7f25d915a8 100644
--- a/src/script/script.cpp
+++ b/src/script/script.cpp
@@ -280,3 +280,55 @@ bool CScript::HasValidOps() const
}
return true;
}
+
+bool GetScriptOp(CScriptBase::const_iterator& pc, CScriptBase::const_iterator end, opcodetype& opcodeRet, std::vector<unsigned char>* pvchRet)
+{
+ opcodeRet = OP_INVALIDOPCODE;
+ if (pvchRet)
+ pvchRet->clear();
+ if (pc >= end)
+ return false;
+
+ // Read instruction
+ if (end - pc < 1)
+ return false;
+ unsigned int opcode = *pc++;
+
+ // Immediate operand
+ if (opcode <= OP_PUSHDATA4)
+ {
+ unsigned int nSize = 0;
+ if (opcode < OP_PUSHDATA1)
+ {
+ nSize = opcode;
+ }
+ else if (opcode == OP_PUSHDATA1)
+ {
+ if (end - pc < 1)
+ return false;
+ nSize = *pc++;
+ }
+ else if (opcode == OP_PUSHDATA2)
+ {
+ if (end - pc < 2)
+ return false;
+ nSize = ReadLE16(&pc[0]);
+ pc += 2;
+ }
+ else if (opcode == OP_PUSHDATA4)
+ {
+ if (end - pc < 4)
+ return false;
+ nSize = ReadLE32(&pc[0]);
+ pc += 4;
+ }
+ if (end - pc < 0 || (unsigned int)(end - pc) < nSize)
+ return false;
+ if (pvchRet)
+ pvchRet->assign(pc, pc + nSize);
+ pc += nSize;
+ }
+
+ opcodeRet = static_cast<opcodetype>(opcode);
+ return true;
+}
diff --git a/src/script/script.h b/src/script/script.h
index 59ceff247c..d8b7c06013 100644
--- a/src/script/script.h
+++ b/src/script/script.h
@@ -385,6 +385,8 @@ private:
*/
typedef prevector<28, unsigned char> CScriptBase;
+bool GetScriptOp(CScriptBase::const_iterator& pc, CScriptBase::const_iterator end, opcodetype& opcodeRet, std::vector<unsigned char>* pvchRet);
+
/** Serialized script, used inside transaction inputs and outputs */
class CScript : public CScriptBase
{
@@ -493,84 +495,16 @@ public:
}
- bool GetOp(iterator& pc, opcodetype& opcodeRet, std::vector<unsigned char>& vchRet)
- {
- // Wrapper so it can be called with either iterator or const_iterator
- const_iterator pc2 = pc;
- bool fRet = GetOp2(pc2, opcodeRet, &vchRet);
- pc = begin() + (pc2 - begin());
- return fRet;
- }
-
- bool GetOp(iterator& pc, opcodetype& opcodeRet)
- {
- const_iterator pc2 = pc;
- bool fRet = GetOp2(pc2, opcodeRet, nullptr);
- pc = begin() + (pc2 - begin());
- return fRet;
- }
-
bool GetOp(const_iterator& pc, opcodetype& opcodeRet, std::vector<unsigned char>& vchRet) const
{
- return GetOp2(pc, opcodeRet, &vchRet);
+ return GetScriptOp(pc, end(), opcodeRet, &vchRet);
}
bool GetOp(const_iterator& pc, opcodetype& opcodeRet) const
{
- return GetOp2(pc, opcodeRet, nullptr);
+ return GetScriptOp(pc, end(), opcodeRet, nullptr);
}
- bool GetOp2(const_iterator& pc, opcodetype& opcodeRet, std::vector<unsigned char>* pvchRet) const
- {
- opcodeRet = OP_INVALIDOPCODE;
- if (pvchRet)
- pvchRet->clear();
- if (pc >= end())
- return false;
-
- // Read instruction
- if (end() - pc < 1)
- return false;
- unsigned int opcode = *pc++;
-
- // Immediate operand
- if (opcode <= OP_PUSHDATA4)
- {
- unsigned int nSize = 0;
- if (opcode < OP_PUSHDATA1)
- {
- nSize = opcode;
- }
- else if (opcode == OP_PUSHDATA1)
- {
- if (end() - pc < 1)
- return false;
- nSize = *pc++;
- }
- else if (opcode == OP_PUSHDATA2)
- {
- if (end() - pc < 2)
- return false;
- nSize = ReadLE16(&pc[0]);
- pc += 2;
- }
- else if (opcode == OP_PUSHDATA4)
- {
- if (end() - pc < 4)
- return false;
- nSize = ReadLE32(&pc[0]);
- pc += 4;
- }
- if (end() - pc < 0 || (unsigned int)(end() - pc) < nSize)
- return false;
- if (pvchRet)
- pvchRet->assign(pc, pc + nSize);
- pc += nSize;
- }
-
- opcodeRet = static_cast<opcodetype>(opcode);
- return true;
- }
/** Encode/decode small integers: */
static int DecodeOP_N(opcodetype opcode)
@@ -588,34 +522,6 @@ public:
return (opcodetype)(OP_1+n-1);
}
- int FindAndDelete(const CScript& b)
- {
- int nFound = 0;
- if (b.empty())
- return nFound;
- CScript result;
- iterator pc = begin(), pc2 = begin();
- opcodetype opcode;
- do
- {
- result.insert(result.end(), pc2, pc);
- while (static_cast<size_t>(end() - pc) >= b.size() && std::equal(b.begin(), b.end(), pc))
- {
- pc = pc + b.size();
- ++nFound;
- }
- pc2 = pc;
- }
- while (GetOp(pc, opcode));
-
- if (nFound > 0) {
- result.insert(result.end(), pc2, end());
- *this = result;
- }
-
- return nFound;
- }
-
/**
* Pre-version-0.6, Bitcoin always counted CHECKMULTISIGs
* as 20 sigops. With pay-to-script-hash, that changed:
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index a06b573b37..068f1e66f4 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -1349,43 +1349,43 @@ BOOST_AUTO_TEST_CASE(script_FindAndDelete)
s = CScript() << OP_1 << OP_2;
d = CScript(); // delete nothing should be a no-op
expect = s;
- BOOST_CHECK_EQUAL(s.FindAndDelete(d), 0);
+ BOOST_CHECK_EQUAL(FindAndDelete(s, d), 0);
BOOST_CHECK(s == expect);
s = CScript() << OP_1 << OP_2 << OP_3;
d = CScript() << OP_2;
expect = CScript() << OP_1 << OP_3;
- BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1);
+ BOOST_CHECK_EQUAL(FindAndDelete(s, d), 1);
BOOST_CHECK(s == expect);
s = CScript() << OP_3 << OP_1 << OP_3 << OP_3 << OP_4 << OP_3;
d = CScript() << OP_3;
expect = CScript() << OP_1 << OP_4;
- BOOST_CHECK_EQUAL(s.FindAndDelete(d), 4);
+ BOOST_CHECK_EQUAL(FindAndDelete(s, d), 4);
BOOST_CHECK(s == expect);
s = ScriptFromHex("0302ff03"); // PUSH 0x02ff03 onto stack
d = ScriptFromHex("0302ff03");
expect = CScript();
- BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1);
+ BOOST_CHECK_EQUAL(FindAndDelete(s, d), 1);
BOOST_CHECK(s == expect);
s = ScriptFromHex("0302ff030302ff03"); // PUSH 0x2ff03 PUSH 0x2ff03
d = ScriptFromHex("0302ff03");
expect = CScript();
- BOOST_CHECK_EQUAL(s.FindAndDelete(d), 2);
+ BOOST_CHECK_EQUAL(FindAndDelete(s, d), 2);
BOOST_CHECK(s == expect);
s = ScriptFromHex("0302ff030302ff03");
d = ScriptFromHex("02");
expect = s; // FindAndDelete matches entire opcodes
- BOOST_CHECK_EQUAL(s.FindAndDelete(d), 0);
+ BOOST_CHECK_EQUAL(FindAndDelete(s, d), 0);
BOOST_CHECK(s == expect);
s = ScriptFromHex("0302ff030302ff03");
d = ScriptFromHex("ff");
expect = s;
- BOOST_CHECK_EQUAL(s.FindAndDelete(d), 0);
+ BOOST_CHECK_EQUAL(FindAndDelete(s, d), 0);
BOOST_CHECK(s == expect);
// This is an odd edge case: strip of the push-three-bytes
@@ -1393,44 +1393,44 @@ BOOST_AUTO_TEST_CASE(script_FindAndDelete)
s = ScriptFromHex("0302ff030302ff03");
d = ScriptFromHex("03");
expect = CScript() << ParseHex("ff03") << ParseHex("ff03");
- BOOST_CHECK_EQUAL(s.FindAndDelete(d), 2);
+ BOOST_CHECK_EQUAL(FindAndDelete(s, d), 2);
BOOST_CHECK(s == expect);
// Byte sequence that spans multiple opcodes:
s = ScriptFromHex("02feed5169"); // PUSH(0xfeed) OP_1 OP_VERIFY
d = ScriptFromHex("feed51");
expect = s;
- BOOST_CHECK_EQUAL(s.FindAndDelete(d), 0); // doesn't match 'inside' opcodes
+ BOOST_CHECK_EQUAL(FindAndDelete(s, d), 0); // doesn't match 'inside' opcodes
BOOST_CHECK(s == expect);
s = ScriptFromHex("02feed5169"); // PUSH(0xfeed) OP_1 OP_VERIFY
d = ScriptFromHex("02feed51");
expect = ScriptFromHex("69");
- BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1);
+ BOOST_CHECK_EQUAL(FindAndDelete(s, d), 1);
BOOST_CHECK(s == expect);
s = ScriptFromHex("516902feed5169");
d = ScriptFromHex("feed51");
expect = s;
- BOOST_CHECK_EQUAL(s.FindAndDelete(d), 0);
+ BOOST_CHECK_EQUAL(FindAndDelete(s, d), 0);
BOOST_CHECK(s == expect);
s = ScriptFromHex("516902feed5169");
d = ScriptFromHex("02feed51");
expect = ScriptFromHex("516969");
- BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1);
+ BOOST_CHECK_EQUAL(FindAndDelete(s, d), 1);
BOOST_CHECK(s == expect);
s = CScript() << OP_0 << OP_0 << OP_1 << OP_1;
d = CScript() << OP_0 << OP_1;
expect = CScript() << OP_0 << OP_1; // FindAndDelete is single-pass
- BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1);
+ BOOST_CHECK_EQUAL(FindAndDelete(s, d), 1);
BOOST_CHECK(s == expect);
s = CScript() << OP_0 << OP_0 << OP_1 << OP_0 << OP_1 << OP_1;
d = CScript() << OP_0 << OP_1;
expect = CScript() << OP_0 << OP_1; // FindAndDelete is single-pass
- BOOST_CHECK_EQUAL(s.FindAndDelete(d), 2);
+ BOOST_CHECK_EQUAL(FindAndDelete(s, d), 2);
BOOST_CHECK(s == expect);
// Another weird edge case:
@@ -1438,13 +1438,13 @@ BOOST_AUTO_TEST_CASE(script_FindAndDelete)
s = ScriptFromHex("0003feed");
d = ScriptFromHex("03feed"); // ... can remove the invalid push
expect = ScriptFromHex("00");
- BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1);
+ BOOST_CHECK_EQUAL(FindAndDelete(s, d), 1);
BOOST_CHECK(s == expect);
s = ScriptFromHex("0003feed");
d = ScriptFromHex("00");
expect = ScriptFromHex("03feed");
- BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1);
+ BOOST_CHECK_EQUAL(FindAndDelete(s, d), 1);
BOOST_CHECK(s == expect);
}
diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp
index a2bd8998b1..6b8856ef47 100644
--- a/src/test/sighash_tests.cpp
+++ b/src/test/sighash_tests.cpp
@@ -35,7 +35,7 @@ uint256 static SignatureHashOld(CScript scriptCode, const CTransaction& txTo, un
// In case concatenating two scripts ends up with two codeseparators,
// or an extra one at the end, this prevents all those possible incompatibilities.
- scriptCode.FindAndDelete(CScript(OP_CODESEPARATOR));
+ FindAndDelete(scriptCode, CScript(OP_CODESEPARATOR));
// Blank out other inputs' signatures
for (unsigned int i = 0; i < txTmp.vin.size(); i++)