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))
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
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