# -*- coding: utf-8 -*- # =================================================== # ==================== META DATA =================== # ================================================== __author__ = "Daxeel Soni" __url__ = "https://daxeel.github.io" __email__ = "daxeelsoni44@gmail.com" __license__ = "MIT" __version__ = "0.1" __maintainer__ = "Daxeel Soni" # ================================================== # ================= IMPORT MODULES ================= # ================================================== import os import hashlib import datetime import json from colorama import Fore, Back, Style import time import sys import base64 from numpy import random from PIL import Image # ================================================== # =================== BLOCK CLASS ================== # ================================================== class Block: """ Create a new block in chain with metadata """ def __init__(self): self.index = -1 self.previousHash = "" self.uid_epita = -1 self.email_epita = "" self.firstname = "" self.lastname = "" self.image = "" self.timestamp = str(datetime.datetime.now()) self.nonce = 0 self.hash = self.calculateHash() @classmethod def fromSave(cls, data): block = cls() for key, value in data.items(): setattr(block, key, value) return block @classmethod def fromValues(cls, uid_epita, email_epita, firstname, lastname, index = 0): block = cls() block.index = index block.uid_epita = uid_epita block.email_epita = email_epita block.firstname = firstname block.lastname = lastname block.createRandomImage() return block def calculateHash(self): """ Method to calculate hash from metadata """ hashData = str(self.index) + str(self.previousHash) + str(self.uid_epita) + str(self.email_epita) + str(self.firstname) + str(self.lastname) + str(self.image) + str(self.timestamp) + str(self.nonce) return hashlib.sha256(hashData.encode('utf-8')).hexdigest() def mineBlock(self, difficulty): """ Method for Proof of Work """ print(Back.RED + "\n[Status] Mining block (" + str(self.index) + ") with PoW ...") startTime = time.time() self.hash = "" while self.hash[:difficulty] != "0"*difficulty: self.nonce += 1 self.hash = self.calculateHash() endTime = time.time() print(Back.BLUE + "[ Info ] Time Elapsed : " + str(endTime - startTime) + " seconds.") print(Back.BLUE + "[ Info ] Mined Hash : " + self.hash) print(Style.RESET_ALL) def createRandomImage(self): """ Method to create random image in base64 """ imgarray = random.rand(30, 30, 3) * 255 image = Image.fromarray(imgarray.astype('uint8')).convert('RGB') image.save('random.png') with open("random.png", "rb") as imageFile: self.image = str(base64.b64encode(imageFile.read())) if os.path.exists("random.png"): os.remove("random.png") # ================================================== # ================ BLOCKCHAIN CLASS ================ # ================================================== class Blockchain: """ Initialize blockchain """ def __init__(self): self.chain = [self.createGenesisBlock()] self.difficulty = 3 def createGenesisBlock(self): """ Method create genesis block """ return Block.fromValues(-1, "init@epita.fr", "Genesis", "Block") def addBlock(self, newBlock): """ Method to add new block from Block class """ newBlock.index = len(self.chain) newBlock.previousHash = self.chain[-1].hash newBlock.mineBlock(self.difficulty) self.chain.append(newBlock) self.writeBlocks() def writeBlocks(self): """ Method to write new mined block to blockchain """ with open("chain.txt", "w") as dataFile: chainData = [] for eachBlock in self.chain: chainData.append(eachBlock.__dict__) dataFile.write(json.dumps(chainData, indent=4)) def loadBlocks(self, filename): """ Method to load existing blockchain from file """ try: with open(filename, "r") as dataFile: chainData = json.loads(dataFile.read()) self.chain = [] for eachBlock in chainData: self.chain.append(Block.fromSave(eachBlock)) except Exception as e: print(Back.RED + "[Error] No existing blockchain found.") print(Back.RED + "[Error] Creating new blockchain.") print(Style.RESET_ALL) self.writeBlocks() def modifyBlock(self, hash, uid_epita, email_epita, firstname, lastname): """ Method to modify existing block """ i = 0 for i in range(len(self.chain)): eachBlock = self.chain[i] if eachBlock.hash == hash: eachBlock.uid_epita = uid_epita eachBlock.email_epita = email_epita eachBlock.firstname = firstname eachBlock.lastname = lastname eachBlock.createRandomImage() eachBlock.mineBlock(self.difficulty) break if i == len(self.chain) - 1: return False for i in range(i+1, len(self.chain)): eachBlock = self.chain[i] eachBlock.index = i eachBlock.previousHash = self.chain[i-1].hash eachBlock.mineBlock(self.difficulty) self.writeBlocks() return True def isChainValid(self): """ Method to verify integrity of blockchain """ for i in range(1, len(self.chain)): eachBlock = self.chain[i] if eachBlock.hash != eachBlock.calculateHash(): return i if eachBlock.previousHash != self.chain[i-1].hash: return i return 0