Эх сурвалжийг харах

[research/ouroboros] dynamic staking

mohab 4 жил өмнө
parent
commit
112f93389a

+ 11 - 14
script/research/dpos/ouroboros/beacon.py

@@ -24,6 +24,8 @@ class TrustedBeacon(SynchedNTPClock, threading.Thread):
         self.log = Logger(self, genesis_time)
         self.log.info(f"constructed for node {str(node)}")
         self.bb=0 # epoch counts since genesis (big bang)
+        self.sigmas = []
+        self.proofs = []
 
     def __repr__(self):
         return f"trustedbeacon"
@@ -48,24 +50,19 @@ class TrustedBeacon(SynchedNTPClock, threading.Thread):
                 # new nodes attached to the network, need to either request old blocks, or wait for next epoch's broadcst
                 # it's temporarily, and or simplicity set to the latter 
                 return
-            self.log.info(f"callback: new slot of idx: {self.current_slot}")
-            #y, pi = self.vrf.sign(self.current_slot)
-            self.log.info(f"callbaxck: signature calculated for {str(self.node)}")
-            self.node.new_slot(self.current_slot)
+            self.node.new_slot(self.current_slot, self.sigmas[self.current_slot%self.epoch_length], self.proofs[self.current_slot%self.epoch_length])
         else:
-            self.bb+=1
-            sigmas = []
-            proofs = []
             #TODO since it's expensive, but to generate single (y,pi) pair as seed 
             # and use random hash function to generate the rest randomly. 
             if self.node.am_current_leader:
+                self.bb+=1
+                self.sigmas = []
+                self.proofs = []
                 for i in range(self.epoch_length):
-                    self.log.info(f"callback: new slot of idx: {self.current_slot}, epoch slot {i}")
-                    y, pi = self.vrf.sign(self.current_slot)
-                    self.log.info(f"callback: signature calculated for {str(self.node)}")
-                    sigmas.append(y)
-                    proofs.append(pi)
-            self.node.new_epoch(self.current_slot, sigmas, proofs)
+                    y, pi = self.vrf.sign(self.current_slot+i)
+                    self.sigmas.append(y)
+                    self.proofs.append(pi)
+                self.node.new_epoch(self.current_slot, self.sigmas, self.proofs)
 
     def verify(self, y, pi, pk_raw, g):
-        return VRF.verify(self.current_slot, y, pi, pk_raw, g)
+        return VRF.verify(self.current_slot, y, pi, pk_raw, g)

+ 12 - 3
script/research/dpos/ouroboros/block.py

@@ -28,6 +28,8 @@ class Block(object):
         self.is_genesis=genesis
         self.endorsed=False
         self.log = Logger(genesis_time)
+        self.leader_id=None
+        self.endorser_id=None
 
     def __repr__(self):
         if self.is_genesis:
@@ -59,6 +61,12 @@ class Block(object):
     def set_endorsed(self):
         self.endorsed=True
 
+    def set_endorser(self, id):
+        self.endorser_id=id
+        self.set_endorsed()
+
+    def set_leader(self, id):
+        self.leader_id=id
     
     @property
     def data(self):
@@ -83,9 +91,10 @@ class GensisBlock(Block):
     '''
     def __init__(self, previous_block, data, slot_uid, genesis_time=time.time()):
         # stakeholders is list of tuple (pk_i, s_i) for the ith stakeholder
-        self.stakeholders = data[STAKEHOLDERS]
-        self.distribution = data[STAKEHOLDERS_DISTRIBUTIONS]
-        self.seed = data.get(SEED, '') #needed for pvss
+        dist_block = data[0]
+        self.stakeholders = dist_block[STAKEHOLDERS]
+        self.distribution = dist_block[STAKEHOLDERS_DISTRIBUTIONS]
+        self.seed = dist_block[SEED] #needed for pvss
         shd_buff = ''
         for shd in self.distribution:
             shd_buff +=str(shd)

+ 24 - 6
script/research/dpos/ouroboros/blockchain.py

@@ -1,3 +1,4 @@
+import math
 from ouroboros.logger import Logger
 
 '''
@@ -9,6 +10,7 @@ class Blockchain(object):
         self.blocks = []
         self.log = Logger(self, genesis_time)
         self.R = R # how many slots in single epoch
+        self.epochs = []
     
     @property
     def epoch_length(self):
@@ -16,19 +18,29 @@ class Blockchain(object):
 
     def __repr__(self):
         buff=''
-        for i in range(len(self.blocks)):
-            buff+=str(self.blocks[i])
+        for e in range(len(self.epochs)):
+            for b in range(len(e)):
+                buff+=str(b)+'\n'
         return buff
-    
+
+    '''
+    @return: epoch reference
+    '''
     def __getitem__(self, i):
-        return self.blocks[i]
+        e_idx = math.floor(i/self.epoch_length)
+        e_blk_idx = i%self.epoch_length
+        return self.epochs[e_idx][e_blk_idx]
 
+    '''
+    @return: number of blocks
+    '''
     def __len__(self):
-        return len(self.blocks)
+        return len(self.epochs*self.epoch_length)
 
+    '''
     def __add_block(self, block):
         self.blocks.append(block)
-
+    
     def add_epoch(self, epoch):
         assert epoch!=None, 'epoch cant be None'
         assert len(epoch)>0 , 'epoch cant be zero-sized'
@@ -37,3 +49,9 @@ class Blockchain(object):
                 self.__add_block(block)
             else:
                 self.log.warn(f"an empty block at index of index: {block.index},\nrelative slot:{idx}\nabsolute slot: {self.length*idx+block.slot}")
+    '''
+    def append(self, epoch):
+        assert epoch!=None, 'epoch cant be None'
+        assert len(epoch)>0 , 'epoch cant be zero-sized'
+        assert len(epoch)==self.epoch_length
+        self.append(epoch)

+ 107 - 0
script/research/dpos/ouroboros/data.py

@@ -0,0 +1,107 @@
+import time
+from ouroboros.logger import Logger
+
+'''
+\class Item is the basic item in the block data
+'''
+class Item(object):
+    def __init__(self, data, fee=1):
+        self.data = data
+        self.fee = fee
+        self.log = Logger(self)
+    
+    '''
+    coffee reward for the miner
+    '''
+    @property
+    def coffee(self):
+        return self.fee
+
+class GenesisItem(Item):
+    def __init__(self, dict_data):
+        self.fee=0
+        Item.__init__(self, dict_data)
+    
+    def __getitem__(self, key):
+        return self.data.get(key, '')
+
+#TODO implement
+class StateTransition(Item):
+    def __init__(self, balance):
+        self.balance = balance
+
+#TODO implement
+class TransitionProcessor(object):
+    def __init__(self):
+        pass
+
+'''
+\class Transaction coin exchange between two entities
+'''
+class Transaction(Item):
+    def __init__(self, sndr_addr, rcvr_addr, amnt, fee=1, lock_time=time.time()):
+        self.sndr_addr = sndr_addr
+        self.rcvr_addr = rcvr_addr
+        self.amnt = amnt
+        self.lock_time = lock_time
+        self.stamp = time.time()
+        fee = fee
+        Item.__init__(self, str(self), fee)
+        self.log.info(str(self))
+
+    def __repr__(self):
+        return f'sender: {self.sndr_addr}, receiver: {self.rcvr_addr}, amount: {self.amnt}, self.lock time: {self.lock_time}'
+
+class CoinBase(Item):
+    def __init__(self):
+        pass
+
+'''
+\class Data is the whole data stored in a single block, 
+consist of list of Items
+'''
+class Data(list):
+
+    def __init__(self, txs=[]):
+        self.txs = txs        
+    '''
+    Pall, is the accumulated transactions fee/gas/coffee for a block 
+    '''
+    @property
+    def coffee(self):
+        pall = 0
+        for item in self.txs:
+            pall += item.coffee
+        return pall
+
+    def __repr__(self):
+        buff = ''
+        for item in self.txs:
+            buff += str(item) + '\n'
+        return buff
+
+    def __len__(self):
+        return len(self.txs)
+
+    def __iter__(self):
+        self.n=0
+        return self
+
+    def __next__(self):
+        item  = None
+        if self.n <= self.length:
+            try:
+                item = self.txs[self.n]
+                self.n+=1
+                return item
+            except IndexError:
+                raise StopIteration
+    
+    def append(self, item):
+        self.txs.append(item)
+
+    def __getitem__(self, i):
+        L = len(self)
+        if i >= L or i < 0:
+            return None
+        return self.txs[i]

+ 63 - 14
script/research/dpos/ouroboros/environment.py

@@ -4,9 +4,12 @@ import random
 import time
 from ouroboros.logger import Logger
 from ouroboros.consts import *
+from ouroboros.data import Item, GenesisItem
+from ouroboros import utils
 
 '''
-\class Z is the environment
+\class Z is the environment,
+environment is ought to interfece with the network
 '''
 class Z(object):
     def __init__(self, stakeholdes, epoch_length, genesis_time=time.time()):
@@ -21,22 +24,60 @@ class Z(object):
         self.log.info("Z initialized")
         self.current_blk_endorser_sig=None
         self.epoch_inited=False
+        self.cached_dist = []
+        self.beta = 0.5 # endorser weight
+        #
+        self.l=0
+        #a transaction is declared stable if and only if it is in a block that,
+        # is more than k blocks deep in the ledger.
+        self.k = self.epoch_length/2 - self.l -1 
     
+    @property
+    def endorser_len(self):
+        #TODO (impl)
+        pass
+
     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}"
+        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_idx}"
         for sh in self.stakeholders:
             buff+=str(sh)+"\n"
         return buff
+   
+    '''
+    issue a coinbase for claimed reward 2(k+l) after the block
+    '''
+    def issue_coinbase(self):
+        #TODO
+        pass
+
+    '''
+    returns true if before time, false otherwise
+    '''
+    @property
+    def iceage(self):
+        return self.block_id==0
+
+    @property
+    def previous_epoch_stake_distribution(self):
+        if self.iceage:
+            return self.get_epoch_distribution()
+        else:
+            return self.cached_dist
+
+    def get_epoch_distribution(self):
+        stakes = [node.stake for node in self.stakeholders]
+        return stakes
 
     '''
         return genesis data of the current epoch
     '''
     def get_genesis_data(self):
         #TODO implement dynaming staking
+        distribution = self.get_epoch_distribution()
         genesis_data = {STAKEHOLDERS: self.stakeholders,
-        STAKEHOLDERS_DISTRIBUTIONS:[],
+        STAKEHOLDERS_DISTRIBUTIONS: distribution,
             SEED: ''}
-        return genesis_data
+        return GenesisItem(genesis_data)
     
     @property
     def epoch_slot(self):
@@ -52,13 +93,16 @@ class Z(object):
         return self.stakeholders[self.current_leader_id]
 
     @property
-    def current_endorser_id(self):
+    def current_endorser_idx(self):
         return self.current_epoch_endorsers[self.epoch_slot]
 
+    def current_endorser_id(self):
+        return self.current_endorser.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]
+        return self.stakeholders[self.current_endorser_idx]
 
     @property
     def current_leader_vrf_pk(self):
@@ -74,7 +118,7 @@ class Z(object):
     
     @property
     def current_endorser_sig_pk(self):
-        return self.stakeholders[self.current_endorser_id].sig_pk
+        return self.stakeholders[self.current_endorser_idx].sig_pk
 
     def endorser(self, epoch_slot):
         assert epoch_slot >= 0 and epoch_slot < self.epoch_length
@@ -124,6 +168,10 @@ class Z(object):
     def honest(self):
         return len(self.stakeholders[self.adversary_mask])
 
+    @property
+    def random(self):
+        return utils.weighted_random(self.previous_epoch_stake_distribution)
+
     def select_epoch_leaders(self, sigmas, proofs):
         assert len(sigmas)==self.epoch_length and len(proofs)==self.epoch_length, self.log.error(f"size mismatch between sigmas: {len(sigmas)}, proofs: {len(proofs)}, and epoch_length: {self.epoch_length}")
         for i in range(self.epoch_length):
@@ -136,15 +184,15 @@ class Z(object):
                 return y_hypotenuse2
             seed = leader_selection_hash(sigma)
             random.seed(seed)
-            leader_idx=seed%self.length
-            endorser_idx=random.randint(0,self.length-1)
+            leader_idx=self.random
+            endorser_idx=self.random
             # only select an honest leaders
             while leader_idx==endorser_idx or not self.adversary_mask[leader_idx] or not self.adversary_mask[endorser_idx]:
-                leader_idx=random.randint(0,self.length-1)
-                endorser_idx=random.randint(0,self.length-1)
-
+                leader_idx=self.random
+                endorser_idx=self.random
             #TODO select the following leader for this epoch, note, 
             # under a single condition that no one is able to predict who is next
+            assert not leader_idx==endorser_idx
             self.current_epoch_leaders[i]=leader_idx
             self.current_epoch_endorsers[i]=endorser_idx
         return self.current_epoch_leaders, self.current_epoch_endorsers
@@ -155,11 +203,12 @@ class Z(object):
         current_leader = self.stakeholders[self.current_leader_id]
         assert current_leader is not None, "current leader cant be None"
         self.log.highlight('selecting epochs leaders, and ensorsers ---->')
-        self.stakeholders[self.current_epoch_endorsers[self.current_endorser_id]].set_endorser()
+        self.stakeholders[self.current_epoch_endorsers[self.current_endorser_idx]].set_endorser()
         self.stakeholders[self.current_epoch_leaders[self.current_leader_id]].set_leader()
         self.log.highlight('selected epochs leaders, and ensorsers <----')
         
     def new_epoch(self, slot, sigmas, proofs):
+        self.cached_dist = self.get_epoch_distribution()
         self.epoch_inited=True
         self.current_slot=slot
         leaders, endorsers = self.select_epoch_leaders(sigmas, proofs)
@@ -208,7 +257,7 @@ class Z(object):
         self.corrupt(self.current_leader_id)
 
     def corrupt_endorse(self):
-        self.corrupt(self.current_endorser_id)
+        self.corrupt(self.current_endorser_idx)
 
     def corrupt_blk(self):
         self.log.warn(f"<corrupt_blk> at slot: {self.current_slot}")

+ 10 - 4
script/research/dpos/ouroboros/epoch.py

@@ -12,7 +12,6 @@ class Epoch(list):
         self.blocks = []
         self.R = R #maximum epoch legnth, and it's a fixed property of the system
         self.e = epoch_idx
-        self.n=0
         self.log = Logger(genesis_time)
 
     @property
@@ -33,6 +32,13 @@ class Epoch(list):
             return None
         return self.blocks[0]
 
+    @property
+    def coffee(self):
+        epoch_fee = 0
+        for blk in self.blocks:
+            epoch_fee += blk.data.coffee
+        return epoch_fee
+
     def __len__(self):
         return self.length
 
@@ -53,10 +59,10 @@ class Epoch(list):
     
     def __next__(self):
         blk=None
-        for i in range(self.length):
+        if self.n <= self.length:
             try:
                 blk=self.blocks[self.n]
+                self.n+=1
+                return blk
             except IndexError:
                 raise StopIteration
-            self.n+=1
-            return blk

+ 13 - 0
script/research/dpos/ouroboros/hashtree.py

@@ -0,0 +1,13 @@
+from ouroboros.data import Data
+
+'''
+\class HashTree
+'''
+class HashTree(object):
+
+    def __init__(self, data):
+        self.data = data
+
+    def root(self):
+        #TODO implement
+        return self.data

+ 72 - 35
script/research/dpos/ouroboros/stakeholder.py

@@ -8,6 +8,7 @@ from ouroboros.vrf import verify, VRF
 from ouroboros.utils import *
 from ouroboros.logger import Logger
 from ouroboros.consts import *
+from ouroboros.data import Data, Transaction, Item
 
 '''
 \class Stakeholder
@@ -16,7 +17,7 @@ class Stakeholder(object):
     def __init__(self, epoch_length, passwd='password'):
         #TODO (fix) remove redundant variables reley on environment
         self.passwd=passwd
-        self.stake=0
+        self.stake=1
         self.epoch_length=epoch_length
         self.vrf = VRF(self.passwd)
         #verification keys
@@ -29,14 +30,25 @@ class Stakeholder(object):
         self.sig_pk = sig_pk
         #
         self.current_block = None
-        self.uncommited_tx=''
-        self.tx=''
         self.current_epoch = None
         self.am_current_leader=False
         self.am_current_endorser=False
         self.am_corrupt=False
         #
         self.blockchain=None
+        #
+        self.data = Data()
+        #verifiable fingerprint for a stakeholder taking advantage of public sig, vrf
+
+        self.id = sign_message(self.passwd, self.sig_sk, str(self.vrf_pk))
+
+    def receive_tx(self, tx):
+        #TODO validate trx
+        self.data.append(tx)
+
+    def broadcast_tx(self, tx):
+        self.data.append(tx)
+        self.env.broadcast_tx(tx)
 
     @property
     def is_leader(self):
@@ -53,11 +65,11 @@ class Stakeholder(object):
     def __repr__(self):
         buff=''
         if self.am_current_leader:
-            buff = f"\tleader {(hash(self.passwd))} with stake:{self.stake}\nsig_sk: {self.sig_pk}"
+            buff = f"\tleader {self.id} with stake:{self.stake}\nsig_sk: {self.sig_pk}"
         elif self.am_current_endorser:
-            buff = f"\tendorser {(hash(self.passwd))} with stake:{self.stake}\nsig_sk: {self.sig_pk}"
+            buff = f"\tendorser {self.id} with stake:{self.stake}\nsig_sk: {self.sig_pk}"
         else:
-            buff = f"\thonest committee memeber {(hash(self.passwd))} with stake:{self.stake}\nsig_sk: {self.sig_pk}"
+            buff = f"\thonest committee memeber {self.id} with stake:{self.stake}\nsig_sk: {self.sig_pk}"
         return buff
 
     def __call__(self, env):
@@ -67,10 +79,9 @@ class Stakeholder(object):
         self.beacon = TrustedBeacon(self,  self.vrf, self.epoch_length, self.env.genesis_time)
         self.current_slot_uid = self.beacon.slot
 
-
     def start(self):
         self.log.info("thread [started]")
-        self.beacon.start()
+        self.beacon.start()  
         self.log.info("thread [ended]")
 
     @property
@@ -80,13 +91,19 @@ class Stakeholder(object):
     def __gen_genesis_epoch(self):
         '''
         '''
-        self.tx = self.env.get_genesis_data()
-        self.tx[TX]=self.uncommited_tx
-        self.uncommited_tx=''
-        self.current_block=GensisBlock(self.current_block, self.tx, self.current_slot_uid, self.env.genesis_time)
+        tx_item = self.env.get_genesis_data()
+        self.data.append(tx_item)
+        self.current_block=GensisBlock(self.current_block, self.data, self.current_slot_uid, self.env.genesis_time)
         assert self.current_block is not None
         self.current_epoch=Epoch(self.current_block, self.epoch_length, self.epoch_index, self.env.genesis_time)
-   
+
+    def end_slot(self):
+        # start new transactions 
+        self.data = Data()
+
+    def add_epoch(self):
+        self.blockchain.append(self.current_epoch)
+        self.update_stake()
     '''
     it's a callback function, and called by the diffuser
     '''
@@ -100,38 +117,34 @@ class Stakeholder(object):
         if self.am_current_leader:
             self.env.new_epoch(slot, sigmas, proofs)
         self.current_slot_uid = slot
-        #kickoff gensis block
         # add old epoch to the ledger
         if self.current_slot_uid > 1 and self.current_epoch!=None and len(self.current_epoch)>0:
-            self.blockchain.add_epoch(self.current_epoch)  
-        #if leader, you need to broadcast the block
+            self.add_epoch()
         while not self.env.epoch_inited:
             self.log.info("pending epoch initialization")
             time.sleep(1)
         self.__gen_genesis_epoch()
-        if self.am_current_leader:
-            self.broadcast_block()
-            self.end_leadership()
-        elif self.am_current_endorser:
-            self.endorse_block()
-            self.end_endorsing()
+        self.new_slot(self.current_slot_uid, sigmas[0], proofs[0])
+
+    def terminate_slot(self):
+        pass
 
     '''
     it's a callback function, and called by the diffuser
     '''
-    #def new_slot(self, slot, sigma, proof):
-    def new_slot(self, slot):
+    def new_slot(self, slot, sigma, proof):
         '''
         #TODO implement praos
         for this implementation we assume synchrony,
         and at this point, and no delay is considered (for simplicity)
         '''
         self.log.highlight("<new_slot> start")
+        self.terminate_slot()
         self.env.new_slot(slot)
-        '''
+
         vrf_pk = self.env.current_leader_vrf_pk
         vrf_g = self.env.current_leader_vrf_g
-        if not verify(slot, sigma, proof, vrf_pk,vrf_g) :
+        if not verify(slot, sigma, proof, vrf_pk,vrf_g):
             #TODO the leader is corrupted, action to be taken against the corrupt stakeholder
             #in this case this slot is empty
             self.log.warn(f"<new_slot> leader verification fails")
@@ -140,14 +153,13 @@ class Stakeholder(object):
                 self.__gen_genesis_epoch()
             self.current_epoch.add_block(self.current_block)
             return
-        '''
-        if self.current_epoch==None:
-            self.log.warn(f"<new_slot> current_epoch is None!")
-            self.__gen_genesis_epoch()
+
         self.current_slot_uid = slot
-        prev_blk = self.blockchain[-1] if len(self.blockchain)>0 else EmptyBlock(self.env.genesis_time)
-        self.current_block=Block(prev_blk, self.tx, self.current_slot_uid, self.env.genesis_time)
-        self.current_epoch.add_block(self.current_block)
+        if self.current_slot_uid%self.epoch_length!=0:
+            prev_blk = self.blockchain[-1] if len(self.blockchain)>0 else EmptyBlock(self.env.genesis_time)
+            self.current_block=Block(prev_blk, self.data, self.current_slot_uid, self.env.genesis_time)
+            self.current_epoch.add_block(self.current_block)
+
         if self.am_current_leader:
             self.log.highlight(f"{str(self)} is broadcasting block")
             self.broadcast_block()
@@ -157,6 +169,20 @@ class Stakeholder(object):
             self.endorse_block()
             self.end_endorsing()
 
+    def update_stake(self):
+        if len(self.blockchain)==0:
+            return
+        epoch = self.blockchain[-1]
+        pall = epoch.coffee()
+        leader_cnt=0
+        endorser_cnt=0
+        for blk in epoch:
+            if blk.leader_id==self.id:
+                leader_cnt+=1
+            elif blk.endorser_id==self.id:
+                endorser_cnt+=1
+        self.stake += (self.env.beta * (endorser_cnt/self.env.endorser_len) + \
+            (1-self.env.beta) * (leader_cnt/self.env.epoch_length)) * pall
 
     def end_leadership(self):
         self.log.info(f"stakeholder:{str(self)} ending leadership for slot{self.current_slot_uid}")
@@ -175,7 +201,13 @@ class Stakeholder(object):
     def set_corrupt(self):
         self.am_corrupt=False
 
+    '''
+    only leader can broadcast block
+    '''
     def broadcast_block(self):
+        if not self.am_current_leader:
+            return
+        self.current_block.set_leader(self.id)
         self.log.highlight("broadcasting block")
         assert self.am_current_leader and self.current_block is not None
         signed_block=None
@@ -187,14 +219,17 @@ class Stakeholder(object):
             endorsing_cnt-=1
         if not self.current_block.endorsed:
             self.log.warn("failure endorsing the block...")
-        if not self.current_block.endorsed:
             self.current_block = EmptyBlock(self.env.genesis_time)
         signed_block = sign_message(self.passwd, self.sig_sk, self.current_block)
         self.env.broadcast_block(signed_block, self.current_slot_uid)
     
+    '''
+    only endorser can broadcast block
+    '''
     def endorse_block(self):
         if not self.am_current_endorser:
             return
+        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.am_current_endorser:
             self.log.warn("not endorser")
@@ -252,11 +287,13 @@ class Stakeholder(object):
         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):
             if self.current_slot_uid==self.env.current_slot:
+                self.current_block.set_endorser(self.current_endorser_id)
                 self.current_block.set_endorsed()
             else:
+                self.blockchain[blk_uid].set_endorser(self.current_endorser_id)
                 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)}")
             confirmed=False
-        return confirmed
+        return confirmed

+ 0 - 1
script/research/dpos/ouroboros/utils.py

@@ -3,7 +3,6 @@ from cryptography.hazmat.primitives.asymmetric import rsa, padding
 from cryptography.hazmat.backends import default_backend
 from cryptography.exceptions import InvalidSignature
 import random
-import joblib
 import pickle
 
 def extended_euclidean_algorithm(a, b):

+ 3 - 4
script/research/dpos/simulation.py

@@ -2,11 +2,11 @@ import time
 from ouroboros import Stakeholder
 from ouroboros import Z
 
-'''
-EPOCH_LENGTH = 3
+
+EPOCH_LENGTH = 2
 stakeholders = []
 
-for i in range(3):
+for i in range(2):
     stakeholders.append(Stakeholder(EPOCH_LENGTH, 'passwd'+str(i)))
 
 stakeholders[0].set_leader()
@@ -16,4 +16,3 @@ environment.start()
 
 for sh in environment.stakeholders:
     sh.beacon.join()
-'''