diff --git a/source-code/Spectre/Block.py b/source-code/Spectre/Block.py index 399fad7..f92b81e 100644 --- a/source-code/Spectre/Block.py +++ b/source-code/Spectre/Block.py @@ -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 diff --git a/source-code/Spectre/BlockHandler.py b/source-code/Spectre/BlockHandler.py index 80bdf1f..c72dd23 100644 --- a/source-code/Spectre/BlockHandler.py +++ b/source-code/Spectre/BlockHandler.py @@ -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)