def broadcast_transaction(self, transaction):
        """ Broadcasts a transaction to the Bitcoin network

        Args:
            transaction (bytes or str): serialized, signed transaction

        Returns:
            str: The transaction ID
        """
        if isinstance(transaction, bytes):
            signed_hex = bytes_to_str(transaction)
        elif isinstance(transaction, Transaction):
            signed_hex = bytes_to_str(bytes(transaction))
        elif isinstance(transaction, str):
            signed_hex = transaction
        else:
            raise TypeError(
                "transaction must be one of: bytes, str, Transaction.")

        data = {"rawtx": signed_hex}
        r = self._request("POST", "tx/send", json=data)

        if r.status_code == 200:
            j = r.json()
            return j["txid"]
        elif r.status_code == 400:
            j = r.json()

            # TODO: Change this to some more meaningful exception type
            raise exceptions.TransactionBroadcastError(j['message'])
        else:
            # Some other status code... should never happen.
            raise exceptions.TransactionBroadcastError(
                "Unexpected response: %r" % r.status_code)
Exemple #2
0
    def broadcast_transaction(self, transaction):
        """ Broadcasts a transaction to the Bitcoin network

        Args:
            transaction (bytes or str): serialized, signed transaction

        Returns:
            str: The transaction ID
        """
        if isinstance(transaction, bytes):
            signed_hex = bytes_to_str(transaction)
        elif isinstance(transaction, Transaction):
            signed_hex = bytes_to_str(bytes(transaction))
        elif isinstance(transaction, str):
            signed_hex = transaction
        else:
            raise TypeError(
                "transaction must be one of: bytes, str, Transaction.")

        data = {"signed_hex": signed_hex}
        r = self._request("POST", "transactions/send", json=data)
        if r.status_code == 200:
            j = r.json()
            return j["transaction_hash"]
        elif r.status_code == 400:
            j = r.json()

            # TODO: Change this to some more meaningful exception type
            raise exceptions.TransactionBroadcastError(j['message'])
        else:
            # Some other status code... should never happen.
            raise exceptions.TransactionBroadcastError(
                "Unexpected response: %r" % r.status_code)
def test_serialization():
    scr = 'OP_ADD OP_IF OP_DUP OP_HASH160 0x68bf827a2fa3b31e53215e5dd19260d21fdf053e OP_EQUALVERIFY OP_CHECKSIG OP_ELSE OP_IF OP_DUP OP_ELSE OP_2ROT OP_ENDIF OP_HASH160 0x68bf827a2fa3b31e53215e5dd19260d21fdf053e OP_EQUAL OP_ENDIF 0x010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101'    # nopep8

    s = Script(scr)
    assert s._tokens == ['OP_ADD', 'OP_IF', 'OP_DUP', 'OP_HASH160', b'h\xbf\x82z/\xa3\xb3\x1eS!^]\xd1\x92`\xd2\x1f\xdf\x05>', 'OP_EQUALVERIFY', 'OP_CHECKSIG', 'OP_ELSE', 'OP_IF', 'OP_DUP', 'OP_ELSE', 'OP_2ROT', 'OP_ENDIF', 'OP_HASH160', b'h\xbf\x82z/\xa3\xb3\x1eS!^]\xd1\x92`\xd2\x1f\xdf\x05>', 'OP_EQUAL', 'OP_ENDIF',  b'\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01']    # nopep8

    s_bytes = bytes(s)
    s_hex_str = bytes_to_str(s_bytes)

    s1 = Script.from_bytes(pack_var_str(s_bytes))[0]
    assert bytes(s1) == s_bytes

    raw_scr = "483045022100d60baf72dbaed8d15c3150e3309c9f7725fbdf91b0560330f3e2a0ccb606dfba02206422b1c73ce390766f0dc4e9143d0fbb400cc207e4a9fd9130e7f79e52bf81220121034ccd52d8f72cfdd680077a1a171458a1f7574ebaa196095390ae45e68adb3688"  # nopep8
    s = Script(bytes.fromhex(raw_scr))
    s._check_tokenized()
    assert s._tokens
    assert s._ast

    s_hex_str = bytes_to_str(bytes(s))
    assert s_hex_str == raw_scr

    s = Script('OP_0 OP_IF 0x1337c0de OP_ENDIF OP_1')
    b = bytes.fromhex("0063041337c0de6851")
    s1 = Script.from_bytes(pack_var_str(b))[0]
    assert bytes(s) == b
    assert bytes(s) == bytes(s1)
Exemple #4
0
    def __str__(self):
        """ Gives the hex-encoded serialization of the header.

        Returns:
            str: hex-encoded string.
        """
        return bytes_to_str(bytes(self))
    def to_hex(self):
        """ Generates a hex encoding of the serialized script.

        Returns:
            str: Hex-encoded serialization.
        """
        return bytes_to_str(bytes(self))
Exemple #6
0
    def to_hex(self):
        """ Generates a hex encoding of the serialized transaction.

        Returns:
            str: Hex-encoded serialization.
        """
        return bytes_to_str(bytes(self))
Exemple #7
0
    def __str__(self):
        """ Gives the hex-encoded serialization of the header.

        Returns:
            str: hex-encoded string.
        """
        return bytes_to_str(bytes(self))
Exemple #8
0
    def to_hex(self):
        """ 序列化字节流的十六进制表示。

        返回值:
            h (str): 十六进制字符串.
        """
        return bytes_to_str(bytes(self))
Exemple #9
0
    def to_hex(self):
        """ 生成序列化密钥的十六进制编码。

        返回值:
           str: 表示密钥的十六进制编码字符串。
        """
        return bytes_to_str(bytes(self))
Exemple #10
0
def write_ew_message(msg):
    """Write a message to the blockchain."""
    print("write_ew_message({})" % msg)

    # Create a bitcoin script object with our message
    if len(msg) > 72:
        raise Exception('Message is too long and may not be accepted.')
    msg = "EW " + msg
    message_script = Script('OP_RETURN 0x{}'.format(utils.bytes_to_str(msg.encode())))

    # Define the fee we're willing to pay for the tx
    tx_fee = 11000

    # Get the first UTXO from our set that can cover the fee
    utxo = None
    for utxo_addr, utxos in wallet.get_utxos().items():
        for u in utxos:
            if u.value > tx_fee:
                utxo = u
                break
        if utxo:
            break

    if not utxo:
        raise Exception('No UTXOs available to pay for the transaction.')

    # Build the transaction inputs (there is only one, but Transaction expects a list)
    inputs = [TransactionInput(outpoint=utxo.transaction_hash,
                               outpoint_index=utxo.outpoint_index,
                               script=utxo.script,
                               sequence_num=0xffffffff)]

    outputs = []
    # Build one output with our custom message script
    outputs.append(TransactionOutput(value=0, script=message_script))
    # Build another output to pay the UTXO money back to one of our addresses
    _, change_key_hash = utils.address_to_key_hash(wallet._accounts[0].get_next_address(True))
    outputs.append(TransactionOutput(value=utxo.value - tx_fee,
                                     script=Script.build_p2pkh(change_key_hash)))

    # Build an unsigned transaction object
    txn = Transaction(version=Transaction.DEFAULT_TRANSACTION_VERSION,
                      inputs=inputs,
                      outputs=outputs,
                      lock_time=0
                      )

    # Sign the transaction with the correct private key
    private_key = wallet.get_private_key(utxo_addr)
    txn.sign_input(input_index=0,
                   hash_type=Transaction.SIG_HASH_ALL,
                   private_key=private_key,
                   sub_script=utxo.script
                   )

    # Broadcast the transaction
    tx = wallet.broadcast_transaction(txn.to_hex())
    return tx
def test_is_p2pkh_sig():
    t = Transaction.from_hex("0100000001205607fb482a03600b736fb0c257dfd4faa49e45db3990e2c4994796031eae6e000000008b483045022100ed84be709227397fb1bc13b749f235e1f98f07ef8216f15da79e926b99d2bdeb02206ff39819d91bc81fecd74e59a721a38b00725389abb9cbecb42ad1c939fd8262014104e674caf81eb3bb4a97f2acf81b54dc930d9db6a6805fd46ca74ac3ab212c0bbf62164a11e7edaf31fbf24a878087d925303079f2556664f3b32d125f2138cbefffffffff0128230000000000001976a914f1fd1dc65af03c30fe743ac63cef3a120ffab57d88ac00000000")  # nopep8

    assert t.inputs[0].script.is_p2pkh_sig()

    sig_info = t.inputs[0].script.extract_sig_info()
    assert bytes_to_str(sig_info['public_key']) == '04e674caf81eb3bb4a97f2acf81b54dc930d9db6a6805fd46ca74ac3ab212c0bbf62164a11e7edaf31fbf24a878087d925303079f2556664f3b32d125f2138cbef'  # nopep8

    input_addresses = t.inputs[0].script.get_addresses()
    assert len(input_addresses) == 1
    assert input_addresses[0] == '1NKxQnbtKDdL6BY1UaKdrzCxQHfn3TQnqZ'
Exemple #12
0
def _send_transaction_eoa(address, params, value=0, data=""):
    gas = params['estimate']
    gas_price = DEFAULT_GAS_PRICE
    nonce = _get_nonce()
    tx = Transaction(nonce, gas_price, gas, address, value,
                     parse_as_bin(data)).sign(signing_key)
    response = rpc_call("eth_sendRawTransaction",
                        ["0x" + bytes_to_str(rlp.encode(tx))])
    result = response.get("result")
    if not result:
        raise RpcException(response.get("error"))
    return result
Exemple #13
0
    def __str__(self):
        """ Returns a human readable formatting of this input.

        Returns:
            s (str): A string containing the human readable input.
        """
        return (
            "CoinbaseInput(" +
            "Outpoint: %s " % (self.outpoint) +
            "Outpoint Index: 0x%08x " % (self.outpoint_index) +
            "Script: %s " % (bytes_to_str(self.script)) +
            "Sequence: 0x%08x)" % (self.sequence_num))
Exemple #14
0
    def __str__(self):
        """ Returns a human readable formatting of this input.

        Returns:
            s (str): A string containing the human readable input.
        """
        return (
            "CoinbaseInput(" +
            "Outpoint: %s " % (self.outpoint) +
            "Outpoint Index: 0x%08x " % (self.outpoint_index) +
            "Script: %s " % (bytes_to_str(self.script)) +
            "Sequence: 0x%08x)" % (self.sequence_num))
    def broadcast_transaction(self, transaction):
        """ Broadcasts a transaction to the Bitcoin network

        Args:
            transaction (bytes or str): serialized, signed transaction

        Returns:
            str: The transaction ID
        """
        if isinstance(transaction, bytes):
            signed_hex = bytes_to_str(transaction)
        elif isinstance(transaction, Transaction):
            signed_hex = bytes_to_str(bytes(transaction))
        elif isinstance(transaction, str):
            signed_hex = transaction
        else:
            raise TypeError(
                "transaction must be one of: bytes, str, Transaction.")

        data = {"signed_hex": signed_hex}
        response_body = self._request("POST", "transactions/send", data=data).json()
        return response_body["transaction_hash"]
Exemple #16
0
    def broadcast_transaction(self, transaction):
        """ Broadcasts a transaction to the Bitcoin network

        Args:
            transaction (bytes or str): serialized, signed transaction

        Returns:
            str: The transaction ID
        """
        if isinstance(transaction, bytes):
            signed_hex = bytes_to_str(transaction)
        elif isinstance(transaction, Transaction):
            signed_hex = bytes_to_str(bytes(transaction))
        elif isinstance(transaction, str):
            signed_hex = transaction
        else:
            raise TypeError(
                "transaction must be one of: bytes, str, Transaction.")

        data = {"signed_hex": signed_hex}
        response_body = self._request("POST", "transactions/send",
                                      data=data).json()
        return response_body["transaction_hash"]
    def __str__(self):
        """ Creates a human-readable string representation of the script.

        Returns:
            s (str): String representation of the script
        """
        script = ""
        self._check_tokenized()
        for t in self._tokens:
            if isinstance(t, bytes):
                script += "0x%s " % bytes_to_str(t)
            else:
                script += t + " "

        return script.rstrip()
Exemple #18
0
    def __str__(self):
        """ Creates a human-readable string representation of the script.

        Returns:
            s (str): String representation of the script
        """
        script = ""
        self._check_tokenized()
        for t in self._tokens:
            if isinstance(t, bytes):
                script += "0x%s " % bytes_to_str(t)
            else:
                script += t + " "

        return script.rstrip()
def test_multisig():
    # This test-case taken from:
    # https://gist.github.com/gavinandresen/3966071
    pubkeys = [
        "0491bba2510912a5bd37da1fb5b1673010e43d2c6d812c514e91bfa9f2eb129e1c183329db55bd868e209aac2fbc02cb33d98fe74bf23f0c235d6126b1d8334f86",  # nopep8
        "04865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac09ef122b1a986818a7cb624532f062c1d1f8722084861c5c3291ccffef4ec6874",  # nopep8
        "048d2455d2403e08708fc1f556002f1b6cd83f992d085097f9974ab08a28838f07896fbab08f39495e15fa6fad6edbfb1e754e35fa1c7844c41f322a1863d46213"]  # nopep8

    serialized_pubkeys = [bytes.fromhex(p) for p in pubkeys]

    redeem_script = Script.build_multisig_redeem(2, serialized_pubkeys)

    assert bytes_to_str(bytes(redeem_script)) == "52410491bba2510912a5bd37da1fb5b1673010e43d2c6d812c514e91bfa9f2eb129e1c183329db55bd868e209aac2fbc02cb33d98fe74bf23f0c235d6126b1d8334f864104865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac09ef122b1a986818a7cb624532f062c1d1f8722084861c5c3291ccffef4ec687441048d2455d2403e08708fc1f556002f1b6cd83f992d085097f9974ab08a28838f07896fbab08f39495e15fa6fad6edbfb1e754e35fa1c7844c41f322a1863d4621353ae"  # nopep8

    assert redeem_script.is_multisig_redeem()

    # Get the address of the redeem script
    assert redeem_script.address(True).startswith("2")
    address = redeem_script.address()
    assert address == "3QJmV3qfvL9SuYo34YihAf3sRCW3qSinyC"
Exemple #20
0
def test_txn_serialization(txns_json):
    ''' txn_json: a JSON dict from api.chain.com that also contains
                 the raw hex of the transaction in the 'hex' key
    '''
    for txn_json in txns_json:
        txn = txn_from_json(txn_json)
        txn_bytes = bytes(txn)
        txn_hash = txn.hash

        try:
            assert txn.num_inputs == len(txn_json['inputs'])
            assert txn.num_outputs == len(txn_json['outputs'])
            assert str(txn_hash) == txn_json['hash'], \
                "Hash does not match for txn: %s\nCorrect bytes:\n%s\nConstructed bytes:\n%s\nJSON:\n%s" % (
                    txn_json['hash'],
                    txn_json['hex'],
                    bytes_to_str(txn_bytes),
                    txn_json)
        except AssertionError as e:
            print(e)
            raise
Exemple #21
0
def test_txn_serialization(txns_json):
    ''' txn_json: a JSON dict from api.chain.com that also contains
                 the raw hex of the transaction in the 'hex' key
    '''
    for txn_json in txns_json:
        txn = txn_from_json(txn_json)
        txn_bytes = bytes(txn)
        txn_hash = txn.hash

        try:
            assert txn.num_inputs == len(txn_json['inputs'])
            assert txn.num_outputs == len(txn_json['outputs'])
            assert str(txn_hash) == txn_json['hash'], \
                "Hash does not match for txn: %s\nCorrect bytes:\n%s\nConstructed bytes:\n%s\nJSON:\n%s" % (
                    txn_json['hash'],
                    txn_json['hex'],
                    bytes_to_str(txn_bytes),
                    txn_json)
        except AssertionError as e:
            print(e)
            raise
Exemple #22
0
def test_multisig_sign():
    # This test case taken from:
    # https://github.com/libbitcoin/libbitcoin-explorer/wiki/How-to-Spend-From-a-Multisig-Address

    unsigned_hex = "01000000010506344de69d47e432eb0174500d6e188a9e63c1e84a9e8796ec98c99b7559f70100000000ffffffff01c8af0000000000001976a91458b7a60f11a904feef35a639b6048de8dd4d9f1c88ac00000000"  # nopep8

    tx = txn.Transaction.from_hex(unsigned_hex)

    pub_keys_hex = [
        "02b66fcb1064d827094685264aaa90d0126861688932eafbd1d1a4ba149de3308b",
        "025cab5e31095551582630f168280a38eb3a62b0b3e230b20f8807fc5463ccca3c",
        "021098babedb3408e9ac2984adcf2a8e4c48e56a785065893f76d0fa0ff507f010"
    ]
    pub_keys = [bytes.fromhex(p) for p in pub_keys_hex]
    redeem_script = script.Script.build_multisig_redeem(2, pub_keys)
    script.Script.build_p2sh(
        bytes.fromhex("5c406de4915e37a7e71c7ef9bff42fbf1404daa0"))

    priv_keys_hex = [
        "0x9d695afea1c3ab99e11248e4b74e698332b11f5c5c051e6e80da61aa19ae7c89",
        "0x68ebab45a918444d7e088c49bda76d7df89b9ea6ba5ddeb1aab5945391828b83"
    ]
    priv_keys = [crypto.PrivateKey.from_int(int(p, 0)) for p in priv_keys_hex]

    # Now sign the input with the first private key
    tx.sign_input(input_index=0,
                  hash_type=txn.Transaction.SIG_HASH_ALL,
                  private_key=priv_keys[0],
                  sub_script=redeem_script)

    # Check the sig script
    assert utils.bytes_to_str(
        tx.inputs[0].script.ast[1]
    ) == "30440220695a28c42daa23c13e192e36a20d03a2a79994e0fe1c3c6b612d0ae23743064602200ca19003e7c1ce0cecb0bbfba9a825fc3b83cf54e4c3261cd15f080d24a8a5b901"  # nopep8

    # Now sign with the second private key
    tx.sign_input(input_index=0,
                  hash_type=txn.Transaction.SIG_HASH_ALL,
                  private_key=priv_keys[1],
                  sub_script=redeem_script)

    assert utils.bytes_to_str(
        tx.inputs[0].script.ast[2]
    ) == "3045022100aa9096ce71995c24545694f20ab0482099a98c99b799c706c333c521e51db66002206578f023fa46f4a863a6fa7f18b95eebd1a91fcdf6ce714e8795d902bd6b682b01"  # nopep8

    # Now make sure the entire serialized txn is correct
    assert tx.to_hex(
    ) == "01000000010506344de69d47e432eb0174500d6e188a9e63c1e84a9e8796ec98c99b7559f701000000fdfd00004730440220695a28c42daa23c13e192e36a20d03a2a79994e0fe1c3c6b612d0ae23743064602200ca19003e7c1ce0cecb0bbfba9a825fc3b83cf54e4c3261cd15f080d24a8a5b901483045022100aa9096ce71995c24545694f20ab0482099a98c99b799c706c333c521e51db66002206578f023fa46f4a863a6fa7f18b95eebd1a91fcdf6ce714e8795d902bd6b682b014c69522102b66fcb1064d827094685264aaa90d0126861688932eafbd1d1a4ba149de3308b21025cab5e31095551582630f168280a38eb3a62b0b3e230b20f8807fc5463ccca3c21021098babedb3408e9ac2984adcf2a8e4c48e56a785065893f76d0fa0ff507f01053aeffffffff01c8af0000000000001976a91458b7a60f11a904feef35a639b6048de8dd4d9f1c88ac00000000"  # nopep8

    script_pub_key = script.Script.build_p2sh(redeem_script.hash160())
    assert tx.verify_input_signature(0, script_pub_key)

    assert not tx.verify_input_signature(0, redeem_script)

    wrong_script_pub_key = script.Script(
        "OP_HASH160 0x5c406de4915e37a7e71c7ef9bff42fbf1404daa1 OP_EQUAL")
    assert not tx.verify_input_signature(0, wrong_script_pub_key)

    # Test not enough signatures
    tx = txn.Transaction.from_hex(unsigned_hex)

    # Sign the input with only the first private key
    tx.sign_input(input_index=0,
                  hash_type=txn.Transaction.SIG_HASH_ALL,
                  private_key=priv_keys[0],
                  sub_script=redeem_script)

    assert not tx.verify_input_signature(0, script_pub_key)

    # Try doing it with the 2nd private key but not the first
    tx = txn.Transaction.from_hex(unsigned_hex)
    tx.sign_input(input_index=0,
                  hash_type=txn.Transaction.SIG_HASH_ALL,
                  private_key=priv_keys[1],
                  sub_script=redeem_script)

    assert not tx.verify_input_signature(0, script_pub_key)

    # Now try doing the sigs in reverse order
    tx = txn.Transaction.from_hex(unsigned_hex)
    tx.sign_input(input_index=0,
                  hash_type=txn.Transaction.SIG_HASH_ALL,
                  private_key=priv_keys[1],
                  sub_script=redeem_script)
    tx.sign_input(input_index=0,
                  hash_type=txn.Transaction.SIG_HASH_ALL,
                  private_key=priv_keys[0],
                  sub_script=redeem_script)

    # This should still work
    assert tx.verify_input_signature(0, script_pub_key)
    # The partial should also work
    assert tx.verify_partial_multisig(0, script_pub_key)

    # Now hack the txn bytes to have the sigs in reverse order.
    # This should fail.
    txn_hex = "01000000010506344de69d47e432eb0174500d6e188a9e63c1e84a9e8796ec98c99b7559f701000000fdfd0000483045022100aa9096ce71995c24545694f20ab0482099a98c99b799c706c333c521e51db66002206578f023fa46f4a863a6fa7f18b95eebd1a91fcdf6ce714e8795d902bd6b682b014730440220695a28c42daa23c13e192e36a20d03a2a79994e0fe1c3c6b612d0ae23743064602200ca19003e7c1ce0cecb0bbfba9a825fc3b83cf54e4c3261cd15f080d24a8a5b9014c69522102b66fcb1064d827094685264aaa90d0126861688932eafbd1d1a4ba149de3308b21025cab5e31095551582630f168280a38eb3a62b0b3e230b20f8807fc5463ccca3c21021098babedb3408e9ac2984adcf2a8e4c48e56a785065893f76d0fa0ff507f01053aeffffffff01c8af0000000000001976a91458b7a60f11a904feef35a639b6048de8dd4d9f1c88ac00000000"  # nopep8

    tx = txn.Transaction.from_hex(txn_hex)

    assert not tx.verify_input_signature(0, script_pub_key)

    # Test a partially signed txn
    txn_hex = "0100000001124f2e9522043794a438bfa44dd161b8976af246e4850948f85a2b50c113611a000000009200483045022100ec2e3fd3e116eb25644f055ba7945d940f828b39060d4a93c7d2b6d3cbd9d41802203c9f1ad2208122e1ffcbeba09d37a596ae5ce445be465b9417481f66ab804b070147522102395a983fd92e55200fbde624f62cda10f8d0adf8261506e5c983cfe92326c5aa2102bb70b001d807721e74d96bda71d225dc6c09fe8d541d260258145b42afac93e152ae0000000001a0860100000000001976a914e205124b0e25dc77e2b29b2e57c2f56ed10771eb88ac095635ac"  # nopep8

    tx = txn.Transaction.from_hex(txn_hex)

    sig_info = tx.inputs[0].script.extract_multisig_sig_info()
    script_pub_key = script.Script.build_p2sh(
        sig_info['redeem_script'].hash160())
    assert not tx.verify_input_signature(0, script_pub_key)

    assert tx.verify_partial_multisig(0, script_pub_key)
Exemple #23
0
 def to_hex(self, compressed=True):
     if compressed:
         return bytes_to_str(self.compressed_bytes)
     else:
         return bytes_to_str(bytes(self))
Exemple #24
0
else:
    for arg in sys.argv:
        if arg == 'USD':
            rate = Price(wallet.balance())._get_usd_rate()
            print(rate)
        elif ':' in arg:
            address = arg.split(':')[1].strip()
            btc_amount = float(arg.split(':')[2].strip())
            sat_amount = convert_to_satoshis(btc_amount)
            txs = wallet.send_to(address, sat_amount)
            tx = txs[0]
            obj = {}
            obj['txid'] = tx['txid']
            obj['hex'] = tx['txn'].to_hex()

            print(json.dumps({'tx': obj}))
        elif '>' in arg:
            commands = arg.split('>')
            result = None
            for command in commands:
                toCallOn = result or wallet
                methodToCall = getattr(toCallOn, command)
                result = methodToCall()

            if isinstance(result, bytes):
                print(json.dumps({'data': bytes_to_str(result)}))
            else:
                print(json.dumps({'data': result}))
        else:
            execute(arg)
Exemple #25
0
from pywallet.utils import HDPrivateKey, HDKey
from two1.bitcoin.utils import bytes_to_str

from service.api.ethereum.utils import normalize_key, ecsign
from service.settings import RELAY_ACCOUNT_PHRASE

master_key = HDPrivateKey.master_key_from_mnemonic(RELAY_ACCOUNT_PHRASE)
root_key = HDKey.from_path(master_key, "m/44'/60'/0'/0/0")
sender = root_key[-1].public_key.address()
signing_key = bytes_to_str(bytes(root_key[-1])[-32:])
normalized_key = normalize_key(signing_key)


def sign(hash):
    return ecsign(hash, normalized_key)
Exemple #26
0
 def __str__(self):
     """ Returns a hex string in RPC order
     """
     return bytes_to_str(self._bytes[::-1])
Exemple #27
0
 def __str__(self):
     """ Returns a hex string in RPC order
     """
     return bytes_to_str(self._bytes[::-1])
Exemple #28
0
def test_rest():
    m = mock_provider
    m.hd_master_key = master
    m.reset_mocks()

    m.set_num_used_accounts(1)
    m.set_num_used_addresses(account_index=0, n=1, change=0)
    m.set_num_used_addresses(account_index=0, n=2, change=1)

    m.set_txn_side_effect_for_hd_discovery()

    wallet = Two1Wallet(params_or_file=config,
                        data_provider=m,
                        passphrase=passphrase)

    # First 5 internal addresses of account 0
    # These can be gotten from https://dcpos.github.io/bip39/
    ext_addrs = ["1Kv1QLXekeE42rKhvZ41kHS1auE7R3t21o",
                 "1CYhVFaBwmTQRQwdyLc4rq9HwaxdqtQ68G",
                 "18KCKKB5MGs4Rqu4t8jL9Bkt9SAp7NpUvm",
                 "1FqUrpUpqWfHoPVga4uMKYCPHHoApvNiPa",
                 "12zb1hJP5WEHCSKz5LyoPM9iaCwXtTthRc"]

    int_addrs = ["1Hiv6LroFmqcaVV9rhY6eNUjnFQh4y6kL7",
                 "1GTUuNbgk4sv7LPQd2WqSP9PiinzeuBmay",
                 "14fpkEZZ6QP3QEcQnfSjH7adkC2RsMuiZw",
                 "1LPNyqqX6RU5b4oPumePR72tFfwiNUho4s",
                 "1FqvNKJb8au82PhtGP8D1odXWVC1Ae4jN9"]

    bad_addrs = ["1CEDwjjtYjCQUoRZQW9RUXHH5Ao7PWYKf",
                 "1CbHFUNsyCzZSDu7hYae7HHqgzMjBfqoP9"]

    paths = wallet.find_addresses(int_addrs + ext_addrs + bad_addrs)

    assert len(paths.keys()) == 10

    for i in range(5):
        # Hardened account key derivation, thus 0x80000000
        assert paths[ext_addrs[i]] == (0x80000000, 0, i)
        assert paths[int_addrs[i]] == (0x80000000, 1, i)

        # Check address belongs
        assert wallet.address_belongs(ext_addrs[i]) == "m/44'/0'/0'/0/%d" % i
        assert wallet.address_belongs(int_addrs[i]) == "m/44'/0'/0'/1/%d" % i

    for b in bad_addrs:
        assert b not in paths
        assert wallet.address_belongs(b) is None

    # Check that there's an account name
    assert wallet.get_account_name(0) == "default"

    # Check the balance
    assert wallet.balances == {'confirmed': 10000, 'total': 20000}

    # Check that we can get a new payout address
    ext_addr = wallet.get_payout_address("default")
    assert ext_addr == ext_addrs[1]
    assert wallet.accounts[0].last_indices[0] == 0

    # Check the balance again - should be the same
    m.set_num_used_addresses(0, 1, 0)
    assert wallet.balances == {'confirmed': 10000, 'total': 20000}

    # Try sending below the dust limit
    with pytest.raises(ValueError):
        wallet.send_to(address="14ocdLGpBp7Yv3gsPDszishSJUv3cpLqUM",
                       amount=544)

    # Try sending a non-integer amount (mistaken user tries to send in btc
    # instead of satoshi)
    with pytest.raises(exceptions.SatoshiUnitsError):
        wallet.send_to(address="14ocdLGpBp7Yv3gsPDszishSJUv3cpLqUM",
                       amount=0.0001)

    # Try sending more than we have and make sure it raises an exception
    with pytest.raises(exceptions.WalletBalanceError):
        wallet.send_to(address="14ocdLGpBp7Yv3gsPDszishSJUv3cpLqUM",
                       amount=1000000)

    # Should still fail when using unconfirmed if amount is greater
    # than unconfirmed balance
    with pytest.raises(exceptions.WalletBalanceError):
        wallet.send_to(address="14ocdLGpBp7Yv3gsPDszishSJUv3cpLqUM",
                       use_unconfirmed=True,
                       amount=1000000)

    # Should fail when not using unconfirmed txns and
    # confirmed < amount < unconfirmed.
    with pytest.raises(exceptions.WalletBalanceError):
        wallet.send_to(address="14ocdLGpBp7Yv3gsPDszishSJUv3cpLqUM",
                       use_unconfirmed=False,
                       amount=15000)

    # Should get past checking balance but raise a NotImplementedError
    with pytest.raises(NotImplementedError):
        wallet.send_to(
            address="14ocdLGpBp7Yv3gsPDszishSJUv3cpLqUM",
            use_unconfirmed=False,
            amount=7700)

    # Should get past checking balance but raise a signing error
    with pytest.raises(NotImplementedError):
        wallet.send_to(
            address="14ocdLGpBp7Yv3gsPDszishSJUv3cpLqUM",
            use_unconfirmed=True,
            amount=12581)

    # test number of addresses in spread_utxos
    with pytest.raises(ValueError):
        wallet.spread_utxos(
            threshold=500000,
            num_addresses=0,
            accounts=[])
    with pytest.raises(ValueError):
        wallet.spread_utxos(
            threshold=500000,
            num_addresses=101,
            accounts=[])

    # test units for spread_utxos
    with pytest.raises(exceptions.SatoshiUnitsError):
        wallet.spread_utxos(
            threshold=0.0001,
            num_addresses=1,
            accounts=[])

    # Finally check storing to a file
    params = {}
    with tempfile.NamedTemporaryFile(delete=True) as tf:
        wallet.to_file(tf)

        # Read it back
        tf.seek(0, 0)
        params = json.loads(tf.read().decode('utf-8'))

        # Check that the params match expected
        assert params['master_key'] == config['master_key']
        assert params['master_seed'] == config['master_seed']
        assert params['locked']
        assert params['key_salt'] == bytes_to_str(enc_key_salt)
        assert params['passphrase_hash'] == passphrase_hash
        assert params['account_type'] == "BIP44BitcoinMainnet"
        assert params['account_map']['default'] == 0
        assert len(params['accounts']) == 1
        assert params['accounts'][0]['last_payout_index'] == 0
        assert params['accounts'][0]['last_change_index'] == 1
        assert params['accounts'][0]['public_key'] == config['accounts'][0]['public_key']

        # Now create the wallet from the file
        with pytest.raises(exceptions.PassphraseError):
            w2 = Two1Wallet(params_or_file=tf.name,
                            data_provider=m,
                            passphrase='wrong_pass')

        # Now do with the correct passphrase
        m.set_txn_side_effect_for_hd_discovery()
        w2 = Two1Wallet(params_or_file=tf.name,
                        data_provider=m,
                        passphrase=passphrase)

        assert len(w2.accounts) == 1
        assert not w2._testnet

        acct = w2.accounts[0]
        assert acct.last_indices[0] == 0
        assert acct.last_indices[1] == 1
def test_rest():
    m = mock_provider
    m.hd_master_key = master
    m.reset_mocks()

    m.set_num_used_accounts(1)
    m.set_num_used_addresses(account_index=0, n=1, change=0)
    m.set_num_used_addresses(account_index=0, n=2, change=1)

    m.set_txn_side_effect_for_hd_discovery()

    wallet = Two1Wallet(params_or_file=config,
                        data_provider=m,
                        passphrase=passphrase)

    # First 5 internal addresses of account 0
    # These can be gotten from https://dcpos.github.io/bip39/
    ext_addrs = [
        "1Kv1QLXekeE42rKhvZ41kHS1auE7R3t21o",
        "1CYhVFaBwmTQRQwdyLc4rq9HwaxdqtQ68G",
        "18KCKKB5MGs4Rqu4t8jL9Bkt9SAp7NpUvm",
        "1FqUrpUpqWfHoPVga4uMKYCPHHoApvNiPa",
        "12zb1hJP5WEHCSKz5LyoPM9iaCwXtTthRc"
    ]

    int_addrs = [
        "1Hiv6LroFmqcaVV9rhY6eNUjnFQh4y6kL7",
        "1GTUuNbgk4sv7LPQd2WqSP9PiinzeuBmay",
        "14fpkEZZ6QP3QEcQnfSjH7adkC2RsMuiZw",
        "1LPNyqqX6RU5b4oPumePR72tFfwiNUho4s",
        "1FqvNKJb8au82PhtGP8D1odXWVC1Ae4jN9"
    ]

    bad_addrs = [
        "1CEDwjjtYjCQUoRZQW9RUXHH5Ao7PWYKf",
        "1CbHFUNsyCzZSDu7hYae7HHqgzMjBfqoP9"
    ]

    paths = wallet.find_addresses(int_addrs + ext_addrs + bad_addrs)

    assert len(paths.keys()) == 10

    for i in range(5):
        # Hardened account key derivation, thus 0x80000000
        assert paths[ext_addrs[i]] == (0x80000000, 0, i)
        assert paths[int_addrs[i]] == (0x80000000, 1, i)

        # Check address belongs
        assert wallet.address_belongs(ext_addrs[i]) == "m/44'/0'/0'/0/%d" % i
        assert wallet.address_belongs(int_addrs[i]) == "m/44'/0'/0'/1/%d" % i

    for b in bad_addrs:
        assert b not in paths
        assert wallet.address_belongs(b) is None

    # Check that there's an account name
    assert wallet.get_account_name(0) == "default"

    # Check the balance
    assert wallet.balances == {'confirmed': 100000, 'total': 200000}

    # Check that we can get a new payout address
    ext_addr = wallet.get_payout_address("default")
    assert ext_addr == ext_addrs[1]
    assert wallet.accounts[0].last_indices[0] == 0

    # Check the balance again - should be the same
    m.set_num_used_addresses(0, 1, 0)
    assert wallet.balances == {'confirmed': 100000, 'total': 200000}

    # Try sending below the dust limit
    with pytest.raises(ValueError):
        wallet.send_to(address="14ocdLGpBp7Yv3gsPDszishSJUv3cpLqUM",
                       amount=544)

    # Try sending a non-integer amount (mistaken user tries to send in btc
    # instead of satoshi)
    with pytest.raises(exceptions.SatoshiUnitsError):
        wallet.send_to(address="14ocdLGpBp7Yv3gsPDszishSJUv3cpLqUM",
                       amount=0.0001)

    # Try sending more than we have and make sure it raises an exception
    with pytest.raises(exceptions.WalletBalanceError):
        wallet.send_to(address="14ocdLGpBp7Yv3gsPDszishSJUv3cpLqUM",
                       amount=10000000)

    # Should still fail when using unconfirmed if amount is greater
    # than unconfirmed balance
    with pytest.raises(exceptions.WalletBalanceError):
        wallet.send_to(address="14ocdLGpBp7Yv3gsPDszishSJUv3cpLqUM",
                       use_unconfirmed=True,
                       amount=10000000)

    # Should fail when not using unconfirmed txns and
    # confirmed < amount < unconfirmed.
    with pytest.raises(exceptions.WalletBalanceError):
        wallet.send_to(address="14ocdLGpBp7Yv3gsPDszishSJUv3cpLqUM",
                       use_unconfirmed=False,
                       amount=150000)

    # Should get past checking balance but raise a NotImplementedError
    with pytest.raises(NotImplementedError):
        wallet.send_to(address="14ocdLGpBp7Yv3gsPDszishSJUv3cpLqUM",
                       use_unconfirmed=False,
                       amount=7700)

    # Should get past checking balance but raise a signing error
    with pytest.raises(NotImplementedError):
        wallet.send_to(address="14ocdLGpBp7Yv3gsPDszishSJUv3cpLqUM",
                       use_unconfirmed=True,
                       amount=12581)

    # test number of addresses in spread_utxos
    with pytest.raises(ValueError):
        wallet.spread_utxos(threshold=500000, num_addresses=0, accounts=[])
    with pytest.raises(ValueError):
        wallet.spread_utxos(threshold=500000, num_addresses=101, accounts=[])

    # test units for spread_utxos
    with pytest.raises(exceptions.SatoshiUnitsError):
        wallet.spread_utxos(threshold=0.0001, num_addresses=1, accounts=[])

    # Finally check storing to a file
    params = {}
    with tempfile.NamedTemporaryFile(delete=True) as tf:
        wallet.to_file(tf)

        # Read it back
        tf.seek(0, 0)
        params = json.loads(tf.read().decode('utf-8'))

        # Check that the params match expected
        assert params['master_key'] == config['master_key']
        assert params['master_seed'] == config['master_seed']
        assert params['locked']
        assert params['key_salt'] == bytes_to_str(enc_key_salt)
        assert params['passphrase_hash'] == passphrase_hash
        assert params['account_type'] == "BIP44BitcoinMainnet"
        assert params['account_map']['default'] == 0
        assert len(params['accounts']) == 1
        assert params['accounts'][0]['last_payout_index'] == 0
        assert params['accounts'][0]['last_change_index'] == 1
        assert params['accounts'][0]['public_key'] == config['accounts'][0][
            'public_key']

        # Now create the wallet from the file
        with pytest.raises(exceptions.PassphraseError):
            w2 = Two1Wallet(params_or_file=tf.name,
                            data_provider=m,
                            passphrase='wrong_pass')

        # Now do with the correct passphrase
        m.set_txn_side_effect_for_hd_discovery()
        w2 = Two1Wallet(params_or_file=tf.name,
                        data_provider=m,
                        passphrase=passphrase)

        assert len(w2.accounts) == 1
        assert not w2._testnet

        acct = w2.accounts[0]
        assert acct.last_indices[0] == 0
        assert acct.last_indices[1] == 1
import requests
import json
import time
from two1.bitcoin.utils import bytes_to_str
from pywallet.utils import HDPrivateKey, HDKey
from web3 import Web3

mnemonic = os.environ['MNEMONIC']
infura_key = os.environ['INFURA_KEY']

w3 = Web3(Web3.HTTPProvider('https://rinkeby.infura.io/v3/' + infura_key))

master_key = HDPrivateKey.master_key_from_mnemonic(mnemonic)
root_key = HDKey.from_path(master_key, "m/44'/60'/0'/0/0")
sender_address = w3.toChecksumAddress(root_key[-1].public_key.address())
private_key = bytes_to_str(bytes(root_key[-1])[-32:])
DAI_BASE_VALUE = 1000000000000000000


class Call:
    def __init__(self, method, params):
        self.method = method
        self.params = params


class State:
    def __init__(self):
        self.safes = {}
        self.last_module_block = "0x4ca0b0"
        self.last_top_up_block = "0x4ca0b0"
Exemple #31
0
passphrase = "test_wallet"
passphrase_hash = PBKDF2.crypt(passphrase)

master_key = "xprv9s21ZrQH143K2dUcTctuNw8oV8e7gi4ZbHFGAnyGJtWwmKbKTbLGtx48DQGzioGDdhVn8zFhJe8hbDdfDnK19ykxjwXLzd6EpxnTqi4zQGN"  # nopep8
master_seed = "tuna object element cancel hard nose faculty noble swear net subway offer"

mkey_enc, mseed_enc = Two1Wallet.encrypt(master_key=master_key,
                                         master_seed=master_seed,
                                         passphrase=passphrase,
                                         key_salt=enc_key_salt)

config = {'master_key': mkey_enc,
          'master_seed': mseed_enc,
          'locked': True,
          'passphrase_hash': passphrase_hash,
          'key_salt': bytes_to_str(enc_key_salt),
          'account_type': "BIP44BitcoinMainnet",
          'accounts': [{'public_key': "xpub6CNX3TRAXGpoV1a3ai3Hs9R85t63V3k6BGsTaxZZMJJ4DL6kRY8riYA1r6hxyeuxgeb33FfBgrJrV6wxv6VXEVHAfPGJNw8ZzbEJHgsbmpz",  # nopep8
                        'last_payout_index': 2,
                        'last_change_index': 1}],
          'account_map': {'default': 0}}

master = HDPrivateKey.master_key_from_mnemonic(master_seed, passphrase)
mock_provider = MockProvider("BIP44BitcoinMainnet", master)


def test_encrypt_decrypt():
    mkey_enc, mseed_enc = Two1Wallet.encrypt(master_key=config['master_key'],
                                             master_seed=config['master_seed'],
                                             passphrase=passphrase,
                                             key_salt=enc_key_salt)
Exemple #32
0
 def to_hex(self):
     return bytes_to_str(bytes(self))
mkey_enc, mseed_enc = Two1Wallet.encrypt(master_key=master_key,
                                         master_seed=master_seed,
                                         passphrase=passphrase,
                                         key_salt=enc_key_salt)

config = {
    'master_key':
    mkey_enc,
    'master_seed':
    mseed_enc,
    'locked':
    True,
    'passphrase_hash':
    passphrase_hash,
    'key_salt':
    bytes_to_str(enc_key_salt),
    'account_type':
    "BIP44BitcoinMainnet",
    'accounts': [{
        'public_key':
        "xpub6CNX3TRAXGpoV1a3ai3Hs9R85t63V3k6BGsTaxZZMJJ4DL6kRY8riYA1r6hxyeuxgeb33FfBgrJrV6wxv6VXEVHAfPGJNw8ZzbEJHgsbmpz",  # nopep8
        'last_payout_index': 2,
        'last_change_index': 1
    }],
    'account_map': {
        'default': 0
    }
}

master = HDPrivateKey.master_key_from_mnemonic(master_seed, passphrase)
mock_provider = MockProvider("BIP44BitcoinMainnet", master)
Exemple #34
0
def test_multisig_sign():
    # This test case taken from:
    # https://github.com/libbitcoin/libbitcoin-explorer/wiki/How-to-Spend-From-a-Multisig-Address

    unsigned_hex = "01000000010506344de69d47e432eb0174500d6e188a9e63c1e84a9e8796ec98c99b7559f70100000000ffffffff01c8af0000000000001976a91458b7a60f11a904feef35a639b6048de8dd4d9f1c88ac00000000"  # nopep8

    tx = txn.Transaction.from_hex(unsigned_hex)

    pub_keys_hex = ["02b66fcb1064d827094685264aaa90d0126861688932eafbd1d1a4ba149de3308b",
                    "025cab5e31095551582630f168280a38eb3a62b0b3e230b20f8807fc5463ccca3c",
                    "021098babedb3408e9ac2984adcf2a8e4c48e56a785065893f76d0fa0ff507f010"]
    pub_keys = [bytes.fromhex(p) for p in pub_keys_hex]
    redeem_script = script.Script.build_multisig_redeem(2, pub_keys)
    script.Script.build_p2sh(
        bytes.fromhex("5c406de4915e37a7e71c7ef9bff42fbf1404daa0"))

    priv_keys_hex = ["0x9d695afea1c3ab99e11248e4b74e698332b11f5c5c051e6e80da61aa19ae7c89",
                     "0x68ebab45a918444d7e088c49bda76d7df89b9ea6ba5ddeb1aab5945391828b83"]
    priv_keys = [crypto.PrivateKey.from_int(int(p, 0))
                 for p in priv_keys_hex]

    # Now sign the input with the first private key
    tx.sign_input(input_index=0,
                  hash_type=txn.Transaction.SIG_HASH_ALL,
                  private_key=priv_keys[0],
                  sub_script=redeem_script)

    # Check the sig script
    assert utils.bytes_to_str(tx.inputs[0].script.ast[1]) == "30440220695a28c42daa23c13e192e36a20d03a2a79994e0fe1c3c6b612d0ae23743064602200ca19003e7c1ce0cecb0bbfba9a825fc3b83cf54e4c3261cd15f080d24a8a5b901"  # nopep8

    # Now sign with the second private key
    tx.sign_input(input_index=0,
                  hash_type=txn.Transaction.SIG_HASH_ALL,
                  private_key=priv_keys[1],
                  sub_script=redeem_script)

    assert utils.bytes_to_str(tx.inputs[0].script.ast[2]) == "3045022100aa9096ce71995c24545694f20ab0482099a98c99b799c706c333c521e51db66002206578f023fa46f4a863a6fa7f18b95eebd1a91fcdf6ce714e8795d902bd6b682b01"  # nopep8

    # Now make sure the entire serialized txn is correct
    assert tx.to_hex() == "01000000010506344de69d47e432eb0174500d6e188a9e63c1e84a9e8796ec98c99b7559f701000000fdfd00004730440220695a28c42daa23c13e192e36a20d03a2a79994e0fe1c3c6b612d0ae23743064602200ca19003e7c1ce0cecb0bbfba9a825fc3b83cf54e4c3261cd15f080d24a8a5b901483045022100aa9096ce71995c24545694f20ab0482099a98c99b799c706c333c521e51db66002206578f023fa46f4a863a6fa7f18b95eebd1a91fcdf6ce714e8795d902bd6b682b014c69522102b66fcb1064d827094685264aaa90d0126861688932eafbd1d1a4ba149de3308b21025cab5e31095551582630f168280a38eb3a62b0b3e230b20f8807fc5463ccca3c21021098babedb3408e9ac2984adcf2a8e4c48e56a785065893f76d0fa0ff507f01053aeffffffff01c8af0000000000001976a91458b7a60f11a904feef35a639b6048de8dd4d9f1c88ac00000000"  # nopep8

    script_pub_key = script.Script.build_p2sh(redeem_script.hash160())
    assert tx.verify_input_signature(0, script_pub_key)

    assert not tx.verify_input_signature(0, redeem_script)

    wrong_script_pub_key = script.Script(
        "OP_HASH160 0x5c406de4915e37a7e71c7ef9bff42fbf1404daa1 OP_EQUAL")
    assert not tx.verify_input_signature(0, wrong_script_pub_key)

    # Test not enough signatures
    tx = txn.Transaction.from_hex(unsigned_hex)

    # Sign the input with only the first private key
    tx.sign_input(input_index=0,
                  hash_type=txn.Transaction.SIG_HASH_ALL,
                  private_key=priv_keys[0],
                  sub_script=redeem_script)

    assert not tx.verify_input_signature(0, script_pub_key)

    # Try doing it with the 2nd private key but not the first
    tx = txn.Transaction.from_hex(unsigned_hex)
    tx.sign_input(input_index=0,
                  hash_type=txn.Transaction.SIG_HASH_ALL,
                  private_key=priv_keys[1],
                  sub_script=redeem_script)

    assert not tx.verify_input_signature(0, script_pub_key)

    # Now try doing the sigs in reverse order
    tx = txn.Transaction.from_hex(unsigned_hex)
    tx.sign_input(input_index=0,
                  hash_type=txn.Transaction.SIG_HASH_ALL,
                  private_key=priv_keys[1],
                  sub_script=redeem_script)
    tx.sign_input(input_index=0,
                  hash_type=txn.Transaction.SIG_HASH_ALL,
                  private_key=priv_keys[0],
                  sub_script=redeem_script)

    # This should still work
    assert tx.verify_input_signature(0, script_pub_key)
    # The partial should also work
    assert tx.verify_partial_multisig(0, script_pub_key)

    # Now hack the txn bytes to have the sigs in reverse order.
    # This should fail.
    txn_hex = "01000000010506344de69d47e432eb0174500d6e188a9e63c1e84a9e8796ec98c99b7559f701000000fdfd0000483045022100aa9096ce71995c24545694f20ab0482099a98c99b799c706c333c521e51db66002206578f023fa46f4a863a6fa7f18b95eebd1a91fcdf6ce714e8795d902bd6b682b014730440220695a28c42daa23c13e192e36a20d03a2a79994e0fe1c3c6b612d0ae23743064602200ca19003e7c1ce0cecb0bbfba9a825fc3b83cf54e4c3261cd15f080d24a8a5b9014c69522102b66fcb1064d827094685264aaa90d0126861688932eafbd1d1a4ba149de3308b21025cab5e31095551582630f168280a38eb3a62b0b3e230b20f8807fc5463ccca3c21021098babedb3408e9ac2984adcf2a8e4c48e56a785065893f76d0fa0ff507f01053aeffffffff01c8af0000000000001976a91458b7a60f11a904feef35a639b6048de8dd4d9f1c88ac00000000"  # nopep8

    tx = txn.Transaction.from_hex(txn_hex)

    assert not tx.verify_input_signature(0, script_pub_key)

    # Test a partially signed txn
    txn_hex = "0100000001124f2e9522043794a438bfa44dd161b8976af246e4850948f85a2b50c113611a000000009200483045022100ec2e3fd3e116eb25644f055ba7945d940f828b39060d4a93c7d2b6d3cbd9d41802203c9f1ad2208122e1ffcbeba09d37a596ae5ce445be465b9417481f66ab804b070147522102395a983fd92e55200fbde624f62cda10f8d0adf8261506e5c983cfe92326c5aa2102bb70b001d807721e74d96bda71d225dc6c09fe8d541d260258145b42afac93e152ae0000000001a0860100000000001976a914e205124b0e25dc77e2b29b2e57c2f56ed10771eb88ac095635ac"  # nopep8

    tx = txn.Transaction.from_hex(txn_hex)

    sig_info = tx.inputs[0].script.extract_multisig_sig_info()
    script_pub_key = script.Script.build_p2sh(sig_info['redeem_script'].hash160())
    assert not tx.verify_input_signature(0, script_pub_key)

    assert tx.verify_partial_multisig(0, script_pub_key)