Beispiel #1
0
    def handle_partner_response(self):
        """

        :return: response to send to peer
        """
        # local variables
        need_update_balance = False

        # handle the resign body firstly
        resign_ack = None
        resign_trade = None
        if self.resign_body:
            resign_ack, resign_trade = self.handle_resign_body(
                self.wallet, self.channel_name, self.resign_body)

            # here if the peer not provide the signature, we need re-calculate the balance based on resign trade
            if not (self.commitment and self.delay_commitment):
                _, self.sender_balance, self.receiver_balance = self.calculate_balance_after_payment(
                    resign_trade.balance,
                    resign_trade.peer_balance,
                    self.payment,
                    is_htlc_type=True)

        # to check whether the negotiated nonce is legal or not
        self.validate_negotiated_nonce()

        # create htlc response message
        htlc_sign_body = self.response(self.sender_balance,
                                       self.receiver_balance, self.payment,
                                       self.hashcode, 1, self.delay_block)

        # get some common local variables
        sign_hashcode, sign_rcode = self.get_default_rcode()
        payer_balance = int(self.sender_balance)
        payee_balance = int(self.receiver_balance)
        payment = int(self.payment)

        # use this nonce for following message of current transaction
        nonce = self.nego_nonce or self.nonce

        # special case when nego-nonce is setting
        if nonce != self.nonce:
            # get previous record
            old_trade = Channel.query_trade(self.channel_name, self.nonce)

            # generate the htlc trade
            htlc_trade = Channel.htlc_trade(
                type=EnumTradeType.TRADE_TYPE_HTLC,
                role=EnumTradeRole.TRADE_ROLE_FOUNDER,
                asset_type=self.asset_type,
                balance=payer_balance,
                peer_balance=payee_balance,
                payment=payment,
                hashcode=self.hashcode,
                delay_block=old_trade.delay_block,
                channel=old_trade.channel)
            #
            # Update the trade or add new one
            self.record_transaction(nonce, **htlc_trade)

            # delete old one
            if nonce < self.nonce:
                Channel.delete_trade(self.channel_name, self.nonce)

        # Get current transaction record
        current_trade = Channel.query_trade(self.channel_name, nonce)
        if current_trade.commitment and current_trade.delay_commitment:
            # it means the htlc has already signed before.
            commitment = current_trade.commitment
            delay_commitment = current_trade.delay_commitment
        else:
            # start to sign this new transaction and save it
            # check balance
            self.check_balance(self.channel_name,
                               self.asset_type,
                               self.payer_address,
                               payer_balance,
                               self.payee_address,
                               payee_balance,
                               is_htcl_type=True,
                               payment=payment)

            # sign the transaction with 2 parts: rsmc and htlc-locked part
            commitment = self.sign_content(
                self.wallet, RsmcMessage._sign_type_list, [
                    self.channel_name, nonce, self.payer_address,
                    payer_balance, self.payee_address, payee_balance,
                    sign_hashcode, sign_rcode
                ])

            delay_commitment = self.sign_content(
                self.wallet,
                self._sign_type_list, [
                    self.channel_name, self.payer_address, self.payee_address,
                    int(self.delay_block),
                    int(payment), self.hashcode
                ],
                start=5)

            # update the transaction info
            Channel.update_trade(self.channel_name,
                                 nonce,
                                 commitment=commitment,
                                 delay_commitment=delay_commitment)

        # peer has already sign the new transaction with nonce
        if self.commitment and self.delay_commitment:
            # check the signature of rsmc part
            self.check_signature(self.wallet,
                                 self.sender_address,
                                 type_list=RsmcMessage._sign_type_list,
                                 value_list=[
                                     self.channel_name, nonce,
                                     self.payer_address,
                                     int(self.sender_balance),
                                     self.payee_address,
                                     int(self.receiver_balance), sign_hashcode,
                                     sign_rcode
                                 ],
                                 signature=self.commitment)

            # check signature of htlc-lock part
            self.check_signature(self.wallet,
                                 self.sender_address,
                                 type_list=self._sign_type_list,
                                 value_list=[
                                     self.channel_name, self.payer_address,
                                     self.payee_address,
                                     int(self.delay_block),
                                     int(payment), self.hashcode
                                 ],
                                 signature=self.delay_commitment)

            # update this trade confirmed state
            Channel.update_trade(self.channel_name,
                                 nonce,
                                 commitment=commitment,
                                 delay_commitment=delay_commitment,
                                 peer_commitment=self.commitment,
                                 peer_delay_commitment=self.delay_commitment,
                                 state=EnumTradeState.confirming.name)
            need_update_balance = True

            htlc_sign_body.update({
                'Commitment': commitment,
                'DelayCommitment': delay_commitment
            })

        # has resign response ??
        if resign_ack:
            htlc_sign_body.update({'ResignBody': resign_ack})

        return need_update_balance, htlc_sign_body
Beispiel #2
0
    def create(cls,
               channel_name,
               asset_type,
               sender,
               receiver,
               payment,
               hashcode,
               router,
               current_channel=None,
               comments=None):
        """

        :param channel_name:
        :param asset_type:
        :param sender:
        :param receiver:
        :param payment:
        :param hashcode:
        :param router:
        :param current_channel:
        :param comments:
        :return:
        """
        cls.check_channel_state(channel_name)
        cls.check_router(router, hashcode)
        cls.check_asset_type(asset_type)
        cls.check_both_urls(sender, receiver)

        payer_address, _, _ = uri_parser(sender)
        payee_address, _, _ = uri_parser(receiver)
        asset_type = asset_type.upper()
        channel = Channel(channel_name)

        # get nonce
        nonce = Channel.new_nonce(channel_name)
        if HtlcMessage._FOUNDER_NONCE > nonce:
            raise GoTo(
                EnumResponseStatus.RESPONSE_TRADE_WITH_INCORRECT_NONCE,
                'HtlcMessage::create: Incorrect nonce<{}> for channel<{}>'.
                format(nonce, channel_name))

        # to check whether previous transaction need be resigned or not
        resign_body, valid_trade = HtlcMessage.create_resign_message_body(
            sender, channel_name, nonce)

        # there're one trade need resign, we need adjust the nonce value
        if valid_trade and valid_trade.state in [
                EnumTradeState.confirming.name
        ]:
            payer_balance = valid_trade.balance
            payee_balance = valid_trade.peer_balance
        else:
            # to get channel balance
            balance = channel.balance
            payer_balance = balance.get(payer_address).get(asset_type)
            payee_balance = balance.get(payee_address).get(asset_type)

        # To calculate the balance after payment
        _, payer_balance, payee_balance = HtlcMessage.calculate_balance_after_payment(
            payer_balance, payee_balance, payment, is_htlc_type=True)

        # exclude current router from the router
        end_block_height = cls.get_unlocked_block_height(len(router))

        # generate htlc transaction and record it into database later
        htlc_trade = Channel.htlc_trade(type=EnumTradeType.TRADE_TYPE_HTLC,
                                        role=EnumTradeRole.TRADE_ROLE_FOUNDER,
                                        asset_type=asset_type,
                                        balance=payer_balance,
                                        peer_balance=payee_balance,
                                        payment=payment,
                                        hashcode=hashcode,
                                        delay_block=end_block_height)

        # record the channel if RResponse is triggered
        if current_channel:
            htlc_trade.update({'channel': current_channel})

        # create message
        htlc_request = HtlcMessage.request(payer_balance, payee_balance,
                                           payment, hashcode, end_block_height)
        # has transaction which is needed to be resigned
        if resign_body:
            htlc_request.update({'ResignBody': resign_body})

        # start to create message  and send later
        message = HtlcMessage.create_message_header(sender, receiver,
                                                    HtlcMessage._message_name,
                                                    channel_name, asset_type,
                                                    nonce)
        message.update({'Router': router})
        message.update({'MessageBody': htlc_request})

        if comments:
            message.update({'Comments': comments})

        HtlcMessage.send(message)

        # record the transaction
        Channel.add_trade(channel_name, nonce=nonce, **htlc_trade)

        return None
Beispiel #3
0
    def create(cls,
               wallet,
               channel_name,
               asset_type,
               tx_nonce,
               sender,
               receiver,
               payment,
               sender_balance,
               receiver_balance,
               hashcode,
               delay_block,
               peer_commitment,
               peer_hlock_commitment,
               router,
               next_router,
               comments=None):
        """

        :param wallet:
        :param channel_name:
        :param asset_type:
        :param tx_nonce:
        :param sender:
        :param receiver:
        :param payment:
        :param sender_balance:
        :param receiver_balance:
        :param hashcode:
        :param delay_block:
        :param peer_commitment:
        :param peer_hlock_commitment:
        :param router:
        :param next_router:
        :param comments:
        :return:
        """
        # get nonce from latest trade
        _, nonce = HtlcResponsesMessage.check_nonce(tx_nonce, channel_name)

        # start to verify balance
        payer_address, _, _ = uri_parser(sender)
        payee_address, _, _ = uri_parser(receiver)
        asset_type = asset_type.upper()

        # check balance
        _, payer_balance, payee_balance = HtlcResponsesMessage.check_balance(
            channel_name,
            asset_type,
            payer_address,
            sender_balance,
            payee_address,
            receiver_balance,
            is_htcl_type=True,
            payment=payment)

        # 2 parts in htlc message: conclusive and inconclusive part
        sign_hashcode, sign_rcode = cls.get_default_rcode()
        rsmc_commitment = HtlcResponsesMessage.sign_content(
            typeList=RsmcMessage._sign_type_list,
            valueList=[
                channel_name, nonce, payer_address, payer_balance,
                payee_address, payee_balance, sign_hashcode, sign_rcode
            ],
            privtKey=wallet._key.private_key_string)

        hlock_commitment = HtlcResponsesMessage.sign_content(
            start=5,
            typeList=HtlcResponsesMessage._sign_type_list,
            valueList=[
                channel_name, payer_address, payee_address, delay_block,
                int(payment), hashcode
            ],
            privtKey=wallet._key.private_key_string)

        # # ToDo: need re-sign all unconfirmed htlc message later
        htlc_trade = Channel.htlc_trade(
            type=EnumTradeType.TRADE_TYPE_HTLC,
            role=EnumTradeRole.TRADE_ROLE_PARTNER,
            asset_type=asset_type,
            balance=payee_balance,
            peer_balance=payer_balance,
            payment=payment,
            hashcode=hashcode,
            delay_block=delay_block,
            commitment=rsmc_commitment,
            peer_commitment=peer_commitment,
            delay_commitment=hlock_commitment,
            peer_delay_commitment=peer_hlock_commitment,
            channel=channel_name)
        Channel.add_trade(channel_name, nonce=nonce, **htlc_trade)

        # create message
        message = HtlcResponsesMessage.create_message_header(
            receiver, sender, HtlcResponsesMessage._message_name, channel_name,
            asset_type, tx_nonce)
        message = message.message_header
        message.update({
            'Router': router,
            'Next': next_router,
        })
        message_body = {
            'SenderBalance': payer_balance,
            'ReceiverBalance': payee_balance,
            'Commitment': rsmc_commitment,
            'Payment': payment,
            'DelayBlock': delay_block,
            'DelayCommitment': hlock_commitment,
            'HashR': hashcode
        }

        # orgnize the message
        message.update({'MessageBody': message_body})
        message.update({'Status': EnumResponseStatus.RESPONSE_OK.name})
        if comments:
            message.update({'Comments': comments})

        # Before the response ok, we could update the channel balance
        HtlcResponsesMessage.update_balance_for_channel(channel_name,
                                                        asset_type,
                                                        payer_address,
                                                        payee_address,
                                                        payment,
                                                        is_htlc_type=True)

        # send response ok message to peer
        HtlcResponsesMessage.send(message)

        return
Beispiel #4
0
    def handle(self):
        super(HtlcMessage, self).handle()

        status = EnumResponseStatus.RESPONSE_OK
        resign_ack = None
        resign_request = None
        nonce = None
        try:
            # common check
            self.check_channel_state(self.channel_name)
            self.check_router(self.router, self.hashcode)
            self.verify()

            # resign request by peer ??
            if self.resign_body:
                resign_ack, nego_trade = self.handle_resign_body(
                    self.wallet, self.channel_name, self.resign_body)
            else:
                # check whether need resign previous transaction
                resign_request, nego_trade = self.create_resign_message_body(
                    self.wallet.url, self.channel_name, self.nonce)

            # real nonce
            nego_nonce = nego_trade and (nego_trade.nonce + 1)
            nonce = nego_nonce or self.nonce

            # some local variables to save later
            htlc_sign_body = self.response(self.sender_balance,
                                           self.receiver_balance, self.payment,
                                           self.hashcode, self.htlc_sign_role,
                                           self.delay_block)
            htlc_trade = Channel.htlc_trade(
                type=EnumTradeType.TRADE_TYPE_HTLC,
                role=EnumTradeRole.TRADE_ROLE_PARTNER,
                asset_type=self.asset_type,
                balance=self.receiver_balance,
                peer_balance=self.sender_balance,
                payment=self.payment,
                hashcode=self.hashcode,
                delay_block=self.delay_block,
                channel=self.channel_name)

            # if need resign, just send resign message body
            sign_hashcode, sign_rcode = self.get_default_rcode()
            if resign_request:
                # add resign body to response body
                htlc_sign_body.update({'ResignBody': resign_request})
            else:
                # check the balance
                _, payer_balance, payee_balance = self.check_balance(
                    self.channel_name,
                    self.asset_type,
                    self.payer_address,
                    self.sender_balance,
                    self.payee_address,
                    self.receiver_balance,
                    is_htcl_type=True,
                    payment=self.payment)

                # sign the transaction
                # 2 parts in htlc message: conclusive and inconclusive part
                rsmc_commitment = HtlcMessage.sign_content(
                    self.wallet, RsmcMessage._sign_type_list, [
                        self.channel_name, nonce, self.payer_address,
                        payer_balance, self.payee_address, payee_balance,
                        sign_hashcode, sign_rcode
                    ])

                hlock_commitment = HtlcMessage.sign_content(
                    self.wallet,
                    self._sign_type_list, [
                        self.channel_name, self.payer_address,
                        self.payee_address,
                        int(self.delay_block),
                        int(self.payment), self.hashcode
                    ],
                    start=5)

                # update the htlc_trade
                htlc_trade.update({
                    'commitment': rsmc_commitment,
                    'delay_commitment': hlock_commitment,
                    'state': EnumTradeState.confirming.name
                })

                # update the message body with signature
                htlc_sign_body.update({
                    'Commitment': rsmc_commitment,
                    'DelayCommitment': hlock_commitment
                })

                # add resign ack
                if resign_ack:
                    htlc_sign_body.update({'ResignBody': resign_ack})

            # Response message header
            response_message = HtlcResponsesMessage.create_message_header(
                self.receiver, self.sender, HtlcResponsesMessage._message_name,
                self.channel_name, self.asset_type, self.nonce, nonce)
            response_message.update({'MessageBody': htlc_sign_body})
            response_message.update({'Router': self.router})
            response_message.update({'Status': status.name})
            self.send(response_message)

            # record the transaction
            self.record_transaction(nonce, **htlc_trade)
        except TrinityException as error:
            LOG.exception(error)
            status = error.reason
        except Exception as error:
            LOG.exception(
                'Failed to handle Htlc message for channel<{}>, HashR<{}>. Exception:{}'
                .format(self.channel_name, self.hashcode, error))
            status = EnumResponseStatus.RESPONSE_EXCEPTION_HAPPENED
        finally:
            # failed operation
            if EnumResponseStatus.RESPONSE_OK != status:
                # send error response
                HtlcResponsesMessage.send_error_response(
                    self.sender, self.receiver, self.channel_name,
                    self.asset_type, self.nonce, status)

                # delete some related resources
                self.rollback_resource(self.channel_name, nonce or self.nonce,
                                       self.payment, status.name)

        return
Beispiel #5
0
    def create(cls,
               wallet,
               channel_name,
               asset_type,
               sender,
               receiver,
               payment,
               hashcode,
               router,
               next_router,
               current_channel=None,
               comments=None):
        """

        :param channel_name:
        :param wallet:
        :param sender:
        :param receiver:
        :param asset_type:
        :param payment:
        :param nonce:
        :param hashcode:
        :param router:
        :param next_router:
        :param comments:
        :return:
        """
        cls.check_channel_state(channel_name)
        cls.check_router(router, hashcode)
        cls.check_asset_type(asset_type)
        cls.check_both_urls(sender, receiver)
        cls.check_router(router, hashcode)

        # get nonce
        nonce = Channel.new_nonce(channel_name)
        if HtlcMessage._FOUNDER_NONCE > nonce:
            raise GoTo(
                EnumResponseStatus.RESPONSE_TRADE_WITH_INCORRECT_NONCE,
                'HtlcMessage::create: Incorrect nonce<{}> for channel<{}>'.
                format(nonce, channel_name))

        # get sender & receiver address from sender or receiver
        payer_address, _, _ = uri_parser(sender)
        payee_address, _, _ = uri_parser(receiver)
        asset_type = asset_type.upper()

        # check whether the balance is enough or not
        channel = Channel(channel_name)
        balance = channel.balance
        _, payer_balance, payee_balance = HtlcMessage.calculate_balance_after_payment(
            balance.get(payer_address, {}).get(asset_type),
            balance.get(payee_address, {}).get(asset_type),
            payment,
            is_htlc_type=True)

        # calculate the end block height
        jumps_index = HtlcMessage.this_jump(sender, router)
        end_block_height = cls.get_locked_block_height(len(router),
                                                       jumps_index)

        # Htlc is made up of 2 parts: rsmc and hlock part
        sign_hashcode, sign_rcode = cls.get_default_rcode()
        rsmc_commitment = HtlcMessage.sign_content(
            typeList=RsmcMessage._sign_type_list,
            valueList=[
                channel_name, nonce, payer_address, payer_balance,
                payee_address, payee_balance, sign_hashcode, sign_rcode
            ],
            privtKey=wallet._key.private_key_string)

        # hlock parts
        hlock_commitment = HtlcMessage.sign_content(
            start=5,
            typeList=HtlcMessage._sign_type_list,
            valueList=[
                channel_name, payer_address, payee_address, end_block_height,
                int(payment), hashcode
            ],
            privtKey=wallet._key.private_key_string)

        # # add trade to database
        htlc_trade = Channel.htlc_trade(type=EnumTradeType.TRADE_TYPE_HTLC,
                                        role=EnumTradeRole.TRADE_ROLE_FOUNDER,
                                        asset_type=asset_type,
                                        balance=payer_balance,
                                        peer_balance=payee_balance,
                                        payment=payment,
                                        hashcode=hashcode,
                                        delay_block=end_block_height,
                                        commitment=rsmc_commitment,
                                        delay_commitment=hlock_commitment)
        if current_channel:
            htlc_trade.update({'channel': current_channel})
        Channel.add_trade(channel_name, nonce=nonce, **htlc_trade)

        # generate the messages
        message_body = {
            'SenderBalance': payer_balance,
            'ReceiverBalance': payee_balance,
            'Commitment': rsmc_commitment,
            'Payment': payment,
            'DelayBlock': end_block_height,
            'DelayCommitment': hlock_commitment,
            'HashR': hashcode
        }

        message = HtlcMessage.create_message_header(sender, receiver,
                                                    HtlcMessage._message_name,
                                                    channel_name, asset_type,
                                                    nonce)
        message = message.message_header
        message.update({
            'Router': router,
            'Next': next_router,
        })
        message.update({'MessageBody': message_body})

        if comments:
            message.update({'Comments': comments})

        HtlcMessage.send(message)

        return None