Esempio n. 1
0
    def create_payment_tx(self, deposit_tx, redeem_script, merchant_public_key,
                          customer_public_key, amount, fee):
        # Find P2SH output index in deposit_tx
        deposit_utxo_index = deposit_tx.output_index_for_address(
            redeem_script.hash160())

        # Look up deposit amount
        deposit_amount = deposit_tx.outputs[deposit_utxo_index].value - fee

        # Build unsigned payment transaction
        script_sig = Script()
        inp = TransactionInput(deposit_tx.hash, deposit_utxo_index, script_sig,
                               0xffffffff)
        out1 = TransactionOutput(
            amount, Script.build_p2pkh(merchant_public_key.hash160()))
        out2 = TransactionOutput(
            deposit_amount - amount,
            Script.build_p2pkh(customer_public_key.hash160()))
        payment_tx = Transaction(1, [inp], [out1, out2], 0x0)

        # Sign payment transaction
        public_key = redeem_script.customer_public_key
        private_key = self.get_private_for_public(public_key)
        sig = payment_tx.get_signature_for_input(0, Transaction.SIG_HASH_ALL,
                                                 private_key, redeem_script)[0]

        # Update input script sig
        script_sig = Script([
            sig.to_der() + utils.pack_compact_int(Transaction.SIG_HASH_ALL),
            'OP_1',
            bytes(redeem_script)
        ])
        payment_tx.inputs[0].script = script_sig

        return payment_tx
Esempio n. 2
0
    def create_payment_tx(self, deposit_tx, redeem_script, merchant_public_key,
                          customer_public_key, amount, fee):
        # Find P2SH output index in deposit_tx
        deposit_utxo_index = deposit_tx.output_index_for_address(redeem_script.hash160())

        # Look up deposit amount
        deposit_amount = deposit_tx.outputs[deposit_utxo_index].value - fee

        # Build unsigned payment transaction
        script_sig = Script()
        inp = TransactionInput(deposit_tx.hash, deposit_utxo_index, script_sig, 0xffffffff)
        out1 = TransactionOutput(amount, Script.build_p2pkh(merchant_public_key.hash160()))
        out2 = TransactionOutput(deposit_amount - amount, Script.build_p2pkh(customer_public_key.hash160()))
        payment_tx = Transaction(1, [inp], [out1, out2], 0x0)

        # Sign payment transaction
        public_key = redeem_script.customer_public_key
        private_key = self.get_private_for_public(public_key)
        sig = payment_tx.get_signature_for_input(0, Transaction.SIG_HASH_ALL, private_key, redeem_script)[0]

        # Update input script sig
        script_sig = Script(
            [sig.to_der() + utils.pack_compact_int(Transaction.SIG_HASH_ALL), 'OP_1', bytes(redeem_script)])
        payment_tx.inputs[0].script = script_sig

        return payment_tx
Esempio n. 3
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
Esempio n. 4
0
 def create_deposit_tx(self, hash160):
     """Return a mocked deposit transaction."""
     utxo_script_sig = Script.build_p2pkh(self._private_key.public_key.hash160())
     inp = TransactionInput(
         outpoint=Hash('0' * 64), outpoint_index=0, script=utxo_script_sig, sequence_num=0xffffffff)
     out = TransactionOutput(value=120000, script=Script.build_p2sh(hash160))
     txn = Transaction(version=Transaction.DEFAULT_TRANSACTION_VERSION, inputs=[inp], outputs=[out], lock_time=0)
     txn.sign_input(
         input_index=0, hash_type=Transaction.SIG_HASH_ALL, private_key=self._private_key,
         sub_script=utxo_script_sig)
     return txn
Esempio n. 5
0
 def create_deposit_tx(self, hash160):
     """Return a mocked deposit transaction."""
     utxo_script_sig = Script.build_p2pkh(
         self._private_key.public_key.hash160())
     inp = TransactionInput(outpoint=Hash('0' * 64),
                            outpoint_index=0,
                            script=utxo_script_sig,
                            sequence_num=0xffffffff)
     out = TransactionOutput(value=120000,
                             script=Script.build_p2sh(hash160))
     txn = Transaction(version=Transaction.DEFAULT_TRANSACTION_VERSION,
                       inputs=[inp],
                       outputs=[out],
                       lock_time=0)
     txn.sign_input(input_index=0,
                    hash_type=Transaction.SIG_HASH_ALL,
                    private_key=self._private_key,
                    sub_script=utxo_script_sig)
     return txn
Esempio n. 6
0
    def receive_payment(self, deposit_txid, payment_tx):
        """Receive and process a payment within the channel.

        The customer makes a payment in the channel by sending the merchant a
        half-signed payment transaction. The merchant signs the other half of
        the transaction and saves it in its records (but does not broadcast it
        or send it to the customer). The merchant responds with 200 to verify
        that the payment was handled successfully.

        Args:
            deposit_txid (string): string representation of the deposit
                transaction hash. This is used to look up the payment channel.
            payment_tx (string): half-signed payment transaction from a
                customer.
        Returns:
            (string): payment transaction id
        """
        # Parse payment channel `payment` parameters
        payment_tx = Transaction.from_hex(payment_tx)

        # Get channel and addresses related to the deposit
        channel = self._db.pc.lookup(deposit_txid)

        if not channel:
            raise PaymentChannelNotFoundError('Related channel not found.')

        # Get merchant public key information from payment channel
        redeem_script = PaymentChannelRedeemScript.from_bytes(
            payment_tx.inputs[0].script[-1])
        merch_pubkey = redeem_script.merchant_public_key

        # Verify that the payment has a valid signature from the customer
        txn_copy = payment_tx._copy_for_sig(0, Transaction.SIG_HASH_ALL,
                                            redeem_script)
        msg_to_sign = bytes(
            Hash.dhash(bytes(txn_copy) + pack_u32(Transaction.SIG_HASH_ALL)))
        sig = Signature.from_der(payment_tx.inputs[0].script[0][:-1])
        if not redeem_script.customer_public_key.verify(
                msg_to_sign, sig, False):
            raise BadTransactionError('Invalid payment signature.')

        # Verify the length of the script is what we expect
        if len(payment_tx.inputs[0].script) != 3:
            raise BadTransactionError(
                'Invalid payment channel transaction structure.')

        # Verify the script template is valid for accepting a merchant signature
        if (not Script.validate_template(payment_tx.inputs[0].script,
                                         [bytes, 'OP_1', bytes])
                and not Script.validate_template(payment_tx.inputs[0].script,
                                                 [bytes, 'OP_TRUE', bytes])):
            raise BadTransactionError(
                'Invalid payment channel transaction structure.')

        # Verify that the payment channel is ready
        if channel.state == ChannelSQLite3.CONFIRMING:
            confirmed = self._blockchain.check_confirmed(channel.deposit_txid)
            if confirmed:
                self._db.pc.update_state(channel.deposit_txid,
                                         ChannelSQLite3.READY)
            else:
                raise ChannelClosedError('Payment channel not ready.')
        elif channel.state == ChannelSQLite3.CLOSED:
            raise ChannelClosedError('Payment channel closed.')

        # Verify that payment is made to the merchant's pubkey
        index = payment_tx.output_index_for_address(merch_pubkey.hash160())
        if index is None:
            raise BadTransactionError('Payment must pay to merchant pubkey.')

        # Verify that both payments are not below the dust limit
        for output_index, output in enumerate(payment_tx.outputs):
            if output.value < PaymentServer.DUST_LIMIT:
                # Payment to merchant is less than dust limit
                if output_index == index:
                    raise BadTransactionError(
                        'Initial payment must be greater than {}.'.format(
                            PaymentServer.DUST_LIMIT))
                # Payment to customer is less than dust limit
                else:
                    raise BadTransactionError(
                        'Payment channel balance is not large enough to make payment.'
                    )

        # Validate that the payment is more than the last one
        new_pmt_amt = payment_tx.outputs[index].value
        if new_pmt_amt <= channel.last_payment_amount:
            raise BadTransactionError('Payment must be greater than 0.')

        # Verify that the transaction has adequate fees
        net_pmt_amount = sum([d.value for d in payment_tx.outputs])
        deposit_amount = channel.amount
        if deposit_amount < net_pmt_amount + PaymentServer.MIN_TX_FEE:
            raise BadTransactionError('Payment must have adequate fees.')

        # Update the current payment transaction
        self._db.pc.update_payment(deposit_txid, payment_tx, new_pmt_amt)
        self._db.pmt.create(deposit_txid, payment_tx,
                            new_pmt_amt - channel.last_payment_amount)

        return str(payment_tx.hash)
Esempio n. 7
0
    def receive_payment(self, deposit_txid, payment_tx):
        """Receive and process a payment within the channel.

        The customer makes a payment in the channel by sending the merchant a
        half-signed payment transaction. The merchant signs the other half of
        the transaction and saves it in its records (but does not broadcast it
        or send it to the customer). The merchant responds with 200 to verify
        that the payment was handled successfully.

        Args:
            deposit_txid (string): string representation of the deposit
                transaction hash. This is used to look up the payment channel.
            payment_tx (string): half-signed payment transaction from a
                customer.
        Returns:
            (string): payment transaction id
        """
        # Parse payment channel `payment` parameters
        payment_tx = Transaction.from_hex(payment_tx)

        # Get channel and addresses related to the deposit
        channel = self._db.pc.lookup(deposit_txid)

        if not channel:
            raise PaymentChannelNotFoundError('Related channel not found.')

        # Get merchant public key information from payment channel
        merchant_public_key = PublicKey.from_hex(channel.merchant_pubkey)

        # Verify that redeem script contains the merchant public key
        redeem_script = PaymentChannelRedeemScript.from_bytes(payment_tx.inputs[0].script[-1])
        if redeem_script.merchant_public_key.to_hex() != merchant_public_key.to_hex():
            raise BadTransactionError('Invalid merchant pubkey.')

        # Verify that the payment has a valid signature from the customer
        txn_copy = payment_tx._copy_for_sig(0, Transaction.SIG_HASH_ALL, redeem_script)
        msg_to_sign = bytes(Hash.dhash(bytes(txn_copy) + pack_u32(Transaction.SIG_HASH_ALL)))
        sig = Signature.from_der(payment_tx.inputs[0].script[0][:-1])
        if not redeem_script.customer_public_key.verify(msg_to_sign, sig, False):
            raise BadTransactionError('Invalid payment signature.')

        # Verify the length of the script is what we expect
        if len(payment_tx.inputs[0].script) != 3:
            raise BadTransactionError('Invalid payment channel transaction structure.')

        # Verify the script template is valid for accepting a merchant signature
        if (not Script.validate_template(payment_tx.inputs[0].script, [bytes, 'OP_1', bytes]) and
                not Script.validate_template(payment_tx.inputs[0].script, [bytes, 'OP_TRUE', bytes])):
            raise BadTransactionError('Invalid payment channel transaction structure.')

        # Verify that the payment channel is ready
        if channel.state == ChannelSQLite3.CONFIRMING:
            confirmed = self._blockchain.check_confirmed(channel.deposit_txid)
            if confirmed:
                self._db.pc.update_state(channel.deposit_txid, ChannelSQLite3.READY)
            else:
                raise ChannelClosedError('Payment channel not ready.')
        elif channel.state == ChannelSQLite3.CLOSED:
            raise ChannelClosedError('Payment channel closed.')

        # Verify that payment is made to the merchant public key
        index = payment_tx.output_index_for_address(merchant_public_key.hash160())
        if index is None:
            raise BadTransactionError('Payment must pay to merchant pubkey.')

        # Verify that both payments are not below the dust limit
        for output_index, output in enumerate(payment_tx.outputs):
            if output.value < PaymentServer.DUST_LIMIT:
                # Payment to merchant is less than dust limit
                if output_index == index:
                    raise BadTransactionError(
                        'Initial payment must be greater than {}.'.format(PaymentServer.DUST_LIMIT))
                # Payment to customer is less than dust limit
                else:
                    raise BadTransactionError(
                        'Payment channel balance is not large enough to make payment.')

        # Validate that the payment is more than the last one
        new_pmt_amt = payment_tx.outputs[index].value
        if new_pmt_amt <= channel.last_payment_amount:
            raise BadTransactionError('Payment must be greater than 0.')

        # Verify that the transaction has adequate fees
        net_pmt_amount = sum([d.value for d in payment_tx.outputs])
        deposit_amount = channel.amount
        fee = deposit_amount - net_pmt_amount
        if fee < PaymentServer.MIN_TX_FEE:
            raise BadTransactionError('Payment must have adequate fees.')

        # Recreate redeem script from merchant side
        redeem_script_copy = PaymentChannelRedeemScript(
            merchant_public_key,
            redeem_script.customer_public_key,
            channel.expires_at)
        if redeem_script.to_hex() != redeem_script_copy.to_hex():
            raise BadTransactionError('Invalid redeem script.')

        # Recreate customer payment from merchant side
        payment_tx_copy = self._wallet.create_unsigned_payment_tx(
            channel.deposit_tx, redeem_script, new_pmt_amt, fee)

        # Recreate signed input script using signature from customer
        hash_type = pack_compact_int(Transaction.SIG_HASH_ALL)
        signed_input_script = Script(
            [sig.to_der() + hash_type, "OP_1", bytes(redeem_script)])
        payment_tx_copy.inputs[0].script = signed_input_script

        if payment_tx.to_hex() != payment_tx_copy.to_hex():
            raise BadTransactionError('Invalid payment channel transaction structure.')

        # Update the current payment transaction
        self._db.pc.update_payment(deposit_txid, payment_tx_copy, new_pmt_amt)
        self._db.pmt.create(deposit_txid, payment_tx_copy, new_pmt_amt - channel.last_payment_amount)

        return str(payment_tx_copy.hash)
Esempio n. 8
0
def test_channel_sync(monkeypatch):
    """Test ability to sync the status of all channels."""
    channel_server._db = DatabaseSQLite3(':memory:', db_dir='')

    # Seed the database with activity in Channel A
    test_client_a = _create_client_txs()
    deposit_txid_a = channel_server.open(test_client_a.deposit_tx,
                                         test_client_a.redeem_script)
    payment_txid = channel_server.receive_payment(deposit_txid_a,
                                                  test_client_a.payment_tx)
    amount = channel_server.redeem(payment_txid)
    assert amount == TEST_PMT_AMOUNT

    # Seed the database with activity in Channel B
    cust_wallet._private_key = PrivateKey.from_random()
    test_client_b = _create_client_txs()
    deposit_txid_b = channel_server.open(test_client_b.deposit_tx,
                                         test_client_b.redeem_script)
    payment_txid = channel_server.receive_payment(deposit_txid_b,
                                                  test_client_b.payment_tx)
    amount = channel_server.redeem(payment_txid)
    payment_tx1 = _create_client_payment(test_client_b, 2)
    payment_tx2 = _create_client_payment(test_client_b, 3)
    payment_tx3 = _create_client_payment(test_client_b, 4)
    payment_txid1 = channel_server.receive_payment(deposit_txid_b, payment_tx1)
    payment_txid2 = channel_server.receive_payment(deposit_txid_b, payment_tx2)
    payment_txid3 = channel_server.receive_payment(deposit_txid_b, payment_tx3)
    amount1 = channel_server.redeem(payment_txid1)
    amount2 = channel_server.redeem(payment_txid3)
    amount3 = channel_server.redeem(payment_txid2)
    assert amount1 == TEST_PMT_AMOUNT
    assert amount2 == TEST_PMT_AMOUNT
    assert amount3 == TEST_PMT_AMOUNT

    # Both channels should be `ready` since our channel is zeroconf by default
    channels = channel_server._db.pc.lookup()
    assert channels, 'Channel lookup with no args should return a list of all channels.'
    for channel in channels:
        assert channel.state == ChannelSQLite3.READY, 'Channel should be READY.'

    # Change Channel A to `confirming` for testing purposes
    channel_server._db.pc.update_state(deposit_txid_a,
                                       ChannelSQLite3.CONFIRMING)
    test_state = channel_server._db.pc.lookup(deposit_txid_a).state
    assert test_state == ChannelSQLite3.CONFIRMING, 'Channel should be CONFIRMING'

    # Change Channel B's expiration to be very close to allowable expiration
    new_expiry = int(time.time() + 3600)
    update = 'UPDATE payment_channel SET expires_at=? WHERE deposit_txid=?'
    channel_server._db.pc.c.execute(update, (new_expiry, deposit_txid_b))
    channel_server._db.pc.c.connection.commit()
    test_expiry = channel_server._db.pc.lookup(deposit_txid_b).expires_at
    assert test_expiry == new_expiry, 'Channel should closing soon.'

    # Sync all of the server's payment channels
    channel_server.sync()

    # Test that Channel A is `ready` after a sync
    test_state = channel_server._db.pc.lookup(deposit_txid_a).state
    assert test_state == ChannelSQLite3.READY, 'Channel should be READY'

    # Test that Channel B is `closed` after a sync
    test_state = channel_server._db.pc.lookup(deposit_txid_b).state
    assert test_state == ChannelSQLite3.CLOSED, 'Channel should be CLOSED'

    # Test that Channel B payment is fully signed after a sync
    test_payment = channel_server._db.pc.lookup(deposit_txid_b).payment_tx
    goodsig_1 = Script.validate_template(test_payment.inputs[0].script,
                                         [bytes, bytes, 'OP_1', bytes])
    goodsig_true = Script.validate_template(test_payment.inputs[0].script,
                                            [bytes, bytes, 'OP_TRUE', bytes])
    assert goodsig_1 or goodsig_true, 'Payment should be in a fully signed format'

    # Test that Channel A remains `ready` after another sync
    channel_server.sync()
    test_state = channel_server._db.pc.lookup(deposit_txid_a).state
    assert test_state == ChannelSQLite3.READY, 'Channel should be READY'

    # Modify `lookup_spend_txid` to return a txid, as if the tx were spent
    monkeypatch.setattr(MockBlockchain, 'lookup_spend_txid',
                        mock_lookup_spent_txid)

    # Test that Channel A is `closed` after a sync where it finds a spent txid
    channel_server.sync()
    test_state = channel_server._db.pc.lookup(deposit_txid_a).state
    assert test_state == ChannelSQLite3.CLOSED, 'Channel should be CLOSED'
Esempio n. 9
0
def test_channel_sync(monkeypatch):
    """Test ability to sync the status of all channels."""
    channel_server._db = DatabaseSQLite3(':memory:', db_dir='')

    # Seed the database with activity in Channel A
    test_client_a = _create_client_txs()
    deposit_txid_a = channel_server.open(test_client_a.deposit_tx, test_client_a.redeem_script)
    payment_txid = channel_server.receive_payment(deposit_txid_a, test_client_a.payment_tx)
    amount = channel_server.redeem(payment_txid)
    assert amount == TEST_PMT_AMOUNT

    # Seed the database with activity in Channel B
    cust_wallet._private_key = PrivateKey.from_random()
    test_client_b = _create_client_txs()
    deposit_txid_b = channel_server.open(test_client_b.deposit_tx, test_client_b.redeem_script)
    payment_txid = channel_server.receive_payment(deposit_txid_b, test_client_b.payment_tx)
    amount = channel_server.redeem(payment_txid)
    payment_tx1 = _create_client_payment(test_client_b, 2)
    payment_tx2 = _create_client_payment(test_client_b, 3)
    payment_tx3 = _create_client_payment(test_client_b, 4)
    payment_txid1 = channel_server.receive_payment(deposit_txid_b, payment_tx1)
    payment_txid2 = channel_server.receive_payment(deposit_txid_b, payment_tx2)
    payment_txid3 = channel_server.receive_payment(deposit_txid_b, payment_tx3)
    amount1 = channel_server.redeem(payment_txid1)
    amount2 = channel_server.redeem(payment_txid3)
    amount3 = channel_server.redeem(payment_txid2)
    assert amount1 == TEST_PMT_AMOUNT
    assert amount2 == TEST_PMT_AMOUNT
    assert amount3 == TEST_PMT_AMOUNT

    # Both channels should be `ready` since our channel is zeroconf by default
    channels = channel_server._db.pc.lookup()
    assert channels, 'Channel lookup with no args should return a list of all channels.'
    for channel in channels:
        assert channel.state == ChannelSQLite3.READY, 'Channel should be READY.'

    # Change Channel A to `confirming` for testing purposes
    channel_server._db.pc.update_state(deposit_txid_a, ChannelSQLite3.CONFIRMING)
    test_state = channel_server._db.pc.lookup(deposit_txid_a).state
    assert test_state == ChannelSQLite3.CONFIRMING, 'Channel should be CONFIRMING'

    # Change Channel B's expiration to be very close to allowable expiration
    new_expiry = int(time.time() + 3600)
    update = 'UPDATE payment_channel SET expires_at=? WHERE deposit_txid=?'
    channel_server._db.pc.c.execute(update, (new_expiry, deposit_txid_b))
    channel_server._db.pc.c.connection.commit()
    test_expiry = channel_server._db.pc.lookup(deposit_txid_b).expires_at
    assert test_expiry == new_expiry, 'Channel should closing soon.'

    # Sync all of the server's payment channels
    channel_server.sync()

    # Test that Channel A is `ready` after a sync
    test_state = channel_server._db.pc.lookup(deposit_txid_a).state
    assert test_state == ChannelSQLite3.READY, 'Channel should be READY'

    # Test that Channel B is `closed` after a sync
    test_state = channel_server._db.pc.lookup(deposit_txid_b).state
    assert test_state == ChannelSQLite3.CLOSED, 'Channel should be CLOSED'

    # Test that Channel B payment is fully signed after a sync
    test_payment = channel_server._db.pc.lookup(deposit_txid_b).payment_tx
    goodsig_1 = Script.validate_template(test_payment.inputs[0].script, [bytes, bytes, 'OP_1', bytes])
    goodsig_true = Script.validate_template(test_payment.inputs[0].script, [bytes, bytes, 'OP_TRUE', bytes])
    assert goodsig_1 or goodsig_true, 'Payment should be in a fully signed format'

    # Test that Channel A remains `ready` after another sync
    channel_server.sync()
    test_state = channel_server._db.pc.lookup(deposit_txid_a).state
    assert test_state == ChannelSQLite3.READY, 'Channel should be READY'

    # Modify `lookup_spend_txid` to return a txid, as if the tx were spent
    monkeypatch.setattr(MockBlockchain, 'lookup_spend_txid', mock_lookup_spent_txid)

    # Test that Channel A is `closed` after a sync where it finds a spent txid
    channel_server.sync()
    test_state = channel_server._db.pc.lookup(deposit_txid_a).state
    assert test_state == ChannelSQLite3.CLOSED, 'Channel should be CLOSED'
Esempio n. 10
0
    def receive_payment(self, deposit_txid, payment_tx):
        """Receive and process a payment within the channel.

        The customer makes a payment in the channel by sending the merchant a
        half-signed payment transaction. The merchant signs the other half of
        the transaction and saves it in its records (but does not broadcast it
        or send it to the customer). The merchant responds with 200 to verify
        that the payment was handled successfully.

        Args:
            deposit_txid (string): string representation of the deposit
                transaction hash. This is used to look up the payment channel.
            payment_tx (string): half-signed payment transaction from a
                customer.
        Returns:
            (string): payment transaction id
        """
        with self.lock:
            # Parse payment channel `payment` parameters
            payment_tx = Transaction.from_hex(payment_tx)

            # Get channel and addresses related to the deposit
            channel = self._db.pc.lookup(deposit_txid)

            if not channel:
                raise PaymentChannelNotFoundError('Related channel not found.')

            # Get merchant public key information from payment channel
            redeem_script = PaymentChannelRedeemScript.from_bytes(payment_tx.inputs[0].script[-1])
            merch_pubkey = redeem_script.merchant_public_key

            # Verify that the payment has a valid signature from the customer
            txn_copy = payment_tx._copy_for_sig(0, Transaction.SIG_HASH_ALL, redeem_script)
            msg_to_sign = bytes(Hash.dhash(bytes(txn_copy) + pack_u32(Transaction.SIG_HASH_ALL)))
            sig = Signature.from_der(payment_tx.inputs[0].script[0][:-1])
            if not redeem_script.customer_public_key.verify(msg_to_sign, sig, False):
                raise BadTransactionError('Invalid payment signature.')

            # Verify the length of the script is what we expect
            if len(payment_tx.inputs[0].script) != 3:
                raise BadTransactionError('Invalid payment channel transaction structure.')

            # Verify the script template is valid for accepting a merchant signature
            if (not Script.validate_template(payment_tx.inputs[0].script, [bytes, 'OP_1', bytes]) and
                    not Script.validate_template(payment_tx.inputs[0].script, [bytes, 'OP_TRUE', bytes])):
                raise BadTransactionError('Invalid payment channel transaction structure.')

            # Verify that the payment channel is ready
            if channel.state == ChannelSQLite3.CONFIRMING:
                raise ChannelClosedError('Payment channel not ready.')
            elif channel.state == ChannelSQLite3.CLOSED:
                raise ChannelClosedError('Payment channel closed.')

            # Verify that payment is made to the merchant's pubkey
            index = payment_tx.output_index_for_address(merch_pubkey.hash160())
            if index is None:
                raise BadTransactionError('Payment must pay to merchant pubkey.')

            # Verify that both payments are not below the dust limit
            if any(p.value < PaymentServer.DUST_LIMIT for p in payment_tx.outputs):
                raise BadTransactionError(
                    'Final payment must have outputs greater than {}.'.format(PaymentServer.DUST_LIMIT))

            # Validate that the payment is more than the last one
            new_pmt_amt = payment_tx.outputs[index].value
            if new_pmt_amt <= channel.last_payment_amount:
                raise BadTransactionError('Payment must be greater than 0.')

            # Verify that the transaction has adequate fees
            net_pmt_amount = sum([d.value for d in payment_tx.outputs])
            deposit_amount = channel.amount
            if deposit_amount < net_pmt_amount + PaymentServer.MIN_TX_FEE:
                raise BadTransactionError('Payment must have adequate fees.')

            # Update the current payment transaction
            self._db.pc.update_payment(deposit_txid, payment_tx, new_pmt_amt)
            self._db.pmt.create(deposit_txid, payment_tx, new_pmt_amt - channel.last_payment_amount)

            return str(payment_tx.hash)