research-lab/source-code/Poisson-Graphs/Graph.py

205 lines
8.4 KiB
Python
Raw Normal View History

from Blockchain import *
from Node import *
from Edge import *
from copy import *
def newIntensity(params):
x = random.random()
return x
def newOffset(params):
x = 2.0*random.random() - 1.0
return x
class Graph(object):
'''
Explanation
'''
def __init__(self, params):
self.nodes = {}
self.edges = {}
self.mode = params[0]
self.targetRate = params[1]
self.numInitNodes = params[2]
self.maxNeighbors = params[3]
self.probEdge = params[4]
self.verbosity = params[5]
self.startTime = deepcopy(time.time())
self.runTime = params[6]
self.globalTime = deepcopy(self.startTime)
self.birthRate = params[7]
self.deathRate = params[8]
self.filename = params[9]
self.data = params[10]
self.blankBlockchain = Blockchain()
self.blankBlockchain.targetRate = self.targetRate
self.blankBlockchain.mode = self.mode
self.blankBlockchain.diff = 1.0
self._createInit()
def _createInit(self):
# For simplicity, all nodes will have a genesis block with t=0.0 and no offset
for i in range(self.numInitNodes):
offset = newOffset(None)
intens = newIntensity(None)
name = newIdent(len(self.nodes))
dat = {"offset":offset, "intensity":intens, "blockchain":deepcopy(self.blankBlockchain)}
params = {"ident":name, "data":dat, "verbose":self.verbosity, "mode":self.mode, "targetRate":self.targetRate}
nelly = Node(params)
self.nodes.update({nelly.ident:nelly})
t = self.startTime
self.nodes[nelly.ident].generateBlock(t)
touched = {}
for xNode in self.nodes:
for yNode in self.nodes:
notSameNode = (xNode != yNode)
xNodeHasRoom = (len(self.nodes[xNode].edges) < self.maxNeighbors)
yNodeHasRoom = (len(self.nodes[yNode].edges) < self.maxNeighbors)
xyNotTouched = ((xNode, yNode) not in touched)
yxNotTouched = ((yNode, xNode) not in touched)
if notSameNode and xNodeHasRoom and yNodeHasRoom and xyNotTouched and yxNotTouched:
touched.update({(xNode,yNode):True, (yNode,xNode):True})
if random.random() < self.probEdge:
params = [newIdent(len(self.edges)), {"pendingBlocks":{}, "length":random.random()}, self.verbosity]
ed = Edge(params)
ed.nodes.update({xNode:self.nodes[xNode], yNode:self.nodes[yNode]})
self.edges.update({ed.ident:ed})
self.nodes[xNode].edges.update({ed.ident:ed})
self.nodes[yNode].edges.update({ed.ident:ed})
def eventNodeJoins(self, t):
# timestamp,nodeJoins,numberNeighbors,neighbor1.ident,edge1.ident,neighbor2.ident,edge2.ident,...,
out = ""
neighbors = []
for xNode in self.nodes:
xNodeHasRoom = (len(self.nodes[xNode].edges) < self.maxNeighbors)
iStillHasRoom = (len(neighbors) < self.maxNeighbors)
if xNodeHasRoom and iStillHasRoom and random.random() < self.probEdge:
neighbors.append(xNode)
newNodeName = newIdent(len(self.nodes))
offset = newOffset(None)
intens = newIntensity(None)
dat = {"offset":offset, "intensity":intens, "blockchain":deepcopy(self.blankBlockchain)}
params = {"ident":newNodeName, "data":dat, "verbose":self.verbosity, "mode":self.mode, "targetRate":self.targetRate}
newNode = Node(params)
self.nodes.update({newNode.ident:newNode})
self.nodes[newNode.ident].generateBlock(self.startTime, 0)
out = str(t) + ",nodeJoins," + str(newNode.ident) + "," + str(len(neighbors)) + ","
for neighbor in neighbors:
out += neighbor + ","
params = [newIdent(len(self.edges)), {}, self.verbosity]
ed = Edge(params)
ed.nodes.update({neighbor:self.nodes[neighbor], newNode.ident:self.nodes[newNode.ident]})
out += ed.ident + ","
self.edges.update({ed.ident:ed})
self.nodes[neighbor].edges.update({ed.ident:ed})
self.nodes[newNode.ident].edges.update({ed.ident:ed})
return out
def eventNodeLeaves(self, t):
out = str(t) + ",nodeLeaves,"
leaverIdent = random.choice(list(self.nodes.keys()))
out += str(leaverIdent) + ","
leaver = self.nodes[leaverIdent]
neighbors = []
for ed in leaver.edges:
edge = leaver.edges[ed]
neighbors.append((edge.ident, edge.getNeighbor(leaverIdent)))
for neighbor in neighbors:
edIdent = neighbor[0]
neiIdent = neighbor[1]
del self.nodes[neiIdent].edges[edIdent]
del self.edges[edIdent]
del self.nodes[leaverIdent]
return out
def eventBlockDiscovery(self, discoIdent, t):
out = str(t) + ",blockDisco," + str(discoIdent) + ","
blockIdent = self.nodes[discoIdent].generateBlock(t)
out += str(blockIdent)
self.nodes[discoIdent].propagate(t, blockIdent)
return out
def eventBlockArrival(self, pendingIdent, edgeIdent, t):
out = str(t) + ",blockArriv,"
edge = self.edges[edgeIdent]
pendingData = edge.data["pendingBlocks"][pendingIdent] # pendingDat = {"timeOfArrival":timeOfArrival, "destIdent":otherIdent, "block":blockToProp}
out += str(pendingData["destIdent"]) + "," + str(edgeIdent) + "," + str(pendingData["block"].ident)
destNode = self.nodes[pendingData["destIdent"]]
edge = self.edges[edgeIdent]
block = deepcopy(pendingData["block"])
block.arrivTimestamp = t + destNode.data["offset"]
destNode.updateBlockchain({block.ident:block})
del edge.data["pendingBlocks"][pendingIdent]
return out
def go(self):
with open(self.filename,"w") as writeFile:
writeFile.write("timestamp,eventId,eventData\n")
eventType = None
while self.globalTime - self.startTime< self.runTime:
u = -1.0*math.log(1.0-random.random())/self.birthRate
eventType = ("nodeJoins", None)
v = -1.0*math.log(1.0-random.random())/self.deathRate
if v < u:
eventType = ("nodeLeaves", None)
u = v
for nodeIdent in self.nodes:
localBlockDiscoRate = self.nodes[nodeIdent].data["intensity"]/self.nodes[nodeIdent].data["blockchain"].diff
v = -1.0*math.log(1.0-random.random())/localBlockDiscoRate
if v < u:
eventType = ("blockDisco", nodeIdent)
u = v
for edgeIdent in self.edges:
edge = self.edges[edgeIdent]
pB = edge.data["pendingBlocks"]
for pendingIdent in pB:
pendingData = pB[pendingIdent]
if pendingData["timeOfArrival"] - self.globalTime < u:
eventType = ("blockArriv", pendingIdent, edgeIdent)
u = v
assert eventType is not None
self.globalTime += u
out = ""
if eventType[0] == "nodeJoins":
out = self.eventNodeJoins(self.globalTime)
elif eventType[0] == "nodeLeaves":
out = self.eventNodeLeaves(self.globalTime)
elif eventType[0] == "blockDisco":
out = self.eventBlockDiscovery(eventType[1], self.globalTime)
elif eventType[0] == "blockArriv":
out = self.eventBlockArrival(eventType[1], eventType[2], self.globalTime)
else:
print("WHAAAA")
with open(self.filename, "a") as writeFile:
writeFile.write(out + "\n")
mode = "Nakamoto"
targetRate = 1.0/600000.0
numInitNodes = 10
maxNeighbors = 8
probEdge = 0.1
verbosity = True
startTime = time.time()
runTime = 10.0
globalTime = startTime
birthRate = 1.0/10.0
deathRate = 0.99*1.0/10.0
filename = "output.csv"
greg = Graph([mode, targetRate, numInitNodes, maxNeighbors, probEdge, verbosity, runTime, birthRate, deathRate, filename, []])
greg.go()