예제 #1
0
파일: link.py 프로젝트: guruvan/amiko-pay
	def withdraw(self, channelID):
		if not self.isConnected():
			raise Exception("Not connected")

		existingIDs = [c.ID for c in self.channels]
		if channelID not in existingIDs:
			raise Exception("Channel ID does not exist")

		channel = self.channels[existingIDs.index(channelID)]
		msg = channel.makeWithdrawMessage(None)
		if msg != None:
			self.connection.sendMessage(msg)
		self.context.sendSignal(None, event.signals.save)
예제 #2
0
파일: link.py 프로젝트: guruvan/amiko-pay
	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.")