-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.py
114 lines (86 loc) · 2.88 KB
/
main.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
"Blockchain dummy example"
from dataclasses import dataclass
from datetime import datetime
import hashlib
import random
from typing import List
from Crypto.Hash import SHA256
from Crypto.Signature import pkcs1_15
from Crypto.PublicKey import RSA
@dataclass
class Transaction:
amount: float
payer: str
payee: str
def to_string(self) -> str:
return str(self)
@dataclass
class Block:
previous_hash: str
transaction: Transaction
ts: str = str(datetime.now())
nonce: int = random.randint(0, 100000) * 99999999999999
@property
def hash(self) -> str:
block_str = str(self).encode("utf-8")
hasher = hashlib.sha256()
hasher.update(block_str)
return hasher.hexdigest()
class Chain:
chain: List[Block] = [Block("", Transaction(100, "genesis", "satoshi"))]
@property
def last_block(self) -> Block:
return self.chain[-1]
@staticmethod
def mine(nonce: int) -> int:
solution = 1
print("🔨 mining...")
while True:
hasher = hashlib.md5()
hasher.update(str(nonce + solution).encode("utf-8"))
attempt = hasher.hexdigest()
if attempt[0:4] == "0000":
print(f"Solved: {solution}")
break
solution += 1
return solution
def add_block(
self, transaction: Transaction, sender_public_key: str, signature: bytes
) -> None:
sender_public_key_ = RSA.import_key(sender_public_key)
verifier = pkcs1_15.new(sender_public_key_)
hasher = SHA256.new()
hasher.update(transaction.to_string().encode("utf-8"))
try:
verifier.verify(hasher, signature)
is_valid = True
except ValueError:
is_valid = False
if is_valid:
new_block = Block(self.last_block.hash, transaction)
self.mine(new_block.nonce)
self.chain.append(new_block)
class Wallet:
def __init__(self):
keypair = RSA.generate(2048)
self.public_key = keypair.public_key().export_key()
self.private_key = keypair.export_key()
def send_money(self, amount: float, payee_public_key: str, chain: Chain) -> None:
transaction = Transaction(amount, self.public_key, payee_public_key)
hasher = SHA256.new()
hasher.update(transaction.to_string().encode("utf-8"))
private_key = RSA.import_key(self.private_key)
signer = pkcs1_15.new(private_key)
signature = signer.sign(hasher)
chain.add_block(transaction, self.public_key, signature)
def main() -> None:
chain = Chain()
satoshi = Wallet()
bob = Wallet()
alice = Wallet()
satoshi.send_money(50, bob.public_key, chain)
satoshi.send_money(23, alice.public_key, chain)
satoshi.send_money(5, bob.public_key, chain)
print(chain.chain)
if __name__ == "__main__":
main()