|
1 | 1 | import time |
2 | 2 |
|
3 | 3 | from backend.util.crypto_hash import crypto_hash |
| 4 | +from backend.util.hex_to_binary import hex_to_binary |
4 | 5 | from backend.config import MINE_RATE |
5 | 6 |
|
6 | 7 | GENESIS_DATA = { |
@@ -48,7 +49,7 @@ def mine_block(last_block, data): |
48 | 49 | nonce = 0 |
49 | 50 | hash = crypto_hash(timestamp, last_hash, data, difficulty, nonce) |
50 | 51 |
|
51 | | - while hash[0:difficulty] != '0' * difficulty: |
| 52 | + while hex_to_binary(hash)[0:difficulty] != '0' * difficulty: |
52 | 53 | nonce += 1 |
53 | 54 | timestamp = time.time_ns() |
54 | 55 | difficulty = Block.adjust_difficulty(last_block, timestamp) |
@@ -78,10 +79,44 @@ def adjust_difficulty(last_block, new_timestamp): |
78 | 79 |
|
79 | 80 | return 1 |
80 | 81 |
|
| 82 | + @staticmethod |
| 83 | + def is_valid_block(last_block, block): |
| 84 | + """ |
| 85 | + Validate block by enforcing the following rules: |
| 86 | + - the block must have the proper last_hash reference |
| 87 | + - the block must meet the proof of work requirement |
| 88 | + - the difficulty must only adjust by 1 |
| 89 | + - the block hash must be a valid combination of the block fields |
| 90 | + """ |
| 91 | + if block.last_hash != last_block.hash: |
| 92 | + raise Exception('The block last_hash must be correct') |
| 93 | + |
| 94 | + if hex_to_binary(block.hash)[0:block.difficulty] != '0' * block.difficulty: |
| 95 | + raise Exception('The proof of work requirement was not met') |
| 96 | + |
| 97 | + if abs(last_block.difficulty - block.difficulty) > 1: |
| 98 | + raise Exception('The block difficulty must only adjust by 1') |
| 99 | + |
| 100 | + reconstructed_hash = crypto_hash( |
| 101 | + block.timestamp, |
| 102 | + block.last_hash, |
| 103 | + block.data, |
| 104 | + block.nonce, |
| 105 | + block.difficulty |
| 106 | + ) |
| 107 | + |
| 108 | + if block.hash != reconstructed_hash: |
| 109 | + raise Exception('The block hash must be correct') |
| 110 | + |
81 | 111 | def main(): |
82 | 112 | genesis_block = Block.genesis() |
83 | | - block = Block.mine_block(genesis_block, 'foo') |
84 | | - print(block) |
| 113 | + bad_block = Block.mine_block(genesis_block, 'foo') |
| 114 | + bad_block.last_hash = 'evil_data' |
| 115 | + |
| 116 | + try: |
| 117 | + Block.is_valid_block(genesis_block, bad_block) |
| 118 | + except Exception as e: |
| 119 | + print(f'is_valid_block: {e}') |
85 | 120 |
|
86 | 121 | if __name__ == '__main__': |
87 | 122 | main() |
0 commit comments