-
Notifications
You must be signed in to change notification settings - Fork 2
/
r2ac.py
1806 lines (1598 loc) · 76.3 KB
/
r2ac.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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
import pickle
import Pyro4
import socket
import logging.config
import logging as logger
import os
import sys
import time
import threading
import merkle
import traceback
import thread
import random
from os import listdir
from os.path import isfile, join
from flask import Flask, request
from Crypto.PublicKey import RSA
import Transaction
import DeviceInfo
import PeerInfo
import DeviceKeyMapping
import chainFunctions
import criptoFunctions
def getMyIP():
""" Return the IP from the gateway
@return str
"""
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(("8.8.8.8", 80))
myIP = s.getsockname()[0]
s.close()
return myIP
def getTime():
""" Return the IP from the gateway
@return str
"""
return time.time()
lock=thread.allocate_lock()
consensusLock=thread.allocate_lock()
blockConsesusCandiateList = []
# logging.config.fileConfig('logging.conf')
# logger = logging.getLogger(__name__)
#https://docs.python.org/3/library/logging.html#logrecord-attributes
FORMAT = "[%(levelname)s-%(lineno)s-%(funcName)17s()] %(message)s"
#logger.basicConfig(filename=getMyIP()+str(time.time()),level=logging.DEBUG, format=FORMAT)
logger.basicConfig(filename=getMyIP()+str(getTime()),level=logging.INFO, format=FORMAT)
# Enable/Disable the transaction validation when peer receives a transaction
validatorClient = True
myName=socket.gethostname()
app = Flask(__name__)
peers = []
genKeysPars = []
myURI = ""
gwPvt = ""
gwPub = ""
myOwnBlock = ""
orchestratorObject=""
consensus = "None" #it can be None, dBFT, PBFT, PoW, Witness3
votesForNewOrchestrator = [] #list of votes for new orchestrator votes are: voter gwPub, voted gwPub, signature
myVoteForNewOrchestrator =[] # my gwPub, voted gwPub, my signed vote
def bootstrapChain2():
""" generate the RSA key pair for the gateway and create the chain"""
global gwPub
global gwPvt
chainFunctions.startBlockChain()
gwPub, gwPvt = criptoFunctions.generateRSAKeyPair()
#############################################################################
#############################################################################
######################### PEER MANAGEMENT ###############################
#############################################################################
#############################################################################
def findPeer(peerURI):
""" Receive the peer URI generated automatically by pyro4 and verify if it on the network\n
@param peerURI URI from the peer wanted\n
@return True - peer found\n
@return False - peer not found
"""
global peers
for p in peers:
if p.peerURI == peerURI:
return True
return False
def getPeer(peerURI):
""" Receive the peer URI generated automatically by pyro4 and return the peer object\n
@param peerURI URI from the peer wanted\n
@return p - peer object \n
@return False - peer not found
"""
global peers
for p in peers:
if p.peerURI == peerURI:
return p
return False
def addBack(peer, isFirst):
""" Receive a peer object add it to a list of peers.\n
the var isFirst is used to ensure that the peer will only be added once.\n
@param peer - peer object\n
@param isFirst - Boolean condition to add only one time a peer
"""
global myURI
if(isFirst):
obj = peer.object
obj.addPeer(myURI, isFirst)
# pickedUri = pickle.dumps(myURI)
# print("Before gettin last chain blocks")
# print("Picked URI in addback: " + str(pickedUri))
# obj.getLastChainBlocks(pickedUri, 0)
#else:
# print ("done adding....")
def sendTransactionToPeers(devPublicKey, transaction):
""" Send a transaction received to all peers connected.\n
@param devPublickey - public key from the sending device\n
@param transaction - info to be add to a block
"""
global peers
for peer in peers:
obj = peer.object
#logger.debug("sending to: " + peer.peerURI)
trans = pickle.dumps(transaction)
obj.updateBlockLedger(devPublicKey, trans)
# class sendBlks(threading.Thread):
# def __init__(self, threadID, iotBlock):
# threading.Thread.__init__(self)
# self.threadID = threadID
# self.iotBlock = iotBlock
#
# def run(self):
# print "Starting "
# # Get lock to synchronize threads
# global peers
# for peer in peers:
# print ("runnin in a thread: ")
# obj = peer.object
# #logger.debug("sending IoT Block to: " + peer.peerURI)
# dat = pickle.dumps(self.iotBlock)
# obj.updateIOTBlockLedger(dat)
def sendBlockToPeers(IoTBlock):
"""
Receive a block and send it to all peers connected.\n
@param IoTBlock - BlockHeader object
"""
global peers
print("sending block to peers")
logger.debug("Running through peers")
for peer in peers:
#print ("Inside for in peers")
obj = peer.object
print("sending IoT Block to: " + str(peer.peerURI))
logger.debug("sending IoT Block to: " + str(peer.peerURI))
dat = pickle.dumps(IoTBlock)
obj.updateIOTBlockLedger(dat,myName)
print("block sent to all peers")
def syncChain(newPeer):
"""
Send the actual chain to a new peer\n
@param newPeer - peer object
TODO update this pydoc after write this method code
"""
#write the code to identify only a change in the iot block and insert.
return True
def connectToPeers(nameServer):
"""this method recieves a nameServer parameter, list all remote objects connected to it, and
add these remote objetcts as peers to the current node \n
@param nameServer - list all remote objects connected to it
"""
#print ("found # results:"+str(len(nameServer.list())))
for peerURI in nameServer.list():
if(peerURI.startswith("PYRO:") and peerURI != myURI):
#print ("adding new peer:"+peerURI)
addPeer2(peerURI)
#orchestratorObject.
#else:
#print ("nothing to do")
#print (peerURI )
print ("finished connecting to all peers")
def addPeer2(peerURI):
""" Receive a peerURI and add the peer to the network if it is not already in\n
@param peerURI - peer id on the network\n
@return True - peer added to the network\n
@return False - peer already in the network
"""
global peers
if not (findPeer(peerURI)):
print ("peer not found. Create new node and add to list")
print ("[addPeer2]adding new peer:" + peerURI)
newPeer = PeerInfo.PeerInfo(peerURI, Pyro4.Proxy(peerURI))
peers.append(newPeer)
print("Runnin addback...")
addBack(newPeer, True)
#syncChain(newPeer)
print ("finished addback...")
return True
return False
#############################################################################
#############################################################################
######################### CRIPTOGRAPHY ################################
#############################################################################
#############################################################################
def generateAESKey(devPubKey):
""" Receive a public key and generate a private key to it with AES 256\n
@param devPubKey - device public key\n
@return randomAESKey - private key linked to the device public key
"""
global genKeysPars
randomAESKey = os.urandom(32) # AES key: 256 bits
obj = DeviceKeyMapping.DeviceKeyMapping(devPubKey, randomAESKey)
genKeysPars.append(obj)
return randomAESKey
def findAESKey(devPubKey):
""" Receive the public key from a device and found the private key linked to it\n
@param devPubKey - device public key\n
@return AESkey - found the key\n
@return False - public key not found
"""
global genKeysPars
for b in genKeysPars:
if (b.publicKey == devPubKey):
return b.AESKey
return False
#############################################################################
#############################################################################
################# Consensus Algorithm Methods #########################
#############################################################################
#############################################################################
answers = {}
trustedPeers = []
def addTrustedPeers():
""" Run on the peers list and add all to a list called trustedPeers """
global peers
for p in peers:
trustedPeers.append(p.peerURI)
############################ Consensus PoW
####TODO -> should create a nonce in the block and in the transaction in order to generate it
#### we could add also a signature set (at least 5 as ethereum or 8 as bitcoin?) to do before send the block for update
#### peers should verify both block data, hash, timestamp, etc and the signatures, very similar to what is done by verifyBlockCandidate
#### maybe this verifications could be put in a another method... maybe something called " verifyBlockData "
###########################END NEW CONSENSUS @Roben
##########################
def peerIsTrusted(i):
global trustedPeers
for p in trustedPeers:
if p == i: return True
return False
def peerIsActive(i):
return True # TO DO
def sendBlockToConsensus(newBlock, gatewayPublicKey, devicePublicKey):
obj = peer.object
data = pickle.dumps(newBlock)
obj.isValidBlock(data, gatewayPublicKey, devicePublicKey)
def receiveBlockConsensus(self, data, gatewayPublicKey, devicePublicKey, consensus):
newBlock = pickle.loads(data)
answer[newBlock].append(consensus)
def isValidBlock(self, data, gatewayPublicKey, devicePublicKey, peer):
newBlock = pickle.loads(data)
blockIoT = chainFunctions.findBlock(devicePublicKey)
consensus = True
if blockIoT == False:
print("Block not found in IoT ledger")
consensus = False
lastBlock = blockIoT.blockLedger[len(blockIoT.blockLedger) - 1]
if newBlock.index != lastBlock.index + 1:
print("New blovk Index not valid")
consensus = False
if lastBlock.calculateHashForBlockLedger(lastBlock) != newBlock.previousHash:
print("New block previous hash not valid")
consensus = False
now = "{:.0f}".format(((time.time() * 1000) * 1000))
# check time
if not (newBlock.timestamp > newBlock.signature.timestamp and newBlock.timestamp < now):
print("New block time not valid")
consensus = False
# check device time
if not (newBlock.signature.timestamp > lastBlock.signature.timestamp and newBlock.signature.timestamp < now):
print("New block device time not valid")
consensus = False
# check device signature with device public key
if not (criptoFunctions.signVerify(newBlock.signature.data, newBlock.signature.deviceSignature, gatewayPublicKey)):
print("New block device signature not valid")
consensus = False
peer = getPeer(peer)
obj = peer.object
obj.receiveBlockConsensus(data, gatewayPublicKey, devicePublicKey, consensus)
def isTransactionValid(transaction,pubKey):
data = str(transaction.data)[-22:-2]
signature = str(transaction.data)[:-22]
res = criptoFunctions.signVerify(data, signature, pubKey)
return res
def isBlockValid(block):
#Todo Fix the comparison between the hashes... for now is just a mater to simulate the time spend calculating the hashes...
#global BlockHeaderChain
#print(str(len(BlockHeaderChain)))
lastBlk = chainFunctions.getLatestBlock()
#print("Index:"+str(lastBlk.index)+" prevHash:"+str(lastBlk.previousHash)+ " time:"+str(lastBlk.timestamp)+ " pubKey:")
#lastBlkHash = criptoFunctions.calculateHash(lastBlk)
lastBlkHash = criptoFunctions.calculateHash(lastBlk.index, lastBlk.previousHash, lastBlk.timestamp, lastBlk.publicKey, lastBlk.nonce)
#print ("This Hash:"+str(lastBlkHash))
#print ("Last Hash:"+str(block.previousHash))
if(lastBlkHash == block.previousHash):
#logger.info("isBlockValid == true")
return True
else:
logger.error("isBlockValid == false")
logger.error("lastBlkHash="+str(lastBlkHash))
logger.error("block.previous="+str(block.previousHash))
logger.error("lastBlk Index="+str(lastBlk.index))
logger.error("block.index="+str(block.index))
#return False
return True
#############################################################################
#############################################################################
###################### R2AC Class ###################################
#############################################################################
#############################################################################
@Pyro4.expose
@Pyro4.behavior(instance_mode="single")
class R2ac(object):
def __init__(self):
""" Init the R2AC chain on the peer"""
print("R2AC initialized")
logger.debug("R2AC initialized")
def addTransaction(self, devPublicKey, encryptedObj):
""" Receive a new transaction to be add to the chain, add the transaction
to a block and send it to all peers\n
@param devPublicKey - Public key from the sender device\n
@param encryptedObj - Info of the transaction encrypted with AES 256\n
@return "ok!" - all done\n
@return "Invalid Signature" - an invalid key are found\n
@return "Key not found" - the device's key are not found
"""
logger.debug("transaction received")
global gwPvt
global gwPub
t1 = time.time()
blk = chainFunctions.findBlock(devPublicKey)
if (blk != False and blk.index > 0):
devAESKey = findAESKey(devPublicKey)
if (devAESKey != False):
logger.debug("Transaction is going to be appended to block#("+str(blk.index)+")")
# plainObject contains [Signature + Time + Data]
plainObject = criptoFunctions.decryptAES(encryptedObj, devAESKey)
signature = plainObject[:-20] # remove the last 20 chars
devTime = plainObject[-20:-4] # remove the 16 char of timestamp
deviceData = plainObject[-4:] # retrieve the las 4 chars which are the data
d = devTime+deviceData
isSigned = criptoFunctions.signVerify(d, signature, devPublicKey)
if isSigned:
deviceInfo = DeviceInfo.DeviceInfo(signature, devTime, deviceData)
nextInt = blk.transactions[len(blk.transactions) - 1].index + 1
signData = criptoFunctions.signInfo(gwPvt, str(deviceInfo))
gwTime = "{:.0f}".format(((time.time() * 1000) * 1000))
# code responsible to create the hash between Info nodes.
prevInfoHash = criptoFunctions.calculateTransactionHash(chainFunctions.getLatestBlockTransaction(blk))
transaction = Transaction.Transaction(nextInt, prevInfoHash, gwTime, deviceInfo, signData)
# send to consensus
#if not consensus(newBlockLedger, gwPub, devPublicKey):
# return "Not Approved"
# if not PBFTConsensus(blk, gwPub, devPublicKey):
# return "Consensus Not Reached"
chainFunctions.addBlockTransaction(blk, transaction)
#logger.info("block added locally... now sending to peers..")
t2 = time.time()
logger.info("==2=>time to add transaction in a block: " + '{0:.12f}'.format((t2 - t1) * 1000))
sendTransactionToPeers(devPublicKey, transaction) # --->> this function should be run in a different thread.
#print("all done")
return "ok!"
else:
logger.debug("--Transaction not appended--Transaction Invalid Signature")
return "Invalid Signature"
logger.debug("--Transaction not appended--Key not found")
return "key not found"
def addTransactionSC(self, devPublicKey, encryptedObj):
""" Receive a new transaction to be add to the chain, add the transaction
to a block and send it to all peers\n
@param devPublicKey - Public key from the sender device\n
@param encryptedObj - Info of the transaction encrypted with AES 256\n
@return "ok!" - all done\n
@return "Invalid Signature" - an invalid key are found\n
@return "Key not found" - the device's key are not found
"""
logger.debug("transaction received")
global gwPvt
global gwPub
t1 = time.time()
blk = chainFunctions.findBlock(devPublicKey)
if (blk != False and blk.index > 0):
devAESKey = findAESKey(devPublicKey)
if (devAESKey != False):
logger.debug("Transaction is going to be appended to block#("+str(blk.index)+")")
# plainObject contains [Signature + Time + Data]
plainObject = criptoFunctions.decryptAES(encryptedObj, devAESKey)
deviceData = plainObject[(172+16):] # retrieve the last chars, excluding timestamp and signature
signature = plainObject[:-(16+len(deviceData))] # remove the last 20 chars
print("###Signature after receiving: "+signature)
print("###Device Data: "+deviceData)
devTime = plainObject[-(16+len(deviceData)):-len(deviceData)] # remove the 16 char of timestamp
print("###devTime: "+devTime)
d = devTime+deviceData
isSigned = criptoFunctions.signVerify(d, signature, devPublicKey)
if isSigned:
print("it is signed!!!")
deviceInfo = DeviceInfo.DeviceInfo(signature, devTime, deviceData)
nextInt = blk.transactions[len(blk.transactions) - 1].index + 1
signData = criptoFunctions.signInfo(gwPvt, str(deviceInfo))
gwTime = "{:.0f}".format(((time.time() * 1000) * 1000))
# code responsible to create the hash between Info nodes.
prevInfoHash = criptoFunctions.calculateTransactionHash(chainFunctions.getLatestBlockTransaction(blk))
transaction = Transaction.Transaction(nextInt, prevInfoHash, gwTime, deviceInfo, signData)
# send to consensus
#if not consensus(newBlockLedger, gwPub, devPublicKey):
# return "Not Approved"
# if not PBFTConsensus(blk, gwPub, devPublicKey):
# return "Consensus Not Reached"
chainFunctions.addBlockTransaction(blk, transaction)
#logger.info("block added locally... now sending to peers..")
t2 = time.time()
logger.info("==2=>time to add transaction in a block: " + '{0:.12f}'.format((t2 - t1) * 1000))
sendTransactionToPeers(devPublicKey, transaction) # --->> this function should be run in a different thread.
print("all done in transations")
return "ok!"
else:
print("Signature is not ok")
logger.debug("--Transaction not appended--Transaction Invalid Signature")
return "Invalid Signature"
logger.debug("--Transaction not appended--Key not found")
return "key not found"
#update local bockchain adding a new transaction
def updateBlockLedger(self, pubKey, transaction):
""" Recive a new transaction and add it to the chain\n
@param pubKey - Block public key\n
@param transaction - Data to be insert on the block\n
@return "done" - method done (the block are not necessarily inserted)
"""
trans = pickle.loads(transaction)
t1 = time.time()
#logger.info("Received Transaction #:" + (str(trans.index)))
blk = chainFunctions.findBlock(pubKey)
if blk != False:
logger.info("Transaction size in the block:"+str(len(blk.transactions)))
if not (chainFunctions.blockContainsTransaction(blk, trans)):
if validatorClient:
isTransactionValid(trans, pubKey)
chainFunctions.addBlockTransaction(blk, trans)
t2 = time.time()
logger.info("==3=>time to update transaction received: " + '{0:.12f}'.format((t2 - t1) * 1000))
return "done"
# update local bockchain adding a new block
def updateIOTBlockLedger(self, iotBlock, gwName):
""" Receive a block and add it to the chain\n
@param iotBlock - Block to be add\n
@param gwName - sender peer's name
"""
print("Updating IoT Block Ledger, in Gw: "+str(gwName))
logger.debug("updateIoTBlockLedger Function")
b = pickle.loads(iotBlock)
#print("picked....")
t1 = time.time()
logger.debug("Received Block #:" + (str(b.index)))
#logger.info("Received block #:"+str(b.index)+" From:"+str(gwName))
if isBlockValid(b):
print("updating is valid...")
chainFunctions.addBlockHeader(b)
t2 = time.time()
print("updating was done")
logger.info("==4=>time to add new block in peers: " + '{0:.12f}'.format((t2 - t1) * 1000))
def addBlockConsensusCandidate(self, devPubKey):
#TODO
global blockConsesusCandiateList
logger.debug("================================================")
#print("Inside addBlockConsensusCandidate, devPubKey: ")
#print(devPubKey)
devKey = pickle.loads(devPubKey)
#print("Inside addBlockConsensusCandidate, devKey: ")
#print(devPubKey)
logger.debug("This method is executed by orchestrator."+str(devKey))
#logger.debug("received new block consensus candidate. Queue Size:"+srt(len(blockConsesusCandiateList)))
addNewBlockToSyncList(devKey)
logger.debug("added to the sync list")
logger.debug("================================================")
def acquireLockRemote(self):
global consensusLock
return consensusLock.acquire(False) #with False argument, it will return true if it was locked or false if it could not be locked
#consensusLock.acquire(1)
#return True
def releaseLockRemote(self):
global consensusLock
consensusLock.release()
def addBlock(self, devPubKey):
""" Receive a device public key from a device and link it to A block on the chain\n
@param devPubKey - request's device public key\n
@return encKey - RSA encrypted key for the device be able to communicate with the peers
"""
global gwPub
global consensusLock
#print("addingblock... DevPubKey:" + devPubKey)
logger.debug("|---------------------------------------------------------------------|")
logger.debug("Block received from device")
aesKey = ''
t1 = time.time()
blk = chainFunctions.findBlock(devPubKey)
if (blk != False and blk.index > 0):
#print("inside first if")
aesKey = findAESKey(devPubKey)
if aesKey == False:
#print("inside second if")
#logger.info("Using existent block data")
aesKey = generateAESKey(blk.publicKey)
encKey = criptoFunctions.encryptRSA2(devPubKey, aesKey)
t2 = time.time()
else:
#print("inside else")
logger.info("***** New Block: Chain size:" + str(chainFunctions.getBlockchainSize()))
pickedKey = pickle.dumps(devPubKey)
aesKey = generateAESKey(devPubKey)
#print("pickedKey: ")
#print(pickedKey)
encKey = criptoFunctions.encryptRSA2(devPubKey, aesKey)
t2 = time.time()
#####Old No Consensus
# bl = chainFunctions.createNewBlock(devPubKey, gwPvt)
# sendBlockToPeers(bl)
logger.debug("starting block consensus")
#############LockCONSENSUS STARTS HERE###############
if(consensus=="PBFT"):
### PBFT elect new orchestator every time that a new block should be inserted
#allPeersAreLocked = False
self.lockForConsensus()
#print("ConsensusLocks acquired!")
self.electNewOrchestrator()
orchestratorObject.addBlockConsensusCandidate(pickedKey)
orchestratorObject.runPBFT()
if(consensus=="dBFT" or consensus == "Witness3"):
# consensusLock.acquire(1) # only 1 consensus can be running at same time
# for p in peers:
# obj=p.object
# obj.acquireLockRemote()
self.lockForConsensus()
#print("ConsensusLocks acquired!")
orchestratorObject.addBlockConsensusCandidate(pickedKey)
orchestratorObject.rundBFT()
if(consensus=="PoW"):
# consensusLock.acquire(1) # only 1 consensus can be running at same time
# for p in peers:
# obj=p.object
# obj.acquireLockRemote()
self.lockForConsensus()
#print("ConsensusLocks acquired!")
self.addBlockConsensusCandidate(pickedKey)
self.runPoW()
if(consensus=="None"):
self.addBlockConsensusCandidate(pickedKey)
self.runNoConsesus()
#print("after orchestratorObject.addBlockConsensusCandidate")
#try:
#PBFTConsensus(bl, gwPub, devPubKey)
# except KeyboardInterrupt:
# sys.exit()
# except:
# print("failed to execute:")
# logger.error("failed to execute:")
# exc_type, exc_value, exc_traceback = sys.exc_info()
# print "*** print_exception:" l
# traceback.print_exception(exc_type, exc_value, exc_traceback,
# limit=6, file=sys.stdout)
#
logger.debug("end block consensus")
# try:
# #thread.start_new_thread(sendBlockToPeers,(bl))
# t1 = sendBlks(1, bl)
# t1.start()
# except:
# print "thread not working..."
if(consensus=="PBFT" or consensus=="dBFT" or consensus=="Witness3" or consensus=="PoW"):
consensusLock.release()
for p in peers:
obj = p.object
obj.releaseLockRemote()
#print("ConsensusLocks released!")
######end of lock consensus################
#print("Before encription of rsa2")
t3 = time.time()
logger.info("==1=>time to generate key: " + '{0:.12f}'.format((t2 - t1) * 1000))
logger.info("==8=>Time to add block (perform consensus and update all peers): " + '{0:.12f}'.format((t3 - t1) * 1000))
logger.debug("|---------------------------------------------------------------------|")
print("block added")
return encKey
def addPeer(self, peerURI, isFirst):
""" Receive a peer URI add it to a list of peers.\n
the var isFirst is used to ensure that the peer will only be added once.\n
@param peerURI - peer URI\n
@param isFirst - Boolean condition to add only one time a peer\n
@return True - peer successfully added\n
@return False - peer is already on the list
"""
global peers
if not (findPeer(peerURI)):
newPeer = PeerInfo.PeerInfo(peerURI, Pyro4.Proxy(peerURI))
peers.append(newPeer)
if isFirst:
#after adding the original peer, send false to avoid loop
addBack(newPeer, False)
syncChain(newPeer)
return True
else:
print("peer is already on the list")
return False
def showIoTLedger(self):
""" Log all chain \n
@return "ok" - done
"""
#logger.info("Showing Block Header data for peer: " + myURI)
print("Showing Block Header data for peer: " + myURI)
size = chainFunctions.getBlockchainSize()
#logger.info("IoT Ledger size: " + str(size))
#logger.info("|-----------------------------------------|")
print("IoT Ledger size: " + str(size))
print("|-----------------------------------------|")
theChain = chainFunctions.getFullChain()
for b in theChain:
#logger.info(b.strBlock())
#logger.info("|-----------------------------------------|")
print(b.strBlock())
print("|-----------------------------------------|")
return "ok"
def showLastTransactionData(self,blockIndex):
print("Showing Data from Last Transaction from block #: " + str(blockIndex))
blk = chainFunctions.getBlockByIndex(blockIndex)
lastTransactionInfo = chainFunctions.getLatestBlockTransaction(blk).data
transactionData=lastTransactionInfo.strInfoData()
print("My data is: "+str(transactionData))
return transactionData
def showBlockLedger(self, index):
""" Log all transactions of a block\n
@param index - index of the block\n
@return "ok" - done
"""
print("Showing Transactions data for peer: " + myURI)
#logger.info("Showing Trasactions data for peer: " + myURI)
blk = chainFunctions.getBlockByIndex(index)
print("Block for index"+str(index))
size = len(blk.transactions)
#logger.info("Block Ledger size: " + str(size))
#logger.info("-------")
print("Block Ledger size: " + str(size))
print("-------")
for b in blk.transactions:
logger.info(b.strBlock())
logger.info("-------")
print(b.strBlock())
print("-------")
return "ok"
def listPeer(self):
""" Log all peers in the network\n
@return "ok" - done
"""
global peers
logger.info("|--------------------------------------|")
for p in peers:
logger.info("PEER URI: "+p.peerURI)
logger.info("|--------------------------------------|")
return "ok"
def calcMerkleTree(self, blockToCalculate):
print ("received: "+str(blockToCalculate))
t1 = time.time()
blk = chainFunctions.getBlockByIndex(blockToCalculate)
trans = blk.transactions
size = len(blk.transactions)
mt = merkle.MerkleTools()
mt.add_leaf(trans, True)
mt.make_tree()
t2 = time.time()
logger.info("==5=>time to generate Merkle Tree size (" + str(size) + ") : " + '{0:.12f}'.format((t2 - t1) * 1000))
#print("=====5=====>time to generate Merkle Tree size (" + str(size) + ") : " + '{0:.12f}'.format((t2 - t1) * 1000))
return "ok"
def getRemotePeerBlockChain(self):
pickledChain = pickle.dumps(chainFunctions.getFullChain())
return pickledChain
#Get the missing blocks from orchestrator
def getLastChainBlocks(self, peerURI, lastBlockIndex):
print("Inside get last chain block...")
chainSize=chainFunctions.getBlockchainSize()
print("Chainsized: " + str(chainSize))
if(chainSize > 1):
newBlock = chainFunctions.getBlockByIndex(1)
print("My Key is: "+ str(newBlock.publicKey) + "My index is" + str(newBlock.index))
#destinationURI = pickle.loads(peerURI)
#peerUri= getPeerbyPK(destinationPK)
sendBlockToPeers(newBlock)
# print("Inside get last chain block... requested by URI: "+destinationURI)
# #peer=Pyro4.Proxy(destinationURI)
# peer = PeerInfo.PeerInfo(destinationURI, Pyro4.Proxy(destinationURI))
# obj = peer.object
# print("After creating obj in getlastchain")
# for index in range(lastBlockIndex+1, chainSize-1):
# #logger.debug("sending IoT Block to: " + str(peer.peerURI))
# print("Sending to peer"+ str(destinationURI) + "Block Index: "+ str(index) + "chainsize: "+ str(chainSize))
# newBlock=chainFunctions.getBlockByIndex(index)
# #dat = pickle.dumps(chainFunctions.getBlockByIndex(index))
# #obj.updateIOTBlockLedger(dat, myName)
# obj.chainFunctions.addBlockHeader(newBlock)
#print("For finished")
def getMyOrchestrator(self):
dat = pickle.dumps(orchestratorObject)
return dat
def addVoteOrchestrator(self, sentVote):
global votesForNewOrchestrator
dat = pickle.loads(sentVote)
#print("adding vote in remote peer"+str(dat))
votesForNewOrchestrator.append(dat)
#print("finished adding vote for orchetrator")
return True
def peerVoteNewOrchestrator(self):
global myVoteForNewOrchestrator
global votesForNewOrchestrator
randomGw = random.randint(0, len(peers) - 1)
#randomGw=1
votedURI = peers[randomGw].peerURI
print("VotedURI: " + str(votedURI))
#myVoteForNewOrchestrator = [gwPub, votedURI, criptoFunctions.signInfo(gwPvt, votedURI)] # not safe sign, just for test
myVoteForNewOrchestrator = votedURI
votesForNewOrchestrator.append(myVoteForNewOrchestrator)
pickedVote = pickle.dumps(myVoteForNewOrchestrator)
return pickedVote
def electNewOrchestrator(self):
global votesForNewOrchestrator
global orchestratorObject
t1 = time.time()
for peer in peers:
obj = peer.object
#print("objeto criado")
receivedVote = obj.peerVoteNewOrchestrator()
votesForNewOrchestrator.append(pickle.loads(receivedVote))
voteNewOrchestrator()
#newOrchestratorURI = mode(votesForNewOrchestrator)
newOrchestratorURI = max(set(votesForNewOrchestrator), key=votesForNewOrchestrator.count)
print("Elected node was" + newOrchestratorURI)
orchestratorObject = Pyro4.Proxy(newOrchestratorURI)
for peer in peers:
obj = peer.object
dat = pickle.dumps(orchestratorObject)
obj.loadElectedOrchestrator(dat)
t2 = time.time()
logger.info("==7=>time to execute New Election block consensus: " + '{0:.12f}'.format((t2 - t1) * 1000))
#logger.info("New Orchestator loaded is: " + str(newOrchestratorURI))
print("New Orchestator loaded is: " + str(newOrchestratorURI))
print("=====>time to execute New Election block consensus: " + '{0:.12f}'.format((t2 - t1) * 1000))
# orchestratorObject
def loadElectedOrchestrator(self, data):
global orchestratorObject
newOrchestrator = pickle.loads(data)
orchestratorObject = newOrchestrator
#logger.info("New Orchestator loaded is: " + str(orchestratorObject.exposedURI()))
print("new loaded orchestrator: " + str(orchestratorObject.exposedURI()))
return True
def exposedURI(self):
return myURI
def setConsensus(self, receivedConsensus):
global consensus
if (receivedConsensus != consensus):
consensus = receivedConsensus
print("######")
print("Changed my consensus to " + consensus)
for p in peers:
obj = p.object
obj.setConsensus(receivedConsensus)
return True
def runPBFT(self):
""" Run the PBFT consensus to add a new block on the chain """
# print("I am in runPBFT")
t1 = time.time()
global gwPvt
devPubKey = getBlockFromSyncList()
blk = chainFunctions.createNewBlock(devPubKey, gwPvt, consensus)
logger.debug("Running PBFT function to block(" + str(blk.index) + ")")
PBFTConsensus(blk, gwPub, devPubKey)
t2 = time.time()
logger.info("==6=>time to exec block consensus: " + '{0:.12f}'.format((t2 - t1) * 1000))
print("Finish PBFT consensus in: "+ '{0:.12f}'.format((t2 - t1) * 1000))
def rundBFT(self):
""" Run the dBFT consensus to add a new block on the chain """
# print("I am in rundBFT")
t1 = time.time()
global gwPvt
devPubKey = getBlockFromSyncList()
blk = chainFunctions.createNewBlock(devPubKey, gwPvt, consensus)
logger.debug("Running dBFT function to block(" + str(blk.index) + ")")
PBFTConsensus(blk, gwPub, devPubKey)
t2 = time.time()
logger.info("==6=>time to exec block consensus: " + '{0:.12f}'.format((t2 - t1) * 1000))
print("Finish dBFT consensus in: "+ '{0:.12f}'.format((t2 - t1) * 1000))
################Consensus PoW
def runPoW(self):
""" Run the PoW consensus to add a new block on the chain """
print("I am in runPoW")
t1 = time.time()
global gwPvt
devPubKey = getBlockFromSyncList()
blk = chainFunctions.createNewBlock(devPubKey, gwPvt, consensus)
#print("Device PubKey (insire runPoW): " + str(devPubKey))
if (PoWConsensus(blk, gwPub, devPubKey)):
t2 = time.time()
logger.info("==6=>time to exec block consensus: " + '{0:.12f}'.format((t2 - t1) * 1000))
print("Finish PoW consensus in: "+ '{0:.12f}'.format((t2 - t1) * 1000))
else:
t2 = time.time()
logger.info(
"Something went wrong, time to execute PoW Block Consensus" + '{0:.12f}'.format((t2 - t1) * 1000))
print("I finished runPoW - Wrong")
def runNoConsesus(self):
print("Running without consensus")
t1=time.time()
global peers
devPubKey = getBlockFromSyncList()
newBlock = chainFunctions.createNewBlock(devPubKey, gwPvt, consensus)
signature = verifyBlockCandidate(newBlock, gwPub, devPubKey, peers)
if (signature == False):
logger.info("Consesus was not Achieved!!! Block(" + str(newBlock.index) + ") will not added")
return False
chainFunctions.addBlockHeader(newBlock)
sendBlockToPeers(newBlock)
t2 = time.time()
logger.info("==6=>time to exec block consensus: " + '{0:.12f}'.format((t2 - t1) * 1000))
print("Finish adding Block without consensus in: "+ '{0:.12f}'.format((t2 - t1) * 1000))
return True
def lockForConsensus(self):
""" lock the consensusLock without resulting in deadlocks """
global consensusLock
global peers
counter = 0
while (counter < len(peers)):
while (consensusLock.acquire(
False) == False): # in this mode (with False value) it will lock the execution and return true if it was locked or false if not
#logger.info("I can't lock my lock, waiting for it")
time.sleep(0.01)
# print("##Before for and after acquire my lock")
for p in peers:
obj = p.object
thisPeerIsNotAvailableToLock = obj.acquireLockRemote()
counter = counter + 1
# print("On counter = "+str(counter)+" lock result was: "+str(thisPeerIsNotAvailableToLock))
if (thisPeerIsNotAvailableToLock == False):
counter = counter - 1 # I have to unlock the locked ones, the last was not locked
#logger.info("Almost got a deadlock")
consensusLock.release()
if (counter > 0):
for p in peers:
obj = p.object
obj.releaseLockRemote()
#logger.info("released lock counter: " + str(counter))
counter = counter - 1
if (counter == 0):
#logger.info("released locks")
break
print("After first break PBFT")
#logger.info("After first break PBFT")
#logger.info("sleeping 0.01")
time.sleep(0.01)
break
return True
# def voteNewOrchestratorExposed(self):
# global myVoteForNewOrchestrator
# global votesForNewOrchestrator
#
# randomGw = random.randint(0, len(peers) - 1)
# votedpubKey = peers[randomGw].object.getGwPubkey()
# # print("Selected Gw is: " + str(randomGw))
# # print("My pubKey:"+ str(gwPub))
# print("VotedpubKey: " + str(votedpubKey))
# myVoteForNewOrchestrator = [gwPub, votedpubKey,
# criptoFunctions.signInfo(gwPvt, votedpubKey)] # not safe sign, just for test
# votesForNewOrchestrator.append(myVoteForNewOrchestrator)
# pickedVote = pickle.dumps(myVoteForNewOrchestrator)
# for count in range(0, (len(peers))):
# # print("testing range of peers: "+ str(count))
# # if(peer != peers[0]):
# obj = peers[count].object
# obj.addVoteOrchestrator(pickedVote)
# return True
# # print(str(myVoteForNewOrchestrator))