mirror of
https://github.com/monero-project/research-lab.git
synced 2024-12-22 19:49:35 +00:00
Deleted bullshit
This commit is contained in:
parent
0cd82ab66b
commit
81b179262b
1 changed files with 0 additions and 275 deletions
|
@ -1,275 +0,0 @@
|
||||||
import copy, hashlib, time
|
|
||||||
|
|
||||||
class Event(object):
|
|
||||||
''' Generalized event object '''
|
|
||||||
def __init__(self,params):
|
|
||||||
self.data = {}
|
|
||||||
self.timeOfEvent = None
|
|
||||||
self.eventType = None
|
|
||||||
|
|
||||||
|
|
||||||
class Block(object):
|
|
||||||
''' Block object, very simple... has an identity and a timestamp'''
|
|
||||||
def __init__(self, params):
|
|
||||||
self.ident = params[0]
|
|
||||||
self.timestamp = params[1]
|
|
||||||
|
|
||||||
class Node(object):
|
|
||||||
'''
|
|
||||||
Node object, represents a computer on the network.
|
|
||||||
Has an identity, a dict (?) of edges, a time offset on [-1,1]
|
|
||||||
representing how inaccurate the node's wall clock appears to be,
|
|
||||||
an intensity representing the node's hash rate, a blockchain
|
|
||||||
which is merely a list of block objects (ordered by their arrival
|
|
||||||
at the node, for simplicity), and a difficulty score (which is
|
|
||||||
a function of the blockchain)
|
|
||||||
'''
|
|
||||||
def __init__(self, params):
|
|
||||||
self.ident = params[0] # string
|
|
||||||
self.edges = params[1] # dict of edges
|
|
||||||
self.timeOffset = params[2] # float
|
|
||||||
self.intensity = params[3] # float (positive)
|
|
||||||
self.difficulty = params[4]
|
|
||||||
self.blockchain = []
|
|
||||||
|
|
||||||
def makeBlock(self, t):
|
|
||||||
ts = t + self.timeOffset
|
|
||||||
newBlock = Block()
|
|
||||||
salt = random.random()
|
|
||||||
n = len(self.blockchain)
|
|
||||||
x = hash(str(n) + str(salt))
|
|
||||||
newBlock.ident = x
|
|
||||||
newBlock.timestamp = ts
|
|
||||||
self.blockchain.append(newBlock)
|
|
||||||
self.computeDifficulty()
|
|
||||||
return newBlock
|
|
||||||
|
|
||||||
# node object needs receiveBlock(block) method
|
|
||||||
def receiveBlock(self, blockToReceive):
|
|
||||||
self.blockchain.append(blockToReceive)
|
|
||||||
|
|
||||||
def computeDifficulty(self, target, sampleSize):
|
|
||||||
N = min(sampleSize,len(self.blockchain))
|
|
||||||
tempSum = 0.0
|
|
||||||
for i in range(N):
|
|
||||||
tempSum += abs(self.blockchain[-i].timestamp - self.blockchain[-i-1].timestamp)
|
|
||||||
tempSum = float(tempSum)/float(N) # Average absolute time difference of last N blocks
|
|
||||||
lambdaMLE = 1.0/tempSum
|
|
||||||
self.difficulty = float(lambdaMLE/target)*self.difficulty
|
|
||||||
|
|
||||||
class Edge(object):
|
|
||||||
'''
|
|
||||||
Edge object representing the connection between one node and another.
|
|
||||||
Has two node objects, a and b, a length l, and a dictionary of pending blocks.
|
|
||||||
'''
|
|
||||||
def __init__(self, params):
|
|
||||||
self.ident = params[0] # edge ident
|
|
||||||
self.a = params[1] # node ident of one incident node
|
|
||||||
self.b = params[2] # node ident of the other incident node (may be None when creating new blocks?)
|
|
||||||
self.l = params[3] # length of edge as measured in propagation time.
|
|
||||||
self.pendingBlocks = {} # blockIdent:(block, destination node ident, deterministic time of arrival)
|
|
||||||
|
|
||||||
def addBlock(self, blockToAdd, blockFinderIdent, curTime):
|
|
||||||
# Include new block to self.pendingBlocks
|
|
||||||
timeOfArrival = curTime + self.l
|
|
||||||
if blockFinderIdent == self.a.ident:
|
|
||||||
self.pendingBlocks.update({blockToAdd.ident:(blockToAdd, self.b.ident, timeOfArrival)})
|
|
||||||
elif blockFinderIdent == self.b.ident:
|
|
||||||
self.pendingBlocks.update({blockToAdd.ident:(blockToAdd, self.a.ident, timeOfArrival)})
|
|
||||||
else:
|
|
||||||
print("fish sticks.")
|
|
||||||
|
|
||||||
|
|
||||||
class Network(object):
|
|
||||||
'''
|
|
||||||
Network object consisting of a number of vertices, a probability that any pair of vertices
|
|
||||||
has an edge between them, a death rate of vertices, a dictionary of vertices, a dictionary
|
|
||||||
of edges, and a clock t.
|
|
||||||
'''
|
|
||||||
def __init__(self, params):
|
|
||||||
self.numVertices = params[0] # integer
|
|
||||||
self.probOfEdge = params[1] # float (between 0.0 and 1.0)
|
|
||||||
self.deathRate = params[2] # float 1.0/(avg vertex lifespan)
|
|
||||||
self.vertices = {} # Dict with keys=node idents and values=nodes
|
|
||||||
self.edges = {} # Dict with keys=edge idents and values=edges
|
|
||||||
self.t = 0.0
|
|
||||||
self.defaultNodeLength = 30.0 # milliseconds
|
|
||||||
self.initialize()
|
|
||||||
|
|
||||||
def initialize(self):
|
|
||||||
# Generate self.numVertices new nodes with probability self.probOfEdge
|
|
||||||
# that any pair are incident. Discard any disconnected nodes (unless
|
|
||||||
# there is only one node)
|
|
||||||
try:
|
|
||||||
assert self.numVertices > 1
|
|
||||||
except AssertionError:
|
|
||||||
print("Fish sticks... AGAIN! Come ON, fellas!")
|
|
||||||
|
|
||||||
count = self.numVertices - 1
|
|
||||||
|
|
||||||
e = Event()
|
|
||||||
e.eventType = "node birth"
|
|
||||||
e.timeOfEvent = 0.0
|
|
||||||
e.data = {"neighbors":[]}
|
|
||||||
self.birthNode(e)
|
|
||||||
|
|
||||||
while count > 0:
|
|
||||||
count -= 1
|
|
||||||
e.eventType = "node birth"
|
|
||||||
e.timeOfEvent = 0.0
|
|
||||||
e.data = {"neighbors":[]}
|
|
||||||
for x in self.vertices:
|
|
||||||
u = random.random()
|
|
||||||
if u < self.probOfEdge:
|
|
||||||
e.data["neighbors"].append(x)
|
|
||||||
self.birthNode(e)
|
|
||||||
|
|
||||||
def run(self, maxTime, birthrate=lambda x:math.exp(-(x-10.0)**2.0)):
|
|
||||||
# Run the simulation for maxTime and birthrate function (of time)
|
|
||||||
while self.t < maxTime:
|
|
||||||
if type(birthrate) is float: # We may pass in a constant birthrate
|
|
||||||
birthrate = lambda x:birthrate # but we want it treated as a function
|
|
||||||
e = self.nextEvent(birthrate) # Generate next event.
|
|
||||||
try:
|
|
||||||
assert e is not None
|
|
||||||
except AssertionError:
|
|
||||||
print("Got null event in run, bailing...")
|
|
||||||
break
|
|
||||||
self.t = e.timeOfEvent # Get time until next event.
|
|
||||||
self.execute(e) # Run the execute method
|
|
||||||
|
|
||||||
def nextEvent(self, birthrate, t):
|
|
||||||
# The whole network experiences stochastic birth and death as a Poisson
|
|
||||||
# process, each node experiences stochastic block discovery as a (non-
|
|
||||||
# homogeneous) Poisson process. Betwixt these arrivals, other
|
|
||||||
# deterministic events occur as blocks are propagated along edges,
|
|
||||||
# changing the (local) block discovery rates.
|
|
||||||
|
|
||||||
# Birth of node?
|
|
||||||
u = random.random()
|
|
||||||
u = math.ln(1.0-u)/birthrate(t)
|
|
||||||
e = Event()
|
|
||||||
e.eventType = "node birth"
|
|
||||||
e.timeOfEvent = self.t + u
|
|
||||||
e.data = {"neighbors":[]}
|
|
||||||
for x in self.vertices:
|
|
||||||
u = random.random()
|
|
||||||
if u < self.probOfEdge:
|
|
||||||
e.data["neighbors"].append(x)
|
|
||||||
|
|
||||||
for x in self.vertices:
|
|
||||||
u = random.random()
|
|
||||||
u = math.ln(1.0 - u)/self.deathRate
|
|
||||||
tempTime = self.t + u
|
|
||||||
if tempTime < e.timeOfEvent:
|
|
||||||
e.eventType = "node death"
|
|
||||||
e.timeOfEvent = tempTime
|
|
||||||
e.data = {"identToKill":x}
|
|
||||||
|
|
||||||
u = random.random()
|
|
||||||
localIntensity = self.vertices[x].intensity/self.vertices[x].difficulty
|
|
||||||
u = math.ln(1.0 - u)/localIntensity
|
|
||||||
tempTime = self.t + u
|
|
||||||
if tempTime < e.timeOfEvent:
|
|
||||||
e.eventType = "block found"
|
|
||||||
e.timeOfEvent = tempTime
|
|
||||||
e.data = {"blockFinderIdent":x}
|
|
||||||
|
|
||||||
for edgeIdent in self.vertices[x].edges:
|
|
||||||
for pendingBlockIdent in self.edges[edgeIdent]:
|
|
||||||
timeOfBlockArrival = self.edges[edgeIdent].pendingBlocks[pendingBlockIdent][2]
|
|
||||||
if timeOfBlockArrival < e.timeOfEvent:
|
|
||||||
e.eventType = "block propagated"
|
|
||||||
e.timeOfEvent = timeOfBlockArrival
|
|
||||||
e.data = {"propEdgeIdent":edgeIdent, "pendingBlockIdent":blockIdent}
|
|
||||||
return e
|
|
||||||
|
|
||||||
def execute(self, e):
|
|
||||||
# Take an event e as input. Depending on eventType of e, execute
|
|
||||||
# the correspondsing method.
|
|
||||||
if e.eventType == "node birth":
|
|
||||||
self.birthNode(e)
|
|
||||||
elif e.eventType == "node death":
|
|
||||||
self.killNode(e)
|
|
||||||
elif e.eventType == "block found":
|
|
||||||
self.foundBlock(e)
|
|
||||||
elif e.eventType == "block propagated":
|
|
||||||
self.propBlock(e)
|
|
||||||
|
|
||||||
def birthNode(self, e):
|
|
||||||
# In this event, a new node is added to the network and edges are randomly decided upon.
|
|
||||||
# I will probably limit the number of peers for a new node eventually: a fixed probability
|
|
||||||
# of even 1% of edges per pair of nodes, in a graph with, say 1000 nodes, will see 10 peers
|
|
||||||
# per node...
|
|
||||||
# Also, I was kind of thinking this code should probably run with less than 50 nodes at a time, in general,
|
|
||||||
# otherwise the simulation needs to be highly optimized to make for reasonable simulation times.
|
|
||||||
|
|
||||||
newNodeIdent = hash(str(len(self.vertices)) + str(random.random())) # Pick a new random node ident
|
|
||||||
newOffset = 2.0*random.random() - 1.0 # New time offset for the new node
|
|
||||||
newIntensity = random.random() # New node hash rate
|
|
||||||
newDifficulty = 1.0 # Dummy variable, will be replaced
|
|
||||||
|
|
||||||
newbc = [] # This will be the union of the blockchains of all neighbors in e.data["neighbors"]
|
|
||||||
count = 0 # This will be a nonce to be combined with a salt for a unique identifier
|
|
||||||
newEdges = {}
|
|
||||||
for neighborIdent in e.data["neighbors"]:
|
|
||||||
newbc += [z for z in self.vertices[neighborIdent].blockchain if z not in newbc]
|
|
||||||
newEdgeIdent = hash(str(count) + str(random.random()))
|
|
||||||
count += 1
|
|
||||||
newLength = random.random()*self.defaultNodeLength
|
|
||||||
otherSide = random.choice(self.vertices.keys())
|
|
||||||
newEdge = Edge([newEdgeIdent, newNodeIdent, otherSide, newLength])
|
|
||||||
newEdges.update({newEdgeIdent:newEdge})
|
|
||||||
|
|
||||||
params = [newNodeIdent, newEdges, newOffset, newIntensity, newDifficulty]
|
|
||||||
newNode = Node(params) # Create new node
|
|
||||||
newNode.blockchain = newbc # Store new blockchain
|
|
||||||
newNode.computeDifficulty() # Compute new node's difficulty
|
|
||||||
|
|
||||||
self.vertices.update({newIdent:newNode}) # Add new node to self.vertices
|
|
||||||
self.edges.update(newEdges) # Add all new edges to self.edges
|
|
||||||
|
|
||||||
def killNode(self, e):
|
|
||||||
# Remove node and all incident edges
|
|
||||||
nodeIdentToKill = e.data["identToKill"]
|
|
||||||
#edgesToKill = e.data["edgesToKill"]
|
|
||||||
for edgeIdentToKill in self.vertices[nodeIdentToKill].edges:
|
|
||||||
del self.edges[edgeIdentToKill]
|
|
||||||
del self.vertices[nodeIdentToKill]
|
|
||||||
|
|
||||||
def foundBlock(self, e):
|
|
||||||
# In this instance, a node found a new block.
|
|
||||||
blockFinderIdent = e.data["blockFinderIdent"] # get identity of node that found the block.
|
|
||||||
blockFound = self.vertices[blockFinderIdent].makeBlock() # Nodes need a makeBlock method
|
|
||||||
for nextEdge in self.vertices[blockFinderIdent].edges: # propagate to edges
|
|
||||||
self.edges[nextEdge].addBlock(blockFound, blockFinderIdent, self.t) # Edges need an addBlock method
|
|
||||||
|
|
||||||
def propBlock(self, e):
|
|
||||||
# In this instance, a block on an edge is plunked onto its destination node and then
|
|
||||||
# propagated to the resulting edges.
|
|
||||||
propEdgeIdent = e.data["propEdgeIdent"] # get the identity of the edge along which the block was propagating
|
|
||||||
blockToPropIdent = e.data["blockIdent"] # get the identity of the block beign propagated
|
|
||||||
# Get the block being propagated and the node identity of the receiver.
|
|
||||||
(blockToAdd, destIdent) = self.edges[propEdgeIdent].pendingBlocks[blockToPropIdent]
|
|
||||||
self.vertices[destIdent].receiveBlock(blockToAdd) # Call receiveBlock from the destination node.
|
|
||||||
del self.edges[propEdgeIdent].pendingBlocks[blockToPropIdent] # Now that the block has been received
|
|
||||||
for nextEdge in self.vertices[destIdent].edges:
|
|
||||||
if nextEdge != propEdgeIdent:
|
|
||||||
if self.edges[nextEdge].a.ident == destIdent:
|
|
||||||
otherSideIdent = self.edges[nextEdge].b.ident
|
|
||||||
elif self.edges[nextEdge].b.ident == destIdent:
|
|
||||||
otherSideIdent = self.edges[nextEdge].a.ident
|
|
||||||
else:
|
|
||||||
print("awww fish sticks, fellas")
|
|
||||||
|
|
||||||
if blockToAdd.ident not in self.vertices[otherSideIdent].blockchain:
|
|
||||||
self.edges[nextEdge].addBlock(blockToAdd, destIdent, self.t)
|
|
||||||
|
|
||||||
class Simulator(object):
|
|
||||||
def __init__(self, params):
|
|
||||||
#todo lol cryptonote style
|
|
||||||
pass
|
|
||||||
|
|
||||||
def go(self):
|
|
||||||
nelly = Network([43, 0.25, 1.0/150.0])
|
|
||||||
self.run(maxTime, birthrate=lambda x:math.exp((-(x-500.0)**2.0))/(2.0*150.0))
|
|
Loading…
Reference in a new issue