-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathNode.py
More file actions
103 lines (91 loc) · 4.23 KB
/
Node.py
File metadata and controls
103 lines (91 loc) · 4.23 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
from Blockchain import Blockchain
from TransactionPool import TransactionPool
from Wallet import Wallet
from SocketCommunication import SocketCommunication
from NodeAPI import NodeAPI
from Message import Message
from BlockchainUtils import BlockchainUtils
import copy
class Node():
def __init__(self, ip, port, key=None):
self.p2p = None
self.ip = ip
self.port = port
self.blockchain = Blockchain()
self.transactionPool = TransactionPool()
self.wallet = Wallet()
if key is not None:
self.wallet.fromKey(key)
def startP2P(self):
self.p2p = SocketCommunication(self.ip, self.port)
self.p2p.startSocketCommunication(self)
def startAPI(self, apiPort):
self.api = NodeAPI()
self.api.injectNode(self)
self.api.start(apiPort)
def handleTransaction(self, transaction):
data = transaction.payload()
signature = transaction.signature
signerPublicKey = transaction.senderPublicKey
signatureValid = Wallet.signatureValid(
data, signature, signerPublicKey)
transactionExists = self.transactionPool.transactionExists(transaction)
transactionInBlock = self.blockchain.transactionExists(transaction)
if not transactionExists and not transactionInBlock and signatureValid:
self.transactionPool.addTransaction(transaction)
message = Message(self.p2p.socketConnector,
'TRANSACTION', transaction)
encodedMessage = BlockchainUtils.encode(message)
self.p2p.broadcast(encodedMessage)
forgingRequired = self.transactionPool.forgingRequired()
if forgingRequired:
self.forge()
def handleBlock(self, block):
forger = block.forger
blockHash = block.payload()
signature = block.signature
blockCountValid = self.blockchain.blockCountValid(block)
lastBlockHashValid = self.blockchain.lastBlockHashValid(block)
forgerValid = self.blockchain.forgerValid(block)
transactionsValid = self.blockchain.transactionsValid(
block.transactions)
signatureValid = Wallet.signatureValid(blockHash, signature, forger)
if not blockCountValid:
self.requestChain()
if lastBlockHashValid and forgerValid and transactionsValid and signatureValid:
self.blockchain.addBlock(block)
self.transactionPool.removeFromPool(block.transactions)
message = Message(self.p2p.socketConnector, 'BLOCK', block)
encodedMessage = BlockchainUtils.encode(message)
self.p2p.broadcast(encodedMessage)
def requestChain(self):
message = Message(self.p2p.socketConnector, 'BLOCKCHAINREQUEST', None)
encodedMessage = BlockchainUtils.encode(message)
self.p2p.broadcast(encodedMessage)
def handleBlockchainRequest(self, requestingNode):
message = Message(self.p2p.socketConnector,
'BLOCKCHAIN', self.blockchain)
encodedMessage = BlockchainUtils.encode(message)
self.p2p.send(requestingNode, encodedMessage)
def handleBlockchain(self, blockchain):
localBlockchainCopy = copy.deepcopy(self.blockchain)
localBlockCount = len(localBlockchainCopy.blocks)
receivedChainBlockCount = len(blockchain.blocks)
if localBlockCount < receivedChainBlockCount:
for blockNumber, block in enumerate(blockchain.blocks):
if blockNumber >= localBlockCount:
localBlockchainCopy.addBlock(block)
self.transactionPool.removeFromPool(block.transactions)
self.blockchain = localBlockchainCopy
def forge(self):
forger = self.blockchain.nextForger()
if forger == self.wallet.publicKeyString():
print('i am the forger')
block = self.blockchain.createBlock(
self.transactionPool.transactions, self.wallet)
self.transactionPool.removeFromPool(
self.transactionPool.transactions)
message = Message(self.p2p.socketConnector, 'BLOCK', block)
self.p2p.broadcast(BlockchainUtils.encode(message))
else:
print('i am not the forger')