Created
August 23, 2018 09:23
-
-
Save Orbifold/78baacdd4d9d6e1f00bec8e7309675ff to your computer and use it in GitHub Desktop.
Poor man's basic blockchain implementation to grasp the principles.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import hashlib as hasher | |
import datetime as date | |
import requests | |
import time | |
import math | |
import uuid | |
import random | |
class Block: | |
""" | |
The basic unit of a blockchain. | |
""" | |
def __init__(self, index, data, previous_hash): | |
if index is None or not isinstance(index, int) or index < 0: | |
raise Exception("Given index is not acceptable.") | |
self.index = index | |
self.timestamp = date.datetime.now() | |
self.data = data | |
self.previous_hash = previous_hash | |
sha = hasher.sha256() | |
sha.update(str(self.index).encode('utf-8') + str(self.timestamp).encode( | |
'utf-8') + str(self.data).encode('utf-8') + str(self.previous_hash).encode('utf-8')) | |
self.hash = sha.hexdigest() | |
class Chain: | |
""" | |
The basic blockchain. | |
""" | |
def __init__(self): | |
self.head = Block(0, "Genesis", "0") | |
self.tail = self.head | |
self._blocks = [self.tail] | |
def __iter__(self): | |
return self._blocks.__iter__() | |
def append(self, data: str): | |
self._blocks.append(Block(self.tail.index + 1, data, self.tail.hash)) | |
self.tail = self._blocks[-1] | |
return self.tail | |
def __str__(self): | |
return f"Chain of length {len(self._blocks)}" | |
def serialize(self): | |
coll = [] | |
for block in self._blocks: | |
coll.append({ | |
"index": str(block.index), | |
"timestamp": str(block.timestamp), | |
"data": str(block.data), | |
"hash": block.hash | |
}) | |
return coll | |
def last(self): | |
return self.tail | |
# { | |
# "from": "public key 1", | |
# "to": "public key 2", | |
# "value": 45 | |
# } | |
class Node: | |
def __init__(self): | |
self._address = str(uuid.uuid4()) | |
self._chain = Chain() | |
self._peers = [] | |
self._transactions = [] | |
def add_transaction(self, tx): | |
self._transactions.append(tx) | |
def add_peer(self,url): | |
self._peers.append(url) | |
def get_peer_chains(self): | |
coll = [] | |
for node_url in self._peers: | |
try: | |
blocks = requests.get(f"{node_url}/blocks").content | |
blocks = json.loads(blocks) | |
coll.append(blocks) | |
except Exception: | |
pass | |
return coll | |
def get_blocks(self): | |
return self._chain.serialize() | |
def get_transactions(self): | |
return self._transactions | |
def consensus(self): | |
# accept the longest one | |
other_chains = self.get_peer_chains() | |
longest_chain = self._chain | |
for chain in other_chains: | |
if len(longest_chain) < len(chain): | |
longest_chain = chain | |
self._chain = longest_chain | |
def proof_of_work(self,last_proof): | |
# compute something intense and return your supposedly good answer to the puzzle | |
time.sleep(2) | |
return random.randint(1, 1e12) | |
def mine(self): | |
last_block = self._chain.last() | |
last_proof = last_block.data | |
proof = self.proof_of_work(last_proof) | |
self._transactions.append( | |
{ | |
"from": "network", | |
"to": self._address, | |
"amount": 1 | |
} | |
) | |
self._chain.append(proof) | |
return self._chain.last() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment