-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathinteract.py
More file actions
112 lines (93 loc) · 3.72 KB
/
interact.py
File metadata and controls
112 lines (93 loc) · 3.72 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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import requests
import time
from cryptography.hazmat.primitives import serialization, hashes
from cryptography.hazmat.primitives.asymmetric import padding, rsa
# --- CONFIGURATION ---
NODE_A = "http://localhost:50000"
NODE_B = "http://localhost:50001"
def generate_keys():
"""Generates a pair of RSA keys for a user."""
private = rsa.generate_private_key(public_exponent=65537, key_size=2048)
public = private.public_key()
# Convert to PEM format (String)
pem_priv = private.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.NoEncryption()
).decode('utf-8')
pem_pub = public.public_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo
).decode('utf-8')
return pem_priv, pem_pub
def sign_transaction(private_key_pem, sender, recipient, amount):
"""Signs the data with the private key."""
# The message must comprise the exact data being sent
message = f"{sender}{recipient}{amount}"
priv_key_obj = serialization.load_pem_private_key(private_key_pem.encode(), password=None)
signature = priv_key_obj.sign(
message.encode(),
padding.PSS(mgf=padding.MGF1(hashes.SHA256()), salt_length=padding.PSS.MAX_LENGTH),
hashes.SHA256()
)
return signature.hex()
# ==========================================
# EXECUTION FLOW
# ==========================================
print(f"--- 1. CONNECTING THE NODES ---")
# Tell Node A that Node B exists
requests.post(f"{NODE_A}/nodes/register", json={"nodes": [NODE_B]})
# Tell Node B that Node A exists
requests.post(f"{NODE_B}/nodes/register", json={"nodes": [NODE_A]})
print("Nodes are now peered.\n")
print(f"--- 2. CREATING WALLETS ---")
alice_priv, alice_pub = generate_keys()
bob_priv, bob_pub = generate_keys()
print("Alice and Bob now have ID cards (Public Keys) and Passwords (Private Keys).\n")
print(f"--- 3. FUNDING ALICE (THE HACK) ---")
# In a real blockchain, you mine to get coins.
# To speed this up, we will issue a 'System Reward' (Sender "0") to Alice.
# Sender "0" requires no signature in our code.
tx_fund = {
"sender": "0",
"recipient": alice_pub,
"amount": 100,
"signature": "GENESIS_FUNDING"
}
requests.post(f"{NODE_A}/transactions/new", json=tx_fund)
# Mine the block so the money actually appears in the ledger
print("Mining block on Node A to process funding...")
requests.get(f"{NODE_A}/mine")
print("Alice now has 100 coins.\n")
print(f"--- 4. ALICE SENDS 50 COINS TO BOB ---")
# 1. Sign the transaction
amount = 50
signature = sign_transaction(alice_priv, alice_pub, bob_pub, amount)
# 2. Send payload
tx_data = {
"sender": alice_pub,
"recipient": bob_pub,
"amount": amount,
"signature": signature
}
response = requests.post(f"{NODE_A}/transactions/new", json=tx_data)
if response.status_code == 201:
print("Transaction accepted by Node A!")
else:
print(f"Error: {response.text}")
print(f"--- 5. MINING & CONSENSUS ---")
# The transaction is currently in the "pool". We need to mine a block to finalize it.
print("Mining block on Node A...")
requests.get(f"{NODE_A}/mine")
# Wait a moment for Node A to tell Node B
time.sleep(1)
print(f"\n--- 6. CHECKING NODE B (FAULT TOLERANCE) ---")
# We never sent the transaction to Node B.
# Node B should have received the block from Node A automatically.
chain_b = requests.get(f"{NODE_B}/chain").json()
print(f"Node A Chain Length: {len(requests.get(f'{NODE_A}/chain').json()['chain'])}")
print(f"Node B Chain Length: {chain_b['length']}")
if len(chain_b['chain']) > 1:
print("\nSUCCESS: Node B automatically synced with Node A!")
else:
print("\nFAIL: Node B did not sync.")