Example #1
0
	def makeT1AndT2(self):
		fee = 10000 #0.1 mBTC (TODO: make configurable)

		if self.amountLocal <= 2*fee: #both deposit and withdraw fees
			raise Exception("The deposited amount needs to be more than the transaction fees")

		ownPubKey = self.ownKey.getPublicKey()
		peerPubKey = self.peerKey.getPublicKey()
		returnKeyHash = crypto.RIPEMD160(crypto.SHA256(ownPubKey))

		#We send an extra fee here, so that T2's initial return becomes
		# exactly self.amountLocal
		assert self.hasFirstPublicKey
		self.T1 = sendToMultiSigPubKey(self.bitcoind, self.amountLocal + fee,
			ownPubKey,
			peerPubKey,
			returnKeyHash,
			fee)

		T1_ID = self.T1.getTransactionID() #opposite endianness as in Bitcoind

		#TODO: set lock time!!!
		lockTime = 0
		#The amount argument is the amount in the INPUT of T2, so it's again
		#with an added fee, to make the OUTPUT equal to self.amountLocal.
		self.T2_latest = MultiSigTransaction.makeNew(
			self.ownKey, T1_ID, self.amountLocal + fee, fee, lockTime)
Example #2
0
	def __init__(self, bitcoind, state):
		channel.Channel.__init__(self, state)
		self.bitcoind = bitcoind

		self.stage = stages[state["stage"]] #name -> integer

		self.ownAddress = str(state["ownAddress"])
		ownPrivateKey = base58.decodeBase58Check(
			self.bitcoind.getPrivateKey(self.ownAddress), 128
			)
		self.ownKey = crypto.Key()
		self.ownKey.setPrivateKey(ownPrivateKey)

		self.peerKey = None
		if "peerPublicKey" in state:
			self.peerKey = crypto.Key()
			self.peerKey.setPublicKey(
				binascii.unhexlify(state["peerPublicKey"])
				)

		self.escrowKey = None
		if "escrowPublicKey" in state:
			self.escrowKey = crypto.Key()
			self.escrowKey.setPublicKey(
				binascii.unhexlify(state["escrowPublicKey"])
				)

		self.hasFirstPublicKey = bool(state["hasFirstPublicKey"])

		self.T1 = None
		self.T2_peerSigned = None
		self.T2_latest = None
		self.peerSignature = None
		if "T1" in state:
			self.T1 = bitcointransaction.Transaction.deserialize(
				binascii.unhexlify(state["T1"])
				)
		if "T2_peerSigned" in state:
			self.T2_peerSigned = MultiSigTransaction.makeFromState(
				state["T2_peerSigned"])
		if "T2_latest" in state:
			self.T2_latest = MultiSigTransaction.makeFromState(
				state["T2_latest"])
		if "peerSignature" in state:
			self.peerSignature = binascii.unhexlify(state["peerSignature"])
Example #3
0
	def processTransactionPayload(self, payload):
		peerSignature = payload[0]
		T2 = MultiSigTransaction.deserialize(payload[1])

		pubKey1, pubKey2 = self.getPublicKeyPair()
		if not verifyMultiSigSignature(
			T2.transaction, 0, [pubKey1, pubKey2], self.peerKey, peerSignature):
				raise Exception("Signature failure!") #TODO: what to do now?

		#TODO: lots of checks on T2 (IMPORTANT!)

		self.peerSignature = peerSignature
		self.T2_latest = T2
		self.T2_peerSigned = copy.deepcopy(T2)
Example #4
0
	def makeWithdrawMessage(self, message):
		self.checkT1()

		#TODO: make some code to enter the "stopping" state prior to withdrawing,
		#and then wait until there are no more ongoing transactions.
		#This is not necessary for low-volume tests in controlled environments,
		#but as soon as people start transferring other peoples' transactions,
		#you want to be able to stop other peoples' transactions from
		#interfering with your withdrawal.
		if self.stage == stages["Ready"]:
			self.stage = stages["Stopping"]

		self.checkStopped()

		if message == None:
			if self.stage != stages["Stopped"]:
				raise Exception("Can not withdraw: channel must be Stopped, but is " + \
					stageNames[self.stage])

			self.makeWithdrawT2()
			self.stage = stages["OwnWithdraw_SendingT2"]
			return messages.Withdraw(
				self.ID, stage=self.stage, payload=[self.T2_latest.serialize()])

		elif self.stage == stages["Stopped"] and \
			message.stage == stages["OwnWithdraw_SendingT2"]:

			#Received T2
			self.T2_latest = MultiSigTransaction.deserialize(message.payload[0])
			#TODO: maybe re-serialize to check consistency
			#TODO: lots of checks on T2 (IMPORTANT!)
			pubKey1, pubKey2 = self.getPublicKeyPair()
			signature = signMultiSigTransaction(
				self.T2_latest.transaction, 0, [pubKey1, pubKey2], self.ownKey)
			self.stage = stages["PeerWithdraw_SendingSignature"]
			return messages.Withdraw(
				self.ID, stage=self.stage, payload=[signature])

		elif self.stage == stages["OwnWithdraw_SendingT2"] and \
			message.stage == stages["PeerWithdraw_SendingSignature"]:

			peerSignature = message.payload[0]
			pubKey1, pubKey2 = self.getPublicKeyPair()
			if not verifyMultiSigSignature(
				self.T2_latest.transaction, 0,
				[pubKey1, pubKey2], self.peerKey, peerSignature):
					raise Exception("Signature failure!") #TODO: what to do now?

			ownSignature = signMultiSigTransaction(
				self.T2_latest.transaction, 0, [pubKey1, pubKey2], self.ownKey)

			if self.hasFirstPublicKey:
				applyMultiSigSignatures(self.T2_latest.transaction, ownSignature, peerSignature)
			else:
				applyMultiSigSignatures(self.T2_latest.transaction, peerSignature, ownSignature)

			self.peerSignature = peerSignature
			self.T2_peerSigned = copy.deepcopy(self.T2_latest)
			self.stage = stages["Closed"]

			#Publish T2 in Bitcoind
			T2_serialized = self.T2_latest.transaction.serialize()
			self.bitcoind.sendRawTransaction(T2_serialized)

			return messages.Withdraw(
				self.ID, stage=self.stage, payload=[T2_serialized])

		elif self.stage == stages["PeerWithdraw_SendingSignature"] and \
			message.stage == stages["Closed"]:

			T2 = bitcointransaction.Transaction.deserialize(message.payload[0])
			#TODO: maybe re-serialize to check consistency
			#TODO: lots of checks on T2 (IMPORTANT!)

			#TODO:
			#self.T2_latest = T2
			#self.peerSignature = TODO
			#self.T2_peerSigned = copy.deepcopy(T2)
			self.stage = stages["Closed"]

			#Publish T2 in Bitcoind
			T2_serialized = message.payload[0]
			self.bitcoind.sendRawTransaction(T2_serialized)

			print "DONE"

		else:
			raise Exception("Received illegal withdraw message")

		return None
Example #5
0
	def makeDepositMessage(self, message):
		if self.stage == stages["OwnDeposit_Initial"] and \
			message == None:

			#Initial message:
			self.stage = stages["OwnDeposit_SendingPublicKey"]
			return messages.Deposit(
				self.ID, self.getType(), isInitial=True, stage=self.stage,
				payload=[self.ownKey.getPublicKey(), self.escrowKey.getPublicKey()])

		elif self.stage == stages["PeerDeposit_Initial"] and \
			message.stage == stages["OwnDeposit_SendingPublicKey"]:

			#Received deposit message with public key from peer
			self.peerKey = crypto.Key()
			self.peerKey.setPublicKey(message.payload[0])
			self.escrowKey = crypto.Key()
			self.escrowKey.setPublicKey(message.payload[1])
			#TODO: check whether the escrow key is accepted
			self.stage = stages["PeerDeposit_SendingPublicKey"]
			return messages.Deposit(
				self.ID, self.getType(), stage=self.stage,
				payload=[self.ownKey.getPublicKey()])

		elif self.stage == stages["OwnDeposit_SendingPublicKey"] and \
			message.stage == stages["PeerDeposit_SendingPublicKey"]:

			#Received reply on own deposit message
			self.peerKey = crypto.Key()
			self.peerKey.setPublicKey(message.payload[0])
			self.makeT1AndT2()
			self.stage = stages["OwnDeposit_SendingT2"]
			return messages.Deposit(
				self.ID, self.getType(), stage=self.stage,
				payload=[self.T2_latest.serialize()])

		elif self.stage == stages["PeerDeposit_SendingPublicKey"] and \
			message.stage == stages["OwnDeposit_SendingT2"]:

			#Received T2
			self.T2_latest = MultiSigTransaction.deserialize(message.payload[0])
			#TODO: maybe re-serialize to check consistency
			self.amountRemote = sum(tx.amount for tx in self.T2_latest.transaction.tx_out)
			assert not self.hasFirstPublicKey
			signature = signMultiSigTransaction(
				self.T2_latest.transaction, 0,
				[self.peerKey.getPublicKey(), self.ownKey.getPublicKey()],
				self.ownKey)
			self.stage = stages["PeerDeposit_SendingSignature"]
			return messages.Deposit(
				self.ID, self.getType(), stage=self.stage, payload=[signature])

		elif self.stage == stages["OwnDeposit_SendingT2"] and \
			message.stage == stages["PeerDeposit_SendingSignature"]:

			signature = message.payload[0]
			assert self.hasFirstPublicKey
			if not verifyMultiSigSignature(
				self.T2_latest.transaction, 0,
				[self.ownKey.getPublicKey(), self.peerKey.getPublicKey()],
				self.peerKey, signature):
					raise Exception("Signature failure!") #TODO: what to do now?
			self.peerSignature = signature
			self.T2_peerSigned = copy.deepcopy(self.T2_latest)
			T1_serialized = self.T1.serialize()
			self.stage = stages["WaitingForT1"]

			#Publish T1 in Bitcoind
			self.bitcoind.sendRawTransaction(T1_serialized)

			return messages.Deposit(
				self.ID, self.getType(), stage=self.stage, payload=[T1_serialized])

		elif self.stage == stages["PeerDeposit_SendingSignature"] and \
			message.stage == stages["WaitingForT1"]:

			T1_serialized = message.payload[0]
			self.T1 = bitcointransaction.Transaction.deserialize(T1_serialized)
			#TODO: maybe re-serialize to check consistency
			#TODO: check T1 (and that it matches T2)

			self.stage = stages["WaitingForT1"]

			#Publish T1 in Bitcoind
			self.bitcoind.sendRawTransaction(T1_serialized)

			print "DONE"

		else:
			raise Exception("Received illegal deposit message")

		return None