Further efficiency improvements
This commit is contained in:
parent
02ac09a8d0
commit
5bbca50547
108
casper/casper.py
108
casper/casper.py
|
@ -6,8 +6,8 @@ import math
|
|||
|
||||
NUM_VALIDATORS = 20
|
||||
BLKTIME = 40
|
||||
BY_CHAIN = False
|
||||
NETSPLITS = False
|
||||
NETSPLITS = 2
|
||||
CHECK_INTEGRITY = True
|
||||
|
||||
GENESIS_STATE = 0
|
||||
|
||||
|
@ -31,6 +31,9 @@ class Signature():
|
|||
# Finalized height
|
||||
self.sign_from = sign_from
|
||||
|
||||
def get_height(self):
|
||||
return self.sign_from + len(self.probs)
|
||||
|
||||
|
||||
class Block():
|
||||
def __init__(self, maker, height):
|
||||
|
@ -42,6 +45,13 @@ class Block():
|
|||
self.hash = random.randrange(10**20) + 10**21 + 10**23 * self.height
|
||||
|
||||
|
||||
class BlockRequest():
|
||||
def __init__(self, sender, height):
|
||||
self.sender = sender
|
||||
self.ask_height = height
|
||||
self.hash = random.randrange(10**14)
|
||||
|
||||
|
||||
def state_transition(state, block):
|
||||
return state if block is None else (state ** 3 + block.hash ** 5) % 10**40
|
||||
|
||||
|
@ -83,6 +93,9 @@ class Validator():
|
|||
def get_time(self):
|
||||
return self.network.time + self.time_offset
|
||||
|
||||
def broadcast(self, obj):
|
||||
self.network.broadcast(self, obj)
|
||||
|
||||
def sign(self, block):
|
||||
# Initialize the probability array, the core of the signature
|
||||
best_guesses = [None] * len(self.received_blocks)
|
||||
|
@ -99,7 +112,17 @@ class Validator():
|
|||
my_opinion = 0.5001
|
||||
votes = self.received_signatures[i].values() if i < len(self.received_signatures) else []
|
||||
votes += [my_opinion] * (NUM_VALIDATORS - len(votes))
|
||||
best_guesses[i] = min(vote(votes), 1 if self.received_blocks[i] is not None else my_opinion)
|
||||
vote_from_signatures = vote(votes)
|
||||
bg = min(vote_from_signatures, 1 if self.received_blocks[i] is not None else my_opinion)
|
||||
# In case we fall into an equilibrium trap at 0.5, eventually force divergence
|
||||
if self.get_time() - BLKTIME * i > BLKTIME * 40:
|
||||
fac = 1.0 / (1.0 + (self.get_time() - BLKTIME * i) / (BLKTIME * 40))
|
||||
if 0.14 < bg < 1 - 0.5 * fac:
|
||||
bg = 0.14 + (bg - 0.14) * fac
|
||||
best_guesses[i] = bg
|
||||
|
||||
if vote_from_signatures > 0.95 and self.received_blocks[i] is None:
|
||||
self.broadcast(BlockRequest(self.id, i))
|
||||
if best_guesses[i] > 0.9999:
|
||||
while len(self.finalized_hashes) <= i:
|
||||
self.finalized_hashes.append(None)
|
||||
|
@ -144,14 +167,11 @@ class Validator():
|
|||
for i, p in enumerate(obj.probs):
|
||||
self.received_signatures[i + obj.sign_from][obj.signer] = p
|
||||
self.network.broadcast(self, obj)
|
||||
# Received an object request, respond if we have it
|
||||
elif isinstance(obj, ObjRequest):
|
||||
if obj.ask_hash in self.received_objects:
|
||||
self.network.direct_send(obj.sender_id, ObjResponse(
|
||||
self.received_objects[obj.ask_hash]))
|
||||
# Received an object response, add to database
|
||||
elif isinstance(obj, ObjResponse):
|
||||
self.received_objects[obj.obj.hash] = obj.obj
|
||||
# Received a block request, respond if we have it
|
||||
elif isinstance(obj, BlockRequest):
|
||||
if obj.ask_height < len(self.received_blocks):
|
||||
if self.received_blocks[obj.ask_height] is not None:
|
||||
self.network.direct_send(obj.sender, self.received_blocks[obj.ask_height])
|
||||
self.received_objects[obj.hash] = obj
|
||||
self.time_received[obj.hash] = self.get_time()
|
||||
|
||||
|
@ -180,12 +200,15 @@ all_signatures = []
|
|||
now = [0]
|
||||
|
||||
|
||||
|
||||
def who_heard_of(h, n):
|
||||
o = ''
|
||||
for x in n.agents:
|
||||
o += '1' if h in x.received_objects else '0'
|
||||
return o
|
||||
o = ''
|
||||
for x in n.agents:
|
||||
o += '1' if h in x.received_objects else '0'
|
||||
return o
|
||||
|
||||
|
||||
ALPHA = '0123456789'
|
||||
|
||||
|
||||
def get_opinions(n):
|
||||
o = []
|
||||
|
@ -198,19 +221,22 @@ def get_opinions(n):
|
|||
for x in n.agents:
|
||||
if len(x.probs) <= h:
|
||||
p += '_'
|
||||
elif x.probs[h] < 0.5:
|
||||
p += str(int(5 - math.log(x.probs[h]) / math.log(0.0001) * 4) if x.probs[h] > 0.0001 else 0)
|
||||
elif x.probs[h] >= 0.5:
|
||||
p += str(int(5 + math.log(1 - x.probs[h]) / math.log(0.0001) * 4) if x.probs[h] < 0.9999 else 9)
|
||||
elif x.probs[h] < 0.0001:
|
||||
p += '-'
|
||||
elif x.probs[h] > 0.9999:
|
||||
p += '+'
|
||||
else:
|
||||
p += ALPHA[int(x.probs[h] * (len(ALPHA) - 0.0001))]
|
||||
q += 'n' if len(x.received_blocks) <= h or x.received_blocks[h] is None else 'y'
|
||||
o.append((h, p, q))
|
||||
return o
|
||||
|
||||
|
||||
def get_finalization_heights(n):
|
||||
o = []
|
||||
for x in n.agents:
|
||||
o.append(x.max_finalized_height)
|
||||
return o
|
||||
o = []
|
||||
for x in n.agents:
|
||||
o.append(x.max_finalized_height)
|
||||
return o
|
||||
|
||||
|
||||
# Check how often blocks that are assigned particular probabilities of
|
||||
|
@ -243,7 +269,7 @@ def run(steps=4000):
|
|||
n = networksim.NetworkSimulator()
|
||||
for i in range(NUM_VALIDATORS):
|
||||
n.agents.append(Validator(i, n))
|
||||
n.generate_peers()
|
||||
n.generate_peers(3)
|
||||
while len(all_signatures):
|
||||
all_signatures.pop()
|
||||
for x in future.keys():
|
||||
|
@ -255,29 +281,37 @@ def run(steps=4000):
|
|||
for i in range(steps):
|
||||
n.tick()
|
||||
if i % 500 == 0:
|
||||
print get_opinions(n)[-60:]
|
||||
minmax = 99999999999999999
|
||||
for x in n.agents:
|
||||
minmax = min(minmax, x.max_finalized_height - 10)
|
||||
print get_opinions(n)[max(minmax, 0):]
|
||||
finalized0 = [(v.max_finalized_height, v.finalized_hashes) for v in n.agents]
|
||||
finalized = sorted(finalized0, key=lambda x: len(x[1]))
|
||||
for j in range(len(n.agents) - 1):
|
||||
for k in range(len(finalized[j][1])):
|
||||
if finalized[j][1][k] is not None and finalized[j+1][1][k] is not None:
|
||||
if finalized[j][1][k] != finalized[j+1][1][k]:
|
||||
print finalized[j]
|
||||
print finalized[j+1]
|
||||
raise Exception("Finalization mismatch: %r %r" % (finalized[j][1][k], finalized[j+1][1][k]))
|
||||
if CHECK_INTEGRITY:
|
||||
finalized = sorted(finalized0, key=lambda x: len(x[1]))
|
||||
for j in range(len(n.agents) - 1):
|
||||
for k in range(len(finalized[j][1])):
|
||||
if finalized[j][1][k] is not None and finalized[j+1][1][k] is not None:
|
||||
if finalized[j][1][k] != finalized[j+1][1][k]:
|
||||
print finalized[j]
|
||||
print finalized[j+1]
|
||||
raise Exception("Finalization mismatch: %r %r" % (finalized[j][1][k], finalized[j+1][1][k]))
|
||||
print 'Finalized status: %r' % [x[0] for x in finalized0]
|
||||
if i == 10000 and NETSPLITS:
|
||||
_all = finalized0[0][1]
|
||||
_pos = len([x for x in _all if x])
|
||||
_neg = len([x for x in _all if not x])
|
||||
print 'Finalized blocks: %r (%r positive, %r negaitve)' % (len(_all), _pos, _neg)
|
||||
if i == 10000 and NETSPLITS >= 1:
|
||||
print "###########################################################"
|
||||
print "Knocking off 20% of the network!!!!!"
|
||||
print "###########################################################"
|
||||
n.knock_offline_random(NUM_VALIDATORS // 5)
|
||||
if i == 20000 and NETSPLITS:
|
||||
if i == 20000 and NETSPLITS >= 2:
|
||||
print "###########################################################"
|
||||
print "Simluating a netsplit!!!!!"
|
||||
print "###########################################################"
|
||||
n.generate_peers()
|
||||
n.partition()
|
||||
if i == 30000 and NETSPLITS:
|
||||
if i == 30000 and NETSPLITS >= 1:
|
||||
print "###########################################################"
|
||||
print "Network health back to normal!"
|
||||
print "###########################################################"
|
||||
|
|
Loading…
Reference in New Issue