예제 #1
0
    def calculate_balance_after_payment(cls,
                                        balance,
                                        peer_balance,
                                        payment,
                                        hlock_to_rsmc=False,
                                        is_htlc_type=False):
        """

        :param balance: payer's balance
        :param peer_balance: payee's balance
        :param payment:
        :param hlock_to_rsmc: exchange htlc lock part to rsmc transaction
        :return:
        """
        # if payment has occurred, calculate the balance after payment
        payment = int(payment)
        if 0 < payment <= int(balance):
            if hlock_to_rsmc:
                return True, int(balance), int(peer_balance) + payment
            elif is_htlc_type:
                return True, int(balance) - payment, int(peer_balance)
            else:
                return True, int(balance) - payment, int(
                    peer_balance) + payment
        elif payment > int(balance):
            raise GoTo(
                EnumResponseStatus.
                RESPONSE_TRADE_NO_ENOUGH_BALANCE_FOR_PAYMENT,
                'Sender has not enough balance<{}> for payment<{}>'.format(
                    balance, payment))
        else:
            raise GoTo(
                EnumResponseStatus.RESPONSE_TRADE_NEGATIVE_PAYMENT,
                'Payment<{}> should not be negative number.'.format(payment))
예제 #2
0
    def check_balance(cls,
                      channel_name,
                      asset_type,
                      address,
                      balance,
                      peer_address,
                      peer_balance,
                      hlock_to_rsmc=False,
                      is_htcl_type=False,
                      **kwargs):
        """

        :param channel_name:
        :param asset_type:
        :param address:
        :param balance:
        :param peer_address:
        :param peer_balance:
        :param hlock_to_rsmc:
        :param is_htcl_type:
        :param kwargs:
        :return:
        """
        try:
            # get channel if trade has already existed
            channel_set = Channel.query_channel(channel_name)[0]
            expected_balance = int(
                channel_set.balance.get(address).get(asset_type))
            expected_peer_balance = int(
                channel_set.balance.get(peer_address).get(asset_type))

            # to calculate the balance after payment
            if kwargs and kwargs.__contains__('payment'):
                _, expected_balance, expected_peer_balance = \
                    cls.calculate_balance_after_payment(expected_balance, expected_peer_balance,
                                                        kwargs.get('payment'), hlock_to_rsmc, is_htcl_type)

            if int(balance) == expected_balance and int(
                    peer_balance) == expected_peer_balance:
                return True, expected_balance, expected_peer_balance
            else:
                raise GoTo(
                    EnumResponseStatus.RESPONSE_TRADE_BALANCE_UNMATCHED_BETWEEN_PEERS,
                    'Channel<{}> balances are unmatched between channel peers<self: {}, expected: {}. peers: {}, expected: {}>' \
                    .format(channel_name, balance, expected_balance, peer_balance, expected_peer_balance))
        except Exception as error:
            raise GoTo(
                EnumResponseStatus.RESPONSE_TRADE_BALANCE_ERROR,
                'Channel<{}> not found or balance error. Exception: {}'.format(
                    channel_name, error))
예제 #3
0
    def sign_content(cls,
                     wallet,
                     sign_type_list,
                     sign_value_list,
                     *args,
                     start=3,
                     **kwargs):
        """

        :param wallet:
        :param sign_type_list:
        :param sign_value_list:
        :param args:
        :param start:
        :param kwargs:
        :return:
        """
        if not (wallet and sign_type_list and sign_value_list):
            raise GoTo(
                EnumResponseStatus.RESPONSE_ILLEGAL_INPUT_PARAMETER,
                'Lack of mandatory parameters: wallet<{}>, type_list<{}>, value_list<{}>' \
                    .format(wallet, sign_type_list, sign_value_list)
            )

        kwargs.update({
            'typeList': sign_type_list,
            'valueList': sign_value_list,
            'privtKey': wallet._key.private_key_string
        })

        return cls.contract_event_api().sign_content(start, *args, **kwargs)
예제 #4
0
    def check_role(cls, role):
        # row index related check
        if int(role) not in [0, 1]:
            raise GoTo(EnumResponseStatus.RESPONSE_TRADE_INCORRECT_ROLE,
                       'RsmcSign with illegal role index<{}>'.format(role))

        return True
예제 #5
0
 def verify_hr(cls, hashcode, rcode):
     try:
         rcode = rcode.replace('0x', '').strip()
         return hashcode.__contains__(cls.hash_r(rcode).__str__())
     except Exception as error:
         raise GoTo('Invalid RCode<{}> for HashR<{}>. Exception: {}'.format(
             rcode, hashcode, error))
예제 #6
0
    def validate_transaction(self):
        """

        :return:
        """
        # check the trade with nonce existed or not
        try:
            pre_trade = Channel.query_trade(self.channel_name, self.nonce - 1)
        except Exception as error:
            # should never go here
            raise (
                EnumResponseStatus.RESPONSE_TRADE_NOT_FOUND,
                'Transaction with nonce<{}> is not found'.format(self.nonce -
                                                                 1))
        else:
            if pre_trade.state in [
                    EnumTradeState.confirmed.name
                    or EnumTradeState.confirmed_onchain.name
            ]:
                return True
            elif pre_trade.state in [EnumTradeState.confirming.name] \
                    and EnumTradeType.TRADE_TYPE_HTLC.name == pre_trade.type \
                    and pre_trade.peer_commitment and pre_trade.peer_delay_commitment:
                return True

            raise GoTo(
                EnumResponseStatus.
                RESPONSE_TRADE_RESIGN_REQUEST_NOT_IMPLEMENTED,
                'Wait for next resign. current confirmed nonce<{}>, request nonce<{}>'
                .format(Channel.latest_confirmed_nonce(), self.nonce))
예제 #7
0
    def check_nonce(cls, nonce, channel_name='', is_founder=False):
        """

        :param channel_name:
        :param nonce:
        :return:
        """
        nonce = int(nonce)
        nego_trade = Channel.query_trade(channel_name, nonce)
        pre_trade = Channel.query_trade(channel_name, nonce - 1)

        # to check whether the nonce is legal one or not
        if not (TransactionBase._FOUNDER_NONCE < nonce and pre_trade.state in [
                EnumTradeState.confirmed.name,
                EnumTradeState.confirmed_onchain.name
        ] and (
            (nego_trade.state in [EnumTradeState.init.state] and is_founder) or
            (nego_trade.state in [EnumTradeState.confirming.state]
             and not is_founder))):
            raise GoTo(
                EnumResponseStatus.RESPONSE_TRADE_WITH_INCOMPATIBLE_NONCE,
                '{}::Channel<{}> has incompatible nonce<{}>, state<previous:{}, negotiated: {}>' \
                    .format(cls.__name__, channel_name, nonce, pre_trade.state, nego_trade.state))
        else:
            return True, nego_trade
예제 #8
0
    def check_router(self, router, hashcode):
        if not router:
            raise GoTo(
                EnumResponseStatus.RESPONSE_ROUTER_VOID_ROUTER,
                'Router<{}> NOT found for htlc trade with HashR<{}>'.format(
                    router, hashcode))

        return True
예제 #9
0
    def check_deposit(cls, founder_deposit: int, partner_deposit: int):
        if not (0 <= partner_deposit <= founder_deposit
                and 0 < founder_deposit):
            raise  GoTo(EnumResponseStatus.RESPONSE_FOUNDER_DEPOSIT_LESS_THAN_PARTNER,
                        'Founder deposit<{}> should not be less than partner\'s deposit<{}>'. \
                        format(founder_deposit,partner_deposit))

        return True
예제 #10
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
예제 #11
0
    def check_channel_state(cls, channel_name):
        channel = Channel(channel_name)

        if not channel.is_opened:
            raise GoTo(
                EnumResponseStatus.RESPONSE_CHANNEL_NOT_OPENED,
                'Channel is not OPENED. Current tate<{}>'.format(
                    channel.state))

        return channel
예제 #12
0
 def check_hashcode_used(cls, channel_name, hashcode):
     try:
         trade_record = Channel.batch_query_trade(
             channel_name, filters={'hashcode': hashcode})[0]
     except Exception as error:
         return True
     else:
         raise GoTo(
             EnumResponseStatus.RESPONSE_TRADE_HASHR_ALREADY_EXISTED,
             'HashR<{}> already used by trade with nonce<{}>'.format(
                 hashcode, trade_record.nonce))
예제 #13
0
    def check_asset_type(cls, asset_type):
        """

        :param asset_type:
        :return:
        """
        if not IS_SUPPORTED_ASSET_TYPE(asset_type):
            raise GoTo(EnumResponseStatus.RESPONSE_ASSET_TYPE_NOT_SUPPORTED,
                       'Unsupported Asset type: \'{}\''.format(asset_type))

        return True, None
예제 #14
0
    def check_url_format(cls, wallet_url):
        """

        :param wallet_url:
        :return:
        """
        # TODO: it's better to use regex expression to check the url's validity
        if not wallet_url.__contains__('@'):
            raise GoTo(
                EnumResponseStatus.RESPONSE_INVALID_URL_FORMAT,
                'Invalid format of url<{}>. Should be like 0xYYYY@ip:port'.
                format(wallet_url))
예제 #15
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
예제 #16
0
    def check_nonce(cls, nonce, **kwargs):
        """

        :param nonce:
        :param kwargs:
        :return:
        """
        if FounderBase._FOUNDER_NONCE != int(nonce):
            raise GoTo(
                EnumResponseStatus.RESPONSE_FOUNDER_WITH_ILLEGAL_NONCE,
                'Founder with invalid nonce<{}>. Must be one'.format(nonce))

        return True
예제 #17
0
    def check_signature(cls, wallet, type_list, value_list, signature):
        """"""
        if not (wallet and type_list and value_list and signature):
            raise GoTo(
                EnumResponseStatus.RESPONSE_ILLEGAL_INPUT_PARAMETER,
                'Illegal input parameters: type_list<{}>, value_list<{}>, signature<{}>' \
                    .format(type_list, value_list, signature)
            )

        sign_hash = cls.contract_event_api().solidity_hash(
            type_list, value_list)
        return wallet.address == wallet.recoverHash(sign_hash,
                                                    signature=signature)
예제 #18
0
    def check_rcode(cls, hashcode, rcode):
        """

        :param hashcode:
        :param rcode:
        :return:
        """
        if Payment.verify_hr(hashcode, rcode):
            return True
        else:
            raise GoTo(
                EnumResponseStatus.RESPONSE_TRADE_HASHR_NOT_MATCHED_WITH_RCODE,
                'HashR<{}> is not compatible with Rcode<{}>'.format(
                    hashcode, rcode))
예제 #19
0
    def check_network_magic(cls, magic):
        """

        :param magic:
        :return:
        """
        net_magic = get_magic()
        if net_magic != magic:
            raise GoTo(
                EnumResponseStatus.RESPONSE_INVALID_NETWORK_MAGIC,
                'Invalid network ID<{}>. should be equal to {}'.format(
                    magic, net_magic))

        return True, net_magic
예제 #20
0
    def check_signature(cls, wallet, expected, type_list, value_list,
                        signature):
        """"""
        if not (wallet and type_list and value_list and signature):
            raise GoTo(
                EnumResponseStatus.RESPONSE_ILLEGAL_INPUT_PARAMETER,
                'Illegal input parameters: type_list<{}>, value_list<{}>, signature<{}>' \
                    .format(type_list, value_list, signature)
            )

        sign_hash = cls.contract_event_api().solidity_hash(
            type_list, value_list)
        peer_wallet_address = wallet.recoverHash(sign_hash, signature)

        if expected == peer_wallet_address:
            return True
        else:
            LOG.error(
                'Error data hash<{}> with value<{}> by signature<{}>'.format(
                    binascii.b2a_hex(sign_hash), value_list, signature))
            raise GoTo(
                EnumResponseStatus.RESPONSE_SIGNATURE_VERIFIED_ERROR,
                'Signature verification error: expected<{}>, parsed-address<{}>'
                .format(expected, peer_wallet_address))
예제 #21
0
    def check_nonce(cls, nonce, **kwargs):
        """

        :param nonce:
        :param kwargs:
        :return:
        """
        if SettleBase._SETTLE_NONCE != int(nonce):
            raise GoTo(
                EnumResponseStatus.
                RESPONSE_QUICK_CLOSE_CHANNEL_WITH_ILLEGAL_NONCE,
                'Quick close channel with invalid nonce<{}>. Must be zero'.
                format(nonce))

        return True
예제 #22
0
    def check_nonce(cls, nonce, channel_name=''):
        """

        :param channel_name:
        :param nonce:
        :return:
        """
        new_nonce = Channel.new_nonce(channel_name)

        if not (TransactionBase._FOUNDER_NONCE < int(nonce) == new_nonce):
            raise GoTo(
                EnumResponseStatus.RESPONSE_TRADE_WITH_INCOMPATIBLE_NONCE,
                '{}::Channel<{}> has incompatible nonce<self: {}, peer: {}>'.
                format(cls.__name__, channel_name, new_nonce, nonce))
        else:
            return True, new_nonce
예제 #23
0
    def check_both_urls(cls, sender, receiver):
        """

        :param sender:
        :param receiver:
        :return:
        """
        # check whether the sender and receiver are correct url or not
        # TODO: it's better to use regex expression to check the url's validity
        try:
            return sender.__contains__('@') and receiver.__contains__('@')
        except Exception as error:
            LOG.error('Illegal URL is found. Exception: {}'.format(error))
            raise GoTo(EnumResponseStatus.RESPONSE_INVALID_URL_FORMAT,
                       'Invalid format of sender<{}> or receiver<{}>. Should be like 0xYYYY@ip:port' \
                       .format(sender, receiver))
예제 #24
0
 def exclude_wallet_from_router(cls, current_url, router):
     """
     Description: remove current wallet url from the router
     :param router: router from messages
     :return:
     """
     try:
         router_url = [jump[0] for jump in router]
         this_jump = router_url.index(current_url)
     except Exception as error:
         raise GoTo(
             EnumResponseStatus.RESPONSE_ROUTER_WITHOUT_CURRENT_WALLET,
             'Why wallet<{}> receive this messages. Router<{}> without current wallet'
             .format(current_url, router))
     else:
         return router[this_jump:], router[this_jump]
예제 #25
0
    def validate_negotiated_nonce(self):
        """

        :return:
        """
        # to validate the negotiated nonce
        valid_trade, valid_nonce = Channel.latest_valid_trade(
            self.channel_name)

        nonce = self.nego_nonce or self.nonce
        if valid_nonce and valid_nonce + 1 == nonce:
            return valid_trade
        else:
            raise GoTo(
                EnumResponseStatus.RESPONSE_TRADE_COULD_NOT_BE_OVERWRITTEN,
                'Could not use negotiated nonce <{}>, current valid nonce<{}>'.
                format(self.nego_nonce, valid_nonce))
예제 #26
0
    def get_htlc_trade_by_hashr(cls, channel_name, hashcode):
        """

        :param channel_name:
        :param hashcode:
        :return:
        """
        try:
            return Channel.batch_query_trade(
                channel_name,
                filters={
                    'type': EnumTradeType.TRADE_TYPE_HTLC.name,
                    'hashcode': hashcode
                })[0]
        except Exception as error:
            raise GoTo(
                EnumResponseStatus.RESPONSE_TRADE_HASHR_NOT_FOUND,
                'Htlc trade not found by the HashR<{}> in channel<{}>'.format(
                    hashcode, channel_name))
예제 #27
0
    def check_payment(cls, channel_name, address, asset_type, payment):
        """

        :param channel_name:
        :param address:
        :param asset_type:
        :param payment:
        :return:
        """
        channel_balance = Channel(channel_name).balance
        balance = channel_balance.get(address).get(asset_type.upper())

        if not 0 < int(payment) <= int(balance):
            raise GoTo(
                EnumResponseStatus.
                RESPONSE_TRADE_NO_ENOUGH_BALANCE_FOR_PAYMENT,
                'Invalid payment<{}>, payer balance<{}>'.format(
                    payment, balance))

        return True, int(balance)
예제 #28
0
    def get_rcode(cls, channel_name, hashcode):
        """

        :param hashcode:
        :return:
        """
        if cls.is_hlock_to_rsmc(hashcode):
            htlc_trade = Channel.batch_query_trade(
                channel_name,
                filters={
                    'type': EnumTradeType.TRADE_TYPE_HTLC.name,
                    'hashcode': hashcode
                })
            if not htlc_trade:
                raise GoTo(
                    EnumResponseStatus.RESPONSE_TRADE_HASHR_NOT_FOUND,
                    'Htlc trade with HashR<{}> NOT found'.format(hashcode))
            htlc_trade = htlc_trade[0]
            return hashcode, htlc_trade.rcode
        else:
            return cls.get_default_rcode()
예제 #29
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)

            # 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)
예제 #30
0
    def update_balance_for_channel(cls,
                                   channel_name,
                                   asset_type,
                                   payer_address,
                                   payee_address,
                                   payment,
                                   is_hlock_to_rsmc=False,
                                   is_htlc_type=False):
        """

        :param channel_name:
        :param payer_address:
        :param payee_address:
        :param asset_type:
        :param payment:
        :param is_hlock_to_rsmc:
        :return:
        """
        channel = Channel(channel_name)

        try:
            asset_type = asset_type.upper()
            channel_balance = channel.balance
            channel_hlock = channel.hlock

            # calculate the left balance
            payer_balance = channel_balance.get(payer_address).get(asset_type)
            payee_balance = channel_balance.get(payee_address).get(asset_type)

            if is_hlock_to_rsmc:
                payer_hlock = channel_hlock.get(payer_address).get(asset_type)
                payer_hlock = cls.big_number_calculate(payer_hlock, payment,
                                                       False)
                if 0 > payer_hlock:
                    raise GoTo(
                        EnumResponseStatus.
                        RESPONSE_TRADE_LOCKED_ASSET_LESS_THAN_PAYMENT,
                        'Why here? Payment<{}> should less than locked asset'.
                        format(payment))
                channel_hlock.update(
                    {payer_address: {
                        asset_type: str(payer_hlock)
                    }})
                payee_balance = cls.big_number_calculate(
                    payee_balance, payment)
            elif is_htlc_type:
                payer_hlock = channel_hlock.get(payer_address).get(asset_type)
                payer_hlock = cls.big_number_calculate(payer_hlock, payment)
                channel_hlock.update(
                    {payer_address: {
                        asset_type: str(payer_hlock)
                    }})
                payer_balance = cls.big_number_calculate(
                    payer_balance, payment, False)
            else:
                payer_balance = cls.big_number_calculate(
                    payer_balance, payment, False)
                payee_balance = cls.big_number_calculate(
                    payee_balance, payment)

            if int(payer_balance) >= 0 and int(payee_balance) >= 0:
                Channel.update_channel(channel_name,
                                       balance={
                                           payer_address: {
                                               asset_type: str(payer_balance)
                                           },
                                           payee_address: {
                                               asset_type: str(payee_balance)
                                           }
                                       },
                                       hlock=channel_hlock)
            else:
                raise GoTo(
                    EnumResponseStatus.
                    RESPONSE_TRADE_NO_ENOUGH_BALANCE_FOR_PAYMENT,
                    'Payer has not enough balance for this payment<{}>'.format(
                        payment))

        except Exception as error:
            raise GoTo(
                EnumResponseStatus.RESPONSE_TRADE_BALANCE_UPDATE_FAILED,
                'Update channel<{}> balance error. payment<{}>. Exception: {}'.
                format(channel_name, payment, error))