mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-01-09 14:48:08 -05:00
[research/dpos] reverted from pvss to vrf
This commit is contained in:
@@ -6,11 +6,9 @@ from ouroboros.logger import Logger
|
||||
'''
|
||||
\class TrustedBeacon
|
||||
|
||||
the trusted beacon is decentralized, such that at the onset of the Epoch,
|
||||
the leader of the first slot generated the signed seed, and release the signature,
|
||||
proof, and base to the ge nesis block.
|
||||
|
||||
#TODO implement trustedbeacon as a node
|
||||
leaky, non-resettable beacon, leaky in the sense that the slots are
|
||||
predictable, and non-resettable, beacon is basically a synchronized
|
||||
timestamp.
|
||||
'''
|
||||
class TrustedBeacon(SynchedNTPClock, threading.Thread):
|
||||
|
||||
@@ -42,7 +40,3 @@ class TrustedBeacon(SynchedNTPClock, threading.Thread):
|
||||
y, pi = vrf.sign(slot_idx)
|
||||
rands[slot_idx] = (y,pi)
|
||||
return rands
|
||||
'''
|
||||
def verify(self, y, pi, pk_raw, g):
|
||||
return VRF.verify(self.current_slot, y, pi, pk_raw, g)
|
||||
'''
|
||||
@@ -25,17 +25,27 @@ class Block(object):
|
||||
self.state=state_hash(previous_block)
|
||||
self.tx = data
|
||||
self.sl = slot_uid
|
||||
self.signature = None # block issuer signature
|
||||
self.sigma = None # proof that the block is valid.
|
||||
self.is_genesis=genesis
|
||||
self.endorsed=False
|
||||
self.log = Logger(genesis_time)
|
||||
self.leader_id=None
|
||||
self.endorser_id=None
|
||||
|
||||
@property
|
||||
def slot(self):
|
||||
return self.sl
|
||||
|
||||
def __repr__(self):
|
||||
if self.is_genesis:
|
||||
return "GensisBlock at {slot:"+str(self.sl)+",data:"+str(self.tx)+",state:"+str(self.state)+"}\n"+str(self.tx)
|
||||
return "Block at {slot:"+str(self.sl)+",data:"+str(self.tx)+",state:"+str(self.state)+"}"
|
||||
return "GensisBlock " + str(self.__to_dict)
|
||||
return "Block " + str(self.__to_dict)
|
||||
|
||||
@property
|
||||
def __to_dict(self):
|
||||
return {SLOT: self.st, STATE: self.state, DATA: self.tx, PROOF: self.sigma, SIGN: self.signature}
|
||||
|
||||
def __hash__(self):
|
||||
if type(self.tx)==str:
|
||||
return hash((self.state, self.tx, self.sl))
|
||||
@@ -50,9 +60,7 @@ class Block(object):
|
||||
self.sl == block.sl
|
||||
|
||||
def to_json(self):
|
||||
d = {'state':self.state, \
|
||||
'data': self.tx, \
|
||||
'sl': self.sl}
|
||||
d = self.__to_dict
|
||||
return json.encoder(d)
|
||||
|
||||
def set_endorsed(self):
|
||||
@@ -65,6 +73,12 @@ class Block(object):
|
||||
def set_leader(self, id):
|
||||
self.leader_id=id
|
||||
|
||||
def set_sigma(self, sigma):
|
||||
self.sigma = sigma
|
||||
|
||||
def set_signature(self, sign):
|
||||
self.signature = sign
|
||||
|
||||
@property
|
||||
def data(self):
|
||||
return self.tx
|
||||
@@ -78,7 +92,7 @@ class Block(object):
|
||||
return (self.tx=='' or self.slot<0) and self.state==''
|
||||
|
||||
def encode(self):
|
||||
return str(self).encode()
|
||||
return str(self.__to_dict).encode()
|
||||
|
||||
class GensisBlock(Block):
|
||||
'''
|
||||
|
||||
@@ -8,7 +8,7 @@ import math
|
||||
|
||||
class SynchedNTPClock(object):
|
||||
|
||||
def __init__(self, epoch_length, slot_length=180, ntp_server='europe.pool.ntp.org'):
|
||||
def __init__(self, epoch_length, slot_length=60, 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
|
||||
|
||||
@@ -1,4 +1,16 @@
|
||||
STAKEHOLDERS_DISTRIBUTIONS='distributions'
|
||||
STAKEHOLDERS='stakeholders'
|
||||
SEED='seed'
|
||||
TX='tx'
|
||||
TX='tx'
|
||||
|
||||
# block keys
|
||||
'''
|
||||
the block in praos is consistent of the following
|
||||
(sl, st,d, B_pi, sigma)
|
||||
'''
|
||||
SLOT = "SLOT" # sl
|
||||
STATE = "STATE" #st
|
||||
DATA = "DATA" #d
|
||||
PROOF = "PROOF" #B_pi
|
||||
SIGN = "SIGNATURE" #sigma
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ from ouroboros.stakeholder import Stakeholder
|
||||
environment is ought to interfece with the network
|
||||
'''
|
||||
class Z(object):
|
||||
def __init__(self, stakeholdes, epoch_length, genesis_time=time.time()):
|
||||
def __init__(self, stakeholdes, epoch_length, genesis_time=time.time(), f=0.1):
|
||||
self.genesis_time=genesis_time
|
||||
self.beacon = TrustedBeacon(epoch_length, genesis_time)
|
||||
self.log = Logger(self, genesis_time)
|
||||
@@ -41,8 +41,19 @@ class Z(object):
|
||||
self.prev_leader_id=-1
|
||||
#
|
||||
self.current_block=None
|
||||
self.f = f
|
||||
self.init()
|
||||
|
||||
'''
|
||||
active slot coefficient determine the relation between,
|
||||
probability of leader being selected, and the relative stake,
|
||||
it's defined as the probability that a party holding all the stake
|
||||
will be selected to be a leader for given slot.
|
||||
'''
|
||||
@property
|
||||
def slot_coef(self):
|
||||
return self.f
|
||||
|
||||
|
||||
def init(self):
|
||||
for sh in self.stakeholders:
|
||||
@@ -51,9 +62,10 @@ class Z(object):
|
||||
#pick initial leader to be the first stakeholder
|
||||
initial_leader = self.stakeholders[0]
|
||||
#pick initial endorser to be the first endorser
|
||||
initial_endorser = self.stakeholders[1]
|
||||
#initial_endorser = self.stakeholders[1]
|
||||
self.current_epoch = self.beacon.epoch
|
||||
self.rands = self.beacon.next_epoch_seeds(initial_leader.vrf)
|
||||
self.log.info(f"rands length: {len(self.rands)}")
|
||||
self.current_slot = self.beacon.slot
|
||||
self.select_epoch_leaders()
|
||||
self.prev_leader_id=0
|
||||
@@ -116,9 +128,15 @@ class Z(object):
|
||||
|
||||
|
||||
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}"
|
||||
for sh in self.stakeholders:
|
||||
buff+=str(sh)+"\n"
|
||||
buff = ''
|
||||
if len (self.slot_committee)>0:
|
||||
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}"
|
||||
for sh in self.stakeholders:
|
||||
buff+=str(sh)+"\n"
|
||||
else:
|
||||
buff = f"envirnment of {self.length} stakholders\tepoch_slot: {self.epoch_slot}"
|
||||
return buff
|
||||
|
||||
'''
|
||||
@@ -163,7 +181,7 @@ class Z(object):
|
||||
|
||||
@property
|
||||
def current_leader_id(self):
|
||||
return self.slot_committee[self.current_slot][0]
|
||||
return self.slot_committee[self.epoch_slot][0]
|
||||
|
||||
@property
|
||||
def current_stakeholder(self):
|
||||
@@ -172,7 +190,7 @@ class Z(object):
|
||||
|
||||
@property
|
||||
def current_endorser_id(self):
|
||||
return self.slot_committee[self.current_slot][1]
|
||||
return self.slot_committee[self.epoch_slot][1]
|
||||
|
||||
@property
|
||||
def current_endorser_uid(self):
|
||||
@@ -197,7 +215,7 @@ class Z(object):
|
||||
return self.endorser(slot).vrf_pk
|
||||
|
||||
def is_current_endorser(self, id):
|
||||
_, edr_idx = self.slot_committee[self.beacon.slot]
|
||||
_, edr_idx = self.slot_committee[self.epoch_slot]
|
||||
return id == self.stakeholders[edr_idx].id
|
||||
|
||||
@property
|
||||
@@ -209,7 +227,7 @@ class Z(object):
|
||||
return self.stakeholders[self.current_leader_id].vrf_base
|
||||
|
||||
def is_current_leader(self, id):
|
||||
ldr_idx, _ = self.slot_committee[self.beacon.current_slot]
|
||||
ldr_idx, _ = self.slot_committee[self.epoch_slot]
|
||||
return id == self.stakeholders[ldr_idx].id
|
||||
|
||||
|
||||
@@ -230,8 +248,6 @@ class Z(object):
|
||||
def current_leader_sig_pk(self):
|
||||
return self.stakeholders[self.current_leader_id].sig_pk
|
||||
|
||||
|
||||
|
||||
#note! assumes epoch_slot lays in the current epoch
|
||||
def leader(self, slot):
|
||||
return self.stakeholders[self.slot_committee[slot][0]]
|
||||
@@ -301,11 +317,14 @@ class Z(object):
|
||||
return self.beacon.epoch
|
||||
|
||||
def select_epoch_leaders(self):
|
||||
self.log.info("[Z/select_epoch_leaders]")
|
||||
#assert len(self.sigmas)==self.epoch_length and len(self.proofs)==self.epoch_length, \
|
||||
#self.log.error(f"size mismatch between sigmas: {len(self.sigmas)}, proofs: {len(self.proofs)}, and epoch_length: {self.epoch_length}")
|
||||
for i in range(self.epoch_length):
|
||||
#self.log.info(f"current sigma of index {i} , epoch_length: {self.epoch_length}")
|
||||
self.log.info(f"current sigma of index {i} , epoch_length: {self.epoch_length}, rand : {self.rands}")
|
||||
slot_idx = self.current_slot + i
|
||||
assert len(self.rands)>0
|
||||
slot_idx_relative = slot_idx%self.epoch_length
|
||||
sigma, _ = self.rands[slot_idx]
|
||||
assert sigma!=None, 'proof cant be None'
|
||||
def leader_selection_hash(sigma):
|
||||
@@ -324,11 +343,11 @@ 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.slot_committee[slot_idx_relative] = (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):
|
||||
def broadcast_block(self, cur_block):
|
||||
while self.current_blk_endorser_sig is None:
|
||||
self.log.info('pending endorsing...')
|
||||
time.sleep(1)
|
||||
@@ -337,11 +356,10 @@ class Z(object):
|
||||
self.current_block = cur_block
|
||||
for stakeholder in self.stakeholders:
|
||||
if not stakeholder.is_leader:
|
||||
stakeholder.receive_block(signed_block, self.current_blk_endorser_sig, slot_uid)
|
||||
stakeholder.receive_block(cur_block, self.current_blk_endorser_sig)
|
||||
#stakeholder.receive_block(cur_block.signature, self.current_blk_endorser_sig, cur_block.slot)
|
||||
self.print_blockchain()
|
||||
|
||||
|
||||
|
||||
@property
|
||||
def block_id(self):
|
||||
return self.current_slot%self.epoch_length
|
||||
|
||||
0
script/research/dpos/ouroboros/protocol.tex
Normal file
0
script/research/dpos/ouroboros/protocol.tex
Normal file
@@ -1,5 +1,6 @@
|
||||
from copy import deepcopy
|
||||
import time
|
||||
import numpy as np
|
||||
from ouroboros.block import Block, GensisBlock, EmptyBlock
|
||||
from ouroboros.blockchain import Blockchain
|
||||
from ouroboros.epoch import Epoch
|
||||
@@ -9,6 +10,7 @@ from ouroboros.logger import Logger
|
||||
from ouroboros.consts import *
|
||||
from ouroboros.data import Data, Transaction, Item
|
||||
|
||||
|
||||
'''
|
||||
\class Stakeholder
|
||||
'''
|
||||
@@ -53,7 +55,21 @@ class Stakeholder(object):
|
||||
@property
|
||||
def vrf_base(self):
|
||||
return self.__vrf_base
|
||||
|
||||
@property
|
||||
def probability_leader_election(self):
|
||||
return 1 - np.pow(1 - self.env.slot_coef, self.stake)
|
||||
|
||||
'''
|
||||
true random oracle from the blockchain
|
||||
it's simulate by a hash function that is modeled as a random oracle. This hash function
|
||||
is applied to the concatenation of VRF values that are inserted into each block, using values from
|
||||
all blocks up to and including the middle ~ 8k slots of an epoch that lasts approximately 24k slots
|
||||
in entirety
|
||||
'''
|
||||
def random_oracle(self):
|
||||
pass
|
||||
|
||||
def __repr__(self):
|
||||
buff=''
|
||||
if self.env.is_current_leader(self.id):
|
||||
@@ -154,7 +170,8 @@ class Stakeholder(object):
|
||||
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)
|
||||
self.current_block.set_signature(signed_block)
|
||||
self.env.broadcast_block(self.current_block)
|
||||
|
||||
@property
|
||||
def current_slot(self):
|
||||
@@ -198,14 +215,14 @@ class Stakeholder(object):
|
||||
time.sleep(1)
|
||||
return cur_blk, stashed
|
||||
|
||||
def receive_block(self, signed_block, endorser_sig, blk_uid):
|
||||
def receive_block(self, blk, endorser_sig):
|
||||
self.log.highlight("receiving block")
|
||||
cur_blk, stashed = self.__get_blk(blk_uid)
|
||||
cur_blk, stashed = self.__get_blk(blk.slot)
|
||||
#TODO to consider deley should retrive leader_pk of corresponding blk_uid
|
||||
self.log.highlight(f'receiving block {str(cur_blk)}')
|
||||
self.log.highlight(f'receiving block has slot_uid: {self.current_slot_uid}')
|
||||
self.log.highlight(f'receiving block has sig_pk: {self.env.current_endorser_sig_pk}')
|
||||
blk_verified = verify_signature(self.env.current_leader_sig_pk, cur_blk, signed_block)
|
||||
blk_verified = verify_signature(self.env.current_leader_sig_pk, cur_blk, blk.signature)
|
||||
self.log.info("endorser sig_pk {self.env.current_endorser_sig_pk}, cur_blk: {cur_blk}, endorser_sig: {endorser_sig}")
|
||||
blk_edrs_verified = verify_signature(self.env.current_endorser_sig_pk, cur_blk, endorser_sig)
|
||||
if blk_verified and blk_edrs_verified:
|
||||
|
||||
0
script/research/dpos/protocol.tex
Normal file
0
script/research/dpos/protocol.tex
Normal file
1
script/research/streamlet_rust/.gitignore
vendored
Normal file
1
script/research/streamlet_rust/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
target/*
|
||||
1695
script/research/streamlet_rust/Cargo.lock
generated
Normal file
1695
script/research/streamlet_rust/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user