Esempio n. 1
0
    def execute(self,
                block_height,
                invoker='',
                channel_name='',
                invoker_key=''):
        """

        :param block_height:
        :param invoker_uri:
        :param channel_name:
        :param trade:
        :param invoker_key:
        :param gwei:
        :return:
        """
        super(ChannelEndSettleEvent, self).execute(block_height)

        # close channel event
        result = self.contract_event_api.end_close_channel(
            invoker, channel_name, invoker_key, gwei_coef=self.gwei_coef)

        # set channel settling
        if result is not None and 'success' in result.values():
            Channel.update_channel(self.channel_name,
                                   state=EnumChannelState.SETTLED.name)
            APIStatistics.update_statistics(
                self.wallet_address, state=EnumChannelState.SETTLED.name)
        self.next_stage()
Esempio n. 2
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)

            if 0 == self.role_index:
                need_update_balance, rsmc_sign_body = self.handle_partner_response()
            elif 1 == self.role_index:
                need_update_balance, rsmc_sign_body = self.handle_founder_response()
            else:
                raise GoTo(EnumResponseStatus.RESPONSE_FAIL, 'Invalid Role<{}> of RsmcResponse'.format(self.role_index))

            # send RsmcSign to peer
            if rsmc_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({'MessageBody': rsmc_sign_body})
                response_message.update({'Status': status.name})
                self.send(response_message)

            is_htlc_to_rsmc = self.is_hlock_to_rsmc(self.hashcode)
            if is_htlc_to_rsmc:
                # update the htlc transaction state.
                Channel.confirm_payment(self.channel_name, self.hashcode, is_htlc_to_rsmc)

            # update the channel balance
            if need_update_balance:
                APIStatistics.update_statistics(self.wallet.address, payment=self.payment, payer=(0==self.role_index))
                self.update_balance_for_channel(self.channel_name, self.asset_type, self.payer_address,
                                                self.payee_address, self.payment, is_htlc_to_rsmc)
        except GoTo as error:
            LOG.exception(error)
            status = error.reason
        except Exception as error:
            status = EnumResponseStatus.RESPONSE_EXCEPTION_HAPPENED
            LOG.exception('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
    def terminate(self, block_height, *args, asset_type='TNC'):
        super(ChannelQuickSettleEvent, self).terminate(block_height)

        # to check the total deposit of the channel
        total_deposit = self.contract_event_api.get_channel_total_balance(self.channel_name)
        if 0 >= total_deposit:
            Channel.update_channel(self.channel_name, state=EnumChannelState.CLOSED.name)
            APIStatistics.update_statistics(self.wallet_address, state=EnumChannelState.CLOSED.name)
            console_log.info('Channel {} state is {}'.format(self.channel_name, EnumChannelState.CLOSED.name))
            self.next_stage()
Esempio n. 4
0
    def execute(self,
                block_height,
                invoker_uri='',
                channel_name='',
                invoker_key='',
                nonce=None):
        """

        :param block_height:
        :param invoker_uri:
        :param channel_name:
        :param trade:
        :param invoker_key:
        :param gwei:
        :return:
        """
        super(ChannelUpdateSettleEvent, self).execute(block_height)

        # close channel event
        # ToDo uncomment below codes in future
        # latest_trade = Channel.latest_confirmed_trade()
        # if isinstance(nonce, int) and int(nonce) == latest_trade.nonce: # or check balance:
        #     self.next_stage()
        #     return

        result = Channel.force_release_rsmc(
            invoker_uri,
            channel_name,
            nonce,
            invoker_key,
            gwei_coef=self.gwei_coef,
            trigger=self.contract_event_api.update_close_channel)

        # set channel settling
        if result is not None and 'success' in result.values():
            Channel.update_channel(self.channel_name,
                                   state=EnumChannelState.SETTLED.name)
            APIStatistics.update_statistics(
                self.wallet_address, state=EnumChannelState.SETTLED.name)
        self.next_stage()
Esempio n. 5
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))
    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 > 0:
            Channel.update_channel(self.channel_name, state=EnumChannelState.OPENED.name)
            Channel.update_trade(self.channel_name, self.nonce, state=EnumTradeState.confirmed.name)
            APIStatistics.update_statistics(self.wallet_address, state=EnumChannelState.OPENED.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()
Esempio n. 7
0
    def create(wallet,
               channel_name,
               asset_type,
               founder,
               founder_deposit,
               partner,
               partner_deposit,
               founder_commitment,
               comments=None):
        """

        :param wallet:
        :param channel_name:
        :param asset_type:
        :param founder:
        :param founder_deposit:
        :param partner:
        :param partner_deposit:
        :param founder_commitment:
        :param comments:
        :return:
        """
        # check the deposit
        founder_deposit = int(founder_deposit)
        partner_deposit = int(partner_deposit)
        FounderResponsesMessage.check_deposit(founder_deposit, partner_deposit)

        nonce = FounderResponsesMessage._FOUNDER_NONCE
        # start to sign content
        founder_address, _, _ = uri_parser(founder)
        partner_address, _, _ = uri_parser(partner)
        # Sign this data to the
        commitment = FounderResponsesMessage.sign_content(
            wallet, FounderResponsesMessage._sign_type_list, [
                channel_name, nonce, founder_address, founder_deposit,
                partner_address, partner_deposit
            ])

        # start add channel
        deposit = {
            founder_address: {
                asset_type: str(founder_deposit)
            },
            partner_address: {
                asset_type: str(partner_deposit)
            }
        }
        hlock = {
            founder_address: {
                asset_type: '0'
            },
            partner_address: {
                asset_type: '0'
            }
        }
        Channel.add_channel(channel=channel_name,
                            src_addr=founder,
                            dest_addr=partner,
                            state=EnumChannelState.INIT.name,
                            deposit=deposit,
                            hlock=hlock,
                            magic=get_magic())

        APIStatistics.update_statistics(wallet.address,
                                        state=EnumChannelState.INIT.name)

        # add trade to database
        founder_trade = Channel.founder_trade(
            type=EnumTradeType.TRADE_TYPE_FOUNDER,
            role=EnumTradeRole.TRADE_ROLE_PARTNER,
            asset_type=asset_type,
            balance=partner_deposit,
            peer_balance=founder_deposit,
            commitment=commitment,
            peer_commitment=founder_commitment,
            state=EnumTradeState.confirming)
        Channel.add_trade(channel_name, nonce=nonce, **founder_trade)

        # create messages
        asset_type = asset_type.upper()
        message = FounderResponsesMessage.create_message_header(
            partner, founder, FounderResponsesMessage._message_name,
            channel_name, asset_type, nonce)
        message_body = {"Commitment": commitment}
        message.update({"MessageBody": message_body})

        # Add comments in the messages
        if comments:
            message.update({"Comments": comments})

        # fill message status
        message.update({'Status': EnumResponseStatus.RESPONSE_OK.name})
        # send message to peer
        FounderResponsesMessage.send(message)

        return
Esempio n. 8
0
    def create(wallet,
               channel_name,
               asset_type,
               founder,
               founder_deposit,
               partner,
               partner_deposit=None,
               comments=None):
        """

        :param wallet:
        :param channel_name:
        :param asset_type:
        :param founder:
        :param founder_deposit:
        :param partner:
        :param partner_deposit:
        :param comments:
        :return:
        """
        founder_deposit = int(founder_deposit)
        if partner_deposit is None:
            partner_deposit = founder_deposit
        partner_deposit = int(partner_deposit)

        # check the deposit
        FounderMessage.check_deposit(founder_deposit, partner_deposit)

        # get addresses of peers
        nonce = FounderMessage._FOUNDER_NONCE
        founder_address, _, _ = uri_parser(founder)
        partner_address, _, _ = uri_parser(partner)

        # Sign this data to hash value
        commitment = FounderMessage.sign_content(
            wallet, FounderMessage._sign_type_list, [
                channel_name, nonce, founder_address, founder_deposit,
                partner_address, partner_deposit
            ])

        # add channel
        asset_type = asset_type.upper()
        deposit = {
            founder_address: {
                asset_type: str(founder_deposit)
            },
            partner_address: {
                asset_type: str(partner_deposit)
            }
        }
        hlock = {
            founder_address: {
                asset_type: '0'
            },
            partner_address: {
                asset_type: '0'
            }
        }
        Channel.add_channel(channel=channel_name,
                            src_addr=founder,
                            dest_addr=partner,
                            state=EnumChannelState.INIT.name,
                            deposit=deposit,
                            magic=get_magic(),
                            hlock=hlock)

        APIStatistics.update_statistics(wallet.address,
                                        state=EnumChannelState.INIT.name)

        # record the transaction
        founder_trade = Channel.founder_trade(
            type=EnumTradeType.TRADE_TYPE_FOUNDER,
            role=EnumTradeRole.TRADE_ROLE_FOUNDER,
            asset_type=asset_type,
            balance=founder_deposit,
            peer_balance=partner_deposit,
            commitment=commitment)
        Channel.add_trade(channel_name, nonce=nonce, **founder_trade)

        # create founder request message
        message = FounderMessage.create_message_header(
            founder, partner, FounderMessage._message_name, channel_name,
            asset_type, nonce)
        message_body = {
            "FounderDeposit": str(founder_deposit),
            "PartnerDeposit": str(partner_deposit),
            "Commitment": commitment,
        }
        message.update({'MessageBody': message_body})

        # Add comments in the messages
        if comments:
            message.update({"Comments": comments})

        FounderMessage.send(message)
        return
Esempio n. 9
0
    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__())
                }
Esempio n. 10
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))
Esempio n. 11
0
    def create(channel_name, asset_type, sender, receiver, payment, hashcode=None, comments=None):
        """

        :param channel_name:
        :param asset_type:
        :param sender:
        :param receiver:
        :param payment:
        :param hashcode:
        :param comments:
        :param hlock_to_rsmc:
        :return:
        """
        # check channel state
        RsmcMessage.check_asset_type(asset_type)
        channel = RsmcMessage.check_channel_state(channel_name)
        payer_address, _, _ = uri_parser(sender)
        payee_address, _, _ = uri_parser(receiver)
        asset_type = asset_type.upper()
        resign_body = None

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

        # to check whether there's a transaction which is needed to resign
        resign_body, valid_trade = RsmcMessage.create_resign_message_body(sender, channel_name, nonce)

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

        # judge whether it is htlc lock part to rsmc trade or not
        hlock_to_rsmc = RsmcMessage.is_hlock_to_rsmc(hashcode)
        _, payer_balance, payee_balance = RsmcBase.calculate_balance_after_payment(
            payer_balance, payee_balance, payment, hlock_to_rsmc=hlock_to_rsmc
        )

        # sign the trade
        sign_hashcode, sign_rcode = RsmcMessage.get_rcode(channel_name, hashcode)
        rsmc_trade = Channel.rsmc_trade(
            type=EnumTradeType.TRADE_TYPE_RSMC, role=EnumTradeRole.TRADE_ROLE_FOUNDER, asset_type=asset_type,
            balance=payer_balance, peer_balance=payee_balance, payment=payment,
            hashcode=sign_hashcode, rcode=sign_rcode
        )

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

        # start to create message
        message = RsmcMessage.create_message_header(sender, receiver, RsmcMessage._message_name,
                                                    channel_name, asset_type, nonce)
        message.update({'MessageBody': rsmc_request})
        if comments:
            message.update({'Comments': comments})

        RsmcMessage.send(message)

        # record the transaction
        Channel.add_trade(channel_name, nonce=nonce, **rsmc_trade)
        APIStatistics.update_statistics(payer_address, rsmc='rsmc')

        return None
Esempio n. 12
0
    def handle(self):
        super(RsmcMessage, self).handle()

        status = EnumResponseStatus.RESPONSE_OK
        resign_ack = None
        resign_request = None
        try:
            # common check
            self.check_channel_state(self.channel_name)
            self.verify()

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

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

            rsmc_sign_body = self.response(self.asset_type, self.payment, self.sender_balance, self.receiver_balance,
                                           self.rsmc_sign_role, self.hashcode)

            # record the transaction without any signature
            sign_hashcode, sign_rcode = self.get_rcode(self.channel_name, self.hashcode)
            rsmc_trade = Channel.rsmc_trade(
                type=EnumTradeType.TRADE_TYPE_RSMC, role=EnumTradeRole.TRADE_ROLE_PARTNER, asset_type=self.asset_type,
                balance=self.receiver_balance, peer_balance=self.sender_balance, payment=self.payment,
                hashcode=sign_hashcode, rcode=sign_rcode
            )

            # if need resign, just send resign message body
            if resign_request:
                # add resign body to message body
                rsmc_sign_body.update({'ResignBody': resign_request})
            else:
                # check the balance
                htlc_to_rsmc = self.is_hlock_to_rsmc(self.hashcode)
                _, payer_balance, payee_balance = self.check_balance(
                    self.channel_name, self.asset_type, self.payer_address, self.sender_balance,
                    self.payee_address, self.receiver_balance, hlock_to_rsmc=htlc_to_rsmc, payment=self.payment
                )

                # sign the trade
                commitment = RsmcResponsesMessage.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]
                )

                # update the rsmc_trade
                rsmc_trade.update({'commitment': commitment, 'state':EnumTradeState.confirming.name})

                # update the message body with signature
                rsmc_sign_body.update({'Commitment': commitment})

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

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

            # record the transaction
            self.record_transaction(nonce, **rsmc_trade)
            APIStatistics.update_statistics(self.wallet.address, rsmc='rsmc')
        except TrinityException as error:
            status = error.reason
            LOG.exception(error)
        except Exception as error:
            status = EnumResponseStatus.RESPONSE_EXCEPTION_HAPPENED
            LOG.exception('Failed to handle RsmcMessage. Exception: {}'.format(error))
        finally:
            if EnumResponseStatus.RESPONSE_OK != status:
                # nofify error response
                RsmcResponsesMessage.send_error_response(self.sender, self.receiver, self.channel_name, self.asset_type,
                                                         self.nonce, status)

        return
Esempio n. 13
0
    def force_release_rsmc(cls,
                           uri=None,
                           channel_name=None,
                           nonce=None,
                           sign_key=None,
                           gwei_coef=1,
                           trigger=None,
                           is_debug=False):
        """

        :param uri:
        :param channel_name:
        :param nonce:
        :param sign_key:
        :param gwei_coef:
        :param trigger:
        :return:
        """
        if not (uri and channel_name and sign_key and trigger):
            LOG.warn(
                'uri<{}>, channel_name<{}>, trigger<{}> and sign_key should not be none'
                .format(uri, channel_name, trigger))
            return None

        try:
            # get records by nonce from the trade history
            if is_debug and nonce is not None:
                trade = cls.query_trade(channel_name, int(nonce))
            else:
                trade = cls.latest_confirmed_trade(channel_name)
                latest_nonce = int(trade.nonce)
                if nonce is not None and (latest_nonce == int(nonce)
                                          or int(nonce) > latest_nonce + 1):
                    LOG.debug(
                        'No need update transaction. nonce<{}>, latest_nonce<{}>'
                        .format(nonce, latest_nonce))
                    # update the channel to settling state
                    Channel.update_channel(
                        channel_name, state=EnumChannelState.SETTLING.name)
                    release_invoker, _, _ = uri_parser(uri)
                    APIStatistics.update_statistics(
                        release_invoker, state=EnumChannelState.SETTLED.name)
                    return None
                nonce = latest_nonce
        except Exception as error:
            LOG.exception('No trade record could be forced to release. channel<{}>, nonce<{}>. Exception: {}' \
                      .format(channel_name, nonce, error))
        else:
            channel = cls(channel_name)
            peer_uri = channel.peer_uri(uri)
            self_address, _, _ = uri_parser(uri)
            peer_address, _, _ = uri_parser(peer_uri)

            LOG.debug('Force to close channel<{}> with nonce<{}>'.format(
                channel_name, nonce))
            LOG.debug('Trade nonce: {}'.format(trade.nonce))

            # get hashcode and rcode
            hashcode = None
            rcode = None
            if trade.nonce not in [0, 1]:
                hashcode = trade.hashcode
                rcode = trade.rcode

            trade_role = trade.role
            if EnumTradeRole.TRADE_ROLE_FOUNDER.name == trade_role:
                result = trigger(self_address, channel_name, nonce,
                                 self_address, trade.balance, peer_address,
                                 trade.peer_balance, hashcode, rcode,
                                 trade.commitment, trade.peer_commitment,
                                 sign_key, gwei_coef)
            else:
                result = trigger(self_address, channel_name, nonce,
                                 peer_address, trade.peer_balance,
                                 self_address, trade.balance, hashcode, rcode,
                                 trade.peer_commitment, trade.commitment,
                                 sign_key, gwei_coef)

            return result

        return None