def makeRouteOutgoing(self, msg): routeID = self.__makeRouteID(msg.transactionID, msg.isPayerSide) isOutgoing = msg.isPayerSide #Try the channels one by one: for i, c in enumerate(self.channels): #Reserve funds in channel. try: c.reserve(isOutgoing, routeID, msg.startTime, msg.endTime, msg.amount) except Exception as e: #TODO: make sure the state of the channel is restored? log.log("Reserving on channel %d failed: returned exception \"%s\"" % (i, str(e))) continue log.log("Reserving on channel %d succeeded" % i) msg = copy.deepcopy(msg) msg.ID = self.remoteID msg.channelIndex = i return \ [ messages.OutboundMessage(localID=self.localID, message=msg) ] #None of the channels worked (or there are no channels): #TODO: haveNoRoute return []
def settleCommitOutgoing(self, msg): transactionID = settings.hashAlgorithm(msg.token) routeID = self.__makeRouteID(transactionID, msg.isPayerSide) try: c, ci = self.__findChannelWithRoute(routeID) except RouteNotInChannelsException: log.log('No channel found for route; assuming settleCommitOutgoing was already performed, so we skip it.') return [] ret = self.handleChannelOutput( ci, c.settleCommitOutgoing(routeID, msg.token) ) #TODO: add payload msg = copy.deepcopy(msg) msg.ID = self.remoteID return ret + \ [ messages.OutboundMessage(localID=self.localID, message=msg), messages.FilterTimeouts(function = lambda message: \ not( isinstance(message, messages.LinkTimeout_Commit) and message.transactionID == transactionID and message.isPayerSide == msg.isPayerSide and message.ID == self.localID )) ]
def haveRouteOutgoing(self, msg): #Simply pass it to the payer, who keeps track of whether the route is complete return \ [ messages.OutboundMessage(localID = msg.ID, message = \ messages.HaveRoute(transactionID=None, isPayerSide=False) ) ]
def haveNoRouteOutgoing(self, transactionID, isPayerSide): self.state = self.states.cancelled return self.__removeTimeouts() + \ [ messages.OutboundMessage(localID = messages.payerLocalID, message = \ messages.Cancel() ), messages.SetEvent(event=messages.SetEvent.events.paymentFinished) ]
def msg_confirm(self, msg): log.log("PayerLink: Received confirm: %s" % str(msg.agreement)) if self.state != self.states.hasReceipt: raise Exception( "msg_confirm should not be called in state %s" % \ self.state ) ret = [] if msg.agreement: self.state = self.states.confirmed ret = \ [ messages.OutboundMessage(localID = messages.payerLocalID, message = \ messages.Confirm(meetingPointID=self.meetingPointID) ), messages.MakeRoute( #This will start the transaction routing ID=messages.payerLocalID, routingContext=self.routingContext, amount=self.amount, transactionID=self.transactionID, startTime=None, #Will be received from the payee side endTime=None, #Will be received from the payee side meetingPointID=self.meetingPointID, isPayerSide=True ) ] else: self.state = self.states.cancelled ret = self.__removeTimeouts() + \ [ messages.OutboundMessage(localID = messages.payerLocalID, message = \ messages.Cancel() ), messages.SetEvent(event=messages.SetEvent.events.paymentFinished) ] return ret
def haveRouteOutgoing(self, msg): routeID = self.__makeRouteID(msg.transactionID, msg.isPayerSide) isOutgoing = not msg.isPayerSide c, ci = self.__findChannelWithRoute(routeID) c.updateReservation(isOutgoing, routeID, msg.startTime, msg.endTime) #Forward to peer: msg = copy.deepcopy(msg) msg.ID = self.remoteID return [messages.OutboundMessage(localID=self.localID, message=msg)]
def lockOutgoing(self, msg): log.log("Payee: locked; committing") self.state = self.states.sentRequestCommit return \ [ messages.RequestCommit(ID=self.ID, token=self.token, isPayerSide=False), messages.OutboundMessage(localID = self.ID, message = \ messages.SettleCommit(token=self.token) ) ]
def cancelOutgoing(self, msg): routeID = self.__makeRouteID(msg.transactionID, msg.isPayerSide) isOutgoing = msg.isPayerSide c, ci = self.__findChannelWithRoute(routeID) ret = self.handleChannelOutput( ci, c.unreserve(isOutgoing, routeID) ) msg = copy.deepcopy(msg) msg.ID = self.remoteID return ret + [messages.OutboundMessage(localID=self.localID, message=msg)]
def settleRollbackOutgoing(self, msg): #TODO: process payload routeID = self.__makeRouteID(msg.transactionID, msg.isPayerSide) c, ci = self.__findChannelWithRoute(routeID) ret = self.handleChannelOutput( ci, c.settleRollbackOutgoing(routeID) ) #TODO: add payload msg = copy.deepcopy(msg) msg.ID = self.remoteID return ret + [messages.OutboundMessage(localID=self.localID, message=msg)]
def msg_pay(self, msg): if self.state != self.states.initial: raise Exception( "msg_pay should not be called in state %s" % \ self.state ) return [messages.OutboundMessage(localID = msg.ID, message = \ messages.Receipt( amount=self.amount, receipt=self.receipt, transactionID=self.transactionID, meetingPoints=self.meetingPoints ))]
def haveNoRouteOutgoing(self, transactionID, isPayerSide): if self.state != self.states.confirmed: raise Exception( "haveNoRouteOutgoing should not be called in state %s" % \ self.state ) self.state = self.states.cancelled return \ [ messages.OutboundMessage(localID = self.ID, message = \ messages.Cancel() ) ]
def haveNoRouteOutgoing(self, transactionID, isPayerSide): routeID = self.__makeRouteID(transactionID, isPayerSide) isOutgoing = not isPayerSide c, ci = self.__findChannelWithRoute(routeID) ret = self.handleChannelOutput( ci, c.unreserve(isOutgoing, routeID) ) return ret + \ [ messages.OutboundMessage(localID=self.localID, message=messages.HaveNoRoute( transactionID=transactionID, isPayerSide=isPayerSide)) ]
def settleRollbackOutgoing(self, msg): if self.state != self.states.locked: raise Exception( "settleRollbackOutgoing should not be called in state %s" % \ self.state ) log.log("Payer: received settleRollback -> cancelled") self.state = self.states.cancelled return self.__removeTimeouts() + \ [ messages.OutboundMessage(localID = messages.payerLocalID, message = \ messages.Cancel() ), messages.SetEvent(event=messages.SetEvent.events.paymentFinished) ]
def msg_ownDeposit(self, msg): if self.remoteID is None: raise Exception('Can not deposit into a link whose remote ID is unknown') self.channels.append(msg.channel) channelIndex = len(self.channels) - 1 #Allow the channel to start a conversation with the peer, #related to the deposit. return \ [ messages.OutboundMessage(localID=self.localID, message=messages.Deposit( channelIndex=channelIndex, channelClass=str(msg.channel.__class__.__name__) )) ] + \ self.startChannelConversation(channelIndex)
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 handleChannelOutput(self, channelIndex, channelOutput): log.log("Channel output: " + str(channelOutput)) channelMessages, otherMessages = channelOutput ret = otherMessages for msg in ret: if isinstance(msg, messages.BitcoinCommand): msg.returnID = self.localID msg.returnChannelIndex = channelIndex elif isinstance(msg, messages.NodeState_TimeoutRollback): msg.ID = self.localID msg.isPayerSide, msg.transactionID = \ self.__decodeRouteID(msg.transactionID) ret += \ [ messages.OutboundMessage(localID=self.localID, message=messages.ChannelMessage( channelIndex=channelIndex, message=m)) for m in channelMessages ] return ret
def requestCommitOutgoing(self, msg): msg = copy.deepcopy(msg) msg.ID = self.remoteID return [messages.OutboundMessage(localID=self.localID, message=msg)]