Example #1
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))
Example #2
0
    def channel_trans(self, arguments):
        """

        :param arguments:
        :return:
        """

        if len(arguments) == 2:
            # payment code
            pay_code = get_arg(arguments, 1)
            result, info = Payment.decode_payment_code(pay_code)
            if result:
                receiver = info.get("uri")
                net_magic = info.get('net_magic')
                if not net_magic or net_magic != str(get_magic()):
                    console_log.error("No correct net magic")
                    return None
                hashcode = info.get("hashcode")
                asset_type = info.get("asset_type")
                # asset_type = get_asset_type_name(asset_type)
                count = info.get("payment")
                comments = info.get("comments")
                console_log.info("will pay {} {} to {} comments {}".format(
                    TrinityNumber.convert_to_number(count), asset_type,
                    receiver, comments))
            else:
                console_log.error("The payment code is not correct")
                return
        else:
            receiver = get_arg(arguments, 1)
            asset_type = get_arg(arguments, 2)
            count = TrinityNumber(get_arg(arguments, 3).strip()).number
            hashcode = get_arg(arguments, 4)
            if not receiver or not asset_type or not count:
                self.help()
                return None

            asset_type = asset_type.upper() if check_support_asset_type(
                asset_type) else None
            if not asset_type:
                console_log.error(
                    "No support asset, current just support {}".format(
                        str(SupportAssetType.SupportAssetType)))
                return None

            if 0 >= count:
                console_log.warn('Not support negative number or zero.')
                return None

        # query channels by address
        channel_set = Channel.get_channel(self.Wallet.url, receiver,
                                          EnumChannelState.OPENED)
        if channel_set and channel_set[0]:
            Channel.transfer(channel_set[0].channel,
                             self.Wallet,
                             receiver,
                             asset_type,
                             count,
                             cli=True,
                             comments=hashcode,
                             trigger=RsmcMessage.create)
        else:
            if not hashcode:
                console_log.error("No hashcode")
                return None
            try:
                message = {
                    "MessageType": "GetRouterInfo",
                    "Sender": self.Wallet.url,
                    "Receiver": receiver,
                    "AssetType": asset_type,
                    "NetMagic": get_magic(),
                    "MessageBody": {
                        "AssetType": asset_type,
                        "Value": count
                    }
                }
                result = gate_way.get_router_info(message)
                routerinfo = json.loads(result.get("result"))
            except Exception as error:
                LOG.error(
                    'Exception occurred during get route info. Exception: {}'.
                    format(error))
                console_log.warning('No router was found.')
                return
            else:
                router = routerinfo.get("RouterInfo")
                if not router:
                    LOG.error('Router between {} and {} was not found.'.format(
                        self.Wallet.url, receiver))
                    console_log.error('Router not found for HTLC transfer.')
                    return

            full_path = router.get("FullPath")
            LOG.info("Get Router {}".format(str(full_path)))

            next_jump = router.get("Next")
            LOG.info("Get Next {}".format(str(next_jump)))
            fee_router = [
                i for i in full_path if i[0] not in (self.Wallet.url, receiver)
            ]
            if fee_router:
                # fee = reduce(lambda x, y:x+y,[TrinityNumber(str(i[1]).strip()).number for i in fee_router])
                fee = reduce(lambda x, y: x + y,
                             [float(i[1]) for i in fee_router])
            else:
                fee = 0

            fee = TrinityNumber(str(fee)).number
            count = int(count) + fee
            fee = fee / pow(10, 8)
            receiver = full_path[1][0]
            channel_set = Channel.get_channel(self.Wallet.url, receiver,
                                              EnumChannelState.OPENED)
            if not (channel_set and channel_set[0]):
                print('No OPENED channel was found for HTLC trade.')
                return
            LOG.info("Get Fee {}".format(fee))
            answer = prompt(
                "You will pay extra fee {}. Do you wish continue this transaction? [Yes/No]>"
                .format(fee))
            if answer.upper() in ["YES", "Y"]:
                channel_name = channel_set[0].channel
                Channel.transfer(channel_name,
                                 self.Wallet,
                                 receiver,
                                 asset_type,
                                 count,
                                 hashcode,
                                 router=full_path,
                                 next_jump=full_path[2][0],
                                 cli=True,
                                 trigger=HtlcMessage.create)

            else:
                return
Example #3
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