Ejemplo n.º 1
0
    def notify_rcode_to_next_peer(cls, htlc_trade, rcode):
        """

        :param next_channel:
        :return:
        """
        if not htlc_trade:
            LOG.error('void input parameter -- htlc_trade')
            return

        if not htlc_trade.channel:
            LOG.info('Htlc trade with HashR<{}> has been finished'.format(
                htlc_trade.hashcode))
            return

        peer = None
        try:
            # notify the previous node the R-code
            LOG.debug('Payment get channel {}/{}'.format(
                htlc_trade.channel, htlc_trade.hashcode))
            channel = Channel(htlc_trade.channel)
            nonce = channel.latest_nonce(htlc_trade.channel)
            LOG.info("Next peer: {}".format(peer))

            from wallet.transaction.htlc import RResponse
            RResponse.create(htlc_trade.channel, 'TNC', nonce,
                             channel.partner_uri, channel.founder_uri,
                             htlc_trade.hashcode, rcode, None)
        except Exception as error:
            LOG.error('Failed to notify RCode<{}> to peer<{}>'.format(
                rcode, peer))
Ejemplo n.º 2
0
    def confirm_payment(cls, channel_name, hashcode, hlock_to_rsmc=False):
        """"""
        if not hlock_to_rsmc:
            return

        # find the htlc trade history
        try:
            htlc_lock = cls.batch_query_trade(
                channel_name,
                filters={
                    'type': EnumTradeType.TRADE_TYPE_HTLC.name,
                    'hashcode': hashcode
                })[0]
            cls.update_trade(channel_name,
                             htlc_lock.nonce,
                             state=EnumTradeState.confirmed.name)

            return
        except Exception as error:
            LOG.error(
                'Payment for channel<{}> with HashR<{}> Not found from the DB'.
                format(channel_name, hashcode))
            LOG.error('confirm payament Exception: {}'.format(error))

        return
Ejemplo n.º 3
0
    def latest_valid_trade(cls, channel_name):
        """

        :param channel_name:
        :return:
        """
        try:
            filters = {
                '$or': [{
                    'state': EnumTradeState.confirmed_onchain.name
                }, {
                    'state': EnumTradeState.confirmed.name
                }, {
                    'state': EnumTradeState.confirming.name
                }]
            }
            valid_trade = APITransaction(channel_name).sort(key='nonce',
                                                            filters=filters)[0]
        except Exception as error:
            LOG.exception(
                'No valid transaction records were found for channel<{}>.'.
                format(channel_name))
            return None, None
        else:
            return valid_trade, valid_trade.nonce
Ejemplo n.º 4
0
    def quick_close(cls, channel_name, wallet=None, cli=False, trigger=None):
        """

        :param channel_name:
        :param wallet:
        :param cli:
        :param trigger:
        :return:
        """
        try:
            channel = cls.query_channel(channel_name)[0]

            # get peer address
            peer = channel.src_addr
            if wallet.url == peer:
                peer = channel.dest_addr

            # start trigger to close channel quickly
            trigger(wallet, peer, channel_name, 'TNC')
        except Exception as error:
            if cli:
                console_log.error(
                    'Failed to close channel: {}'.format(channel_name))
            LOG.error('Failed to close channel<{}>, Exception: {}'.format(
                channel_name, error))
Ejemplo n.º 5
0
 def latest_trade(channel_name):
     try:
         trade = APITransaction(channel_name).sort(key='nonce')[0]
     except Exception as error:
         LOG.error(
             'No transaction records were found for channel<{}>. Exception: {}'
             .format(channel_name, error))
         return None
     else:
         return trade
Ejemplo n.º 6
0
    def transfer(
        cls,
        channel_name,
        wallet,
        receiver,
        asset_type,
        count,
        hashcode=None,
        cli=False,
        router=None,
        next_jump=None,
        comments=None,
        trigger=None,
    ):
        """

        :param sender:
        :param receiver:
        :param asset_type:
        :param count:
        :param hash_random:
        :param wallet:
        :return:
        """
        try:
            if router:
                # HTLC transaction
                trigger(wallet,
                        channel_name,
                        asset_type,
                        wallet.url,
                        receiver,
                        count,
                        hashcode,
                        router,
                        next_jump,
                        comments=comments)
            else:
                # RSMC transaction
                trigger(channel_name,
                        asset_type,
                        wallet.url,
                        receiver,
                        count,
                        hashcode=None,
                        comments=comments)
        except Exception as error:
            LOG.error('Failed to transfer {} {} to receiver<{}>. Exception: {}' \
                      .format(count, asset_type, receiver, error))

        return
Ejemplo n.º 7
0
def sync_channel_info_to_gateway(channel_name, type, asset_type='TNC'):
    LOG.info("Debug sync_channel_info_to_gateway  channel {} type {}".format(
        channel_name, type))
    ch = Channel(channel_name)
    if not ch:
        return None

    balance = ch.balance
    nb = {}
    for item, value in balance.items():
        if ch.founder_uri.__contains__(item):
            nb[ch.founder_uri] = value
        else:
            nb[ch.partner_uri] = value

    return sync_channel(type, ch.channel_name, ch.founder_uri, ch.partner_uri,
                        nb, asset_type)
Ejemplo n.º 8
0
 def latest_confirmed_trade(cls, channel_name):
     try:
         filters = {
             '$or': [{
                 'state': EnumTradeState.confirmed_onchain.name
             }, {
                 'state': EnumTradeState.confirmed.name
             }]
         }
         trade = APITransaction(channel_name).sort(key='nonce',
                                                   filters=filters)[0]
     except Exception as error:
         LOG.error(
             'No transaction records were found for channel<{}>. Exception: {}'
             .format(channel_name, error))
         return None
     else:
         return trade
Ejemplo n.º 9
0
    def get_channel(cls, address1, address2, state=None):
        channels = []
        filter_list = [{
            'src_addr': address1,
            'dest_addr': address2
        }, {
            'src_addr': address2,
            'dest_addr': address1
        }]

        for filter_item in filter_list:
            if state:
                filter_item.update({'state': state.name})

            try:
                channels.extend(
                    APIChannel.batch_query_channel(filters=filter_item))
            except Exception as error:
                LOG.debug(
                    'Batch query channels from DB error: {}'.format(error))

        return channels
Ejemplo n.º 10
0
    def force_release_htlc(cls,
                           uri='',
                           channel_name='',
                           hashcode='',
                           rcode='',
                           sign_key='',
                           gwei_coef=1,
                           trigger=None,
                           is_debug=False,
                           is_pubnishment=False,
                           htcl_to_rsmc=False):
        """

        :param uri:
        :param channel_name:
        :param hashcode:
        :param rcode:
        :param sign_key:
        :param gwei_coef:
        :param trigger:
        :param is_debug:
        :param htcl_to_rsmc:
        :return:
        """

        # some internal function here
        # ToDo: not a good way, could be optimized later
        def common_kwargs_for_trigger(invoker,
                                      channel_id,
                                      lock_hash,
                                      lock_secret,
                                      invoker_key,
                                      gwei_coef=1):
            # makeup the parameters for callback
            return {
                'invoker': invoker,
                'channel_id': channel_id,
                'lock_hash': lock_hash,
                'lock_secret': lock_secret,
                'invoker_key': invoker_key,
                'gwei_coef': gwei_coef
            }

        def unlock_htlc_kwargs(trade, address, peer_address, is_debug):
            """"""
            trigger_kwargs = {
                'lock_period': trade.delay_block,
                'lock_amount': trade.payment
            }

            # is debug by test engineer
            if not is_debug:
                trigger_kwargs.update({'lock_secret': htlc_trade.rcode})

            # what role is played by this wallet
            if EnumTradeRole.TRADE_ROLE_FOUNDER.name == trade.role:
                trigger_kwargs.update({
                    'founder':
                    address,
                    'founder_signature':
                    trade.delay_commitment,
                    'partner':
                    peer_address,
                    'partner_signature':
                    trade.peer_delay_commitment
                })
            else:
                trigger_kwargs.update({
                    'founder':
                    peer_address,
                    'founder_signature':
                    trade.peer_delay_commitment,
                    'partner':
                    address,
                    'partner_signature':
                    trade.delay_commitment
                })

            return trigger_kwargs

        def punishment_htlc_kwargs(trade, address, peer_address):
            """"""
            trigger_kwargs = {
                'nonce': trade.nonce,
                'lock_secret': htlc_trade.rcode
            }

            # what role is played by this wallet
            if EnumTradeRole.TRADE_ROLE_FOUNDER.name == trade.role:
                trigger_kwargs.update({
                    'founder':
                    address,
                    'partner':
                    peer_address,
                    'founder_balance':
                    trade.balance,
                    'partner_balance':
                    trade.peer_balance,
                    'founder_signature':
                    trade.commitment,
                    'partner_signature':
                    trade.peer_commitment
                })
            else:
                trigger_kwargs.update({
                    'founder': peer_address,
                    'partner': address,
                    'founder_balance': trade.peer_balance,
                    'partner_balance': trade.balance,
                    'founder_signature': trade.peer_commitment,
                    'partner_signature': trade.commitment
                })

            return trigger_kwargs

        # start to unlock the payment of htlc-locked part
        try:
            # get the htlc record by hashcode
            htlc_trade = cls.batch_query_trade(
                channel_name,
                filters={
                    'type': EnumTradeType.TRADE_TYPE_HTLC.name,
                    'hashcode': hashcode
                })[0]

            # if the state of this trasaction is confirming, no need to update transaction
            rsmc_trade = None
            if is_pubnishment:
                rsmc_trade = cls.batch_query_trade(
                    channel_name,
                    filters={
                        'type': EnumTradeType.TRADE_TYPE_RSMC.name,
                        'hashcode': hashcode
                    })

                rsmc_trade = rsmc_trade[0] if rsmc_trade else None

                # no action Rsmc trade with this HashR has already existed and the state of trade is confirmed
                if rsmc_trade and rsmc_trade.state in [
                        EnumTradeState.confirmed.name
                ]:
                    # to trigger the htlc punishment and close the channel
                    pass
                else:
                    # Below actions are needed:
                    # step 1 : validate the R-code
                    # step 2 : update the R-code to htlc trade
                    LOG.info(
                        'No need to punish hlock transaction with HashR<{}>'.
                        format(hashcode))

                    # to record this rcode if rcode is correct one
                    if Payment.verify_hr(hashcode, rcode):
                        cls.update_trade(channel_name,
                                         htlc_trade.nonce,
                                         rcode=rcode)

                        # here, we need to notify the rcode to next wallet
                        if htcl_to_rsmc:
                            cls.notify_rcode_to_next_peer(htlc_trade, rcode)

                    return {'result': 'success'}

        except Exception as error:
            LOG.error('No Htlc trade was found or rcode is error. channel<{}>, HashR<{}>. Exception: {}' \
                      .format(channel_name, hashcode, 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('Unlock Htlc payment: channel<{}>, HashR<{}>'.format(
                channel_name, hashcode))

            # makeup the parameters for callback function
            trigger_kwargs = common_kwargs_for_trigger(self_address,
                                                       channel_name, hashcode,
                                                       rcode, sign_key,
                                                       gwei_coef)

            # is withdraw update topic of the contract
            if is_pubnishment:
                trigger_kwargs.update(
                    punishment_htlc_kwargs(rsmc_trade, self_address,
                                           peer_address))
            else:
                trigger_kwargs.update(
                    unlock_htlc_kwargs(htlc_trade, self_address, peer_address,
                                       is_debug))

            # start trigger the callback and return the result.
            LOG.debug('Force to unlock htlc with aruments: {}'.format(
                trigger_kwargs))
            return trigger(**trigger_kwargs)

        return None
Ejemplo n.º 11
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)
                    return None
                nonce = latest_nonce
        except Exception as error:
            LOG.error('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
Ejemplo n.º 12
0
    def create(cls,
               wallet,
               founder,
               partner,
               asset_type,
               deposit,
               partner_deposit=None,
               comments=None,
               trigger=None,
               cli=True):
        """
            Provide one method to be called by the wallet prompt console.
        :param wallet:
        :param partner:
        :param asset_type:
        :param deposit:
        :param partner_deposit:
        :param comments:
        :param cli:
        :return:
        """
        if not (wallet and partner and asset_type and deposit):
            LOG.error('Invalid parameters:wallet<{}>, founder<{}>, partner<{}>, asset_type<{}>, deposit<{}>' \
                      .format(wallet, founder, partner, asset_type, deposit))
            # here we could use some hooks to register event to handle output console ????
            console_log.error(
                'Illegal mandatory parameters. Please check in your command.')
            return False

        # use deposit as default value for both partners if partner's deposit is not set:
        if not partner_deposit:
            partner_deposit = deposit

        # judge whether the channel exist or not
        if Channel.get_channel(founder, partner, EnumChannelState.OPENED):
            console_log.warning('OPENED channel already exists.')
            return False
        else:
            # creating channel is ongoing
            # channel = Channel.get_channel(founder, partner, EnumChannelState.OPENING)
            # if :
            #     console.warning('Channel {} is on the way. Please try later if failed')
            #     return
            pass

        channel_name = cls.new_channel_name(founder, partner)
        if cli:
            deposit = int(deposit)
            partner_deposit = int(partner_deposit)
            if 0 >= deposit or 0 >= partner_deposit:
                LOG.error('Could not register channel because of illegal deposit<{}:{}>.'\
                          .format(deposit, partner_deposit))
                return False

            try:
                trigger(wallet, channel_name, asset_type, founder, deposit,
                        partner, partner_deposit, comments)
            except Exception as error:
                LOG.info('Create channel<{}> failed. Exception: {}'.format(
                    channel_name, error))
                return False

        return True
Ejemplo n.º 13
0
 def add_channel(**kwargs):
     if kwargs.get('channel') is None:
         LOG.error('MUST specified the key parameter \'channel\'')
         return False
     kwargs.update({'alive_block': 0})
     return APIChannel.add_channel(**kwargs)