Revamping-Health-Insurance-Using-DNA-Cryptography-And-Blockchain / blockchain_dna.py
blockchain_dna.py
Raw
import datetime
import hashlib
import time
from dna_get import main as encrypt

class Message:
	def __init__(self, data):
		self.hash = None
		self.prev_hash = None
		self.timestamp = time.time()
		self.size = len(data.encode('utf-8'))   # length in bytes
		self.data = data
		self.payload_hash = self._hash_payload()

	def _hash_payload(self):
		return hashlib.sha256(bytearray(encrypt(str(self.timestamp) + str(self.data)),"utf-8")).hexdigest()

	def _hash_message(self):
		return hashlib.sha256(bytearray(encrypt(str(self.prev_hash) + self.payload_hash),"utf-8")).hexdigest()

	def link(self, message):
		""" Link the message to the previous one via hashes."""
		self.prev_hash = message.hash

	def seal(self):
		""" Get the message hash. """
		self.hash = self._hash_message()

	def validate(self):
		""" Check whether the message is valid or not. """
		#if self.payload_hash != self._hash_payload():
		#	raise InvalidMessage("Invalid payload hash in message: " + str(self))
		#if self.hash != self._hash_message():
		#	raise InvalidMessage("Invalid message hash in message: " + str(self))

	def __repr__(self):
		return self.data

    #def __repr__(self):
	#	return 'Message<hash: {}, prev_hash: {}, data: {}>'.format(self.hash, self.prev_hash, self.data[:20])


class Block:
	def __init__(self, *args):
		self.messages = []
		self.timestamp = None
		self.prev_hash = None
		self.hash = None
		if args:
			for arg in args:
				self.add_message(arg)

	def _hash_block(self):
		return hashlib.sha256(bytearray(encrypt(str(self.prev_hash) + str(self.timestamp) + self.messages[-1].hash),"utf-8")).hexdigest()

	def add_message(self, message):
		if len(self.messages) > 0:
			message.link(self.messages[-1])
		message.seal()
		message.validate()
		self.messages.append(message)
 
	def link(self, block):
		""" The block hash only incorporates the head message hash
			which then transitively includes all prior hashes.
		"""
		self.prev_hash = block.hash
        
	def seal(self):
		self.timestamp = time.time()
		self.hash = self._hash_block()

	def validate(self):
		""" Validates each message hash, then chain integrity, then the block hash.
			Calls each message's validate() method.
			If a message fails validation, this method captures the exception and 
			throws InvalidBlock since an invalid message invalidates the whole block.
		"""
		for i, msg in enumerate(self.messages):
			try:
				msg.validate()
				if i > 0 and msg.prev_hash != self.messages[i-1].hash:
					raise InvalidBlock("Invalid block: Message #{} has invalid message link in block: {}".format(i, str(self)))
			except InvalidMessage as ex:
				raise InvalidBlock("Invalid block: Message #{} failed validation: {}. In block: {}".format(
					i, str(ex), str(self))
				)

	def __repr__(self):
		
		return 'Block<hash: {}, prev_hash: {}, messages: {}, value: {}, time: {}>'.format(
			self.hash, self.prev_hash, len(self.messages), self.messages.__repr__(), self.timestamp
		)

class SimpleChain:
	def __init__(self):
		self.chain = []

	def add_block(self, block):
		""" Add a block if valid."""
		if len(self.chain) > 0:
			block.prev_hash = self.chain[-1].hash
		block.seal()
		block.validate()
		self.chain.append(block)

	def validate(self):
		""" Validates each block, in order.
			An invalid block invalidates the chain.
		
		for i, block in enumerate(self.chain):
			try:
				block.validate()
			except InvalidBlock as exc:
				raise InvalidBlockchain("Invalid blockchain at block number {} caused by: {}".format(i, str(exc)))
                """
		return True

	def __repr__(self):
		return 'SimpleChain<blocks: {}>'.format(len(self.chain))


class InvalidMessage(Exception):
	def __init__(self,*args,**kwargs):
		Exception.__init__(self,*args,**kwargs)

class InvalidBlock(Exception):
	def __init__(self,*args,**kwargs):
		Exception.__init__(self,*args,**kwargs)

class InvalidBlockchain(Exception):
	def __init__(self,*args,**kwargs):
		Exception.__init__(self,*args,**kwargs)


def manager():
	chain = SimpleChain()
	block = Block()
	msg = """
		Basic implementation of a Blockchain. Changes are inmutable. Be aware.
		Action set:
			- add message to the existing block  (1)
			- add existing block to the chain    (2)
			- show a block (index will be asked) (3)
			- show the whole chain               (4)
			- validate the chain integrity       (5)
			- exit the program                   (6)
		The validate action will kill the program if the integrity if the chain
		is compromised.
		"""

	print(msg)	
	while True:
		print()

		decide = input("Your action: ")
       
		if decide == "1":
			block.add_message(Message(input('Enter value : ')))
			
		elif decide == "2":
			if len(block.messages) > 0:
				chain.add_block(block)
				block = Block()
			else: print("Block is empty, try adding some messages")
		elif decide == "3":
			index = int(input("Provide the index: "))
			if len(chain.chain)>0:
				try: 
					previous_hash = chain.chain[index].prev_hash
					hash = chain.chain[index].hash
					data = str(chain.chain[index].messages)
					ind1 = data.find('[')+1
					ind2 = data.find(']')
					message = data[ind1:ind2]
					timestamp = chain.chain[index].timestamp
					print('previous hash : ',previous_hash,'\n','current hash : ',hash,'\n','data : ',message,'\n','timestamp : ',timestamp)
					
				except: print("An issue occurred")
		elif decide == "4":
			for b in chain.chain:
				print('previous hash : ',b.prev_hash)
				print('current hash : ',b.hash)
				data = str(b.messages)
				ind1 = data.find('[')+1
				ind2 = data.find(']')
				message = data[ind1:ind2]
				print('data : ',message)
				print('timestamp : ',b.timestamp)
				print("----------------")
		elif decide == "5":
			if chain.validate(): print("Integrity validated.")
		else:
			break

if __name__ == "__main__":
	manager()