mirror of
https://github.com/monero-project/research-lab.git
synced 2024-12-22 19:49:35 +00:00
Architecture present for whole sims and transcripts.
This commit is contained in:
parent
f51f35669a
commit
956c59ad24
17 changed files with 1210 additions and 7324 deletions
File diff suppressed because it is too large
Load diff
|
@ -4,7 +4,7 @@ class Edge(object):
|
||||||
'''
|
'''
|
||||||
Edge object. Has an identity, some data, and a dict of nodes.
|
Edge object. Has an identity, some data, and a dict of nodes.
|
||||||
'''
|
'''
|
||||||
def __init__(self, params=["", {}, True]):
|
def __init__(self, params):
|
||||||
try:
|
try:
|
||||||
assert len(params)==3
|
assert len(params)==3
|
||||||
except AssertionError:
|
except AssertionError:
|
||||||
|
@ -29,66 +29,11 @@ class Edge(object):
|
||||||
|
|
||||||
class Test_Edge(unittest.TestCase):
|
class Test_Edge(unittest.TestCase):
|
||||||
def test_e(self):
|
def test_e(self):
|
||||||
nellyIdent = newIdent(0)
|
nelly = Node(params)
|
||||||
bill = Blockchain([], verbosity=True)
|
milly = Node(params)
|
||||||
|
ed = Edge(params)
|
||||||
name = newIdent(0)
|
ed.nodes.update({nelly.ident:nelly, milly.ident:milly})
|
||||||
t = time.time()
|
self.assertEqual(len(self.nodes),2)
|
||||||
diff = 1.0
|
|
||||||
params = [name, t, t+1, None, diff, bill.verbose] # Genesis block has no parent, so parent = None
|
|
||||||
genesis = Block(params)
|
|
||||||
bill.addBlock(genesis)
|
|
||||||
|
|
||||||
time.sleep(10)
|
|
||||||
|
|
||||||
name = newIdent(1)
|
|
||||||
t = time.time()
|
|
||||||
diff = 1.0
|
|
||||||
params = [name, t, t+1, genesis.ident, diff, bill.verbose]
|
|
||||||
blockA = Block(params)
|
|
||||||
bill.addBlock(blockA)
|
|
||||||
|
|
||||||
# Nodes need an identity and a blockchain object and verbosity and difficulty
|
|
||||||
nelly = Node([nellyIdent, copy.deepcopy(bill), bill.verbosity, diff])
|
|
||||||
nelly.updateDifficulty(mode="Nakamoto")
|
|
||||||
|
|
||||||
time.sleep(9)
|
|
||||||
|
|
||||||
name = newIdent(len(nelly.data))
|
|
||||||
t = time.time()
|
|
||||||
params = [name, t, t+1, blockA.ident, nelly.diff, nelly.verbose]
|
|
||||||
blockB = Block(params)
|
|
||||||
nelly.updateBlockchain({blockB.ident:blockB})
|
|
||||||
|
|
||||||
time.sleep(8)
|
|
||||||
|
|
||||||
name = newIdent(len(nelly.data))
|
|
||||||
t = time.time()
|
|
||||||
params = [name, t, t+1, blockB.ident, nelly.diff, nelly.verbose]
|
|
||||||
blockC = Block(params)
|
|
||||||
nelly.updateBlockchain({blockC.ident:blockC})
|
|
||||||
|
|
||||||
time.sleep(1)
|
|
||||||
name = newIdent(len(nelly.data))
|
|
||||||
t = time.time()
|
|
||||||
params = [name, t, t+1, blockB.ident, nelly.diff, nelly.verbose] # Fork off
|
|
||||||
blockD = Block(params)
|
|
||||||
nelly.updateBlockchain({blockD.ident:blockD})
|
|
||||||
|
|
||||||
time.sleep(7)
|
|
||||||
name = newIdent(len(nelly.data))
|
|
||||||
t = time.time()
|
|
||||||
params = [name, t, t+1, blockD.ident, nelly.diff, nelly.verbose]
|
|
||||||
blockE = Block(params)
|
|
||||||
nelly.updateBlockchain({blockE.ident:blockE})
|
|
||||||
|
|
||||||
|
|
||||||
time.sleep(6)
|
|
||||||
name = newIdent(len(nelly.data))
|
|
||||||
t = time.time()
|
|
||||||
params = [name, t, t+1, blockE.ident, nelly.diff, nelly.verbose]
|
|
||||||
blockF = Block(params)
|
|
||||||
nelly.updateBlockchain({blockF.ident:blockF})
|
|
||||||
|
|
||||||
|
|
||||||
suite = unittest.TestLoader().loadTestsFromTestCase(Test_Edge)
|
suite = unittest.TestLoader().loadTestsFromTestCase(Test_Edge)
|
||||||
|
|
|
@ -1,307 +0,0 @@
|
||||||
import unittest, copy, random, math, time
|
|
||||||
from scipy.stats import skew
|
|
||||||
from numpy import var
|
|
||||||
from numpy import random as nprandom
|
|
||||||
|
|
||||||
#TODO: Node.data["blockchain"] != node.data
|
|
||||||
|
|
||||||
def newIdent(params):
|
|
||||||
nonce = params
|
|
||||||
# Generate new random identity.
|
|
||||||
return hash(str(nonce) + str(random.random()))
|
|
||||||
|
|
||||||
def newIntensity(params):
|
|
||||||
mode = params
|
|
||||||
if mode=="uniform":
|
|
||||||
return random.random()
|
|
||||||
|
|
||||||
def newOffset(params):
|
|
||||||
mode = params
|
|
||||||
if mode=="unifDST":
|
|
||||||
r = 2.0*random.random() - 1.0 # hours
|
|
||||||
r = 60.0*60.0*r #60 min/hr, 60 sec/min
|
|
||||||
return r
|
|
||||||
if mode=="sumOfSkellams":
|
|
||||||
# This mode uses a skellam distribution, which is
|
|
||||||
# the difference of two poisson-distributed random
|
|
||||||
# variables.
|
|
||||||
# HourOffset = skellam
|
|
||||||
# SecondOffset = skellam
|
|
||||||
# TotalOffset = 60*60*HourOffset + 60*MinuteOffset + SecondOffset
|
|
||||||
# Each skellam = poisson(1) - poisson(1)
|
|
||||||
# Reasoning: We consider most computers' local time offset from UTC
|
|
||||||
# to be a two time-scale random variable, one on the hour scale and one on
|
|
||||||
# the second scale. We make
|
|
||||||
x = nprandom.poisson(1, (2,2))
|
|
||||||
totalOffset = 60.0*60.0*float(x[0][0] - x[1][0]) + float((x[0][1] - x[1][1]))
|
|
||||||
return totalOffset
|
|
||||||
|
|
||||||
|
|
||||||
class FishGraph(StochasticProcess):
|
|
||||||
'''
|
|
||||||
Stochastic process on a graph
|
|
||||||
with the graph growing in a stochastic process too
|
|
||||||
'''
|
|
||||||
# TODO: Check if output.txt exists before beginning. If so, clear it and create a new one.
|
|
||||||
# TODO: Instead of/in addition to storing graph data in a text file, can we plot with ggplot in R?
|
|
||||||
def __init__(self, params=None, verbosity=True):
|
|
||||||
# Initialize
|
|
||||||
|
|
||||||
assert "maxTime" in params
|
|
||||||
self.maxTime = copy.deepcopy(params["maxTime"])
|
|
||||||
del params["maxTime"]
|
|
||||||
|
|
||||||
assert "numNodes" in params
|
|
||||||
numNodes = params["numNodes"]
|
|
||||||
del params["numNodes"]
|
|
||||||
|
|
||||||
self.data = params
|
|
||||||
self.t = 0.0
|
|
||||||
self.state = Graph()
|
|
||||||
self.filename = "output.txt"
|
|
||||||
self.verbose = verbosity
|
|
||||||
|
|
||||||
# Create graph
|
|
||||||
self.state.createGraph(numNodes, self.data["probEdge"], self.data["maxNeighbors"])
|
|
||||||
|
|
||||||
# Update node data
|
|
||||||
for nIdent in self.state.nodes:
|
|
||||||
n = self.state.nodes[nIdent]
|
|
||||||
difficulty = 1.0
|
|
||||||
intensity = newIntensity(params="uniform")
|
|
||||||
offset = newOffset(params="sumOfSkellams")
|
|
||||||
dat = {"intensity":intensity, "offset":offset, "blockchain":Blockchain([], verbosity=self.verbose)}
|
|
||||||
n.data.update(dat)
|
|
||||||
|
|
||||||
# Update edge data.
|
|
||||||
for eIdent in self.state.edges:
|
|
||||||
e = self.state.edges[eIdent]
|
|
||||||
e.data.update({"pendingBlocks":{}})
|
|
||||||
|
|
||||||
def go(self):
|
|
||||||
assert self.maxTime > 0.0
|
|
||||||
while self.t <= self.maxTime and len(self.state.nodes) > 0:
|
|
||||||
deltaT = self.getNextTime()
|
|
||||||
self.updateState(self.t, deltaT)
|
|
||||||
self.record()
|
|
||||||
|
|
||||||
def getNextTime(self):
|
|
||||||
# Each Poisson process event generates an exponential random variable.
|
|
||||||
# The smallest of these is selected
|
|
||||||
# The rate of the smallest determines event type.
|
|
||||||
eventTag = None
|
|
||||||
|
|
||||||
u = 0.0
|
|
||||||
while(u == 0.0):
|
|
||||||
u = copy.deepcopy(random.random())
|
|
||||||
u = -1.0*math.log(copy.deepcopy(u))/self.data["birthRate"] # Time until next stochastic birth
|
|
||||||
eventTag = "birth"
|
|
||||||
|
|
||||||
v = 0.0
|
|
||||||
while(v == 0.0):
|
|
||||||
v = copy.deepcopy(random.random())
|
|
||||||
v = -1.0*math.log(copy.deepcopy(v))/self.data["deathRate"] # Time until next stochastic death
|
|
||||||
if v < u:
|
|
||||||
u = copy.deepcopy(v)
|
|
||||||
eventTag = "death"
|
|
||||||
|
|
||||||
for nIdent in self.state.nodes:
|
|
||||||
n = self.state.nodes[nIdent] # n.ident = nIdent
|
|
||||||
v = 0.0
|
|
||||||
while(v == 0.0):
|
|
||||||
v = copy.deepcopy(random.random())
|
|
||||||
v = -1.0*math.log(copy.deepcopy(v))/n.data["intensity"]
|
|
||||||
if v < u:
|
|
||||||
u = copy.deepcopy(v)
|
|
||||||
eventTag = ["discovery", n.ident]
|
|
||||||
|
|
||||||
# Now that all the STOCHASTIC arrivals have been decided,
|
|
||||||
# We check if any of the deterministic events fire off instead.
|
|
||||||
for eIdent in self.state.edges:
|
|
||||||
e = self.state.edges[eIdent] # e.ident = eIdent
|
|
||||||
pB = e.data["pendingBlocks"]
|
|
||||||
if len(pB) > 0:
|
|
||||||
for pendingIdent in pB:
|
|
||||||
arrivalInfo = pB[pendingIdent]
|
|
||||||
v = arrivalInfo["timeOfArrival"] - self.t
|
|
||||||
if v < u and 0.0 < v:
|
|
||||||
u = copy.deepcopy(v)
|
|
||||||
eventTag = ["arrival", e.ident, pendingIdent]
|
|
||||||
|
|
||||||
deltaT = (u, eventTag)
|
|
||||||
# Formats:
|
|
||||||
# eventTag = ["arrival", e.ident, pendingIdent]
|
|
||||||
# eventTag = ["discovery", n.ident]
|
|
||||||
# eventTag = "death"
|
|
||||||
# eventTag = "birth"
|
|
||||||
return deltaT
|
|
||||||
|
|
||||||
def updateState(self, t, deltaT, mode="Nakamoto", targetRate=1.0/1209600.0):
|
|
||||||
# Depending on eventTag, update the state...
|
|
||||||
u = deltaT[0]
|
|
||||||
shout = ""
|
|
||||||
eventTag = deltaT[1]
|
|
||||||
|
|
||||||
if type(eventTag)==type("birthordeath"):
|
|
||||||
if eventTag == "death":
|
|
||||||
# Picks random nodeIdent and kills it
|
|
||||||
toDie = random.choice(list(self.state.nodes.keys()))
|
|
||||||
x = len(self.state.nodes)
|
|
||||||
shout += "DEATH, Pop(Old)=" + str(x) + ", Pop(New)="
|
|
||||||
if self.verbose:
|
|
||||||
print(shout)
|
|
||||||
self.state.delNode(toDie)
|
|
||||||
y = len(self.state.nodes)
|
|
||||||
assert y == x - 1
|
|
||||||
shout += str(y) + "\n"
|
|
||||||
|
|
||||||
elif eventTag == "birth":
|
|
||||||
# Adds node with some randomly determined edges
|
|
||||||
x = len(self.state.nodes)
|
|
||||||
shout += "BIRTH, Pop(Old)=" + str(x) + ", Pop(New)="
|
|
||||||
if self.verbose:
|
|
||||||
print(shout)
|
|
||||||
nIdent = self.state.addNode()
|
|
||||||
n = self.state.nodes[nIdent]
|
|
||||||
intensity = random.random()/1000.0
|
|
||||||
offset = 2.0*random.random() - 1.0
|
|
||||||
n.data.update({"intensity":intensity, "offset":offset, "blockchain":{}})
|
|
||||||
# Auto syncs new node.
|
|
||||||
for eIdent in n.edges:
|
|
||||||
e = n.edges[eIdent]
|
|
||||||
e.data.update({"pendingBlocks":{}})
|
|
||||||
mIdent = e.getNeighbor(n.ident)
|
|
||||||
m = self.state.nodes[mIdent]
|
|
||||||
mdata = m.data["blockchain"]
|
|
||||||
n.updateBlockchain(mdata)
|
|
||||||
y = len(self.state.nodes)
|
|
||||||
assert y == x + 1
|
|
||||||
shout += str(y) + "\n"
|
|
||||||
else:
|
|
||||||
print("Error: eventTag had length 1 but was neighter a birth or a death, this shouldn't happen so this else case will eventually be removed, I guess? Our eventTag = ", eventTag)
|
|
||||||
elif len(eventTag)==2:
|
|
||||||
# Block is discovered and plunked into each edge's pendingBlock list.
|
|
||||||
|
|
||||||
shout += "DISCOVERY\n"
|
|
||||||
if self.verbose:
|
|
||||||
print(shout)
|
|
||||||
|
|
||||||
if self.verbose:
|
|
||||||
print("Checking formation of eventTag = [\"discovery\", nodeIdent]")
|
|
||||||
assert eventTag[0]=="discovery"
|
|
||||||
assert eventTag[1] in self.state.nodes
|
|
||||||
|
|
||||||
if self.verbose:
|
|
||||||
print("Retrieving discoverer's identity")
|
|
||||||
nIdent = eventTag[1] # get founding node's identity
|
|
||||||
|
|
||||||
if self.verbose:
|
|
||||||
print("Retrieving discoverer")
|
|
||||||
n = self.state.nodes[nIdent] # get founding node
|
|
||||||
|
|
||||||
if self.verbose:
|
|
||||||
print("Computing discoverer's wall clock")
|
|
||||||
s = self.t + n.data["offset"] # get founding node's wall clock
|
|
||||||
|
|
||||||
|
|
||||||
if self.verbose:
|
|
||||||
print("Generating new block identity")
|
|
||||||
newBlockIdent = newIdent(len(n.data["blockchain"].blocks)) # generate new identity
|
|
||||||
|
|
||||||
if self.verbose:
|
|
||||||
print("Setting timestamps")
|
|
||||||
disco = s
|
|
||||||
arriv = s
|
|
||||||
|
|
||||||
if self.verbose:
|
|
||||||
print("Retrieving parent")
|
|
||||||
parent = n.data["blockchain"].miningIdent
|
|
||||||
|
|
||||||
if self.verbose:
|
|
||||||
print("getting difficulty")
|
|
||||||
diff = copy.deepcopy(n.diff)
|
|
||||||
|
|
||||||
if self.verbose:
|
|
||||||
print("setting verbosity")
|
|
||||||
verbosity = self.verbose
|
|
||||||
|
|
||||||
if self.verbose:
|
|
||||||
print("Initializing a new block")
|
|
||||||
newBlock = Block([newBlockIdent, disco, arriv, parent, diff, verbosity])
|
|
||||||
|
|
||||||
if self.verbose:
|
|
||||||
print("Updating discovering node's blockchain")
|
|
||||||
n.updateBlockchain({newBlockIdent:newBlock})
|
|
||||||
|
|
||||||
if self.verbose:
|
|
||||||
print("Computing discoverer's new difficulty")
|
|
||||||
n.updateDifficulty(mode, targetRate)
|
|
||||||
|
|
||||||
if self.verbose:
|
|
||||||
print("propagating new block.")
|
|
||||||
n.propagate(self.t, newBlockIdent)
|
|
||||||
|
|
||||||
if self.verbose:
|
|
||||||
print("discovery complete")
|
|
||||||
|
|
||||||
elif len(eventTag)==3:
|
|
||||||
#eventTag = ("arrival", e.ident, pendingIdent)
|
|
||||||
# A block deterministically arrives at the end of an edge.
|
|
||||||
|
|
||||||
assert eventTag[0]=="arrival"
|
|
||||||
shout += "ARRIVAL"
|
|
||||||
if self.verbose:
|
|
||||||
print(shout)
|
|
||||||
|
|
||||||
eIdent = eventTag[1]
|
|
||||||
pendingIdent = eventTag[2]
|
|
||||||
e = self.state.edges[eIdent]
|
|
||||||
pB = e.data["pendingBlocks"]
|
|
||||||
arrivalInfo = pB[pendingIdent] # arrivalInfo = {"timeOfArrival":toa, "destIdent":mIdent, "block":newBlock}
|
|
||||||
|
|
||||||
assert arrivalInfo["destIdent"] in self.state.nodes
|
|
||||||
assert self.t + u == arrivalInfo["timeOfArrival"]
|
|
||||||
receiver = self.state.nodes[arrivalInfo["destIdent"]]
|
|
||||||
arriv = self.t + u + receiver.data["offset"]
|
|
||||||
newBlock = arrivalInfo["block"]
|
|
||||||
newBlock.arrivTimestamp = copy.deepcopy(arriv)
|
|
||||||
receiver.updateBlockchain({newBlock.ident:newBlock})
|
|
||||||
receiver.updateDifficulty(mode, targetRate)
|
|
||||||
receiver.propagate(self.t, newBlock.ident)
|
|
||||||
|
|
||||||
else:
|
|
||||||
print("Error: eventTag was not a string, or not an array length 2 or 3. In fact, we have eventTag = ", eventTag)
|
|
||||||
|
|
||||||
if self.verbose:
|
|
||||||
print("u = ", u)
|
|
||||||
self.t += u
|
|
||||||
if self.verbose:
|
|
||||||
print(str(self.t) + "\t" + shout)
|
|
||||||
|
|
||||||
def record(self):
|
|
||||||
with open(self.filename, "a") as f:
|
|
||||||
line = ""
|
|
||||||
# Format will be edgeIdent,nodeAident,nodeBident
|
|
||||||
line += str("t=" + str(self.t) + ",")
|
|
||||||
ordKeyList = sorted(list(self.state.edges.keys()))
|
|
||||||
for key in ordKeyList:
|
|
||||||
entry = []
|
|
||||||
entry.append(key)
|
|
||||||
nodeKeyList = sorted(list(self.state.edges[key].nodes))
|
|
||||||
for kkey in nodeKeyList:
|
|
||||||
entry.append(kkey)
|
|
||||||
line += str(entry) + ","
|
|
||||||
f.write(line + "\n")
|
|
||||||
|
|
||||||
class Test_FishGraph(unittest.TestCase):
|
|
||||||
def test_fishGraph(self):
|
|
||||||
for i in range(10):
|
|
||||||
params = {"numNodes":10, "probEdge":0.5, "maxNeighbors":10, "maxTime":10.0, "birthRate":0.1, "deathRate":0.1}
|
|
||||||
greg = FishGraph(params, verbosity=True)
|
|
||||||
greg.go()
|
|
||||||
|
|
||||||
|
|
||||||
suite = unittest.TestLoader().loadTestsFromTestCase(Test_FishGraph)
|
|
||||||
unittest.TextTestRunner(verbosity=1).run(suite)
|
|
||||||
|
|
||||||
|
|
|
@ -1,101 +1,187 @@
|
||||||
from Edge import *
|
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):
|
class Graph(object):
|
||||||
'''
|
'''
|
||||||
Graph object. Contains some data, a dict of nodes, and a dict of edges.
|
Explanation
|
||||||
'''
|
'''
|
||||||
def __init__(self, params={}, verbosity=True):
|
def __init__(self, params):
|
||||||
self.data=params
|
|
||||||
self.verbose = verbosity
|
|
||||||
self.nodes = {}
|
self.nodes = {}
|
||||||
self.edges = {}
|
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.data = params[9]
|
||||||
|
|
||||||
def createGraph(self, numNodes, probEdge, maxNeighbors):
|
self.blankBlockchain = Blockchain()
|
||||||
# Create a new random graph with numNodes nodes, a
|
self.blankBlockchain.targetRate = self.data["targetRate"]
|
||||||
# likelihood any unordered pair of vertices has an edge
|
self.blankBlockchain.mode = self.data["mode"]
|
||||||
# probEdge, and maximum number of neighbors per node
|
|
||||||
# maxNeighbors.
|
|
||||||
|
|
||||||
# First, include inputted information into self.data
|
self._createInit()
|
||||||
self.data.update({"probEdge":probEdge, "maxNeighbors":maxNeighbors})
|
|
||||||
|
|
||||||
|
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()
|
||||||
|
intens = newIntensity()
|
||||||
|
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, i)
|
||||||
|
|
||||||
|
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.ndoes[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)), {}, 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 and iStillHasRoom and random.random() < self.probEdge:
|
||||||
|
neighbors.append(xNode)
|
||||||
|
|
||||||
|
|
||||||
|
newNodeName = newIdent(len(self.nodes))
|
||||||
|
offset = newOffset()
|
||||||
|
intens = newIntensity()
|
||||||
|
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:
|
||||||
|
neighbors.append((ed.Ident, ed.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, destNodeIdent, edgeIdent, blockIdent, t):
|
||||||
|
out = str(t) + ",blockArriv," + str(destNodeIdent) + "," + str(edgeIdent) + "," + str(blockIdent) + ","
|
||||||
|
destNode = self.nodes[destNodeIdent]
|
||||||
|
edge = self.edges[edgeIdent]
|
||||||
|
block = deepcopy(edge.data["pendingBlocks"][blockIdent])
|
||||||
|
block.arrivTimestamp = t + self.nodes[destNodeIdent].data["offset"]
|
||||||
|
self.nodes[destNodeIdent].updateBlockchain({blockIdent:block})
|
||||||
|
return out
|
||||||
|
|
||||||
|
def go(self):
|
||||||
|
with open(self.filename,"w") as writeFile:
|
||||||
|
writeFile.write("timestamp,eventId,eventData\n")
|
||||||
|
|
||||||
|
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] # pendingDat = {"timeOfArrival":timeOfArrival, "destIdent":otherIdent, "block":blockToProp}
|
||||||
|
if pendingData["timeOfArrival"] - self.globalTime < u:
|
||||||
|
eventTime = ("blockArriv", (pendingData["destIdent"], edgeIdent, pendingData["block"]))
|
||||||
|
u = v
|
||||||
|
|
||||||
|
self.globalTime += u
|
||||||
|
out = ""
|
||||||
|
if eventTime[0] == "nodeJoins":
|
||||||
|
out = self.eventNodeJoins(self.globalTime)
|
||||||
|
elif eventTime[0] == "nodeLeaves":
|
||||||
|
out = self.eventNodeLeaves(self.globalTime)
|
||||||
|
elif eventTime[0] == "blockDisco":
|
||||||
|
out = self.eventBlockDiscovery(eventTime[1], self.globalTime)
|
||||||
|
elif eventTime[0] == "blockArriv":
|
||||||
|
out = self.eventBlockArrival(eventTime[1], eventTime[2], eventTime[3], self.globalTime)
|
||||||
|
else:
|
||||||
|
print("WHAAAA")
|
||||||
|
|
||||||
|
with open(self.filename, "a") as writeFile:
|
||||||
|
writeFile.write(out + "\n")
|
||||||
|
|
||||||
# Next, for each node to be added, create the node and name it.
|
|
||||||
for i in range(numNodes):
|
|
||||||
nIdent = newIdent(i)
|
|
||||||
bl = Blockchain([], verbosity=True)
|
|
||||||
dat = {"blockchain":bl, "intensity":newIntensity(["uniform"]), "offset":newOffset("sumOfSkellams")}
|
|
||||||
# A node needs an ident, a data object, a verbosity, and a difficulty
|
|
||||||
n = Node([nIdent, dat, self.verbose, 1.0])
|
|
||||||
self.nodes.update({n.ident:n})
|
|
||||||
|
|
||||||
# Next, for each possible node pair, decide if an edge exists.
|
|
||||||
touched = {} # Dummy list of node pairs we have already considered.
|
|
||||||
for nIdent in self.nodes:
|
|
||||||
n = self.nodes[nIdent] # Pick a node
|
|
||||||
for mIdent in self.nodes:
|
|
||||||
m = self.nodes[mIdent] # Pick a pair element
|
|
||||||
notSameNode = (nIdent != mIdent) # Ensure we aren't dealing with (x,x)
|
|
||||||
nOpenSlots = (len(n.edges) < self.data["maxNeighbors"]) # ensure both nodes have open slots available for new edges
|
|
||||||
mOpenSlots = (len(m.edges) < self.data["maxNeighbors"])
|
|
||||||
untouched = ((nIdent, mIdent) not in touched) # make sure the pair and its transposition have not been touched
|
|
||||||
dehcuotnu = ((mIdent, nIdent) not in touched)
|
|
||||||
if notSameNode and nOpenSlots and mOpenSlots and untouched and dehcuotnu:
|
|
||||||
# Mark pair as touhed
|
|
||||||
touched.update({(nIdent,mIdent):True, (mIdent,nIdent):True})
|
|
||||||
if random.random() < self.data["probEdge"]:
|
|
||||||
# Determine if edge should exist and if so, add it.
|
|
||||||
nonce = len(self.edges)
|
|
||||||
e = Edge([newIdent(nonce),{"length":random.random(), "pendingBlocks":[]},self.verbose])
|
|
||||||
e.nodes.update({n.ident:n, m.ident:m})
|
|
||||||
self.nodes[nIdent].edges.update({e.ident:e})
|
|
||||||
self.nodes[mIdent].edges.update({e.ident:e})
|
|
||||||
self.edges.update({e.ident:e})
|
|
||||||
|
|
||||||
def addNode(self):
|
|
||||||
# Add new node
|
|
||||||
n = Node([newIdent(len(self.nodes)), {}, self.verbose, 1.0])
|
|
||||||
self.nodes.update({n.ident:n})
|
|
||||||
for mIdent in self.nodes:
|
|
||||||
# For every other node, check if an edge should exist and if so add it.
|
|
||||||
m = self.nodes[mIdent]
|
|
||||||
notSameNode = (n.ident != mIdent)
|
|
||||||
nOpenSlots = (len(n.edges) < self.data["maxNeighbors"])
|
|
||||||
mOpenSlots = (len(m.edges) < self.data["maxNeighbors"])
|
|
||||||
if notSameNode and nOpenSlots and mOpenSlots and random.random() < self.data["probEdge"]:
|
|
||||||
nonce = len(self.edges)
|
|
||||||
e = Edge([newIdent(nonce), {"length":random.random(), "pendingBlocks":[]}, self.verbose])
|
|
||||||
e.nodes.update({n.ident:n, m.ident:m})
|
|
||||||
n.edges.update({e.ident:e})
|
|
||||||
self.nodes[mIdent].edges.update({e.ident:e})
|
|
||||||
self.edges.update({e.ident:e})
|
|
||||||
return n.ident
|
|
||||||
|
|
||||||
def delNode(self, ident):
|
|
||||||
# Remove a node and wipe all memory of its edges from history.
|
|
||||||
edgesToDelete = self.nodes[ident].edges
|
|
||||||
for edgeIdent in edgesToDelete:
|
|
||||||
e = edgesToDelete[edgeIdent]
|
|
||||||
otherIdent = e.getNeighbor(ident)
|
|
||||||
del self.edges[edgeIdent]
|
|
||||||
del self.nodes[otherIdent].edges[edgeIdent]
|
|
||||||
del self.nodes[ident]
|
|
||||||
|
|
||||||
class Test_Graph(unittest.TestCase):
|
|
||||||
def test_graph(self):
|
|
||||||
greg = Graph()
|
|
||||||
greg.createGraph(3, 0.5, 10)
|
|
||||||
self.assertEqual(len(greg.nodes),3)
|
|
||||||
greg.addNode()
|
|
||||||
self.assertEqual(len(greg.nodes),4)
|
|
||||||
for edge in greg.edges:
|
|
||||||
self.assertEqual(len(greg.edges[edge].nodes),2)
|
|
||||||
nodeToKill = random.choice(list(greg.nodes.keys()))
|
|
||||||
greg.delNode(nodeToKill)
|
|
||||||
for edge in greg.edges:
|
|
||||||
self.assertEqual(len(greg.edges[edge].nodes),2)
|
|
||||||
for nodeIdent in greg.edges[edge].nodes:
|
|
||||||
self.assertTrue(nodeIdent in greg.nodes)
|
|
||||||
|
|
||||||
suite = unittest.TestLoader().loadTestsFromTestCase(Test_Graph)
|
|
||||||
unittest.TextTestRunner(verbosity=1).run(suite)
|
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,53 +0,0 @@
|
||||||
import unittest, random, time
|
|
||||||
|
|
||||||
class StochasticProcess(object):
|
|
||||||
'''
|
|
||||||
Stochastic processes have a clock and a state.
|
|
||||||
The clock moves forward, and then the state updates.
|
|
||||||
More detail requires knowledge of the underlying stochProc.
|
|
||||||
'''
|
|
||||||
def __init__(self, params=None):
|
|
||||||
# initialize with initial data
|
|
||||||
self.data = params
|
|
||||||
self.t = 0.0 # should always start at t=0.0
|
|
||||||
self.state = 0.0 # magic number
|
|
||||||
self.maxTime = 1000.0 # magic number
|
|
||||||
self.saveFile = "output.csv"
|
|
||||||
self.verbose = True
|
|
||||||
|
|
||||||
def go(self):
|
|
||||||
# Executes stochastic process.
|
|
||||||
assert self.maxTime > 0.0 # Check loop will eventually terminate.
|
|
||||||
t = self.t
|
|
||||||
while t <= self.maxTime:
|
|
||||||
deltaT = self.getNextTime() # Pick the next "time until event" and a description of the event.
|
|
||||||
self.updateState(t, deltaT) # Update state with deltaT input
|
|
||||||
t = self.t
|
|
||||||
if self.verbose:
|
|
||||||
print("Recording...")
|
|
||||||
self.record()
|
|
||||||
|
|
||||||
def getNextTime(self):
|
|
||||||
return 1 # Magic number right now
|
|
||||||
|
|
||||||
def updateState(self, t, deltaT):
|
|
||||||
# Update the state of the system. In this case,
|
|
||||||
# we are doing a random walk on the integers.
|
|
||||||
self.state += random.randrange(-1,2,1) # [-1, 0, 1]
|
|
||||||
self.t += deltaT
|
|
||||||
|
|
||||||
def record(self):
|
|
||||||
with open(self.saveFile,"w") as recordKeeper:
|
|
||||||
line = str(self.t) + ",\t" + str(self.state) + "\n"
|
|
||||||
recordKeeper.write(line)
|
|
||||||
|
|
||||||
class Test_StochasticProcess(unittest.TestCase):
|
|
||||||
def test_sp(self):
|
|
||||||
sally = StochasticProcess()
|
|
||||||
sally.verbose = False
|
|
||||||
sally.go()
|
|
||||||
|
|
||||||
suite = unittest.TestLoader().loadTestsFromTestCase(Test_StochasticProcess)
|
|
||||||
unittest.TextTestRunner(verbosity=1).run(suite)
|
|
||||||
|
|
||||||
|
|
|
@ -1,46 +0,0 @@
|
||||||
import unittest, random, time
|
|
||||||
|
|
||||||
def newIdent(params):
|
|
||||||
nonce = params
|
|
||||||
# Generate new random identity.
|
|
||||||
return hash(str(nonce) + str(random.random()))
|
|
||||||
#### #### #### #### #### #### #### #### #### #### #### #### #### #### #### ####
|
|
||||||
class Block(object):
|
|
||||||
'''
|
|
||||||
Each block has: an identity, a timestamp of discovery (possibly false),
|
|
||||||
has a timestamp of arrival at the local node (possibly unnecessary), a
|
|
||||||
parent block's identity, and a difficulty score.
|
|
||||||
'''
|
|
||||||
def __init__(self, params={}):
|
|
||||||
self.ident = None
|
|
||||||
self.discoTimestamp = None
|
|
||||||
self.arrivTimestamp = None
|
|
||||||
self.parent = None
|
|
||||||
self.diff = None
|
|
||||||
try:
|
|
||||||
assert len(params)==5
|
|
||||||
except AssertionError:
|
|
||||||
print("Error in Block(): Tried to add a malformed block. We received params = " + str(params) + ", but should have had something of the form {\"ident\":ident, \"disco\":disco, \"arriv\":arriv, \"parent\":parent, \"diff\":diff}.")
|
|
||||||
self.ident = params["ident"]
|
|
||||||
self.discoTimestamp = params["disco"]
|
|
||||||
self.arrivTimestamp = params["arriv"]
|
|
||||||
self.parent = params["parent"]
|
|
||||||
self.diff = params["diff"]
|
|
||||||
|
|
||||||
class Test_Block(unittest.TestCase):
|
|
||||||
def test_b(self):
|
|
||||||
#bill = Block()
|
|
||||||
name = newIdent(0)
|
|
||||||
t = time.time()
|
|
||||||
s = t+1
|
|
||||||
diff = 1.0
|
|
||||||
params = {"ident":name, "disco":t, "arriv":s, "parent":None, "diff":diff}
|
|
||||||
bill = Block(params)
|
|
||||||
self.assertEqual(bill.ident,name)
|
|
||||||
self.assertEqual(bill.discoTimestamp,t)
|
|
||||||
self.assertEqual(bill.arrivTimestamp,t+1)
|
|
||||||
self.assertTrue(bill.parent is None)
|
|
||||||
self.assertEqual(bill.diff,diff)
|
|
||||||
|
|
||||||
suite = unittest.TestLoader().loadTestsFromTestCase(Test_Block)
|
|
||||||
unittest.TextTestRunner(verbosity=1).run(suite)
|
|
|
@ -1,46 +0,0 @@
|
||||||
import unittest, random, time
|
|
||||||
|
|
||||||
def newIdent(params):
|
|
||||||
nonce = params
|
|
||||||
# Generate new random identity.
|
|
||||||
return hash(str(nonce) + str(random.random()))
|
|
||||||
#### #### #### #### #### #### #### #### #### #### #### #### #### #### #### ####
|
|
||||||
class Block(object):
|
|
||||||
'''
|
|
||||||
Each block has: an identity, a timestamp of discovery (possibly false),
|
|
||||||
has a timestamp of arrival at the local node (possibly unnecessary), a
|
|
||||||
parent block's identity, and a difficulty score.
|
|
||||||
'''
|
|
||||||
def __init__(self, params={}):
|
|
||||||
self.ident = None
|
|
||||||
self.discoTimestamp = None
|
|
||||||
self.arrivTimestamp = None
|
|
||||||
self.parent = None
|
|
||||||
self.diff = None
|
|
||||||
try:
|
|
||||||
assert len(params)==5
|
|
||||||
except AssertionError:
|
|
||||||
print("Error in Block(): Tried to add a malformed block. We received params = " + str(params) + ", but should have had something of the form {\"ident\":ident, \"disco\":disco, \"arriv\":arriv, \"parent\":parent, \"diff\":diff}.")
|
|
||||||
self.ident = params["ident"]
|
|
||||||
self.discoTimestamp = params["disco"]
|
|
||||||
self.arrivTimestamp = params["arriv"]
|
|
||||||
self.parent = params["parent"]
|
|
||||||
self.diff = params["diff"]
|
|
||||||
|
|
||||||
class Test_Block(unittest.TestCase):
|
|
||||||
def test_b(self):
|
|
||||||
#bill = Block()
|
|
||||||
name = newIdent(0)
|
|
||||||
t = time.time()
|
|
||||||
s = t+1
|
|
||||||
diff = 1.0
|
|
||||||
params = {"ident":name, "disco":t, "arriv":s, "parent":None, "diff":diff}
|
|
||||||
bill = Block(params)
|
|
||||||
self.assertEqual(bill.ident,name)
|
|
||||||
self.assertEqual(bill.discoTimestamp,t)
|
|
||||||
self.assertEqual(bill.arrivTimestamp,t+1)
|
|
||||||
self.assertTrue(bill.parent is None)
|
|
||||||
self.assertEqual(bill.diff,diff)
|
|
||||||
|
|
||||||
suite = unittest.TestLoader().loadTestsFromTestCase(Test_Block)
|
|
||||||
unittest.TextTestRunner(verbosity=1).run(suite)
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,116 +0,0 @@
|
||||||
from Blockchain import *
|
|
||||||
|
|
||||||
class Node(object):
|
|
||||||
'''
|
|
||||||
Node object. params [identity, blockchain (data), verbosity, difficulty]
|
|
||||||
'''
|
|
||||||
def __init__(self, params={}):
|
|
||||||
try:
|
|
||||||
assert len(params)==5
|
|
||||||
except AssertionError:
|
|
||||||
print("Error, Tried to create malformed node.")
|
|
||||||
else:
|
|
||||||
self.ident = params["ident"]
|
|
||||||
self.data = params["data"]
|
|
||||||
self.verbose = params["verbose"]
|
|
||||||
self.edges = {}
|
|
||||||
self.mode = params["mode"]
|
|
||||||
self.targetRate = params["targetRate"]
|
|
||||||
|
|
||||||
def generateBlock(self, discoTime, nonce):
|
|
||||||
newName = newIdent(nonce)
|
|
||||||
t = discoTime
|
|
||||||
s = t+self.data["offset"]
|
|
||||||
diff = self.data["blockchain"].diff
|
|
||||||
params = {"ident":name, "disco":t, "arriv":s, "parent":None, "diff":diff}
|
|
||||||
newBlock = Block(params)
|
|
||||||
self.data["blockchain"].addBlock(newBlock, mode, tr)
|
|
||||||
return newName
|
|
||||||
|
|
||||||
def updateBlockchain(self, incBlocks):
|
|
||||||
# incBlocks shall be a dictionary of block identities (as keys) and their associated blocks (as values)
|
|
||||||
# to be added to the local data. We assume difficulty scores have been reported honestly for now.
|
|
||||||
|
|
||||||
tempData = copy.deepcopy(incBlocks)
|
|
||||||
for key in incBlocks:
|
|
||||||
if key in self.data["blockchain"].blocks:
|
|
||||||
del tempData[key]
|
|
||||||
elif incBlocks[key].parent in self.data["blockchain"].blocks or incBlocks[key].parent is None:
|
|
||||||
self.data["blockchain"].addBlock(incBlocks[key], self.mode, self.targetRate)
|
|
||||||
del tempData[key]
|
|
||||||
incBlocks = copy.deepcopy(tempData)
|
|
||||||
while len(incBlocks)>0:
|
|
||||||
for key in incBlocks:
|
|
||||||
if key in self.data["blockchain"].blocks:
|
|
||||||
del tempData[key]
|
|
||||||
elif incBlocks[key].parent in self.data["blockchain"].blocks:
|
|
||||||
self.data["blockchain"].addBlock(incBlocks[key], self.mode, self.targetRate)
|
|
||||||
del tempData[key]
|
|
||||||
incBlocks = copy.deepcopy(tempData)
|
|
||||||
|
|
||||||
def propagate(self, timeOfProp, blockIdent):
|
|
||||||
for edgeIdent in self.edges:
|
|
||||||
edge = self.edges[edgeIdent]
|
|
||||||
length = e.data["length"]
|
|
||||||
timeOfArrival = timeOfProp + length
|
|
||||||
otherIdent = e.getNeighbor(self.ident)
|
|
||||||
other = e.nodes[otherIdent]
|
|
||||||
bc = other.data["blockchain"]
|
|
||||||
if blockIdent not in bc.blocks:
|
|
||||||
pB = e.data["pendingBlocks"]
|
|
||||||
pendingIdent = newIdent(len(pB))
|
|
||||||
mybc = self.data["blockchain"]
|
|
||||||
blockToProp = mybc.blocks[blockIdent]
|
|
||||||
pendingDat = {"timeOfArrival":timeOfArrival, "destIdent":otherIdent, "block":blockToProp}
|
|
||||||
pB.update({pendingIdent:pendingDat})
|
|
||||||
|
|
||||||
|
|
||||||
class Test_Node(unittest.TestCase):
|
|
||||||
# TODO test each method separately
|
|
||||||
def test_all(self):
|
|
||||||
bill = Blockchain([], verbosity=True)
|
|
||||||
mode="Nakamoto"
|
|
||||||
tr = 1.0/600000.0
|
|
||||||
deltaT = 600000.0
|
|
||||||
bill.targetRate = tr
|
|
||||||
|
|
||||||
name = newIdent(0)
|
|
||||||
t = 0.0
|
|
||||||
s = t
|
|
||||||
diff = 1.0
|
|
||||||
params = {"ident":name, "disco":t, "arriv":s, "parent":None, "diff":diff}
|
|
||||||
genesis = Block(params)
|
|
||||||
bill.addBlock(genesis, mode, tr)
|
|
||||||
|
|
||||||
parent = genesis.ident
|
|
||||||
|
|
||||||
nellyname = newIdent(time.time())
|
|
||||||
mode = "Nakamoto"
|
|
||||||
targetRate = 1.0/600000.0
|
|
||||||
params = {"ident":nellyname, "data":{"offset":0.0, "intensity":1.0, "blockchain":bill}, "verbose":True, "mode":mode, "targetRate":targetRate}
|
|
||||||
nelly = Node(params)
|
|
||||||
|
|
||||||
while len(nelly.data["blockchain"].blocks) < 2015:
|
|
||||||
name = newIdent(0)
|
|
||||||
diff = nelly.data["blockchain"].diff
|
|
||||||
t += deltaT*diff*(2.0*random.random()-1.0)
|
|
||||||
s = t
|
|
||||||
params = {"ident":name, "disco":t, "arriv":s, "parent":parent, "diff":diff}
|
|
||||||
newBlock = Block(params)
|
|
||||||
bill.addBlock(newBlock, mode, tr)
|
|
||||||
parent = name
|
|
||||||
|
|
||||||
|
|
||||||
while len(nelly.data["blockchain"].blocks) < 5000:
|
|
||||||
name = newIdent(0)
|
|
||||||
diff = nelly.data["blockchain"].diff
|
|
||||||
t += deltaT*diff
|
|
||||||
s = t
|
|
||||||
params = {"ident":name, "disco":t, "arriv":s, "parent":parent, "diff":diff}
|
|
||||||
newBlock = Block(params)
|
|
||||||
bill.addBlock(newBlock, mode, tr)
|
|
||||||
parent = name
|
|
||||||
|
|
||||||
suite = unittest.TestLoader().loadTestsFromTestCase(Test_Node)
|
|
||||||
unittest.TextTestRunner(verbosity=1).run(suite)
|
|
||||||
|
|
|
@ -1,116 +0,0 @@
|
||||||
from Blockchain import *
|
|
||||||
|
|
||||||
class Node(object):
|
|
||||||
'''
|
|
||||||
Node object. params [identity, blockchain (data), verbosity, difficulty]
|
|
||||||
'''
|
|
||||||
def __init__(self, params={}):
|
|
||||||
try:
|
|
||||||
assert len(params)==5
|
|
||||||
except AssertionError:
|
|
||||||
print("Error, Tried to create malformed node.")
|
|
||||||
else:
|
|
||||||
self.ident = params["ident"]
|
|
||||||
self.data = params["data"]
|
|
||||||
self.verbose = params["verbose"]
|
|
||||||
self.edges = {}
|
|
||||||
self.mode = params["mode"]
|
|
||||||
self.targetRate = params["targetRate"]
|
|
||||||
|
|
||||||
def generateBlock(self, discoTime, nonce):
|
|
||||||
newName = newIdent(nonce)
|
|
||||||
t = discoTime
|
|
||||||
s = t+self.data["offset"]
|
|
||||||
diff = self.data["blockchain"].diff
|
|
||||||
params = {"ident":name, "disco":t, "arriv":s, "parent":None, "diff":diff}
|
|
||||||
newBlock = Block(params)
|
|
||||||
self.data["blockchain"].addBlock(newBlock, mode, tr)
|
|
||||||
return newName
|
|
||||||
|
|
||||||
def updateBlockchain(self, incBlocks):
|
|
||||||
# incBlocks shall be a dictionary of block identities (as keys) and their associated blocks (as values)
|
|
||||||
# to be added to the local data. We assume difficulty scores have been reported honestly for now.
|
|
||||||
|
|
||||||
tempData = copy.deepcopy(incBlocks)
|
|
||||||
for key in incBlocks:
|
|
||||||
if key in self.data["blockchain"].blocks:
|
|
||||||
del tempData[key]
|
|
||||||
elif incBlocks[key].parent in self.data["blockchain"].blocks or incBlocks[key].parent is None:
|
|
||||||
self.data["blockchain"].addBlock(incBlocks[key], self.mode, self.targetRate)
|
|
||||||
del tempData[key]
|
|
||||||
incBlocks = copy.deepcopy(tempData)
|
|
||||||
while len(incBlocks)>0:
|
|
||||||
for key in incBlocks:
|
|
||||||
if key in self.data["blockchain"].blocks:
|
|
||||||
del tempData[key]
|
|
||||||
elif incBlocks[key].parent in self.data["blockchain"].blocks:
|
|
||||||
self.data["blockchain"].addBlock(incBlocks[key], self.mode, self.targetRate)
|
|
||||||
del tempData[key]
|
|
||||||
incBlocks = copy.deepcopy(tempData)
|
|
||||||
|
|
||||||
def propagate(self, timeOfProp, blockIdent):
|
|
||||||
for edgeIdent in self.edges:
|
|
||||||
edge = self.edges[edgeIdent]
|
|
||||||
length = e.data["length"]
|
|
||||||
timeOfArrival = timeOfProp + length
|
|
||||||
otherIdent = e.getNeighbor(self.ident)
|
|
||||||
other = e.nodes[otherIdent]
|
|
||||||
bc = other.data["blockchain"]
|
|
||||||
if blockIdent not in bc.blocks:
|
|
||||||
pB = e.data["pendingBlocks"]
|
|
||||||
pendingIdent = newIdent(len(pB))
|
|
||||||
mybc = self.data["blockchain"]
|
|
||||||
blockToProp = mybc.blocks[blockIdent]
|
|
||||||
pendingDat = {"timeOfArrival":timeOfArrival, "destIdent":otherIdent, "block":blockToProp}
|
|
||||||
pB.update({pendingIdent:pendingDat})
|
|
||||||
|
|
||||||
|
|
||||||
class Test_Node(unittest.TestCase):
|
|
||||||
# TODO test each method separately
|
|
||||||
def test_all(self):
|
|
||||||
bill = Blockchain([], verbosity=True)
|
|
||||||
mode="Nakamoto"
|
|
||||||
tr = 1.0/600000.0
|
|
||||||
deltaT = 600000.0
|
|
||||||
bill.targetRate = tr
|
|
||||||
|
|
||||||
name = newIdent(0)
|
|
||||||
t = 0.0
|
|
||||||
s = t
|
|
||||||
diff = 1.0
|
|
||||||
params = {"ident":name, "disco":t, "arriv":s, "parent":None, "diff":diff}
|
|
||||||
genesis = Block(params)
|
|
||||||
bill.addBlock(genesis, mode, tr)
|
|
||||||
|
|
||||||
parent = genesis.ident
|
|
||||||
|
|
||||||
nellyname = newIdent(time.time())
|
|
||||||
mode = "Nakamoto"
|
|
||||||
targetRate = 1.0/600000.0
|
|
||||||
params = {"ident":nellyname, "data":{"offset":0.0, "intensity":1.0, "blockchain":bill}, "verbose":True, "mode":mode, "targetRate":targetRate}
|
|
||||||
nelly = Node(params)
|
|
||||||
|
|
||||||
while len(nelly.data["blockchain"].blocks) < 2015:
|
|
||||||
name = newIdent(0)
|
|
||||||
diff = nelly.data["blockchain"].diff
|
|
||||||
t += deltaT*diff*(2.0*random.random()-1.0)
|
|
||||||
s = t
|
|
||||||
params = {"ident":name, "disco":t, "arriv":s, "parent":parent, "diff":diff}
|
|
||||||
newBlock = Block(params)
|
|
||||||
bill.addBlock(newBlock, mode, tr)
|
|
||||||
parent = name
|
|
||||||
|
|
||||||
|
|
||||||
while len(nelly.data["blockchain"].blocks) < 5000:
|
|
||||||
name = newIdent(0)
|
|
||||||
diff = nelly.data["blockchain"].diff
|
|
||||||
t += deltaT*diff
|
|
||||||
s = t
|
|
||||||
params = {"ident":name, "disco":t, "arriv":s, "parent":parent, "diff":diff}
|
|
||||||
newBlock = Block(params)
|
|
||||||
bill.addBlock(newBlock, mode, tr)
|
|
||||||
parent = name
|
|
||||||
|
|
||||||
suite = unittest.TestLoader().loadTestsFromTestCase(Test_Node)
|
|
||||||
unittest.TextTestRunner(verbosity=1).run(suite)
|
|
||||||
|
|
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load diff
|
@ -1,602 +0,0 @@
|
||||||
time,rateConstant,difficulty
|
|
||||||
0.0,1.0,1.0
|
|
||||||
1.0,1.0,1.0
|
|
||||||
2.0,1.0,1.0
|
|
||||||
3.0,1.0,1.0
|
|
||||||
4.0,1.0,1.0
|
|
||||||
5.0,1.0,1.0
|
|
||||||
6.0,1.0,1.0
|
|
||||||
7.0,1.0,1.0
|
|
||||||
8.0,1.0,1.0
|
|
||||||
9.0,1.0,1.0
|
|
||||||
10.0,1.0,1.0
|
|
||||||
11.0,1.0,1.0
|
|
||||||
12.0,1.0,1.0
|
|
||||||
13.0,1.0,1.0
|
|
||||||
14.0,1.0,1.0
|
|
||||||
15.0,1.0,1.0
|
|
||||||
16.0,1.0,1.0
|
|
||||||
17.0,1.0,1.0
|
|
||||||
18.0,1.0,1.0
|
|
||||||
19.0,1.0,1.0
|
|
||||||
20.0,1.0,1.0
|
|
||||||
21.0,1.0,1.0
|
|
||||||
22.0,1.0,1.0
|
|
||||||
23.0,1.0,1.0
|
|
||||||
24.0,1.0,1.0
|
|
||||||
25.0,1.0,1.0
|
|
||||||
26.0,1.0,1.0
|
|
||||||
27.0,1.0,1.0
|
|
||||||
28.0,1.0,1.0
|
|
||||||
29.0,1.0,1.0
|
|
||||||
30.0,1.0,1.0
|
|
||||||
31.0,1.0,1.0
|
|
||||||
32.0,1.0,1.0
|
|
||||||
33.0,1.0,1.0
|
|
||||||
34.0,1.0,1.0
|
|
||||||
35.0,1.0,1.0
|
|
||||||
36.0,1.0,1.0
|
|
||||||
37.0,1.0,1.0
|
|
||||||
38.0,1.0,1.0
|
|
||||||
39.0,1.0,1.0
|
|
||||||
40.0,1.0,1.0
|
|
||||||
41.0,1.0,1.0
|
|
||||||
42.0,1.0,1.0
|
|
||||||
43.0,1.0,1.0
|
|
||||||
44.0,1.0,1.0
|
|
||||||
45.0,1.0,1.0
|
|
||||||
46.0,1.0,1.0
|
|
||||||
47.0,1.0,1.0
|
|
||||||
48.0,1.0,1.0
|
|
||||||
49.0,1.0,1.0
|
|
||||||
50.0,1.0,1.0
|
|
||||||
51.0,1.0,1.0
|
|
||||||
52.0,1.0,1.0
|
|
||||||
53.0,1.0,1.0
|
|
||||||
54.0,1.0,1.0
|
|
||||||
55.0,1.0,1.0
|
|
||||||
56.0,1.0,1.0
|
|
||||||
57.0,1.0,1.0
|
|
||||||
58.0,1.0,1.0
|
|
||||||
59.0,1.0,1.0
|
|
||||||
60.0,1.0,1.0
|
|
||||||
61.0,1.0,1.0
|
|
||||||
62.0,1.0,1.0
|
|
||||||
63.0,1.0,1.0
|
|
||||||
64.0,1.0,1.0
|
|
||||||
65.0,1.0,1.0
|
|
||||||
66.0,1.0,1.0
|
|
||||||
67.0,1.0,1.0
|
|
||||||
68.0,1.0,1.0
|
|
||||||
69.0,1.0,1.0
|
|
||||||
70.0,1.0,1.0
|
|
||||||
71.0,1.0,1.0
|
|
||||||
72.0,1.0,1.0
|
|
||||||
73.0,1.0,1.0
|
|
||||||
74.0,1.0,1.0
|
|
||||||
75.0,1.0,1.0
|
|
||||||
76.0,1.0,1.0
|
|
||||||
77.0,1.0,1.0
|
|
||||||
78.0,1.0,1.0
|
|
||||||
79.0,1.0,1.0
|
|
||||||
80.0,1.0,1.0
|
|
||||||
81.0,1.0,1.0
|
|
||||||
82.0,1.0,1.0
|
|
||||||
83.0,1.0,1.0
|
|
||||||
84.0,1.0,1.0
|
|
||||||
85.0,1.0,1.0
|
|
||||||
86.0,1.0,1.0
|
|
||||||
87.0,1.0,1.0
|
|
||||||
88.0,1.0,1.0
|
|
||||||
89.0,1.0,1.0
|
|
||||||
90.0,1.0,1.0
|
|
||||||
91.0,1.0,1.0
|
|
||||||
92.0,1.0,1.0
|
|
||||||
93.0,1.0,1.0
|
|
||||||
94.0,1.0,1.0
|
|
||||||
95.0,1.0,1.0
|
|
||||||
96.0,1.0,1.0
|
|
||||||
97.0,1.0,1.0
|
|
||||||
98.0,1.0,1.0
|
|
||||||
99.0,1.0,1.0
|
|
||||||
100.0,1.0,1.0
|
|
||||||
101.0,1.0,1.0
|
|
||||||
102.0,1.0,1.0
|
|
||||||
103.0,1.0,1.0
|
|
||||||
104.0,1.0,1.0
|
|
||||||
105.0,1.0,1.0
|
|
||||||
106.0,1.0,1.0
|
|
||||||
107.0,1.0,1.0
|
|
||||||
108.0,1.0,1.0
|
|
||||||
109.0,1.0,1.0
|
|
||||||
110.0,1.0,1.0
|
|
||||||
111.0,1.0,1.0
|
|
||||||
112.0,1.0,1.0
|
|
||||||
113.0,1.0,1.0
|
|
||||||
114.0,1.0,1.0
|
|
||||||
115.0,1.0,1.0
|
|
||||||
116.0,1.0,1.0
|
|
||||||
117.0,1.0,1.0
|
|
||||||
118.0,1.0,1.0
|
|
||||||
119.0,1.0,1.0
|
|
||||||
120.0,1.0,1.0
|
|
||||||
121.0,1.0,1.0
|
|
||||||
122.0,1.0,1.0
|
|
||||||
123.0,1.0,1.0
|
|
||||||
124.0,1.0,1.0
|
|
||||||
125.0,1.0,1.0
|
|
||||||
126.0,1.0,1.0
|
|
||||||
127.0,1.0,1.0
|
|
||||||
128.0,1.0,1.0
|
|
||||||
129.0,1.0,1.0
|
|
||||||
130.0,1.0,1.0
|
|
||||||
131.0,1.0,1.0
|
|
||||||
132.0,1.0,1.0
|
|
||||||
133.0,1.0,1.0
|
|
||||||
134.0,1.0,1.0
|
|
||||||
135.0,1.0,1.0
|
|
||||||
136.0,1.0,1.0
|
|
||||||
137.0,1.0,1.0
|
|
||||||
138.0,1.0,1.0
|
|
||||||
139.0,1.0,1.0
|
|
||||||
140.0,1.0,1.0
|
|
||||||
141.0,1.0,1.0
|
|
||||||
142.0,1.0,1.0
|
|
||||||
143.0,1.0,1.0
|
|
||||||
144.0,1.0,1.0
|
|
||||||
145.0,1.0,1.0
|
|
||||||
146.0,1.0,1.0
|
|
||||||
147.0,1.0,1.0
|
|
||||||
148.0,1.0,1.0
|
|
||||||
149.0,1.0,1.0
|
|
||||||
150.0,1.0,1.0
|
|
||||||
151.0,1.0,1.0
|
|
||||||
152.0,1.0,1.0
|
|
||||||
153.0,1.0,1.0
|
|
||||||
154.0,1.0,1.0
|
|
||||||
155.0,1.0,1.0
|
|
||||||
156.0,1.0,1.0
|
|
||||||
157.0,1.0,1.0
|
|
||||||
158.0,1.0,1.0
|
|
||||||
159.0,1.0,1.0
|
|
||||||
160.0,1.0,1.0
|
|
||||||
161.0,1.0,1.0
|
|
||||||
162.0,1.0,1.0
|
|
||||||
163.0,1.0,1.0
|
|
||||||
164.0,1.0,1.0
|
|
||||||
165.0,1.0,1.0
|
|
||||||
166.0,1.0,1.0
|
|
||||||
167.0,1.0,1.0
|
|
||||||
168.0,1.0,1.0
|
|
||||||
169.0,1.0,1.0
|
|
||||||
170.0,1.0,1.0
|
|
||||||
171.0,1.0,1.0
|
|
||||||
172.0,1.0,1.0
|
|
||||||
173.0,1.0,1.0
|
|
||||||
174.0,1.0,1.0
|
|
||||||
175.0,1.0,1.0
|
|
||||||
176.0,1.0,1.0
|
|
||||||
177.0,1.0,1.0
|
|
||||||
178.0,1.0,1.0
|
|
||||||
179.0,1.0,1.0
|
|
||||||
180.0,1.0,1.0
|
|
||||||
181.0,1.0,1.0
|
|
||||||
182.0,1.0,1.0
|
|
||||||
183.0,1.0,1.0
|
|
||||||
184.0,1.0,1.0
|
|
||||||
185.0,1.0,1.0
|
|
||||||
186.0,1.0,1.0
|
|
||||||
187.0,1.0,1.0
|
|
||||||
188.0,1.0,1.0
|
|
||||||
189.0,1.0,1.0
|
|
||||||
190.0,1.0,1.0
|
|
||||||
191.0,1.0,1.0
|
|
||||||
192.0,1.0,1.0
|
|
||||||
193.0,1.0,1.0
|
|
||||||
194.0,1.0,1.0
|
|
||||||
195.0,1.0,1.0
|
|
||||||
196.0,1.0,1.0
|
|
||||||
197.0,1.0,1.0
|
|
||||||
198.0,1.0,1.0
|
|
||||||
199.0,1.0,1.0
|
|
||||||
200.0,1.0,1.0
|
|
||||||
201.0,1.0,1.0
|
|
||||||
202.0,1.0,1.0
|
|
||||||
203.0,1.0,1.0
|
|
||||||
204.0,1.0,1.0
|
|
||||||
205.0,1.0,1.0
|
|
||||||
206.0,1.0,1.0
|
|
||||||
207.0,1.0,1.0
|
|
||||||
208.0,1.0,1.0
|
|
||||||
209.0,1.0,1.0
|
|
||||||
210.0,1.0,1.0
|
|
||||||
211.0,1.0,1.0
|
|
||||||
212.0,1.0,1.0
|
|
||||||
213.0,1.0,1.0
|
|
||||||
214.0,1.0,1.0
|
|
||||||
215.0,1.0,1.0
|
|
||||||
216.0,1.0,1.0
|
|
||||||
217.0,1.0,1.0
|
|
||||||
218.0,1.0,1.0
|
|
||||||
219.0,1.0,1.0
|
|
||||||
220.0,1.0,1.0
|
|
||||||
221.0,1.0,1.0
|
|
||||||
222.0,1.0,1.0
|
|
||||||
223.0,1.0,1.0
|
|
||||||
224.0,1.0,1.0
|
|
||||||
225.0,1.0,1.0
|
|
||||||
226.0,1.0,1.0
|
|
||||||
227.0,1.0,1.0
|
|
||||||
228.0,1.0,1.0
|
|
||||||
229.0,1.0,1.0
|
|
||||||
230.0,1.0,1.0
|
|
||||||
231.0,1.0,1.0
|
|
||||||
232.0,1.0,1.0
|
|
||||||
233.0,1.0,1.0
|
|
||||||
234.0,1.0,1.0
|
|
||||||
235.0,1.0,1.0
|
|
||||||
236.0,1.0,1.0
|
|
||||||
237.0,1.0,1.0
|
|
||||||
238.0,1.0,1.0
|
|
||||||
239.0,1.0,1.0
|
|
||||||
240.0,1.0,1.0
|
|
||||||
241.0,1.0,1.0
|
|
||||||
242.0,1.0,1.0
|
|
||||||
243.0,1.0,1.0
|
|
||||||
244.0,1.0,1.0
|
|
||||||
245.0,1.0,1.0
|
|
||||||
246.0,1.0,1.0
|
|
||||||
247.0,1.0,1.0
|
|
||||||
248.0,1.0,1.0
|
|
||||||
249.0,1.0,1.0
|
|
||||||
250.0,1.0,1.0
|
|
||||||
251.0,1.0,1.0
|
|
||||||
252.0,1.0,1.0
|
|
||||||
253.0,1.0,1.0
|
|
||||||
254.0,1.0,1.0
|
|
||||||
255.0,1.0,1.0
|
|
||||||
256.0,1.0,1.0
|
|
||||||
257.0,1.0,1.0
|
|
||||||
258.0,1.0,1.0
|
|
||||||
259.0,1.0,1.0
|
|
||||||
260.0,1.0,1.0
|
|
||||||
261.0,1.0,1.0
|
|
||||||
262.0,1.0,1.0
|
|
||||||
263.0,1.0,1.0
|
|
||||||
264.0,1.0,1.0
|
|
||||||
265.0,1.0,1.0
|
|
||||||
266.0,1.0,1.0
|
|
||||||
267.0,1.0,1.0
|
|
||||||
268.0,1.0,1.0
|
|
||||||
269.0,1.0,1.0
|
|
||||||
270.0,1.0,1.0
|
|
||||||
271.0,1.0,1.0
|
|
||||||
272.0,1.0,1.0
|
|
||||||
273.0,1.0,1.0
|
|
||||||
274.0,1.0,1.0
|
|
||||||
275.0,1.0,1.0
|
|
||||||
276.0,1.0,1.0
|
|
||||||
277.0,1.0,1.0
|
|
||||||
278.0,1.0,1.0
|
|
||||||
279.0,1.0,1.0
|
|
||||||
280.0,1.0,1.0
|
|
||||||
281.0,1.0,1.0
|
|
||||||
282.0,1.0,1.0
|
|
||||||
283.0,1.0,1.0
|
|
||||||
284.0,1.0,1.0
|
|
||||||
285.0,1.0,1.0
|
|
||||||
286.0,1.0,1.0
|
|
||||||
287.0,1.0,1.0
|
|
||||||
288.0,1.0,1.0
|
|
||||||
289.0,1.0,1.0
|
|
||||||
290.0,1.0,1.0
|
|
||||||
291.0,1.0,1.0
|
|
||||||
292.0,1.0,1.0
|
|
||||||
293.0,1.0,1.0
|
|
||||||
294.0,1.0,1.0
|
|
||||||
295.0,1.0,1.0
|
|
||||||
296.0,1.0,1.0
|
|
||||||
297.0,1.0,1.0
|
|
||||||
298.0,1.0,1.0
|
|
||||||
299.0,1.0,1.0
|
|
||||||
300.0,1.0,1.0
|
|
||||||
301.0,1.0,1.0
|
|
||||||
302.0,1.0,1.0
|
|
||||||
303.0,1.0,1.0
|
|
||||||
304.0,1.0,1.0
|
|
||||||
305.0,1.0,1.0
|
|
||||||
306.0,1.0,1.0
|
|
||||||
307.0,1.0,1.0
|
|
||||||
308.0,1.0,1.0
|
|
||||||
309.0,1.0,1.0
|
|
||||||
310.0,1.0,1.0
|
|
||||||
311.0,1.0,1.0
|
|
||||||
312.0,1.0,1.0
|
|
||||||
313.0,1.0,1.0
|
|
||||||
314.0,1.0,1.0
|
|
||||||
315.0,1.0,1.0
|
|
||||||
316.0,1.0,1.0
|
|
||||||
317.0,1.0,1.0
|
|
||||||
318.0,1.0,1.0
|
|
||||||
319.0,1.0,1.0
|
|
||||||
320.0,1.0,1.0
|
|
||||||
321.0,1.0,1.0
|
|
||||||
322.0,1.0,1.0
|
|
||||||
323.0,1.0,1.0
|
|
||||||
324.0,1.0,1.0
|
|
||||||
325.0,1.0,1.0
|
|
||||||
326.0,1.0,1.0
|
|
||||||
327.0,1.0,1.0
|
|
||||||
328.0,1.0,1.0
|
|
||||||
329.0,1.0,1.0
|
|
||||||
330.0,1.0,1.0
|
|
||||||
331.0,1.0,1.0
|
|
||||||
332.0,1.0,1.0
|
|
||||||
333.0,1.0,1.0
|
|
||||||
334.0,1.0,1.0
|
|
||||||
335.0,1.0,1.0
|
|
||||||
336.0,1.0,1.0
|
|
||||||
337.0,1.0,1.0
|
|
||||||
338.0,1.0,1.0
|
|
||||||
339.0,1.0,1.0
|
|
||||||
340.0,1.0,1.0
|
|
||||||
341.0,1.0,1.0
|
|
||||||
342.0,1.0,1.0
|
|
||||||
343.0,1.0,1.0
|
|
||||||
344.0,1.0,1.0
|
|
||||||
345.0,1.0,1.0
|
|
||||||
346.0,1.0,1.0
|
|
||||||
347.0,1.0,1.0
|
|
||||||
348.0,1.0,1.0
|
|
||||||
349.0,1.0,1.0
|
|
||||||
350.0,1.0,1.0
|
|
||||||
351.0,1.0,1.0
|
|
||||||
352.0,1.0,1.0
|
|
||||||
353.0,1.0,1.0
|
|
||||||
354.0,1.0,1.0
|
|
||||||
355.0,1.0,1.0
|
|
||||||
356.0,1.0,1.0
|
|
||||||
357.0,1.0,1.0
|
|
||||||
358.0,1.0,1.0
|
|
||||||
359.0,1.0,1.0
|
|
||||||
360.0,1.0,1.0
|
|
||||||
361.0,1.0,1.0
|
|
||||||
362.0,1.0,1.0
|
|
||||||
363.0,1.0,1.0
|
|
||||||
364.0,1.0,1.0
|
|
||||||
365.0,1.0,1.0
|
|
||||||
366.0,1.0,1.0
|
|
||||||
367.0,1.0,1.0
|
|
||||||
368.0,1.0,1.0
|
|
||||||
369.0,1.0,1.0
|
|
||||||
370.0,1.0,1.0
|
|
||||||
371.0,1.0,1.0
|
|
||||||
372.0,1.0,1.0
|
|
||||||
373.0,1.0,1.0
|
|
||||||
374.0,1.0,1.0
|
|
||||||
375.0,1.0,1.0
|
|
||||||
376.0,1.0,1.0
|
|
||||||
377.0,1.0,1.0
|
|
||||||
378.0,1.0,1.0
|
|
||||||
379.0,1.0,1.0
|
|
||||||
380.0,1.0,1.0
|
|
||||||
381.0,1.0,1.0
|
|
||||||
382.0,1.0,1.0
|
|
||||||
383.0,1.0,1.0
|
|
||||||
384.0,1.0,1.0
|
|
||||||
385.0,1.0,1.0
|
|
||||||
386.0,1.0,1.0
|
|
||||||
387.0,1.0,1.0
|
|
||||||
388.0,1.0,1.0
|
|
||||||
389.0,1.0,1.0
|
|
||||||
390.0,1.0,1.0
|
|
||||||
391.0,1.0,1.0
|
|
||||||
392.0,1.0,1.0
|
|
||||||
393.0,1.0,1.0
|
|
||||||
394.0,1.0,1.0
|
|
||||||
395.0,1.0,1.0
|
|
||||||
396.0,1.0,1.0
|
|
||||||
397.0,1.0,1.0
|
|
||||||
398.0,1.0,1.0
|
|
||||||
399.0,1.0,1.0
|
|
||||||
400.0,1.0,1.0
|
|
||||||
401.0,1.0,1.0
|
|
||||||
402.0,1.0,1.0
|
|
||||||
403.0,1.0,1.0
|
|
||||||
404.0,1.0,1.0
|
|
||||||
405.0,1.0,1.0
|
|
||||||
406.0,1.0,1.0
|
|
||||||
407.0,1.0,1.0
|
|
||||||
408.0,1.0,1.0
|
|
||||||
409.0,1.0,1.0
|
|
||||||
410.0,1.0,1.0
|
|
||||||
411.0,1.0,1.0
|
|
||||||
412.0,1.0,1.0
|
|
||||||
413.0,1.0,1.0
|
|
||||||
414.0,1.0,1.0
|
|
||||||
415.0,1.0,1.0
|
|
||||||
416.0,1.0,1.0
|
|
||||||
417.0,1.0,1.0
|
|
||||||
418.0,1.0,1.0
|
|
||||||
419.0,1.0,1.0
|
|
||||||
420.0,1.0,1.0
|
|
||||||
421.0,1.0,1.0
|
|
||||||
422.0,1.0,1.0
|
|
||||||
423.0,1.0,1.0
|
|
||||||
424.0,1.0,1.0
|
|
||||||
425.0,1.0,1.0
|
|
||||||
426.0,1.0,1.0
|
|
||||||
427.0,1.0,1.0
|
|
||||||
428.0,1.0,1.0
|
|
||||||
429.0,1.0,1.0
|
|
||||||
430.0,1.0,1.0
|
|
||||||
431.0,1.0,1.0
|
|
||||||
432.0,1.0,1.0
|
|
||||||
433.0,1.0,1.0
|
|
||||||
434.0,1.0,1.0
|
|
||||||
435.0,1.0,1.0
|
|
||||||
436.0,1.0,1.0
|
|
||||||
437.0,1.0,1.0
|
|
||||||
438.0,1.0,1.0
|
|
||||||
439.0,1.0,1.0
|
|
||||||
440.0,1.0,1.0
|
|
||||||
441.0,1.0,1.0
|
|
||||||
442.0,1.0,1.0
|
|
||||||
443.0,1.0,1.0
|
|
||||||
444.0,1.0,1.0
|
|
||||||
445.0,1.0,1.0
|
|
||||||
446.0,1.0,1.0
|
|
||||||
447.0,1.0,1.0
|
|
||||||
448.0,1.0,1.0
|
|
||||||
449.0,1.0,1.0
|
|
||||||
450.0,1.0,1.0
|
|
||||||
451.0,1.0,1.0
|
|
||||||
452.0,1.0,1.0
|
|
||||||
453.0,1.0,1.0
|
|
||||||
454.0,1.0,1.0
|
|
||||||
455.0,1.0,1.0
|
|
||||||
456.0,1.0,1.0
|
|
||||||
457.0,1.0,1.0
|
|
||||||
458.0,1.0,1.0
|
|
||||||
459.0,1.0,1.0
|
|
||||||
460.0,1.0,1.0
|
|
||||||
461.0,1.0,1.0
|
|
||||||
462.0,1.0,1.0
|
|
||||||
463.0,1.0,1.0
|
|
||||||
464.0,1.0,1.0
|
|
||||||
465.0,1.0,1.0
|
|
||||||
466.0,1.0,1.0
|
|
||||||
467.0,1.0,1.0
|
|
||||||
468.0,1.0,1.0
|
|
||||||
469.0,1.0,1.0
|
|
||||||
470.0,1.0,1.0
|
|
||||||
471.0,1.0,1.0
|
|
||||||
472.0,1.0,1.0
|
|
||||||
473.0,1.0,1.0
|
|
||||||
474.0,1.0,1.0
|
|
||||||
475.0,1.0,1.0
|
|
||||||
476.0,1.0,1.0
|
|
||||||
477.0,1.0,1.0
|
|
||||||
478.0,1.0,1.0
|
|
||||||
479.0,1.0,1.0
|
|
||||||
480.0,1.0,1.0
|
|
||||||
481.0,1.0,1.0
|
|
||||||
482.0,1.0,1.0
|
|
||||||
483.0,1.0,1.0
|
|
||||||
484.0,1.0,1.0
|
|
||||||
485.0,1.0,1.0
|
|
||||||
486.0,1.0,1.0
|
|
||||||
487.0,1.0,1.0
|
|
||||||
488.0,1.0,1.0
|
|
||||||
489.0,1.0,1.0
|
|
||||||
490.0,1.0,1.0
|
|
||||||
491.0,1.0,1.0
|
|
||||||
492.0,1.0,1.0
|
|
||||||
493.0,1.0,1.0
|
|
||||||
494.0,1.0,1.0
|
|
||||||
495.0,1.0,1.0
|
|
||||||
496.0,1.0,1.0
|
|
||||||
497.0,1.0,1.0
|
|
||||||
498.0,1.0,1.0
|
|
||||||
499.0,1.0,1.0
|
|
||||||
500.0,1.0,1.0
|
|
||||||
501.0,1.0,1.0
|
|
||||||
502.0,1.0,1.0
|
|
||||||
503.0,1.0,1.0
|
|
||||||
504.0,1.0,1.0
|
|
||||||
505.0,1.0,1.0
|
|
||||||
506.0,1.0,1.0
|
|
||||||
507.0,1.0,1.0
|
|
||||||
508.0,1.0,1.0
|
|
||||||
509.0,1.0,1.0
|
|
||||||
510.0,1.0,1.0
|
|
||||||
511.0,1.0,1.0
|
|
||||||
512.0,1.0,1.0
|
|
||||||
513.0,1.0,1.0
|
|
||||||
514.0,1.0,1.0
|
|
||||||
515.0,1.0,1.0
|
|
||||||
516.0,1.0,1.0
|
|
||||||
517.0,1.0,1.0
|
|
||||||
518.0,1.0,1.0
|
|
||||||
519.0,1.0,1.0
|
|
||||||
520.0,1.0,1.0
|
|
||||||
521.0,1.0,1.0
|
|
||||||
522.0,1.0,1.0
|
|
||||||
523.0,1.0,1.0
|
|
||||||
524.0,1.0,1.0
|
|
||||||
525.0,1.0,1.0
|
|
||||||
526.0,1.0,1.0
|
|
||||||
527.0,1.0,1.0
|
|
||||||
528.0,1.0,1.0
|
|
||||||
529.0,1.0,1.0
|
|
||||||
530.0,1.0,1.0
|
|
||||||
531.0,1.0,1.0
|
|
||||||
532.0,1.0,1.0
|
|
||||||
533.0,1.0,1.0
|
|
||||||
534.0,1.0,1.0
|
|
||||||
535.0,1.0,1.0
|
|
||||||
536.0,1.0,1.0
|
|
||||||
537.0,1.0,1.0
|
|
||||||
538.0,1.0,1.0
|
|
||||||
539.0,1.0,1.0
|
|
||||||
540.0,1.0,1.0
|
|
||||||
541.0,1.0,1.0
|
|
||||||
542.0,1.0,1.0
|
|
||||||
543.0,1.0,1.0
|
|
||||||
544.0,1.0,1.0
|
|
||||||
545.0,1.0,1.0
|
|
||||||
546.0,1.0,1.0
|
|
||||||
547.0,1.0,1.0
|
|
||||||
548.0,1.0,1.0
|
|
||||||
549.0,1.0,1.0
|
|
||||||
550.0,1.0,1.0
|
|
||||||
551.0,1.0,1.0
|
|
||||||
552.0,1.0,1.0
|
|
||||||
553.0,1.0,1.0
|
|
||||||
554.0,1.0,1.0
|
|
||||||
555.0,1.0,1.0
|
|
||||||
556.0,1.0,1.0
|
|
||||||
557.0,1.0,1.0
|
|
||||||
558.0,1.0,1.0
|
|
||||||
559.0,1.0,1.0
|
|
||||||
560.0,1.0,1.0
|
|
||||||
561.0,1.0,1.0
|
|
||||||
562.0,1.0,1.0
|
|
||||||
563.0,1.0,1.0
|
|
||||||
564.0,1.0,1.0
|
|
||||||
565.0,1.0,1.0
|
|
||||||
566.0,1.0,1.0
|
|
||||||
567.0,1.0,1.0
|
|
||||||
568.0,1.0,1.0
|
|
||||||
569.0,1.0,1.0
|
|
||||||
570.0,1.0,1.0
|
|
||||||
571.0,1.0,1.0
|
|
||||||
572.0,1.0,1.0
|
|
||||||
573.0,1.0,1.0
|
|
||||||
574.0,1.0,1.0
|
|
||||||
575.0,1.0,1.0
|
|
||||||
576.0,1.0,1.0
|
|
||||||
577.0,1.0,1.0
|
|
||||||
578.0,1.0,1.0
|
|
||||||
579.0,1.0,1.0
|
|
||||||
580.0,1.0,1.0
|
|
||||||
581.0,1.0,1.0
|
|
||||||
582.0,1.0,1.0
|
|
||||||
583.0,1.0,1.0
|
|
||||||
584.0,1.0,1.0
|
|
||||||
585.0,1.0,1.0
|
|
||||||
586.0,1.0,1.0
|
|
||||||
587.0,1.0,1.0
|
|
||||||
588.0,1.0,1.0
|
|
||||||
589.0,1.0,1.0
|
|
||||||
590.0,1.0,1.0
|
|
||||||
591.0,1.0,1.0
|
|
||||||
592.0,1.0,1.0
|
|
||||||
593.0,1.0,1.0
|
|
||||||
594.0,1.0,1.0
|
|
||||||
595.0,1.0,1.0
|
|
||||||
596.0,1.0,1.0
|
|
||||||
597.0,1.0,1.0
|
|
||||||
598.0,1.0,1.0
|
|
||||||
599.0,1.0,1.0
|
|
||||||
600.0,1.0,1.0
|
|
|
@ -1,201 +0,0 @@
|
||||||
time,rateConstant,difficulty
|
|
||||||
0.0,1.0,1.0
|
|
||||||
120458.46590012926,1.0,1.0
|
|
||||||
240605.33373578714,1.0,1.0
|
|
||||||
360287.44233708055,1.0,1.0
|
|
||||||
480034.84471731156,1.0,1.0
|
|
||||||
601021.4072874074,1.0,1.0
|
|
||||||
720155.9397105722,1.0,1.0
|
|
||||||
840557.1097845419,1.0,1.0
|
|
||||||
960142.4715273783,1.0,1.0
|
|
||||||
1080326.4196690398,1.0,1.0
|
|
||||||
1200228.3567496322,1.0,1.0
|
|
||||||
1321393.1769845556,1.0,1.0
|
|
||||||
1442403.7637959223,1.0,1.0
|
|
||||||
1563312.6884154421,1.0,1.0
|
|
||||||
1683650.3562759135,1.0,1.0
|
|
||||||
1804242.0878089573,1.0,1.0
|
|
||||||
1923957.6270508477,1.0,1.0
|
|
||||||
2043603.5193920576,1.0,1.0
|
|
||||||
2162815.4440224506,1.0,1.0
|
|
||||||
2282288.929005547,1.0,1.0
|
|
||||||
2402114.705755926,1.0,1.0
|
|
||||||
2522303.585101224,1.0,1.0
|
|
||||||
2643267.2988593285,1.0,1.0
|
|
||||||
2762617.5338163865,1.0,1.0
|
|
||||||
2882563.380726947,1.0,1.0
|
|
||||||
3003489.532699132,1.0,1.0
|
|
||||||
3124641.562256374,1.0,1.0
|
|
||||||
3245100.9215427977,1.0,1.0
|
|
||||||
3365536.420458877,1.0,1.0
|
|
||||||
3484337.996609595,1.0,1.0
|
|
||||||
3604694.7847104715,1.0,1.0
|
|
||||||
3724951.576782264,1.0,1.0
|
|
||||||
3846026.69613723,1.0,1.0
|
|
||||||
3967024.7982774274,1.0,1.0
|
|
||||||
4085911.063711746,1.0,1.0
|
|
||||||
4205815.028144305,1.0,1.0
|
|
||||||
4325421.232620401,1.0,1.0
|
|
||||||
4444827.052513202,1.0,1.0
|
|
||||||
4565099.154304211,1.0,1.0
|
|
||||||
4686236.387124661,1.0,1.0
|
|
||||||
4806734.051850467,1.0,1.0
|
|
||||||
4926566.647937627,1.0,1.0
|
|
||||||
5045488.866484466,1.0,1.0
|
|
||||||
5166502.755345808,1.0,1.0
|
|
||||||
5287233.653263695,1.0,1.0
|
|
||||||
5407908.334559678,1.0,1.0
|
|
||||||
5528786.366282915,1.0,1.0
|
|
||||||
5647678.3122160155,1.0,1.0
|
|
||||||
5767244.089580304,1.0,1.0
|
|
||||||
5886473.651601109,1.0,1.0
|
|
||||||
6006435.897878854,1.0,1.0
|
|
||||||
6125341.27352921,1.0,1.0
|
|
||||||
6245479.785253891,1.0,1.0
|
|
||||||
6365523.236878065,1.0,1.0
|
|
||||||
6485749.795878896,1.0,1.0
|
|
||||||
6605240.444894265,1.0,1.0
|
|
||||||
6724686.210446132,1.0,1.0
|
|
||||||
6844155.218750592,1.0,1.0
|
|
||||||
6963341.181369955,1.0,1.0
|
|
||||||
7082695.6923123505,1.0,1.0
|
|
||||||
7203655.141225615,1.0,1.0
|
|
||||||
7322627.204840391,1.0,1.0
|
|
||||||
7441799.159546731,1.0,1.0
|
|
||||||
7562822.49932097,1.0,1.0
|
|
||||||
7683323.524066307,1.0,1.0
|
|
||||||
7804477.48899398,1.0,1.0
|
|
||||||
7923457.857637024,1.0,1.0
|
|
||||||
8043898.249303401,1.0,1.0
|
|
||||||
8164187.296374614,1.0,1.0
|
|
||||||
8283469.107294493,1.0,1.0
|
|
||||||
8402627.723784521,1.0,1.0
|
|
||||||
8523745.89200794,1.0,1.0
|
|
||||||
8643778.9729813,1.0,1.0
|
|
||||||
8764635.624631569,1.0,1.0
|
|
||||||
8885538.059417976,1.0,1.0
|
|
||||||
9006433.79263568,1.0,1.0
|
|
||||||
9127489.588015186,1.0,1.0
|
|
||||||
9247569.28782317,1.0,1.0
|
|
||||||
9367958.084440755,1.0,1.0
|
|
||||||
9487586.29442678,1.0,1.0
|
|
||||||
9606427.886281481,1.0,1.0
|
|
||||||
9725872.946140163,1.0,1.0
|
|
||||||
9846820.596317865,1.0,1.0
|
|
||||||
9966080.313457007,1.0,1.0
|
|
||||||
10085765.108573573,1.0,1.0
|
|
||||||
10206008.374459436,1.0,1.0
|
|
||||||
10326807.845790997,1.0,1.0
|
|
||||||
10447513.423168132,1.0,1.0
|
|
||||||
10566795.347145824,1.0,1.0
|
|
||||||
10686179.997466285,1.0,1.0
|
|
||||||
10805522.808373246,1.0,1.0
|
|
||||||
10925591.945700001,1.0,1.0
|
|
||||||
11045387.795286857,1.0,1.0
|
|
||||||
11165651.717103494,1.0,1.0
|
|
||||||
11286830.098064246,1.0,1.0
|
|
||||||
11406728.71699933,1.0,1.0
|
|
||||||
11525922.789870113,1.0,1.0
|
|
||||||
11646476.03903497,1.0,1.0
|
|
||||||
11766081.434268286,1.0,1.0
|
|
||||||
11886554.737807736,1.0,1.0
|
|
||||||
12006591.066234503,1.0,1.0
|
|
||||||
12125475.542528223,1.0,1.0
|
|
||||||
12245282.608027933,1.0,1.0
|
|
||||||
12364566.337023206,1.0,1.0
|
|
||||||
12484001.537563423,1.0,1.0
|
|
||||||
12604914.58673975,1.0,1.0
|
|
||||||
12725797.319719713,1.0,1.0
|
|
||||||
12844665.121160349,1.0,1.0
|
|
||||||
12964577.111847764,1.0,1.0
|
|
||||||
13083664.372389417,1.0,1.0
|
|
||||||
13204397.122438395,1.0,1.0
|
|
||||||
13324189.80038166,1.0,1.0
|
|
||||||
13445349.787586372,1.0,1.0
|
|
||||||
13564667.751049513,1.0,1.0
|
|
||||||
13684270.141374838,1.0,1.0
|
|
||||||
13804933.175467426,1.0,1.0
|
|
||||||
13926075.032552686,1.0,1.0
|
|
||||||
14045914.739095576,1.0,1.0
|
|
||||||
14166631.90042476,1.0,1.0
|
|
||||||
14286319.61550191,1.0,1.0
|
|
||||||
14406521.722056692,1.0,0.434741782576
|
|
||||||
14527069.972553544,1.0,0.19008730551
|
|
||||||
14647876.788742132,1.0,0.0840528337448
|
|
||||||
14766882.452974409,1.0,0.037302520528
|
|
||||||
14886464.10335911,1.0,0.0165590754676
|
|
||||||
15006383.983595744,1.0,0.00734675515331
|
|
||||||
15125494.942906044,1.0,0.00323569454228
|
|
||||||
15246686.831929097,1.0,0.00142738653296
|
|
||||||
15365567.953963466,1.0,0.000625305203658
|
|
||||||
15485210.071059253,1.0,0.00027137099116
|
|
||||||
15605744.64157258,1.0,0.00011715461834
|
|
||||||
15726806.733151415,1.0,5.07010986398e-05
|
|
||||||
15847473.63409661,1.0,2.20995440742e-05
|
|
||||||
15967616.71119521,1.0,9.7101015984e-06
|
|
||||||
16087483.017800437,1.0,4.29503052419e-06
|
|
||||||
16208328.180223988,1.0,1.92536966438e-06
|
|
||||||
16328269.772618307,1.0,8.74191715802e-07
|
|
||||||
16448898.77254663,1.0,4.04296324402e-07
|
|
||||||
16569068.683560552,1.0,1.90818902578e-07
|
|
||||||
16689986.260285133,1.0,9.28633545485e-08
|
|
||||||
16810906.032656457,1.0,4.72143204458e-08
|
|
||||||
16930289.120968327,1.0,2.49711320542e-08
|
|
||||||
17050753.779718515,1.0,1.3892256413e-08
|
|
||||||
17170600.427019596,1.0,8.15844774794e-09
|
|
||||||
17289713.01359109,1.0,4.99225078962e-09
|
|
||||||
17410383.421790008,1.0,3.25190780354e-09
|
|
||||||
17530744.28431112,1.0,2.30869255122e-09
|
|
||||||
17649863.36025036,1.0,1.75633116174e-09
|
|
||||||
17771007.11205409,1.0,1.56057621444e-09
|
|
||||||
17891565.791564044,1.0,2.04725172611e-09
|
|
||||||
18010728.55130284,1.0,3.28303372549e-09
|
|
||||||
18131143.8843602,1.0,3.25496154055e-09
|
|
||||||
18251685.45446652,1.0,2.60736708269e-09
|
|
||||||
18371507.007102486,1.0,1.85630105501e-09
|
|
||||||
18491403.948076807,1.0,1.21928659457e-09
|
|
||||||
18611553.039604228,1.0,7.49792394597e-10
|
|
||||||
18730744.251551468,1.0,4.45186327526e-10
|
|
||||||
18849856.685056694,1.0,2.61385070862e-10
|
|
||||||
18968926.062500622,1.0,1.55149613051e-10
|
|
||||||
19088067.33909847,1.0,9.51850841053e-11
|
|
||||||
19207594.13354391,1.0,6.1434055957e-11
|
|
||||||
19328017.11208744,1.0,4.14815251504e-11
|
|
||||||
19448814.951942917,1.0,2.86357848006e-11
|
|
||||||
19567841.28162038,1.0,2.11150220091e-11
|
|
||||||
19688388.179414563,1.0,1.6406642243e-11
|
|
||||||
19807627.873820234,1.0,1.43187359575e-11
|
|
||||||
19928483.04169874,1.0,1.35913238196e-11
|
|
||||||
20048557.76424465,1.0,1.4331290576e-11
|
|
||||||
20167664.74191137,1.0,2.37342192382e-11
|
|
||||||
20287610.467802733,1.0,3.14063325262e-11
|
|
||||||
20408382.62417472,1.0,3.36556321046e-11
|
|
||||||
20527817.08243184,1.0,3.00938650991e-11
|
|
||||||
20646637.59478427,1.0,2.24650389033e-11
|
|
||||||
20766577.880066067,1.0,1.49080962166e-11
|
|
||||||
20885785.934438772,1.0,8.89077367161e-12
|
|
||||||
21005536.07104386,1.0,4.87060433801e-12
|
|
||||||
21124902.305172637,1.0,2.47052077112e-12
|
|
||||||
21244885.7076036,1.0,1.17786853388e-12
|
|
||||||
21364581.43746038,1.0,5.31532928098e-13
|
|
||||||
21484493.676516064,1.0,2.28757375026e-13
|
|
||||||
21603916.644479226,1.0,9.40324531004e-14
|
|
||||||
21723733.860411238,1.0,3.70938898759e-14
|
|
||||||
21844771.38186735,1.0,1.42162474893e-14
|
|
||||||
21964794.368862327,1.0,5.30817642226e-15
|
|
||||||
22085627.151319932,1.0,1.94525471916e-15
|
|
||||||
22205153.52382764,1.0,6.9852514309e-16
|
|
||||||
22324878.40351138,1.0,2.45757880538e-16
|
|
||||||
22444702.60558849,1.0,8.47565473955e-17
|
|
||||||
22564133.40356277,1.0,2.8611824903e-17
|
|
||||||
22684916.550748322,1.0,9.50429614301e-18
|
|
||||||
22804924.811821572,1.0,3.10972949853e-18
|
|
||||||
22924555.89776567,1.0,1.00142181128e-18
|
|
||||||
23044673.155832924,1.0,3.17850639386e-19
|
|
||||||
23164255.219417505,1.0,9.93453168398e-20
|
|
||||||
23283874.042637054,1.0,3.05585142432e-20
|
|
||||||
23403159.90787814,1.0,9.23510334381e-21
|
|
||||||
23522146.490881946,1.0,2.7354446299e-21
|
|
||||||
23641985.23572208,1.0,7.94854774163e-22
|
|
||||||
23760806.412928328,1.0,2.26044417743e-22
|
|
||||||
23881715.30956635,1.0,6.31881915952e-23
|
|
Loading…
Reference in a new issue