@@ -292,6 +292,7 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
292
292
CScript::const_iterator pend = script.end ();
293
293
CScript::const_iterator pbegincodehash = script.begin ();
294
294
opcodetype opcode;
295
+ opcodetype prev_opcode = OP_INVALIDOPCODE;
295
296
valtype vchPushValue;
296
297
std::vector<bool > vfExec;
297
298
std::vector<valtype> altstack;
@@ -774,18 +775,34 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
774
775
{
775
776
// Don't verify before enabled...
776
777
if (flags & SCRIPT_VERIFY_OUTPUTS_HASH) {
777
- CScript::const_iterator lookahead = pc;
778
- opcodetype argument;
779
- // Read ahead one opcode as a lookahead argument
780
- if (!script.GetOp (lookahead, argument, vchPushValue))
781
- return set_error (serror, SCRIPT_ERR_BAD_OPCODE);
782
- // If lookahead argument was exactly 32 bytes, check OutputHash
778
+
779
+ if (stack.size () < 1 )
780
+ return set_error (serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
781
+
782
+ // Previous executed operation must be a data push.
783
+ //
784
+ // NOTE:
785
+ //
786
+ // INVALID_STACK_OPERATION might not be appropriate error code
787
+ // in this case, but this is closest thing in existing error codes.
788
+ //
789
+ // Making opcode behavior depend on the previous executed opcode
790
+ // adds complexity to the script execution model, but the amount
791
+ // of complexity added by this opcode-lookbehind mode is small,
792
+ // and this is arguably better than making non-pushdata
793
+ // opcodes use data lookahead, because this erodes the consistency
794
+ // of the stack machine execution model. The argument here seems
795
+ // to boil down to complexity vs model consistency.
796
+ // Reducing consistency just externalizes the complexity outside:
797
+ // to the users of the script and to the tools that operate on it.
798
+ if (prev_opcode > OP_PUSHDATA4)
799
+ return set_error (serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
800
+
801
+ valtype& vchHash = stacktop (-1 );
802
+
803
+ // If stack argument was exactly 32 bytes, check OutputHash
783
804
// This is so that we can later add different semantics for this opcode
784
- if (vchPushValue.size () == 32 ) {
785
- // Argument should be == 0x20 -- will fail later anyways
786
- if (!CheckMinimalPush (vchPushValue, argument)) {
787
- return set_error (serror, SCRIPT_ERR_MINIMALDATA);
788
- }
805
+ if (vchHash.size () == 32 ) {
789
806
// If multiple inputs allowed, two inputs with the same OutputsHashVerify
790
807
// would pay only half intended amount!
791
808
if (!checker.CheckOnlyOneInput ()) {
@@ -796,7 +813,6 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
796
813
return set_error (serror, SCRIPT_ERR_OUTPUTSHASHVERIFY);
797
814
}
798
815
}
799
-
800
816
}
801
817
}
802
818
break ;
@@ -1155,6 +1171,8 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
1155
1171
if (stack.size () + altstack.size () > MAX_STACK_SIZE)
1156
1172
return set_error (serror, SCRIPT_ERR_STACK_SIZE);
1157
1173
1174
+ prev_opcode = opcode;
1175
+
1158
1176
++opcode_pos;
1159
1177
}
1160
1178
}
0 commit comments