def ucoro_event(coro, iter_data): try: coro.send(iter_data) except StopIteration as error: LOG.debug('Co-routine has been killed.') except Exception as error: LOG.exception('Error occurred during using co-routine. error: {}'.format(error))
def update_close_channel(cls, invoker, channel_id, nonce, founder, founder_balance, partner, partner_balance, lock_hash, lock_secret, founder_signature, partner_signature, invoker_key, gwei_coef=1): try: result = cls._eth_interface.update_transaction( invoker, channel_id, nonce, founder, int(founder_balance), partner, int(partner_balance), lock_hash, lock_secret, founder_signature, partner_signature, invoker_key, gwei_coef=gwei_coef) LOG.debug('update_close_channel result: {}'.format(result)) return result except Exception as error: LOG.error('update_close_channel error: {}'.format(error)) return None
def handle(self): """ :return: """ old_block = get_block_count() - 1 _event_coroutine = self.timer_event() next(_event_coroutine) self.prepare_handle_event() while WebSocketConnection._websocket_listening: try: response = self.receive() block_height = get_block_count() # handle response self.handle_event(block_height, response) # handle timer event if old_block != block_height: for block in range(old_block + 1, block_height + 1): ucoro_event(_event_coroutine, block) # set new value to old_block old_block = block_height time.sleep(0.5) except Exception as error: LOG.debug('websocket handle: {}'.format(error)) time.sleep(1) ucoro_event(_event_coroutine, None)
def approve(cls, address, deposit, private_key, gwei_coef=1): """ :param address: :param deposit: :param private_key: :param gwei_coef: :return: """ deposit = int(deposit) # approved_asset = cls.get_approved_asset(address) # # if approved_asset >= deposit: # LOG.info('Has been approved asset count: {}'.format(approved_asset)) # return True try: # return tx_id tx_id = cls._eth_interface.approve(address, deposit, private_key, gwei_coef=gwei_coef) LOG.debug( 'ContractEventInterface::approve: txId: {}'.format(tx_id)) return tx_id except Exception as error: LOG.error('authorized deposit error: {}'.format(error)) return False
def htlc_unlock_payment(cls, invoker, channel_id, founder, partner, lock_period, lock_amount, lock_hash, founder_signature, partner_signature, lock_secret, invoker_key, gwei_coef=1): try: result = cls._eth_interface.withdraw(invoker, channel_id, founder, partner, int(lock_period), int(lock_amount), lock_hash, founder_signature, partner_signature, lock_secret, invoker_key, gwei_coef=gwei_coef) LOG.debug('htlc_unlock_payment result: {}'.format(result)) return result except Exception as error: LOG.error('htlc_unlock_payment error: {}'.format(error)) return None
def contruct_transaction(self, invoker, contract, method, args, key, gwei_coef=None, gasLimit=4500000): """""" try: # pre-check the transaction estimate_gas = contract.functions[method](*args).estimateGas( {'from': checksum_encode(invoker)}) gasLimit = estimate_gas + 5000 + randint(1, 10000) except Exception as error: LOG.debug('Failed to execute {}. Exception: {}'.format( method, error)) LOG.info('the parameters are : {}'.format(args)) finally: LOG.debug('Estimated to spend {} gas'.format(gasLimit)) tx_dict = contract.functions[method](*args).buildTransaction({ 'gas': gasLimit, 'gasPrice': pow(10, 9) * gwei_coef, 'nonce': self.web3.eth.getTransactionCount(checksum_encode(invoker)), }) signed = self.web3.eth.account.signTransaction(tx_dict, key) tx_id = self.web3.eth.sendRawTransaction(signed.rawTransaction) return binascii.hexlify(tx_id).decode()
def prepare(self, block_height, address='', deposit=0.0, key=''): super(ChannelDepositEvent, self).prepare(block_height) # if this transaction id is approved, it means successful by eth block chain if self.approved_tx_id: checked = self.check_transaction_success(self.approved_tx_id) if checked: LOG.debug('Approved asset by address<{}:{}>'.format(address, deposit)) Channel.update_channel(self.channel_name, state=EnumChannelState.OPENING.name) LOG.info('Start to create channel<{}>. State: OPENING.'.format(self.channel_name)) console_log.info('Channel<{}> is opening'.format(self.channel_name)) # go to next stage self.next_stage() return True elif checked is False: return False else: # new transaction is pushed to chain self.approved_tx_id = None else: approved_deposit = self.contract_event_api.get_approved_asset(address) if approved_deposit >= int(deposit): LOG.debug('Has already approved: {}'.format(approved_deposit)) # go to next stage self.next_stage() return True # make transaction to chain result = self.contract_event_api.approve(address, int(deposit), key, gwei_coef=self.gwei_coef) if result: self.approved_tx_id = '0x'+result.strip() return False
def notify_rcode_to_next_peer(self, next_channel): """ :param next_channel: :return: """ peer = None try: # original payer is found if not next_channel: 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 next_channel != htlc_trade.channel: LOG.error('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) 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) except Exception as error: LOG.error('Failed to notify RCode<{}> to peer<{}>'.format( self.rcode, peer))
def monitorCloseChannel(self, message): """ :param message: :return: message like below format: { 'playload': '0xabf328663edff39bfa3f157556afa52bdcb14fda32d35c70e6e3386e954e7995', 'txId': '0xc0461c9a92a295eec4dd1060e4abd34bbb1c8139e2b9bc5e35e7c2daa1dccfc5', 'channelId': '0xabf328663edff39bfa3f157556afa52bdcb14fda32d35c70e6e3386e954e7995', 'invoker': '0x23cca051bfedb5e17d3aad2038ba0a5155d1b1b7', 'nonce': 5, 'blockNumber': 3924231, 'messageType': 'monitorCloseChannel' } """ if not message: LOG.error('Invalid message: {}'.format(message)) return try: invoker = message.get('invoker').strip() channel_name = message.get('channelId') nonce = message.get('nonce') end_time = int(message.get('blockNumber')) except Exception as error: LOG.exception('Invalid message: {}. Exception: {}'.format( message, error)) else: if not (self.wallet_address and invoker): LOG.error( 'Wallet address<{}> or invoker<{}> should not be none'. format(self.wallet_address, invoker)) return if invoker != self.wallet_address.lower(): channel_event = ChannelUpdateSettleEvent( channel_name, self.wallet_address) channel_event.register_args( EnumEventAction.EVENT_EXECUTE, self.wallet.url, channel_name, self.wallet._key.private_key_string, nonce) event_machine.register_event(channel_name, channel_event) event_machine.trigger_start_event(channel_name) else: LOG.debug('register ChannelEndSettleEvent at block<{}>'.format( end_time)) channel_event = ChannelEndSettleEvent(channel_name, self.wallet_address) channel_event.register_args( EnumEventAction.EVENT_EXECUTE, invoker, channel_name, self.wallet._key.private_key_string) self.register_event(channel_event, end_time) return
def timer_event(self, received=None): if not received: return LOG.debug('Handle timer event at block<{}>'.format(received)) event_list = self.get_event(received) for event in event_list: # move this event to event machine event_machine.register_event(event.channel_name, event) event_machine.trigger_start_event(event.channel_name)
def end_close_channel(cls, invoker, channel_id, invoker_key, gwei_coef=1): try: result = cls._eth_interface.settle_transaction(invoker, channel_id, invoker_key, gwei_coef=gwei_coef) LOG.debug('end_close_channel result: {}'.format(result)) return result except Exception as error: LOG.error('end force_settle error: {}'.format(error)) return None
def wrapper(*args, **kwargs): try: payload = callback(*args, **kwargs) payload.update({'chainType': 'ETH'}) if not payload.get('walletAddress'): payload.update({'walletAddress': ws_instance.wallet_address}) except Exception as error: LOG.error('Call {} error: {}'.format(callback.__name__, error)) else: # to send the data by wwebsocket connection LOG.debug('Register event<{}> to full-node'.format(payload)) ws_instance.send(json.dumps(payload))
def sign_content(cls, start=3, *args, **kwargs): """ :return: """ typeList = args[0] if 0 < len(args) else kwargs.get('typeList') valueList = args[1] if 1 < len(args) else kwargs.get('valueList') privtKey = args[2] if 2 < len(args) else kwargs.get('privtKey') content = cls._eth_client.sign_args(typeList, valueList, privtKey) LOG.debug('Sign_content<{}> with value<{}>'.format(content, valueList)) return '0x' + content
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
def execute(self, block_height, address='', channel_id='', nonce='', founder='', deposit=0, partner='', partner_deposit=0, founder_sign='', partner_sign='', private_key=''): super(ChannelDepositEvent, self).execute(block_height) # update the founder and partner deposit self.deposit = int(deposit) self.partner_deposit = int(partner_deposit) # execute stage of channel event try: # if this wallet is not the event founder, go to next step directly. if not self.is_event_founder: self.next_stage() return True # below codes is just executed by the founder # check whether deposit is success or not if self.deposit_tx_id: checked = self.check_transaction_success(self.deposit_tx_id) if checked: # go to next stage self.next_stage() return True elif checked is False: return False else: # new transaction is pushed to chain self.deposit_tx_id = None # get approved asset of both partners peer_approved_deposit = self.contract_event_api.get_approved_asset(partner) approved_deposit = self.contract_event_api.get_approved_asset(founder) LOG.debug('Approved asset in wallet<{}>: founder<{}:{}>, partner<{}:{}>' \ .format(address, founder, approved_deposit, partner, peer_approved_deposit)) # check approved asset of both side for event founder. if not (approved_deposit >= self.deposit and peer_approved_deposit >= self.partner_deposit): return False # Trigger deposit action if is_event_founder is True result = self.deposit_tx_id = self.contract_event_api.approve_deposit( address, channel_id, nonce, founder, deposit, partner, partner_deposit, founder_sign, partner_sign, private_key, gwei_coef=self.gwei_coef) if result: self.deposit_tx_id = '0x'+result.strip() except Exception as error: LOG.exception('Failed to approve deposit of Channel<{}>. Exception: {}'.format(self.channel_name, error)) return False
def monitorWithdraw(self, message): """ :param message: :return: """ if not message: LOG.error('Invalid message: {}'.format(message)) return try: invoker = message.get('invoker').strip() channel_name = message.get('channelId') hashcode = message.get('lockHash') rcode = message.get('secret') end_time = int(message.get('blockNumber')) except Exception as error: LOG.exception('Invalid message: {}. Exception: {}'.format( message, error)) else: if not (self.wallet_address and invoker): LOG.error('monitorWithdraw: Wallet address<{}> or invoker<{}> should not be none' \ .format(self.wallet_address, invoker)) return if invoker != self.wallet_address.lower(): channel_event = ChannelPunishHtlcUnlockEvent(channel_name) channel_event.register_args( EnumEventAction.EVENT_EXECUTE, self.wallet.url, channel_name, hashcode, rcode, self.wallet._key.private_key_string) event_machine.register_event(channel_name, channel_event) event_machine.trigger_start_event(channel_name) else: LOG.debug( 'monitorWithdraw: register ChannelEndSettleEvent at next block' ) channel_event = ChannelSettleHtlcUnlockEvent(channel_name) channel_event.register_args( EnumEventAction.EVENT_EXECUTE, invoker, channel_name, hashcode, self.wallet._key.private_key_string) self.register_event(channel_event, end_time) return
def settle_after_htlc_unlock_payment(cls, invoker, channel_id, lock_hash, invoker_key, gwei_coef=1): """""" try: result = cls._eth_interface.withdraw_settle(invoker, channel_id, lock_hash, invoker_key, gwei_coef=gwei_coef) LOG.debug( 'settle_after_htlc_unlock_payment result: {}'.format(result)) return result except Exception as error: LOG.error( 'settle_after_htlc_unlock_payment error: {}'.format(error)) return None
def __coroutine_handler(self, *args, **kwargs): if not args: LOG.debug('No event is received.') return received_event = args[0] # for console event, there are 3 parts: EnumConsoleTrigger type, args and kwargs self.event_type = received_event[0] argument = received_event[1] kwargument = received_event[2] if not EnumConsoleTrigger.__contains__(self.event_type): LOG.error('Console event<{}> type is undefined.'.format( self.event_type)) return # to call the event handler self.__dict__.get(self.event_type.name, self.error_handler)(*argument, **kwargument) return
def contruct_Transaction(self, invoker, contract, method, args, key, gwei_coef=None, gasLimit=4600000): """""" try: # pre-check the transaction precheck_arguments = [item for item in args if item] estimate_gas = contract.functions[method](*precheck_arguments).estimateGas({'from': invoker}) estimate_gas += 5000 + randint(1, 10000) except Exception as error: LOG.error('Failed to execute {}. Use default gasLimit: 4600000. Exception: {}'.format(method, error)) estimate_gas = gasLimit finally: LOG.debug('Estimated to spend {} gas'.format(estimate_gas)) tx_dict = contract.functions[method](*args).buildTransaction({ 'gas': estimate_gas, 'gasPrice': pow(10, 9) * gwei_coef, 'nonce': self.web3.eth.getTransactionCount(checksum_encode(invoker)), }) signed = self.web3.eth.account.signTransaction(tx_dict, key) tx_id = self.web3.eth.sendRawTransaction(signed.rawTransaction) return binascii.hexlify(tx_id).decode()
def execute(self, block_height, invoker_uri='', channel_name='', hashcode='', rcode='', invoker_key='', is_debug=False): """ :param block_height: :param invoker_uri: :param channel_name: :param hashcode: :param rcode: :param invoker_key: :param is_debug: :return: """ super(ChannelHtlcUnlockEvent, self).execute(block_height) LOG.debug('unlock htlc payment parameter: {}, {}, {}'.format( invoker_uri, channel_name, hashcode)) LOG.debug('unlock htlc payment event args: {}, kwargs {}' \ .format(self.event_arguments.args, self.event_arguments.kwargs)) # close channel event result = Channel.force_release_htlc( invoker_uri, channel_name, hashcode, rcode, invoker_key, gwei_coef=self.gwei_coef, trigger=self.contract_event_api.htlc_unlock_payment, is_debug=is_debug) # Don't close channel if result and 'success' in result.values(): self.next_stage()
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)
def execute(self, block_height, invoker_uri='', channel_name='', nonce=None, invoker_key='', is_debug=False): """ :param block_height: :param invoker_uri: :param channel_name: :param trade: :param invoker_key: :param gwei: :return: """ super(ChannelForceSettleEvent, self).execute(block_height) LOG.debug('parameter: {}, {}, {}, {}'.format(invoker_uri, channel_name, nonce, invoker_key)) LOG.debug('event args: {}, kwargs'.format(self.event_arguments.args, self.event_arguments.kwargs)) # close channel event result = Channel.force_release_rsmc( invoker_uri, channel_name, nonce, invoker_key, gwei_coef=self.gwei_coef, trigger=self.contract_event_api.close_channel, is_debug=is_debug) # set channel settling if result is not None and 'success' in result.values(): Channel.update_channel(self.channel_name, state=EnumChannelState.SETTLED.name) self.next_stage()
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))
def generate_payment_code(cls, receiver, asset_type, value, hashcode, comments='', cli=False): """""" if 0 >= int(value): console_log.error('Not support negative number.') return if not IS_SUPPORTED_ASSET_TYPE(asset_type): text = 'AssetType: {} is not supported'.format(asset_type) LOG.error(text) if cli: console_log.error(text) return None asset_type = asset_type.replace('0x', '') if asset_type.upper() in SUPPORTED_ASSET_TYPE.keys(): asset_type = asset_type.upper() hashcode = hashcode.strip() code = "{uri}&{net_magic}&{hashcode}&{asset_type}&{payment}&{comments}".format( uri=receiver, net_magic=get_magic(), hashcode=hashcode, asset_type=asset_type, payment=value, comments=comments) base58_code = base58.b58encode(code.encode()) try: return "TN{}".format(base58_code.decode()) except Exception as error: LOG.debug('generate_payment_code error: {}'.format(error)) return "TN{}".format(base58_code)
def close_channel(cls, invoker, channel_id, nonce, founder, founder_balance, partner, partner_balance, lock_hash, lock_secret, founder_signature, partner_signature, invoker_key, gwei_coef=1): try: if 1 == nonce: lock_hash = cls.default_hash_and_secret lock_secret = cls.default_hash_and_secret result = cls._eth_interface.close_channel(invoker, channel_id, nonce, founder, int(founder_balance), partner, int(partner_balance), lock_hash, lock_secret, founder_signature, partner_signature, invoker_key, gwei_coef=gwei_coef) LOG.debug('close_channel result: {}'.format(result)) return result except Exception as error: LOG.exception('force_settle error: {}'.format(error)) return None
def terminate(self, block_height, *args, **kwargs): LOG.debug('{} stage of event<{}-{}> at block-{}'.format( self.stage_action, self.event_name, self.event_type_name, block_height)) return True
def prepare(self, block_height, *args, **kwargs): LOG.debug('{} stage of event<{}-{}> at block-{}'.format( self.stage_action, self.event_name, self.event_type_name, block_height)) self.set_event_start_time(int(block_height)) return True
def set_event_ready(self, ready=True): LOG.debug('set event<{}> ready'.format(self.event_name)) self.is_event_ready = ready
def json_rpc_method_handler(self, method, params): # if method == "SendRawtransaction": # return transaction.TrinityTransaction.sendrawtransaction(params[0]) if method == "TransactionMessage": LOG.info("<-- {}".format(params)) return MessageList.append(params) # elif method == "FunderTransaction": # return transaction.funder_trans(params) # elif method == "FunderCreate": # return transaction.funder_create(params) # elif method == "RSMCTransaction": # return transaction.rsmc_trans(params) # # elif method == "HTLCTransaction": # return transaction.hltc_trans(params) elif method == "SyncWallet": from wallet import prompt as PR wallet_info = PR.CurrentLiveWallet.wallet_info() return {"MessageType": "SyncWallet", "MessageBody": wallet_info} elif method == "GetChannelState": return { 'MessageType': 'GetChannelState', 'MessageBody': get_channel_via_name(params) } elif method == "GetChannelList": LOG.debug("GetChannelList") from wallet.utils import get_wallet_info if CurrentLiveWallet.Wallet: try: channel_list = query_channel_list( CurrentLiveWallet.Wallet.url) except Exception as e: channel_list = None LOG.error(e) wallet_info = get_wallet_info(CurrentLiveWallet.Wallet) return { "MessageType": "GetChannelList", "MessageBody": { "Channel": channel_list, "Wallet": wallet_info } } else: return { "MessageType": "GetChannelList", "MessageBody": { "Error": "Wallet No Open" } } elif method == "GetPayment": asset_type = params[0] payment = params[1] try: hash_r, rcode = Payment.create_hr() pycode = Payment.generate_payment_code( CurrentLiveWallet.Wallet.url, asset_type, payment, hash_r) Channel.add_payment(None, hash_r, rcode, payment) except Exception as e: LOG.error(e) pycode = None return { "MessageType": "GetPaymentAck", "MessageBody": { "pycode": pycode } } elif method == "GetWalletStatistics": try: statistics_data = APIStatistics.query_statistics(params[0])[0] except Exception as e: LOG.error(e) return { "MessageType": "GetWalletStatisticsAck", "MessageBody": { "Error": "data is null" } } else: return { "MessageType": "GetWalletStatisticsAck", "MessageBody": json.loads(statistics_data.__str__()) }
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) # To handle the founder and partner response by role index if 0 == self.role_index: need_update_balance, htlc_sign_body = self.handle_partner_response( ) elif 1 == self.role_index: need_update_balance, htlc_sign_body = self.handle_founder_response( ) else: raise GoTo( EnumResponseStatus.RESPONSE_TRADE_INCORRECT_ROLE, 'Invalid Role<{}> of HtlcResponse'.format(self.role_index)) # send HtlcSign to peer if htlc_sign_body: response_message = self.create_message_header( self.receiver, self.sender, self._message_name, self.channel_name, self.asset_type, self.nego_nonce or self.nonce) response_message.update({'Router': self.router}) response_message.update({'MessageBody': htlc_sign_body}) response_message.update({'Status': status.name}) self.send(response_message) # update the channel balance if need_update_balance: self.update_balance_for_channel(self.channel_name, self.asset_type, self.payer_address, self.payee_address, self.payment, is_htlc_type=True) # now we need trigger htlc to next jump if 1 == self.role_index: # trigger htlc or RResponse self.trigger_htlc_to_next_jump() except TrinityException as error: LOG.exception(error) status = error.reason except Exception as error: LOG.exception( '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)