Example #1
0
    def __init__(self, message):
        self.message = message

        self.sender = message.get('Sender')
        self.sender_address, _, _ = uri_parser(self.sender)
        self.receiver = message.get('Receiver')
        self.receiver_address, _, _, = uri_parser(self.receiver)

        self.message_type = message.get('MessageType', '')
        self.message_body = message.get('MessageBody')
        self.resign_body = self.message_body.get('ResignBody')
        self.channel_name = message.get('ChannelName')
        self.asset_type = message.get('AssetType', 'INVALID_ASSET').upper()
        self.net_magic = message.get('NetMagic')
        self.status = message.get('Status')
        self.comments = self.message.get('Comments')

        self.nonce = int(message.get('TxNonce'))
        try:
            self.nego_nonce = int(message.get('ResetTxNonce'))
        except:
            self.nego_nonce = None

        # transaction is triggered by command cline
        trigger_by_cli = int(self.message_body.get('TriggeredByCLI', 0))
        self.trigger_by_cli = True if trigger_by_cli else False
Example #2
0
    def create(wallet,
               channel_name,
               asset_type,
               nonce,
               sender,
               sender_balance,
               receiver,
               receiver_balance,
               peer_commitment,
               comments=None):
        """

        :param wallet:
        :param channel_name:
        :param asset_type:
        :param sender:
        :param receiver:
        :param sender_balance:
        :param receiver_balance:
        :param peer_commitment:
        :param status:
        :return:
        """
        sender_address, _, _ = uri_parser(sender)
        receiver_address, _, _ = uri_parser(receiver)
        asset_type = asset_type.upper()

        # sign the contents
        commitment = SettleResponseMessage.sign_content(
            wallet, SettleResponseMessage._sign_type_list, [
                channel_name, nonce, sender_address,
                int(sender_balance), receiver_address,
                int(receiver_balance)
            ])

        # finally, add the transaction information to database
        settle_trade = Channel.settle_trade(
            type=EnumTradeType.TRADE_TYPE_QIUCK_SETTLE,
            role=EnumTradeRole.TRADE_ROLE_PARTNER,
            asset_type=asset_type,
            balance=receiver_balance,
            peer_balance=sender_balance,
            commitment=commitment,
            peer_commitment=peer_commitment)
        SettleResponseMessage.add_or_update_quick_settle_trade(
            channel_name, EnumTradeRole.TRADE_ROLE_PARTNER, **settle_trade)

        message = SettleResponseMessage.create_message_header(
            receiver, sender, SettleResponseMessage._message_name,
            channel_name, asset_type, nonce)

        message.update({"MessageBody": {"Commitment": commitment}})

        if not comments:
            message.update({'Comments': comments})

        # send response OK message
        message.update({'Status': EnumResponseStatus.RESPONSE_OK.name})
        Message.send(message)
Example #3
0
    def create(wallet, receiver, channel_name, asset_type):
        """

        :param channel_name:
        :param wallet:
        :param sender:
        :param receiver:
        :param asset_type:
        :return:
        """
        sender = wallet.url
        channel = Channel(channel_name)
        nonce = SettleMessage._SETTLE_NONCE
        asset_type = asset_type.upper()

        sender_address, _, _, = uri_parser(sender)
        receiver_address, _, _, = uri_parser(receiver)

        balance = channel.balance
        sender_balance = balance.get(sender_address, {}).get(asset_type)
        receiver_balance = balance.get(receiver_address, {}).get(asset_type)

        commitment = SettleMessage.sign_content(
            typeList=SettleMessage._sign_type_list,
            valueList=[
                channel_name, nonce, sender_address,
                int(sender_balance), receiver_address,
                int(receiver_balance)
            ],
            privtKey=wallet._key.private_key_string)

        # add trade to database
        settle_trade = Channel.settle_trade(
            type=EnumTradeType.TRADE_TYPE_QIUCK_SETTLE,
            role=EnumTradeRole.TRADE_ROLE_FOUNDER,
            asset_type=asset_type,
            balance=sender_balance,
            peer_balance=receiver_balance,
            commitment=commitment)
        SettleMessage.add_or_update_quick_settle_trade(
            channel_name, EnumTradeRole.TRADE_ROLE_FOUNDER, **settle_trade)

        # create settle request message
        message = SettleMessage.create_message_header(
            sender, receiver, SettleMessage._message_name, channel_name,
            asset_type, nonce)
        message = message.message_header
        message_body = {
            "Commitment": commitment,
            "SenderBalance": sender_balance,
            "ReceiverBalance": receiver_balance
        }
        message.update({'MessageBody': message_body})

        Message.send(message)

        return
Example #4
0
    def __init__(self, message):
        self.message = message

        self.sender = message.get('Sender')
        self.sender_address, _, _ = uri_parser(self.sender)
        self.receiver = message.get('Receiver')
        self.receiver_address, _, _, = uri_parser(self.receiver)

        self.message_type = message.get('MessageType')
        self.message_body = message.get('MessageBody')
        self.channel_name = message.get('ChannelName')
        self.asset_type = message.get('AssetType', 'INVALID_ASSET').upper()
        self.nonce = int(message.get('TxNonce'))
        self.net_magic = message.get('NetMagic')
        self.status = message.get('Status')
        self.comments = self.message.get('Comments')
Example #5
0
    def create(channel_name,
               asset_type,
               nonce,
               sender,
               receiver,
               hashcode,
               rcode,
               comments=None):
        """

        :param channel_name:
        :param asset_type:
        :param nonce:
        :param sender:
        :param receiver:
        :param hashcode:
        :param value:
        :param comments:
        :return:
        """
        htlc_trade = RResponse.get_htlc_trade_by_hashr(channel_name, hashcode)
        asset_type = asset_type.upper()
        payer_address, _, _ = uri_parser(receiver)
        payment = htlc_trade.payment

        message = RResponse.create_message_header(sender, receiver,
                                                  RResponse._message_name,
                                                  channel_name, asset_type,
                                                  nonce)
        message = message.message_header

        message_body = {
            "HashR": hashcode,
            "R": rcode,
            "PaymentCount": payment,
        }

        message.update({'MessageBody': message_body})

        if comments:
            message.update({'Comments': comments})

        RResponse.send(message)
Example #6
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
Example #7
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
Example #8
0
    def create(cls,
               channel_name,
               asset_type,
               sender,
               receiver,
               payment,
               hashcode,
               router,
               current_channel=None,
               comments=None):
        """

        :param channel_name:
        :param asset_type:
        :param sender:
        :param receiver:
        :param payment:
        :param hashcode:
        :param router:
        :param current_channel:
        :param comments:
        :return:
        """
        cls.check_channel_state(channel_name)
        cls.check_router(router, hashcode)
        cls.check_asset_type(asset_type)
        cls.check_both_urls(sender, receiver)

        payer_address, _, _ = uri_parser(sender)
        payee_address, _, _ = uri_parser(receiver)
        asset_type = asset_type.upper()
        channel = Channel(channel_name)

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

        # to check whether previous transaction need be resigned or not
        resign_body, valid_trade = HtlcMessage.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)

        # To calculate the balance after payment
        _, payer_balance, payee_balance = HtlcMessage.calculate_balance_after_payment(
            payer_balance, payee_balance, payment, is_htlc_type=True)

        # exclude current router from the router
        end_block_height = cls.get_unlocked_block_height(len(router))

        # generate htlc transaction and record it into database later
        htlc_trade = Channel.htlc_trade(type=EnumTradeType.TRADE_TYPE_HTLC,
                                        role=EnumTradeRole.TRADE_ROLE_FOUNDER,
                                        asset_type=asset_type,
                                        balance=payer_balance,
                                        peer_balance=payee_balance,
                                        payment=payment,
                                        hashcode=hashcode,
                                        delay_block=end_block_height)

        # record the channel if RResponse is triggered
        if current_channel:
            htlc_trade.update({'channel': current_channel})

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

        # start to create message  and send later
        message = HtlcMessage.create_message_header(sender, receiver,
                                                    HtlcMessage._message_name,
                                                    channel_name, asset_type,
                                                    nonce)
        message.update({'Router': router})
        message.update({'MessageBody': htlc_request})

        if comments:
            message.update({'Comments': comments})

        HtlcMessage.send(message)

        # record the transaction
        Channel.add_trade(channel_name, nonce=nonce, **htlc_trade)

        return None
Example #9
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
Example #10
0
    def handle_resign_body(cls, wallet, channel_name, resign_body):
        """"""
        if not resign_body:
            return None

        if not (wallet and channel_name):
            raise GoTo(
                EnumResponseStatus.RESPONSE_ILLEGAL_INPUT_PARAMETER,
                'Void wallet<{}> or Illegal channel name<{}>'.format(
                    wallet, channel_name))

        resign_nonce = int(resign_body.get('Nonce'))
        update_channel_db = {}
        update_trade_db = {}

        # get transaction by the resign_nonce
        resign_trade = Channel.query_trade(channel_name, resign_nonce)
        asset_type = resign_trade.asset_type

        channel = Channel(channel_name)
        self_address, _, _ = uri_parser(wallet.url)
        peer_address, _, _ = uri_parser(channel.peer_uri(wallet.url))

        # Is this wallet sender side of this trade ?????
        if EnumTradeRole.TRADE_ROLE_PARTNER.name == resign_trade.role:
            payer_address = peer_address
            payee_address = self_address
            payer_balance = resign_trade.peer_balance
            payee_balance = resign_trade.balance
        elif EnumTradeRole.TRADE_ROLE_FOUNDER.name == resign_trade.role:
            payer_address = self_address
            payee_address = peer_address
            payer_balance = resign_trade.balance
            payee_balance = resign_trade.peer_balance
        else:
            raise GoTo(
                EnumResponseStatus.RESPONSE_DATABASE_ERROR_TRADE_ROLE,
                'Error trade role<{}> for nonce<{}>'.format(
                    resign_trade.role, resign_nonce))

        if EnumTradeType.TRADE_TYPE_HTLC.name == resign_trade.type:
            rsmc_sign_hashcode, rsmc_sign_rcode = cls.get_default_rcode()
        elif EnumTradeType.TRADE_TYPE_RSMC.name == resign_trade.type:
            rsmc_sign_hashcode, rsmc_sign_rcode = resign_trade.hashcode, resign_trade.rcode
        else:
            raise GoTo(
                EnumResponseStatus.RESPONSE_TRADE_RESIGN_NOT_SUPPORTED_TYPE,
                'Only support HTLC and RSMC resign. Current transaction type: {}'
                .format(resign_trade.type))

        rsmc_list = [
            channel_name, resign_nonce, payer_address,
            int(payer_balance), payee_address,
            int(payee_balance), rsmc_sign_hashcode, rsmc_sign_rcode
        ]

        # self commitment is None
        if not resign_trade.commitment:
            commitment = cls.sign_content(wallet, cls._rsmc_sign_type_list,
                                          rsmc_list)
            update_trade_db.update({'commitment': commitment})

        # self lock commitment is none
        htlc_list = None
        if EnumTradeType.TRADE_TYPE_HTLC.name == resign_trade.type:
            htlc_list = [
                channel_name, payer_address, payee_address,
                int(resign_trade.delay_block),
                int(resign_trade.payment), resign_trade.hashcode
            ]
            delay_commitment = cls.sign_content(wallet,
                                                cls._htlc_sign_type_list,
                                                htlc_list)
            update_trade_db.update({'delay_commitment': delay_commitment})

        # check whether the trade need update or not
        if resign_trade.state not in [
                EnumTradeState.confirmed.name,
                EnumTradeState.confirmed_onchain.name
        ]:
            peer_commitment = resign_body.get('Commitment')
            peer_delay_commitment = resign_body.get('DelayCommitment')

            # check peer signature
            cls.check_signature(wallet, peer_address, cls._rsmc_sign_type_list,
                                rsmc_list, peer_commitment)

            # update transaction and channel balance
            update_trade_db.update({'peer_commitment': peer_commitment})
            update_channel_db = {
                'balance': {
                    payer_address: {
                        asset_type: payer_balance
                    },
                    payee_address: {
                        asset_type: payee_balance
                    }
                }
            }

            # check the htlc part signature
            if EnumTradeType.TRADE_TYPE_HTLC.name == resign_trade.type:
                cls.check_signature(wallet, peer_address,
                                    cls._htlc_sign_type_list, htlc_list,
                                    peer_delay_commitment)
                update_trade_db.update(
                    {'peer_delay_commitment': peer_delay_commitment})
                update_trade_db.update(
                    {'state': EnumTradeState.confirming.name})

                # need update the hlock part
                if payer_address == self_address:
                    channel = Channel(channel_name)
                    channel_hlock = channel.hlock
                    if channel_hlock and channel_hlock.get(payer_address):
                        payer_hlock = int(resign_trade.payment) + int(
                            channel_hlock.get(payer_address).get(asset_type))
                        channel_hlock.update(
                            {payer_address: {
                                asset_type: str(payer_hlock)
                            }})
                        update_channel_db.update({'hlock': channel_hlock})
            else:  # RSMC type transaction
                update_trade_db.update(
                    {'state': EnumTradeState.confirmed.name})

            # update transaction
            Channel.update_trade(channel_name, resign_nonce, **update_trade_db)

            # update Channel balance to new one
            Channel.update_channel(channel_name, **update_channel_db)

        # return resign message body
        return cls.create_resign_message_body(wallet.url, channel_name,
                                              resign_nonce, True)
Example #11
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
Example #12
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
Example #13
0
    def rsmc_sign(cls,
                  wallet,
                  channel_name,
                  asset_type,
                  nonce,
                  sender,
                  receiver,
                  payment,
                  sender_balance,
                  receiver_balance,
                  role_index=0,
                  hashcode=None,
                  comments=None):
        """
        Descriptions: create and send RsmcSign messages.
        :param wallet:
        :param channel_name:
        :param asset_type:
        :param nonce:
        :param sender:
        :param receiver:
        :param payment:
        :param sender_balance:
        :param receiver_balance:
        :param role_index:
        :param comments:
        :param hashcode:
        :return:
        """
        asset_type = asset_type.upper()

        # different ROLE by role index
        role_index = int(role_index)
        payer, payee = RsmcMessage.get_payer_and_payee(role_index, sender,
                                                       receiver)
        payer_address, _, _ = uri_parser(payer)
        payee_address, _, _ = uri_parser(payee)

        # check balance
        is_hlock_to_rsmc = RsmcResponsesMessage.is_hlock_to_rsmc(hashcode)
        _, payer_balance, payee_balance = RsmcResponsesMessage.check_balance(
            channel_name,
            asset_type,
            payer_address,
            sender_balance,
            payee_address,
            receiver_balance,
            hlock_to_rsmc=is_hlock_to_rsmc,
            payment=payment)

        # sign the trade
        sign_hashcode, sign_rcode = cls.get_rcode(channel_name, hashcode)
        commitment = RsmcResponsesMessage.sign_content(
            typeList=RsmcResponsesMessage._sign_type_list,
            valueList=[
                channel_name, nonce, payer_address, payer_balance,
                payee_address, payee_balance, sign_hashcode, sign_rcode
            ],
            privtKey=wallet._key.private_key_string)

        # add trade to database
        if 0 == role_index:
            trade_role = EnumTradeRole.TRADE_ROLE_PARTNER
            self_balance = payee_balance
            peer_balance = payer_balance
        else:
            trade_role = EnumTradeRole.TRADE_ROLE_FOUNDER
            self_balance = payer_balance
            peer_balance = payee_balance

        # ToDo: need re-sign all unconfirmed htlc message later
        rsmc_trade = Channel.rsmc_trade(type=EnumTradeType.TRADE_TYPE_RSMC,
                                        role=trade_role,
                                        asset_type=asset_type,
                                        balance=self_balance,
                                        peer_balance=peer_balance,
                                        payment=payment,
                                        hashcode=sign_hashcode,
                                        rcode=sign_rcode,
                                        commitment=commitment)
        Channel.add_trade(channel_name, nonce=nonce, **rsmc_trade)

        # update message body
        message_body = {
            'AssetType': asset_type.upper(),
            'PaymentCount': str(payment),
            'SenderBalance': str(payer_balance),
            'ReceiverBalance': str(payee_balance),
            'Commitment': commitment,
            'RoleIndex': str(role_index),
        }

        if hashcode:
            message_body.update({'HashR': hashcode})

        # generate the message header
        message = RsmcResponsesMessage.create_message_header(
            receiver, sender, RsmcResponsesMessage._message_name, channel_name,
            asset_type, nonce)
        message = message.message_header

        # to send response OK message
        message.update({'MessageBody': message_body})
        message.update({'Status': EnumResponseStatus.RESPONSE_OK.name})
        if comments:
            message.update({'Comments': comments})

        # send RsmcSign message
        RsmcResponsesMessage.send(message)

        return
Example #14
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)

        # 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 get channel balance
        balance = channel.balance
        payer_address, _, _ = uri_parser(sender)
        payee_address, _, _ = uri_parser(receiver)
        asset_type = asset_type.upper()

        # 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(
            balance.get(payer_address).get(asset_type),
            balance.get(payee_address).get(asset_type),
            payment,
            hlock_to_rsmc=hlock_to_rsmc)

        # create message
        message_body = {
            'AssetType': asset_type.upper(),
            'PaymentCount': str(payment),
            'SenderBalance': str(payer_balance),
            'ReceiverBalance': str(payee_balance),
        }

        if hlock_to_rsmc:
            message_body.update({'HashR': hashcode})

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

        RsmcMessage.send(message)

        return None
Example #15
0
    def create(cls,
               wallet,
               channel_name,
               asset_type,
               tx_nonce,
               sender,
               receiver,
               payment,
               sender_balance,
               receiver_balance,
               hashcode,
               delay_block,
               peer_commitment,
               peer_hlock_commitment,
               router,
               next_router,
               comments=None):
        """

        :param wallet:
        :param channel_name:
        :param asset_type:
        :param tx_nonce:
        :param sender:
        :param receiver:
        :param payment:
        :param sender_balance:
        :param receiver_balance:
        :param hashcode:
        :param delay_block:
        :param peer_commitment:
        :param peer_hlock_commitment:
        :param router:
        :param next_router:
        :param comments:
        :return:
        """
        # get nonce from latest trade
        _, nonce = HtlcResponsesMessage.check_nonce(tx_nonce, channel_name)

        # start to verify balance
        payer_address, _, _ = uri_parser(sender)
        payee_address, _, _ = uri_parser(receiver)
        asset_type = asset_type.upper()

        # check balance
        _, payer_balance, payee_balance = HtlcResponsesMessage.check_balance(
            channel_name,
            asset_type,
            payer_address,
            sender_balance,
            payee_address,
            receiver_balance,
            is_htcl_type=True,
            payment=payment)

        # 2 parts in htlc message: conclusive and inconclusive part
        sign_hashcode, sign_rcode = cls.get_default_rcode()
        rsmc_commitment = HtlcResponsesMessage.sign_content(
            typeList=RsmcMessage._sign_type_list,
            valueList=[
                channel_name, nonce, payer_address, payer_balance,
                payee_address, payee_balance, sign_hashcode, sign_rcode
            ],
            privtKey=wallet._key.private_key_string)

        hlock_commitment = HtlcResponsesMessage.sign_content(
            start=5,
            typeList=HtlcResponsesMessage._sign_type_list,
            valueList=[
                channel_name, payer_address, payee_address, delay_block,
                int(payment), hashcode
            ],
            privtKey=wallet._key.private_key_string)

        # # ToDo: need re-sign all unconfirmed htlc message later
        htlc_trade = Channel.htlc_trade(
            type=EnumTradeType.TRADE_TYPE_HTLC,
            role=EnumTradeRole.TRADE_ROLE_PARTNER,
            asset_type=asset_type,
            balance=payee_balance,
            peer_balance=payer_balance,
            payment=payment,
            hashcode=hashcode,
            delay_block=delay_block,
            commitment=rsmc_commitment,
            peer_commitment=peer_commitment,
            delay_commitment=hlock_commitment,
            peer_delay_commitment=peer_hlock_commitment,
            channel=channel_name)
        Channel.add_trade(channel_name, nonce=nonce, **htlc_trade)

        # create message
        message = HtlcResponsesMessage.create_message_header(
            receiver, sender, HtlcResponsesMessage._message_name, channel_name,
            asset_type, tx_nonce)
        message = message.message_header
        message.update({
            'Router': router,
            'Next': next_router,
        })
        message_body = {
            'SenderBalance': payer_balance,
            'ReceiverBalance': payee_balance,
            'Commitment': rsmc_commitment,
            'Payment': payment,
            'DelayBlock': delay_block,
            'DelayCommitment': hlock_commitment,
            'HashR': hashcode
        }

        # orgnize the message
        message.update({'MessageBody': message_body})
        message.update({'Status': EnumResponseStatus.RESPONSE_OK.name})
        if comments:
            message.update({'Comments': comments})

        # Before the response ok, we could update the channel balance
        HtlcResponsesMessage.update_balance_for_channel(channel_name,
                                                        asset_type,
                                                        payer_address,
                                                        payee_address,
                                                        payment,
                                                        is_htlc_type=True)

        # send response ok message to peer
        HtlcResponsesMessage.send(message)

        return
Example #16
0
    def create(cls,
               wallet,
               channel_name,
               asset_type,
               sender,
               receiver,
               payment,
               hashcode,
               router,
               next_router,
               current_channel=None,
               comments=None):
        """

        :param channel_name:
        :param wallet:
        :param sender:
        :param receiver:
        :param asset_type:
        :param payment:
        :param nonce:
        :param hashcode:
        :param router:
        :param next_router:
        :param comments:
        :return:
        """
        cls.check_channel_state(channel_name)
        cls.check_router(router, hashcode)
        cls.check_asset_type(asset_type)
        cls.check_both_urls(sender, receiver)
        cls.check_router(router, hashcode)

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

        # get sender & receiver address from sender or receiver
        payer_address, _, _ = uri_parser(sender)
        payee_address, _, _ = uri_parser(receiver)
        asset_type = asset_type.upper()

        # check whether the balance is enough or not
        channel = Channel(channel_name)
        balance = channel.balance
        _, payer_balance, payee_balance = HtlcMessage.calculate_balance_after_payment(
            balance.get(payer_address, {}).get(asset_type),
            balance.get(payee_address, {}).get(asset_type),
            payment,
            is_htlc_type=True)

        # calculate the end block height
        jumps_index = HtlcMessage.this_jump(sender, router)
        end_block_height = cls.get_locked_block_height(len(router),
                                                       jumps_index)

        # Htlc is made up of 2 parts: rsmc and hlock part
        sign_hashcode, sign_rcode = cls.get_default_rcode()
        rsmc_commitment = HtlcMessage.sign_content(
            typeList=RsmcMessage._sign_type_list,
            valueList=[
                channel_name, nonce, payer_address, payer_balance,
                payee_address, payee_balance, sign_hashcode, sign_rcode
            ],
            privtKey=wallet._key.private_key_string)

        # hlock parts
        hlock_commitment = HtlcMessage.sign_content(
            start=5,
            typeList=HtlcMessage._sign_type_list,
            valueList=[
                channel_name, payer_address, payee_address, end_block_height,
                int(payment), hashcode
            ],
            privtKey=wallet._key.private_key_string)

        # # add trade to database
        htlc_trade = Channel.htlc_trade(type=EnumTradeType.TRADE_TYPE_HTLC,
                                        role=EnumTradeRole.TRADE_ROLE_FOUNDER,
                                        asset_type=asset_type,
                                        balance=payer_balance,
                                        peer_balance=payee_balance,
                                        payment=payment,
                                        hashcode=hashcode,
                                        delay_block=end_block_height,
                                        commitment=rsmc_commitment,
                                        delay_commitment=hlock_commitment)
        if current_channel:
            htlc_trade.update({'channel': current_channel})
        Channel.add_trade(channel_name, nonce=nonce, **htlc_trade)

        # generate the messages
        message_body = {
            'SenderBalance': payer_balance,
            'ReceiverBalance': payee_balance,
            'Commitment': rsmc_commitment,
            'Payment': payment,
            'DelayBlock': end_block_height,
            'DelayCommitment': hlock_commitment,
            'HashR': hashcode
        }

        message = HtlcMessage.create_message_header(sender, receiver,
                                                    HtlcMessage._message_name,
                                                    channel_name, asset_type,
                                                    nonce)
        message = message.message_header
        message.update({
            'Router': router,
            'Next': next_router,
        })
        message.update({'MessageBody': message_body})

        if comments:
            message.update({'Comments': comments})

        HtlcMessage.send(message)

        return None