def handle_partner_response(self): """ :return: response to send to peer """ # local variables need_update_balance = False is_htlc_to_rsmc = self.is_hlock_to_rsmc(self.hashcode) # handle the resign body firstly resign_ack = None if self.resign_body: resign_ack, resign_trade = self.handle_resign_body(self.wallet, self.channel_name, self.resign_body) # here if the peer not provide the signature, we need re-calculate the balance if not self.commitment: _, self.sender_balance, self.receiver_balance = self.calculate_balance_after_payment( resign_trade.balance, resign_trade.peer_balance, self.payment, is_htlc_to_rsmc ) # to check whether the negotiated nonce is legal or not self.validate_negotiated_nonce() # create RSMC response message with RoleIndex==1 rsmc_sign_body = self.response(self.asset_type, self.payment, self.sender_balance, self.receiver_balance, 1, self.hashcode) # get some common local variables sign_hashcode, sign_rcode = self.get_rcode(self.channel_name, self.hashcode) payer_balance = int(self.sender_balance) payee_balance = int(self.receiver_balance) payment = int(self.payment) # use this nonce for following message of current transaction nonce = self.nego_nonce or self.nonce # if negotiated nonce by peer, delete the transaction with self.nonce if nonce != self.nonce: # generate the rsmc trade part rsmc_trade = Channel.rsmc_trade( type=EnumTradeType.TRADE_TYPE_RSMC, role=EnumTradeRole.TRADE_ROLE_FOUNDER, asset_type=self.asset_type, balance=payer_balance, peer_balance=payee_balance, payment=payment, hashcode=sign_hashcode, rcode=sign_rcode ) self.record_transaction(nonce, **rsmc_trade) if nonce < self.nonce: Channel.delete_trade(self.channel_name, self.nonce) # query the trade by nonce current_trade = Channel.query_trade(self.channel_name, nonce) if current_trade.commitment: # It means that the transaction is already signed during resign # previous transaction record. commitment = current_trade.commitment else: # start to sign this new transaction and save it # check balance self.check_balance(self.channel_name, self.asset_type, self.payer_address, payer_balance, self.payee_address, payee_balance, hlock_to_rsmc=is_htlc_to_rsmc, payment=payment) # sign the transaction commitment = RsmcResponsesMessage.sign_content( self.wallet, self._sign_type_list, [self.channel_name, nonce, self.payer_address, payer_balance, self.payee_address, payee_balance, sign_hashcode, sign_rcode] ) # update the transaction Channel.update_trade(self.channel_name, nonce, commitment=commitment) # peer has already sign the new transaction with nonce if self.commitment: # check the signature self.check_signature( self.wallet, self.sender_address, type_list=self._sign_type_list, value_list=[self.channel_name, nonce, self.payer_address, int(self.sender_balance), self.payee_address, int(self.receiver_balance), sign_hashcode, sign_rcode], signature=self.commitment ) # update this trade confirmed state Channel.update_trade( self.channel_name, nonce, peer_commitment=self.commitment, state=EnumTradeState.confirmed.name ) need_update_balance = True rsmc_sign_body.update({'Commitment': commitment}) # has resign response ?? if resign_ack: rsmc_sign_body.update({'ResignBody': resign_ack}) return need_update_balance, rsmc_sign_body
def handle(self): super(RsmcMessage, self).handle() status = EnumResponseStatus.RESPONSE_OK resign_ack = None resign_request = None try: # common check self.check_channel_state(self.channel_name) self.verify() # resign request by peer ?? if self.resign_body: resign_ack, nego_trade = self.handle_resign_body(self.wallet, self.channel_name, self.resign_body) else: # check whether need resign previous transaction resign_request, nego_trade = self.create_resign_message_body(self.wallet.url, self.channel_name, self.nonce) # real nonce nego_nonce = nego_trade and (nego_trade.nonce+1) nonce = nego_nonce or self.nonce rsmc_sign_body = self.response(self.asset_type, self.payment, self.sender_balance, self.receiver_balance, self.rsmc_sign_role, self.hashcode) # record the transaction without any signature sign_hashcode, sign_rcode = self.get_rcode(self.channel_name, self.hashcode) rsmc_trade = Channel.rsmc_trade( type=EnumTradeType.TRADE_TYPE_RSMC, role=EnumTradeRole.TRADE_ROLE_PARTNER, asset_type=self.asset_type, balance=self.receiver_balance, peer_balance=self.sender_balance, payment=self.payment, hashcode=sign_hashcode, rcode=sign_rcode ) # if need resign, just send resign message body if resign_request: # add resign body to message body rsmc_sign_body.update({'ResignBody': resign_request}) else: # check the balance htlc_to_rsmc = self.is_hlock_to_rsmc(self.hashcode) _, payer_balance, payee_balance = self.check_balance( self.channel_name, self.asset_type, self.payer_address, self.sender_balance, self.payee_address, self.receiver_balance, hlock_to_rsmc=htlc_to_rsmc, payment=self.payment ) # sign the trade commitment = RsmcResponsesMessage.sign_content( self.wallet, RsmcMessage._sign_type_list, [self.channel_name, nonce, self.payer_address, payer_balance, self.payee_address, payee_balance, sign_hashcode, sign_rcode] ) # update the rsmc_trade rsmc_trade.update({'commitment': commitment, 'state':EnumTradeState.confirming.name}) # update the message body with signature rsmc_sign_body.update({'Commitment': commitment}) # add resign ack if resign_ack: rsmc_sign_body.update({'ResignBody': resign_ack}) # Response message header response_message = RsmcResponsesMessage.create_message_header( self.receiver, self.sender, RsmcResponsesMessage._message_name, self.channel_name, self.asset_type, self.nonce, nonce ) response_message.update({'MessageBody': rsmc_sign_body}) response_message.update({'Status': status.name}) self.send(response_message) # record the transaction self.record_transaction(nonce, **rsmc_trade) APIStatistics.update_statistics(self.wallet.address, rsmc='rsmc') except TrinityException as error: status = error.reason LOG.exception(error) except Exception as error: status = EnumResponseStatus.RESPONSE_EXCEPTION_HAPPENED LOG.exception('Failed to handle RsmcMessage. Exception: {}'.format(error)) finally: if EnumResponseStatus.RESPONSE_OK != status: # nofify error response RsmcResponsesMessage.send_error_response(self.sender, self.receiver, self.channel_name, self.asset_type, self.nonce, status) return
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
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