voteFor, pendingVotes, transmitVote working

This commit is contained in:
Brandon Goodell 2017-12-13 10:46:00 -07:00
parent ba5049ddcc
commit 1445943246
2 changed files with 410 additions and 61 deletions

View file

@ -20,18 +20,19 @@ class Block(object):
b1 = Block(dataIn = otherStuff, parentsIn = { b0.ident : b0 })
"""
def __init__(self, dataIn=None, parentsIn=None):
def __init__(self, dataIn=None, parentsIn=[]):
# Initialize with empty payload, no identity, and empty parents.
self.data = dataIn
self.ident = hash(str(0))
assert type(parentsIn)==type([])
self.parents = parentsIn
self.addParents({})
self._recomputeIdent()
def addParents(self, parentsIn): # dict of parents
def addParents(self, parentsIn=[]): # list of parentIdents
if self.parents is None:
self.parents = parentsIn
else:
self.parents.update(parentsIn)
self.parents = self.parents + parentsIn
self._recomputeIdent()
def _recomputeIdent(self):

View file

@ -10,6 +10,7 @@
ing transactions from a reduced/robust BlockHandler object.
'''
from Block import *
import random
class BlockHandler(object):
def __init__(self):
@ -19,17 +20,52 @@ class BlockHandler(object):
self.blocks = {} # Set of blocks (which track parents)
self.family = {} # Doubly linked list tracks parent-and-child links
self.invDLL = {} # subset of blocks unlikely to be re-orged
self.roots = {} # dict {blockIdent : block} root blocks
self.leaves = {}
self.roots = [] # list of root blockIdents
self.leaves = [] # list of leaf blockIdents
self.antichains = []
self.vids = []
self.antichainCutoff = 600 # stop re-orging after this many layers
self.pendingVotes = {}
self.votes = {}
def _addBlocks(self, blocksIn):
print("Adding Blocks")
# Take dict of {blockIdent : block} and call _addBlock on each.
for b in blocksIn:
self._addBlock(blocksIn[b])
self.oldVotes = {}
def sumPendingVote(self, vid, touched):
for (xid,yid) in zip(self.vids,self.vids):
if (vid, xid, yid) in self.pendingVotes:
if self.pendingVotes[(vid,xid,yid)] > 0:
touched = self.voteFor((vid,xid,yid), touched)
elif self.pendingVotes[(vid,xid,yid)] <0:
touched = self.voteFor((vid,yid,xid), touched)
else:
self.votes.update({(vid,xid,yid): 0, (vid,yid,xid): 0})
touched.update({(vid,xid,yid): True, (vid,yid,xid): True})
return touched
def voteFor(self, votingIdents, touched):
(vid, xid, yid) = votingIdents
self.votes.update({(vid,xid,yid):1, (vid,yid,xid):-1})
touched.update({(vid,xid,yid):True, (vid,yid,xid):True})
self.transmitVote((vid,xid,yid))
return touched
def transmitVote(self, votingIdents):
(vid, xid, yid) = votingIdents
q = deque()
for wid in self.blocks[vid].parents:
if wid in self.vids:
q.append(wid)
while(len(q)>0):
wid = q.popleft()
if (wid,xid,yid) not in self.pendingVotes:
self.pendingVotes.update({(wid,xid,yid):0})
if (wid,yid,xid) not in self.pendingVotes:
self.pendingVotes.update({(wid,yid,xid):0})
self.pendingVotes[(wid,xid,yid)]+=1
self.pendingVotes[(wid,yid,xid)]-=1
#print(self.blocks[wid].parents)
for pid in self.blocks[wid].parents:
if pid in self.vids:
q.append(pid)
def _addBlock(self, b):
#print("Adding block")
@ -49,73 +85,385 @@ class BlockHandler(object):
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
self.leaves.append(b.ident) # 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
self.family.update({b.ident:{"parents":b.parents, "children":[]}})
# Add fam history fam (new blocks have no children yet)
# 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 b.parents is not None:
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 "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":{}})
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 self.blocks[parentIdent].parents is not None:
for pid in self.blocks[parentIdent].parents:
if pid not in self.family[parentIdent]["parents"]:
self.family[parentIdent]["parents"].append(pid)
#for p in self.blocks[parentIdent].parents: self.family[parentIdent]["parents"].append(p)
# Update "children" sub-dict of family history of parent
self.family[parentIdent]["children"].append(b.ident)
# If the parent was previously a leaf, it is no longer
if parentIdent in self.leaves:
del self.leaves[parentIdent]
# If the parent was previously a leaf, it is no longer
if parentIdent in self.leaves:
self.leaves.remove(parentIdent)
else:
if b.ident not in self.roots:
self.roots.append(b.ident)
if b.ident not in self.leaves:
self.leaves.append(b.ident)
if b.ident not in self.family:
self.family.update({b.ident:{"parents":{}, "children":{}}})
else:
if b.ident not in self.roots:
self.roots.update(diffDict)
self.leaves.update(diffDict)
self.roots.append(b.ident)
if b.ident not in self.leaves:
self.leaves.append(b.ident)
if b.ident not in self.family:
self.family.update({b.ident:{"parents":{}, "children":{}}})
def _hasAncestor(self, xid, yid):
# Return true if y is an ancestor of x
assert xid in self.blocks
assert yid in self.blocks
q = deque()
found = False
if self.blocks[xid].parents is not None:
for pid in self.blocks[xid].parents:
if pid==yid:
found = True
break
q.append(pid)
while(len(q)>0 and not found):
xid = q.popleft()
if self.blocks[xid].parents is not None:
if len(self.blocks[xid].parents) > 0:
for pid in self.blocks[xid].parents:
if pid==yid:
found = True
q.append(pid)
return found
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
def leafBackAntichain(self):
#print("Computing antichain")
temp = copy.deepcopy(self)
decomposition = []
vulnIdents = []
decomposition.append([])
for lid in temp.leaves:
decomposition[-1].append(lid)
vulnIdents = copy.deepcopy(decomposition[-1])
temp = temp.pruneLeaves()
while(len(temp.blocks)>0 and len(decomposition) < self.antichainCutoff):
decomposition.append([])
for lid in temp.leaves:
decomposition[-1].append(lid)
for xid in decomposition[-1]:
if xid not in vulnIdents:
vulnIdents.append(xid)
temp = temp.pruneLeaves()
return decomposition, vulnIdents
class Test_RoBlock(unittest.TestCase):
def test_BlockHandler(self):
def test_betterTest(self):
R = BlockHandler()
b = Block(dataIn="zirconium encrusted tweezers", parentsIn={})
R._addBlock(b)
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)
#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"])
self.assertTrue(R.data is None)
self.assertEqual(len(R.blocks),0)
self.assertEqual(type(R.blocks),type({}))
self.assertEqual(len(R.family),0)
self.assertEqual(type(R.family),type({}))
self.assertEqual(len(R.invDLL),0)
self.assertEqual(type(R.invDLL),type({}))
self.assertEqual(len(R.roots),0)
self.assertEqual(type(R.leaves),type([]))
self.assertEqual(len(R.leaves),0)
self.assertEqual(R.antichainCutoff,600)
self.assertEqual(type(R.roots),type([]))
self.assertEqual(len(R.pendingVotes),0)
self.assertEqual(type(R.pendingVotes),type({}))
self.assertEqual(len(R.votes),0)
self.assertEqual(type(R.votes),type({}))
gen = Block() # genesis block
self.assertTrue(gen.data is None)
self.assertEqual(gen.parents,[])
msg = str(0) + str(None) + str([])
self.assertEqual(gen.ident, hash(msg))
block0 = gen
block1 = Block(parentsIn=[block0.ident], dataIn={"timestamp":time.time(), "txns":"pair of zircon encrusted tweezers"})
block2 = Block(parentsIn=[block1.ident], dataIn={"timestamp":time.time(), "txns":"watch out for that yellow snow"})
block3 = Block(parentsIn=[block1.ident], dataIn={"timestamp":time.time(), "txns":"he had the stank foot"})
block4 = Block(parentsIn=[block2.ident, block3.ident], dataIn={"timestamp":time.time(), "txns":"come here fido"})
block5 = Block(parentsIn=[block3.ident], dataIn={"timestamp":time.time(), "txns":"applied rotation on her sugar plum"})
block6 = Block(parentsIn=[block5.ident], dataIn={"timestamp":time.time(), "txns":"listen to frank zappa for the love of all that is good"})
R._addBlock(block0)
self.assertTrue(block0.ident in R.leaves)
self.assertTrue(block0.ident in R.roots)
R._addBlock(block1)
self.assertTrue(block1.ident in R.leaves and block0.ident not in R.leaves)
R._addBlock(block2)
self.assertTrue(block2.ident in R.leaves and block1.ident not in R.leaves)
R._addBlock(block3)
self.assertTrue(block3.ident in R.leaves and block2.ident in R.leaves and block1.ident not in R.leaves)
R._addBlock(block4)
self.assertTrue(block4.ident in R.leaves and block3.ident not in R.leaves and block2.ident not in R.leaves)
R._addBlock(block5)
self.assertTrue(block4.ident in R.leaves and block5.ident in R.leaves and block3.ident not in R.leaves)
R._addBlock(block6)
self.assertTrue(block4.ident in R.leaves and block6.ident in R.leaves and block5.ident not in R.leaves)
self.assertEqual(len(R.blocks), 7)
self.assertEqual(len(R.family), 7)
self.assertEqual(len(R.invDLL), 0)
self.assertEqual(len(R.roots), 1)
self.assertEqual(len(R.leaves),2)
self.assertEqual(R.antichainCutoff, 600)
self.assertEqual(len(R.pendingVotes),0)
self.assertEqual(len(R.votes),0)
self.assertTrue( R._hasAncestor(block6.ident, block0.ident) and not R._hasAncestor(block0.ident, block6.ident))
self.assertTrue( R._hasAncestor(block5.ident, block0.ident) and not R._hasAncestor(block0.ident, block5.ident))
self.assertTrue( R._hasAncestor(block4.ident, block0.ident) and not R._hasAncestor(block0.ident, block4.ident))
self.assertTrue( R._hasAncestor(block3.ident, block0.ident) and not R._hasAncestor(block0.ident, block3.ident))
self.assertTrue( R._hasAncestor(block2.ident, block0.ident) and not R._hasAncestor(block0.ident, block2.ident))
self.assertTrue( R._hasAncestor(block1.ident, block0.ident) and not R._hasAncestor(block0.ident, block1.ident))
self.assertTrue( R._hasAncestor(block6.ident, block1.ident) and not R._hasAncestor(block1.ident, block6.ident))
self.assertTrue( R._hasAncestor(block5.ident, block1.ident) and not R._hasAncestor(block1.ident, block5.ident))
self.assertTrue( R._hasAncestor(block4.ident, block1.ident) and not R._hasAncestor(block1.ident, block4.ident))
self.assertTrue( R._hasAncestor(block3.ident, block1.ident) and not R._hasAncestor(block1.ident, block3.ident))
self.assertTrue( R._hasAncestor(block2.ident, block1.ident) and not R._hasAncestor(block1.ident, block2.ident))
self.assertTrue(not R._hasAncestor(block0.ident, block1.ident) and R._hasAncestor(block1.ident, block0.ident))
self.assertTrue(not R._hasAncestor(block6.ident, block2.ident) and not R._hasAncestor(block2.ident, block6.ident))
self.assertTrue(not R._hasAncestor(block5.ident, block2.ident) and not R._hasAncestor(block2.ident, block5.ident))
self.assertTrue( R._hasAncestor(block4.ident, block2.ident) and not R._hasAncestor(block2.ident, block4.ident))
self.assertTrue(not R._hasAncestor(block3.ident, block2.ident) and not R._hasAncestor(block2.ident, block3.ident))
self.assertTrue(not R._hasAncestor(block1.ident, block2.ident) and R._hasAncestor(block2.ident, block1.ident))
self.assertTrue(not R._hasAncestor(block0.ident, block2.ident) and R._hasAncestor(block2.ident, block0.ident))
self.assertTrue( R._hasAncestor(block6.ident, block3.ident) and not R._hasAncestor(block3.ident, block6.ident))
self.assertTrue( R._hasAncestor(block5.ident, block3.ident) and not R._hasAncestor(block3.ident, block5.ident))
self.assertTrue( R._hasAncestor(block4.ident, block3.ident) and not R._hasAncestor(block3.ident, block4.ident))
self.assertTrue(not R._hasAncestor(block2.ident, block3.ident) and not R._hasAncestor(block3.ident, block2.ident))
self.assertTrue(not R._hasAncestor(block1.ident, block3.ident) and R._hasAncestor(block3.ident, block1.ident))
self.assertTrue(not R._hasAncestor(block0.ident, block3.ident) and R._hasAncestor(block3.ident, block0.ident))
self.assertTrue(not R._hasAncestor(block6.ident, block4.ident) and not R._hasAncestor(block4.ident, block6.ident))
self.assertTrue(not R._hasAncestor(block5.ident, block4.ident) and not R._hasAncestor(block4.ident, block5.ident))
self.assertTrue(not R._hasAncestor(block3.ident, block4.ident) and R._hasAncestor(block4.ident, block3.ident))
self.assertTrue(not R._hasAncestor(block2.ident, block4.ident) and R._hasAncestor(block4.ident, block2.ident))
self.assertTrue(not R._hasAncestor(block1.ident, block4.ident) and R._hasAncestor(block4.ident, block1.ident))
self.assertTrue(not R._hasAncestor(block0.ident, block4.ident) and R._hasAncestor(block4.ident, block0.ident))
self.assertTrue( R._hasAncestor(block6.ident, block5.ident) and not R._hasAncestor(block5.ident, block6.ident))
self.assertTrue(not R._hasAncestor(block4.ident, block5.ident) and not R._hasAncestor(block5.ident, block4.ident))
self.assertTrue(not R._hasAncestor(block3.ident, block5.ident) and R._hasAncestor(block5.ident, block3.ident))
self.assertTrue(not R._hasAncestor(block2.ident, block5.ident) and not R._hasAncestor(block5.ident, block2.ident))
self.assertTrue(not R._hasAncestor(block1.ident, block5.ident) and R._hasAncestor(block5.ident, block1.ident))
self.assertTrue(not R._hasAncestor(block0.ident, block5.ident) and R._hasAncestor(block5.ident, block0.ident))
self.assertTrue(not R._hasAncestor(block5.ident, block6.ident) and R._hasAncestor(block6.ident, block5.ident))
self.assertTrue(not R._hasAncestor(block4.ident, block6.ident) and not R._hasAncestor(block6.ident, block4.ident))
self.assertTrue(not R._hasAncestor(block3.ident, block6.ident) and R._hasAncestor(block6.ident, block3.ident))
self.assertTrue(not R._hasAncestor(block2.ident, block6.ident) and not R._hasAncestor(block6.ident, block2.ident))
self.assertTrue(not R._hasAncestor(block1.ident, block6.ident) and R._hasAncestor(block6.ident, block1.ident))
self.assertTrue(not R._hasAncestor(block0.ident, block6.ident) and R._hasAncestor(block6.ident, block0.ident))
R = R.pruneLeaves()
self.assertEqual(len(R.blocks), 5)
self.assertEqual(len(R.family), 5)
self.assertEqual(len(R.invDLL), 0)
self.assertEqual(len(R.roots), 1)
self.assertEqual(len(R.leaves),2)
self.assertEqual(R.antichainCutoff, 600)
self.assertEqual(len(R.pendingVotes),0)
self.assertEqual(len(R.votes),0)
self.assertTrue( R._hasAncestor(block5.ident, block0.ident) and not R._hasAncestor(block0.ident, block5.ident))
self.assertTrue( R._hasAncestor(block3.ident, block0.ident) and not R._hasAncestor(block0.ident, block3.ident))
self.assertTrue( R._hasAncestor(block2.ident, block0.ident) and not R._hasAncestor(block0.ident, block2.ident))
self.assertTrue( R._hasAncestor(block1.ident, block0.ident) and not R._hasAncestor(block0.ident, block1.ident))
self.assertTrue( R._hasAncestor(block5.ident, block1.ident) and not R._hasAncestor(block1.ident, block5.ident))
self.assertTrue( R._hasAncestor(block3.ident, block1.ident) and not R._hasAncestor(block1.ident, block3.ident))
self.assertTrue( R._hasAncestor(block2.ident, block1.ident) and not R._hasAncestor(block1.ident, block2.ident))
self.assertTrue(not R._hasAncestor(block0.ident, block1.ident) and R._hasAncestor(block1.ident, block0.ident))
self.assertTrue(not R._hasAncestor(block5.ident, block2.ident) and not R._hasAncestor(block2.ident, block5.ident))
self.assertTrue(not R._hasAncestor(block3.ident, block2.ident) and not R._hasAncestor(block2.ident, block3.ident))
self.assertTrue(not R._hasAncestor(block1.ident, block2.ident) and R._hasAncestor(block2.ident, block1.ident))
self.assertTrue(not R._hasAncestor(block0.ident, block2.ident) and R._hasAncestor(block2.ident, block0.ident))
self.assertTrue( R._hasAncestor(block5.ident, block3.ident) and not R._hasAncestor(block3.ident, block5.ident))
self.assertTrue(not R._hasAncestor(block2.ident, block3.ident) and not R._hasAncestor(block3.ident, block2.ident))
self.assertTrue(not R._hasAncestor(block1.ident, block3.ident) and R._hasAncestor(block3.ident, block1.ident))
self.assertTrue(not R._hasAncestor(block0.ident, block3.ident) and R._hasAncestor(block3.ident, block0.ident))
self.assertTrue(not R._hasAncestor(block3.ident, block5.ident) and R._hasAncestor(block5.ident, block3.ident))
self.assertTrue(not R._hasAncestor(block2.ident, block5.ident) and not R._hasAncestor(block5.ident, block2.ident))
self.assertTrue(not R._hasAncestor(block1.ident, block5.ident) and R._hasAncestor(block5.ident, block1.ident))
self.assertTrue(not R._hasAncestor(block0.ident, block5.ident) and R._hasAncestor(block5.ident, block0.ident))
## Formal unit tests for leafBackAntichain() to follow: visual inspection reveals this does what it says on the tin.
#R.vote()
#print(R.votes)
def test_big_bertha(self):
R = BlockHandler()
gen = Block() # genesis block
msg = str(0) + str(None) + str([])
block0 = gen
block1 = Block(parentsIn=[block0.ident], dataIn={"timestamp":time.time(), "txns":"pair of zircon encrusted tweezers"})
block2 = Block(parentsIn=[block1.ident], dataIn={"timestamp":time.time(), "txns":"watch out for that yellow snow"})
block3 = Block(parentsIn=[block1.ident], dataIn={"timestamp":time.time(), "txns":"he had the stank foot"})
block4 = Block(parentsIn=[block2.ident, block3.ident], dataIn={"timestamp":time.time(), "txns":"come here fido"})
block5 = Block(parentsIn=[block3.ident], dataIn={"timestamp":time.time(), "txns":"applied rotation on her sugar plum"})
block6 = Block(parentsIn=[block5.ident], dataIn={"timestamp":time.time(), "txns":"listen to frank zappa for the love of all that is good"})
R._addBlock(block0)
R._addBlock(block1)
R._addBlock(block2)
R._addBlock(block3)
R._addBlock(block4)
R._addBlock(block5)
R._addBlock(block6)
# Testing voteFor
# Verify all roots have children
for rid in R.roots:
self.assertFalse(len(R.family[rid]["children"])==0)
# Verify that all children of all roots have children and collect grandchildren idents
gc = []
for rid in R.roots:
for cid in R.family[rid]["children"]:
self.assertFalse(len(R.family[cid]["children"]) == 0)
gc = gc + R.family[cid]["children"]
# Pick a random grandchild of the root.
gcid = random.choice(gc)
# Pick a random block with gcid in its past
vid = random.choice(list(R.blocks.keys()))
while(not R._hasAncestor(vid, gcid)):
vid = random.choice(list(R.blocks.keys()))
# Pick a random pair of blocks for gcid and vid to vote on.
xid = random.choice(list(R.blocks.keys()))
yid = random.choice(list(R.blocks.keys()))
# Have vid cast vote that xid < yid
R.voteFor((vid,xid,yid),{})
# Verify that R.votes has correct entries
self.assertEqual(R.votes[(vid,xid,yid)], 1)
self.assertEqual(R.votes[(vid,yid,xid)],-1)
# Check that for each ancestor of vid, that they received an appropriate pending vote
q = deque()
for pid in R.blocks[vid].parents:
if pid in R.vids:
q.append(pid)
while(len(q)>0):
wid = q.popleft()
self.assertEqual(R.pendingVotes[(wid,xid,yid)],1)
for pid in R.blocks[wid].parents:
if pid in R.vids:
q.append(pid)
# Now we are going to mess around with how voting at gcid interacts with the above.
# First, we let gcid cast a vote that xid < yid and check that it propagates appropriately as above.
R.voteFor((gcid,xid,yid),{})
self.assertEqual(R.votes[(gcid,xid,yid)],1)
self.assertEqual(R.votes[(gcid,yid,xid)],-1)
for pid in R.blocks[vid].parents:
if pid in R.vids:
q.append(gpid)
while(len(q)>0):
wid = q.popleft()
self.assertEqual(R.pendingVotes[(wid,xid,yid)],2)
self.assertEqual(R.pendingVotes[(wid,yid,xid)],-2)
for pid in R.blocks[wid].parents:
if pid in R.vids:
q.append(pid)
# Now we are going to have gcid cast the opposite vote. this should change what is stored in R.votes
# but also change pending votes below gcid
R.voteFor((gcid,yid,xid),{})
self.assertEqual(R.votes[(gcid,xid,yid)],-1)
self.assertEqual(R.votes[(gcid,yid,xid)],1)
for pid in R.blocks[vid].parents:
if pid in R.vids:
q.append(gpid)
while(len(q)>0):
wid = q.popleft()
self.assertEqual(R.pendingVotes[(wid,xid,yid)],0)
self.assertEqual(R.pendingVotes[(wid,yid,yid)],0)
for pid in R.blocks[wid].parents:
if pid in R.vids:
q.append(pid)
# Do again, now pending votes should be negative
R.voteFor((gcid,yid,xid),{})
self.assertEqual(R.votes[(gcid,xid,yid)],-1)
self.assertEqual(R.votes[(gcid,yid,xid)],1)
for pid in R.blocks[vid].parents:
if pid in R.vids:
q.append(gpid)
while(len(q)>0):
wid = q.popleft()
self.assertEqual(R.pendingVotes[(wid,xid,yid)],-1)
self.assertEqual(R.pendingVotes[(wid,yid,yid)],-1)
for pid in R.blocks[wid].parents:
if pid in R.vids:
q.append(pid)
#R.vote()
#print(R.votes)