|
40 | 40 |
|
41 | 41 | SCRIPT_VERIFY_P2SH = object() |
42 | 42 | SCRIPT_VERIFY_STRICTENC = object() |
43 | | -SCRIPT_VERIFY_EVEN_S = object() |
44 | | -SCRIPT_VERIFY_NOCACHE = object() |
| 43 | +SCRIPT_VERIFY_DERSIG = object() |
| 44 | +SCRIPT_VERIFY_LOW_S = object() |
| 45 | +SCRIPT_VERIFY_NULLDUMMY = object() |
| 46 | +SCRIPT_VERIFY_SIGPUSHONLY = object() |
| 47 | +SCRIPT_VERIFY_MINIMALDATA = object() |
| 48 | +SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS = object() |
| 49 | +SCRIPT_VERIFY_CLEANSTACK = object() |
| 50 | +SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY = object() |
| 51 | + |
| 52 | +SCRIPT_VERIFY_FLAGS_BY_NAME = { |
| 53 | + 'P2SH': SCRIPT_VERIFY_P2SH, |
| 54 | + 'STRICTENC': SCRIPT_VERIFY_STRICTENC, |
| 55 | + 'DERSIG': SCRIPT_VERIFY_DERSIG, |
| 56 | + 'LOW_S': SCRIPT_VERIFY_LOW_S, |
| 57 | + 'NULLDUMMY': SCRIPT_VERIFY_NULLDUMMY, |
| 58 | + 'SIGPUSHONLY': SCRIPT_VERIFY_SIGPUSHONLY, |
| 59 | + 'MINIMALDATA': SCRIPT_VERIFY_MINIMALDATA, |
| 60 | + 'DISCOURAGE_UPGRADABLE_NOPS': SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS, |
| 61 | + 'CLEANSTACK': SCRIPT_VERIFY_CLEANSTACK, |
| 62 | + 'CHECKLOCKTIMEVERIFY': SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, |
| 63 | +} |
45 | 64 |
|
46 | 65 | class EvalScriptError(bitcoin.core.ValidationError): |
47 | 66 | """Base class for exceptions raised when a script fails during EvalScript() |
@@ -133,7 +152,7 @@ def _CheckSig(sig, pubkey, script, txTo, inIdx, err_raiser): |
133 | 152 | return key.verify(h, sig) |
134 | 153 |
|
135 | 154 |
|
136 | | -def _CheckMultiSig(opcode, script, stack, txTo, inIdx, err_raiser, nOpCount): |
| 155 | +def _CheckMultiSig(opcode, script, stack, txTo, inIdx, flags, err_raiser, nOpCount): |
137 | 156 | i = 1 |
138 | 157 | if len(stack) < i: |
139 | 158 | err_raiser(MissingOpArgumentsError, opcode, stack, i) |
@@ -190,14 +209,24 @@ def _CheckMultiSig(opcode, script, stack, txTo, inIdx, err_raiser, nOpCount): |
190 | 209 | if opcode == OP_CHECKMULTISIGVERIFY: |
191 | 210 | err_raiser(VerifyOpFailedError, opcode) |
192 | 211 |
|
193 | | - while i > 0: |
| 212 | + while i > 1: |
194 | 213 | stack.pop() |
195 | 214 | i -= 1 |
196 | 215 |
|
| 216 | + # Note how Bitcoin Core duplicates the len(stack) check, rather than |
| 217 | + # letting pop() handle it; maybe that's wrong? |
| 218 | + if len(stack) and SCRIPT_VERIFY_NULLDUMMY in flags: |
| 219 | + if stack[-1] != b'': |
| 220 | + raise err_raiser(ArgumentsInvalidError, opcode, "dummy value not OP_0") |
| 221 | + |
| 222 | + stack.pop() |
| 223 | + |
197 | 224 | if opcode == OP_CHECKMULTISIG: |
198 | 225 | if success: |
199 | 226 | stack.append(b"\x01") |
200 | 227 | else: |
| 228 | + # FIXME: this is incorrect, but not caught by existing |
| 229 | + # test cases |
201 | 230 | stack.append(b"\x00") |
202 | 231 |
|
203 | 232 |
|
@@ -457,7 +486,7 @@ def check_args(n): |
457 | 486 |
|
458 | 487 | elif sop == OP_CHECKMULTISIG or sop == OP_CHECKMULTISIGVERIFY: |
459 | 488 | tmpScript = CScript(scriptIn[pbegincodehash:]) |
460 | | - _CheckMultiSig(sop, tmpScript, stack, txTo, inIdx, err_raiser, nOpCount) |
| 489 | + _CheckMultiSig(sop, tmpScript, stack, txTo, inIdx, flags, err_raiser, nOpCount) |
461 | 490 |
|
462 | 491 | elif sop == OP_CHECKSIG or sop == OP_CHECKSIGVERIFY: |
463 | 492 | check_args(2) |
@@ -572,9 +601,15 @@ def check_args(n): |
572 | 601 | check_args(2) |
573 | 602 | del stack[-2] |
574 | 603 |
|
575 | | - elif sop == OP_NOP or (sop >= OP_NOP1 and sop <= OP_NOP10): |
| 604 | + elif sop == OP_NOP: |
576 | 605 | pass |
577 | 606 |
|
| 607 | + elif sop >= OP_NOP1 and sop <= OP_NOP10: |
| 608 | + if SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS in flags: |
| 609 | + err_raiser(EvalScriptError, "%s reserved for soft-fork upgrades" % OPCODE_NAMES[sop]) |
| 610 | + else: |
| 611 | + pass |
| 612 | + |
578 | 613 | elif sop == OP_OVER: |
579 | 614 | check_args(2) |
580 | 615 | vch = stack[-2] |
@@ -735,21 +770,30 @@ def VerifyScript(scriptSig, scriptPubKey, txTo, inIdx, flags=()): |
735 | 770 | if not scriptSig.is_push_only(): |
736 | 771 | raise VerifyScriptError("P2SH scriptSig not is_push_only()") |
737 | 772 |
|
738 | | - # stackCopy cannot be empty here, because if it was the |
| 773 | + # restore stack |
| 774 | + stack = stackCopy |
| 775 | + |
| 776 | + # stack cannot be empty here, because if it was the |
739 | 777 | # P2SH HASH <> EQUAL scriptPubKey would be evaluated with |
740 | 778 | # an empty stack and the EvalScript above would return false. |
741 | | - assert len(stackCopy) |
| 779 | + assert len(stack) |
742 | 780 |
|
743 | | - pubKey2 = CScript(stackCopy.pop()) |
| 781 | + pubKey2 = CScript(stack.pop()) |
744 | 782 |
|
745 | | - EvalScript(stackCopy, pubKey2, txTo, inIdx, flags=flags) |
| 783 | + EvalScript(stack, pubKey2, txTo, inIdx, flags=flags) |
746 | 784 |
|
747 | | - if not len(stackCopy): |
| 785 | + if not len(stack): |
748 | 786 | raise VerifyScriptError("P2SH inner scriptPubKey left an empty stack") |
749 | 787 |
|
750 | | - if not _CastToBool(stackCopy[-1]): |
| 788 | + if not _CastToBool(stack[-1]): |
751 | 789 | raise VerifyScriptError("P2SH inner scriptPubKey returned false") |
752 | 790 |
|
| 791 | + if SCRIPT_VERIFY_CLEANSTACK in flags: |
| 792 | + assert SCRIPT_VERIFY_P2SH in flags |
| 793 | + |
| 794 | + if len(stack) != 1: |
| 795 | + raise VerifyScriptError("scriptPubKey left extra items on stack") |
| 796 | + |
753 | 797 |
|
754 | 798 | class VerifySignatureError(bitcoin.core.ValidationError): |
755 | 799 | pass |
@@ -782,8 +826,15 @@ def VerifySignature(txFrom, txTo, inIdx): |
782 | 826 | 'MAX_STACK_ITEMS', |
783 | 827 | 'SCRIPT_VERIFY_P2SH', |
784 | 828 | 'SCRIPT_VERIFY_STRICTENC', |
785 | | - 'SCRIPT_VERIFY_EVEN_S', |
786 | | - 'SCRIPT_VERIFY_NOCACHE', |
| 829 | + 'SCRIPT_VERIFY_DERSIG', |
| 830 | + 'SCRIPT_VERIFY_LOW_S', |
| 831 | + 'SCRIPT_VERIFY_NULLDUMMY', |
| 832 | + 'SCRIPT_VERIFY_SIGPUSHONLY', |
| 833 | + 'SCRIPT_VERIFY_MINIMALDATA', |
| 834 | + 'SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS', |
| 835 | + 'SCRIPT_VERIFY_CLEANSTACK', |
| 836 | + 'SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY', |
| 837 | + 'SCRIPT_VERIFY_FLAGS_BY_NAME', |
787 | 838 | 'EvalScriptError', |
788 | 839 | 'MaxOpCountError', |
789 | 840 | 'MissingOpArgumentsError', |
|
0 commit comments