Пример #1
0
	def msg_settleCommit(self, msg):
		transactionID = settings.hashAlgorithm(msg.token)

		ret = []

		try:
			payer = self.__getLinkObject(msg.ID)
			ret += payer.settleCommitIncoming(msg)
		except LinkNotFound:
			#Payment is committed, so payer object may already be deleted
			#Pass: continue with payee side handling and tx removing
			pass

		try:
			tx = self.findTransaction(transactionID=transactionID, payerID=msg.ID)
		except TransactionNotFound:
			#Payment is committed, so transaction object may already be deleted
			#Return here: don't remove non-existing tx
			return ret

		try:
			payee = self.__getLinkObject(tx.payeeID)
			ret += payee.settleCommitOutgoing(msg)
		except LinkNotFound:
			#Payment is committed, so payee object may already be deleted
			#Pass: continue with removing tx
			pass

		#Clean up no-longer-needed transaction:
		self.transactions.remove(tx)

		return ret
Пример #2
0
	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
				))
		]
Пример #3
0
	def settleCommitIncoming(self, msg):
		#TODO: process payload
		transactionID = settings.hashAlgorithm(msg.token)
		c = self.__findChannelWithTransaction(transactionID)
		c.settleCommitIncoming(transactionID)

		return []
Пример #4
0
	def settleCommitIncoming(self, msg):
		#TODO: process payload
		transactionID = settings.hashAlgorithm(msg.token)
		routeID = self.__makeRouteID(transactionID, msg.isPayerSide)
		c, ci = self.__findChannelWithRoute(routeID)
		return self.handleChannelOutput(
			ci,
			c.settleCommitIncoming(routeID)
			)
Пример #5
0
	def msg_commit(self, msg):
		transactionID = settings.hashAlgorithm(msg.token)
		tx = self.transactions[transactionID]
		payer = self.__getLinkObject(tx.payerID)
		payee = self.__getLinkObject(tx.payeeID)

		ret = payee.commitIncoming(msg)
		ret += payer.commitOutgoing(msg)
		ret += payee.settleCommitOutgoing(messages.SettleCommit(token=msg.token))

		return ret
Пример #6
0
	def settleCommitOutgoing(self, msg, localID):
		transactionID = settings.hashAlgorithm(msg.token)
		try:
			c = self.__findChannelWithTransaction(transactionID)
		except TransactionNotInChannelsException:
			log.log('No channel found for transaction; assuming settleCommitOutgoing was already performed, so we skip it.')
			return []

		c.settleCommitOutgoing(transactionID, msg.token)

		#TODO: add payload
		msg = copy.deepcopy(msg)
		msg.ID = self.remoteID
		return [messages.OutboundMessage(localID=localID, message=msg)]
Пример #7
0
	def msg_commit(self, msg):
		transactionID = settings.hashAlgorithm(msg.token)
		try:
			tx = self.findTransaction(transactionID=transactionID, payeeID=msg.ID)
		except TransactionNotFound:
			log.log('Received a commit message for an unknown transaction. Probably we\'ve already settled, so we ignore this.')
			return []

		payer = self.__getLinkObject(tx.payerID)
		payee = self.__getLinkObject(tx.payeeID)

		ret = payee.commitIncoming(msg)
		ret += payer.commitOutgoing(msg)
		ret += payee.settleCommitOutgoing(messages.SettleCommit(token=msg.token))

		return ret
Пример #8
0
	def msg_commit(self, msg):
		transactionID = settings.hashAlgorithm(msg.token)
		try:
			tx = self.transactions[transactionID]
		except KeyError:
			log.log('Received a commit message for an unknown transaction. Probably we\'ve already settled, so we ignore this.')
			return []

		payer = self.__getObject(tx.payerID)
		payee = self.__getObject(tx.payeeID)

		ret = payee.commitIncoming(msg)
		ret += payer.commitOutgoing(msg, tx.payerID)
		ret += payee.settleCommitOutgoing(messages.SettleCommit(token=msg.token), tx.payeeID)

		return ret
Пример #9
0
	def __init__(self, context, routingContext, ID, amount, receipt, token, suggestedMeetingPoints):
		event.Handler.__init__(self, context)
		self.routingContext = routingContext

		self.ID = ID
		self.amount = amount
		self.receipt = receipt
		self.token = token
		self.hash = settings.hashAlgorithm(self.token)
		self.suggestedMeetingPoints = suggestedMeetingPoints

		self.__meetingPoint = None #unknown
		self.__transaction = None

		self.connection = None

		self.state = self.states.initial
		self.__payerHasRoute = False
		self.__payeeHasRoute = False
Пример #10
0
	def msg_settleCommit(self, msg):
		#Special case for payee->payer transmission of this message type:
		if msg.ID == messages.payerLocalID:
			#Start settling on the payer side route,
			#no matter what the payee says.
			msg.isPayerSide = True

		transactionID = settings.hashAlgorithm(msg.token)

		ret = []

		try:
			payer = self.__getLinkObject(msg.ID)
			ret += payer.settleCommitIncoming(msg)
		except LinkNotFound:
			log.log('Payer link not found (ignored)')
			#Payment is committed, so payer object may already be deleted
			#Pass: continue with payee side handling and tx removing
			pass

		try:
			tx = self.findTransaction(
				transactionID=transactionID, payerID=msg.ID, isPayerSide=msg.isPayerSide)
		except TransactionNotFound:
			log.log('Transaction not found (ignored)')
			#Payment is committed, so transaction object may already be deleted
			#Return here: don't remove non-existing tx
			return ret

		try:
			payee = self.__getLinkObject(tx.payeeID)
			ret += payee.settleCommitOutgoing(msg)
		except LinkNotFound:
			log.log('Payee link not found (ignored)')
			#Payment is committed, so payee object may already be deleted
			#Pass: continue with removing tx
			pass

		#Clean up no-longer-needed transaction:
		self.transactions.remove(tx)

		return ret
Пример #11
0
	def msg_requestCommit(self, msg):
		transactionID = settings.hashAlgorithm(msg.token)
		try:
			tx = self.findTransaction(
				transactionID=transactionID, payeeID=msg.ID, isPayerSide=msg.isPayerSide)
		except TransactionNotFound:
			log.log('Received a request commit message for an unknown transaction. Probably we\'ve already settled, so we ignore this.')
			return []

		payer = self.__getLinkObject(tx.payerID)
		payee = self.__getLinkObject(tx.payeeID)

		tx.state = transaction.Transaction.states.requestedCommit

		ret = payee.requestCommitIncoming(msg)
		ret += payer.requestCommitOutgoing(msg)
		ret += payee.settleCommitOutgoing(
			messages.SettleCommit(token=msg.token, isPayerSide=msg.isPayerSide))

		return ret
Пример #12
0
	def msg_settleCommit(self, msg):
		transactionID = settings.hashAlgorithm(msg.token)
		tx = self.transactions[transactionID]

		ret = []

		try:
			payer = self.__getLinkObject(tx.payerID)
			ret += payer.settleCommitIncoming(msg)
		except LinkNotFound:
			pass #Payment is committed, so payer object may already be deleted

		try:
			payee = self.__getLinkObject(tx.payeeID)
			ret += payee.settleCommitOutgoing(msg)
		except LinkNotFound:
			pass #Payment is committed, so payee object may already be deleted

		#Clean up no-longer-needed transaction:
		del self.transactions[transactionID]

		return ret
Пример #13
0
	def __handleMessage(self, message):
		#log.log("Link received message: " + repr(str()))

		if message.__class__ == messages.MyURLs:
			#TODO: check URLs for validity etc.
			#TODO: support multiple remote URLs (for now, just pick the first)
			remoteURL = message.getURLs()[0]
			URL = urlparse(remoteURL)

			oldRemoteID = self.remoteID
			oldRemoteURL = self.remoteURL

			self.remoteID = URL.path[1:]
			self.remoteURL = remoteURL

			if oldRemoteID != self.remoteID or oldRemoteURL != self.remoteURL:
				self.context.sendSignal(None, event.signals.save)

		elif message.__class__ == messages.MakeRoute:
			log.log("Link received MakeRoute")

			try:
				#TODO: do all sorts of checks to see if it makes sense to perform
				#the transaction over this link.
				#For instance, check the responsiveness of the other side, etc. etc.

				#This will check whether enough funds are availbale
				#Note: if we're on the PAYER side of the meeting point,
				#then we're on the PAYEE side of this link, for this transaction.
				#TODO: use multiple channels
				self.channels[0].reserve(
					not message.isPayerSide, message.hash, message.amount)

				#TODO: exception handling for the above

			except channel.CheckFail as f:
				log.log("Route refused by link: " + str(f))

				#Send back a cancel immediately
				#TODO

				return

			if message.isPayerSide:
				self.openTransactions[message.hash] = transaction.Transaction(
					self.context, self.routingContext,
					message.amount, message.hash, message.meetingPoint,
					payerLink=self)
			else:
				self.openTransactions[message.hash] = transaction.Transaction(
					self.context, self.routingContext,
					message.amount, message.hash, message.meetingPoint,
					payeeLink=self)

			#This will start the transaction routing
			self.openTransactions[message.hash].msg_makeRoute()

		elif message.__class__ == messages.HaveRoute:
			log.log("Link received HaveRoute")
			self.openTransactions[message.value].msg_haveRoute(self)

		elif message.__class__ == messages.Lock:
			log.log("Link received Lock")

			#TODO: get new Bitcoin transaction from message and
			# pass it to channel
			#TODO: use multiple channels
			self.channels[0].lockIncoming(message.value)
			#TODO: exception handling for the above

			self.context.sendSignal(None, event.signals.save)

			self.openTransactions[message.value].msg_lock()

		elif message.__class__ == messages.Commit:
			log.log("Link received Commit")
			token = message.value
			hash = settings.hashAlgorithm(token)

			#TODO: get new Bitcoin transaction from message and
			# pass it to channel
			#TODO: use multiple channels
			self.channels[0].commitIncoming(hash)
			#TODO: exception handling for the above

			self.context.sendSignal(None, event.signals.save)

			self.openTransactions[hash].msg_commit(token)

			#We don't need this anymore:
			del self.openTransactions[hash]

		else:
			log.log("Link received unsupported message: %s" % str(message))
Пример #14
0
	def __init__(self, **kwargs):
		serializable.Serializable.__init__(self, **kwargs)

		#This will fail if token is not set (is None).
		#So, token must always be set for successful construction.
		self.transactionID = settings.hashAlgorithm(self.token)
Пример #15
0
	def __handleMessage(self, message):
		log.log("Link received message (%s -> %s): %s" % \
			(str(self.remoteID), str(self.localID), str(message) ))

		if message.__class__ == messages.MyURLs:
			#TODO: check URLs for validity etc.
			#TODO: support multiple remote URLs (for now, just pick the first)
			remoteURL = message.getURLs()[0]
			URL = urlparse(remoteURL)

			oldRemoteID = self.remoteID
			oldRemoteURL = self.remoteURL

			self.remoteID = URL.path[1:]
			self.remoteURL = remoteURL

			if oldRemoteID != self.remoteID or oldRemoteURL != self.remoteURL:
				self.context.sendSignal(None, event.signals.save)

		elif message.__class__ == messages.MakeRoute:
			try:
				#TODO: do all sorts of checks to see if it makes sense to perform
				#the transaction over this link.
				#For instance, check the responsiveness of the other side, etc. etc.

				#This will check whether enough funds are availbale
				#Note: if we're on the PAYER side of the meeting point,
				#then we're on the PAYEE side of this link, for this transaction.
				#TODO: use multiple channels
				self.channels[0].reserve(
					not message.isPayerSide,
					message.hash, message.startTime, message.endTime,
					message.amount)

				#TODO: exception handling for the above

			except channel.CheckFail as f:
				log.log("Route refused by link: " + str(f))

				#Send back a have no route immediately
				#TODO

				return

			if message.isPayerSide:
				self.openTransactions[message.hash] = transaction.Transaction(
					self.context, self.routingContext, message.meetingPoint,
					message.amount,
					message.hash, message.startTime, message.endTime,
					payerLink=self)
			else:
				self.openTransactions[message.hash] = transaction.Transaction(
					self.context, self.routingContext, message.meetingPoint,
					message.amount,
					message.hash, message.startTime, message.endTime,
					payeeLink=self)

			#This will start the transaction routing
			#Give it our own ID, to prevent routing back to this link.
			self.openTransactions[message.hash].msg_makeRoute(self.localID)

		elif message.__class__ == messages.HaveNoRoute:
			#TODO: use multiple channels
			tx = self.openTransactions[message.value]
			self.channels[0].unreserve(tx.isPayerSide, tx.hash)
			tx.msg_haveNoRoute()

		elif message.__class__ == messages.HaveRoute:
			tx = self.openTransactions[message.hash]

			startTime, endTime = message.startTime, message.endTime
			if not tx.isPayerSide:
				#TODO: on payee side, check equality of timestamp values

				#On the payee side, don't overwrite the values that are
				#already in the transaction.
				#Note that these are different from the ones received in the
				#message.
				startTime, endTime = tx.startTime, tx.endTime

			tx.msg_haveRoute(self, startTime, endTime)

		elif message.__class__ == messages.Lock:
			#TODO: check that we're the payee side

			#TODO: use multiple channels
			self.channels[0].lockIncoming(message)
			#TODO: exception handling for the above

			self.context.sendSignal(None, event.signals.save)

			self.openTransactions[message.hash].msg_lock()


		elif message.__class__ == messages.RequestCommit:
			token = message.value
			hash = settings.hashAlgorithm(token)

			#If hash is not in openTransactions, then either the commit token
			#was wrong, or e.g. we already removed the transaction because
			#we received the token from the payer side.
			if hash in self.openTransactions:
				#TODO: check time-out
				#TODO: check that we're the payer side

				#TODO: use multiple channels
				message = self.channels[0].commitOutgoing(hash, token)

				self.context.sendSignal(None, event.signals.save)

				self.connection.sendMessage(message)

				#Now also request a commit on our upstream payer side
				self.openTransactions[hash].msg_requestCommit(token)

				#We don't need this anymore:
				del self.openTransactions[hash]


		elif message.__class__ == messages.Commit:
			token = message.token
			hash = settings.hashAlgorithm(token)

			#TODO: check that we're the payee side

			#TODO: use multiple channels
			self.channels[0].commitIncoming(hash, message)
			#TODO: exception handling for the above

			self.context.sendSignal(None, event.signals.save)

			#If hash is not in openTransactions, then either the commit token
			#was wrong, or e.g. we already removed the transaction because
			#we received the token from the payee side.
			if hash in self.openTransactions:
				self.openTransactions[hash].msg_commit(token)

				#We don't need this anymore:
				del self.openTransactions[hash]


		elif message.__class__ == messages.Deposit:
			existingIDs = [c.ID for c in self.channels]

			if message.isInitial:
				if message.channelID in existingIDs:
					log.log("Initial deposit message contains already existing channel ID")
					#TODO: send refusal reply?
				elif message.type not in ["multisig"]:
					log.log("Initial deposit message with unsupported channel type")
					#TODO: send refusal reply?
				else:
					newChannel = multisigchannel.constructFromDepositMessage(
						self.bitcoind, message)
					self.channels.append(newChannel)
					reply = newChannel.makeDepositMessage(message)
					if reply != None:
						self.connection.sendMessage(reply)
					self.context.sendSignal(None, event.signals.save)
			else:
				try:
					channel = self.channels[existingIDs.index(message.channelID)]
					reply = channel.makeDepositMessage(message)
					if reply != None:
						self.connection.sendMessage(reply)
					self.context.sendSignal(None, event.signals.save)
				except ValueError:
					log.log("Follow-up deposit message contains non-existing channel ID")
					#TODO: send refusal reply?

		elif message.__class__ == messages.Withdraw:
			existingIDs = [c.ID for c in self.channels]

			try:
				channel = self.channels[existingIDs.index(message.channelID)]
				reply = channel.makeWithdrawMessage(message)
				if reply != None:
					self.connection.sendMessage(reply)
				self.context.sendSignal(None, event.signals.save)
			except ValueError:
				log.log("Withdraw message contains non-existing channel ID")
				#TODO: send refusal reply?

		else:
			log.log("Link: message type is not supported; message ignored.")
Пример #16
0
    def __init__(self, **kwargs):
        serializable.Serializable.__init__(self, **kwargs)

        #This will fail if token is not set (is None).
        #So, token must always be set for successful construction.
        self.transactionID = settings.hashAlgorithm(self.token)