Ejemplo n.º 1
0
def generate_multisig_redeem_script(signatures_required: int,
                                    public_key_bytes: List[bytes]) -> bytes:
    """ Generate the redeem script for the multisig output

        <signatures_required> <pubkey 1> <pubkey 2> ... <pubkey N> <pubkey_count> <OP_CHECKMULTISIG>

        :param signatures_required: How many signatures are required to spend the outputs
        :type signatures_required: int

        :param public_key_bytes: Array of public keys that created the multisig wallet
        :type public_key_bytes: List[bytes]

        :return: The redeem script for the multisig wallet
        :rtype: bytes
    """
    if signatures_required > settings.MAX_MULTISIG_SIGNATURES:
        raise ValueError('Signatures required {} is over the limit'.format(
            signatures_required))
    if len(public_key_bytes) > settings.MAX_MULTISIG_PUBKEYS:
        raise ValueError('PubKeys length {} is over the limit'.format(
            len(public_key_bytes)))

    redeem_script = HathorScript()
    redeem_script.addOpcode(
        getattr(Opcode, 'OP_{}'.format(signatures_required)))
    for pubkey_bytes in public_key_bytes:
        redeem_script.pushData(pubkey_bytes)
    redeem_script.addOpcode(
        getattr(Opcode, 'OP_{}'.format(len(public_key_bytes))))
    redeem_script.addOpcode(Opcode.OP_CHECKMULTISIG)
    return redeem_script.data
Ejemplo n.º 2
0
    def test_pushdata(self):
        stack = []
        random_bytes = b'a' * 50
        s = HathorScript()
        s.pushData(random_bytes)

        op_pushdata(0, s.data, stack)

        self.assertEqual(random_bytes, stack.pop())

        with self.assertRaises(OutOfData):
            op_pushdata(0, s.data[:-1], stack)
Ejemplo n.º 3
0
def create_script_with_sigops(nops: int) -> bytes:
    """ Generate a script with multiple OP_CHECKMULTISIG that amounts to `nops` sigops
    """
    hscript = HathorScript()
    # each step adds 16 sigops up to `nops`, but not exceding nops
    for _ in range(nops // 16):
        hscript.addOpcode(Opcode.OP_16)
        hscript.addOpcode(Opcode.OP_CHECKMULTISIG)

    # add `nops % 16` sigops
    hscript.addOpcode(getattr(Opcode, 'OP_{}'.format(nops % 16)))
    hscript.addOpcode(Opcode.OP_CHECKMULTISIG)
    return hscript.data
Ejemplo n.º 4
0
def generate_multisig_redeem_script(signatures_required: int,
                                    public_key_bytes: List[bytes]) -> bytes:
    """ Generate the redeem script for the multisig output

        <signatures_required> <pubkey 1> <pubkey 2> ... <pubkey N> <pubkey_count> <OP_CHECKMULTISIG>

        :param signatures_required: How many signatures are required to spend the outputs
        :type signatures_required: int

        :param public_key_bytes: Array of public keys that created the multisig wallet
        :type public_key_bytes: List[bytes]

        :return: The redeem script for the multisig wallet
        :rtype: bytes
    """
    redeem_script = HathorScript()
    redeem_script.addOpcode(
        getattr(Opcode, 'OP_{}'.format(signatures_required)))
    for pubkey_bytes in public_key_bytes:
        redeem_script.pushData(pubkey_bytes)
    redeem_script.addOpcode(
        getattr(Opcode, 'OP_{}'.format(len(public_key_bytes))))
    redeem_script.addOpcode(Opcode.OP_CHECKMULTISIG)
    return redeem_script.data
Ejemplo n.º 5
0
    def test_data_pattern(self):
        # up to 75 bytes, no Opcode is needed
        s = HathorScript()
        re_match = re_compile('^DATA_75$')
        data = [0x00] * 75
        s.pushData(bytes(data))
        self.assertEqual(76, len(s.data))  # data_len + data
        match = re_match.search(s.data)
        self.assertIsNotNone(match)
        # for now, we also accept <= 75 bytes with OP_PUSHDATA1
        match = re_match.search(bytes([Opcode.OP_PUSHDATA1]) + s.data)
        self.assertIsNotNone(match)

        # with more, use OP_PUSHDATA1
        s = HathorScript()
        re_match = re_compile('^DATA_76$')
        data = [0x00] * 76
        s.pushData(bytes(data))
        self.assertEqual(78, len(s.data))  # OP_PUSHDATA1 + data_len + data
        match = re_match.search(s.data)
        self.assertIsNotNone(match)
        # test without PUSHDATA1 opcode. Should fail
        match = re_match.search(s.data[1:])
        self.assertIsNone(match)

        # DATA_ between other opcodes
        s = HathorScript()
        re_match = re_compile('^OP_HASH160 (DATA_20) OP_EQUALVERIFY$')
        data = [0x00] * 20
        s.addOpcode(Opcode.OP_HASH160)
        s.pushData(bytes(data))
        s.addOpcode(Opcode.OP_EQUALVERIFY)
        match = re_match.search(s.data)
        self.assertIsNotNone(match)

        # wrong length
        s = HathorScript()
        re_match = re_compile('^DATA_20$')
        data = [0x00] * 20
        s.pushData(bytes(data))
        s.data = s.data.replace(b'\x14', b'\x15')
        print(s.data)
        match = re_match.search(s.data)
        self.assertIsNone(match)
Ejemplo n.º 6
0
    def test_push_integers(self):
        # 1 byte
        s = HathorScript()
        s.pushData(255)
        n = get_pushdata(s.data)
        self.assertEqual(1, len(n))
        self.assertEqual(255, binary_to_int(n))

        # 2 bytes
        s = HathorScript()
        s.pushData(65535)
        n = get_pushdata(s.data)
        self.assertEqual(2, len(n))
        self.assertEqual(65535, binary_to_int(n))

        # 4 bytes
        s = HathorScript()
        s.pushData(4294967295)
        n = get_pushdata(s.data)
        self.assertEqual(4, len(n))
        self.assertEqual(4294967295, binary_to_int(n))

        # 8 bytes
        s = HathorScript()
        s.pushData(4294967296)
        n = get_pushdata(s.data)
        self.assertEqual(8, len(n))
        self.assertEqual(4294967296, binary_to_int(n))
Ejemplo n.º 7
0
    def test_get_script_op(self):
        """
            - pushdata, pushdata1, OP_N, OP_X
            - OutOfData in case pos > data_len (tested in get_data_single_byte?)
            - make script and iterate on it to make sure each step is returned
        """
        # for opcode test
        script0 = HathorScript()
        solution0 = []
        # for pushdata stack test
        script1 = HathorScript()
        solution1 = []
        # for integer stack test
        script2 = HathorScript()
        solution2 = []
        # for opcode (non OP_N) stack test
        script3 = HathorScript()

        for i in range(1, 76):
            solution0.append(i)
            solution1.append(b'1' * i)
            script0.pushData(b'1' * i)
            script1.pushData(b'1' * i)
        for i in range(0, 17):
            opc = getattr(Opcode, 'OP_{}'.format(i))
            solution0.append(opc)
            solution2.append(int(opc) - int(Opcode.OP_0))
            script0.addOpcode(opc)
            script2.addOpcode(opc)
        for o in [
                Opcode.OP_DUP,
                Opcode.OP_EQUAL,
                Opcode.OP_EQUALVERIFY,
                Opcode.OP_CHECKSIG,
                Opcode.OP_HASH160,
                Opcode.OP_GREATERTHAN_TIMESTAMP,
                Opcode.OP_CHECKMULTISIG,
                Opcode.OP_CHECKDATASIG,
                Opcode.OP_DATA_STREQUAL,
                Opcode.OP_DATA_GREATERTHAN,
                Opcode.OP_FIND_P2PKH,
                Opcode.OP_DATA_MATCH_VALUE,
        ]:
            solution0.append(o)
            script0.addOpcode(o)
            script3.addOpcode(o)

        data0 = script0.data
        data1 = script1.data
        data2 = script2.data
        data3 = script3.data

        # test opcode recognition
        pos = i = 0
        while pos < len(data0):
            opcode, pos = get_script_op(pos, data0, None)
            self.assertEqual(opcode, solution0[i])
            i += 1

        # test for pushdata stack
        pos = i = 0
        stack = []
        while pos < len(data1):
            opcode, pos = get_script_op(pos, data1, stack)
            self.assertEqual(stack.pop(), solution1[i])
            i += 1

        # test for push integer stack
        pos = i = 0
        stack = []
        while pos < len(data2):
            opcode, pos = get_script_op(pos, data2, stack)
            self.assertEqual(stack.pop(), solution2[i])
            i += 1

        # test for opcode (non OP_N) stack test
        pos = i = 0
        stack = []
        while pos < len(data3):
            opcode, pos = get_script_op(pos, data3, stack)
            self.assertEqual(len(stack), 0)
            i += 1

        # try to get opcode outside of script
        with self.assertRaises(OutOfData):
            pos = len(data0)
            get_script_op(pos, data0, None)

        with self.assertRaises(OutOfData):
            pos = len(data0) + 1
            get_script_op(pos, data0, None)
Ejemplo n.º 8
0
    def test_get_sigops_count(self):
        multisig_script = MultiSig.create_output_script(BURN_ADDRESS)
        p2pkh_script = P2PKH.create_output_script(BURN_ADDRESS)

        redeem_script = HathorScript()
        redeem_script.addOpcode(Opcode.OP_9)
        redeem_script.addOpcode(Opcode.OP_CHECKMULTISIG)

        input_script = HathorScript()
        input_script.pushData(BURN_ADDRESS)
        input_script.addOpcode(Opcode.OP_CHECKSIG)
        input_script.pushData(redeem_script.data)

        # include redeem_script if output is MultiSig
        self.assertEqual(get_sigops_count(input_script.data, multisig_script),
                         10)
        # if output is not MultiSig, count only input
        self.assertEqual(get_sigops_count(input_script.data, p2pkh_script), 1)
        # if no output_script, count only input
        self.assertEqual(get_sigops_count(input_script.data), 1)
Ejemplo n.º 9
0
    def test_count_sigops(self):
        script_0 = HathorScript()
        script_1 = HathorScript()
        script_10 = HathorScript()
        script_100 = HathorScript()

        script_0.addOpcode(Opcode.OP_0)
        self.assertEqual(count_sigops(script_0.data), 0)
        #
        script_1.addOpcode(Opcode.OP_10)
        script_1.addOpcode(Opcode.OP_CHECKSIG)
        self.assertEqual(count_sigops(script_1.data), 1)
        #
        script_10.addOpcode(Opcode.OP_10)
        script_10.addOpcode(Opcode.OP_CHECKMULTISIG)
        self.assertEqual(count_sigops(script_10.data), 10)
        #
        for i in range(6):
            script_100.addOpcode(Opcode.OP_16)
            script_100.addOpcode(Opcode.OP_CHECKMULTISIG)
        for i in range(4):
            script_100.addOpcode(Opcode.OP_CHECKSIG)
        self.assertEqual(count_sigops(script_100.data), 100)