Changeset View
Changeset View
Standalone View
Standalone View
test/functional/test_framework/script.py
Show First 20 Lines • Show All 53 Lines • ▼ Show 20 Lines | def encode_op_pushdata(d): | ||||
else: | else: | ||||
raise ValueError("Data too long to encode in a PUSHDATA op") | raise ValueError("Data too long to encode in a PUSHDATA op") | ||||
@staticmethod | @staticmethod | ||||
def encode_op_n(n): | def encode_op_n(n): | ||||
"""Encode a small integer op, returning an opcode""" | """Encode a small integer op, returning an opcode""" | ||||
if not (0 <= n <= 16): | if not (0 <= n <= 16): | ||||
raise ValueError( | raise ValueError( | ||||
'Integer must be in range 0 <= n <= 16, got %d' % n) | 'Integer must be in range 0 <= n <= 16, got {}'.format(n)) | ||||
if n == 0: | if n == 0: | ||||
return OP_0 | return OP_0 | ||||
else: | else: | ||||
return CScriptOp(OP_1 + n - 1) | return CScriptOp(OP_1 + n - 1) | ||||
def decode_op_n(self): | def decode_op_n(self): | ||||
"""Decode a small integer opcode, returning an integer""" | """Decode a small integer opcode, returning an integer""" | ||||
if self == OP_0: | if self == OP_0: | ||||
return 0 | return 0 | ||||
if not (self == OP_0 or OP_1 <= self <= OP_16): | if not (self == OP_0 or OP_1 <= self <= OP_16): | ||||
raise ValueError('op %r is not an OP_N' % self) | raise ValueError('op {!r} is not an OP_N'.format(self)) | ||||
return int(self - OP_1 + 1) | return int(self - OP_1 + 1) | ||||
def is_small_int(self): | def is_small_int(self): | ||||
"""Return true if the op pushes a small integer to the stack""" | """Return true if the op pushes a small integer to the stack""" | ||||
if 0x51 <= self <= 0x60 or self == 0: | if 0x51 <= self <= 0x60 or self == 0: | ||||
return True | return True | ||||
else: | else: | ||||
return False | return False | ||||
def __str__(self): | def __str__(self): | ||||
return repr(self) | return repr(self) | ||||
def __repr__(self): | def __repr__(self): | ||||
if self in OPCODE_NAMES: | if self in OPCODE_NAMES: | ||||
return OPCODE_NAMES[self] | return OPCODE_NAMES[self] | ||||
else: | else: | ||||
return 'CScriptOp(0x%x)' % self | return 'CScriptOp(0x{:x})'.format(self) | ||||
def __new__(cls, n): | def __new__(cls, n): | ||||
try: | try: | ||||
return _opcode_instances[n] | return _opcode_instances[n] | ||||
except IndexError: | except IndexError: | ||||
assert len(_opcode_instances) == n | assert len(_opcode_instances) == n | ||||
_opcode_instances.append(super(CScriptOp, cls).__new__(cls, n)) | _opcode_instances.append(super(CScriptOp, cls).__new__(cls, n)) | ||||
return _opcode_instances[n] | return _opcode_instances[n] | ||||
▲ Show 20 Lines • Show All 346 Lines • ▼ Show 20 Lines | def __add__(self, other): | ||||
# noticed. | # noticed. | ||||
other = self.__coerce_instance(other) | other = self.__coerce_instance(other) | ||||
try: | try: | ||||
# bytes.__add__ always returns bytes instances unfortunately | # bytes.__add__ always returns bytes instances unfortunately | ||||
return CScript(super(CScript, self).__add__(other)) | return CScript(super(CScript, self).__add__(other)) | ||||
except TypeError: | except TypeError: | ||||
raise TypeError( | raise TypeError( | ||||
'Can not add a %r instance to a CScript' % other.__class__) | 'Can not add a {!r} instance to a CScript'.format(other.__class__)) | ||||
def join(self, iterable): | def join(self, iterable): | ||||
# join makes no sense for a CScript() | # join makes no sense for a CScript() | ||||
raise NotImplementedError | raise NotImplementedError | ||||
def __new__(cls, value=b''): | def __new__(cls, value=b''): | ||||
if isinstance(value, bytes) or isinstance(value, bytearray): | if isinstance(value, bytes) or isinstance(value, bytearray): | ||||
return super(CScript, cls).__new__(cls, value) | return super(CScript, cls).__new__(cls, value) | ||||
Show All 19 Lines | def raw_iter(self): | ||||
i += 1 | i += 1 | ||||
if opcode > OP_PUSHDATA4: | if opcode > OP_PUSHDATA4: | ||||
yield (opcode, None, sop_idx) | yield (opcode, None, sop_idx) | ||||
else: | else: | ||||
datasize = None | datasize = None | ||||
pushdata_type = None | pushdata_type = None | ||||
if opcode < OP_PUSHDATA1: | if opcode < OP_PUSHDATA1: | ||||
pushdata_type = 'PUSHDATA(%d)' % opcode | pushdata_type = 'PUSHDATA({})'.format(opcode) | ||||
datasize = opcode | datasize = opcode | ||||
elif opcode == OP_PUSHDATA1: | elif opcode == OP_PUSHDATA1: | ||||
pushdata_type = 'PUSHDATA1' | pushdata_type = 'PUSHDATA1' | ||||
if i >= len(self): | if i >= len(self): | ||||
raise CScriptInvalidError( | raise CScriptInvalidError( | ||||
'PUSHDATA1: missing data length') | 'PUSHDATA1: missing data length') | ||||
datasize = bord(self[i]) | datasize = bord(self[i]) | ||||
Show All 19 Lines | def raw_iter(self): | ||||
else: | else: | ||||
assert False # shouldn't happen | assert False # shouldn't happen | ||||
data = bytes(self[i:i + datasize]) | data = bytes(self[i:i + datasize]) | ||||
# Check for truncation | # Check for truncation | ||||
if len(data) < datasize: | if len(data) < datasize: | ||||
raise CScriptTruncatedPushDataError( | raise CScriptTruncatedPushDataError( | ||||
'%s: truncated data' % pushdata_type, data) | '{}: truncated data'.format(pushdata_type, data)) | ||||
i += datasize | i += datasize | ||||
yield (opcode, data, sop_idx) | yield (opcode, data, sop_idx) | ||||
def __iter__(self): | def __iter__(self): | ||||
"""'Cooked' iteration | """'Cooked' iteration | ||||
Show All 14 Lines | def __iter__(self): | ||||
else: | else: | ||||
yield CScriptOp(opcode) | yield CScriptOp(opcode) | ||||
def __repr__(self): | def __repr__(self): | ||||
# For Python3 compatibility add b before strings so testcases don't | # For Python3 compatibility add b before strings so testcases don't | ||||
# need to change | # need to change | ||||
def _repr(o): | def _repr(o): | ||||
if isinstance(o, bytes): | if isinstance(o, bytes): | ||||
return b"x('%s')" % hexlify(o).decode('ascii') | return "x('{}')".format(hexlify(o).decode('ascii')).encode() | ||||
else: | else: | ||||
return repr(o) | return repr(o) | ||||
ops = [] | ops = [] | ||||
i = iter(self) | i = iter(self) | ||||
while True: | while True: | ||||
op = None | op = None | ||||
try: | try: | ||||
op = _repr(next(i)) | op = _repr(next(i)) | ||||
except CScriptTruncatedPushDataError as err: | except CScriptTruncatedPushDataError as err: | ||||
op = '%s...<ERROR: %s>' % (_repr(err.data), err) | op = '{}...<ERROR: {}>'.format(_repr(err.data), err) | ||||
break | break | ||||
except CScriptInvalidError as err: | except CScriptInvalidError as err: | ||||
op = '<ERROR: %s>' % err | op = '<ERROR: {}>'.format(err) | ||||
break | break | ||||
except StopIteration: | except StopIteration: | ||||
break | break | ||||
finally: | finally: | ||||
if op is not None: | if op is not None: | ||||
ops.append(op) | ops.append(op) | ||||
return "CScript([%s])" % ', '.join(ops) | return "CScript([{}])".format(', '.join(ops)) | ||||
def GetSigOpCount(self, fAccurate): | def GetSigOpCount(self, fAccurate): | ||||
"""Get the SigOp count. | """Get the SigOp count. | ||||
fAccurate - Accurately count CHECKMULTISIG, see BIP16 for details. | fAccurate - Accurately count CHECKMULTISIG, see BIP16 for details. | ||||
Note that this is consensus-critical. | Note that this is consensus-critical. | ||||
""" | """ | ||||
Show All 40 Lines | def SignatureHash(script, txTo, inIdx, hashtype): | ||||
"""Consensus-correct SignatureHash | """Consensus-correct SignatureHash | ||||
Returns (hash, err) to precisely match the consensus-critical behavior of | Returns (hash, err) to precisely match the consensus-critical behavior of | ||||
the SIGHASH_SINGLE bug. (inIdx is *not* checked for validity) | the SIGHASH_SINGLE bug. (inIdx is *not* checked for validity) | ||||
""" | """ | ||||
HASH_ONE = b'\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | HASH_ONE = b'\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | ||||
if inIdx >= len(txTo.vin): | if inIdx >= len(txTo.vin): | ||||
return (HASH_ONE, "inIdx %d out of range (%d)" % (inIdx, len(txTo.vin))) | return (HASH_ONE, "inIdx {} out of range ({})".format(inIdx, len(txTo.vin))) | ||||
txtmp = CTransaction(txTo) | txtmp = CTransaction(txTo) | ||||
for txin in txtmp.vin: | for txin in txtmp.vin: | ||||
txin.scriptSig = b'' | txin.scriptSig = b'' | ||||
txtmp.vin[inIdx].scriptSig = FindAndDelete( | txtmp.vin[inIdx].scriptSig = FindAndDelete( | ||||
script, CScript([OP_CODESEPARATOR])) | script, CScript([OP_CODESEPARATOR])) | ||||
if (hashtype & 0x1f) == SIGHASH_NONE: | if (hashtype & 0x1f) == SIGHASH_NONE: | ||||
txtmp.vout = [] | txtmp.vout = [] | ||||
for i in range(len(txtmp.vin)): | for i in range(len(txtmp.vin)): | ||||
if i != inIdx: | if i != inIdx: | ||||
txtmp.vin[i].nSequence = 0 | txtmp.vin[i].nSequence = 0 | ||||
elif (hashtype & 0x1f) == SIGHASH_SINGLE: | elif (hashtype & 0x1f) == SIGHASH_SINGLE: | ||||
outIdx = inIdx | outIdx = inIdx | ||||
if outIdx >= len(txtmp.vout): | if outIdx >= len(txtmp.vout): | ||||
return (HASH_ONE, "outIdx %d out of range (%d)" % (outIdx, len(txtmp.vout))) | return (HASH_ONE, "outIdx {} out of range ({})".format(outIdx, len(txtmp.vout))) | ||||
tmp = txtmp.vout[outIdx] | tmp = txtmp.vout[outIdx] | ||||
txtmp.vout = [] | txtmp.vout = [] | ||||
for i in range(outIdx): | for i in range(outIdx): | ||||
txtmp.vout.append(CTxOut(-1)) | txtmp.vout.append(CTxOut(-1)) | ||||
txtmp.vout.append(tmp) | txtmp.vout.append(tmp) | ||||
for i in range(len(txtmp.vin)): | for i in range(len(txtmp.vin)): | ||||
▲ Show 20 Lines • Show All 61 Lines • Show Last 20 Lines |