-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathblockchain.py
More file actions
97 lines (72 loc) · 3.28 KB
/
blockchain.py
File metadata and controls
97 lines (72 loc) · 3.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# blockchain.py
# Final Project - Gabe Kotsonis, Boxian Wang, George McNulty, Karimi Itani
# implementation of a class for the entire blockchain
# NOTE: The structure of this code is partially borrowed from https://www.activestate.com/blog/how-to-build-a-blockchain-in-python/
import time
import json
from block import Block
class Blockchain:
def __init__(self, init=True, chain=[], length=0):
if init:
# initialize empty chain and pending transactions as private variables
self._chain = []
# start with 0 blocks
self._length = 0
# create block object for this initial block
initial_block = Block(0, "", "0")
# add this block to the chain
self.add_block(initial_block)
else:
# initialize empty chain and pending transactions as private variables
self._chain = chain
# start with 0 blocks
self._length = length
def get_length(self):
return self._length
def get_data(self):
return [i.get_data() for i in self._chain][1:]
# add a new block to the chain, no verification is performed
def add_block(self, block):
# append to chain
self._chain.append(block)
# adjust length
self._length += 1
# return a mined block based on the previous hash
@staticmethod
def mine_block(data, prev_hash, index):
new_block = Block(index, data, prev_hash)
# get the hash of this block
hash = new_block.compute_hash()
# re-compute hash with new nonce until we get a hash that starts with
# "difficulty" number of zeroes
while not hash.startswith('0' * new_block.get_diff()):
# increment the nonce, recompute hash
new_block.inc_nonce()
hash = new_block.compute_hash()
# set the value of the proof to this final computed hash
time.sleep(5) # wait here to create a feeling of hard work... use this to test fork
return new_block
# return the hash of the last block in the chain
def get_last_hash(self):
return self._chain[-1].compute_hash()
# check if a proof is valid
def verify_block(self, block):
# check the proof and hash
return (block.compute_hash().startswith('0' * block.get_diff())) and (self.get_last_hash() == block.get_prev_hash())
# verifies the whole chain
def verify_chain(self):
for i in range(1, self._length):
block = self._chain[i]
if (not block.compute_hash().startswith('0' * block.get_diff())): return False # satisfies proof of work
if (block.get_prev_hash() != self._chain[i - 1].compute_hash()): return False # check hash chaining
return True
# to and from json
def to_json(self):
return json.dumps(vars(self), sort_keys=True, default=Block.to_json)
@staticmethod
def load_json(json_string):
chain_dict = json.loads(json_string)
block_decoder = lambda d: Block(d['_index'], d['_data'], d['_prev_hash'], d['_nonce'])
chain = [block_decoder(json.loads(i)) for i in chain_dict['_chain']]
length = chain_dict['_length']
return Blockchain(init=False, chain=chain, length=length)