def handle(self): super(FounderResponsesMessage, self).handle() # check response status if not self.check_response_status(self.status): return try: # some checks and verification for founder message self.verify() self.check_nonce(self.nonce) founder_trade = Channel.query_trade(self.channel_name, self.nonce) self.check_signature(self.wallet, type_list=self._sign_type_list, value_list=[ self.channel_name, self.nonce, self.receiver_address, int(founder_trade.balance), self.sender_address, int(founder_trade.peer_balance) ], signature=self.commitment) # update the trade Channel.update_trade(self.channel_name, self.nonce, peer_commitment=self.commitment) except GoTo as error: LOG.error(error) except Exception as error: LOG.error( 'Exception occurred during creating channel<{}>. Exception: {}' .format(self.channel_name, error)) else: self.register_deposit_event()
def execute(self, block_height, channel_name='', hashcode=''): """ :param block_height: :param channel_name: :param kwargs: :return: """ super(ChannelHtlcUnlockedEvent, self).execute(block_height) # if monitor this event, update the htlc trade state to confirmed if channel_name and hashcode: try: htlc_trade = Channel.batch_query_trade( channel_name, filters={ 'type': EnumTradeType.TRADE_TYPE_HTLC.name, 'hashcode': hashcode })[0] except Exception as error: LOG.error('Htlc trade with HashR<{}> not found for channel<{}>. Exception: {}'\ .format(hashcode, channel_name, error)) else: Channel.update_trade( channel_name, htlc_trade.nonce, state=EnumTradeState.confirmed_onchain.name) else: LOG.error( 'Error input parameters: channel <{}>, hashcode<{}>.'.format( channel_name, hashcode))
def handle_founder_response(self): """ :return: """ need_update_balance = False # handle the resign body firstly if self.resign_body: resign_ack, _ = self.handle_resign_body(self.wallet, self.channel_name, self.resign_body) sign_hashcode, sign_rcode = self.get_rcode(self.channel_name, self.hashcode) # has already signed by peer 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, self.nonce, self.payer_address, int(self.sender_balance), self.payee_address, int(self.receiver_balance), sign_hashcode, sign_rcode], signature=self.commitment ) # Just update current transaction confirmed: Channel.update_trade(self.channel_name, self.nonce, peer_commitment=self.commitment, state=EnumTradeState.confirmed.name) need_update_balance = True if self.comments: self.notify_peer_payment_finished() else: # to check the latest confirmed nonce self.validate_transaction() # if running here, it means that the transaction has been succeeded to resign is_htlc_to_rsmc = self.is_hlock_to_rsmc(self.hashcode) self.check_balance(self.channel_name, self.asset_type, self.payer_address, self.sender_balance, self.payee_address, self.receiver_balance, hlock_to_rsmc=is_htlc_to_rsmc, payment=self.payment) # sign this transaction commitment = RsmcResponsesMessage.sign_content( self.wallet, self._sign_type_list, [self.channel_name, self.nonce, self.payer_address, int(self.sender_balance), self.payee_address, int(self.receiver_balance), sign_hashcode, sign_rcode] ) # update the transaction confirming state Channel.update_trade(self.channel_name, self.nonce, balance=self.receiver_balance, peer_balance=self.sender_balance, commitment=commitment, state=EnumTradeState.confirming.name) rsmc_sign_body = self.response(self.asset_type, self.payment, self.sender_balance, self.receiver_balance, 0, self.hashcode) rsmc_sign_body.update({'Commitment': commitment}) return need_update_balance, rsmc_sign_body return need_update_balance, None
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
def record_transaction(self, nonce, **update_args): """ :param nonce: :param update_args: :return: """ # check the trade with nonce existed or not try: new_trade = Channel.query_trade(self.channel_name, nonce) except Exception as error: new_trade = None # add new transaction if new_trade: Channel.update_trade(self.channel_name, nonce=nonce, **update_args) else: Channel.add_trade(self.channel_name, nonce=nonce, **update_args) return
def terminate(self, block_height, *args, asset_type='TNC'): super(ChannelDepositEvent, self).terminate(block_height, *args) # check the deposit of the contract address total_deposit = self.contract_event_api.get_channel_total_balance(self.channel_name) if total_deposit >= self.deposit + self.partner_deposit: Channel.update_channel(self.channel_name, state=EnumChannelState.OPENED.name) Channel.update_trade(self.channel_name, self.nonce, state=EnumTradeState.confirmed.name) sync_channel_info_to_gateway(self.channel_name, 'AddChannel', asset_type) console_log.info('Channel {} state is {}'.format(self.channel_name, EnumChannelState.OPENED.name)) # to trigger monitor event for closing channel event_monitor_close_channel(self.channel_name) event_monitor_settle(self.channel_name) # to trigger monitor event for unlocking htlc locked payment event_monitor_withdraw(self.channel_name) event_monitor_withdraw_update(self.channel_name) event_monitor_withdraw_settle(self.channel_name) self.next_stage()
def notify_rcode_to_next_peer(self, next_channel): """ :param next_channel: :return: """ peer = None try: # original payer is found if not next_channel or next_channel == self.channel_name: LOG.info('HTLC Founder with HashR<{}> received the R-code<{}>'. format(self.hashcode, self.rcode)) return htlc_trade = self.get_htlc_trade_by_hashr(next_channel, self.hashcode) if htlc_trade.role == EnumTradeRole.TRADE_ROLE_PARTNER.name and next_channel != htlc_trade.channel: LOG.warning( 'Why the channel is different. next_channel<{}>, stored channel<{}>' .format(next_channel, htlc_trade.channel)) # notify the previous node the R-code LOG.debug('Payment get channel {}/{}'.format( next_channel, self.hashcode)) channel = Channel(next_channel) channel.update_trade(next_channel, htlc_trade.nonce, rcode=self.rcode) peer = channel.peer_uri(self.wallet.url) nonce = channel.latest_nonce(next_channel) LOG.info("Next peer: {}".format(peer)) self.create(next_channel, self.asset_type, nonce, self.wallet.url, peer, self.hashcode, self.rcode, self.comments) APIStatistics.update_statistics(self.wallet.address, htlc_rcode=True) except Exception as error: LOG.error('Failed to notify RCode<{}> to peer<{}>'.format( self.rcode, peer))
def add_or_update_quick_settle_trade(cls, channel_name, expected_role, **kwargs): """ :param channel_name: :param expected_role: :param kwargs: :return: """ nonce = cls._SETTLE_NONCE try: settle_trade_db = Channel.query_trade(channel_name, nonce)[0] except Exception as error: LOG.debug( 'No quick settle is created before. Exception: {}'.format( error)) Channel.add_trade(channel_name, nonce=nonce, **kwargs) else: # check the role of the database: if settle_trade_db.role != expected_role.name: # update the settle database Channel.update_trade(channel_name, nonce, **kwargs)
def handle(self): super(SettleResponseMessage, self).handle() # check response status if not self.check_response_status(self.status): return try: # common check arguments self.verify() self.check_nonce(self.nonce) settle_trade = Channel.query_trade(self.channel_name, self.nonce) self.check_signature(self.wallet, self.sender_address, type_list=self._sign_type_list, value_list=[ self.channel_name, self.nonce, self.receiver_address, int(settle_trade.balance), self.sender_address, int(settle_trade.peer_balance) ], signature=self.commitment) # update the trade Channel.update_trade(self.channel_name, SettleResponseMessage._SETTLE_NONCE, peer_commitment=self.commitment) except GoTo as error: LOG.exception(error) except Exception as error: LOG.exception( 'Handle Settle Response error. Exception: {}'.format(error)) else: # register the event to quick close channel self.register_quick_close_event() return
def handle_partner_response(self): """ :return: response to send to peer """ # local variables need_update_balance = False # handle the resign body firstly resign_ack = None resign_trade = 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 based on resign trade if not (self.commitment and self.delay_commitment): _, self.sender_balance, self.receiver_balance = self.calculate_balance_after_payment( resign_trade.balance, resign_trade.peer_balance, self.payment, is_htlc_type=True) # to check whether the negotiated nonce is legal or not self.validate_negotiated_nonce() # create htlc response message htlc_sign_body = self.response(self.sender_balance, self.receiver_balance, self.payment, self.hashcode, 1, self.delay_block) # get some common local variables sign_hashcode, sign_rcode = self.get_default_rcode() 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 # special case when nego-nonce is setting if nonce != self.nonce: # get previous record old_trade = Channel.query_trade(self.channel_name, self.nonce) # generate the htlc trade htlc_trade = Channel.htlc_trade( type=EnumTradeType.TRADE_TYPE_HTLC, role=EnumTradeRole.TRADE_ROLE_FOUNDER, asset_type=self.asset_type, balance=payer_balance, peer_balance=payee_balance, payment=payment, hashcode=self.hashcode, delay_block=old_trade.delay_block, channel=old_trade.channel) # # Update the trade or add new one self.record_transaction(nonce, **htlc_trade) # delete old one if nonce < self.nonce: Channel.delete_trade(self.channel_name, self.nonce) # Get current transaction record current_trade = Channel.query_trade(self.channel_name, nonce) if current_trade.commitment and current_trade.delay_commitment: # it means the htlc has already signed before. commitment = current_trade.commitment delay_commitment = current_trade.delay_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, is_htcl_type=True, payment=payment) # sign the transaction with 2 parts: rsmc and htlc-locked part commitment = self.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 ]) delay_commitment = self.sign_content( self.wallet, self._sign_type_list, [ self.channel_name, self.payer_address, self.payee_address, int(self.delay_block), int(payment), self.hashcode ], start=5) # update the transaction info Channel.update_trade(self.channel_name, nonce, commitment=commitment, delay_commitment=delay_commitment) # peer has already sign the new transaction with nonce if self.commitment and self.delay_commitment: # check the signature of rsmc part self.check_signature(self.wallet, self.sender_address, type_list=RsmcMessage._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) # check signature of htlc-lock part self.check_signature(self.wallet, self.sender_address, type_list=self._sign_type_list, value_list=[ self.channel_name, self.payer_address, self.payee_address, int(self.delay_block), int(payment), self.hashcode ], signature=self.delay_commitment) # update this trade confirmed state Channel.update_trade(self.channel_name, nonce, commitment=commitment, delay_commitment=delay_commitment, peer_commitment=self.commitment, peer_delay_commitment=self.delay_commitment, state=EnumTradeState.confirming.name) need_update_balance = True htlc_sign_body.update({ 'Commitment': commitment, 'DelayCommitment': delay_commitment }) # has resign response ?? if resign_ack: htlc_sign_body.update({'ResignBody': resign_ack}) return need_update_balance, htlc_sign_body
def trigger_htlc_to_next_jump(self): """""" self.router, _ = self.exclude_wallet_from_router( self.wallet.url, self.router) if not self.check_if_the_last_router(): next_router = self.next_jump LOG.debug('Get Next Router {} from {}'.format( str(next_router), self.router)) if not next_router: raise GoTo( EnumResponseStatus.RESPONSE_ROUTER_WITH_ILLEGAL_NEXT_JUMP, 'Illegal next jump<{}> in router<{}>'.format( next_router, self.router)) # to get channel between current wallet and next jump channel_set = Channel.get_channel(self.wallet.url, next_router, state=EnumChannelState.OPENED) if not (channel_set and channel_set[0]): raise GoTo( EnumResponseStatus.RESPONSE_CHANNEL_NOT_FOUND, 'No OPENED channel is found between {} and {}.'.format( self.wallet.url, next_router)) channel_set = channel_set[0] if channel_set.channel == self.channel_name: LOG.warn('Has reached receiver of HTLC transaction.') return # calculate fee and transfer to next jump fee = TrinityNumber(str(self.get_fee(self.wallet.url))).number payment = self.big_number_calculate(self.payment, fee, False) receiver = next_router HtlcMessage.create(channel_set.channel, self.asset_type, self.wallet.url, receiver, payment, self.hashcode, self.router, current_channel=self.channel_name, comments=self.comments) # record channel of next jump in current htlc trade Channel.update_trade(self.channel_name, self.nonce, channel=channel_set.channel) APIStatistics.update_statistics(self.wallet.address, htlc_free=fee) else: # trigger RResponse Channel.update_payment(self.channel_name, self.hashcode) payment_trade = Channel.query_payment(self.channel_name, self.hashcode) if not (payment_trade and payment_trade[0]): raise GoTo( EnumResponseStatus.RESPONSE_TRADE_HASHR_NOT_FOUND, 'Rcode not found for hashcode<{}>'.format(self.hashcode)) payment_trade = payment_trade[0] try: RResponse.create(self.channel_name, self.asset_type, self.nonce, self.wallet.url, self.sender, self.hashcode, payment_trade.rcode, self.comments) # update the htlc trade history Channel.update_trade(self.channel_name, self.nonce, rcode=payment_trade.rcode) except Exception as error: LOG.exception( 'Failed triggerring to send RResponse for HashR<{}>. Exception: {}' .format(self.hashcode, error))
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) sign_hashcode, sign_rcode = self.get_default_rcode() self.check_signature(self.wallet, type_list=RsmcMessage._sign_type_list, value_list=[ self.channel_name, self.nonce, self.receiver_address, int(self.sender_balance), self.sender_address, int(self.receiver_balance), sign_hashcode, sign_rcode ], signature=self.commitment) self.check_signature(self.wallet, type_list=self._sign_type_list, value_list=[ self.channel_name, self.receiver_address, self.sender_address, int(self.delay_block), int(self.payment), self.hashcode ], signature=self.delay_commitment) # update transaction Channel.update_trade(self.channel_name, int(self.nonce), peer_commitment=self.commitment, peer_delay_commitment=self.delay_commitment) # update the channel balance self.update_balance_for_channel(self.channel_name, self.asset_type, self.receiver_address, self.sender_address, self.payment, is_htlc_type=True) except TrinityException as error: LOG.error(error) status = error.reason except Exception as error: LOG.error('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)
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)
def create_resign_message_body(cls, wallet_url, channel_name, nonce, is_resign_response=False): """ :param wallet_url: current opened wallet url :param channel_name: :param nonce: :param is_resign_response: if True, it means has received the peer resign request :return: """ if not (channel_name and isinstance(nonce, int)): raise GoTo( EnumResponseStatus.RESPONSE_ILLEGAL_INPUT_PARAMETER, 'Illegal parameters: channel_name<{}> or nonce<{}, type:{}>'. format(channel_name, nonce, type(nonce))) # record the nonce negotiated by partner of the transaction with nonce # required is True if is_resign_response: nego_nonce = nonce pre_nonce = nonce pre_trade = Channel.query_trade(channel_name, nego_nonce) else: pre_trade, pre_nonce = Channel.latest_valid_trade(channel_name) nego_nonce = pre_nonce + 1 if isinstance(pre_nonce, int) else None # does founder practise fraud ??? if not (pre_trade and nego_nonce) or cls._FOUNDER_NONCE >= nego_nonce: raise GoTo(EnumResponseStatus.RESPONSE_TRADE_WITH_INCORRECT_NONCE, 'Could not finish this transaction because ') # initialize some local variables trade_role = pre_trade.role trade_type = pre_trade.type trade_state = pre_trade.state # local variables resign_body = {'Nonce': str(pre_nonce)} need_update_balance = False # is partner role of this transaction if EnumTradeRole.TRADE_ROLE_PARTNER.name == trade_role and EnumTradeState.confirming.name == trade_state: # update the resign_body by the different trade type if EnumTradeType.TRADE_TYPE_RSMC.name == trade_type: if pre_trade.peer_commitment: # update the trade to confirmed state directly Channel.update_trade(channel_name, pre_nonce, state=EnumTradeState.confirmed.name) # need update channel balance # need_update_balance = True else: # need resign this RSMC transaction by peer resign_body.update({'Commitment': pre_trade.commitment}) elif EnumTradeType.TRADE_TYPE_HTLC.name == trade_type: if pre_trade.peer_commitment and pre_trade.peer_delay_commitment: # update the trade to confirmed state directly Channel.update_trade(channel_name, pre_nonce, state=EnumTradeState.confirming.name) # need update channel balance # need_update_balance = True else: # need resign this HTLC transaction by peer resign_body.update({'Commitment': pre_trade.commitment}) resign_body.update( {'DelayCommitment': pre_trade.delay_commitment}) else: LOG.error( 'Unsupported trade type<{}> to resign in partner<{}> side'. format(trade_type, wallet_url)) return None, pre_trade # need update the channel balance or not??? # if need_update_balance: # channel = Channel(channel_name) # self_address, _, _ = uri_parser(wallet_url) # peer_address, _, _ = uri_parser(channel.peer_uri(wallet_url)) # # # ToDo: if need, here need add asset type check in future # Channel.update_channel(channel_name, balance={ # self_address: {pre_trade.asset_type: pre_trade.balance}, # peer_address: {pre_trade.asset_type: pre_trade.peer_balance} # }) elif is_resign_response is True and EnumTradeRole.TRADE_ROLE_FOUNDER.name == trade_role and \ (EnumTradeState.confirmed.name == trade_state or (EnumTradeState.confirming.name == trade_state and EnumTradeType.TRADE_TYPE_HTLC.name == trade_type)): if EnumTradeType.TRADE_TYPE_RSMC.name == trade_type: if pre_trade.peer_commitment: resign_body.update({'Commitment': pre_trade.commitment}) else: # stop transaction ???? pass elif EnumTradeType.TRADE_TYPE_HTLC.name == trade_type: if pre_trade.peer_commitment and pre_trade.peer_delay_commitment: resign_body.update({'Commitment': pre_trade.commitment}) resign_body.update( {'DelayCommitment': pre_trade.delay_commitment}) else: LOG.error( 'Unsupported trade type<{}> to resign in founder<{}> side'. format(trade_type, wallet_url)) return None, pre_trade else: return None, pre_trade # Previous transaction need to be resigned by peer if 'Commitment' in resign_body: return resign_body, pre_trade return None, pre_trade
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) nonce = self.nonce if 0 == self.role_index else self.nonce + 1 self.check_nonce(nonce, self.channel_name) is_htlc_to_rsmc = self.is_hlock_to_rsmc(self.hashcode) self.check_balance(self.channel_name, self.asset_type, self.payer, self.sender_balance, self.payee, self.receiver_balance, hlock_to_rsmc=is_htlc_to_rsmc, payment=self.payment) sign_hashcode, sign_rcode = self.get_rcode(self.channel_name, self.hashcode) self.check_signature(self.wallet, type_list=self._sign_type_list, value_list=[ self.channel_name, nonce, self.payer, int(self.sender_balance), self.payee, int(self.receiver_balance), sign_hashcode, sign_rcode ], signature=self.commitment) if 0 == self.role_index: self.rsmc_sign(self.wallet, self.channel_name, self.asset_type, self.nonce, self.sender, self.receiver, self.payment, self.sender_balance, self.receiver_balance, self.rsmc_sign_role, self.hashcode, self.comments) # update transaction Channel.update_trade(self.channel_name, self.nonce, peer_commitment=self.commitment, state=EnumTradeState.confirmed.name) Channel.confirm_payment(self.channel_name, self.hashcode, is_htlc_to_rsmc) # update the channel balance self.update_balance_for_channel(self.channel_name, self.asset_type, self.payer, self.payee, self.payment, is_htlc_to_rsmc) except GoTo as error: LOG.error(error) status = error.reason except Exception as error: status = EnumResponseStatus.RESPONSE_EXCEPTION_HAPPENED LOG.error('Failed to handle RsmcSign for channel<{}> nonce<{}>, role_index<{}>.Exception: {}' \ .format(self.channel_name, self.nonce, self.role_index, error)) finally: # send error response if EnumResponseStatus.RESPONSE_OK != status: if 0 == self.role_index: self.send_error_response(self.sender, self.receiver, self.channel_name, self.asset_type, self.nonce, status, kwargs={'RoleIndex': '1'}) # need rollback some resources self.rollback_resource(self.channel_name, self.nonce, self.payment, status=self.status) return
def handle_founder_response(self): """ :return: """ need_update_balance = False # handle the resign body firstly resign_ack = None if self.resign_body: resign_ack, _ = self.handle_resign_body(self.wallet, self.channel_name, self.resign_body) sign_hashcode, sign_rcode = self.get_default_rcode() # has already signed by peer if self.commitment and self.delay_commitment: # check the signature self.check_signature(self.wallet, self.sender_address, type_list=RsmcMessage._sign_type_list, value_list=[ self.channel_name, self.nonce, self.payer_address, int(self.sender_balance), self.payee_address, int(self.receiver_balance), sign_hashcode, sign_rcode ], signature=self.commitment) # check signature of htlc-lock part self.check_signature(self.wallet, self.sender_address, type_list=self._sign_type_list, value_list=[ self.channel_name, self.payer_address, self.payee_address, int(self.delay_block), int(self.payment), self.hashcode ], signature=self.delay_commitment) # Just update current transaction confirmed: Channel.update_trade(self.channel_name, self.nonce, peer_commitment=self.commitment, peer_delay_commitment=self.delay_commitment, state=EnumTradeState.confirming.name) need_update_balance = True else: # to check the latest confirmed nonce self.validate_transaction() # check balance after resign successfully self.check_balance(self.channel_name, self.asset_type, self.payer_address, self.sender_balance, self.payee_address, self.receiver_balance, is_htcl_type=True, payment=self.payment) # sign this transaction # sign the transaction with 2 parts: rsmc and htlc-locked part commitment = self.sign_content( self.wallet, RsmcMessage._sign_type_list, [ self.channel_name, self.nonce, self.payer_address, self.sender_balance, self.payee_address, self.receiver_balance, sign_hashcode, sign_rcode ]) delay_commitment = self.sign_content( self.wallet, self._sign_type_list, [ self.channel_name, self.payer_address, self.payee_address, int(self.delay_block), int(self.payment), self.hashcode ], start=5) # update the transaction confirming state Channel.update_trade(self.channel_name, self.nonce, balance=self.receiver_balance, peer_balance=self.sender_balance, commitment=commitment, delay_commitment=delay_commitment, state=EnumTradeState.confirming.name) # re-trigger the new transaction saved in db before htlc_sign_body = self.response(self.sender_balance, self.receiver_balance, self.payment, self.hashcode, 0, self.delay_block) htlc_sign_body.update({ 'Commitment': commitment, 'DelayCommitment': delay_commitment }) return need_update_balance, htlc_sign_body return need_update_balance, None
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(HtlcMessage, self).handle() trigger_rresponse = False status = EnumResponseStatus.RESPONSE_OK try: self.check_hashcode_used(self.channel_name, self.hashcode) self.check_channel_state(self.channel_name) self.check_router(self.router, self.hashcode) self.verify() _, nonce = self.check_nonce(self.nonce, self.channel_name) _, payer_balance, payee_balance = self.check_balance( self.channel_name, self.asset_type, self.sender_address, self.sender_balance, self.receiver_address, self.receiver_balance, is_htcl_type=True, payment=self.payment) sign_hashcode, sign_rcode = self.get_default_rcode() self.check_signature(self.wallet, type_list=RsmcMessage._sign_type_list, value_list=[ self.channel_name, self.nonce, self.sender_address, int(self.sender_balance), self.receiver_address, int(self.receiver_balance), sign_hashcode, sign_rcode ], signature=self.commitment) self.check_signature(self.wallet, type_list=self._sign_type_list, value_list=[ self.channel_name, self.sender_address, self.receiver_address, int(self.delay_block), int(self.payment), self.hashcode ], signature=self.delay_commitment) # transform the message to the next router if not last router node next_router = self.next_router if not self.check_if_the_last_router(): next_router = self.get_next_router() LOG.debug('Get Next Router {}'.format(str(next_router))) # to get channel channel_set = Channel.get_channel( self.wallet.url, next_router, state=EnumChannelState.OPENED) if not (channel_set and channel_set[0]): status = EnumResponseStatus.RESPONSE_CHANNEL_NOT_FOUND raise GoTo( EnumResponseStatus.RESPONSE_CHANNEL_NOT_FOUND, 'No OPENED channel is found between {} and {}.'.format( self.wallet.url, next_router)) channel_set = channel_set[0] # calculate fee and transfer to next jump fee = TrinityNumber(str(self.get_fee(self.wallet.url))).number payment = self.big_number_calculate(self.payment, fee, False) receiver = next_router self.create(self.wallet, channel_set.channel, self.asset_type, self.wallet.url, receiver, payment, self.hashcode, self.router, next_router, current_channel=self.channel_name, comments=self.comments) else: Channel.update_payment(self.channel_name, self.hashcode) payment_trade = Channel.query_payment(self.channel_name, self.hashcode) if not (payment_trade and payment_trade[0]): raise GoTo( EnumResponseStatus.RESPONSE_TRADE_HASHR_NOT_FOUND, 'Rcode not found for hashcode<{}>'.format( self.hashcode)) payment_trade = payment_trade[0] # trigger RResponse trigger_rresponse = True # send response to receiver HtlcResponsesMessage.create( self.wallet, self.channel_name, self.asset_type, self.nonce, self.sender, self.receiver, self.payment, self.sender_balance, self.receiver_balance, self.hashcode, self.delay_block, self.commitment, self.delay_commitment, self.router, next_router, self.comments) # means last receiver has received this htlc message, then update this trade record. if trigger_rresponse: try: RResponse.create(self.channel_name, self.asset_type, self.nonce, self.wallet.url, self.sender, self.hashcode, payment_trade.rcode, self.comments) # update the htlc trade history Channel.update_trade(self.channel_name, self.nonce, rcode=payment_trade.rcode) except Exception as error: LOG.error('Failed triggerring to send RResponse for HashR<{}>. Exception: {}'\ .format(self.hashcode, error)) except TrinityException as error: LOG.error(error) status = error.reason except Exception as error: LOG.error( 'Failed to handle Htlc message for channel<{}>, HashR<{}>. Exception:{}' .format(self.channel_name, self.hashcode, error)) status = EnumResponseStatus.RESPONSE_EXCEPTION_HAPPENED finally: # failed operation if EnumResponseStatus.RESPONSE_OK != status: # send error response HtlcResponsesMessage.send_error_response( self.sender, self.receiver, self.channel_name, self.asset_type, self.nonce, status) # delete some related resources self.rollback_resource(self.channel_name, self.nonce, self.payment, status.name) return