def msg_haveRoute(self, msg): #Special case for payee->payer transmission of this message type: if msg.ID == messages.payerLocalID: return self.payerLink.haveRouteIncoming(msg) #TODO: check sanity (and data type) of startTime, endTime ret = [] if msg.isPayerSide: tx = self.findTransaction( transactionID=msg.transactionID, payeeID=msg.ID, isPayerSide=True) payer = self.__getLinkObject(tx.payerID) payee = self.__getLinkObject(tx.payeeID) ret += payee.haveRouteIncoming(msg) msg.ID = tx.payerID msg.endTime += self.settings.timeoutIncrement ret += payer.haveRouteOutgoing(msg) else: tx = self.findTransaction( transactionID=msg.transactionID, payerID=msg.ID, isPayerSide=False) payer = self.__getLinkObject(tx.payerID) payee = self.__getLinkObject(tx.payeeID) ret += payer.haveRouteIncoming(msg) msg.ID = tx.payeeID msg.endTime -= self.settings.timeoutIncrement ret += payee.haveRouteOutgoing(msg) #TODO: compare startTime, endTime with MakeRoute values tx.state = transaction.Transaction.states.haveRoute #Lock time-out: #TODO: configurable time-out value? ret.append(messages.TimeoutMessage(timestamp=time.time()+5.0, message=\ messages.NodeStateTimeout_Lock( transactionID=msg.transactionID, isPayerSide=msg.isPayerSide, payerID=tx.payerID ))) #Clean up route time-out: ret.append(messages.FilterTimeouts(function = lambda message: not ( isinstance(message, messages.NodeStateTimeout_Route) and message.transactionID == msg.transactionID and message.isPayerSide == msg.isPayerSide and message.payerID == tx.payerID ))) return ret
def requestCommitOutgoing(self, msg): if self.state != self.states.locked: raise Exception( "requestCommitOutgoing should not be called in state %s" % \ self.state ) self.state = self.states.receivedRequestCommit self.token = msg.token #TODO: maybe check? return \ [ messages.TimeoutMessage(timestamp=time.time()+1.0, message=\ self.getTimeoutMessage() #Add time-out to go to commit ) ]
def msg_makePayer(self, msg): if not (self.payerLink is None): raise Exception("There already is a payment in progress") self.payerLink = payerlink.PayerLink( payeeLinkID=msg.payeeLinkID, routingContext=msg.routingContext) self.connections[messages.payerLocalID] = \ persistentconnection.PersistentConnection( host=msg.host, port=msg.port, connectMessage=messages.Pay(ID=msg.payeeLinkID) ) #Returned messages: return [ messages.TimeoutMessage(timestamp=time.time()+5.0, message=\ self.payerLink.getTimeoutMessage() #Add time-out for payer ) ]
def lockOutgoing(self, msg): routeID = self.__makeRouteID(msg.transactionID, msg.isPayerSide) c, ci = self.__findChannelWithRoute(routeID) c.lockOutgoing(routeID) commitTimeout = c.getOutgoingCommitTimeout(routeID) #TODO: add payload msg = copy.deepcopy(msg) msg.ID = self.remoteID msg.channelIndex = ci return \ [ messages.OutboundMessage(localID=self.localID, message=msg), messages.TimeoutMessage( timestamp=commitTimeout, message=messages.LinkTimeout_Commit( transactionID=msg.transactionID, isPayerSide=msg.isPayerSide, ID=self.localID )) ]
def msg_haveNoRoute(self, msg): log.log('Processing HaveNoRoute message') try: if msg.isPayerSide: tx = self.findTransaction( transactionID=msg.transactionID, payeeID=msg.ID, isPayerSide=True) else: tx = self.findTransaction( transactionID=msg.transactionID, payerID=msg.ID, isPayerSide=False) except TransactionNotFound: log.log(' HaveNoRoute failed: transaction %s does not (or no longer) exist (ignored)' % \ msg.transactionID.encode('hex')) return [] payer = self.__getLinkObject(tx.payerID) payee = self.__getLinkObject(tx.payeeID) ret = [] if tx.isPayerSide: ret += payee.haveNoRouteIncoming(msg) else: ret += payer.haveNoRouteIncoming(msg) #Clean up old route and lock time-out: oldPayerID = tx.payerID #keep reference to innermost object ret.append(messages.FilterTimeouts(function = lambda message: not ( isinstance(message, (messages.NodeStateTimeout_Route, messages.NodeStateTimeout_Lock)) and message.transactionID == msg.transactionID and message.isPayerSide == msg.isPayerSide and message.payerID == oldPayerID ))) #Try to find another route nextRoute = tx.tryNextRoute() if nextRoute is None: log.log(' No remaining route found') if tx.isPayerSide: ret += payer.haveNoRouteOutgoing(msg.transactionID, isPayerSide=True) else: ret += payee.haveNoRouteOutgoing(msg.transactionID, isPayerSide=False) #Clean up cancelled transaction: self.transactions.remove(tx) return ret log.log(' Forwarding MakeRoute to the next route') ret += self.__getLinkObject(nextRoute).makeRouteOutgoing( messages.MakeRoute( amount = tx.amount, transactionID = msg.transactionID, startTime = tx.startTime, endTime = tx.endTime, meetingPointID = tx.meetingPointID, ID = nextRoute, isPayerSide = tx.isPayerSide )) #route time-out: #TODO: configurable time-out value? ret.append(messages.TimeoutMessage(timestamp=time.time()+5.0, message=\ messages.NodeStateTimeout_Route( transactionID=msg.transactionID, isPayerSide=msg.isPayerSide, payerID=tx.payerID ))) return ret
def msg_makeRoute(self, msg): log.log('Processing MakeRoute message') sourceLink = self.__getLinkObject(msg.ID) ret = sourceLink.makeRouteIncoming(msg) payerID, payeeID = \ { True: (msg.ID, None), False: (None, msg.ID) }[msg.isPayerSide] #Possible routes we can take if msg.routingContext is None: #Order is important: try meeting points first possibleLinks = self.meetingPoints.keys() + self.links.keys() else: possibleLinks = [msg.routingContext] def tryRemove(ID): try: possibleLinks.remove(ID) except ValueError: pass #it's OK if the source link wasn't present already #Remove the source link: tryRemove(msg.ID) #Remove source link and possible routes of earlier instances of #this route: #for these, the route should be made by the earlier instance. #Allowing them to be selected by later instances would allow #infinite routing loops. #Note: generally, this will remove ALL routes, if earlier instances of #the same route exist. The only situation where this is not the case #is when an earlier instance was restricted in its routing choices, #and, theoretically, when a new route was created in-between. earlierTransactions = self.findMultipleTransactions( transactionID=msg.transactionID, isPayerSide=msg.isPayerSide) for earlierTx in earlierTransactions: earlierSourceLinkID = earlierTx.payerID if msg.isPayerSide else earlierTx.payeeID tryRemove(earlierSourceLinkID) for ID in earlierTx.initialLinkIDs: tryRemove(ID) #Increment end time on the payee side: #On the payer side, this will be done in haveRoute. if not msg.isPayerSide: #TODO: check sanity (and data type) of startTime, endTime msg.endTime += self.settings.timeoutIncrement #Create new transaction newTx = transaction.Transaction( state=transaction.Transaction.states.makingRoute, isPayerSide=msg.isPayerSide, payeeID=payeeID, payerID=payerID, initialLinkIDs=possibleLinks[:], remainingLinkIDs=possibleLinks[:], meetingPointID=msg.meetingPointID, amount=msg.amount, transactionID=msg.transactionID, startTime=msg.startTime, endTime=msg.endTime ) self.transactions.append(newTx) nextRoute = newTx.tryNextRoute() if nextRoute is None: log.log(' No route found') #Delete the tx we just created: self.transactions.remove(newTx) #Send back haveNoRoute: ret += sourceLink.haveNoRouteOutgoing( msg.transactionID, msg.isPayerSide) return ret log.log(' Forwarding MakeRoute to the first route') ret += self.__getLinkObject(nextRoute).makeRouteOutgoing(msg) #route time-out: #TODO: configurable time-out value? ret.append(messages.TimeoutMessage(timestamp=time.time()+5.0, message=\ messages.NodeStateTimeout_Route( transactionID=msg.transactionID, isPayerSide=msg.isPayerSide, payerID=newTx.payerID ))) return ret