Kaynağa Gözat

[research/ouroboros] fixed evironment epoch/slot synchrony for one epoch only

mohab 4 yıl önce
ebeveyn
işleme
0ec4502a9a

+ 1 - 1
script/research/dpos/ouroboros/clock.py

@@ -8,7 +8,7 @@ import math
 
 class SynchedNTPClock(object):
 
-    def __init__(self, epoch_length, slot_length=120, ntp_server='europe.pool.ntp.org'):
+    def __init__(self, epoch_length, slot_length=180, ntp_server='europe.pool.ntp.org'):
         #TODO how long should be the slot length
         self.epoch_length=epoch_length # how many slots in a a block
         self.slot_length=slot_length

+ 87 - 84
script/research/dpos/ouroboros/environment.py

@@ -57,68 +57,63 @@ class Z(object):
         self.current_slot = self.beacon.slot
         self.select_epoch_leaders()
         self.prev_leader_id=0
-        self.signal()
+        self.new_epoch_signal()
         #TODO need to assign the block from the last slot in the epoch
         while True:
             if not self.beacon.slot == self.current_slot:
                 self.current_slot = self.beacon.slot
-                self.signal()
+                if self.beacon.epoch_slot != 0:
+                    self.new_slot_signal()
+                else:
+                    self.new_epoch_signal()
         
-    def signal(self):
-        ########################
-        #TODO fix cretical
-        ########################
-        # run the state on a member, no static function for new_epoch, new_slot.
-
-        if self.beacon.epoch_slot!=0:
-            ############
-            # NEW SLOT #
-            ############
-            y, pi = self.rands[self.current_slot]
-            threads = []
-            for sk in self.stakeholders:
-                #TODO (fix) failed to synchronized current_slot 1234 for epoch length of 2 is two states
-                # need to pass the slot with it's corresponding sigma, and proof
-                thread = Thread(target=Stakeholder.new_slot, args=(sk, self.current_slot, y, pi))                
-                #sk.new_slot(self.current_slot, y, pi)
-                threads.append(thread)
-                thread.start()
-            for th in threads:
-                th.join()
-        else:
-            #############
-            # NEW EPOCH #
-            #############
-            vrf = self.stakeholders[self.current_leader_id].vrf
-            if self.beacon.epoch != self.current_epoch:
-                self.current_epoch = self.beacon.epoch
-                self.rands = self.beacon.next_epoch_seeds(vrf)
-                self.select_epoch_leaders()
-            for idx, sk in enumerate(self.stakeholders):
-                if sk.id==id:
-                    self.prev_leader_id=idx
-            self.cached_dist = self.get_epoch_distribution()
-            for sk in self.stakeholders:
-                sk.current_slot_uid=self.beacon.slot
+    def new_slot_signal(self):
+        ############
+        # NEW SLOT #
+        ############
+        y, pi = self.rands[self.current_slot]
+        threads = []
+        for sk in self.stakeholders:
+            #TODO (fix) failed to synchronized current_slot 1234 for epoch length of 2 is two states
+            # need to pass the slot with it's corresponding sigma, and proof
+            thread = Thread(target=Stakeholder.new_slot, args=(sk, self.current_slot, y, pi))                
+            #sk.new_slot(self.current_slot, y, pi)
+            threads.append(thread)
+            thread.start()
+        for th in threads:
+            th.join()
+
+    def new_epoch_signal(self):
+        #############
+        # NEW EPOCH #
+        #############
+        vrf = self.stakeholders[self.current_leader_id].vrf
+        if self.beacon.epoch != self.current_epoch:
+            self.current_epoch = self.beacon.epoch
+            self.rands = self.beacon.next_epoch_seeds(vrf)
+            self.select_epoch_leaders()
+        for idx, sk in enumerate(self.stakeholders):
+            if sk.id==id:
+                self.prev_leader_id=idx
+        self.cached_dist = self.get_epoch_distribution()
+        for sk in self.stakeholders:
+            sk.current_slot_uid=self.beacon.slot
             ###
-            genesis_item = self.get_genesis_data()
-            data = Data()
-            data.append(genesis_item)
-            self.current_block=GensisBlock(self.current_block, data, self.beacon.slot, self.genesis_time)
-            assert self.current_block is not None
-            current_epoch=Epoch(self.current_block, self.epoch_length, self.epoch, self.genesis_time)
-            threads = []
-            for sk in self.stakeholders:
-                #sk.new_epoch(current_epoch)
-                thread = Thread(target=Stakeholder.new_epoch, args=(sk, current_epoch))
-                threads.append(thread)
-                thread.start()
-            for th in threads:
-                th.join()
-    @property
-    def endorser_len(self):
-        #TODO (impl)
-        pass
+        genesis_item = self.get_genesis_data()
+        data = Data()
+        data.append(genesis_item)
+        self.current_block=GensisBlock(self.current_block, data, self.beacon.slot, self.genesis_time)
+        assert self.current_block is not None
+        current_epoch=Epoch(self.current_block, self.epoch_length, self.epoch, self.genesis_time)
+        threads = []
+        for sk in self.stakeholders:
+            #sk.new_epoch(current_epoch)
+            thread = Thread(target=Stakeholder.new_epoch, args=(sk, current_epoch))
+            threads.append(thread)
+            thread.start()
+        for th in threads:
+            th.join()
+
 
     def __repr__(self):
         buff= f"envirnment of {self.length} stakholders\tcurrent leader's id: {self.current_leader_id}\tepoch_slot: {self.epoch_slot}\tendorser_id: {self.current_endorser_id}"
@@ -179,11 +174,32 @@ class Z(object):
     def current_endorser_id(self):
         return self.slot_committee[self.current_slot][1]
 
+    @property
+    def current_endorser_uid(self):
+        return self.stakeholders[self.current_endorser_id].id
+    
     @property
     def current_endorser(self):
         self.log.info(f"getting endorser of id: {self.current_leader_id}")
         return self.stakeholders[self.current_endorser_id]
 
+    @property
+    def current_endorser_sig_pk(self):
+        return self.stakeholders[self.current_endorser_id].sig_pk
+
+    def endorser(self, slot):
+        return self.stakeholders[self.slot_committee[slot][1]]
+    
+    def endorser_sig_pk(self, slot):
+        return self.endorser(slot).sig_pk
+
+    def endorser_vrf_pk(self, slot):
+        return self.endorser(slot).vrf_pk
+
+    def is_current_endorser(self, id):
+        _, edr_idx = self.slot_committee[self.beacon.slot]
+        return id == self.stakeholders[edr_idx].id
+
     @property
     def current_leader_vrf_pk(self):
         return self.stakeholders[self.current_leader_id].vrf_pk
@@ -192,6 +208,11 @@ class Z(object):
     def current_leader_vrf_g(self):
         return self.stakeholders[self.current_leader_id].vrf_base
 
+    def is_current_leader(self, id):
+        ldr_idx, _ = self.slot_committee[self.beacon.current_slot]
+        return id == self.stakeholders[ldr_idx].id
+
+    
     '''
     @property
     def current_epoch_leader(self):
@@ -209,25 +230,13 @@ class Z(object):
     def current_leader_sig_pk(self):
         return self.stakeholders[self.current_leader_id].sig_pk
     
-    @property
-    def current_endorser_sig_pk(self):
-        return self.stakeholders[self.current_endorser_id].sig_pk
 
-    def endorser(self, epoch_slot):
-        assert epoch_slot >= 0 and epoch_slot < self.epoch_length
-        return self.stakeholders[epoch_slot]
-    
-    def endorser_sig_pk(self, epoch_slot):
-        return self.endorser(epoch_slot).sig_pk
-
-    def endorser_vrf_pk(self, epoch_slot):
-        return self.endorser(epoch_slot).vrf_pk
 
     #note! assumes epoch_slot lays in the current epoch
-    def leader(self, epoch_slot):
-        assert epoch_slot >= 0 and epoch_slot < self.epoch_length
-        return self.stakeholders[epoch_slot]
+    def leader(self, slot):
+        return self.stakeholders[self.slot_committee[slot][0]]
 
+    '''
     def leader_sig_pk(self, epoch_slot):
         return self.leader(epoch_slot).sig_pk
 
@@ -236,7 +245,7 @@ class Z(object):
     
     def leader_vrf_g(self, epoch_slot):
         return self.leader(epoch_slot).vrf_base
-
+    '''
     def prev_leader_vrf_pk(self):
         return self.stakeholders[self.prev_leader_id].vrf_pk
     
@@ -315,8 +324,8 @@ class Z(object):
             # under a single condition that no one is able to predict who is next
             assert not leader_idx==endorser_idx
             #TODO move leader/endorser to a dictionary
-
             self.slot_committee[slot_idx] = (leader_idx, endorser_idx)
+            self.log.highlight(f'slot {slot_idx} has committee leader/endorser {leader_idx}/{endorser_idx}\nleader: {self.stakeholders[leader_idx]}\nendorser: {self.stakeholders[endorser_idx]}')
         self.epoch_initialized[str(self.epoch)] = True
 
     def broadcast_block(self, cur_block, signed_block, slot_uid):
@@ -332,13 +341,6 @@ class Z(object):
         self.print_blockchain()
 
 
-    def is_current_leader(self, id):
-        ldr_idx, _ = self.slot_committee[self.beacon.current_slot]
-        return id == self.stakeholders[ldr_idx].id
-
-    def is_current_endorser(self, id):
-        _, edr_idx = self.slot_committee[self.beacon.current_slot]
-        return id == self.stakeholders[edr_idx].id
 
     @property
     def block_id(self):
@@ -348,7 +350,7 @@ class Z(object):
         #TODO commit this step to handshake phases
         self.current_blk_endorser_sig=None
         self.log.info(f"endorsing block for current_leader_id: {self.current_leader_id}")
-        confirmed = self.stakeholders[self.current_leader_id].confirm_endorsing(sig, self.block_id, self.epoch_slot)
+        confirmed = self.stakeholders[self.current_leader_id].confirm_endorsing(sig, self.block_id, self.current_slot)
         if confirmed:
             self.current_blk_endorser_sig=sig
         else:
@@ -360,17 +362,18 @@ class Z(object):
             bc = sh.blockchain
             self.log.highlight(f"<blockchain>  {len(bc)} blocks: "+str(bc))
 
+    '''
     def confirm_endorsing(self, sig, blk_uid):
         if blk_uid==self.current_slot:
             self.current_blk_endorser_sig = sig
-
+    '''
     def corrupt_leader(self):
         self.corrupt(self.current_leader_id)
 
-    def corrupt_endorse(self):
+    def corrupt_endorser(self):
         self.corrupt(self.current_endorser_id)
 
     def corrupt_blk(self):
         self.log.warn(f"<corrupt_blk> at slot: {self.current_slot}")
         self.corrupt_leader()
-        self.corrupt_endorse()
+        self.corrupt_endorser()

+ 24 - 12
script/research/dpos/ouroboros/stakeholder.py

@@ -57,11 +57,11 @@ class Stakeholder(object):
     def __repr__(self):
         buff=''
         if self.env.is_current_leader(self.id):
-            buff = f"\tleader {self.id} with stake:{self.stake}\nsig_sk: {self.sig_pk}"
+            buff = f"\tleader {self.id} with stake:{self.stake}\nsig_pk: {self.sig_pk}"
         elif self.env.is_current_endorser(self.id):
-            buff = f"\tendorser {self.id} with stake:{self.stake}\nsig_sk: {self.sig_pk}"
+            buff = f"\tendorser {self.id} with stake:{self.stake}\nsig_pk: {self.sig_pk}"
         else:
-            buff = f"\thonest committee memeber {self.id} with stake:{self.stake}\nsig_sk: {self.sig_pk}"
+            buff = f"\thonest committee memeber {self.id} with stake:{self.stake}\nsig_pk: {self.sig_pk}"
         return buff
 
     def __call__(self, env):
@@ -143,22 +143,30 @@ class Stakeholder(object):
         signed_block=None
         #TODO should wait for l slot until block is endorsed
         endorsing_cnt=10
-        while not self.current_block.endorsed:
+        #TODO (rev)
+        while not self.current_block.endorsed or self.blockchain[self.current_slot_uid]:
             time.sleep(1)
             self.log.info("...waiting for endorsment..")
             endorsing_cnt-=1
+        '''
         if not self.current_block.endorsed:
             self.log.warn("failure endorsing the block...")
             self.current_block = EmptyBlock(self.env.genesis_time)
+        '''
         signed_block = sign_message(self.passwd, self.sig_sk, self.current_block)
         self.env.broadcast_block(self.current_block, signed_block, self.current_slot_uid)
     
+    @property
+    def current_slot(self):
+        return self.env.beacon.current_slot
+
     '''
     only endorser can broadcast block
     '''
     def endorse_block(self):
-        if not self.env.is_current_endorser(self.id):
-            return
+        assert self.env.is_current_endorser(self.id)
+        assert self.env.endorser_sig_pk(self.env.beacon.slot) == self.sig_pk, f' assertion failed for beacon slot {self.env.beacon.slot}, current_slot {self.current_slot}, lhs: {self.env.endorser_sig_pk(self.env.beacon.slot)},\nrhs: {self.sig_pk}\nleader\endorser ids {self.env.slot_committee[self.env.beacon.slot][0]}/{self.env.slot_committee[self.env.beacon.slot][1]}'
+        #assert self.env.endorser_sig_pk(self.current_slot) == self.sig_pk, f'lsh: {self.env.endorser_sig_pk(self.current_slot)},\nrhs: {self.sig_pk}'
         self.current_block.set_endorser(self.id)
         self.log.info(f"endorsing block for current_leader_id: {self.env.current_leader_id}")
         if not self.env.is_current_endorser(self.id):
@@ -210,22 +218,26 @@ class Stakeholder(object):
                 self.log.warn("block endorsing verification failed")
             self.env.corrupt_blk()
 
-    def confirm_endorsing(self, endorser_sig, blk_uid, epoch_slot):
+    def confirm_endorsing(self, endorser_sig, blk_uid, slot):
         self.log.highlight(f"confirming block with epoch slot id {blk_uid}")
         confirmed = False
         cur_blk, _ = self.__get_blk(blk_uid)
         self.log.highlight(f'confirming endorsed block  {str(cur_blk)}')
-        self.log.highlight(f'confirming endorsed has slot_uid: {self.current_slot_uid}')
+        self.log.highlight(f'confirming endorsed has slot: {slot} epoch slot_uid: {self.current_slot_uid}')
         self.log.highlight(f'confirming endorsed has sig_pk: {self.env.current_endorser_sig_pk}')
-        if verify_signature(self.env.endorser_sig_pk(epoch_slot), cur_blk, endorser_sig):
+        endorser_sig_pk = self.env.endorser_sig_pk(self.env.beacon.slot)
+        self.log.highlight(f'confirming endorsed sig pk: {endorser_sig_pk}')
+        if verify_signature(endorser_sig_pk, cur_blk, endorser_sig):
             if self.current_slot_uid==self.env.current_slot:
-                self.current_block.set_endorser(self.current_endorser_id)
+                self.log.highlight("set current block as endorsed")
+                self.current_block.set_endorser(self.env.current_endorser_uid)
                 self.current_block.set_endorsed()
             else:
-                self.blockchain[blk_uid].set_endorser(self.current_endorser_id)
+                self.log.highlight(f"set delayed blockchain block with uid: {blk_uid} as endorsed")
+                self.blockchain[blk_uid].set_endorser(self.env.current_endorser_uid)
                 self.blockchain[blk_uid].set_endorsed()
             confirmed=True
         else:
-            self.log.warn(f"confirmed enderser signature failure for pk: {str(self.env.current_endorser_sig_pk)} on block {str(cur_blk)}  of signature {str(endorser_sig)}")
+            self.log.warn(f"confirmed enderser signature failure for pk: {str(endorser_sig_pk)} on block {str(cur_blk)}  of signature {str(endorser_sig)}")
             confirmed=False
         return confirmed