From f2f87965ea1e4561eb2f5d1ffc2bbc69b7f5214b Mon Sep 17 00:00:00 2001 From: Chris Stewart Date: Thu, 7 Mar 2024 10:39:20 -0600 Subject: [PATCH] consensus: Consistently encode and decode OP_1NEGATE similar to other small ints in Script --- src/script/script.h | 6 +++++- src/script/solver.cpp | 4 ++-- test/functional/test_framework/script.py | 23 ++++++++++++----------- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/script/script.h b/src/script/script.h index f457984980..cb491c286f 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -518,14 +518,18 @@ public: { if (opcode == OP_0) return 0; + if (opcode == OP_1NEGATE) + return -1; assert(opcode >= OP_1 && opcode <= OP_16); return (int)opcode - (int)(OP_1 - 1); } static opcodetype EncodeOP_N(int n) { - assert(n >= 0 && n <= 16); + assert(n >= -1 && n <= 16); if (n == 0) return OP_0; + if (n == -1) + return OP_1NEGATE; return (opcodetype)(OP_1+n-1); } diff --git a/src/script/solver.cpp b/src/script/solver.cpp index bd3c5cdf72..297458e727 100644 --- a/src/script/solver.cpp +++ b/src/script/solver.cpp @@ -55,10 +55,10 @@ static bool MatchPayToPubkeyHash(const CScript& script, valtype& pubkeyhash) return false; } -/** Test for "small positive integer" script opcodes - OP_1 through OP_16. */ +/** Test for "small positive integer" script opcodes - OP_0 through OP_16 and OP_1NEGATE. */ static constexpr bool IsSmallInteger(opcodetype opcode) { - return opcode >= OP_1 && opcode <= OP_16; + return opcode == OP_0 || (opcode >= OP_1 && opcode <= OP_16) || opcode == OP_1NEGATE; } /** Retrieve a minimally-encoded number in range [min,max] from an (opcode, data) pair, diff --git a/test/functional/test_framework/script.py b/test/functional/test_framework/script.py index d510cf9b1c..1e7647e991 100644 --- a/test/functional/test_framework/script.py +++ b/test/functional/test_framework/script.py @@ -66,27 +66,30 @@ class CScriptOp(int): @staticmethod def encode_op_n(n): """Encode a small integer op, returning an opcode""" - if not (0 <= n <= 16): - raise ValueError('Integer must be in range 0 <= n <= 16, got %d' % n) + if not (-1 <= n <= 16): + raise ValueError('Integer must be in range -1 <= n <= 16, got %d' % n) if n == 0: return OP_0 + elif n == -1: + return OP_1NEGATE else: return CScriptOp(OP_1 + n - 1) def decode_op_n(self): """Decode a small integer opcode, returning an integer""" + if not self.is_small_int(): + raise ValueError('op %r is not an OP_N' % self) if self == OP_0: return 0 - - if not (self == OP_0 or OP_1 <= self <= OP_16): - raise ValueError('op %r is not an OP_N' % self) - - return int(self - OP_1 + 1) + elif self == OP_1NEGATE: + return -1 + else: + return int(self - OP_1 + 1) def is_small_int(self): """Return true if the op pushes a small integer to the stack""" - if 0x51 <= self <= 0x60 or self == 0: + if self == OP_0 or OP_1 <= self <= OP_16 or self == OP_1NEGATE: return True else: return False @@ -443,10 +446,8 @@ class CScript(bytes): else: other = CScriptNum.encode(other) elif isinstance(other, int): - if 0 <= other <= 16: + if -1 <= other <= 16: other = bytes([CScriptOp.encode_op_n(other)]) - elif other == -1: - other = bytes([OP_1NEGATE]) else: other = CScriptOp.encode_op_pushdata(bn2vch(other)) elif isinstance(other, (bytes, bytearray)):