-
Notifications
You must be signed in to change notification settings - Fork 0
/
BlockchainNode.py
111 lines (98 loc) · 4.79 KB
/
BlockchainNode.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
import copy
import time
from Blockchain import Blockchain
from Message import Message
from NodeAPI import NodeAPI
from SocketCommunication import SocketCommunication
from TransactionPool import TransactionPool
from Wallet import Wallet
from BlockchainUtils import BlockchainUtils
class BlockchainNode():
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:
self.wallet.fromKey(key)
def startP2P(self):
self.p2p = SocketCommunication(self.ip, self.port)
self.p2p.startSocketCommunication(self)
self.requestChain()
def startAPI(self, apiPort):
self.api = NodeAPI()
self.api.injectNode(self)
self.api.start(apiPort)
def handleTransaction(self, transaction):
validSignature = BlockchainUtils.signatureValid(
transaction.payload(), transaction.signature, transaction.senderPK)
transactionInPool = self.transactionPool.transactionExists(transaction)
transactionInBlock = self.blockchain.transactionExists(transaction)
if not transactionInPool and validSignature and not transactionInBlock:
self.transactionPool.addTransaction(transaction)
BlockchainUtils.broadcastMessage(self.p2p, 'TRANSACTION', transaction)
# New block?
forgingRequired = self.transactionPool.forgerRequired()
if forgingRequired:
self.forgeNewBlock()
def forgeNewBlock(self):
forger = self.blockchain.nextForger()
if forger == self.wallet.publicKeyString():
block = self.blockchain.createBlock(self.transactionPool.transactions, self.wallet)
self.transactionPool.removeTransactions(block.transactions)
BlockchainUtils.broadcastMessage(self.p2p, 'BLOCK', block)
print("Creating block " + str(block.blockCount))
time.sleep(1)
# def handleBlockchainSync(self, block):
# blockCountValid = self.blockchain.blockCountValid(block)
# if not blockCountValid:
# self.requestChain()
# # self.blockchain.validateBlock(block)
# self.blockchain.addBlock(block)
# self.transactionPool.removeTransactions(block.transactions)
# message = BlockchainUtils.createEncodedMessage(self.p2p.socketConnector, 'BLOCK', block)
# self.p2p.broadcast(message)
def handleBlockchainSync(self, block):
forger = block.forger
blockHash = block.payload()
signature = block.signature
print("Syncronizing block " + str(block.blockCount))
blockCountValid = self.blockchain.blockCountValid(block)
lastBlockHashValid = self.blockchain.lastBlockHashValid(block)
forgerValid = self.blockchain.forgerValid(block)
transactionsValid = self.blockchain.transactionsValid(
block.transactions)
signatureValid = BlockchainUtils.signatureValid(
blockHash, signature, forger)
if not blockCountValid:
self.requestChain()
if lastBlockHashValid and forgerValid and transactionsValid and signatureValid:
self.blockchain.addBlock(block)
self.transactionPool.removeTransactions(block.transactions)
# in the original code, is this really necessary?
# message = Message(self.p2p.socketConnector, 'BLOCK', block)
# self.p2p.broadcast(BlockchainUtils.encode(message))
time.sleep(1)
else:
print("Syncronizing failed due to "
+ ("lastBlockHashValid" if lastBlockHashValid else ""
+ "forgerValid" if forgerValid else ""
+ "transactionsValid" if transactionsValid else ""
+ "signatureValid" if signatureValid else ""))
def requestChain(self):
BlockchainUtils.broadcastMessage(self.p2p, 'BLOCKCHAINREQUEST', None)
def handleBlockchainRequest(self, node):
BlockchainUtils.broadcastMessage(self.p2p, 'BLOCKCHAINUPDATE', self.blockchain)
def handleBlockchainUpdate(self, receivedBlockchain):
localBlockchainCopy = copy.deepcopy(self.blockchain)
localBlockchainCount = len(localBlockchainCopy.blocks)
receivedBlockchainCount = len(receivedBlockchain.blocks)
if localBlockchainCount < receivedBlockchainCount:
for blockNumber, block in enumerate(receivedBlockchain.blocks):
if blockNumber >= localBlockchainCount:
localBlockchainCopy.addBlock(block)
self.transactionPool.removeTransactions(block.transactions)
print('Adding update block ' + str(block.blockCount))
self.blockchain = localBlockchainCopy