mirror of
https://github.com/monero-project/research-lab.git
synced 2024-12-22 11:39:32 +00:00
Rem. dep. file
This commit is contained in:
parent
41c8b73f2b
commit
463d8f35e2
1 changed files with 0 additions and 227 deletions
|
@ -1,227 +0,0 @@
|
|||
from Block import *
|
||||
#### #### #### #### #### #### #### #### #### #### #### #### #### #### #### ####
|
||||
class BlockDAG(object):
|
||||
""" Collection of >=1 block. """
|
||||
def __init__(self, params=None):
|
||||
self.genesis = Block()
|
||||
self.genesis.id = "0"
|
||||
self.blocks = {self.genesis.id:self.genesis}
|
||||
self.leaves = {self.genesis.id:self.genesis}
|
||||
|
||||
# Blocks from top-down antichain subsets covering >= 1/2 of blockDAG
|
||||
self.votBlocks = {self.genesis.id:self.genesis}
|
||||
# Blocks from top-down antichain subsets "non-negl" likely to re-org
|
||||
self.ordBlocks = {self.genesis.id:self.genesis}
|
||||
|
||||
if params is not None:
|
||||
self.security = params
|
||||
else:
|
||||
self.security = 10
|
||||
self.vote = {}
|
||||
self.pending = {}
|
||||
for blockZ in self.votBlocks:
|
||||
for blockX in self.ordBlocks:
|
||||
for blockY in self.ordBlocks:
|
||||
self.vote.update({(blockZ,blockX,blockY):0})
|
||||
self.pending.update({(blockZ,blockX,blockY):0})
|
||||
|
||||
def computeVote(self, dagIn):
|
||||
(canopy, fullCanopy) = self.pick(dagIn)
|
||||
for layer in fullCanopy:
|
||||
for blockZ in layer:
|
||||
if blockZ not in dagIn.votBlocks:
|
||||
continue
|
||||
else:
|
||||
for blockX in layer:
|
||||
if blockX not in dagIn.ordBlocks:
|
||||
continue
|
||||
else:
|
||||
for blockY in layer:
|
||||
if blockY not in dagIn.ordBlocks:
|
||||
continue
|
||||
else:
|
||||
if self.inPast(dagIn,blockY,blockZ) and self.inPast(dagIn,blockX,blockZ):
|
||||
# then Z votes recursively
|
||||
if blockZ not in dagIn.seenPasts:
|
||||
dagIn.seenPasts.update({blockZ:dagIn.getPast(blockZ)})
|
||||
dagIn.seenVotes.update({blockZ:dagIn.vote(dagIn.seenPasts[blockZ])})
|
||||
dagIn.vote.update({(blockZ,blockX,blockY):dagIn.seenVotes[blockZ][(blockX,blockY)], (blockZ,blockY,blockX):dagIn.seenVotes[blockZ][(blockY,blockX)], (blockZ,blockX,blockZ):1, (blockZ, blockZ, blockX):-1, (blockZ, blockY, blockZ):1, (blockZ, blockZ, blockY):-1})
|
||||
elif self.inPast(dagIn, blockY, blockZ) and not self.inPast(dagIn, blockX, blockZ):
|
||||
dagIn.vote.update({(blockZ,blockX,blockY):-1, (blockZ,blockY,blockX):1, (blockZ,blockX,blockZ):-1, (blockZ,blockZ,blockX):1, (blockZ,blockZ,blockY):-1, (blockZ,blockY,blockZ):1}) # Then Z votes Y < Z < X
|
||||
elif not self.inPast(dagIn, blockY, blockZ) and self.inPast(dagIn, blockX, blockZ):
|
||||
dagIn.vote.update({(blockZ,blockX,blockY):1, (blockZ,blockY,blockX):-1, (blockZ,blockX,blockZ):1, (blockZ,blockZ,blockX):-1, (blockZ,blockZ,blockY):1, (blockZ,blockY,blockZ):-1}) # Then Z votes X < Z < Y
|
||||
else:
|
||||
if dagIn.pending[(blockZ,blockX,blockY)] > 0:
|
||||
dagIn.vote.update({(blockZ,blockX,blockY):1, (blockZ,blockY,blockX):-1, (blockZ, blockX, blockZ):-1, (blockZ, blockZ, blockX):1, (blockZ, blockY, blockZ):-1, (blockZ, blockZ, blockY):1})
|
||||
elif dagIn.pending[(blockZ,blockX,blockY)] < 0:
|
||||
dagIn.vote.update({(blockZ,blockX,blockY):-1, (blockZ,blockY,blockX):1, (blockZ, blockX, blockZ):-1, (blockZ, blockZ, blockX):1, (blockZ, blockY, blockZ):-1, (blockZ, blockZ, blockY):1})
|
||||
else:
|
||||
dagIn.vote.update({(blockZ,blockX,blockY):0, (blockZ,blockY,blockX):0, (blockZ, blockX, blockZ):-1, (blockZ, blockZ, blockX):1, (blockZ, blockY, blockZ):-1, (blockZ, blockZ, blockY):1})
|
||||
q = deque()
|
||||
for p in dagIn.blocks[blockZ].parents:
|
||||
if p in dagIn.votBlocks:
|
||||
q.append(p)
|
||||
while(len(q)>0):
|
||||
nextBlock = q.popleft()
|
||||
if (nextBlock, blockX, blockY) not in dagIn.pending:
|
||||
dagIn.pending.update({(nextBlock, blockX,blockY):0})
|
||||
if (nextBlock, blockY, blockX) not in dagIn.pending:
|
||||
dagIn.pending.update({(nextBlock, blockY,blockX):0})
|
||||
if dagIn.vote[(blockZ,blockX,blockY)] > 0:
|
||||
dagIn.pending[(nextBlock,blockX,blockY)] += 1
|
||||
dagIn.pending[(nextBlock,blockY,blockX)] -= 1
|
||||
elif dagIn.vote[(blockZ,blockX,blockY)] < 0:
|
||||
dagIn.pending[(nextBlock,blockX,blockY)] -= 1
|
||||
dagIn.pending[(nextBlock,blockY,blockX)] += 1
|
||||
for p in dagIn.blocks[nextBlock].parents:
|
||||
if p in dagIn.votBlocks:
|
||||
q.append(p)
|
||||
totalVote = {}
|
||||
for blockX in dagIn.ordBlocks:
|
||||
for blockY in dagIn.ordBlocks:
|
||||
if (blockX, blockY) not in totalVote:
|
||||
totalVote.update({(blockX,blockY):0, (blockY,blockX):0})
|
||||
for blockZ in dagIn.votBlocks:
|
||||
if dagIn.vote[(blockZ,blockX,blockY)] > 0:
|
||||
totalVote[(blockX,blockY)] += 1
|
||||
elif dagIn.vote[(blockZ,blockX,blockY)] < 0:
|
||||
totalVote[(blockX,blockY)] -= 1
|
||||
if totalVote[(blockX,blockY)] > 0:
|
||||
totalVote[(blockX,blockY)] = 1
|
||||
elif totalVote[(blockX,blockY)] < 0:
|
||||
totalVote[(blockX,blockY)] = -1
|
||||
return totalVote
|
||||
|
||||
def pick(self, dagIn):
|
||||
""" Pick voting blocks and orderable blocks """
|
||||
(canopy, fullCanopy) = self.antichain(dagIn)
|
||||
dagIn.votBlocks = {}
|
||||
dagIn.ordBlocks = {}
|
||||
idx = 0
|
||||
count = len(canopy[idx])
|
||||
for block in canopy[idx]:
|
||||
dagIn.votBlocks.update({block:dagIn.blocks[block]})
|
||||
dagIn.ordBlocks.update({blcok:dagIn.blocks[block]})
|
||||
numVoters = 1 - ((-len(dagIn.blocks))//2)
|
||||
while(count < numVoters):
|
||||
idx += 1
|
||||
count += len(canopy[idx])
|
||||
for block in canopy[idx]:
|
||||
dagIn.votBlocks.update({block:dagIn.blocks[block]})
|
||||
if idx < self.security:
|
||||
dagIn.ordBlocks.update({block:dagIn.blocks[block]})
|
||||
return (canopy, fullCanopy)
|
||||
|
||||
|
||||
def makeBlock(self, idIn, parentsIn):
|
||||
assert idIn not in self.blocks
|
||||
newBlock = Block()
|
||||
newBlock.id = idIn
|
||||
newBlock.addParents(parentsIn)
|
||||
self.blocks.update({newBlock.id:newBlock})
|
||||
for parent in parentsIn:
|
||||
if parent in self.leaves:
|
||||
del self.leaves[parent]
|
||||
self.blocks[parent].addChild(newBlock)
|
||||
self.leaves.update({newBlock.id:newBlock})
|
||||
|
||||
def pruneLeaves(self, dagIn):
|
||||
result = BlockDAG()
|
||||
result.genesis.id = dagIn.genesis.id
|
||||
q = deque()
|
||||
for child in dagIn.genesis.children:
|
||||
if child not in dagIn.leaves:
|
||||
q.append(child)
|
||||
while(len(q)>0):
|
||||
nextBlock = q.popleft()
|
||||
result.makeBlock(nextBlock, dagIn.blocks[nextBlock].parents)
|
||||
for child in dagIn.blocks[nextBlock].children:
|
||||
if child not in dagIn.leaves:
|
||||
q.append(child)
|
||||
return result
|
||||
|
||||
def antichain(self, dagIn):
|
||||
canopy = []
|
||||
fullCanopy = []
|
||||
nextDag = dagIn
|
||||
canopy.append(nextDag.leaves)
|
||||
fullCanopy.append(nextDag.leaves)
|
||||
while(len(nextDag.blocks)>1):
|
||||
nextDag = dagIn.pruneLeaves(dagIn)
|
||||
canopy.append(nextDag.leaves)
|
||||
fullCanopy.append(fullCanopy[-1])
|
||||
for leaf in nextDag.leaves:
|
||||
fullCanopy[-1].append(leaf)
|
||||
nextDag = self.pruneLeaves(dagIn)
|
||||
return (canopy, fullCanopy)
|
||||
|
||||
def inPast(self, dagIn, y, x):
|
||||
""" self.inPast(dag, y,x) if and only if y is in the past of x in dag """
|
||||
found = False
|
||||
if y in dagIn.blocks[x].parents:
|
||||
found = True
|
||||
else:
|
||||
q = deque()
|
||||
for parent in dagIn.blocks[x].parents:
|
||||
q.append(parent)
|
||||
while(len(q)>0):
|
||||
nextBlock = q.popleft()
|
||||
if y in dagIn.blocks[nextBlock].parents:
|
||||
found = True
|
||||
break
|
||||
else:
|
||||
for parent in dagIn.blocks[nextBlock].parents:
|
||||
q.append(parent)
|
||||
return found
|
||||
|
||||
def getPast(self, dagIn, block):
|
||||
subdag = BlockDAG()
|
||||
subdag.genesis = dagIn.genesis
|
||||
q = deque()
|
||||
for child in dagIn.genesis.children:
|
||||
if self.inPast(dagIn,child,block):
|
||||
q.append(child)
|
||||
while len(q) > 0:
|
||||
nextBlock = q.popleft()
|
||||
subdag.makeBlock(dagIn.blocks[nextBlock])
|
||||
for child in dagIn.blocks[nextBlock].children:
|
||||
if self.inPast(dagIn,child,block):
|
||||
q.append(child)
|
||||
return subdag
|
||||
|
||||
|
||||
class Test_BlockDAG(unittest.TestCase):
|
||||
def test_BlockDAG(self):
|
||||
dag = BlockDAG()
|
||||
self.assertTrue("0" in dag.blocks)
|
||||
self.assertTrue("0" in dag.leaves)
|
||||
self.assertTrue(len(dag.blocks)==1)
|
||||
self.assertTrue(len(dag.leaves)==1)
|
||||
b0 = dag.genesis
|
||||
|
||||
dag.makeBlock("1",{"0":b0})
|
||||
b1 = dag.blocks["1"]
|
||||
self.assertTrue("1" in dag.blocks)
|
||||
self.assertTrue("1" in dag.leaves)
|
||||
self.assertTrue("0" not in dag.leaves)
|
||||
self.assertTrue(len(dag.blocks)==2)
|
||||
self.assertTrue(len(dag.leaves)==1)
|
||||
self.assertTrue("1" in b0.children)
|
||||
self.assertTrue("1" in dag.genesis.children)
|
||||
self.assertTrue("1" in dag.blocks[dag.genesis.id].children)
|
||||
|
||||
dag.makeBlock("2", {"0":b0})
|
||||
b2 = dag.blocks["2"]
|
||||
|
||||
dag.makeBlock("3", {"1":b1, "2":b2})
|
||||
b3 = dag.blocks["3"]
|
||||
|
||||
dag.makeBlock("4", {"2":b2})
|
||||
b4 = dag.blocks["4"]
|
||||
|
||||
print(dag.computeVote(dag))
|
||||
|
||||
|
||||
|
||||
suite = unittest.TestLoader().loadTestsFromTestCase(Test_BlockDAG)
|
||||
unittest.TextTestRunner(verbosity=1).run(suite)
|
Loading…
Reference in a new issue