aboutsummaryrefslogtreecommitdiff
path: root/src/script/interpreter.cpp
diff options
context:
space:
mode:
authorWladimir J. van der Laan <laanwj@gmail.com>2014-10-28 13:11:10 +0100
committerWladimir J. van der Laan <laanwj@gmail.com>2014-10-28 13:19:38 +0100
commitcd9114e5136ecc1f60baa43fffeeb632782f2353 (patch)
treec73f172d0131f5f9c4434e391db59238fd4bc447 /src/script/interpreter.cpp
parent068b7f8ee23f4557d356db30b4cbbd98065bd27c (diff)
parent16d78bd68e1488a2a84e368b50bf511c77392d2e (diff)
downloadbitcoin-cd9114e5136ecc1f60baa43fffeeb632782f2353.tar.xz
Merge pull request #5065
16d78bd Add valid invert of invalid every numeric opcode tests (Peter Todd) 2b62e17 Clearly separate PUSHDATA and numeric argument MINIMALDATA tests (Peter Todd) dfeec18 Test every numeric-accepting opcode for correct handling of the numeric minimal encoding rule (Peter Todd) 554147a Ensure MINIMALDATA invalid tests can only fail one way (Peter Todd) 6004e77 Improve CScriptNum() comment (Peter Todd) 698c6ab Add SCRIPT_VERIFY_MINIMALDATA (BIP62 rules 3 and 4) (Pieter Wuille) d752ba8 Add SCRIPT_VERIFY_SIGPUSHONLY (BIP62 rule 2) (Pieter Wuille)
Diffstat (limited to 'src/script/interpreter.cpp')
-rw-r--r--src/script/interpreter.cpp55
1 files changed, 44 insertions, 11 deletions
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp
index cd73b88210..11c909472a 100644
--- a/src/script/interpreter.cpp
+++ b/src/script/interpreter.cpp
@@ -157,6 +157,29 @@ bool static CheckPubKeyEncoding(const valtype &vchSig, unsigned int flags) {
return true;
}
+bool static CheckMinimalPush(const valtype& data, opcodetype opcode) {
+ if (data.size() == 0) {
+ // Could have used OP_0.
+ return opcode == OP_0;
+ } else if (data.size() == 1 && data[0] >= 1 && data[0] <= 16) {
+ // Could have used OP_1 .. OP_16.
+ return opcode == OP_1 + (data[0] - 1);
+ } else if (data.size() == 1 && data[0] == 0x81) {
+ // Could have used OP_1NEGATE.
+ return opcode == OP_1NEGATE;
+ } else if (data.size() <= 75) {
+ // Could have used a direct push (opcode indicating number of bytes pushed + those bytes).
+ return opcode == data.size();
+ } else if (data.size() <= 255) {
+ // Could have used OP_PUSHDATA.
+ return opcode == OP_PUSHDATA1;
+ } else if (data.size() <= 65535) {
+ // Could have used OP_PUSHDATA2.
+ return opcode == OP_PUSHDATA2;
+ }
+ return true;
+}
+
bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker)
{
CScript::const_iterator pc = script.begin();
@@ -169,6 +192,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
if (script.size() > 10000)
return false;
int nOpCount = 0;
+ bool fRequireMinimal = (flags & SCRIPT_VERIFY_MINIMALDATA) != 0;
try
{
@@ -205,9 +229,12 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
opcode == OP_RSHIFT)
return false; // Disabled opcodes.
- if (fExec && 0 <= opcode && opcode <= OP_PUSHDATA4)
+ if (fExec && 0 <= opcode && opcode <= OP_PUSHDATA4) {
+ if (fRequireMinimal && !CheckMinimalPush(vchPushValue, opcode)) {
+ return false;
+ }
stack.push_back(vchPushValue);
- else if (fExec || (OP_IF <= opcode && opcode <= OP_ENDIF))
+ } else if (fExec || (OP_IF <= opcode && opcode <= OP_ENDIF))
switch (opcode)
{
//
@@ -234,6 +261,8 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
// ( -- value)
CScriptNum bn((int)opcode - (int)(OP_1 - 1));
stack.push_back(bn.getvch());
+ // The result of these opcodes should always be the minimal way to push the data
+ // they push, so no need for a CheckMinimalPush here.
}
break;
@@ -458,7 +487,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
// (xn ... x2 x1 x0 n - ... x2 x1 x0 xn)
if (stack.size() < 2)
return false;
- int n = CScriptNum(stacktop(-1)).getint();
+ int n = CScriptNum(stacktop(-1), fRequireMinimal).getint();
popstack(stack);
if (n < 0 || n >= (int)stack.size())
return false;
@@ -557,7 +586,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
// (in -- out)
if (stack.size() < 1)
return false;
- CScriptNum bn(stacktop(-1));
+ CScriptNum bn(stacktop(-1), fRequireMinimal);
switch (opcode)
{
case OP_1ADD: bn += bnOne; break;
@@ -590,8 +619,8 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
// (x1 x2 -- out)
if (stack.size() < 2)
return false;
- CScriptNum bn1(stacktop(-2));
- CScriptNum bn2(stacktop(-1));
+ CScriptNum bn1(stacktop(-2), fRequireMinimal);
+ CScriptNum bn2(stacktop(-1), fRequireMinimal);
CScriptNum bn(0);
switch (opcode)
{
@@ -635,9 +664,9 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
// (x min max -- out)
if (stack.size() < 3)
return false;
- CScriptNum bn1(stacktop(-3));
- CScriptNum bn2(stacktop(-2));
- CScriptNum bn3(stacktop(-1));
+ CScriptNum bn1(stacktop(-3), fRequireMinimal);
+ CScriptNum bn2(stacktop(-2), fRequireMinimal);
+ CScriptNum bn3(stacktop(-1), fRequireMinimal);
bool fValue = (bn2 <= bn1 && bn1 < bn3);
popstack(stack);
popstack(stack);
@@ -727,7 +756,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
if ((int)stack.size() < i)
return false;
- int nKeysCount = CScriptNum(stacktop(-i)).getint();
+ int nKeysCount = CScriptNum(stacktop(-i), fRequireMinimal).getint();
if (nKeysCount < 0 || nKeysCount > 20)
return false;
nOpCount += nKeysCount;
@@ -738,7 +767,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
if ((int)stack.size() < i)
return false;
- int nSigsCount = CScriptNum(stacktop(-i)).getint();
+ int nSigsCount = CScriptNum(stacktop(-i), fRequireMinimal).getint();
if (nSigsCount < 0 || nSigsCount > nKeysCount)
return false;
int isig = ++i;
@@ -980,6 +1009,10 @@ bool SignatureChecker::CheckSig(const vector<unsigned char>& vchSigIn, const vec
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker)
{
+ if ((flags & SCRIPT_VERIFY_SIGPUSHONLY) != 0 && !scriptSig.IsPushOnly()) {
+ return false;
+ }
+
vector<vector<unsigned char> > stack, stackCopy;
if (!EvalScript(stack, scriptSig, flags, checker))
return false;