194 lines
6.2 KiB
Python
194 lines
6.2 KiB
Python
# -*- 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
|
|
|