Ejemplo n.º 1
0
    def handle(self):
        super(FounderResponsesMessage, self).handle()

        # check response status
        if not self.check_response_status(self.status):
            return

        try:
            # some checks and verification for founder message
            self.verify()
            self.check_nonce(self.nonce)
            founder_trade = Channel.query_trade(self.channel_name, self.nonce)
            self.check_signature(self.wallet,
                                 type_list=self._sign_type_list,
                                 value_list=[
                                     self.channel_name, self.nonce,
                                     self.receiver_address,
                                     int(founder_trade.balance),
                                     self.sender_address,
                                     int(founder_trade.peer_balance)
                                 ],
                                 signature=self.commitment)

            # update the trade
            Channel.update_trade(self.channel_name,
                                 self.nonce,
                                 peer_commitment=self.commitment)
        except GoTo as error:
            LOG.error(error)
        except Exception as error:
            LOG.error(
                'Exception occurred during creating channel<{}>. Exception: {}'
                .format(self.channel_name, error))
        else:
            self.register_deposit_event()
Ejemplo n.º 2
0
    def execute(self, block_height, channel_name='', hashcode=''):
        """

        :param block_height:
        :param channel_name:
        :param kwargs:
        :return:
        """
        super(ChannelHtlcUnlockedEvent, self).execute(block_height)

        # if monitor this event, update the htlc trade state to confirmed
        if channel_name and hashcode:
            try:
                htlc_trade = Channel.batch_query_trade(
                    channel_name,
                    filters={
                        'type': EnumTradeType.TRADE_TYPE_HTLC.name,
                        'hashcode': hashcode
                    })[0]
            except Exception as error:
                LOG.error('Htlc trade with HashR<{}> not found for channel<{}>. Exception: {}'\
                          .format(hashcode, channel_name, error))
            else:
                Channel.update_trade(
                    channel_name,
                    htlc_trade.nonce,
                    state=EnumTradeState.confirmed_onchain.name)
        else:
            LOG.error(
                'Error input parameters: channel <{}>, hashcode<{}>.'.format(
                    channel_name, hashcode))
Ejemplo n.º 3
0
    def handle_founder_response(self):
        """

        :return:
        """
        need_update_balance = False
        # handle the resign body firstly
        if self.resign_body:
            resign_ack, _ = self.handle_resign_body(self.wallet, self.channel_name, self.resign_body)

        sign_hashcode, sign_rcode = self.get_rcode(self.channel_name, self.hashcode)
        # has already signed by peer
        if self.commitment:
            # check the signature
            self.check_signature(
                self.wallet, self.sender_address,
                type_list=self._sign_type_list,
                value_list=[self.channel_name, self.nonce, self.payer_address, int(self.sender_balance),
                            self.payee_address, int(self.receiver_balance), sign_hashcode, sign_rcode],
                signature=self.commitment
            )
            # Just update current transaction confirmed:
            Channel.update_trade(self.channel_name, self.nonce, peer_commitment=self.commitment,
                                 state=EnumTradeState.confirmed.name)
            need_update_balance = True

            if self.comments:
                self.notify_peer_payment_finished()
        else:
            # to check the latest confirmed nonce
            self.validate_transaction()

            # if running here, it means that the transaction has been succeeded to resign
            is_htlc_to_rsmc = self.is_hlock_to_rsmc(self.hashcode)
            self.check_balance(self.channel_name, self.asset_type, self.payer_address, self.sender_balance,
                               self.payee_address, self.receiver_balance, hlock_to_rsmc=is_htlc_to_rsmc, payment=self.payment)

            # sign this transaction
            commitment = RsmcResponsesMessage.sign_content(
                self.wallet, self._sign_type_list, [self.channel_name, self.nonce, self.payer_address, int(self.sender_balance),
                                                    self.payee_address, int(self.receiver_balance), sign_hashcode, sign_rcode]
            )

            # update the transaction confirming state
            Channel.update_trade(self.channel_name, self.nonce, balance=self.receiver_balance,
                                 peer_balance=self.sender_balance, commitment=commitment,
                                 state=EnumTradeState.confirming.name)

            rsmc_sign_body = self.response(self.asset_type, self.payment, self.sender_balance, self.receiver_balance,
                                           0, self.hashcode)
            rsmc_sign_body.update({'Commitment': commitment})

            return need_update_balance, rsmc_sign_body

        return need_update_balance, None
Ejemplo n.º 4
0
    def handle(self):
        super(RResponse, self).handle()

        status = EnumResponseStatus.RESPONSE_OK
        try:
            self.check_channel_state(self.channel_name)
            self.check_rcode(self.hashcode, self.rcode)

            htlc_trade = self.get_htlc_trade_by_hashr(self.channel_name,
                                                      self.hashcode)
            Channel.update_trade(self.channel_name,
                                 htlc_trade.nonce,
                                 rcode=self.rcode)
            # check payment:
            stored_payment = int(htlc_trade.payment)
            if stored_payment != self.payment:
                raise GoTo(
                    EnumResponseStatus.RESPONSE_TRADE_UNMATCHED_PAYMENT,
                    'Unmatched payment. self stored payment<{}>, peer payment<{}>'
                    .format(stored_payment, self.payment))

            # send response OK message
            RResponseAck.create(self.channel_name, self.asset_type, self.nonce,
                                self.sender, self.receiver, self.hashcode,
                                self.rcode, self.payment, self.comments,
                                status)
        except TrinityException as error:
            LOG.error(error)
            status = error.reason
        except Exception as error:
            status = EnumResponseStatus.RESPONSE_EXCEPTION_HAPPENED
            LOG.error(
                'Failed to handle RResponse with HashR<{}>. Exception: {}'.
                format(self.hashcode, error))
            pass
        else:
            # trigger rsmc
            self.trigger_pay_by_rsmc()

            # notify rcode to next peer
            LOG.debug(
                'notify the RResponse to next channel<{}>, current channel<{}>'
                .format(htlc_trade.channel, self.channel_name))
            self.notify_rcode_to_next_peer(htlc_trade.channel)
        finally:
            if EnumResponseStatus.RESPONSE_OK != status:
                RResponseAck.send_error_response(self.sender, self.receiver,
                                                 self.channel_name,
                                                 self.asset_type, self.nonce,
                                                 status)

        return None
Ejemplo n.º 5
0
    def record_transaction(self, nonce, **update_args):
        """
        
        :param nonce:
        :param update_args:
        :return:
        """
        # check the trade with nonce existed or not
        try:
            new_trade = Channel.query_trade(self.channel_name, nonce)
        except Exception as error:
            new_trade = None

        # add new transaction
        if new_trade:
            Channel.update_trade(self.channel_name, nonce=nonce, **update_args)
        else:
            Channel.add_trade(self.channel_name, nonce=nonce, **update_args)

        return
Ejemplo n.º 6
0
    def terminate(self, block_height, *args, asset_type='TNC'):
        super(ChannelDepositEvent, self).terminate(block_height, *args)

        # check the deposit of the contract address
        total_deposit = self.contract_event_api.get_channel_total_balance(self.channel_name)
        if total_deposit >= self.deposit + self.partner_deposit:
            Channel.update_channel(self.channel_name, state=EnumChannelState.OPENED.name)
            Channel.update_trade(self.channel_name, self.nonce, state=EnumTradeState.confirmed.name)
            sync_channel_info_to_gateway(self.channel_name, 'AddChannel', asset_type)
            console_log.info('Channel {} state is {}'.format(self.channel_name, EnumChannelState.OPENED.name))

            # to trigger monitor event for closing channel
            event_monitor_close_channel(self.channel_name)
            event_monitor_settle(self.channel_name)

            # to trigger monitor event for unlocking htlc locked payment
            event_monitor_withdraw(self.channel_name)
            event_monitor_withdraw_update(self.channel_name)
            event_monitor_withdraw_settle(self.channel_name)

            self.next_stage()
Ejemplo n.º 7
0
    def notify_rcode_to_next_peer(self, next_channel):
        """

        :param next_channel:
        :return:
        """
        peer = None
        try:
            # original payer is found
            if not next_channel or next_channel == self.channel_name:
                LOG.info('HTLC Founder with HashR<{}> received the R-code<{}>'.
                         format(self.hashcode, self.rcode))
                return

            htlc_trade = self.get_htlc_trade_by_hashr(next_channel,
                                                      self.hashcode)
            if htlc_trade.role == EnumTradeRole.TRADE_ROLE_PARTNER.name and next_channel != htlc_trade.channel:
                LOG.warning(
                    'Why the channel is different. next_channel<{}>, stored channel<{}>'
                    .format(next_channel, htlc_trade.channel))

            # notify the previous node the R-code
            LOG.debug('Payment get channel {}/{}'.format(
                next_channel, self.hashcode))
            channel = Channel(next_channel)
            channel.update_trade(next_channel,
                                 htlc_trade.nonce,
                                 rcode=self.rcode)
            peer = channel.peer_uri(self.wallet.url)
            nonce = channel.latest_nonce(next_channel)
            LOG.info("Next peer: {}".format(peer))
            self.create(next_channel, self.asset_type, nonce, self.wallet.url,
                        peer, self.hashcode, self.rcode, self.comments)

            APIStatistics.update_statistics(self.wallet.address,
                                            htlc_rcode=True)
        except Exception as error:
            LOG.error('Failed to notify RCode<{}> to peer<{}>'.format(
                self.rcode, peer))
Ejemplo n.º 8
0
    def add_or_update_quick_settle_trade(cls, channel_name, expected_role,
                                         **kwargs):
        """

        :param channel_name:
        :param expected_role:
        :param kwargs:
        :return:
        """
        nonce = cls._SETTLE_NONCE
        try:
            settle_trade_db = Channel.query_trade(channel_name, nonce)[0]
        except Exception as error:
            LOG.debug(
                'No quick settle is created before. Exception: {}'.format(
                    error))
            Channel.add_trade(channel_name, nonce=nonce, **kwargs)
        else:
            # check the role of the database:
            if settle_trade_db.role != expected_role.name:
                # update the settle database
                Channel.update_trade(channel_name, nonce, **kwargs)
Ejemplo n.º 9
0
    def handle(self):
        super(SettleResponseMessage, self).handle()

        # check response status
        if not self.check_response_status(self.status):
            return

        try:
            # common check arguments
            self.verify()
            self.check_nonce(self.nonce)
            settle_trade = Channel.query_trade(self.channel_name, self.nonce)
            self.check_signature(self.wallet,
                                 self.sender_address,
                                 type_list=self._sign_type_list,
                                 value_list=[
                                     self.channel_name, self.nonce,
                                     self.receiver_address,
                                     int(settle_trade.balance),
                                     self.sender_address,
                                     int(settle_trade.peer_balance)
                                 ],
                                 signature=self.commitment)

            # update the trade
            Channel.update_trade(self.channel_name,
                                 SettleResponseMessage._SETTLE_NONCE,
                                 peer_commitment=self.commitment)
        except GoTo as error:
            LOG.exception(error)
        except Exception as error:
            LOG.exception(
                'Handle Settle Response error. Exception: {}'.format(error))
        else:
            # register the event to quick close channel
            self.register_quick_close_event()

            return
Ejemplo n.º 10
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
Ejemplo n.º 11
0
    def trigger_htlc_to_next_jump(self):
        """"""
        self.router, _ = self.exclude_wallet_from_router(
            self.wallet.url, self.router)
        if not self.check_if_the_last_router():
            next_router = self.next_jump
            LOG.debug('Get Next Router {} from {}'.format(
                str(next_router), self.router))

            if not next_router:
                raise GoTo(
                    EnumResponseStatus.RESPONSE_ROUTER_WITH_ILLEGAL_NEXT_JUMP,
                    'Illegal next jump<{}> in router<{}>'.format(
                        next_router, self.router))

            # to get channel between current wallet and next jump
            channel_set = Channel.get_channel(self.wallet.url,
                                              next_router,
                                              state=EnumChannelState.OPENED)
            if not (channel_set and channel_set[0]):
                raise GoTo(
                    EnumResponseStatus.RESPONSE_CHANNEL_NOT_FOUND,
                    'No OPENED channel is found between {} and {}.'.format(
                        self.wallet.url, next_router))
            channel_set = channel_set[0]

            if channel_set.channel == self.channel_name:
                LOG.warn('Has reached receiver of HTLC transaction.')
                return

            # calculate fee and transfer to next jump
            fee = TrinityNumber(str(self.get_fee(self.wallet.url))).number
            payment = self.big_number_calculate(self.payment, fee, False)
            receiver = next_router
            HtlcMessage.create(channel_set.channel,
                               self.asset_type,
                               self.wallet.url,
                               receiver,
                               payment,
                               self.hashcode,
                               self.router,
                               current_channel=self.channel_name,
                               comments=self.comments)

            # record channel of next jump in current htlc trade
            Channel.update_trade(self.channel_name,
                                 self.nonce,
                                 channel=channel_set.channel)

            APIStatistics.update_statistics(self.wallet.address, htlc_free=fee)
        else:
            # trigger RResponse
            Channel.update_payment(self.channel_name, self.hashcode)
            payment_trade = Channel.query_payment(self.channel_name,
                                                  self.hashcode)
            if not (payment_trade and payment_trade[0]):
                raise GoTo(
                    EnumResponseStatus.RESPONSE_TRADE_HASHR_NOT_FOUND,
                    'Rcode not found for hashcode<{}>'.format(self.hashcode))

            payment_trade = payment_trade[0]

            try:
                RResponse.create(self.channel_name, self.asset_type,
                                 self.nonce, self.wallet.url, self.sender,
                                 self.hashcode, payment_trade.rcode,
                                 self.comments)

                # update the htlc trade history
                Channel.update_trade(self.channel_name,
                                     self.nonce,
                                     rcode=payment_trade.rcode)
            except Exception as error:
                LOG.exception(
                    'Failed triggerring to send RResponse for HashR<{}>. Exception: {}'
                    .format(self.hashcode, error))
Ejemplo n.º 12
0
    def handle(self):
        super(HtlcResponsesMessage, self).handle()

        status = EnumResponseStatus.RESPONSE_OK
        try:
            # check the response status
            if not self.check_response_status(self.status):
                self.rollback_resource(self.channel_name,
                                       self.nonce,
                                       self.payment,
                                       status=self.status)
                return

            self.check_channel_state(self.channel_name)
            self.check_router(self.router, self.hashcode)
            self.verify()
            _, nonce = self.check_nonce(self.nonce + 1, self.channel_name)
            _, payer_balance, payee_balance = self.check_balance(
                self.channel_name,
                self.asset_type,
                self.receiver_address,
                self.sender_balance,
                self.sender_address,
                self.receiver_balance,
                is_htcl_type=True,
                payment=self.payment)

            sign_hashcode, sign_rcode = self.get_default_rcode()
            self.check_signature(self.wallet,
                                 type_list=RsmcMessage._sign_type_list,
                                 value_list=[
                                     self.channel_name, self.nonce,
                                     self.receiver_address,
                                     int(self.sender_balance),
                                     self.sender_address,
                                     int(self.receiver_balance), sign_hashcode,
                                     sign_rcode
                                 ],
                                 signature=self.commitment)

            self.check_signature(self.wallet,
                                 type_list=self._sign_type_list,
                                 value_list=[
                                     self.channel_name, self.receiver_address,
                                     self.sender_address,
                                     int(self.delay_block),
                                     int(self.payment), self.hashcode
                                 ],
                                 signature=self.delay_commitment)

            # update transaction
            Channel.update_trade(self.channel_name,
                                 int(self.nonce),
                                 peer_commitment=self.commitment,
                                 peer_delay_commitment=self.delay_commitment)

            # update the channel balance
            self.update_balance_for_channel(self.channel_name,
                                            self.asset_type,
                                            self.receiver_address,
                                            self.sender_address,
                                            self.payment,
                                            is_htlc_type=True)
        except TrinityException as error:
            LOG.error(error)
            status = error.reason
        except Exception as error:
            LOG.error('Transaction with none<{}> not found. Error: {}'.format(
                self.nonce, error))
            status = EnumResponseStatus.RESPONSE_EXCEPTION_HAPPENED
        else:
            # successful action
            LOG.debug('Succeed to htlc for channel<{}>'.format(
                self.channel_name))
            return
        finally:
            # rollback the resources
            self.rollback_resource(self.channel_name,
                                   self.nonce,
                                   self.payment,
                                   status=status.name)
Ejemplo n.º 13
0
    def handle_resign_body(cls, wallet, channel_name, resign_body):
        """"""
        if not resign_body:
            return None

        if not (wallet and channel_name):
            raise GoTo(
                EnumResponseStatus.RESPONSE_ILLEGAL_INPUT_PARAMETER,
                'Void wallet<{}> or Illegal channel name<{}>'.format(
                    wallet, channel_name))

        resign_nonce = int(resign_body.get('Nonce'))
        update_channel_db = {}
        update_trade_db = {}

        # get transaction by the resign_nonce
        resign_trade = Channel.query_trade(channel_name, resign_nonce)
        asset_type = resign_trade.asset_type

        channel = Channel(channel_name)
        self_address, _, _ = uri_parser(wallet.url)
        peer_address, _, _ = uri_parser(channel.peer_uri(wallet.url))

        # Is this wallet sender side of this trade ?????
        if EnumTradeRole.TRADE_ROLE_PARTNER.name == resign_trade.role:
            payer_address = peer_address
            payee_address = self_address
            payer_balance = resign_trade.peer_balance
            payee_balance = resign_trade.balance
        elif EnumTradeRole.TRADE_ROLE_FOUNDER.name == resign_trade.role:
            payer_address = self_address
            payee_address = peer_address
            payer_balance = resign_trade.balance
            payee_balance = resign_trade.peer_balance
        else:
            raise GoTo(
                EnumResponseStatus.RESPONSE_DATABASE_ERROR_TRADE_ROLE,
                'Error trade role<{}> for nonce<{}>'.format(
                    resign_trade.role, resign_nonce))

        if EnumTradeType.TRADE_TYPE_HTLC.name == resign_trade.type:
            rsmc_sign_hashcode, rsmc_sign_rcode = cls.get_default_rcode()
        elif EnumTradeType.TRADE_TYPE_RSMC.name == resign_trade.type:
            rsmc_sign_hashcode, rsmc_sign_rcode = resign_trade.hashcode, resign_trade.rcode
        else:
            raise GoTo(
                EnumResponseStatus.RESPONSE_TRADE_RESIGN_NOT_SUPPORTED_TYPE,
                'Only support HTLC and RSMC resign. Current transaction type: {}'
                .format(resign_trade.type))

        rsmc_list = [
            channel_name, resign_nonce, payer_address,
            int(payer_balance), payee_address,
            int(payee_balance), rsmc_sign_hashcode, rsmc_sign_rcode
        ]

        # self commitment is None
        if not resign_trade.commitment:
            commitment = cls.sign_content(wallet, cls._rsmc_sign_type_list,
                                          rsmc_list)
            update_trade_db.update({'commitment': commitment})

        # self lock commitment is none
        htlc_list = None
        if EnumTradeType.TRADE_TYPE_HTLC.name == resign_trade.type:
            htlc_list = [
                channel_name, payer_address, payee_address,
                int(resign_trade.delay_block),
                int(resign_trade.payment), resign_trade.hashcode
            ]
            delay_commitment = cls.sign_content(wallet,
                                                cls._htlc_sign_type_list,
                                                htlc_list)
            update_trade_db.update({'delay_commitment': delay_commitment})

        # check whether the trade need update or not
        if resign_trade.state not in [
                EnumTradeState.confirmed.name,
                EnumTradeState.confirmed_onchain.name
        ]:
            peer_commitment = resign_body.get('Commitment')
            peer_delay_commitment = resign_body.get('DelayCommitment')

            # check peer signature
            cls.check_signature(wallet, peer_address, cls._rsmc_sign_type_list,
                                rsmc_list, peer_commitment)

            # update transaction and channel balance
            update_trade_db.update({'peer_commitment': peer_commitment})
            update_channel_db = {
                'balance': {
                    payer_address: {
                        asset_type: payer_balance
                    },
                    payee_address: {
                        asset_type: payee_balance
                    }
                }
            }

            # check the htlc part signature
            if EnumTradeType.TRADE_TYPE_HTLC.name == resign_trade.type:
                cls.check_signature(wallet, peer_address,
                                    cls._htlc_sign_type_list, htlc_list,
                                    peer_delay_commitment)
                update_trade_db.update(
                    {'peer_delay_commitment': peer_delay_commitment})
                update_trade_db.update(
                    {'state': EnumTradeState.confirming.name})

                # need update the hlock part
                if payer_address == self_address:
                    channel = Channel(channel_name)
                    channel_hlock = channel.hlock
                    if channel_hlock and channel_hlock.get(payer_address):
                        payer_hlock = int(resign_trade.payment) + int(
                            channel_hlock.get(payer_address).get(asset_type))
                        channel_hlock.update(
                            {payer_address: {
                                asset_type: str(payer_hlock)
                            }})
                        update_channel_db.update({'hlock': channel_hlock})
            else:  # RSMC type transaction
                update_trade_db.update(
                    {'state': EnumTradeState.confirmed.name})

            # update transaction
            Channel.update_trade(channel_name, resign_nonce, **update_trade_db)

            # update Channel balance to new one
            Channel.update_channel(channel_name, **update_channel_db)

        # return resign message body
        return cls.create_resign_message_body(wallet.url, channel_name,
                                              resign_nonce, True)
Ejemplo n.º 14
0
    def create_resign_message_body(cls,
                                   wallet_url,
                                   channel_name,
                                   nonce,
                                   is_resign_response=False):
        """

        :param wallet_url: current opened wallet url
        :param channel_name:
        :param nonce:
        :param is_resign_response: if True, it means has received the peer resign request
        :return:
        """
        if not (channel_name and isinstance(nonce, int)):
            raise GoTo(
                EnumResponseStatus.RESPONSE_ILLEGAL_INPUT_PARAMETER,
                'Illegal parameters: channel_name<{}> or nonce<{}, type:{}>'.
                format(channel_name, nonce, type(nonce)))

        # record the nonce negotiated by partner of the transaction with nonce
        # required is True
        if is_resign_response:
            nego_nonce = nonce
            pre_nonce = nonce
            pre_trade = Channel.query_trade(channel_name, nego_nonce)
        else:
            pre_trade, pre_nonce = Channel.latest_valid_trade(channel_name)
            nego_nonce = pre_nonce + 1 if isinstance(pre_nonce, int) else None

        # does founder practise fraud ???
        if not (pre_trade and nego_nonce) or cls._FOUNDER_NONCE >= nego_nonce:
            raise GoTo(EnumResponseStatus.RESPONSE_TRADE_WITH_INCORRECT_NONCE,
                       'Could not finish this transaction because ')

        # initialize some local variables
        trade_role = pre_trade.role
        trade_type = pre_trade.type
        trade_state = pre_trade.state

        # local variables
        resign_body = {'Nonce': str(pre_nonce)}
        need_update_balance = False

        # is partner role of this transaction
        if EnumTradeRole.TRADE_ROLE_PARTNER.name == trade_role and EnumTradeState.confirming.name == trade_state:
            # update the resign_body by the different trade type
            if EnumTradeType.TRADE_TYPE_RSMC.name == trade_type:
                if pre_trade.peer_commitment:
                    # update the trade to confirmed state directly
                    Channel.update_trade(channel_name,
                                         pre_nonce,
                                         state=EnumTradeState.confirmed.name)

                    # need update channel balance
                    # need_update_balance = True
                else:
                    # need resign this RSMC transaction by peer
                    resign_body.update({'Commitment': pre_trade.commitment})
            elif EnumTradeType.TRADE_TYPE_HTLC.name == trade_type:
                if pre_trade.peer_commitment and pre_trade.peer_delay_commitment:
                    # update the trade to confirmed state directly
                    Channel.update_trade(channel_name,
                                         pre_nonce,
                                         state=EnumTradeState.confirming.name)
                    # need update channel balance
                    # need_update_balance = True
                else:
                    # need resign this HTLC transaction by peer
                    resign_body.update({'Commitment': pre_trade.commitment})
                    resign_body.update(
                        {'DelayCommitment': pre_trade.delay_commitment})
            else:
                LOG.error(
                    'Unsupported trade type<{}> to resign in partner<{}> side'.
                    format(trade_type, wallet_url))
                return None, pre_trade

            # need update the channel balance or not???
            # if need_update_balance:
            #     channel = Channel(channel_name)
            #     self_address, _, _ = uri_parser(wallet_url)
            #     peer_address, _, _ = uri_parser(channel.peer_uri(wallet_url))
            #
            #     # ToDo: if need, here need add asset type check in future
            #     Channel.update_channel(channel_name, balance={
            #         self_address: {pre_trade.asset_type: pre_trade.balance},
            #         peer_address: {pre_trade.asset_type: pre_trade.peer_balance}
            #     })
        elif is_resign_response is True and EnumTradeRole.TRADE_ROLE_FOUNDER.name == trade_role and \
                (EnumTradeState.confirmed.name == trade_state or (EnumTradeState.confirming.name == trade_state and
                                                                  EnumTradeType.TRADE_TYPE_HTLC.name == trade_type)):

            if EnumTradeType.TRADE_TYPE_RSMC.name == trade_type:
                if pre_trade.peer_commitment:
                    resign_body.update({'Commitment': pre_trade.commitment})
                else:
                    # stop transaction ????
                    pass
            elif EnumTradeType.TRADE_TYPE_HTLC.name == trade_type:
                if pre_trade.peer_commitment and pre_trade.peer_delay_commitment:
                    resign_body.update({'Commitment': pre_trade.commitment})
                    resign_body.update(
                        {'DelayCommitment': pre_trade.delay_commitment})
            else:
                LOG.error(
                    'Unsupported trade type<{}> to resign in founder<{}> side'.
                    format(trade_type, wallet_url))
                return None, pre_trade
        else:
            return None, pre_trade

        # Previous transaction need to be resigned by peer
        if 'Commitment' in resign_body:
            return resign_body, pre_trade

        return None, pre_trade
Ejemplo n.º 15
0
    def handle(self):
        super(RsmcResponsesMessage, self).handle()

        status = EnumResponseStatus.RESPONSE_OK
        try:
            # check the response status
            if not self.check_response_status(self.status):
                self.rollback_resource(self.channel_name, self.nonce,
                                       self.payment, self.status)
                return

            # common check
            self.check_channel_state(self.channel_name)
            self.verify()
            self.check_role(self.role_index)
            nonce = self.nonce if 0 == self.role_index else self.nonce + 1
            self.check_nonce(nonce, self.channel_name)

            is_htlc_to_rsmc = self.is_hlock_to_rsmc(self.hashcode)
            self.check_balance(self.channel_name,
                               self.asset_type,
                               self.payer,
                               self.sender_balance,
                               self.payee,
                               self.receiver_balance,
                               hlock_to_rsmc=is_htlc_to_rsmc,
                               payment=self.payment)

            sign_hashcode, sign_rcode = self.get_rcode(self.channel_name,
                                                       self.hashcode)
            self.check_signature(self.wallet,
                                 type_list=self._sign_type_list,
                                 value_list=[
                                     self.channel_name, nonce, self.payer,
                                     int(self.sender_balance), self.payee,
                                     int(self.receiver_balance), sign_hashcode,
                                     sign_rcode
                                 ],
                                 signature=self.commitment)

            if 0 == self.role_index:
                self.rsmc_sign(self.wallet, self.channel_name, self.asset_type,
                               self.nonce, self.sender, self.receiver,
                               self.payment, self.sender_balance,
                               self.receiver_balance, self.rsmc_sign_role,
                               self.hashcode, self.comments)

            # update transaction
            Channel.update_trade(self.channel_name,
                                 self.nonce,
                                 peer_commitment=self.commitment,
                                 state=EnumTradeState.confirmed.name)
            Channel.confirm_payment(self.channel_name, self.hashcode,
                                    is_htlc_to_rsmc)

            # update the channel balance
            self.update_balance_for_channel(self.channel_name, self.asset_type,
                                            self.payer, self.payee,
                                            self.payment, is_htlc_to_rsmc)
        except GoTo as error:
            LOG.error(error)
            status = error.reason
        except Exception as error:
            status = EnumResponseStatus.RESPONSE_EXCEPTION_HAPPENED
            LOG.error('Failed to handle RsmcSign for channel<{}> nonce<{}>, role_index<{}>.Exception: {}' \
                      .format(self.channel_name, self.nonce, self.role_index, error))
        finally:
            # send error response
            if EnumResponseStatus.RESPONSE_OK != status:
                if 0 == self.role_index:
                    self.send_error_response(self.sender,
                                             self.receiver,
                                             self.channel_name,
                                             self.asset_type,
                                             self.nonce,
                                             status,
                                             kwargs={'RoleIndex': '1'})

                # need rollback some resources
                self.rollback_resource(self.channel_name,
                                       self.nonce,
                                       self.payment,
                                       status=self.status)

        return
Ejemplo n.º 16
0
    def handle_founder_response(self):
        """

        :return:
        """
        need_update_balance = False
        # handle the resign body firstly
        resign_ack = None
        if self.resign_body:
            resign_ack, _ = self.handle_resign_body(self.wallet,
                                                    self.channel_name,
                                                    self.resign_body)

        sign_hashcode, sign_rcode = self.get_default_rcode()
        # has already signed by peer
        if self.commitment and self.delay_commitment:
            # check the signature
            self.check_signature(self.wallet,
                                 self.sender_address,
                                 type_list=RsmcMessage._sign_type_list,
                                 value_list=[
                                     self.channel_name, self.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(self.payment), self.hashcode
                                 ],
                                 signature=self.delay_commitment)
            # Just update current transaction confirmed:
            Channel.update_trade(self.channel_name,
                                 self.nonce,
                                 peer_commitment=self.commitment,
                                 peer_delay_commitment=self.delay_commitment,
                                 state=EnumTradeState.confirming.name)

            need_update_balance = True
        else:
            # to check the latest confirmed nonce
            self.validate_transaction()

            # check balance after resign successfully
            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 this transaction
            # sign the transaction with 2 parts: rsmc and htlc-locked part
            commitment = self.sign_content(
                self.wallet, RsmcMessage._sign_type_list, [
                    self.channel_name, self.nonce, self.payer_address,
                    self.sender_balance, self.payee_address,
                    self.receiver_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(self.payment), self.hashcode
                ],
                start=5)

            # update the transaction confirming state
            Channel.update_trade(self.channel_name,
                                 self.nonce,
                                 balance=self.receiver_balance,
                                 peer_balance=self.sender_balance,
                                 commitment=commitment,
                                 delay_commitment=delay_commitment,
                                 state=EnumTradeState.confirming.name)

            # re-trigger the new transaction saved in db before
            htlc_sign_body = self.response(self.sender_balance,
                                           self.receiver_balance, self.payment,
                                           self.hashcode, 0, self.delay_block)
            htlc_sign_body.update({
                'Commitment': commitment,
                'DelayCommitment': delay_commitment
            })

            return need_update_balance, htlc_sign_body

        return need_update_balance, None
Ejemplo n.º 17
0
    def handle_partner_response(self):
        """

        :return: response to send to peer
        """
        # local variables
        need_update_balance = False
        is_htlc_to_rsmc = self.is_hlock_to_rsmc(self.hashcode)

        # handle the resign body firstly
        resign_ack = 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
            if not self.commitment:
                _, self.sender_balance, self.receiver_balance = self.calculate_balance_after_payment(
                    resign_trade.balance, resign_trade.peer_balance, self.payment, is_htlc_to_rsmc
                )

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

        # create RSMC response message with RoleIndex==1
        rsmc_sign_body = self.response(self.asset_type, self.payment, self.sender_balance, self.receiver_balance,
                                       1, self.hashcode)

        # get some common local variables
        sign_hashcode, sign_rcode = self.get_rcode(self.channel_name, self.hashcode)
        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

        # if negotiated nonce by peer, delete the transaction with self.nonce
        if nonce != self.nonce:
            # generate the rsmc trade part
            rsmc_trade = Channel.rsmc_trade(
                type=EnumTradeType.TRADE_TYPE_RSMC, role=EnumTradeRole.TRADE_ROLE_FOUNDER,
                asset_type=self.asset_type, balance=payer_balance, peer_balance=payee_balance, payment=payment,
                hashcode=sign_hashcode, rcode=sign_rcode
            )
            self.record_transaction(nonce, **rsmc_trade)

            if nonce < self.nonce:
                Channel.delete_trade(self.channel_name, self.nonce)

        # query the trade by nonce
        current_trade = Channel.query_trade(self.channel_name, nonce)
        if current_trade.commitment:
            # It means that the transaction is already signed during resign
            # previous transaction record.
            commitment = current_trade.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, hlock_to_rsmc=is_htlc_to_rsmc, payment=payment)

            # sign the transaction
            commitment = RsmcResponsesMessage.sign_content(
                self.wallet, self._sign_type_list, [self.channel_name, nonce, self.payer_address, payer_balance,
                                                    self.payee_address, payee_balance, sign_hashcode, sign_rcode]
            )

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

        # peer has already sign the new transaction with nonce
        if self.commitment:
            # check the signature
            self.check_signature(
                self.wallet, self.sender_address,
                type_list=self._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
            )

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

            rsmc_sign_body.update({'Commitment': commitment})

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

        return need_update_balance, rsmc_sign_body
Ejemplo n.º 18
0
    def handle(self):
        super(HtlcMessage, self).handle()

        trigger_rresponse = False
        status = EnumResponseStatus.RESPONSE_OK
        try:
            self.check_hashcode_used(self.channel_name, self.hashcode)
            self.check_channel_state(self.channel_name)
            self.check_router(self.router, self.hashcode)
            self.verify()
            _, nonce = self.check_nonce(self.nonce, self.channel_name)
            _, payer_balance, payee_balance = self.check_balance(
                self.channel_name,
                self.asset_type,
                self.sender_address,
                self.sender_balance,
                self.receiver_address,
                self.receiver_balance,
                is_htcl_type=True,
                payment=self.payment)

            sign_hashcode, sign_rcode = self.get_default_rcode()
            self.check_signature(self.wallet,
                                 type_list=RsmcMessage._sign_type_list,
                                 value_list=[
                                     self.channel_name, self.nonce,
                                     self.sender_address,
                                     int(self.sender_balance),
                                     self.receiver_address,
                                     int(self.receiver_balance), sign_hashcode,
                                     sign_rcode
                                 ],
                                 signature=self.commitment)

            self.check_signature(self.wallet,
                                 type_list=self._sign_type_list,
                                 value_list=[
                                     self.channel_name, self.sender_address,
                                     self.receiver_address,
                                     int(self.delay_block),
                                     int(self.payment), self.hashcode
                                 ],
                                 signature=self.delay_commitment)

            # transform the message to the next router if not last router node
            next_router = self.next_router
            if not self.check_if_the_last_router():
                next_router = self.get_next_router()
                LOG.debug('Get Next Router {}'.format(str(next_router)))

                # to get channel
                channel_set = Channel.get_channel(
                    self.wallet.url,
                    next_router,
                    state=EnumChannelState.OPENED)
                if not (channel_set and channel_set[0]):
                    status = EnumResponseStatus.RESPONSE_CHANNEL_NOT_FOUND
                    raise GoTo(
                        EnumResponseStatus.RESPONSE_CHANNEL_NOT_FOUND,
                        'No OPENED channel is found between {} and {}.'.format(
                            self.wallet.url, next_router))
                channel_set = channel_set[0]

                # calculate fee and transfer to next jump
                fee = TrinityNumber(str(self.get_fee(self.wallet.url))).number
                payment = self.big_number_calculate(self.payment, fee, False)
                receiver = next_router
                self.create(self.wallet,
                            channel_set.channel,
                            self.asset_type,
                            self.wallet.url,
                            receiver,
                            payment,
                            self.hashcode,
                            self.router,
                            next_router,
                            current_channel=self.channel_name,
                            comments=self.comments)
            else:
                Channel.update_payment(self.channel_name, self.hashcode)
                payment_trade = Channel.query_payment(self.channel_name,
                                                      self.hashcode)
                if not (payment_trade and payment_trade[0]):
                    raise GoTo(
                        EnumResponseStatus.RESPONSE_TRADE_HASHR_NOT_FOUND,
                        'Rcode not found for hashcode<{}>'.format(
                            self.hashcode))

                payment_trade = payment_trade[0]
                # trigger RResponse
                trigger_rresponse = True

            # send response to receiver
            HtlcResponsesMessage.create(
                self.wallet, self.channel_name, self.asset_type, self.nonce,
                self.sender, self.receiver, self.payment, self.sender_balance,
                self.receiver_balance, self.hashcode, self.delay_block,
                self.commitment, self.delay_commitment, self.router,
                next_router, self.comments)

            # means last receiver has received this htlc message, then update this trade record.
            if trigger_rresponse:
                try:
                    RResponse.create(self.channel_name, self.asset_type,
                                     self.nonce, self.wallet.url, self.sender,
                                     self.hashcode, payment_trade.rcode,
                                     self.comments)

                    # update the htlc trade history
                    Channel.update_trade(self.channel_name,
                                         self.nonce,
                                         rcode=payment_trade.rcode)
                except Exception as error:
                    LOG.error('Failed triggerring to send RResponse for HashR<{}>. Exception: {}'\
                              .format(self.hashcode, error))
        except TrinityException as error:
            LOG.error(error)
            status = error.reason
        except Exception as error:
            LOG.error(
                '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, self.nonce,
                                       self.payment, status.name)

        return