-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathblockchain.py
157 lines (130 loc) · 4.45 KB
/
blockchain.py
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
from hashlib import sha256 # import sha256 from hashlib
from datetime import datetime # import datetime
now = datetime.now() # get the current time
time = now.strftime("%d/%m/%Y %H:%M:%S") # format the time
# Takes in any number of arguments and produces a sha256 hash as a result
def updatehash(*args):
"""
Takes in any number of arguments and produces a sha256 hash as a result.
Args:
- args: Any number of arguments to be hashed.
Returns:
- The sha256 hash of the concatenated arguments.
"""
hashing_text = ""
h = sha256() # initialize sha256
# loop through each argument and hash
for arg in args:
hashing_text += str(arg) # concatenate the argument
h.update(hashing_text.encode('utf-8')) # update the hash
return h.hexdigest() # return the hash
# The "node" of the blockchain. Points to the previous block by its unique hash in previous_hash.
class Block():
"""
A class representing a block in the blockchain.
Attributes:
- number: The number of the block.
- previous_hash: The hash of the previous block.
- sender: The sender of the transaction.
- recipient: The recipient of the transaction.
- amount: The amount of the transaction.
- nonce: The nonce value of the block.
Methods:
- hash: Returns the sha256 hash of the block's data.
- __str__: Returns a string representation of the block's data.
"""
def __init__(self, number=0, previous_hash="0"*64, sender=None, recipient=None, amount=None, nonce=0):
self.sender = sender
self.recipient = recipient
self.amount = amount
self.number = number
self.previous_hash = previous_hash
self.nonce = nonce
def hash(self):
"""
Returns the sha256 hash of the block's data.
Returns:
- The sha256 hash of the block's data.
"""
return updatehash(
self.number,
self.previous_hash,
self.sender,
self.recipient,
self.amount,
self.nonce
)
def __str__(self):
"""
Returns a string representation of the block's data.
Returns:
- A string representation of the block's data.
"""
return str("Block#: %s\nHash: %s\nPrevious: %s\nSender: %s\nRecipient: %s\nAmount: %s\nNonce: %s\n" % (
self.number,
self.hash(),
self.previous_hash,
self.sender,
self.recipient,
self.amount,
self.nonce
))
# The "LinkedList" of the blocks - a chain of blocks.
class Blockchain():
"""
A class representing a blockchain.
Attributes:
- difficulty: The number of zeros in front of each hash.
- chain: A list representing the blocks in the blockchain.
Methods:
- __init__: Initializes a new blockchain.
- add: Adds a new block to the chain.
- remove: Removes a block from the chain.
- mine: Finds the nonce of the block that satisfies the difficulty and adds it to the chain.
- isValid: Checks if the blockchain is valid.
"""
difficulty = 4
def __init__(self):
self.chain = []
def add(self, block):
"""
Adds a new block to the chain.
Args:
- block: The block to be added to the chain.
"""
self.chain.append(block)
def remove(self, block):
"""
Removes a block from the chain.
Args:
- block: The block to be removed from the chain.
"""
self.chain.remove(block)
def mine(self, block):
"""
Finds the nonce of the block that satisfies the difficulty and adds it to the chain.
Args:
- block: The block to be mined.
"""
try:
block.previous_hash = self.chain[-1].hash()
except IndexError:
pass
while True:
if block.hash()[:self.difficulty] == "0" * self.difficulty:
self.add(block)
break
else:
block.nonce += 1
def isValid(self):
"""
Checks if the blockchain is valid.
Returns:
- True if the blockchain is valid, False otherwise.
"""
for i in range(1, len(self.chain)):
_previous = self.chain[i].previous_hash
_current = self.chain[i-1].hash()
if _previous != _current or _current[:self.difficulty] != "0"*self.difficulty:
return False
return True