Repository navigation
Expand file tree
/
Copy pathmain.py
More file actions
151 lines (123 loc) · 5.73 KB
/
Copy pathmain.py
File metadata and controls
151 lines (123 loc) · 5.73 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
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
from fastapi import FastAPI, HTTPException
import uvicorn
import copy
import random
from blockchain import Blockchain
from schemas import TransactionRequest, BalanceRequest
app = FastAPI()
blockchain = Blockchain()
# Endpoint to simulate hacking a block
@app.get('/hack_block')
def hack_block():
random_block_id = random.randint(1, len(blockchain.chain)-1)
block = blockchain.chain[random_block_id]
nonce, hash = blockchain.hash(block)
block['hash'] = hash
blockchain.chain[random_block_id] = block
response = {'message': 'A block is HACKED',
'index': block['index'],
'timestamp': block['timestamp'],
'nonce': block['nonce'],
'previous_hash': block['previous_hash'],
'hash': block['hash'],
'balances': block['balances'],
'transactions': block['transactions']}
return response
# Endpoint to check if the blockchain is valid
@app.get('/valid')
def valid():
if blockchain.is_chain_valid():
response = {'message': 'The Blockchain is valid.'}
else:
response = {'message': 'The Blockchain is not valid.'}
return response
# Endpoint to mine a new block
@app.get('/mine_block')
def mine_block():
# Check if the blockchain is valid before mining a new block
if not blockchain.is_chain_valid():
raise HTTPException(status_code=400, detail="Blockchain is not valid")
# Get the previous block to determine the previous hash
previous_block = blockchain.get_previous_block()
previous_hash = previous_block['hash']
# Aggregate balances from the previous block and the current block
balances = {k: blockchain.balances.get(k, 0) + previous_block['balances'].get(k, 0) for k in set(blockchain.balances) | set(previous_block['balances'])}
# Create a new block with the aggregated balances and previous hash
block = blockchain.create_block(balances, previous_hash)
is_block_valid = True
sender_aggregations = {}
receiver_aggregations = {}
for transaction in block['transactions']:
sender = transaction["sender"]
receiver = transaction["receiver"]
amount = transaction["amount"]
if sender in sender_aggregations:
sender_aggregations[sender] += amount
else:
sender_aggregations[sender] = amount
if receiver in receiver_aggregations:
receiver_aggregations[receiver] += amount
else:
receiver_aggregations[receiver] = amount
if not block['balances'] and sender_aggregations:
is_block_valid = False
raise HTTPException(status_code=400, detail="Invalid transaction data: Not enough amount")
if block['balances']:
for sender in sender_aggregations:
sender_balance = block['balances'].get(sender, 0)
if sender_balance < sender_aggregations[sender]:
is_block_valid = False
raise HTTPException(status_code=400, detail=f"Invalid transaction data for {sender}: Not enough amount")
else:
block['balances'][sender] = sender_balance - sender_aggregations[sender]
for receiver in receiver_aggregations:
receiver_balance = block['balances'].get(receiver, 0)
block['balances'][receiver] = receiver_balance + receiver_aggregations[receiver]
if is_block_valid:
# Append the mined block to the blockchain and update the peer copy
blockchain.chain.append(block)
blockchain.peer_b = copy.deepcopy(blockchain.chain)
response = {'message': 'A block is MINED',
'index': block['index'],
'timestamp': block['timestamp'],
'nonce': block['nonce'],
'previous_hash': block['previous_hash'],
'hash': block['hash'],
'balances': block['balances'],
'transactions': block['transactions']}
return response
# Endpoint to get the current state of the blockchain
@app.get('/get_chain')
def display_chain():
response = {'chain': blockchain.chain,
'length': len(blockchain.chain)}
return response
# Endpoint to add a new transaction to the blockchain
@app.post('/add_transaction')
def add_transaction(transaction_data: TransactionRequest):
data = transaction_data.dict()
if 'sender' not in data or 'receiver' not in data or 'amount' not in data:
raise HTTPException(status_code=400, detail="Invalid transaction data")
if data['sender'] == data['receiver']:
raise HTTPException(status_code=400, detail="Sender cannot be the same with receiver")
if data['amount'] <= 0:
raise HTTPException(status_code=400, detail="Transaction amount must be greater than zero")
# Add the transaction to the current list of transactions in order to be included in the next mined block
index = blockchain.add_transaction(data['sender'], data['receiver'], data['amount'])
response = {'message': f'Transaction added to block {index}'}
return response
# Endpoint to add a new balance to the blockchain
@app.post('/add_balance')
def add_balance(balance_data: BalanceRequest):
data = balance_data.dict()
if 'receiver' not in data or 'amount' not in data:
raise HTTPException(status_code=400, detail="Invalid transaction data")
if data['amount'] <= 0:
raise HTTPException(status_code=400, detail="Balance must be greater than zero")
# Add the balances to the current list of balances in order to be included in the next mined block
index = blockchain.add_balance(data['receiver'], data['amount'])
response = {'message': f'Balance added to block {index}'}
return response
# Run the FastAPI app using uvicorn
if __name__ == "__main__":
uvicorn.run(app, host='127.0.0.1', port=8000)