-
Notifications
You must be signed in to change notification settings - Fork 0
/
Blockchain.py
147 lines (121 loc) · 5.31 KB
/
Blockchain.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
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
from Block import Block
from BlockchainUtils import BlockchainUtils
from ProofOfStake import ProofOfStake
from AccountModel import AccountModel
class Blockchain():
def __init__(self):
self.blocks = self.genesis()
self.blockIds = {}
self.accounts = AccountModel()
self.pos = ProofOfStake()
def genesis(self):
genesisBlock = Block([], 'genesisHash', 'genesis', 0)
genesisBlock.timestamp = 0
return [genesisBlock]
def addBlock(self, block):
if self.blockIds.get(block.blockCount) != None:
print("BLOCK INVALID!!!!!!!!!!!!!!!!!!!!!")
return
self.executeTransactions(block.transactions) # update accounts too
self.blocks.append(block)
self.blockIds[block.blockCount] = block.forger
def toJson(self):
data = {}
jsonBlocks = []
for block in self.blocks:
jsonBlocks.append(block.toJson())
data['blocks'] = jsonBlocks
return data
def blockCountValid(self, block):
return self.blocks[-1].blockCount == block.blockCount - 1
def lastBlockHashValid(self, block):
latestBlockchainBlockHash = BlockchainUtils.hash(
self.blocks[-1].payload()).hexdigest()
return latestBlockchainBlockHash == block.lastHash
def getCoveredTransactions(self, transactions):
coveredTransactions = []
for transaction in transactions:
if self.transactionsCovered(transaction):
coveredTransactions.append(transaction)
else:
print("Transaction not covered by the Sender")
return coveredTransactions
def transactionsCovered(self, transaction):
if transaction.type == 'EXCHANGE':
return True
senderBalance = self.accounts.getbalance(transaction.senderPK)
return senderBalance >= transaction.amount
def executeTransactions(self, transactions):
for transaction in transactions:
self.executeTransaction(transaction)
def executeTransaction(self, transaction):
senderPK = transaction.senderPK
receiverPK = transaction.receiverPK
amount = transaction.amount
if transaction.type == 'STAKE':
if senderPK == receiverPK:
self.pos.update(senderPK, amount)
self.accounts.updateAccount(senderPK, -amount)
else:
self.accounts.updateAccount(senderPK, -amount)
self.accounts.updateAccount(receiverPK, amount)
def nextForger(self):
lastBlockHash = BlockchainUtils.hash(
self.blocks[-1].payload()).hexdigest()
nextForger = self.pos.forger(lastBlockHash)
return nextForger
def createBlock(self, transactions, forgerWallet):
coveredTransactions = self.getCoveredTransactions(transactions)
self.executeTransactions(coveredTransactions)
newBlock = forgerWallet.createBlock(coveredTransactions, BlockchainUtils.lastBlockHash(
self), len(self.blocks)) #BlockchainUtils.newBlockNumber(self))
self.blocks.append(newBlock)
return newBlock
def transactionExists(self, transaction):
for block in self.blocks:
for blockTransaction in block.transactions:
if transaction.equals(blockTransaction):
return True
return False
def forgerValid(self, block):
forgerPublicKey = self.pos.forger(block.lastHash)
proposedBlockForger = block.forger
if forgerPublicKey == proposedBlockForger:
return True
else:
return False
def transactionsValid(self, transactions):
coveredTransactions = self.getCoveredTransactions(transactions)
if len(coveredTransactions) == len(transactions):
return True
return False
def validateSignature(self, data, signature, publicKeyString):
signatureValid = BlockchainUtils.signatureValid(
data, signature, publicKeyString)
return signatureValid
def validateBlock(self, block):
# 1) validate the correct block number
# 2) validate the correct block hashes
# 3) validate the correct block forger
# 4) validate the block signature
# 5) validate the transactions
# 6) validate the transactions signatures
# if block.blockCount != self.blocks[-1].blockCount + 1:
# raise Exception("Block number INVALID")
# if BlockchainUtils.lastBlockHash(self) != block.lastHash:
# raise Exception("Block hash INVALID")
forgerPublicKey = self.pos.forger(block.lastHash) # ?????
proposedBlockForger = block.forger
if forgerPublicKey != proposedBlockForger:
raise Exception("Forger INVALID")
self.validateSignature(
block.payload(), block.signature, block.forger)
coveredTransactions = self.getCoveredTransactions(block.transactions)
if len(coveredTransactions) != len(block.transactions):
raise Exception("Transactions INVALID")
for transaction in block.transactions:
self.validateSignature(
transaction.toJson(), transaction.signature, transaction.senderPK)
self.validateSignature(
transaction.toJson(), transaction.signature, transaction.receiverPK)
return True