def test_pushdata4_error(self):
        with self.assertRaises(NotImplementedError) as context:
            ser.deserialize(bytes([78]))

        self.assertIn(
            'OP_PUSHDATA4 is a bad idea.',
            str(context.exception))
    def test_deserialize(self):
        self.assertEqual(
            helpers.MSIG_2_2['redeem_script'],
            ser.deserialize(helpers.MSIG_2_2['ser_script']))

        self.assertEqual(
            'OP_IF',
            ser.deserialize(bytes([99])))
Beispiel #3
0
def pubkeys_from_script(script: bytes) -> List[str]:
    '''
    guess-parses pubkeys from a serialized bitcoin script
    '''
    res: List[str] = []
    s = script_ser.deserialize(script)
    for token in s.split():
        if crypto.is_pubkey(token):
            res.append(token)
    return res
Beispiel #4
0
def is_op_return(o: tx.TxOut) -> bool:
    '''
    Checks whether a txout is standard TX_NULL_DATA op_return output
    Args:
        o (tx.TxOut): the output
    Returns:
        (bool): True if standard opreturn, otherwise false
    '''
    script: str = ser.deserialize(o.output_script)
    split_script = script.split()

    # TX_NULL_DATA, up to 83 bytes (80 for safety)
    if (rutils.le2i(o.value) == 0 and split_script[0] == 'OP_RETURN'
            and len(script) < 80):
        return True
    return False
Beispiel #5
0
def is_push_only(script_sig: bytes) -> bool:
    '''
    Determines whether a script is push-only
    Does this by parsing, and inspecting non-data elements
    Args:
        script_sig (bytes): the scriptSig
    Returns:
        (bool): True if Push Only, otherwise False
    '''
    script = ser.deserialize(script_sig)
    non_data_opcodes = [t for t in script if t[0:3] == 'OP_']
    for token in non_data_opcodes:
        integer_opcode = opcodes.CODE_TO_INT[token]
        if (integer_opcode in [79, 80] or integer_opcode >= 97):
            return False
    return True
Beispiel #6
0
def is_standard_output_type(o: tx.TxOut) -> bool:
    '''
    Checks standardness of an output based on its value and output script
    Args:
        o (tx.TxOut): the output the check
    Returns:
        (bool): True if standard, False otherwise
    '''
    # TX_SCRIPTHASH
    # TX_WITNESS_V0_KEYHASH
    # TX_WITNESS_V0_SCRIPTHASH
    # TX_PUBKEYHASH
    try:
        addr.from_output_script(o.output_script)
        return True
    except ValueError:
        pass

    script: str = ser.deserialize(o.output_script)
    split_script = script.split()

    # TX_PUBKEY
    if (split_script[-1] == 'OP_CHECKSIG' and len(split_script) == 2
            and len(bytes.fromhex(split_script[1])) in [33, 65]):
        return True

    # TX_MULTISIG, up to x-of-3
    if (split_script[-1] == 'OP_CHECKMULTISIG'
            and split_script[-2] in ['OP_1', 'OP_2', 'OP_3']):

        num_pubkeys = int(split_script[-2][-1])
        num_sigs = int(split_script[0][-1])

        if (num_sigs > num_pubkeys  # 3-of-2, or 16-of-3, or something
                or len(split_script) != num_pubkeys + 3):  # some junk script
            return False
        for pubkey in split_script[1:-2]:
            if len(bytes.fromhex(pubkey)) not in [33, 65]:
                return False
        return True

    # TX_NONSTANDARD/TX_WITNESS_UNKNOWN
    return False
Beispiel #7
0
 def _parse_script_sig(script_sig: bytes) -> Tuple[bytes, bytes]:
     '''
     byte_string -> (byte_string, byte_string)
     '''
     # Is there a better way to do this?
     stack_script = script_sig
     redeem_script = b''
     try:
         # If the last entry deserializes, it's a p2sh input
         # There is a vanishingly small edge case where the pubkey
         #   forms a deserializable script.
         # Edge case: serialization errors on CODESEPARATOR
         deserialized = serialization.deserialize(script_sig)
         items = deserialized.split()
         serialization.hex_deserialize(items[-1])
         stack_script = serialization.serialize(' '.join(items[:-1]))
         redeem_script = serialization.serialize(items[-1])
     except (IndexError, ValueError, NotImplementedError):
         pass
     return stack_script, redeem_script
    def test_deserialize_error(self):
        with self.assertRaises(IndexError) as context:
            ser.deserialize(b'\x05\x00\x00')
        self.assertIn(
            'Push 5 caused out of bounds exception.',
            str(context.exception))

        with self.assertRaises(NotImplementedError) as context:
            ser.deserialize(b'\xab')
        self.assertIn(
            'OP_CODESEPARATOR is a bad idea.',
            str(context.exception))

        with self.assertRaises(ValueError) as context:
            ser.deserialize(b'\xfe')
        self.assertIn(
            'Unsupported opcode. Got 0xfe',
            str(context.exception))