Skip to content

Commit b7ff4a9

Browse files
committed
Complete section: Proof of Work
1 parent 5ec3f51 commit b7ff4a9

10 files changed

Lines changed: 132 additions & 12 deletions

File tree

README.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,13 @@ source blockchain-env/bin/activate
55

66
**Install all packages**
77
```
8-
pip install -r requirements.txt
8+
pip3 install -r requirements.txt
99
```
1010

1111
**Run the tests**
1212

13-
1413
Make sure to activate the virtual environment.
1514

16-
1715
```
1816
python3 -m pytest backend/tests
1917
```

backend/blockchain/block.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import time
22

33
from backend.util.crypto_hash import crypto_hash
4+
<<<<<<< HEAD
5+
=======
6+
from backend.util.hex_to_binary import hex_to_binary
7+
>>>>>>> a77fccd... Complete proof of work section
48
from backend.config import MINE_RATE
59

610
GENESIS_DATA = {
@@ -25,9 +29,12 @@ def __init__(self, timestamp, last_hash, hash, data, difficulty, nonce):
2529
self.difficulty = difficulty
2630
self.nonce = nonce
2731

32+
<<<<<<< HEAD
2833
def add_block(self, data):
2934
self.chain.append(Block(data))
3035

36+
=======
37+
>>>>>>> a77fccd... Complete proof of work section
3138
def __repr__(self):
3239
return (
3340
'Block('
@@ -51,7 +58,7 @@ def mine_block(last_block, data):
5158
nonce = 0
5259
hash = crypto_hash(timestamp, last_hash, data, difficulty, nonce)
5360

54-
while hash[0:difficulty] != '0' * difficulty:
61+
while hex_to_binary(hash)[0:difficulty] != '0' * difficulty:
5562
nonce += 1
5663
timestamp = time.time_ns()
5764
difficulty = Block.adjust_difficulty(last_block, timestamp)
@@ -70,8 +77,8 @@ def genesis():
7077
def adjust_difficulty(last_block, new_timestamp):
7178
"""
7279
Calculate the adjusted difficulty according to the MINE_RATE.
73-
Increase the difficulty for slowly mined blocks.
7480
Decrease the difficulty for slowly mined blocks.
81+
Increase the difficulty for quickly mined blocks.
7582
"""
7683
if (new_timestamp - last_block.timestamp) < MINE_RATE:
7784
return last_block.difficulty + 1
@@ -84,7 +91,14 @@ def adjust_difficulty(last_block, new_timestamp):
8491
def main():
8592
genesis_block = Block.genesis()
8693
block = Block.mine_block(genesis_block, 'foo')
94+
<<<<<<< HEAD
8795
print(f'block: {block}')
8896

8997
if __name__ == '__main__':
9098
main()
99+
=======
100+
print(block)
101+
102+
if __name__ == '__main__':
103+
main()
104+
>>>>>>> a77fccd... Complete proof of work section

backend/blockchain/blockchain.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ def main():
2020
blockchain.add_block('two')
2121

2222
print(blockchain)
23-
print(f'blockchain.py __name__: {__name__}')
23+
print(f'blockchain.py ___name__: {__name__}')
2424

2525
if __name__ == '__main__':
2626
main()

backend/config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@
33
MILLISECONDS = 1000 * MICROSECONDS
44
SECONDS = 1000 * MILLISECONDS
55

6-
MINE_RATE = 4 * SECONDS
6+
MINE_RATE = 4 * SECONDS
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import time
2+
3+
from backend.blockchain.blockchain import Blockchain
4+
from backend.config import SECONDS
5+
6+
blockchain = Blockchain()
7+
8+
times = []
9+
10+
for i in range(1000):
11+
start_time = time.time_ns()
12+
blockchain.add_block(i)
13+
end_time = time.time_ns()
14+
15+
time_to_mine = (end_time - start_time) / SECONDS
16+
times.append(time_to_mine)
17+
18+
average_time = sum(times) / len(times)
19+
20+
print(f'New block difficulty: {blockchain.chain[-1].difficulty}')
21+
print(f'Time to mine new block: {time_to_mine}s')
22+
print(f'Average time to add blocks: {average_time}s\n')
Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1+
import time
2+
13
from backend.blockchain.block import Block, GENESIS_DATA
4+
from backend.config import MINE_RATE, SECONDS
5+
from backend.util.hex_to_binary import hex_to_binary
26

37
def test_mine_block():
48
last_block = Block.genesis()
@@ -8,10 +12,39 @@ def test_mine_block():
812
assert isinstance(block, Block)
913
assert block.data == data
1014
assert block.last_hash == last_block.hash
11-
assert block.hash[0:block.difficulty] == '0' * block.difficulty
15+
assert hex_to_binary(block.hash)[0:block.difficulty] == '0' * block.difficulty
1216

1317
def test_genesis():
1418
genesis = Block.genesis()
19+
1520
assert isinstance(genesis, Block)
1621
for key, value in GENESIS_DATA.items():
17-
assert getattr(genesis, key) == value
22+
getattr(genesis, key) == value
23+
24+
def test_quickly_mined_block():
25+
last_block = Block.mine_block(Block.genesis(), 'foo')
26+
mined_block = Block.mine_block(last_block, 'bar')
27+
28+
assert mined_block.difficulty == last_block.difficulty + 1
29+
30+
def test_slowly_mined_block():
31+
last_block = Block.mine_block(Block.genesis(), 'foo')
32+
time.sleep(MINE_RATE / SECONDS)
33+
mined_block = Block.mine_block(last_block, 'bar')
34+
35+
assert mined_block.difficulty == last_block.difficulty - 1
36+
37+
def test_mined_block_difficulty_limits_at_1():
38+
last_block = Block(
39+
time.time_ns(),
40+
'test_last_hash',
41+
'test_hash',
42+
'test_data',
43+
1,
44+
0
45+
)
46+
47+
time.sleep(MINE_RATE / SECONDS)
48+
mined_block = Block.mine_block(last_block, 'bar')
49+
50+
assert mined_block.difficulty == 1
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from backend.util.crypto_hash import crypto_hash
22

33
def test_crypto_hash():
4-
# It should create the same hash with arguments of different data types in
5-
# any order
4+
# It should create the same hash with arguments of different data types
5+
# in any order
66
assert crypto_hash(1, [2], 'three') == crypto_hash('three', 1, [2])
77
assert crypto_hash('foo') == 'b2213295d564916f89a6a42455567c87c3f480fcd7a1c15e220f17d7169a790b'
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from backend.util.hex_to_binary import hex_to_binary
2+
3+
def test_hex_to_binary():
4+
original_number = 789
5+
hex_number = hex(original_number)[2:]
6+
binary_number = hex_to_binary(hex_number)
7+
8+
assert int(binary_number, 2) == original_number

backend/util/crypto_hash.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,4 @@ def main():
1515
print(f"crypto_hash(2, 'one', [3]): {crypto_hash(2, 'one', [3])}")
1616

1717
if __name__ == '__main__':
18-
main()
18+
main()

backend/util/hex_to_binary.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
from backend.util.crypto_hash import crypto_hash
2+
3+
HEX_TO_BINARY_CONVERSION_TABLE = {
4+
'0': '0000',
5+
'1': '0001',
6+
'2': '0010',
7+
'3': '0011',
8+
'4': '0100',
9+
'5': '0101',
10+
'6': '0110',
11+
'7': '0111',
12+
'8': '1000',
13+
'9': '1001',
14+
'a': '1010',
15+
'b': '1011',
16+
'c': '1100',
17+
'd': '1101',
18+
'e': '1110',
19+
'f': '1111'
20+
}
21+
22+
def hex_to_binary(hex_string):
23+
binary_string = ''
24+
25+
for character in hex_string:
26+
binary_string += HEX_TO_BINARY_CONVERSION_TABLE[character]
27+
28+
return binary_string
29+
30+
def main():
31+
number = 451
32+
hex_number = hex(number)[2:]
33+
print(f'hex_number: {hex_number}')
34+
35+
binary_number = hex_to_binary(hex_number)
36+
print(f'binary_number: {binary_number}')
37+
38+
original_number = int(binary_number, 2)
39+
print(f'original_number: {original_number}')
40+
41+
hex_to_binary_crypto_hash = hex_to_binary(crypto_hash('test-data'))
42+
print(f'hex_to_binary_crypto_hash: {hex_to_binary_crypto_hash}')
43+
44+
if __name__ == '__main__':
45+
main()

0 commit comments

Comments
 (0)