mirror of
https://github.com/monero-project/research-lab.git
synced 2024-12-22 11:39:32 +00:00
udpate ffs again
This commit is contained in:
parent
cdaeb98d1d
commit
ba5049ddcc
2 changed files with 81 additions and 206 deletions
|
@ -16,18 +16,15 @@ class Block(object):
|
|||
and updates parents to include.
|
||||
_recomputeIdent : recomputes identity
|
||||
Usage:
|
||||
b0 = Block()
|
||||
b0.data = ...
|
||||
b1 = Block()
|
||||
b1.data = ...
|
||||
b1.addParents({b0.ident:b0})
|
||||
b0 = Block(dataIn = stuff, parentsIn = None)
|
||||
b1 = Block(dataIn = otherStuff, parentsIn = { b0.ident : b0 })
|
||||
|
||||
"""
|
||||
def __init__(self):
|
||||
def __init__(self, dataIn=None, parentsIn=None):
|
||||
# Initialize with empty payload, no identity, and empty parents.
|
||||
self.data = None
|
||||
self.data = dataIn
|
||||
self.ident = hash(str(0))
|
||||
self.parents = None
|
||||
self.parents = parentsIn
|
||||
self.addParents({})
|
||||
|
||||
def addParents(self, parentsIn): # dict of parents
|
||||
|
|
|
@ -13,7 +13,7 @@ from Block import *
|
|||
|
||||
class BlockHandler(object):
|
||||
def __init__(self):
|
||||
print("Initializing")
|
||||
#print("Initializing")
|
||||
# Initialize a BlockHandler object.
|
||||
self.data = None
|
||||
self.blocks = {} # Set of blocks (which track parents)
|
||||
|
@ -32,214 +32,92 @@ class BlockHandler(object):
|
|||
self._addBlock(blocksIn[b])
|
||||
|
||||
def _addBlock(self, b):
|
||||
print("Adding block")
|
||||
#print("Adding block")
|
||||
# Take a single block b and add to self.blocks, record family
|
||||
# relations, update leaf monitor, update root monitor if nec-
|
||||
# essary
|
||||
diffDict = {b.ident:b}
|
||||
self.blocks.update(diffDict)
|
||||
self.family.update({b.ident:{}})
|
||||
self.family[b.ident].update({"parents":b.parents, "children":{}})
|
||||
for parentIdent in b.parents:
|
||||
if parentIdent not in self.family:
|
||||
self.family.update({parentIdent:{}})
|
||||
if "parents" not in self.family[parentIdent]:
|
||||
self.family[parentIdent].update({"parents":{}})
|
||||
if "children" not in self.family[parentIdent]:
|
||||
self.family[parentIdent].update({"children":{}})
|
||||
self.family[parentIdent]["parents"].update(b.parents)
|
||||
self.family[parentIdent]["children"].update(diffDict)
|
||||
if parentIdent in self.leaves:
|
||||
del self.leaves[parentIdent]
|
||||
if len(b.parents)==0 and b.ident not in self.roots:
|
||||
self.roots.update(diffDict)
|
||||
self.leaves.update(diffDict)
|
||||
|
||||
def inPast(self, x, y):
|
||||
print("Testing if in past")
|
||||
# Return true if y is an ancestor of x
|
||||
q = deque()
|
||||
for pid in self.blocks[x].parents:
|
||||
if pid==y:
|
||||
return True
|
||||
break
|
||||
q.append(pid)
|
||||
while(len(q)>0):
|
||||
nxtIdent = q.popleft()
|
||||
if len(self.blocks[nxtIdent].parents) > 0:
|
||||
for pid in self.blocks[nxtIdent].parents:
|
||||
if pid==y:
|
||||
return True
|
||||
break
|
||||
q.append(pid)
|
||||
return False
|
||||
|
||||
|
||||
def vote(self):
|
||||
print("Voting")
|
||||
# Compute partial spectre vote for top several layers of
|
||||
# the dag.
|
||||
(U, vids) = self.leafBackAntichain()
|
||||
self.votes = {}
|
||||
|
||||
q = deque()
|
||||
self.pendingVotes = {}
|
||||
for i in range(len(U)):
|
||||
for leafId in U[i]:
|
||||
if i > 0:
|
||||
self.sumPendingVotes(leafId, vids)
|
||||
|
||||
for x in U[i]:
|
||||
if x != leafId:
|
||||
q.append(x)
|
||||
while(len(q)>0):
|
||||
x = q.popleft()
|
||||
if (leafId, leafId, x) not in self.votes:
|
||||
self.votes.update({(leafId, leafId, x):1})
|
||||
else:
|
||||
try:
|
||||
assert self.votes[(leafId, leafId, x)]==1
|
||||
except AssertionError:
|
||||
print("Woops, we found (leafId, leafId, x) as a key in self.votes while running vote(), and it should be +1, but it isn't:\n\n", (leafId, leafId, x), self.votes[(leafId, leafId, x)], "\n\n")
|
||||
if (leafId, x, leafId) not in self.votes:
|
||||
self.votes.update({(leafId, x, leafId):-1})
|
||||
else:
|
||||
try:
|
||||
assert self.votes[(leafId,x,leafId)]==-1
|
||||
except AssertionError:
|
||||
print("Woops, we found (leafId, x, leafId) as a key in self.votes while running vote(), and it should be +1, but it isn't:\n\n", (leafId, x, leafId), self.votes[(leafId, x, leafId)], "\n\n")
|
||||
self.transmitVote(leafId, leafId, x)
|
||||
for pid in self.blocks[x].parents:
|
||||
if not self.inPast(leafId, pid) and pid in vids and pid != leafId:
|
||||
q.append(pid)
|
||||
print(self.votes)
|
||||
|
||||
def sumPendingVotes(self, blockId, vulnIds):
|
||||
print("Summing pending votes")
|
||||
# For a blockId, take all pending votes for vulnerable IDs (x,y)
|
||||
# if the net is positive vote 1, if the net is negative vote -1
|
||||
# otherwise vote 0.
|
||||
for x in vulnIds:
|
||||
for y in vulnIds:
|
||||
if (blockId, x, y) in self.pendingVotes:
|
||||
if self.pendingVotes[(blockId, x, y)] > 0:
|
||||
if (blockId, x, y) not in self.votes:
|
||||
self.votes.update({(blockId, x, y):1})
|
||||
else:
|
||||
try:
|
||||
assert self.votes[(blockId,x,y)]==1
|
||||
except AssertionError:
|
||||
print("Woops, we found (blockId, x, y) as a key in self.votes, and it should be +1, but it isn't:\n\n", (blockId, x, y), self.votes[(blockId, x,y)], "\n\n")
|
||||
if (blockId, y, x) not in self.votes:
|
||||
self.votes.update({(blockId, y, x):-1})
|
||||
else:
|
||||
try:
|
||||
assert self.votes[(blockId,y,x)]==-1
|
||||
except AssertionError:
|
||||
print("Woops, we found (blockId, y, x) as a key in self.votes, and it should be -1, but it isn't:\n\n", (blockId, y, x), self.votes[(blockId, y,x)], "\n\n")
|
||||
self.transmitVote(blockId, x, y)
|
||||
elif self.pendingVotes[(blockId, x, y)] < 0:
|
||||
if (blockId, x, y) not in self.votes:
|
||||
self.votes.update({(blockId, x, y):-1})
|
||||
else:
|
||||
try:
|
||||
assert self.votes[(blockId,x,y)]==-1
|
||||
except AssertionError:
|
||||
print("Woops, we found (blockId, x, y) as a key in self.votes, and it should be -1, but it isn't:\n\n", (blockId, x, y), self.votes[(blockId, x,y)], "\n\n")
|
||||
|
||||
if (blockId, y, x) not in self.votes:
|
||||
self.votes.update({(blockId, y, x):1})
|
||||
else:
|
||||
try:
|
||||
assert self.votes[(blockId,y,x)]==1
|
||||
except AssertionError:
|
||||
print("Woops, we found (blockId, y, x) as a key in self.votes, and it should be +1, but it isn't:\n\n", (blockId, x, y), self.votes[(blockId, x,y)], "\n\n")
|
||||
self.transmitVote(blockId, y, x)
|
||||
else:
|
||||
if (blockId, x, y) not in self.votes:
|
||||
self.votes.update({(blockId, x, y):0})
|
||||
else:
|
||||
try:
|
||||
assert self.votes[(blockId,x,y)]==0
|
||||
except AssertionError:
|
||||
print("Woops, we found (blockId, x, y) as a key in self.votes, and it should be 0, but it isn't:\n\n", (blockId, x, y), self.votes[(blockId, x,y)], "\n\n")
|
||||
if (blockId, y, x) not in self.votes:
|
||||
self.votes.update({(blockId, y, x):0})
|
||||
else:
|
||||
try:
|
||||
assert self.votes[(blockId,y,x)]==0
|
||||
except AssertionError:
|
||||
print("Woops, we found (blockId, y, x) as a key in self.votes, and it should be 0, but it isn't:\n\n", (blockId, y, x), self.votes[(blockId, y,x)], "\n\n")
|
||||
|
||||
|
||||
|
||||
diffDict = {copy.deepcopy(b.ident):copy.deepcopy(b)}
|
||||
|
||||
try:
|
||||
assert b.ident not in self.blocks
|
||||
except AssertionError:
|
||||
print("Woops, tried to add a block with ident in self.blocks, overwriting old block")
|
||||
self.blocks.update(diffDict)
|
||||
|
||||
try:
|
||||
assert b.ident not in self.leaves
|
||||
except AssertionError:
|
||||
print("Woops, tried to add a block to leaf set that is already in the leafset, aborting.")
|
||||
self.leaves.update(diffDict) # New block is always a leaf
|
||||
|
||||
try:
|
||||
assert b.ident not in self.family
|
||||
except AssertionError:
|
||||
print("woops, tried to add a block that already has a recorded family history, aborting.")
|
||||
self.family.update({b.ident:{"parents":b.parents, "children":{}}}) # Add fam history fam
|
||||
|
||||
# Now update each parent's family history to reflect the new child
|
||||
if len(b.parents)>0:
|
||||
for parentIdent in b.parents:
|
||||
if parentIdent not in self.family:
|
||||
# This should never occur.
|
||||
print("Hey, what? confusedTravolta.gif... parentIdent not in self.family, parent not correct somehow.")
|
||||
self.family.update({parentIdent:{}})
|
||||
|
||||
if "parents" not in self.family[parentIdent]:
|
||||
# This should never occur.
|
||||
print("Hey, what? confusedTravolta.gif... family history of parent lacks sub-dict for parentage, parent not correct somehow")
|
||||
self.family[parentIdent].update({"parents":{}})
|
||||
|
||||
if "children" not in self.family[parentIdent]:
|
||||
# This should never occur.
|
||||
print("Hey, what? confusedTravolta.gif... family history of parent lacks sub-dict for children, parent not correct somehow")
|
||||
self.family[parentIdent].update({"children":{}})
|
||||
|
||||
# Make sure grandparents are stored correctly (does nothing if already stored correctly)
|
||||
self.family[parentIdent]["parents"].update(self.blocks[parentIdent].parents)
|
||||
|
||||
# Update "children" sub-dict of family history of parent
|
||||
self.family[parentIdent]["children"].update(diffDict)
|
||||
|
||||
# If the parent was previously a leaf, it is no longer
|
||||
if parentIdent in self.leaves:
|
||||
del self.leaves[parentIdent]
|
||||
|
||||
else:
|
||||
if b.ident not in self.roots:
|
||||
self.roots.update(diffDict)
|
||||
self.leaves.update(diffDict)
|
||||
self.family.update({b.ident:{"parents":{}, "children":{}}})
|
||||
|
||||
def transmitVote(self, v, x, y):
|
||||
print("Transmitting votes")
|
||||
q = deque()
|
||||
for pid in self.blocks[v].parents:
|
||||
q.append(pid)
|
||||
while(len(q)>0):
|
||||
print("Length of queue = ", len(q))
|
||||
nxtPid = q.popleft()
|
||||
if (nxtPid, x, y) not in self.pendingVotes:
|
||||
self.pendingVotes.update({(nxtPid,x,y):1})
|
||||
self.pendingVotes.update({(nxtPid,y,x):-1})
|
||||
else:
|
||||
self.pendingVotes[(nxtPid,x,y)] += 1
|
||||
self.pendingVotes[(nxtPid,y,x)] -= 1
|
||||
if len(self.blocks[nxtPid].parents) > 0:
|
||||
for pid in self.blocks[nxtPid].parents:
|
||||
if pid != nxtPid:
|
||||
q.append(pid)
|
||||
|
||||
|
||||
|
||||
|
||||
def leafBackAntichain(self):
|
||||
print("Computing antichain")
|
||||
temp = copy.deepcopy(self)
|
||||
decomposition = []
|
||||
vulnIdents = None
|
||||
decomposition.append(temp.leaves)
|
||||
vulnIdents = decomposition[-1]
|
||||
temp = temp.pruneLeaves()
|
||||
while(len(temp.blocks)>0 and len(decomposition) < self.antichainCutoff):
|
||||
decomposition.append(temp.leaves)
|
||||
for xid in decomposition[-1]:
|
||||
if xid not in vulnIdents:
|
||||
vulnIdents.update({xid:decomposition[-1][xid]})
|
||||
temp = temp.pruneLeaves()
|
||||
return decomposition, vulnIdents
|
||||
|
||||
def pruneLeaves(self):
|
||||
print("Pruning leaves")
|
||||
out = BlockHandler()
|
||||
q = deque()
|
||||
for rootIdent in self.roots:
|
||||
q.append(rootIdent)
|
||||
while(len(q)>0):
|
||||
thisIdent = q.popleft()
|
||||
if thisIdent not in self.leaves:
|
||||
out._addBlock(self.blocks[thisIdent])
|
||||
for chIdent in self.family[thisIdent]["children"]:
|
||||
q.append(chIdent)
|
||||
return out
|
||||
|
||||
class Test_RoBlock(unittest.TestCase):
|
||||
def test_BlockHandler(self):
|
||||
R = BlockHandler()
|
||||
b = Block()
|
||||
b.data = "zirconium encrusted tweezers"
|
||||
b._recomputeIdent()
|
||||
b = Block(dataIn="zirconium encrusted tweezers", parentsIn={})
|
||||
R._addBlock(b)
|
||||
|
||||
b = Block()
|
||||
b.data = "brontosaurus slippers cannot exist"
|
||||
b.addParents(R.leaves)
|
||||
diffDict = {copy.deepcopy(b.ident) : copy.deepcopy(b)}
|
||||
#print("Differential ", diffDict)
|
||||
b = Block(dataIn="brontosaurus slippers do not exist", parentsIn=copy.deepcopy(diffDict))
|
||||
R._addBlock(b)
|
||||
|
||||
R.vote()
|
||||
#print("Blocks ", R.blocks)
|
||||
#print("Family ", R.family)
|
||||
#print("Leaves ", R.leaves)
|
||||
self.assertEqual(len(R.blocks),2)
|
||||
self.assertEqual(len(R.family),2)
|
||||
self.assertEqual(len(R.leaves),1)
|
||||
#print("Differential ", diffDict)
|
||||
key, value = diffDict.popitem()
|
||||
#print("Differential ", diffDict)
|
||||
#print("Outputted values ", key, value)
|
||||
#print("b.ident should = leaf.ident", b.ident)
|
||||
self.assertTrue(key in R.blocks)
|
||||
self.assertTrue(b.ident in R.blocks)
|
||||
self.assertTrue(key in R.family[b.ident]["parents"])
|
||||
self.assertTrue(b.ident in R.family[key]["children"])
|
||||
|
||||
|
||||
|
||||
suite = unittest.TestLoader().loadTestsFromTestCase(Test_RoBlock)
|
||||
unittest.TextTestRunner(verbosity=1).run(suite)
|
||||
|
|
Loading…
Reference in a new issue