Skip to content

Commit

Permalink
Add chain support
Browse files Browse the repository at this point in the history
  • Loading branch information
dhruv-aggarwal committed Jan 30, 2018
1 parent 1a24d02 commit 30aa5a3
Show file tree
Hide file tree
Showing 5 changed files with 156 additions and 22 deletions.
9 changes: 1 addition & 8 deletions app/managers/block.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,9 @@
from common import get_block_filename, calculate_hash
import json
from common import calculate_hash
from datetime import datetime
from app.models.block import Block
from config import NUM_ZEROS


def save_block(block):
filename = get_block_filename(block.index)
with open(filename, 'w') as block_file:
json.dump(block.__dict__(), block_file)


def mine(last_block):
index = int(last_block.index) + 1
timestamp = datetime.utcnow()
Expand Down
21 changes: 21 additions & 0 deletions app/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
def getter_setter_gen(name, type_):
def getter(self):
return getattr(self, "__" + name)

def setter(self, value):
if not isinstance(value, type_):
raise TypeError(
"%s attribute must be set to an instance of %s" % (name, type_)
)
setattr(self, "__" + name, value)
return property(getter, setter)


def auto_attr_check(cls):
new_dct = {}
for key, value in cls.__dict__.items():
if isinstance(value, type):
value = getter_setter_gen(key, value)
new_dct[key] = value
# Creates a new class, using the modified dictionary as the class dict:
return type(cls)(cls.__name__, cls.__bases__, new_dct)
67 changes: 54 additions & 13 deletions app/models/block.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
from config import num_zeores
import json
from common import get_block_filename


class Block(object):
def __init__(self, **kwargs):
"""
Expand All @@ -6,31 +11,67 @@ def __init__(self, **kwargs):
:param index: The index for the number of blocks in the chain
:type index: int
:param hash: The hash specific for this block
:type index: basestring
:type hash: basestring
:param timestamp: The time when this block was created
:type index: int
:type timestamp: int
:param data: Data contained by this block
:type index: str (json)
:type data: str (json)
:param prev_hash: The hash for the previous block in the chain
:type index: str
:param nonce: Counter used for the proof of work implementation
:type index: int
:type prev_hash: str
:param nonce: For identifying unique requests
:type nonce: str
"""
self.index = kwargs.get('index')
self.hash = kwargs.get('hash')
self.timestamp = kwargs.get('timestamp')
self.data = kwargs.get('data')
self.prev_hash = kwargs.get('prev_hash')
self.nonce = kwargs.get('nonce')
self.block_data_types = {
'index': int,
'nonce': int,
'hash': str,
'prev_hash': str,
'timestamp': int,
'data': str
}
for key, value in kwargs.iteritems():
if key in self.block_data_types:
setattr(self, key, self.block_data_types[key](value))
else:
setattr(self, key, value)

def __dict__(self):
return {
'index': str(self.index),
'timestamp': str(self.timestamp),
'prev_hash': str(self.prev_hash),
'hash': str(self.hash),
'data': str(self.data)
'data': str(self.data),
'nonce': str(self.nonce)
}

def __eq__(self, other):
return (
self.index == other.index and
self.timestamp == other.timestamp and
self.prev_hash == other.prev_hash and
self.hash == other.hash and
self.data == other.data and
self.nonce == other.nonce
)

def __ne__(self, other):
return not self.__eq__(other)

def __str__(self):
return "Block<prev_hash: %s,hash: %s>" % (self.prev_hash, self.hash)

def is_valid_block(self):
"""
Current validity is only that the hash begins with at least NUM_ZEROS
"""
if str(self.hash[0:num_zeores]) == '0' * num_zeores:
return True
return False

def save(self):
# Fill the index with leading zeroes so that we can see the files in
# alphabetical order
filename = get_block_filename(str(self.index).zfill(8))
with open(filename, 'w') as block_file:
json.dump(self.__dict__(), block_file)
78 changes: 78 additions & 0 deletions app/models/chain.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
from block import Block


class Chain:
def __init__(self, blocks):
self.blocks = blocks

def is_valid(self):
'''
Is a valid blockchain if
1) Each block is indexed one after the other
2) Each block's prev hash is the hash of the prev block
3) The block's hash is valid for the number of zeros
'''
for index, cur_block in enumerate(self.blocks[1:]):
prev_block = self.blocks[index]
if prev_block.index + 1 != cur_block.index:
return False
if not cur_block.is_valid():
return False
if prev_block.hash != cur_block.prev_hash:
return False
return True

def save(self):
'''
Save the blockchain to the file system
'''
for block in self.blocks:
block.save()

def find_block_by_hash(self, b_hash):
for block in self.blocks:
if block.hash == b_hash:
return block
return None

def find_block_by_index(self, index):
if len(self) <= index:
return self.blocks[index]
else:
return False

def __len__(self):
return len(self.blocks)

def __gt__(self, other):
return len(self) > len(other)

def __ge__(self, other):
return self.__eq__(other) or self.__gt__(other)

def __eq__(self, other):
if len(self) != len(other):
return False
for self_block, other_block in zip(self.blocks, other.blocks):
if self_block != other_block:
return False
return True

def max_index(self):
'''
We're assuming a valid chain. Might change later
'''
return self.blocks[-1].index

def add_block(self, new_block):
'''
Put the new block into the index that the block is asking.
That is, if the index is of one that currently exists, the new block
would take it's place. Then we want to see if that block is valid.
If it isn't, then we ditch the new block and return False.
'''
self.blocks.append(new_block)
return True

def block_list_dict(self):
return [b.to_dict() for b in self.blocks]
3 changes: 2 additions & 1 deletion config.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
blockchain_dir = 'data'
NUM_ZEROS = 4
broadcast_blockchain_dir = 'broadcast'
num_zeores = 5

0 comments on commit 30aa5a3

Please sign in to comment.