From 4545cf2a1c90a7dd9784c8f418688c30fdeac0a9 Mon Sep 17 00:00:00 2001 From: mohab Date: Fri, 11 Feb 2022 13:42:31 +0200 Subject: [PATCH] [research/ouroboros] finished basic simulation --- script/research/dpos/ouroboros/beacon.py | 12 ++++++------ script/research/dpos/ouroboros/blockchain.py | 5 +++-- script/research/dpos/ouroboros/environment.py | 16 +++++++++------- script/research/dpos/ouroboros/logger.py | 19 +++++++++++++++---- script/research/dpos/ouroboros/stakeholder.py | 16 ++++++++++------ script/research/dpos/ouroboros/vrf.py | 3 +-- script/research/dpos/simulation.py | 4 ++-- 7 files changed, 46 insertions(+), 29 deletions(-) diff --git a/script/research/dpos/ouroboros/beacon.py b/script/research/dpos/ouroboros/beacon.py index 82f40c65e..28ac8335e 100644 --- a/script/research/dpos/ouroboros/beacon.py +++ b/script/research/dpos/ouroboros/beacon.py @@ -14,7 +14,7 @@ proof, and base to the genesis block. #TODO implement trustedbeacon as a node ''' class TrustedBeacon(SynchedNTPClock, threading.Thread): - def __init__(self, node, vrf_sk, epoch_length): + def __init__(self, node, vrf_sk, epoch_length, genesis_time): self.epoch_length=epoch_length # how many slots in a a block SynchedNTPClock.__init__(self) threading.Thread.__init__(self) @@ -22,11 +22,11 @@ class TrustedBeacon(SynchedNTPClock, threading.Thread): self.node = node #stakeholder self.vrf = VRF(self.node.vrf_pk, vrf_sk, self.node.vrf_base) self.current_slot = self.slot - self.log = Logger(self) - self.log.info("[TrustedBeacon]") + self.log = Logger(self, genesis_time) + self.log.info(f"[TrustedBeacon] constructed for node {str(node)}") def __repr__(self): - return f"trustedbeadon\n" + return f"trustedbeacon" def run(self): self.log.info("[TrustedBeacon] thread [start]") @@ -44,9 +44,10 @@ class TrustedBeacon(SynchedNTPClock, threading.Thread): self.current_slot = self.slot sigmas = [] proofs = [] - self.log.info(f"[TrustedBeacon] new slot of idx: {self.current_slot}") for i in range(self.epoch_length): + self.log.info(f"[TrustedBeacon] callback: new slot of idx: {self.current_slot}, epoch slot {i}") y, pi = self.vrf.sign(self.current_slot) + self.log.info(f"[TrustedBeacon] callback: signature calculated for {str(self.node)}") sigmas.append(y) proofs.append(pi) if self.current_slot%self.epoch_length==0: @@ -58,4 +59,3 @@ class TrustedBeacon(SynchedNTPClock, threading.Thread): def verify(self, y, pi, pk_raw, g): return VRF.verify(self.current_slot, y, pi, pk_raw, g) - \ No newline at end of file diff --git a/script/research/dpos/ouroboros/blockchain.py b/script/research/dpos/ouroboros/blockchain.py index c6bb256ee..0323cf0de 100644 --- a/script/research/dpos/ouroboros/blockchain.py +++ b/script/research/dpos/ouroboros/blockchain.py @@ -1,12 +1,13 @@ from ouroboros.logger import Logger +import time ''' Non-forkable Blockchain for simplicity #TODO consider forkable property ''' class Blockchain(object): - def __init__(self, R): + def __init__(self, R, genesis_time): self.blocks = [] - self.log = Logger(self) + self.log = Logger(self, genesis_time) self.R = R # how many slots in single epoch @property diff --git a/script/research/dpos/ouroboros/environment.py b/script/research/dpos/ouroboros/environment.py index 6dfc564bd..ad8f1520f 100644 --- a/script/research/dpos/ouroboros/environment.py +++ b/script/research/dpos/ouroboros/environment.py @@ -2,12 +2,14 @@ import numpy as np import math import random from ouroboros.logger import Logger +import time ''' \class Z is the environment ''' class Z(object): - def __init__(self, stakeholdes, epoch_length): - self.log = Logger(self) + def __init__(self, stakeholdes, epoch_length, genesis_time=time.time()): + self.genesis_time=genesis_time + self.log = Logger(self, genesis_time) self.epoch_length=epoch_length self.stakeholders = np.array(stakeholdes) self.adversary_mask=np.array([True]*len(stakeholdes)) @@ -72,12 +74,12 @@ class Z(object): return len(self.stakeholders[self.adversary_mask]) def select_epoch_leaders(self, sigmas, proofs): - assert(len(sigmas)==self.epoch_length and len(proofs)==self.epoch_length, \ - f"size mismatch between sigmas: {len(sigmas)}, proofs: {len(proofs)}, and epoch_length: {self.epoch_length}") + if len(sigmas)==self.epoch_length or 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): self.log.info(f"current sigma of index {i} of total {len(sigmas)}, epoch_length: {self.epoch_length}") sigma = sigmas[i] - assert (sigma!=None, 'proof cant be None') + assert sigma!=None, 'proof cant be None' def leader_selection_hash(sigma): Y = np.array(sigma) y_hypotenuse2 = math.ceil(np.sum(Y[1]**2+Y[2]**2)) @@ -97,7 +99,7 @@ class Z(object): self.current_slot=slot self.log.info(f"stakeholders: {self.stakeholders}") current_leader = self.stakeholders[self.current_leader_id] - assert(current_leader!=None, "current leader cant be None") + assert current_leader!=None, "current leader cant be None" if current_leader.is_leader: #pass leadership to the current slot leader from the epoch leader self.stakeholders[self.current_epoch_leaders[slot%self.epoch_length]].set_leader() @@ -106,7 +108,7 @@ class Z(object): self.current_slot=slot #self.log.info(f"stakeholders: {self.stakeholders}") #current_leader = self.stakeholders[self.current_leader_id] - #assert(current_leader!=None, 'current leader cant be none') + #assert current_leader!=None, 'current leader cant be none' #assert(current_leader.is_leader) self.select_epoch_leaders(sigmas, proofs) diff --git a/script/research/dpos/ouroboros/logger.py b/script/research/dpos/ouroboros/logger.py index f937b295d..1e5b30cb3 100644 --- a/script/research/dpos/ouroboros/logger.py +++ b/script/research/dpos/ouroboros/logger.py @@ -1,13 +1,24 @@ +import time +import os +os.system("color") + class Logger(object): - def __init__(self, obj): + def __init__(self, obj, genesis_time=time.time()): self.obj = obj + self.genesis=genesis_time + + @property + def diff(self): + cur = time.time() + d = cur - self.genesis + return round(d,1) def info(self, payload): - print(f"\t[{self.obj}]:\n{payload}\n") + print("\033[32m", f"[{self.diff}] - [{self.obj}]:\n\t{payload}\n", "\033[0m") def warn(self, payload): - print(f"\t[{self.obj}]:\n{payload}\n") + print("\033[33m", f"[{self.diff}] - [{self.obj}]:\n\t{payload}\n", "\033[0m") def error(self, payload): - print(f"\t[{self.obj}]:\n{payload}\n") + print("\033[31m", f"[{self.diff}] - [{self.obj}]:\n\t{payload}\n", "\033[0m") exit() diff --git a/script/research/dpos/ouroboros/stakeholder.py b/script/research/dpos/ouroboros/stakeholder.py index 4b09e6950..0d6487daa 100644 --- a/script/research/dpos/ouroboros/stakeholder.py +++ b/script/research/dpos/ouroboros/stakeholder.py @@ -6,7 +6,7 @@ from ouroboros.beacon import TrustedBeacon from ouroboros.vrf import generate_vrf_keys, VRF from ouroboros.utils import * from ouroboros.logger import Logger - +import time ''' \class Stakeholder ''' @@ -17,24 +17,23 @@ class Stakeholder(object): self.stake=0 self.epoch_length=epoch_length pk, sk, g = generate_vrf_keys(self.passwd) + #verification keys self.__vrf_pk = pk self.__vrf_sk = sk self.__vrf_base = g - - self.blockchain = Blockchain(self.epoch_length) - self.beacon = TrustedBeacon(self, self.epoch_length, self.__vrf_sk) + #signature keys sig_sk, sig_pk = generate_sig_keys(self.passwd) self.sig_sk = sig_sk self.sig_pk = sig_pk + # self.current_block = None self.uncommited_tx='' self.tx='' - self.current_slot_uid = self.beacon.slot self.current_epoch = None self.am_current_leader=False self.am_current_endorder=False self.am_corrupt=False - self.log = Logger(self) + # @property def is_leader(self): @@ -55,6 +54,11 @@ class Stakeholder(object): def __call__(self, env): self.env=env + self.log = Logger(self, self.env.genesis_time) + self.blockchain = Blockchain(self.epoch_length, self.env.genesis_time) + self.beacon = TrustedBeacon(self, self.__vrf_sk, self.epoch_length, self.env.genesis_time) + self.current_slot_uid = self.beacon.slot + def start(self): self.log.info("Stakeholder.start [started]") diff --git a/script/research/dpos/ouroboros/vrf.py b/script/research/dpos/ouroboros/vrf.py index 62b6f6eda..51da75547 100644 --- a/script/research/dpos/ouroboros/vrf.py +++ b/script/research/dpos/ouroboros/vrf.py @@ -14,8 +14,7 @@ def generate_vrf_keys(sk_seed): generate pk/sk return: list of pk (public key), sk(secret key), base(field base) ''' - #sk = vrf_hash(sk_seed) - sk=2 + sk = vrf_hash(sk_seed) base = ecc.gen() pk = ecc.scalar_mult(sk, base) return (pk, sk, base) diff --git a/script/research/dpos/simulation.py b/script/research/dpos/simulation.py index 056e07280..6f50169b1 100644 --- a/script/research/dpos/simulation.py +++ b/script/research/dpos/simulation.py @@ -1,13 +1,13 @@ from ouroboros import Stakeholder from ouroboros import Z -import random +import time EPOCH_LENGTH = 3 stakeholders = [] for i in range(3): stakeholders.append(Stakeholder(EPOCH_LENGTH)) -environment = Z(stakeholders, EPOCH_LENGTH) +environment = Z(stakeholders, EPOCH_LENGTH, genesis_time=time.time()) environment.start()